1
0
mirror of https://github.com/openSUSE/osc.git synced 2024-11-09 22:36:14 +01:00

Merge pull request #1040 from dmach/fix/multibuild-commandline

Fix -M/--multibuild user experience, allow globs where possible
This commit is contained in:
Daniel Mach 2022-07-28 11:03:34 +02:00 committed by GitHub
commit e16e196fa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 172 additions and 55 deletions

View File

@ -63,6 +63,13 @@ You can modify osc commands, or roll your own, via the plugin API:
osc was written by several authors. This man page is automatically generated.
"""
HELP_MULTIBUILD_MANY = """Only work with the specified flavors of a multibuild package.
Globs are resolved according to _multibuild file from server.
Empty string is resolved to a package without a flavor."""
HELP_MULTIBUILD_ONE = "Only work with the specified flavor of a multibuild package."
class Osc(cmdln.Cmdln):
"""Usage: osc [GLOBALOPTS] SUBCOMMAND [OPTS] [ARGS...]
or: osc help SUBCOMMAND
@ -5449,8 +5456,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='more verbose output')
@cmdln.option('--no-multibuild', action='store_true', default=False,
help='Disable results for all direct affect packages inside of the project')
@cmdln.option('-M', '--multibuild-package', action='append', default=[],
help='Only show results for the specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR', action='append', default=[],
help=HELP_MULTIBUILD_MANY)
@cmdln.option('-V', '--vertical', action='store_true',
help='list packages vertically instead horizontally for entire project')
@cmdln.option('-w', '--watch', action='store_true',
@ -5472,7 +5479,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
Usage:
osc results # (inside working copy of PRJ or PKG)
osc results PROJECT [PACKAGE]
osc results PROJECT [PACKAGE[:FLAVOR]]
${cmd_option_list}
"""
@ -5520,7 +5527,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
'code': opts.status_filter}
if opts.multibuild_package:
opts.no_multibuild = False
kwargs['multibuild_packages'] = opts.multibuild_package
resolver = MultibuildFlavorResolver(apiurl, project, package, use_local=False)
kwargs['multibuild_packages'] = resolver.resolve(opts.multibuild_package)
if not opts.no_multibuild:
kwargs['multibuild'] = kwargs['locallink'] = True
if opts.xml or opts.csv:
@ -5658,8 +5666,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='Show the last finished log file')
@cmdln.option('--lastsucceeded', '--last-succeeded', action='store_true',
help='Show the last succeeded log file')
@cmdln.option('-M', '--multibuild-package', metavar='MPAC',
help='get log of the specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR',
help=HELP_MULTIBUILD_ONE)
@cmdln.option('-o', '--offset', metavar='OFFSET',
help='get log start or end from the offset')
@cmdln.option('-s', '--strip-time', action='store_true',
@ -5767,8 +5775,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='Show the last finished log file')
@cmdln.option('--lastsucceeded', '--last-succeeded', action='store_true',
help='Show the last succeeded log file')
@cmdln.option('-M', '--multibuild-package', metavar='MPAC',
help='show log file for specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR',
help=HELP_MULTIBUILD_ONE)
@cmdln.option('-o', '--offset', metavar='OFFSET',
help='get log starting or ending from the offset')
@cmdln.option('-s', '--strip-time', action='store_true',
@ -5782,9 +5790,9 @@ Please submit there instead, or use --nodevelproject to force direct submission.
remotebuildlogtail shows just the tail of the log file.
usage:
osc remotebuildlog project package repository arch
osc remotebuildlog project package[:flavor] repository arch
or
osc remotebuildlog project/package/repository/arch
osc remotebuildlog project/package[:flavor]/repository/arch
or
osc remotebuildlog buildlogurl
${cmd_option_list}
@ -5904,8 +5912,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
data = f.read(BUFSIZE)
f.close()
@cmdln.option('-M', '--multibuild-package', metavar='MPAC',
help='get triggerreason of the specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR', help=HELP_MULTIBUILD_ONE)
@cmdln.alias('tr')
def do_triggerreason(self, subcmd, opts, *args):
"""${cmd_name}: Show reason why a package got triggered to build
@ -5922,7 +5929,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
usage in package or project directory:
osc triggerreason REPOSITORY ARCH
osc triggerreason PROJECT PACKAGE REPOSITORY ARCH
osc triggerreason PROJECT PACKAGE[:FLAVOR] REPOSITORY ARCH
${cmd_option_list}
"""
@ -6068,8 +6075,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='verbose output of build dependencies')
@cmdln.option('--alternative-project', metavar='PROJECT',
help='specify the build target project')
@cmdln.option('-M', '--multibuild-package', metavar='MPAC',
help='Show the buildinfo of the specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR',
help=HELP_MULTIBUILD_ONE)
@cmdln.option('-x', '--extra-pkgs', metavar='PAC', action='append',
help='Add this package when computing the buildinfo')
@cmdln.option('-p', '--prefer-pkgs', metavar='DIR', action='append',
@ -6104,7 +6111,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
osc buildinfo [OPTS] (REPOSITORY = build_repository (config option), ARCH = hostarch, BUILD_DESCR is detected automatically)
Note: if BUILD_DESCR does not exist locally the remote BUILD_DESCR is used
osc buildinfo [OPTS] PROJECT PACKAGE REPOSITORY ARCH [BUILD_DESCR]
osc buildinfo [OPTS] PROJECT PACKAGE[:FLAVOR] REPOSITORY ARCH [BUILD_DESCR]
${cmd_option_list}
"""
@ -6526,8 +6533,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='Prefer packages from this directory when installing the build-root')
@cmdln.option('-k', '--keep-pkgs', metavar='DIR',
help='Save built packages into this directory')
@cmdln.option('-M', '--multibuild-package', metavar='MPAC',
help='Build the specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR',
help=HELP_MULTIBUILD_ONE)
@cmdln.option('-x', '--extra-pkgs', metavar='PAC', action='append',
help='Add this package when installing the build-root')
@cmdln.option('--root', metavar='ROOT',
@ -6933,8 +6940,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='generate output in CSV (separated by |)')
@cmdln.option('-l', '--limit', metavar='limit',
help='for setting the number of results')
@cmdln.option('-M', '--multibuild-package', metavar= 'MPAC',
help='Show the buildhistory of the specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR',
help=HELP_MULTIBUILD_ONE)
@cmdln.alias('buildhist')
def do_buildhistory(self, subcmd, opts, *args):
"""${cmd_name}: Shows the build history of a package
@ -6944,7 +6951,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
usage:
osc buildhist REPOSITORY ARCHITECTURE
osc buildhist PROJECT PACKAGE REPOSITORY ARCHITECTURE
osc buildhist PROJECT PACKAGE[:FLAVOR] REPOSITORY ARCHITECTURE
${cmd_option_list}
"""
@ -6982,8 +6989,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='generate output in CSV (separated by |)')
@cmdln.option('-l', '--limit', metavar='limit',
help='for setting the number of results')
@cmdln.option('-M', '--multibuild-package', metavar='MPAC',
help='get jobhistory for the specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR',
help=HELP_MULTIBUILD_ONE)
@cmdln.alias('jobhist')
def do_jobhistory(self, subcmd, opts, *args):
"""${cmd_name}: Shows the job history of a project
@ -6993,7 +7000,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
usage:
osc jobhist REPOSITORY ARCHITECTURE (in project dir)
osc jobhist PROJECT [PACKAGE] REPOSITORY ARCHITECTURE
osc jobhist PROJECT [PACKAGE[:FLAVOR]] REPOSITORY ARCHITECTURE
${cmd_option_list}
"""
wd = os.curdir
@ -7026,7 +7033,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
else:
raise oscerr.WrongArgs('Wrong number of arguments')
if opts.multibuild_package and package is not None:
if opts.multibuild_package and package:
package = package + ":" + opts.multibuild_package
format = 'text'
@ -7207,8 +7214,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
help='trigger rebuilds for a specific repository')
@cmdln.option('-f', '--failed', action='store_true',
help='rebuild all failed packages')
@cmdln.option('-M', '--multibuild-package', action='append',
help='rebuild specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar="FLAVOR", action='append',
help=HELP_MULTIBUILD_MANY)
@cmdln.option('--all', action='store_true',
help='Rebuild all packages of entire project')
@cmdln.alias('rebuildpac')
@ -7224,7 +7231,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
of the 'osc repos' output.
usage:
osc rebuild [PROJECT [PACKAGE [REPOSITORY [ARCH]]]]
osc rebuild [PROJECT [PACKAGE[:FLAVOR] [REPOSITORY [ARCH]]]]
${cmd_option_list}
"""
@ -7265,12 +7272,11 @@ Please submit there instead, or use --nodevelproject to force direct submission.
if not (opts.all or package or repo or arch or code):
raise oscerr.WrongOptions('No option has been provided. If you want to rebuild all packages of the entire project, use --all option.')
packages = []
if opts.multibuild_package:
for subpackage in opts.multibuild_package:
packages.append(package + ":" + subpackage)
resolver = MultibuildFlavorResolver(apiurl, project, package, use_local=False)
packages = resolver.resolve_as_packages(opts.multibuild_package)
else:
packages.append(package)
packages = [package]
for package in packages:
print(rebuild(apiurl, project, package, repo, arch, code))
@ -7292,9 +7298,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
for p in pacs:
print(p.info())
@cmdln.option('-M', '--multibuild-package', action='append',
help='specify a specific multibuild flavor')
@cmdln.option('-M', '--multibuild-package', metavar='FLAVOR', action='append',
help=HELP_MULTIBUILD_MANY)
def do_sendsysrq(self, subcmd, opts, *args):
"""${cmd_name}: trigger a sysrq in a running build
@ -7304,7 +7309,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
usage:
osc sendsysrq REPOSITORY ARCH SYSRQ
osc sendsysrq PROJECT PACKAGE REPOSITORY ARCH SYSRQ
osc sendsysrq PROJECT PACKAGE[:FLAVOR] REPOSITORY ARCH SYSRQ
${cmd_option_list}
"""
args = slash_split(args)
@ -7331,16 +7336,19 @@ Please submit there instead, or use --nodevelproject to force direct submission.
arch = args[3]
sysrq = args[4]
packages = [package]
if opts.multibuild_package:
packages = ['%s:%s' % (package, flavor) for flavor in opts.multibuild_package]
resolver = MultibuildFlavorResolver(apiurl, project, package, use_local=False)
packages = resolver.resolve_as_packages(opts.multibuild_package)
else:
packages = [package]
for package in packages:
print(cmdbuild(apiurl, 'sendsysrq', project, package, arch, repo, None, sysrq))
@cmdln.option('-a', '--arch', metavar='ARCH',
help='Restart builds for a specific architecture')
@cmdln.option('-M', '--multibuild-package', action='append',
help='Restart builds for specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar="FLAVOR", action='append',
help=HELP_MULTIBUILD_MANY)
@cmdln.option('-r', '--repo', metavar='REPO',
help='Restart builds for a specific repository')
@cmdln.option('--all', action='store_true',
@ -7350,7 +7358,7 @@ Please submit there instead, or use --nodevelproject to force direct submission.
"""${cmd_name}: Restart the build of a certain project or package
usage:
osc restartbuild [PROJECT [PACKAGE [REPOSITORY [ARCH]]]]
osc restartbuild [PROJECT [PACKAGE[:FLAVOR] [REPOSITORY [ARCH]]]]
${cmd_option_list}
"""
args = slash_split(args)
@ -7387,12 +7395,11 @@ Please submit there instead, or use --nodevelproject to force direct submission.
if not (opts.all or package or repo or arch):
raise oscerr.WrongOptions('No option has been provided. If you want to restart all packages of the entire project, use --all option.')
packages = []
if opts.multibuild_package:
for subpackage in opts.multibuild_package:
packages.append(package + ":" + subpackage)
resolver = MultibuildFlavorResolver(apiurl, project, package, use_local=False)
packages = resolver.resolve_as_packages(opts.multibuild_package)
else:
packages.append(package)
packages = [package]
for package in packages:
print(cmdbuild(apiurl, subcmd, project, package, arch, repo))
@ -7400,8 +7407,8 @@ Please submit there instead, or use --nodevelproject to force direct submission.
@cmdln.option('-a', '--arch', metavar='ARCH',
help='Delete all binary packages for a specific architecture')
@cmdln.option('-M', '--multibuild-package', action='append',
help='Delete all binary packages for specified multibuild package')
@cmdln.option('-M', '--multibuild-package', metavar="FLAVOR", action='append',
help=HELP_MULTIBUILD_MANY)
@cmdln.option('-r', '--repo', metavar='REPO',
help='Delete all binary packages for a specific repository')
@cmdln.option('--build-disabled', action='store_true',
@ -7423,9 +7430,9 @@ Please submit there instead, or use --nodevelproject to force direct submission.
usage:
osc wipebinaries OPTS # works in checked out project dir
osc wipebinaries OPTS PROJECT [PACKAGE]
osc wipebinaries OPTS PROJECT [PACKAGE[:FLAVOR]]
osc unpublish OPTS # works in checked out project dir
osc unpublish OPTS PROJECT [PACKAGE]
osc unpublish OPTS PROJECT [PACKAGE[:FLAVOR]]
${cmd_option_list}
"""
@ -7470,12 +7477,11 @@ Please submit there instead, or use --nodevelproject to force direct submission.
if len(codes) == 0:
raise oscerr.WrongOptions('No option has been provided. If you want to delete all binaries, use --all option.')
packages = []
if opts.multibuild_package:
for subpackage in opts.multibuild_package:
packages.append(package + ":" + subpackage)
resolver = MultibuildFlavorResolver(apiurl, project, package, use_local=False)
packages = resolver.resolve_as_packages(opts.multibuild_package)
else:
packages.append(package)
packages = [package]
# make a new request for each code= parameter and for each package in packages
for package in packages:

