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 "adrian@suse.com"
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 - adrian@suse.de
+
+- 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"> <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
Architecture: any
--
To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org
For additional commands, e-mail: opensuse-commit+help@opensuse.org