[elbe-devel] [PATCH v2 5/5] elbepack: control: move client actions out of soapclient.py
Thomas Weißschuh
thomas.weissschuh at linutronix.de
Mon Jul 15 17:31:30 CEST 2024
The client actions are highly specific to the control subcommand.
There is no reason to have them in the generic soapclient module.
Signed-off-by: Thomas Weißschuh <thomas.weissschuh at linutronix.de>
---
elbepack/commands/control.py | 357 ++++++++++++++++++++++++++++++++++++++++++-
elbepack/soapclient.py | 349 ------------------------------------------
2 files changed, 353 insertions(+), 353 deletions(-)
diff --git a/elbepack/commands/control.py b/elbepack/commands/control.py
index 6f737b229196..97fff2734a0c 100644
--- a/elbepack/commands/control.py
+++ b/elbepack/commands/control.py
@@ -3,17 +3,366 @@
# SPDX-FileCopyrightText: 2014-2017 Linutronix GmbH
import argparse
+import binascii
+import fnmatch
+import os
import socket
import sys
+import time
from http.client import BadStatusLine
from urllib.error import URLError
from suds import WebFault
-from elbepack.cli import add_arguments_from_decorated_function
+from elbepack.cli import add_argument, add_arguments_from_decorated_function
from elbepack.config import cfg
-from elbepack.elbexml import ValidationMode
-from elbepack.soapclient import ElbeSoapClient, client_actions
+from elbepack.elbexml import ElbeXML, ValidationMode
+from elbepack.soapclient import ElbeSoapClient
+
+
+def _add_project_dir_argument(f):
+ return add_argument('project_dir')(f)
+
+
+def _client_action_upload_file(append, build_dir, filename):
+ size = 1024 * 1024
+
+ with open(filename, 'rb') as f:
+
+ while True:
+
+ bin_data = f.read(size)
+ data = binascii.b2a_base64(bin_data)
+
+ if not isinstance(data, str):
+ data = data.decode('ascii')
+
+ append(build_dir, data)
+
+ if len(bin_data) != size:
+ break
+
+
+ at _add_project_dir_argument
+def _remove_log(client, args):
+ client.service.rm_log(args.project_dir)
+
+
+def _list_projects(client, args):
+ projects = client.service.list_projects()
+
+ try:
+ for p in projects.SoapProject:
+ print(
+ f'{p.builddir}\t{p.name}\t{p.version}\t{p.status}\t'
+ f'{p.edit}')
+ except AttributeError:
+ print('No projects configured in initvm')
+
+
+def _list_users(client, args):
+ users = client.service.list_users()
+
+ for u in users.string:
+ print(u)
+
+
+ at add_argument('name')
+ at add_argument('fullname')
+ at add_argument('password')
+ at add_argument('email')
+def _add_user(client, args):
+ try:
+ client.service.add_user(args.name, args.fullname, args.password, args.email, False)
+ except WebFault as e:
+ if not hasattr(e.fault, 'faultstring'):
+ raise
+
+ if not e.fault.faultstring.endswith('already exists in the database'):
+ raise
+
+ # when we get here, the user we wanted to create already exists.
+ # that is fine, and we dont need to do anything now.
+
+
+def _create_project(client, args):
+ uuid = client.service.new_project()
+ print(uuid)
+
+
+ at _add_project_dir_argument
+def _reset_project(client, args):
+ client.service.reset_project(args.project_dir)
+
+
+ at _add_project_dir_argument
+def _delete_project(client, args):
+ client.service.del_project(args.project_dir)
+
+
+ at _add_project_dir_argument
+ at add_argument('xml')
+def _set_xml(client, args):
+ builddir = args.project_dir
+ filename = args.xml
+
+ try:
+ x = ElbeXML(
+ filename,
+ skip_validate=True,
+ url_validation=ValidationMode.NO_CHECK)
+ except IOError:
+ print(f'{filename} is not a valid elbe xml file')
+ sys.exit(177)
+
+ if not x.has('target'):
+ print("<target> is missing, this file can't be built in an initvm",
+ file=sys.stderr)
+ sys.exit(178)
+
+ size = 1024 * 1024
+ part = 0
+ with open(filename, 'rb') as fp:
+ while True:
+
+ xml_base64 = binascii.b2a_base64(fp.read(size))
+
+ if not isinstance(xml_base64, str):
+ xml_base64 = xml_base64.decode('ascii')
+
+ # finish upload
+ if len(xml_base64) == 1:
+ part = client.service.upload_file(builddir,
+ 'source.xml',
+ xml_base64,
+ -1)
+ else:
+ part = client.service.upload_file(builddir,
+ 'source.xml',
+ xml_base64,
+ part)
+ if part == -1:
+ print('project busy, upload not allowed')
+ return part
+ if part == -2:
+ print('upload of xml finished')
+ return 0
+
+
+ at add_argument('--build-bin', action='store_true', dest='build_bin',
+ help='Build binary repository CDROM, for exact reproduction.')
+ at add_argument('--build-sources', action='store_true', dest='build_sources',
+ help='Build source CDROM')
+ at add_argument('--skip-pbuilder', action='store_true', dest='skip_pbuilder',
+ help="skip pbuilder section of XML (don't build packages)")
+ at _add_project_dir_argument
+def _build(client, args):
+ client.service.build(args.project_dir, args.build_bin, args.build_sources, args.skip_pbuilder)
+
+
+ at _add_project_dir_argument
+def _build_sysroot(client, args):
+ client.service.build_sysroot(args.project_dir)
+
+
+ at _add_project_dir_argument
+def _build_sdk(client, args):
+ client.service.build_sdk(args.project_dir)
+
+
+ at add_argument('--build-bin', action='store_true', dest='build_bin',
+ help='Build binary repository CDROM, for exact reproduction.')
+ at add_argument('--build-sources', action='store_true', dest='build_sources',
+ help='Build source CDROM')
+ at _add_project_dir_argument
+def _build_cdroms(client, args):
+ if not args.build_bin and not args.build_sources:
+ args.parser.error('One of --build-bin or --build-sources needs to be specified')
+
+ client.service.build_cdroms(args.project_dir, args.build_bin, args.build_sources)
+
+
+ at add_argument('--output', required=True, help='Output files to <directory>')
+ at _add_project_dir_argument
+ at add_argument('file')
+def _get_file(client, args):
+ dst = os.path.abspath(args.output)
+ os.makedirs(dst, exist_ok=True)
+ dst_fname = str(os.path.join(dst, args.file)).encode()
+
+ client.download_file(args.project_dir, args.file, dst_fname)
+ print(f'{args.file} saved')
+
+
+ at _add_project_dir_argument
+def _build_chroot(client, args):
+ client.service.build_chroot_tarball(args.project_dir)
+
+
+ at _add_project_dir_argument
+ at add_argument('file')
+def _dump_file(client, args):
+ part = 0
+ while True:
+ ret = client.service.get_file(args.project_dir, args.file, part)
+ if ret == 'FileNotFound':
+ print(ret, file=sys.stderr)
+ sys.exit(187)
+ if ret == 'EndOfFile':
+ return
+
+ os.write(sys.stdout.fileno(), binascii.a2b_base64(ret))
+ part = part + 1
+
+
+ at add_argument('--output', required=True, help='Output files to <directory>')
+ at add_argument('--pbuilder-only', action='store_true', dest='pbuilder_only',
+ help='Only list/download pbuilder Files')
+ at add_argument('--matches', dest='matches', default=False,
+ help='Select files based on wildcard expression.')
+ at _add_project_dir_argument
+def _get_files(client, args):
+ files = client.service.get_files(args.project_dir)
+
+ nfiles = 0
+
+ for f in files[0]:
+ if (args.pbuilder_only and not f.name.startswith('pbuilder_cross')
+ and not f.name.startswith('pbuilder')):
+ continue
+
+ if args.matches and not fnmatch.fnmatch(f.name, args.matches):
+ continue
+
+ nfiles += 1
+ try:
+ print(f'{f.name} \t({f.description})')
+ except AttributeError:
+ print(f'{f.name}')
+
+ dst = os.path.abspath(args.output)
+ os.makedirs(dst, exist_ok=True)
+ dst_fname = str(os.path.join(dst, os.path.basename(f.name)))
+ client.download_file(args.project_dir, f.name, dst_fname)
+
+ if nfiles == 0:
+ sys.exit(189)
+
+
+ at _add_project_dir_argument
+def _wait_busy(client, args):
+ while True:
+ try:
+ msg = client.service.get_project_busy(args.project_dir)
+ # TODO the root cause of this problem is unclear. To enable a
+ # get more information print the exception and retry to see if
+ # the connection problem is just a temporary problem. This
+ # code should be reworked as soon as it's clear what is going on
+ # here
+ except socket.error as e:
+ print(str(e), file=sys.stderr)
+ print('socket error during wait busy occured, retry..',
+ file=sys.stderr)
+ continue
+
+ if not msg:
+ time.sleep(0.1)
+ continue
+
+ if msg == 'ELBE-FINISH':
+ break
+
+ print(msg)
+
+ # exited the while loop -> the project is not busy anymore,
+ # check, whether everything is ok.
+
+ prj = client.service.get_project(args.project_dir)
+ if prj.status != 'build_done':
+ print(
+ 'Project build was not successful, current status: '
+ f'{prj.status}',
+ file=sys.stderr)
+ sys.exit(191)
+
+
+ at _add_project_dir_argument
+ at add_argument('cdrom_file')
+def _set_cdrom(client, args):
+ client.service.start_cdrom(args.project_dir)
+ _client_action_upload_file(client.service.append_cdrom, args.project_dir, args.cdrom_file)
+ client.service.finish_cdrom(args.project_dir)
+
+
+ at _add_project_dir_argument
+ at add_argument('orig_file')
+def _set_orig(client, args):
+ client.service.start_upload_orig(args.project_dir, os.path.basename(args.orig_file))
+ _client_action_upload_file(client.service.append_upload_orig, args.project_dir, args.orig_file)
+ client.service.finish_upload_orig(args.project_dir)
+
+
+ at add_argument('--profile', dest='profile', default='',
+ help='Make pbuilder commands build the specified profile')
+ at add_argument('--cross', dest='cross', action='store_true',
+ help='Creates an environment for crossbuilding if '
+ 'combined with create. Combined with build it'
+ ' will use this environment.')
+ at add_argument('--cpuset', default=-1, type=int,
+ help='Limit cpuset of pbuilder commands (bitmask)'
+ '(defaults to -1 for all CPUs)')
+ at _add_project_dir_argument
+ at add_argument('pdebuild_file')
+def _set_pdebuild(client, args):
+ client.service.start_pdebuild(args.project_dir)
+ _client_action_upload_file(client.service.append_pdebuild, args.project_dir, args.pdebuild_file)
+ client.service.finish_pdebuild(args.project_dir, args.cpuset, args.profile, args.cross)
+
+
+ at add_argument('--cross', dest='cross', action='store_true',
+ help='Creates an environment for crossbuilding if '
+ 'combined with create. Combined with build it'
+ ' will use this environment.')
+ at add_argument('--no-ccache', dest='noccache', action='store_true',
+ help="Deactivates the compiler cache 'ccache'")
+ at add_argument('--ccache-size', dest='ccachesize', default='10G',
+ help='set a limit for the compiler cache size '
+ '(should be a number followed by an optional '
+ 'suffix: k, M, G, T. Use 0 for no limit.)')
+ at _add_project_dir_argument
+def _build_pbuilder(client, args):
+ client.service.build_pbuilder(args.project_dir, args.cross, args.noccache, args.ccachesize)
+
+
+ at _add_project_dir_argument
+def _update_pbuilder(client, args):
+ client.service.update_pbuilder(args.project_dir)
+
+
+_client_actions = {
+ 'rm_log': _remove_log,
+ 'list_projects': _list_projects,
+ 'list_users': _list_users,
+ 'add_user': _add_user,
+ 'create_project': _create_project,
+ 'reset_project': _reset_project,
+ 'del_project': _delete_project,
+ 'set_xml': _set_xml,
+ 'build': _build,
+ 'build_sysroot': _build_sysroot,
+ 'build_sdk': _build_sdk,
+ 'build_cdroms': _build_cdroms,
+ 'get_file': _get_file,
+ 'build_chroot_tarball': _build_chroot,
+ 'dump_file': _dump_file,
+ 'get_files': _get_files,
+ 'wait_busy': _wait_busy,
+ 'set_cdrom': _set_cdrom,
+ 'set_orig': _set_orig,
+ 'set_pdebuild': _set_pdebuild,
+ 'build_pbuilder': _build_pbuilder,
+ 'update_pbuilder': _update_pbuilder,
+}
def run_command(argv):
@@ -53,7 +402,7 @@ def run_command(argv):
subparsers = aparser.add_subparsers(required=True)
- for action_name, do_action in client_actions.items():
+ for action_name, do_action in _client_actions.items():
action_parser = subparsers.add_parser(action_name)
action_parser.set_defaults(func=do_action)
add_arguments_from_decorated_function(action_parser, do_action)
diff --git a/elbepack/soapclient.py b/elbepack/soapclient.py
index 861027a52543..afce77c91a3f 100644
--- a/elbepack/soapclient.py
+++ b/elbepack/soapclient.py
@@ -4,7 +4,6 @@
# SPDX-FileCopyrightText: 2016 Claudius Heine <ch at denx.de>
import binascii
-import fnmatch
import logging
import os
import socket
@@ -16,12 +15,9 @@ from urllib.error import URLError
import debian.deb822
-from suds import WebFault
from suds.client import Client
-from elbepack.cli import add_argument
from elbepack.config import cfg
-from elbepack.elbexml import ElbeXML, ValidationMode
from elbepack.version import elbe_version
@@ -126,351 +122,6 @@ class ElbeSoapClient:
part = part + 1
-def _add_project_dir_argument(f):
- return add_argument('project_dir')(f)
-
-
-def _client_action_upload_file(append, build_dir, filename):
- size = 1024 * 1024
-
- with open(filename, 'rb') as f:
-
- while True:
-
- bin_data = f.read(size)
- data = binascii.b2a_base64(bin_data)
-
- if not isinstance(data, str):
- data = data.decode('ascii')
-
- append(build_dir, data)
-
- if len(bin_data) != size:
- break
-
-
- at _add_project_dir_argument
-def _remove_log(client, args):
- client.service.rm_log(args.project_dir)
-
-
-def _list_projects(client, args):
- projects = client.service.list_projects()
-
- try:
- for p in projects.SoapProject:
- print(
- f'{p.builddir}\t{p.name}\t{p.version}\t{p.status}\t'
- f'{p.edit}')
- except AttributeError:
- print('No projects configured in initvm')
-
-
-def _list_users(client, args):
- users = client.service.list_users()
-
- for u in users.string:
- print(u)
-
-
- at add_argument('name')
- at add_argument('fullname')
- at add_argument('password')
- at add_argument('email')
-def _add_user(client, args):
- try:
- client.service.add_user(args.name, args.fullname, args.password, args.email, False)
- except WebFault as e:
- if not hasattr(e.fault, 'faultstring'):
- raise
-
- if not e.fault.faultstring.endswith('already exists in the database'):
- raise
-
- # when we get here, the user we wanted to create already exists.
- # that is fine, and we dont need to do anything now.
-
-
-def _create_project(client, args):
- uuid = client.service.new_project()
- print(uuid)
-
-
- at _add_project_dir_argument
-def _reset_project(client, args):
- client.service.reset_project(args.project_dir)
-
-
- at _add_project_dir_argument
-def _delete_project(client, args):
- client.service.del_project(args.project_dir)
-
-
- at _add_project_dir_argument
- at add_argument('xml')
-def _set_xml(client, args):
- builddir = args.project_dir
- filename = args.xml
-
- try:
- x = ElbeXML(
- filename,
- skip_validate=True,
- url_validation=ValidationMode.NO_CHECK)
- except IOError:
- print(f'{filename} is not a valid elbe xml file')
- sys.exit(177)
-
- if not x.has('target'):
- print("<target> is missing, this file can't be built in an initvm",
- file=sys.stderr)
- sys.exit(178)
-
- size = 1024 * 1024
- part = 0
- with open(filename, 'rb') as fp:
- while True:
-
- xml_base64 = binascii.b2a_base64(fp.read(size))
-
- if not isinstance(xml_base64, str):
- xml_base64 = xml_base64.decode('ascii')
-
- # finish upload
- if len(xml_base64) == 1:
- part = client.service.upload_file(builddir,
- 'source.xml',
- xml_base64,
- -1)
- else:
- part = client.service.upload_file(builddir,
- 'source.xml',
- xml_base64,
- part)
- if part == -1:
- print('project busy, upload not allowed')
- return part
- if part == -2:
- print('upload of xml finished')
- return 0
-
-
- at add_argument('--build-bin', action='store_true', dest='build_bin',
- help='Build binary repository CDROM, for exact reproduction.')
- at add_argument('--build-sources', action='store_true', dest='build_sources',
- help='Build source CDROM')
- at add_argument('--skip-pbuilder', action='store_true', dest='skip_pbuilder',
- help="skip pbuilder section of XML (don't build packages)")
- at _add_project_dir_argument
-def _build(client, args):
- client.service.build(args.project_dir, args.build_bin, args.build_sources, args.skip_pbuilder)
-
-
- at _add_project_dir_argument
-def _build_sysroot(client, args):
- client.service.build_sysroot(args.project_dir)
-
-
- at _add_project_dir_argument
-def _build_sdk(client, args):
- client.service.build_sdk(args.project_dir)
-
-
- at add_argument('--build-bin', action='store_true', dest='build_bin',
- help='Build binary repository CDROM, for exact reproduction.')
- at add_argument('--build-sources', action='store_true', dest='build_sources',
- help='Build source CDROM')
- at _add_project_dir_argument
-def _build_cdroms(client, args):
- if not args.build_bin and not args.build_sources:
- args.parser.error('One of --build-bin or --build-sources needs to be specified')
-
- client.service.build_cdroms(args.project_dir, args.build_bin, args.build_sources)
-
-
- at add_argument('--output', required=True, help='Output files to <directory>')
- at _add_project_dir_argument
- at add_argument('file')
-def _get_file(client, args):
- dst = os.path.abspath(args.output)
- os.makedirs(dst, exist_ok=True)
- dst_fname = str(os.path.join(dst, args.file)).encode()
-
- client.download_file(args.project_dir, args.file, dst_fname)
- print(f'{args.file} saved')
-
-
- at _add_project_dir_argument
-def _build_chroot(client, args):
- client.service.build_chroot_tarball(args.project_dir)
-
-
- at _add_project_dir_argument
- at add_argument('file')
-def _dump_file(client, args):
- part = 0
- while True:
- ret = client.service.get_file(args.project_dir, args.file, part)
- if ret == 'FileNotFound':
- print(ret, file=sys.stderr)
- sys.exit(187)
- if ret == 'EndOfFile':
- return
-
- os.write(sys.stdout.fileno(), binascii.a2b_base64(ret))
- part = part + 1
-
-
- at add_argument('--output', required=True, help='Output files to <directory>')
- at add_argument('--pbuilder-only', action='store_true', dest='pbuilder_only',
- help='Only list/download pbuilder Files')
- at add_argument('--matches', dest='matches', default=False,
- help='Select files based on wildcard expression.')
- at _add_project_dir_argument
-def _get_files(client, args):
- files = client.service.get_files(args.project_dir)
-
- nfiles = 0
-
- for f in files[0]:
- if (args.pbuilder_only and not f.name.startswith('pbuilder_cross')
- and not f.name.startswith('pbuilder')):
- continue
-
- if args.matches and not fnmatch.fnmatch(f.name, args.matches):
- continue
-
- nfiles += 1
- try:
- print(f'{f.name} \t({f.description})')
- except AttributeError:
- print(f'{f.name}')
-
- dst = os.path.abspath(args.output)
- os.makedirs(dst, exist_ok=True)
- dst_fname = str(os.path.join(dst, os.path.basename(f.name)))
- client.download_file(args.project_dir, f.name, dst_fname)
-
- if nfiles == 0:
- sys.exit(189)
-
-
- at _add_project_dir_argument
-def _wait_busy(client, args):
- while True:
- try:
- msg = client.service.get_project_busy(args.project_dir)
- # TODO the root cause of this problem is unclear. To enable a
- # get more information print the exception and retry to see if
- # the connection problem is just a temporary problem. This
- # code should be reworked as soon as it's clear what is going on
- # here
- except socket.error as e:
- print(str(e), file=sys.stderr)
- print('socket error during wait busy occured, retry..',
- file=sys.stderr)
- continue
-
- if not msg:
- time.sleep(0.1)
- continue
-
- if msg == 'ELBE-FINISH':
- break
-
- print(msg)
-
- # exited the while loop -> the project is not busy anymore,
- # check, whether everything is ok.
-
- prj = client.service.get_project(args.project_dir)
- if prj.status != 'build_done':
- print(
- 'Project build was not successful, current status: '
- f'{prj.status}',
- file=sys.stderr)
- sys.exit(191)
-
-
- at _add_project_dir_argument
- at add_argument('cdrom_file')
-def _set_cdrom(client, args):
- client.service.start_cdrom(args.project_dir)
- _client_action_upload_file(client.service.append_cdrom, args.project_dir, args.cdrom_file)
- client.service.finish_cdrom(args.project_dir)
-
-
- at _add_project_dir_argument
- at add_argument('orig_file')
-def _set_orig(client, args):
- client.service.start_upload_orig(args.project_dir, os.path.basename(args.orig_file))
- _client_action_upload_file(client.service.append_upload_orig, args.project_dir, args.orig_file)
- client.service.finish_upload_orig(args.project_dir)
-
-
- at add_argument('--profile', dest='profile', default='',
- help='Make pbuilder commands build the specified profile')
- at add_argument('--cross', dest='cross', action='store_true',
- help='Creates an environment for crossbuilding if '
- 'combined with create. Combined with build it'
- ' will use this environment.')
- at add_argument('--cpuset', default=-1, type=int,
- help='Limit cpuset of pbuilder commands (bitmask)'
- '(defaults to -1 for all CPUs)')
- at _add_project_dir_argument
- at add_argument('pdebuild_file')
-def _set_pdebuild(client, args):
- client.service.start_pdebuild(args.project_dir)
- _client_action_upload_file(client.service.append_pdebuild, args.project_dir, args.pdebuild_file)
- client.service.finish_pdebuild(args.project_dir, args.cpuset, args.profile, args.cross)
-
-
- at add_argument('--cross', dest='cross', action='store_true',
- help='Creates an environment for crossbuilding if '
- 'combined with create. Combined with build it'
- ' will use this environment.')
- at add_argument('--no-ccache', dest='noccache', action='store_true',
- help="Deactivates the compiler cache 'ccache'")
- at add_argument('--ccache-size', dest='ccachesize', default='10G',
- help='set a limit for the compiler cache size '
- '(should be a number followed by an optional '
- 'suffix: k, M, G, T. Use 0 for no limit.)')
- at _add_project_dir_argument
-def _build_pbuilder(client, args):
- client.service.build_pbuilder(args.project_dir, args.cross, args.noccache, args.ccachesize)
-
-
- at _add_project_dir_argument
-def _update_pbuilder(client, args):
- client.service.update_pbuilder(args.project_dir)
-
-
-client_actions = {
- 'rm_log': _remove_log,
- 'list_projects': _list_projects,
- 'list_users': _list_users,
- 'add_user': _add_user,
- 'create_project': _create_project,
- 'reset_project': _reset_project,
- 'del_project': _delete_project,
- 'set_xml': _set_xml,
- 'build': _build,
- 'build_sysroot': _build_sysroot,
- 'build_sdk': _build_sdk,
- 'build_cdroms': _build_cdroms,
- 'get_file': _get_file,
- 'build_chroot_tarball': _build_chroot,
- 'dump_file': _dump_file,
- 'get_files': _get_files,
- 'wait_busy': _wait_busy,
- 'set_cdrom': _set_cdrom,
- 'set_orig': _set_orig,
- 'set_pdebuild': _set_pdebuild,
- 'build_pbuilder': _build_pbuilder,
- 'update_pbuilder': _update_pbuilder,
-}
-
-
class RepoAction:
repoactiondict = {}
--
2.45.2
More information about the elbe-devel
mailing list