Hello community, here is the log from the commit of package osc for openSUSE:Factory checked in at 2012-12-05 14:01:17 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/osc (Old) and /work/SRC/openSUSE:Factory/.osc.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "osc", Maintainer is "[email protected]" Changes: -------- --- /work/SRC/openSUSE:Factory/osc/osc.changes 2012-10-07 19:54:05.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.osc.new/osc.changes 2012-12-05 14:01:20.000000000 +0100 @@ -1,0 +2,16 @@ +Tue Dec 4 15:46:11 UTC 2012 - [email protected] + +- update to 0.137.0: + - support single binary download via getbinaries command + - support to set the bugowner + # + # Features which requires OBS 2.4 + # + - offer to send set_bugowner request if target is not writeable + - support delete requests for repositories. + - support default maintainer/bugowner search based on binary package names + - support to lookup --all definitions of maintainers of bugowners. Either + for showing or setting them. + - buildinfo --debug option for verbose output of dependency calculation + +------------------------------------------------------------------- Old: ---- osc-0.136.0.tar.gz New: ---- osc-0.137.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ osc.spec ++++++ --- /var/tmp/diff_new_pack.XneH5f/_old 2012-12-05 14:01:21.000000000 +0100 +++ /var/tmp/diff_new_pack.XneH5f/_new 2012-12-05 14:01:21.000000000 +0100 @@ -17,7 +17,7 @@ Name: osc -Version: 0.136.0 +Version: 0.137.0 Release: 0 Summary: openSUSE Build Service Commander License: GPL-2.0+ ++++++ _service ++++++ --- /var/tmp/diff_new_pack.XneH5f/_old 2012-12-05 14:01:21.000000000 +0100 +++ /var/tmp/diff_new_pack.XneH5f/_new 2012-12-05 14:01:21.000000000 +0100 @@ -1,6 +1,6 @@ <services> <service name="tar_scm" mode="disabled"> - <param name="version">0.136.0</param> + <param name="version">0.137.0</param> <param name="url">git://github.com/openSUSE/osc.git</param> <param name="scm">git</param> </service> ++++++ osc-0.136.0.tar.gz -> osc-0.137.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.136.0/.gitignore new/osc-0.137.0/.gitignore --- old/osc-0.136.0/.gitignore 2012-09-27 21:46:58.000000000 +0200 +++ new/osc-0.137.0/.gitignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,5 +0,0 @@ -*.pyc -*.swp -tags -build -tests/junit-xml-results diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.136.0/NEWS new/osc-0.137.0/NEWS --- old/osc-0.136.0/NEWS 2012-09-27 21:46:58.000000000 +0200 +++ new/osc-0.137.0/NEWS 2012-12-04 16:45:58.000000000 +0100 @@ -1,3 +1,16 @@ +0.137 + - support single binary download via getbinaries command + - support to set the bugowner +# +# Features which requires OBS 2.4 +# + - offer to send set_bugowner request if target is not writeable + - support delete requests for repositories. + - support default maintainer/bugowner search based on binary package names + - support to lookup --all definitions of maintainers of bugowners. Either + for showing or setting them. + - buildinfo --debug option for verbose output of dependency calculation + 0.136 - prefer TLS v1.1 or v1.2 if available - declined is considered to be an open state (that is "osc rq list" also shows declined requests) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.136.0/osc/.gitignore new/osc-0.137.0/osc/.gitignore --- old/osc-0.136.0/osc/.gitignore 2012-09-27 21:46:58.000000000 +0200 +++ new/osc-0.137.0/osc/.gitignore 1970-01-01 01:00:00.000000000 +0100 @@ -1,2 +0,0 @@ -*.pyc -*.swp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.136.0/osc/build.py new/osc-0.137.0/osc/build.py --- old/osc-0.136.0/osc/build.py 2012-09-27 21:46:58.000000000 +0200 +++ new/osc-0.137.0/osc/build.py 2012-12-04 16:45:58.000000000 +0100 @@ -152,10 +152,8 @@ def remove_dep(self, name): # we need to iterate over all deps because if this a # kiwi build the same package might appear multiple times - for i in self.deps: - # only remove those which are needed for the build itself - if i.name == name and not i.noinstall: - self.deps.remove(i) + # NOTE: do not loop and remove items, the second same one would not get catched + self.deps = [i for i in self.deps if not i.name == name] class Pac: @@ -181,7 +179,7 @@ self.mp['name'] = node.get('name') or self.mp['binary'] # this is not the ideal place to check if the package is a localdep or not - localdep = self.mp['name'] in localpkgs and not self.mp['noinstall'] + localdep = self.mp['name'] in localpkgs # and not self.mp['noinstall'] if not localdep and not (node.get('project') and node.get('repository')): raise oscerr.APIError('incomplete information for package %s, may be caused by a broken project configuration.' % self.mp['name'] ) @@ -647,7 +645,7 @@ # vs. # arch we are supposed to build for if bi.hostarch != None: - if hostarch != bi.hostarch and not hostarch in can_also_build.get(hostarch, []): + if hostarch != bi.hostarch and not bi.hostarch in can_also_build.get(hostarch, []): print >>sys.stderr, 'Error: hostarch \'%s\' is required.' % (bi.hostarch) return 1 elif hostarch != bi.buildarch: @@ -777,6 +775,10 @@ shutil.rmtree('repos') os.mkdir('repos') for i in bi.deps: + if not i.extproject: + # remove + bi.deps.remove(i) + continue # project pdir = str(i.extproject).replace(':/', ':') # repo @@ -789,16 +791,26 @@ pradir = prdir+"/"+adir # source fullfilename sffn = i.fullfilename - print "Using package: "+sffn + filename=sffn.split("/")[-1] # target fullfilename - tffn = pradir+"/"+sffn.split("/")[-1] + tffn = pradir+"/"+filename if not os.path.exists(os.path.join(pradir)): os.makedirs(os.path.join(pradir)) if not os.path.exists(tffn): + print "Using package: "+sffn if opts.linksources: os.link(sffn, tffn) else: os.symlink(sffn, tffn) + if prefer_pkgs: + for name, path in prefer_pkgs.iteritems(): + if name == filename: + print "Using prefered package: " + path + "/" + filename + os.unlink(tffn) + if opts.linksources: + os.link(path + "/" + filename, tffn) + else: + os.symlink(path + "/" + filename, tffn) if bi.pacsuffix == 'rpm': if opts.no_verify: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.136.0/osc/commandline.py new/osc-0.137.0/osc/commandline.py --- old/osc-0.136.0/osc/commandline.py 2012-09-27 21:46:58.000000000 +0200 +++ new/osc-0.137.0/osc/commandline.py 2012-12-04 16:45:58.000000000 +0100 @@ -1448,13 +1448,14 @@ user = args[0] project = args[1] + package = "" if len(args) > 2: - package = args[2] + package = """package="%s" """ % (args[2]) if get_user_meta(apiurl, user) == None: raise oscerr.WrongArgs('osc: an error occured.') - actionxml = """ <action type="set_bugowner"> <target project="%s" package="%s" /> <person name="%s" /> </action> """ % \ + actionxml = """ <action type="set_bugowner"> <target project="%s" %s /> <person name="%s" /> </action> """ % \ (project, package, user) return actionxml @@ -1635,6 +1636,8 @@ @cmdln.option('-m', '--message', metavar='TEXT', help='specify message TEXT') + @cmdln.option('-r', '--repository', metavar='TEXT', + help='specify message TEXT') @cmdln.alias("dr") @cmdln.alias("dropreq") @cmdln.alias("droprequest") @@ -1645,6 +1648,7 @@ usage: osc deletereq [-m TEXT] # works in checked out project/package osc deletereq [-m TEXT] PROJECT [PACKAGE] + osc deletereq [-m TEXT] PROJECT [--repository REPOSITORY] ${cmd_option_list} """ import cgi @@ -1653,6 +1657,7 @@ project = None package = None + repository = None if len(args) > 2: raise oscerr.WrongArgs('Too many arguments.') @@ -1669,6 +1674,9 @@ else: raise oscerr.WrongArgs('Please specify at least a project.') + if opts.repository: + repository = opts.repository + if not opts.message: import textwrap if package is not None: @@ -1681,7 +1689,7 @@ opts.message = edit_message(footer) r = Request() - r.add_action('delete', tgt_project=project, tgt_package=package) + r.add_action('delete', tgt_project=project, tgt_package=package, tgt_repository=repository) r.description = cgi.escape(opts.message) r.create(self.get_api_url()) print r.reqid @@ -2033,7 +2041,8 @@ for result in results: if days == 0 or result.state.when > since or result.state.name == 'new': if (opts.interactive or conf.config['request_show_interactive']) and not opts.non_interactive: - request_interactive_review(apiurl, result, group=opts.group) + ignore_reviews = subcmd != 'review' + request_interactive_review(apiurl, result, group=opts.group, ignore_reviews=ignore_reviews) else: print result.list_view(), '\n' else: @@ -2071,7 +2080,8 @@ '(request has no \'submit\' action)') return request_interactive_review(apiurl, r, 'e') elif (opts.interactive or conf.config['request_show_interactive']) and not opts.non_interactive: - return request_interactive_review(apiurl, r, group=opts.group) + ignore_reviews = subcmd != 'review' + return request_interactive_review(apiurl, r, group=opts.group, ignore_reviews=ignore_reviews) else: print r if opts.source_buildstatus: @@ -2686,6 +2696,8 @@ help='specify message TEXT') @cmdln.option('--no-cleanup', action='store_true', help='do not remove source project on accept') + @cmdln.option('--cleanup', action='store_true', + help='do remove source project on accept') @cmdln.option('--incident', metavar='INCIDENT', help='specify incident number to merge in') @cmdln.option('--incident-project', metavar='INCIDENT_PROJECT', @@ -2726,9 +2738,11 @@ source_packages = args[1:] release_project = args[-1] source_packages.remove(release_project) + if opts.cleanup: + opt_sourceupdate = 'cleanup' if not opts.no_cleanup: default_branch = 'home:%s:branches:' % (conf.get_apiurl_usr(apiurl)) - if source_project.startswith(default_branch) and not opts.no_cleanup: + if source_project.startswith(default_branch): opt_sourceupdate = 'cleanup' if opts.incident_project: @@ -4735,6 +4749,8 @@ print " ", dep.text + @cmdln.option('-d', '--debug', action='store_true', + help='verbose output of build dependencies') @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', @@ -4810,6 +4826,7 @@ print ''.join(get_buildinfo(apiurl, project, package, repository, arch, specfile=build_descr_data, + debug=opts.debug, addlist=opts.extra_pkgs)) @@ -4915,7 +4932,7 @@ arg_arch = arg_repository = arg_descr = None if len(args) < 3: for arg in args: - if arg.endswith('.spec') or arg.endswith('.dsc') or arg.endswith('.kiwi') or os.path.basename(arg) == 'PKGBUILD': + if arg.endswith('.spec') or arg.endswith('.dsc') or arg.endswith('.kiwi') or arg == 'PKGBUILD': arg_descr = arg else: if (arg in osc.build.can_also_build.get(osc.build.hostarch, []) @@ -4969,7 +4986,7 @@ # can be implemented using # reduce(lambda x, y: x + y, (glob.glob(x) for x in ('*.spec', '*.dsc', '*.kiwi'))) # but be a bit more readable :) - descr = glob.glob('*.spec') + glob.glob('*.dsc') + glob.glob('*.kiwi') + descr = glob.glob('*.spec') + glob.glob('*.dsc') + glob.glob('*.kiwi') + glob.glob('PKGBUILD') # FIXME: # * request repos from server and select by build type. @@ -4980,6 +4997,7 @@ if len(descr) > 1: # guess/prefer build descrs like the following: # <pac>-<repo>.<ext> > <pac>.<ext> + # no guessing for arch's PKGBUILD files (the backend does not do any guessing, too) pac = os.path.basename(os.getcwd()) if is_package_dir(os.getcwd()): pac = store_read_package(os.getcwd()) @@ -5679,24 +5697,28 @@ osc getbinaries REPOSITORY # works in checked out project/package (check out all archs in subdirs) osc getbinaries REPOSITORY ARCHITECTURE # works in checked out project/package osc getbinaries PROJECT PACKAGE REPOSITORY ARCHITECTURE + osc getbinaries PROJECT PACKAGE REPOSITORY ARCHITECTURE FILE ${cmd_option_list} """ args = slash_split(args) apiurl = self.get_api_url() - package = None project = None + package = None + binary = None if len(args) < 1 and is_package_dir('.'): self.print_repos() architecture = None - if len(args) == 4: + if len(args) == 4 or len(args) == 5: project = args[0] package = args[1] repository = args[2] architecture = args[3] + if len(args) == 5: + binary = args[4] elif len(args) >= 1 and len(args) <= 2: if is_package_dir(os.getcwd()): project = store_read_project(os.curdir) @@ -5741,6 +5763,8 @@ continue for i in binaries: + if binary != None and binary != i.name: + continue # skip source rpms if not opts.sources and i.name.endswith('src.rpm'): continue @@ -6414,39 +6438,6 @@ out = r.read() sys.stdout.write(out) - @cmdln.option('-v', '--verbose', action='store_true', - help='show more information') - @cmdln.option('--nodevelproject', action='store_true', - help='do not follow a defined devel project ' \ - '(primary project where a package is developed)') - @cmdln.option('-e', '--email', action='store_true', - help='show email addresses instead of user names') - def do_bugowner(self, subcmd, opts, *args): - """${cmd_name}: Show bugowners of a project/package - - osc bugowner PRJ - osc bugowner PRJ PKG - - PRJ and PKG default to current working-copy path. - Prints bugowner if defined, or maintainer otherwise. - - Shortcut for osc maintainer -B [PRJ] PKG - - ${cmd_option_list} - """ - opts.role = () - opts.bugowner = True - opts.bugowner_only = None - opts.add = None - opts.delete = None - opts.devel_project = None - - if len(args) == 1: - def_p = find_default_project(self.get_api_url(), args[0]) - print >>sys.stderr, 'defaulting to %s/%s' % (def_p, args[0]) - # python has no args.unshift ??? - args = [ def_p, args[0] ] - return self.do_maintainer(subcmd, opts, *args) @cmdln.option('-b', '--bugowner-only', action='store_true', @@ -6463,30 +6454,45 @@ @cmdln.option('-D', '--devel-project', metavar='devel_project', help='define the project where this package is primarily developed') @cmdln.option('-a', '--add', metavar='user', - help='add a new maintainer/bugowner (can be specified via --role)') + help='add a new person for given role ("maintainer" by default)') + @cmdln.option('-A', '--all', action='store_true', + help='list all found entries not just the first one') + @cmdln.option('-s', '--set-bugowner', metavar='user', + help='Set the bugowner to specified person') + @cmdln.option('-S', '--set-bugowner-request', metavar='user', + help='Set the bugowner to specified person via a request') @cmdln.option('-d', '--delete', metavar='user', help='delete a maintainer/bugowner (can be specified via --role)') @cmdln.option('-r', '--role', metavar='role', action='append', default=[], help='Specify user role') + @cmdln.alias('bugowner') def do_maintainer(self, subcmd, opts, *args): """${cmd_name}: Show maintainers of a project/package + osc maintainer <options> + osc maintainer BINARY <options> osc maintainer PRJ <options> osc maintainer PRJ PKG <options> + The tool looks up the default responsible person for a certain project or package. + When using with an OBS 2.4 (or later) server it is doing the lookup for + a given binary according to the server side configuration of default owners. + PRJ and PKG default to current working-copy path. ${cmd_usage} ${cmd_option_list} """ - pac = None + binary = None prj = None - root = None + pac = None + metaroot = None + searchresult = None roles = [ 'bugowner', 'maintainer' ] if len(opts.role): roles = opts.role - if opts.bugowner_only or opts.bugowner: + if opts.bugowner_only or opts.bugowner or opts.set_bugowner or opts.set_bugowner_request or subcmd == 'bugowner': roles = [ 'bugowner' ] if len(args) == 0: @@ -6496,7 +6502,8 @@ pass prj = store_read_project('.') elif len(args) == 1: - prj = args[0] + # it is unclear if one argument is a binary or a project, try binary first for new OBS 2.4 + binary = prj = args[0] elif len(args) == 2: prj = args[0] pac = args[1] @@ -6505,70 +6512,167 @@ apiurl = self.get_api_url() + # Try the OBS 2.4 way first. + if pac==None and binary: + limit=None + if opts.all: + limit=0 + filterroles=roles + if filterroles == [ 'bugowner', 'maintainer' ]: + # use server side configured default + filterroles=None + searchresult = owner(apiurl, binary, usefilter=filterroles, devel=None, limit=limit) + if opts.add: - for role in roles: - addPerson(apiurl, prj, pac, opts.add, role) + if searchresult: + for result in searchresult.findall('owner'): + for role in roles: + addPerson(apiurl, result.get('project'), result.get('package'), opts.add, role) + else: + for role in roles: + addPerson(apiurl, prj, pac, opts.add, role) + elif opts.set_bugowner or opts.set_bugowner_request: + bugowner = opts.set_bugowner or opts.set_bugowner_request + requestactionsxml = "" + if searchresult: + for result in searchresult.findall('owner'): + if opts.set_bugowner: + for role in roles: + try: + setBugowner(apiurl, result.get('project'), result.get('package'), bugowner) + except urllib2.HTTPError, e: + if e.code == 403: + print "No write permission in", result.get('project'), + if result.get('package'): + print "/", result.get('package'), + print + repl = raw_input('\nCreating a request instead? (y/n) ') + if repl.lower() == 'y': + opts.set_bugowner_request = opts.set_bugowner + opts.set_bugowner = None + break + + if opts.set_bugowner_request: + for role in roles: + args = [bugowner, result.get('project')] + if result.get('package'): + args = args + [result.get('package')] + requestactionsxml += self._set_bugowner(args,opts) + + else: + for role in roles: + setBugowner(apiurl, prj, pac, opts.delete, role) + + if requestactionsxml != "": + message = edit_message() + + import cgi + xml = """<request> %s <state name="new"/> <description>%s</description> </request> """ % \ + (requestactionsxml, cgi.escape(message or "")) + u = makeurl(apiurl, ['request'], query='cmd=create') + f = http_POST(u, data=xml) + + root = ET.parse(f).getroot() + print "Request ID:", root.get('id') + elif opts.delete: - for role in roles: - delPerson(apiurl, prj, pac, opts.delete, role) + if searchresult: + for result in searchresult.findall('owner'): + for role in roles: + delPerson(apiurl, result.get('project'), result.get('package'), opts.add, role) + else: + for role in roles: + delPerson(apiurl, prj, pac, opts.delete, role) elif opts.devel_project: # XXX: does it really belong to this command? setDevelProject(apiurl, prj, pac, opts.devel_project) else: if pac: m = show_package_meta(apiurl, prj, pac) - root = ET.fromstring(''.join(m)) + metaroot = ET.fromstring(''.join(m)) if not opts.nodevelproject: - while root.findall('devel'): - d = root.find('devel') + while metaroot.findall('devel'): + d = metaroot.find('devel') prj = d.get('project', prj) pac = d.get('package', pac) if opts.verbose: print "Following to the development space: %s/%s" % (prj, pac) m = show_package_meta(apiurl, prj, pac) - root = ET.fromstring(''.join(m)) - if not root.findall('person'): + metaroot = ET.fromstring(''.join(m)) + if not metaroot.findall('person'): if opts.verbose: print "No dedicated persons in package defined, showing the project persons." pac = None m = show_project_meta(apiurl, prj) - root = ET.fromstring(''.join(m)) + metaroot = ET.fromstring(''.join(m)) else: - m = show_project_meta(apiurl, prj) - root = ET.fromstring(''.join(m)) + # fallback to project lookup for old servers + if not searchresult: + m = show_project_meta(apiurl, prj) + metaroot = ET.fromstring(''.join(m)) + + # extract the maintainers + projects = [] + # from owner search + if searchresult: + for result in searchresult.findall('owner'): + maintainers = {} + maintainers.setdefault("project", result.get('project')) + maintainers.setdefault("package", result.get('package')) + for person in result.findall('person'): + maintainers.setdefault(person.get('role'), []).append(person.get('name')) + projects = projects + [maintainers] + # from meta data + if metaroot: + # we have just one result + maintainers = {} + for person in metaroot.findall('person'): + maintainers.setdefault(person.get('role'), []).append(person.get('userid')) + projects = [maintainers] # showing the maintainers - maintainers = {} - for person in root.findall('person'): - maintainers.setdefault(person.get('role'), []).append(person.get('userid')) - for role in roles: - if opts.bugowner and not len(maintainers.get(role, [])): - role = 'maintainer' - if pac: - print "%s of %s/%s : " %(role, prj, pac) - else: - print "%s of %s : " %(role, prj) - if opts.email: - emails = [] - for maintainer in maintainers.get(role, []): - user = get_user_data(apiurl, maintainer, 'email') - if len(user): - emails.append(''.join(user)) - print ', '.join(emails) or '-' - elif opts.verbose: - userdata = [] - for maintainer in maintainers.get(role, []): - user = get_user_data(apiurl, maintainer, 'login', 'realname', 'email') - userdata.append(user[0]) - if user[1] != '-': - userdata.append("%s <%s>"%(user[1], user[2])) - else: - userdata.append(user[2]) - for row in build_table(2, userdata, None, 3): - print row - else: - print ', '.join(maintainers.get(role, [])) or '-' - print + for maintainers in projects: + indent="" + definingproject=maintainers.get("project") + if definingproject: + definingpackage=maintainers.get("package") + indent=" " + if definingpackage: + print "Defined in package: %s/%s " %(definingproject, definingpackage) + else: + print "Defined in project: ", definingproject + + for role in roles: + if opts.bugowner and not len(maintainers.get(role, [])): + role = 'maintainer' + if pac: + print "%s%s of %s/%s : " %(indent, role, prj, pac) + else: + print "%s%s of %s : " %(indent, role, prj) + if opts.email: + emails = [] + for maintainer in maintainers.get(role, []): + user = get_user_data(apiurl, maintainer, 'email') + if len(user): + emails.append(''.join(user)) + print indent, + print ', '.join(emails) or '-' + elif opts.verbose: + userdata = [] + for maintainer in maintainers.get(role, []): + user = get_user_data(apiurl, maintainer, 'login', 'realname', 'email') + userdata.append(user[0]) + if user[1] != '-': + userdata.append("%s <%s>"%(user[1], user[2])) + else: + userdata.append(user[2]) + for row in build_table(2, userdata, None, 3): + print indent, + print row + else: + print indent, + print ', '.join(maintainers.get(role, [])) or '-' + print @cmdln.alias('who') @cmdln.alias('user') @@ -6693,7 +6797,7 @@ """ apiurl = self.get_api_url() - + args = slash_split(args) if len(args) >= 3 and len(args) <= 4: prj = args[0] package = target_package = args[1] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.136.0/osc/core.py new/osc-0.137.0/osc/core.py --- old/osc-0.136.0/osc/core.py 2012-09-27 21:46:58.000000000 +0200 +++ new/osc-0.137.0/osc/core.py 2012-12-04 16:45:58.000000000 +0100 @@ -3,7 +3,7 @@ # and distributed under the terms of the GNU General Public Licence, # either version 2, or version 3 (at your option). -__version__ = '0.136' +__version__ = '0.137' # __store_version__ is to be incremented when the format of the working copy # "store" changes in an incompatible way. Please add any needed migration @@ -2218,7 +2218,7 @@ 'set_bugowner': ('tgt_project', 'tgt_package', 'person_name'), # obsoleted by add_role 'maintenance_release': ('src_project', 'src_package', 'src_rev', 'tgt_project', 'tgt_package', 'person_name'), 'maintenance_incident': ('src_project', 'src_package', 'src_rev', 'tgt_project', 'tgt_releaseproject', 'person_name', 'opt_sourceupdate'), - 'delete': ('tgt_project', 'tgt_package'), + 'delete': ('tgt_project', 'tgt_package', 'tgt_repository'), 'change_devel': ('src_project', 'src_package', 'tgt_project', 'tgt_package')} # attribute prefix to element name map (only needed for abbreviated attributes) prefix_to_elm = {'src': 'source', 'tgt': 'target', 'opt': 'options'} @@ -2406,9 +2406,11 @@ format an action depending on the action's type. A dict which contains the formatted str's is returned. """ - def prj_pkg_join(prj, pkg): + def prj_pkg_join(prj, pkg, repository=None): if not pkg: - return prj or '' + if not repository: + return prj or '' + return '%s(%s)' % (prj, repository) return '%s/%s' % (prj, pkg) d = {'type': '%s:' % action.type} @@ -2450,7 +2452,7 @@ d['target'] = prj_pkg_join(action.tgt_project, action.tgt_package) elif action.type == 'delete': d['source'] = '' - d['target'] = prj_pkg_join(action.tgt_project, action.tgt_package) + d['target'] = prj_pkg_join(action.tgt_project, action.tgt_package, action.tgt_repository) return d def list_view(self): @@ -5121,11 +5123,13 @@ f = http_GET(u) return f.read() -def get_buildinfo(apiurl, prj, package, repository, arch, specfile=None, addlist=None): +def get_buildinfo(apiurl, prj, package, repository, arch, specfile=None, addlist=None, debug=None): query = [] if addlist: for i in addlist: query.append('add=%s' % quote_plus(i)) + if debug: + query.append('debug=1') u = makeurl(apiurl, ['build', prj, repository, arch, package, '_buildinfo'], query=query) @@ -5644,11 +5648,39 @@ """ res = {} for urlpath, xpath in kwargs.iteritems(): - u = makeurl(apiurl, ['search', urlpath], ['match=%s' % quote_plus(xpath)]) + path = [ 'search' ] + path += urlpath.split('_') # FIXME: take underscores as path seperators. I see no other way atm to fix OBS api calls and not breaking osc api + u = makeurl(apiurl, path, ['match=%s' % quote_plus(xpath)]) f = http_GET(u) res[urlpath] = ET.parse(f).getroot() return res +def owner(apiurl, binary, attribute=None, project=None, usefilter=None, devel=None, limit=None): + """ + Perform a binary package owner search. This is supported since OBS 2.4. + """ + # find default project, if not specified + query = { 'binary': binary } + if attribute: + query['attribute'] = attribute + if project: + query['project'] = project + if devel: + query['devel'] = devel + if limit != None: + query['limit'] = limit + if usefilter: + query['filter'] = ",".join(usefilter) + u = makeurl(apiurl, [ 'search', 'owner' ], query) + res = None + try: + f = http_GET(u) + res = ET.parse(f).getroot() + except urllib2.HTTPError, e: + # old server not supporting this search + pass + return res + def set_link_rev(apiurl, project, package, revision='', expand=False, baserev=False): """ updates the rev attribute of the _link xml. If revision is set to None @@ -5824,6 +5856,35 @@ else: print "an error occured" +def setBugowner(apiurl, prj, pac, user=None, group=None): + """ delete all bugowners (user and group entries) and set one new one in a package or project """ + path = quote_plus(prj), + kind = 'prj' + if pac: + path = path + (quote_plus(pac), ) + kind = 'pkg' + data = meta_exists(metatype=kind, + path_args=path, + template_args=None, + create_new=False) + if data: + root = ET.fromstring(''.join(data)) + for group in root.getiterator('group'): + if group.get('role') == "bugowner": + root.remove(group) + for person in root.getiterator('person'): + if person.get('role') == "bugowner": + root.remove(person) + if user: + root.insert(2, ET.Element('person', role='bugowner', userid=user)) + elif group: + root.insert(2, ET.Element('group', role='bugowner', groupid=group)) + else: + print "Neither user nor group is specified" + edit_meta(metatype=kind, + path_args=path, + data=ET.tostring(root)) + def setDevelProject(apiurl, prj, pac, dprj, dpkg=None): """ set the <devel project="..."> element to package metadata""" path = (quote_plus(prj),) + (quote_plus(pac),) @@ -6118,12 +6179,21 @@ for r in requests: print r.list_view(), '\n' -def request_interactive_review(apiurl, request, initial_cmd='', group=None): +def request_interactive_review(apiurl, request, initial_cmd='', group=None, ignore_reviews=False): """review the request interactively""" import tempfile, re tmpfile = None + def safe_change_request_state(*args, **kwargs): + try: + change_request_state(*args, **kwargs) + return True + except urllib2.HTTPError, e: + print >>sys.stderr, 'Server returned an error:', e + print >>sys.stderr, 'Try -f to force the state change' + return False + def print_request(request): print request @@ -6189,12 +6259,13 @@ prompt = 'd(i)ff/(a)ccept/(b)uildstatus/(e)dit/(s)kip/(c)ancel > ' else: state_map = {'a': 'accepted', 'd': 'declined', 'r': 'revoked'} - mo = re.search('^([adrl])(?:\s+-m\s+(.*))?$', repl) + mo = re.search('^([adrl])(?:\s+(-f)?\s*-m\s+(.*))?$', repl) if mo is None or orequest and mo.group(1) != 'a': print >>sys.stderr, 'invalid choice: \'%s\'' % repl continue state = state_map.get(mo.group(1)) - msg = mo.group(2) + force = mo.group(2) is not None + msg = mo.group(3) footer = '' msg_template = '' if not (state is None or request.state is None): @@ -6216,18 +6287,23 @@ msg = msg.strip('\'').strip('"') if not orequest is None: request.create(apiurl) - change_request_state(apiurl, request.reqid, 'accepted', msg) + if not safe_change_request_state(apiurl, request.reqid, 'accepted', msg, force=force): + # an error occured + continue repl = raw_input('Supersede original request? (y|N) ') if repl in ('y', 'Y'): - change_request_state(apiurl, orequest.reqid, 'superseded', - 'superseded by %s' % request.reqid, request.reqid) + safe_change_request_state(apiurl, orequest.reqid, 'superseded', + 'superseded by %s' % request.reqid, request.reqid, force=force) elif state is None: clone_request(apiurl, request.reqid, msg) else: reviews = [r for r in request.reviews if r.state == 'new'] - if not reviews: - change_request_state(apiurl, request.reqid, state, msg) - break + if not reviews or ignore_reviews: + if safe_change_request_state(apiurl, request.reqid, state, msg, force=force): + break + else: + # an error occured + continue group_reviews = [r for r in reviews if (r.by_group is not None and r.by_group == group)] if len(group_reviews) == 1 and conf.config['review_inherit_group']: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/osc-0.136.0/osc/fetch.py new/osc-0.137.0/osc/fetch.py --- old/osc-0.136.0/osc/fetch.py 2012-09-27 21:46:58.000000000 +0200 +++ new/osc-0.137.0/osc/fetch.py 2012-12-04 16:45:58.000000000 +0100 @@ -5,6 +5,8 @@ import sys, os import urllib2 +from urllib import quote_plus + from urlgrabber.grabber import URLGrabError from urlgrabber.mirror import MirrorGroup from core import makeurl, streamfile @@ -89,47 +91,63 @@ prpap = '%s/%s/%s/%s' % (pac.project, pac.repository, pac.repoarch, pac.repopackage) self.cpio.setdefault(prpap, {})[pac.repofilename] = pac + def __download_cpio_archive(self, apiurl, project, repo, arch, package, **pkgs): + if not pkgs: + return + query = ['binary=%s' % quote_plus(i) for i in pkgs] + query.append('view=cpio') + tmparchive = tmpfile = None + try: + (fd, tmparchive) = tempfile.mkstemp(prefix='osc_build_cpio') + (fd, tmpfile) = tempfile.mkstemp(prefix='osc_build') + url = makeurl(apiurl, ['build', project, repo, arch, package], query=query) + sys.stdout.write("preparing download ...\r") + sys.stdout.flush() + self.gr.urlgrab(url, filename = tmparchive, text = 'fetching packages for \'%s\'' % project) + archive = cpio.CpioRead(tmparchive) + archive.read() + for hdr in archive: + # XXX: we won't have an .errors file because we're using + # getbinarylist instead of the public/... route (which is + # routed to getbinaries (but that won't work for kiwi products)) + if hdr.filename == '.errors': + archive.copyin_file(hdr.filename) + raise oscerr.APIError('CPIO archive is incomplete (see .errors file)') + if package == '_repository': + n = re.sub(r'\.pkg\.tar\..z$', '.arch', hdr.filename) + pac = pkgs[n.rsplit('.', 1)[0]] + else: + # this is a kiwi product + pac = pkgs[hdr.filename] + archive.copyin_file(hdr.filename, os.path.dirname(tmpfile), os.path.basename(tmpfile)) + self.move_package(tmpfile, pac.localdir, pac) + # check if we got all packages... (because we've no .errors file) + for pac in pkgs.itervalues(): + if not os.path.isfile(pac.fullfilename): + raise oscerr.APIError('failed to fetch file \'%s\': ' \ + 'does not exist in CPIO archive' % pac.repofilename) + except URLGrabError, e: + if e.errno != 14 or e.code != 414: + raise + # query str was too large + keys = pkgs.keys() + if len(keys) == 1: + raise oscerr.APIError('unable to fetch cpio archive: server always returns code 414') + n = len(pkgs) / 2 + new_pkgs = dict([(k, pkgs[k]) for k in keys[:n]]) + self.__download_cpio_archive(apiurl, project, repo, arch, package, **new_pkgs) + new_pkgs = dict([(k, pkgs[k]) for k in keys[n:]]) + self.__download_cpio_archive(apiurl, project, repo, arch, package, **new_pkgs) + finally: + if not tmparchive is None and os.path.exists(tmparchive): + os.unlink(tmparchive) + if not tmpfile is None and os.path.exists(tmpfile): + os.unlink(tmpfile) + def __fetch_cpio(self, apiurl): - from urllib import quote_plus for prpap, pkgs in self.cpio.iteritems(): project, repo, arch, package = prpap.split('/', 3) - query = ['binary=%s' % quote_plus(i) for i in pkgs.keys()] - query.append('view=cpio') - tmparchive = tmpfile = None - try: - (fd, tmparchive) = tempfile.mkstemp(prefix='osc_build_cpio') - (fd, tmpfile) = tempfile.mkstemp(prefix='osc_build') - url = makeurl(apiurl, ['build', project, repo, arch, package], query=query) - sys.stdout.write("preparing download ...\r") - sys.stdout.flush() - self.gr.urlgrab(url, filename = tmparchive, text = 'fetching packages for \'%s\'' % project) - archive = cpio.CpioRead(tmparchive) - archive.read() - for hdr in archive: - # XXX: we won't have an .errors file because we're using - # getbinarylist instead of the public/... route (which is - # routed to getbinaries (but that won't work for kiwi products)) - if hdr.filename == '.errors': - archive.copyin_file(hdr.filename) - raise oscerr.APIError('CPIO archive is incomplete (see .errors file)') - if package == '_repository': - n = re.sub(r'\.pkg\.tar\..z$', '.arch', hdr.filename) - pac = pkgs[n.rsplit('.', 1)[0]] - else: - # this is a kiwi product - pac = pkgs[hdr.filename] - archive.copyin_file(hdr.filename, os.path.dirname(tmpfile), os.path.basename(tmpfile)) - self.move_package(tmpfile, pac.localdir, pac) - # check if we got all packages... (because we've no .errors file) - for pac in pkgs.itervalues(): - if not os.path.isfile(pac.fullfilename): - raise oscerr.APIError('failed to fetch file \'%s\': ' \ - 'does not exist in CPIO archive' % pac.repofilename) - finally: - if not tmparchive is None and os.path.exists(tmparchive): - os.unlink(tmparchive) - if not tmpfile is None and os.path.exists(tmpfile): - os.unlink(tmpfile) + self.__download_cpio_archive(apiurl, project, repo, arch, package, **pkgs) def fetch(self, pac, prefix=''): # for use by the failure callback ++++++ osc.dsc ++++++ --- /var/tmp/diff_new_pack.XneH5f/_old 2012-12-05 14:01:21.000000000 +0100 +++ /var/tmp/diff_new_pack.XneH5f/_new 2012-12-05 14:01:21.000000000 +0100 @@ -1,6 +1,6 @@ Format: 1.0 Source: osc -Version: 0.136.0 +Version: 0.137.0 Binary: osc Maintainer: Adrian Schroeter <[email protected]> Architecture: any -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
