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]

Reply via email to