View File

@ -5882,7 +5882,8 @@ def get_results(apiurl, project, package, verbose=False, printJoin='', *args, **
continue
if multibuild_packages:
l = res['pkg'].rsplit(':', 1)
if len(l) != 2 or l[1] not in multibuild_packages:
if (len(l) != 2 or l[1] not in multibuild_packages) and not (len(l) == 1 and "" in multibuild_packages):
# special case: packages without flavor when multibuild_packages contains an empty string
continue
res['status'] = res['code']
if verbose and res['details'] is not None:
@ -7930,7 +7931,7 @@ def filter_role(meta, user, role):
root.remove(node)
def find_default_project(apiurl=None, package=None):
""""
"""
look though the list of conf.config['getpac_default_project']
and find the first project where the given package exists in the build service.
"""
@ -8069,4 +8070,114 @@ def vc_export_env(apiurl, quiet=False):
os.environ[env] = val
class MultibuildFlavorResolver:
def __init__(self, apiurl, project, package, use_local=False):
self.apiurl = apiurl
self.project = project
self.package = package
# whether to use local _multibuild file or download it from server
self.use_local = use_local
def get_multibuild_data(self):
"""
Retrieve contents of _multibuild file from given project/package.
Return None if the file doesn't exist.
"""
# use local _multibuild file
if self.use_local:
try:
with open("_multibuild", "r") as f:
return f.read()
except IOError as e:
if e.errno != errno.EEXIST:
raise
return None
# use _multibuild file from server
query = {}
query['expand'] = 1
u = makeurl(self.apiurl, ['source', self.project, self.package, '_multibuild'], query=query)
try:
f = http_GET(u)
except HTTPError as e:
if e.code == 404:
return None
raise
return f.read()
@staticmethod
def parse_multibuild_data(s):
"""
Return set of flavors from a string with multibuild xml.
"""
result = set()
# handle empty string and None
if not s:
return result
root = ET.fromstring(s)
for node in root.findall("flavor"):
result.add(node.text)
return result
def resolve(self, patterns):
"""
Return list of flavors based on given flavor `patterns`.
If `patterns` contain a glob, it's resolved according to _multibuild file,
values without globs are passed through.
"""
# determine if we're using globs
# yes: contact server and do glob matching
# no: use the specified values directly
use_globs = False
for pattern in patterns:
if '*' in pattern:
use_globs = True
break
if use_globs:
import fnmatch
multibuild_xml = self.get_multibuild_data()
all_flavors = self.parse_multibuild_data(multibuild_xml)
flavors = set()
for pattern in patterns:
# not a glob, use it as it is
if '*' not in pattern:
flavors.add(pattern)
continue
# match the globs with flavors from server
for flavor in all_flavors:
if fnmatch.fnmatch(flavor, pattern):
flavors.add(flavor)
else:
flavors = patterns
return sorted(flavors)
def resolve_as_packages(self, patterns):
"""
Return list of package:flavor based on given flavor `patterns`.
If a value from `patterns` contains a glob, it is resolved according to the _multibuild
file. Values without globs are passed through. If a value is empty string, package
without flavor is returned.
"""
flavors = self.resolve(patterns)
packages = []
for flavor in flavors:
if flavor:
packages.append(self.package + ':' + flavor)
else:
# special case: no flavor
packages.append(self.package)
return packages
# vim: sw=4 et