Hello community,

here is the log from the commit of package osc for openSUSE:Factory checked in 
at 2017-03-12 20:03:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/osc (Old)
 and      /work/SRC/openSUSE:Factory/.osc.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "osc"

Sun Mar 12 20:03:54 2017 rev:117 rq:477742 version:0.157.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/osc/osc.changes  2016-12-29 22:44:28.479330863 
+0100
+++ /work/SRC/openSUSE:Factory/.osc.new/osc.changes     2017-03-12 
20:03:55.414405854 +0100
@@ -1,0 +2,23 @@
+Wed Mar  8 12:14:32 UTC 2017 - [email protected]
+
+- 0.157.1
+  - fix local build of kiwi images using obsrepositories:// 
+
+-------------------------------------------------------------------
+Wed Mar  8 08:57:31 UTC 2017 - [email protected]
+
+- 0.157
+  - add unpublish command (requires OBS 2.8)
+  - add blame command (requires OBS 2.9)
+  - results: show multibuild results by default
+  - getbinaries: make .AppImage files executable
+  - support operation in checked out package for cat/less/blame
+  - add comment command
+  - improved build recipe selection
+  - added multibuild (-M) to commands:
+          buildlog, remotebuildlog, buildinfo, build, buildhistory, jobhistory,
+          rebuild, restartbuild/abortbuild, wipebinaries, getbinaries
+  - add checkconstraints command
+  - add workerinfo command
+
+-------------------------------------------------------------------

Old:
----
  osc-0.156.0.tar.gz

New:
----
  osc-0.157.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ osc.spec ++++++
--- /var/tmp/diff_new_pack.nweu3z/_old  2017-03-12 20:03:56.254287010 +0100
+++ /var/tmp/diff_new_pack.nweu3z/_new  2017-03-12 20:03:56.262285878 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package osc
 #
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,10 +16,10 @@
 #
 
 
-%define version_unconverted 0.156.0
+%define version_unconverted 0.157.1
 
 Name:           osc
-Version:        0.156.0
+Version:        0.157.1
 Release:        0
 Summary:        Open Build Service Commander
 License:        GPL-2.0+

++++++ PKGBUILD ++++++
--- /var/tmp/diff_new_pack.nweu3z/_old  2017-03-12 20:03:56.302280219 +0100
+++ /var/tmp/diff_new_pack.nweu3z/_new  2017-03-12 20:03:56.302280219 +0100
@@ -1,5 +1,5 @@
 pkgname=osc
-pkgver=0.156.0
+pkgver=0.157.1
 pkgrel=0
 pkgdesc="Open Build Service client"
 arch=('i686' 'x86_64')

++++++ _service ++++++
--- /var/tmp/diff_new_pack.nweu3z/_old  2017-03-12 20:03:56.326276823 +0100
+++ /var/tmp/diff_new_pack.nweu3z/_new  2017-03-12 20:03:56.330276257 +0100
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="disabled">
-    <param name="version">0.156.0</param>
-    <param name="revision">0.156.0</param>
+    <param name="version">0.157.1</param>
+    <param name="revision">0.157.1</param>
     <param name="url">git://github.com/openSUSE/osc.git</param>
     <param name="scm">git</param>
   </service>

++++++ debian.changelog ++++++
--- /var/tmp/diff_new_pack.nweu3z/_old  2017-03-12 20:03:56.362271730 +0100
+++ /var/tmp/diff_new_pack.nweu3z/_new  2017-03-12 20:03:56.374270032 +0100
@@ -1,4 +1,4 @@
-osc (0.156.0) unstable; urgency=low
+osc (0.157.1) unstable; urgency=low
   - Install bash completion
 
  -- Nick Brown <[email protected]>  Wed, 26 Oct 2016 10:00:00 +0200

++++++ osc-0.156.0.tar.gz -> osc-0.157.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.156.0/NEWS new/osc-0.157.1/NEWS
--- old/osc-0.156.0/NEWS        2016-12-19 14:47:45.000000000 +0100
+++ new/osc-0.157.1/NEWS        2017-03-08 13:10:35.000000000 +0100
@@ -1,3 +1,21 @@
+0.158
+  -
+
+0.157
+  - add unpublish command (requires OBS 2.8)
+  - add blame command (requires OBS 2.9)
+  - results: show multibuild results by default
+  - getbinaries: make .AppImage files executable
+  - support operation in checked out package for cat/less/blame
+  - add comment command
+  - improved build recipe selection
+  - added multibuild (-M) to commands:
+          buildlog, remotebuildlog, buildinfo, build, buildhistory, jobhistory,
+          rebuild, restartbuild/abortbuild, wipebinaries, getbinaries
+  - add checkconstraints command
+  - add workerinfo command
+  - fix local build of kiwi images using obsrepositories://
+
 0.156
   - highlight scheduled jobs with dispatch problems (due to constraints)
   - allow to specify a log message in lock command
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.156.0/dist/osc.complete 
new/osc-0.157.1/dist/osc.complete
--- old/osc-0.156.0/dist/osc.complete   2016-12-19 14:47:45.000000000 +0100
+++ new/osc-0.157.1/dist/osc.complete   2017-03-08 13:10:35.000000000 +0100
@@ -59,8 +59,8 @@
     --debug --apiurl -A --config -c --no-keyring --no-gnome-keyring --verbose 
--quiet)
 osccmds=(abortbuild add addremove aggregatepac api ar bco bl blt branch 
branchco
     bsdevelproject bse bugowner build buildconfig buildhist buildhistory 
buildinfo
-    buildlog buildlogtail cat changedevelreq changedevelrequest checkin 
checkout
-    chroot ci co commit config copypac cr createincident createrequest creq del
+    buildlog buildlogtail cat changedevelreq changedevelrequest 
checkconstraints checkin checkout
+    chroot ci co comment commit config copypac cr createincident createrequest 
creq del
     delete deletereq deleterequest dependson detachbranch develproject di diff
     distributions dists dr dropreq droprequest getbinaries getpac help 
importsrcpkg
     info init jobhist jobhistory lbl ldiff less linkdiff linkpac linktobranch 
list
@@ -73,11 +73,13 @@
     resolved results revert review rm rq rremove se search service setlinkrev
     signkey sm sr st status submitpac submitreq submitrequest tr triggerreason
     undelete unlock up update updatepacmetafromspec user vc whatdependson who 
whois
-    wipebinaries)
+    wipebinaries workerinfo)
 oscreq=(list log show accept decline revoke reopen setincident supersede 
approvenew
     checkout clone)
 oscrev=(show list add accept decline reopen supersede)
 oscmy=(work pkg prj rq sr)
+osccmt=(list create delete)
+osccmtkind=(package project request)
 
 oscprj=""
 oscpkg=""
@@ -1095,6 +1097,16 @@
        builtin compgen -W "${opts[*]}" -- "${cmdline[3]}"
     fi
     ;;
+comment)
+    opts=(--comment --parent)
+    if ((count == 1)) ; then
+        builtin compgen -W "${osccmds[*]}" -- "${cmdline[count]}"
+    elif ((count == 2)) ; then
+        builtin compgen -W "${opts[*]} ${osccmt[*]}" -- "${cmdline[2]}"
+    elif ((count == 3)) ; then
+        builtin compgen -W "${opts[*]} ${osccmtkind[*]}" -- "${cmdline[3]}"
+    fi
+    ;;
 copypac|linkpac)
     opts=(--help --expand --to-apiurl --revision --keep-develproject 
--keep-link
          --keep-maintainers --client-side-copy)
@@ -1396,7 +1408,7 @@
     opts=(--help --role --delete --set-bugowner-request --set-bugowner --all 
--add
          --devel-project --verbose --nodevelproject --email --bugowner 
--bugowner-only)
     if ((count == 1)) ; then
-       builtin compgen -W "${osccmds[*]}" -- "${cmdline[count]}"
+        builtin compgen -W "${osccmds[*]}" -- "${cmdline[count]}"
     elif ((count >= 2)) ; then
        for ((off=2; off<=count; off++)) ; do
            while test "${cmdline[off+remove]::1}" = "-" ; do
@@ -1812,6 +1824,30 @@
        builtin compgen -W "${opts[*]}" -- "${cmdline[count]}"
     fi
     ;;
+workerinfo)
+    opts=(--help)
+    if ((count == 1)) ; then
+        builtin compgen -W "${osccmds[*]} ${oscopts[*]}" -- "${cmdline[count]}"
+    elif ((count >= 2)) ; then
+        if test "${cmdline[count]::1}" = "-" ; then
+            builtin compgen -W "${opts[*]}" -- "${cmdline[count]}"
+        else
+            targets ${opts[*]} -- "${cmdline[count]}"
+        fi
+    fi
+    ;;
+checkconstraints)
+    opts=(--help --ignore-file)
+    if ((count == 1)) ; then
+        builtin compgen -W "${osccmds[*]} ${oscopts[*]}" -- "${cmdline[count]}"
+    elif ((count >= 2)) ; then
+        if test "${cmdline[count]::1}" = "-" ; then
+            builtin compgen -W "${opts[*]}" -- "${cmdline[count]}"
+        else
+            targets ${opts[*]} -- "${cmdline[count]}"
+        fi
+    fi
+    ;;
 *)
     opts=(--help)
     if ((count == 1)) ; then
@@ -1822,5 +1858,5 @@
        else
            targets ${opts[*]} -- "${cmdline[count]}"
        fi
-    fi 
+    fi
 esac
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.156.0/osc/babysitter.py 
new/osc-0.157.1/osc/babysitter.py
--- old/osc-0.156.0/osc/babysitter.py   2016-12-19 14:47:45.000000000 +0100
+++ new/osc-0.157.1/osc/babysitter.py   2017-03-08 13:10:35.000000000 +0100
@@ -143,7 +143,7 @@
         print('Failed to reach a server:\n', e.reason, file=sys.stderr)
         return 1
     except URLGrabError as e:
-        print('Failed to grab %s: %s' % (e.url, e.exception), file=sys.stderr)
+        print('Failed to grab %s: %s' % (e.url, e.strerror), file=sys.stderr)
         return 1
     except IOError as e:
         # ignore broken pipe
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.156.0/osc/build.py new/osc-0.157.1/osc/build.py
--- old/osc-0.156.0/osc/build.py        2016-12-19 14:47:45.000000000 +0100
+++ new/osc-0.157.1/osc/build.py        2017-03-08 13:10:35.000000000 +0100
@@ -1009,7 +1009,7 @@
                       buildargs.append('--kiwi-parameter')
                       buildargs.append('--add-repo')
                       buildargs.append('--kiwi-parameter')
-                      buildargs.append("repos/"+path)
+                      buildargs.append("dir://./repos/"+path)
                       buildargs.append('--kiwi-parameter')
                       buildargs.append('--add-repotype')
                       buildargs.append('--kiwi-parameter')
@@ -1027,7 +1027,7 @@
                    buildargs.append('--kiwi-parameter')
                    buildargs.append('--add-repo')
                    buildargs.append('--kiwi-parameter')
-                   buildargs.append("repos/"+project+"/"+repo)
+                   buildargs.append("dir://./repos/"+project+"/"+repo)
                    buildargs.append('--kiwi-parameter')
                    buildargs.append('--add-repotype')
                    buildargs.append('--kiwi-parameter')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.156.0/osc/commandline.py 
new/osc-0.157.1/osc/commandline.py
--- old/osc-0.156.0/osc/commandline.py  2016-12-19 14:47:45.000000000 +0100
+++ new/osc-0.157.1/osc/commandline.py  2017-03-08 13:10:35.000000000 +0100
@@ -441,6 +441,7 @@
                     opts.expand = True
                 if fname and print_not_found:
                     print('file \'%s\' does not exist' % fname)
+                    return 1
 
 
     @cmdln.option('-s', '--skip-disabled', action='store_true',
@@ -724,6 +725,8 @@
             fd = urlopen(req, data=None)
             print(fd.read())
         else:
+            if args and args[0] in ['create', 'delete', 'trigger']:
+                raise oscerr.WrongArgs("Did you mean --" + args[0] + "?")
             # just list token
             for data in streamfile(url, http_GET):
                 sys.stdout.write(data)
@@ -1078,6 +1081,20 @@
 
         ${cmd_option_list}
         """
+        def _check_service(root):
+            serviceinfo = root.find('serviceinfo')
+            if serviceinfo is not None:
+                # code "running" is ok, because the api will choke when trying
+                # to create the sr (if it is still running)
+                if serviceinfo.get('code') not in ('running', 'succeeded'):
+                    print('A service run for package %s %s:'
+                          % (root.get('name'), serviceinfo.get('code')),
+                          file=sys.stderr)
+                    error = serviceinfo.find('error')
+                    if error is not None:
+                        print('\n'.join(error.text.split('\\n')))
+                    sys.exit('\nPlease fix this first')
+
 
         if opts.cleanup and opts.no_cleanup:
             raise oscerr.WrongOptions('\'--cleanup\' and \'--no-cleanup\' are 
mutually exclusive')
@@ -1176,14 +1193,8 @@
                         print("Skipping package ", p,  " since it is a source 
link pointing inside the project.")
                         continue
 
-                serviceinfo = root.find('serviceinfo')
-                if serviceinfo != None:
-                    if serviceinfo.get('code') != "succeeded":
-                        print("Package ", p, " has a ", 
serviceinfo.get('code'), " source service")
-                        sys.exit("Please fix this first")
-                    if serviceinfo.get('error'):
-                        print("Package ", p, " contains a failed source 
service.")
-                        sys.exit("Please fix this first")
+                # check for failed source service
+                _check_service(root)
 
                 # submitting this package
                 if opts.separate_requests or opts.seperate_requests:
@@ -1269,18 +1280,11 @@
             raise oscerr.WrongArgs('Incorrect number of arguments.\n\n' \
                   + self.get_cmd_help('request'))
 
-        # check for running source service
+        # check for failed source service
         u = makeurl(apiurl, ['source', src_project, src_package])
         f = http_GET(u)
         root = ET.parse(f).getroot()
-        serviceinfo = root.find('serviceinfo')
-        if serviceinfo != None:
-            if serviceinfo.get('code') != "succeeded":
-                print("Package ", src_package, " has a ", 
serviceinfo.get('code'), " source service")
-                sys.exit("Please fix this first")
-            if serviceinfo.get('error'):
-                print("Package ", src_package, " contains a failed source 
service.")
-                sys.exit("Please fix this first")
+        _check_service(root)
 
         if not opts.nodevelproject:
             devloc = None
@@ -1332,7 +1336,7 @@
             return
         supersede_existing = False
         reqs = []
-        if not opts.supersede:
+        if not opts.supersede and not opts.yes:
             (supersede_existing, reqs) = check_existing_requests(apiurl,
                                                                  src_project,
                                                                  src_package,
@@ -2944,7 +2948,7 @@
     def do_releaserequest(self, subcmd, opts, *args):
         """${cmd_name}: Create a request for releasing a maintenance update.
 
-        [See 
http://doc.opensuse.org/products/draft/OBS/obs-reference-guide_draft/cha.obs.maintenance_setup.html
+        [See 
http://openbuildservice.org/help/manuals/obs-reference-guide/cha.obs.maintenance_setup.html
          for information on this topic.]
 
         This command is used by the maintence team to start the release 
process of a maintenance update.
@@ -2990,7 +2994,7 @@
     def do_createincident(self, subcmd, opts, *args):
         """${cmd_name}: Create a maintenance incident
 
-        [See 
http://doc.opensuse.org/products/draft/OBS/obs-reference-guide_draft/cha.obs.maintenance_setup.html
+        [See 
http://openbuildservice.org/help/manuals/obs-reference-guide/cha.obs.maintenance_setup.html
         for information on this topic.]
 
         This command is asking to open an empty maintence incident. This can 
usually only be done by a responsible
@@ -3062,7 +3066,7 @@
     def do_maintenancerequest(self, subcmd, opts, *args):
         """${cmd_name}: Create a request for starting a maintenance incident.
 
-        [See 
http://doc.opensuse.org/products/draft/OBS/obs-reference-guide_draft/cha.obs.maintenance_setup.html
+        [See 
http://openbuildservice.org/help/manuals/obs-reference-guide/cha.obs.maintenance_setup.html
         for information on this topic.]
 
         This command is asking the maintence team to start a maintence 
incident based on a
@@ -4185,10 +4189,10 @@
     @cmdln.option('-M', '--meta', action='store_true',
                         help='checkout out meta data instead of sources' )
     @cmdln.option('-c', '--current-dir', action='store_true',
-                        help='place PACKAGE folder in the current directory' \
+                        help='place PACKAGE folder in the current directory ' \
                              'instead of a PROJECT/PACKAGE directory')
     @cmdln.option('-o', '--output-dir', metavar='outdir',
-                        help='place package in the specified directory' \
+                        help='place package in the specified directory ' \
                              'instead of a PROJECT/PACKAGE directory')
     @cmdln.option('-s', '--source-service-files', action='store_true',
                         help='Run source services.' )
@@ -4977,8 +4981,8 @@
                         help='Show results only for specified architecture(s)')
     @cmdln.option('-v', '--verbose', action='store_true', default=False,
                         help='more verbose output')
-    @cmdln.option('-m', '--multibuild', action='store_true', default=False,
-                        help='Show results for all packages in multibuild')
+    @cmdln.option('--no-multibuild', action='store_true', default=False,
+                        help='Disable results for all direct affect packages 
inside of the project')
     @cmdln.option('-M', '--multibuild-package', action='append', default=[],
                         help='Only show results for the specified multibuild 
package')
     @cmdln.option('-w', '--watch', action='store_true', default=False,
@@ -5040,16 +5044,17 @@
                   'lastbuild': opts.last_build, 'repository': opts.repo,
                   'arch': opts.arch, 'wait': opts.watch}
         if opts.multibuild_package:
-            opts.multibuild = True
+            opts.no_multibuild = False
             kwargs['multibuild_packages'] = opts.multibuild_package
-        kwargs['multibuild'] = kwargs['locallink'] = opts.multibuild
+        if not opts.no_multibuild:
+            kwargs['multibuild'] = kwargs['locallink'] = True
         if opts.xml or opts.csv:
             for xml in get_package_results(**kwargs):
                 if opts.xml:
                     print(xml, end='')
                 else:
                     # csv formatting
-                    results = result_xml_to_dicts(xml)
+                    results = [r for r, _ in result_xml_to_dicts(xml)]
                     print('\n'.join(format_results(results, opts.format)))
         else:
             kwargs['verbose'] = opts.verbose
@@ -5137,6 +5142,8 @@
     @cmdln.alias('buildlogtail')
     @cmdln.option('-l', '--last', action='store_true',
                         help='Show the last finished log file')
+    @cmdln.option('-M', '--multibuild-package', metavar='MPAC',
+                    help='get log of the specified multibuild package')
     @cmdln.option('-o', '--offset', metavar='OFFSET',
                     help='get log start or end from the offset')
     @cmdln.option('-s', '--strip-time', action='store_true',
@@ -5184,6 +5191,9 @@
                 repository = args[0]
                 arch = args[1]
 
+        if opts.multibuild_package:
+            package = package + ":" + opts.multibuild_package
+
         offset = 0
         if subcmd == "blt" or subcmd == "buildlogtail":
             query = { 'view': 'entry' }
@@ -5231,6 +5241,8 @@
     @cmdln.alias('remotebuildlogtail')
     @cmdln.option('-l', '--last', action='store_true',
                         help='Show the last finished log file')
+    @cmdln.option('-M', '--multibuild-package', metavar='MPAC',
+                        help='show log file for specified multibuild package')
     @cmdln.option('-o', '--offset', metavar='OFFSET',
                     help='get log starting or ending from the offset')
     @cmdln.option('-s', '--strip-time', action='store_true',
@@ -5263,6 +5275,9 @@
             else:
                 project, package, repository, arch = args
 
+        if opts.multibuild_package:
+            package = package + ":" + opts.multibuild_package
+
         offset = 0
         if subcmd == "rblt" or subcmd == "rbuildlogtail" or subcmd == 
"remotebuildlogtail":
             query = { 'view': 'entry' }
@@ -5491,6 +5506,8 @@
 
     @cmdln.option('-d', '--debug', action='store_true',
                   help='verbose output of build dependencies')
+    @cmdln.option('-M', '--multibuild-package', metavar='MPAC',
+                  help='Show the buildinfo of the specified multibuild 
package')
     @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',
@@ -5538,7 +5555,7 @@
                 raise oscerr.WrongArgs('Incorrect number of arguments (Note: 
\'.\' is no package wc)')
             project = store_read_project('.')
             package = store_read_package('.')
-            repository, arch, build_descr = self.parse_repoarchdescr(args, 
ignore_descr=True)
+            repository, arch, build_descr = self.parse_repoarchdescr(args, 
ignore_descr=True, multibuild_package=opts.multibuild_package)
         elif len(args) == 4 or len(args) == 5:
             project = args[0]
             package = args[1]
@@ -5567,6 +5584,9 @@
             cpiodata.add(os.path.basename(build_descr), build_descr_data)
             build_descr_data = cpiodata.get()
 
+        if opts.multibuild_package:
+            package = package + ":" + opts.multibuild_package
+
         print(''.join(get_buildinfo(apiurl,
                                     project, package, repository, arch,
                                     specfile=build_descr_data,
@@ -5617,6 +5637,74 @@
         print(''.join(get_buildconfig(apiurl, project, repository)))
 
 
+    def do_workerinfo(self, subcmd, opts, worker):
+        """${cmd_name}: gets the information to a worker from the server
+
+        Examples:
+            osc workerinfo <workername>
+
+        ${cmd_usage}
+        ${cmd_option_list}
+        """
+        apiurl = self.get_api_url()
+        print(''.join(get_worker_info(apiurl, worker)))
+
+
+    @cmdln.option('', '--ignore-file', action='store_true',
+                  help='ignore _constraints file and only check project 
constraints')
+    def do_checkconstraints(self, subcmd, opts, *args):
+        """${cmd_name}: check the constraints and view compliant workers
+
+        Checks the constraints for compliant workers.
+
+        usage:
+            in a package working copy:
+                osc checkconstraints [OPTS] REPOSITORY ARCH CONSTRAINTSFILE
+                osc checkconstraints [OPTS] CONSTRAINTSFILE
+                osc checkconstraints [OPTS]
+
+        ${cmd_option_list}
+        """
+        repository = arch = constraintsfile = None
+        project = store_read_project('.')
+        package = store_read_package('.')
+        if len(args) == 1:
+            constraintsfile = args[0]
+        elif len(args) == 2 or len(args) == 3:
+            repository = args[0]
+            arch = args[1]
+            if len(args) == 3:
+                constraintsfile = args[2]
+
+        constraintsfile_data = None
+        if constraintsfile is not None:
+            constraintsfile_data = open(constraintsfile, 'r').read()
+        elif not opts.ignore_file:
+            if os.path.isfile("_constraints"):
+                constraintsfile_data = open("_constraints", 'r').read()
+            else:
+                print("No local _constraints file. Using just the project 
constraints")
+
+        apiurl = self.get_api_url()
+        r = []
+        if not arch and not repository:
+            result_line_templ = '%(name)-25s %(arch)-25s %(comp_workers)s'
+            for repo in get_repos_of_project(apiurl, project):
+                rmap = {}
+                rmap['name'] = repo.name
+                rmap['arch'] = repo.arch
+                workers = check_constraints(apiurl, project, repo.name, 
repo.arch, package, constraintsfile_data)
+                rmap['comp_workers'] = len(workers)
+                r.append(result_line_templ % rmap)
+            r.insert(0, 'Repository                Arch                      
Worker')
+            r.insert(1, '----------                ----                      
------')
+        else:
+            r = check_constraints(apiurl, project, repository, arch, package, 
constraintsfile_data)
+            r.insert(0, 'Worker')
+            r.insert(1, '------')
+
+        print('\n'.join(r))
+
     @cmdln.alias('repos')
     @cmdln.alias('platforms')
     def do_repositories(self, subcmd, opts, *args):
@@ -5669,10 +5757,11 @@
                 print(row)
 
 
-    def parse_repoarchdescr(self, args, noinit = False, alternative_project = 
None, ignore_descr = False, vm_type = None):
+    def parse_repoarchdescr(self, args, noinit = False, alternative_project = 
None, ignore_descr = False, vm_type = None, multibuild_package = None):
         """helper to parse the repo, arch and build description from args"""
         import osc.build
         import glob
+        import tempfile
         arg_arch = arg_repository = arg_descr = None
         if len(args) < 3:
             # some magic, works only sometimes, but people seem to like it :/
@@ -5717,15 +5806,18 @@
                 # only persist our own repos
                 Repo.tofile(repolistfile, repositories)
 
+        no_repo = False
         repo_names = sorted(set([r.name for r in repositories]))
         if not arg_repository and repositories:
             # XXX: we should avoid hardcoding repository names
             # Use a default value from config, but just even if it's available
             # unless try standard, or openSUSE_Factory, or openSUSE_Tumbleweed
+            no_repo = True
             arg_repository = repositories[-1].name
             for repository in (conf.config['build_repository'], 'standard', 
'openSUSE_Factory', 'openSUSE_Tumbleweed'):
                 if repository in repo_names:
                     arg_repository = repository
+                    no_repo = False
                     break
 
         if not arg_repository:
@@ -5749,22 +5841,39 @@
         elif not arg_descr:
             msg = None
             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)
+                if no_repo:
+                    raise oscerr.WrongArgs("Repository is missing. Cannot 
guess build description without repository")
+                apiurl = self.get_api_url()
+                project = store_read_project('.')
+                bc = get_buildconfig(apiurl, project, arg_repository)
+                with tempfile.NamedTemporaryFile() as f:
+                    f.write(bc)
+                    f.flush()
+                    recipe = return_external('/usr/lib/build/queryconfig', 
'--dist', f.name, 'type')
+                recipe = recipe.strip()
+                if recipe == 'arch':
+                    recipe = 'PKGBUILD'
                 pac = os.path.basename(os.getcwd())
                 if is_package_dir(os.getcwd()):
                     pac = store_read_package(os.getcwd())
-                extensions = ['spec', 'dsc', 'kiwi', 'livebuild']
-                cands = [i for i in descr for ext in extensions if i == 
'%s-%s.%s' % (pac, arg_repository, ext)]
+                if multibuild_package:
+                    pac = multibuild_package
+                if recipe == 'PKGBUILD':
+                    cands = [d for d in descr if d.startswith(recipe)]
+                else:
+                    cands = [d for d in descr if d.endswith('.' + recipe)]
+                if len(cands) > 1:
+                    repo_cands = [d for d in cands if d == '%s-%s.%s' % (pac, 
arg_repository, recipe)]
+                    if repo_cands:
+                        cands = repo_cands
+                    else:
+                        pac_cands = [d for d in cands if d == '%s.%s' % (pac, 
recipe)]
+                        if pac_cands:
+                            cands = pac_cands
                 if len(cands) == 1:
                     arg_descr = cands[0]
-                else:
-                    cands = [i for i in descr for ext in extensions if i == 
'%s.%s' % (pac, ext)]
-                    if len(cands) == 1:
-                        arg_descr = cands[0]
                 if not arg_descr:
-                    msg = 'Multiple build description files found: %s' % ', 
'.join(descr)
+                    msg = 'Multiple build description files found: %s' % ', 
'.join(cands)
             elif not ignore_descr:
                 msg = 'Missing argument: build description (spec, dsc, kiwi or 
livebuild file)'
                 try:
@@ -5805,6 +5914,8 @@
                   help='Prefer packages from this directory when installing 
the build-root')
     @cmdln.option('-k', '--keep-pkgs', metavar='DIR',
                   help='Save built packages into this directory')
+    @cmdln.option('-M', '--multibuild-package', metavar='MPAC',
+                  help='Build the specified multibuild package')
     @cmdln.option('-x', '--extra-pkgs', metavar='PAC', action='append',
                   help='Add this package when installing the build-root')
     @cmdln.option('--root', metavar='ROOT',
@@ -5923,7 +6034,7 @@
         if len(args) > 3:
             raise oscerr.WrongArgs('Too many arguments')
 
-        args = self.parse_repoarchdescr(args, opts.noinit or opts.offline, 
opts.alternative_project, False, opts.vm_type)
+        args = self.parse_repoarchdescr(args, opts.noinit or opts.offline, 
opts.alternative_project, False, opts.vm_type, opts.multibuild_package)
 
         # check for source services
         r = None
@@ -6201,6 +6312,8 @@
                         help='generate output in CSV (separated by |)')
     @cmdln.option('-l', '--limit', metavar='limit',
                         help='for setting the number of results')
+    @cmdln.option('-M', '--multibuild-package', metavar= 'MPAC',
+                        help='Show the buildhistory of the specified 
multibuild package')
     @cmdln.alias('buildhist')
     def do_buildhistory(self, subcmd, opts, *args):
         """${cmd_name}: Shows the build history of a package
@@ -6235,6 +6348,9 @@
         else:
             raise oscerr.WrongArgs('Wrong number of arguments')
 
+        if opts.multibuild_package:
+            package = package + ":" + opts.multibuild_package
+
         format = 'text'
         if opts.csv:
             format = 'csv'
@@ -6245,6 +6361,8 @@
                         help='generate output in CSV (separated by |)')
     @cmdln.option('-l', '--limit', metavar='limit',
                         help='for setting the number of results')
+    @cmdln.option('-M', '--multibuild-package', metavar='MPAC',
+                        help='get jobhistory for the specified multibuild 
package')
     @cmdln.alias('jobhist')
     def do_jobhistory(self, subcmd, opts, *args):
         """${cmd_name}: Shows the job history of a project
@@ -6287,6 +6405,9 @@
         else:
             raise oscerr.WrongArgs('Wrong number of arguments')
 
+        if opts.multibuild_package and package is not None:
+            package = package + ":" + opts.multibuild_package
+
         format = 'text'
         if opts.csv:
             format = 'csv'
@@ -6449,6 +6570,8 @@
                         help='trigger rebuilds for a specific repository')
     @cmdln.option('-f', '--failed', action='store_true',
                   help='rebuild all failed packages')
+    @cmdln.option('-M', '--multibuild-package', action='append',
+                  help='rebuild specified multibuild package')
     @cmdln.option('--all', action='store_true',
                         help='Rebuild all packages of entire project')
     @cmdln.alias('rebuildpac')
@@ -6505,7 +6628,15 @@
         if not (opts.all or package or repo or arch or code):
             raise oscerr.WrongOptions('No option has been provided. If you 
want to rebuild all packages of the entire project, use --all option.')
 
-        print(rebuild(apiurl, project, package, repo, arch, code))
+        packages = []
+        if opts.multibuild_package:
+            for subpackage in opts.multibuild_package:
+                packages.append(package + ":" + subpackage)
+        else:
+            packages.append(package)
+
+        for package in packages:
+            print(rebuild(apiurl, project, package, repo, arch, code))
 
 
     def do_info(self, subcmd, opts, *args):
@@ -6527,6 +6658,8 @@
 
     @cmdln.option('-a', '--arch', metavar='ARCH',
                         help='Restart builds for a specific architecture')
+    @cmdln.option('-M', '--multibuild-package', action='append',
+                        help='Restart builds for specified multibuild package')
     @cmdln.option('-r', '--repo', metavar='REPO',
                         help='Restart builds for a specific repository')
     @cmdln.option('--all', action='store_true',
@@ -6573,11 +6706,21 @@
         if not (opts.all or package or repo or arch):
             raise oscerr.WrongOptions('No option has been provided. If you 
want to restart all packages of the entire project, use --all option.')
 
-        print(cmdbuild(apiurl, subcmd, project, package, arch, repo))
+        packages = []
+        if opts.multibuild_package:
+            for subpackage in opts.multibuild_package:
+                packages.append(package + ":" + subpackage)
+        else:
+            packages.append(package)
+
+        for package in packages:
+            print(cmdbuild(apiurl, subcmd, project, package, arch, repo))
 
 
     @cmdln.option('-a', '--arch', metavar='ARCH',
                         help='Delete all binary packages for a specific 
architecture')
+    @cmdln.option('-M', '--multibuild-package', action='append',
+                        help='Delete all binary packages for specified 
multibuild package')
     @cmdln.option('-r', '--repo', metavar='REPO',
                         help='Delete all binary packages for a specific 
repository')
     @cmdln.option('--build-disabled', action='store_true',
@@ -6590,6 +6733,7 @@
                         help='Delete all binaries of packages which have 
dependency errors')
     @cmdln.option('--all', action='store_true',
                         help='Delete all binaries regardless of the package 
status (previously default)')
+    @cmdln.alias("unpublish")
     def do_wipebinaries(self, subcmd, opts, *args):
         """${cmd_name}: Delete all binary packages of a certain project/package
 
@@ -6599,6 +6743,8 @@
         usage:
             osc wipebinaries OPTS                       # works in checked out 
project dir
             osc wipebinaries OPTS PROJECT [PACKAGE]
+            osc unpublish OPTS                       # works in checked out 
project dir
+            osc unpublish OPTS PROJECT [PACKAGE]
         ${cmd_option_list}
         """
 
@@ -6641,15 +6787,28 @@
         if len(codes) == 0:
             raise oscerr.WrongOptions('No option has been provided. If you 
want to delete all binaries, use --all option.')
 
-        # make a new request for each code= parameter
-        for code in codes:
-            print(wipebinaries(apiurl, project, package, opts.arch, opts.repo, 
code))
+        packages = []
+        if opts.multibuild_package:
+            for subpackage in opts.multibuild_package:
+                packages.append(package + ":" + subpackage)
+        else:
+            packages.append(package)
+
+        # make a new request for each code= parameter and for each package in 
packages
+        for package in packages:
+            for code in codes:
+                if subcmd == 'unpublish':
+                    print(unpublish(apiurl, project, package, opts.arch, 
opts.repo, code))
+                else:
+                    print(wipebinaries(apiurl, project, package, opts.arch, 
opts.repo, code))
 
 
     @cmdln.option('-q', '--quiet', action='store_true',
                   help='do not show downloading progress')
     @cmdln.option('-d', '--destdir', default='./binaries', metavar='DIR',
                   help='destination directory')
+    @cmdln.option('-M', '--multibuild-package', action='append',
+                  help='get binaries from specified multibuild package')
     @cmdln.option('--sources', action="store_true",
                   help='also fetch source packages')
     @cmdln.option('--debug', action="store_true",
@@ -6713,10 +6872,17 @@
         if architecture is None:
             arches = [i.arch for i in repos if repository == i.name]
 
+
         if package is None:
             package = meta_get_packagelist(apiurl, project)
         else:
-            package = [package]
+            if opts.multibuild_package:
+                packages = []
+                for subpackage in opts.multibuild_package:
+                    packages.append(package + ":" + subpackage)
+                package = packages
+            else:
+                package = [package]
 
         # Set binary target directory and create if not existing
         target_dir = os.path.normpath(opts.destdir)
@@ -7768,16 +7934,24 @@
                   help='always work with unexpanded packages.')
     @cmdln.option('-M', '--meta', action='store_true',
                         help='list meta data files')
+    @cmdln.alias('blame')
     @cmdln.alias('less')
     def do_cat(self, subcmd, opts, *args):
         """${cmd_name}: Output the content of a file to standard output
 
         Examples:
+            osc cat file
             osc cat project package file
             osc cat project/package/file
             osc cat http://api.opensuse.org/build/.../_log
             osc cat http://api.opensuse.org/source/../_link
 
+            osc less file
+            osc less project package file
+
+            osc blame file
+            osc blame project package file
+
         ${cmd_usage}
         ${cmd_option_list}
         """
@@ -7790,22 +7964,32 @@
             opts.file = None
             return self.do_api('list', opts, *args)
 
-
-
         args = slash_split(args)
-        if len(args) != 3:
+        project = package = filename = None
+        if len(args) == 3:
+            project = args[0]
+            package = args[1]
+            filename = args[2]
+        elif len(args) == 1 and is_package_dir(os.getcwd()):
+            project = store_read_project(os.curdir)
+            package = store_read_package(os.curdir)
+            filename = args[0]
+        else:
             raise oscerr.WrongArgs('Wrong number of arguments.')
+
         rev, dummy = parseRevisionOption(opts.revision)
         apiurl = self.get_api_url()
 
         query = { }
+        if subcmd == 'blame':
+            query['view'] = "blame"
         if opts.meta:
             query['meta'] = 1
         if opts.revision:
             query['rev'] = opts.revision
         if opts.expand:
-            query['rev'] = show_upstream_srcmd5(apiurl, args[0], args[1], 
expand=True, revision=opts.revision, meta=opts.meta)
-        u = makeurl(apiurl, ['source', args[0], args[1], args[2]], query=query)
+            query['rev'] = show_upstream_srcmd5(apiurl, project, package, 
expand=True, revision=opts.revision, meta=opts.meta)
+        u = makeurl(apiurl, ['source', project, package, filename], 
query=query)
         try:
             if subcmd == 'less':
                 f = http_GET(u)
@@ -7816,8 +8000,8 @@
         except HTTPError as e:
             if e.code == 404 and not opts.expand and not opts.unexpand:
                 print('expanding link...', file=sys.stderr)
-                query['rev'] = show_upstream_srcmd5(apiurl, args[0], args[1], 
expand=True, revision=opts.revision)
-                u = makeurl(apiurl, ['source', args[0], args[1], args[2]], 
query=query)
+                query['rev'] = show_upstream_srcmd5(apiurl, project, package, 
expand=True, revision=opts.revision)
+                u = makeurl(apiurl, ['source', project, package, filename], 
query=query)
                 if subcmd == "less":
                     f = http_GET(u)
                     run_pager(''.join(f.readlines()))
@@ -8571,6 +8755,73 @@
                 if not opts.dry_run:
                     os.unlink(os.path.join(p.absdir, filename))
 
+    @cmdln.option('-c', '--comment',
+            help='comment text', metavar='COMMENT')
+    @cmdln.option('-p', '--parent',
+            help='reply to comment with parent id', metavar='PARENT')
+    def do_comment(self, subcmd, opts, *args):
+        """${cmd_name}: List / create / delete comments
+
+        On create:
+            If -p is given a reply to the ID is created. Otherwise
+            a toplevel comment is created.
+            If -c is not given the default editor will be opened and
+            you can type your comment
+
+        usage:
+            osc comment list package PROJECT PACKAGE
+            osc comment list project PROJECT
+            osc comment list request REQUEST_ID
+
+            osc comment create [-p PARENT_ID] [-c COMMENT] package PROJECT 
PACKAGE
+            osc comment create [-p PARENT_ID] [-c COMMENT] project PROJECT
+            osc comment create [-p PARENT_ID] [-c COMMENT] request REQUEST_ID
+
+            osc comment delete ID
+
+        """
+
+        comment = None
+        args = slash_split(args)
+        apiurl = self.get_api_url()
+
+        if len(args) < 2:
+            raise oscerr.WrongArgs('Incorrect number of arguments.\n\n' \
+                  + self.get_cmd_help('comment'))
+
+        cmds = ['list', 'create', 'delete']
+        if args[0] not in cmds:
+            raise oscerr.WrongArgs('Unknown comment action %s. Choose one of 
%s.' \
+                                                % (args[0], ', '.join(cmds)))
+
+        comment_targets = ['package', 'project', 'request']
+        if args[0] != 'delete' and args[1] not in comment_targets:
+            raise oscerr.WrongArgs('Unknown comment target %s. Choose one of 
%s.' \
+                                                % (args[1], ', 
'.join(comment_targets)))
+
+        if args[1] == 'package' and len(args) != 4:
+            raise oscerr.WrongArgs('Please use PROJECT PACKAGE')
+        elif args[1] == 'project' and len(args) != 3:
+            raise oscerr.WrongArgs('Please use PROJECT')
+        elif args[1] == 'request' and len(args) != 3:
+            raise oscerr.WrongArgs('Please use REQUEST')
+        elif args[0] == 'delete' and len(args) != 2:
+            raise oscerr.WrongArgs('Please use COMMENT_ID')
+        if not opts.comment and args[0] == 'create':
+            comment = edit_text()
+        else:
+            comment = opts.comment
+
+        if args[0] == 'list':
+            print_comments(apiurl, args[1], *args[2:])
+        elif args[0] == 'create':
+            result = create_comment(apiurl, args[1], comment,
+                                    *args[2:], parent=opts.parent)
+            print(result)
+        elif args[0] == 'delete':
+            result = delete_comment(apiurl, args[1])
+            print(result)
+
     def _load_plugins(self):
         plugin_dirs = [
             '/usr/lib/osc-plugins',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.156.0/osc/core.py new/osc-0.157.1/osc/core.py
--- old/osc-0.156.0/osc/core.py 2016-12-19 14:47:45.000000000 +0100
+++ new/osc-0.157.1/osc/core.py 2017-03-08 13:10:35.000000000 +0100
@@ -5,7 +5,7 @@
 
 from __future__ import print_function
 
-__version__ = '0.156'
+__version__ = '0.157'
 
 # __store_version__ is to be incremented when the format of the working copy
 # "store" changes in an incompatible way. Please add any needed migration
@@ -3918,8 +3918,9 @@
         tmpfile.write(message)
         tmpfile.flush()
         pager = os.getenv('PAGER', default=get_default_pager())
+        cmd = shlex.split(pager) + [tmpfile.name]
         try:
-            run_external(pager, tmpfile.name)
+            run_external(*cmd)
         finally:
             tmpfile.close()
 
@@ -4511,6 +4512,8 @@
     where = package or '_repository'
     u = makeurl(apiurl, ['build', prj, repo, arch, where, filename])
     download(u, target_filename, progress_obj, target_mtime)
+    if target_filename.endswith('.AppImage'):
+        os.chmod(target_filename, 0o755)
 
 def dgst_from_string(str):
     # Python 2.5 depracates the md5 modules
@@ -4799,16 +4802,19 @@
                 # if project roots were previously inconsistent
                 root_dots = "../../"
             if is_project_dir(root_dots):
+                oldproj = store_read_project(root_dots)
                 if conf.config['checkout_no_colon']:
-                    oldproj = store_read_project(root_dots)
                     n = len(oldproj.split(':'))
                 else:
                     n = 1
+                if root_dots == '.':
+                    root_dots = ''
                 root_dots = root_dots + "../" * n
 
     if root_dots != '.':
         if conf.config['verbose']:
-            print("found root of %s at %s" % (oldproj, root_dots))
+            print("%s is project dir of %s. Root found at %s" %
+                  (prj_dir, oldproj, os.path.abspath(root_dots)))
         prj_dir = root_dots + prj_dir
 
     if not pathname:
@@ -4816,7 +4822,7 @@
 
     # before we create directories and stuff, check if the package actually
     # exists
-    show_package_meta(apiurl, project, package, meta)
+    show_package_meta(apiurl, quote_plus(project), quote_plus(package), meta)
 
     isfrozen = False
     if expand_link:
@@ -5894,7 +5900,26 @@
     f = http_GET(u)
     return f.read()
 
- 
+
+def get_worker_info(apiurl, worker):
+    u = makeurl(apiurl, ['worker', worker])
+    f = http_GET(u)
+
+    return f.read()
+
+
+def check_constraints(apiurl, prj, repository, arch, package, 
constraintsfile=None):
+    query = {'cmd': 'checkconstraints'}
+    query['project'] = prj
+    query['package'] = package
+    query['repository'] = repository
+    query['arch'] = arch
+    u = makeurl(apiurl, ['worker'], query)
+    f = http_POST(u, data=constraintsfile)
+    root = ET.fromstring(''.join(f))
+    return [node.get('name') for node in root.findall('entry')]
+
+
 def get_source_rev(apiurl, project, package, revision=None):
     # API supports ?deleted=1&meta=1&rev=4
     # but not rev=current,rev=latest,rev=top, or anything like this.
@@ -6237,6 +6262,9 @@
 def restartbuild(apiurl, project, package=None, arch=None, repo=None):
     return cmdbuild(apiurl, 'restartbuild', project, package, arch, repo)
 
+def unpublish(apiurl, project, package=None, arch=None, repo=None, code=None):
+    return cmdbuild(apiurl, 'unpublish', project, package, arch, repo, code)
+
 def wipebinaries(apiurl, project, package=None, arch=None, repo=None, 
code=None):
     return cmdbuild(apiurl, 'wipe', project, package, arch, repo, code)
 
@@ -7288,6 +7316,32 @@
             raise
         raise oscerr.ExtRuntimeError(e.strerror, filename)
 
+def return_external(filename, *args, **kwargs):
+    """Executes the program filename via subprocess.check_output.
+
+    *args are additional arguments which are passed to the
+    program filename. **kwargs specify additional arguments for
+    the subprocess.check_output function.
+    if no args are specified the plain filename is passed
+    to subprocess.check_output (this can be used to execute a shell
+    command). Otherwise [filename] + list(args) is passed
+    to the subprocess.check_output function.
+
+    Returns the output of the command.
+
+    """
+    if args:
+        cmd = [filename] + list(args)
+    else:
+        cmd = filename
+
+    try:
+        return subprocess.check_output(cmd, **kwargs)
+    except OSError as e:
+        if e.errno != errno.ENOENT:
+            raise
+        raise oscerr.ExtRuntimeError(e.strerror, filename)
+
 # backward compatibility: local role filtering
 def filter_role(meta, user, role):
     """
@@ -7353,26 +7407,40 @@
     return None
 
 
-def get_comments(apiurl, kind, name):
-    url = makeurl(apiurl, ['comments', kind, name])
+def get_comments(apiurl, kind, *args):
+    url = makeurl(apiurl, ('comments', kind) + args)
     f = http_GET(url)
     return ET.parse(f).getroot()
 
 
-def print_comments(apiurl, kind, name):
+def print_comments(apiurl, kind, *args):
     def print_rec(comments, indent=''):
         for comment in comments:
             print(indent, end='')
-            print('On', comment.get('when'), comment.get('who'), 'wrote:')
+            print('(', comment.get('id'), ')', 'On', comment.get('when'), 
comment.get('who'), 'wrote:')
             text = indent + comment.text.replace('\r\n',' \n')
             print(('\n' + indent).join(text.split('\n')))
             print()
             print_rec([c for c in root if c.get('parent') == 
comment.get('id')], indent + '  ')
-
-    root = get_comments(apiurl, kind, name)
+    root = get_comments(apiurl, kind, *args)
     comments = [c for c in root if c.get('parent') is None]
     if comments:
         print('\nComments:')
         print_rec(comments)
 
+def create_comment(apiurl, kind, comment, *args, **kwargs):
+    query = {}
+    if kwargs.get('parent') is not None:
+        query = {'parent_id': kwargs['parent']}
+    u = makeurl(apiurl, ('comments', kind) + args, query=query)
+    f = http_POST(u, data=comment)
+    ret = ET.fromstring(f.read()).find('summary')
+    return ret.text
+
+def delete_comment(apiurl, cid):
+    u = makeurl(apiurl, ['comment', cid])
+    f = http_DELETE(u)
+    ret = ET.fromstring(f.read()).find('summary')
+    return ret.text
+
 # vim: sw=4 et
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.156.0/osc/oscssl.py 
new/osc-0.157.1/osc/oscssl.py
--- old/osc-0.156.0/osc/oscssl.py       2016-12-19 14:47:45.000000000 +0100
+++ new/osc-0.157.1/osc/oscssl.py       2017-03-08 13:10:35.000000000 +0100
@@ -249,13 +249,36 @@
         self.appname = kwargs.pop('appname', 'generic')
         M2Crypto.httpslib.HTTPSConnection.__init__(self, *args, **kwargs)
 
-    def connect(self, *args):
-        self.sock = SSL.Connection(self.ssl_ctx)
+    def _connect(self, family):
+        self.sock = SSL.Connection(self.ssl_ctx, family=family)
         if self.session:
             self.sock.set_session(self.session)
         if hasattr(self.sock, 'set_tlsext_host_name'):
             self.sock.set_tlsext_host_name(self.host)
         self.sock.connect((self.host, self.port))
+        return True
+
+    def connect(self):
+        # based on M2Crypto.httpslib.HTTPSConnection.connect
+        last_exc = None
+        connected = False
+        for addrinfo in socket.getaddrinfo(self.host, self.port,
+                                           socket.AF_UNSPEC,
+                                           socket.SOCK_STREAM,
+                                           0, 0):
+            try:
+                connected = self._connect(addrinfo[0])
+                break
+            except socket.error as e:
+                last_exc = e
+            finally:
+                if not connected and self.sock is not None:
+                    self.sock.close()
+        if not connected:
+            if last_exc is None:
+                raise RuntimeError('getaddrinfo returned empty list')
+            raise last_exc
+        # ok we are connected, verify cert
         verify_certificate(self)
 
     def getHost(self):

++++++ osc.dsc ++++++
--- /var/tmp/diff_new_pack.nweu3z/_old  2017-03-12 20:03:56.802209477 +0100
+++ /var/tmp/diff_new_pack.nweu3z/_new  2017-03-12 20:03:56.802209477 +0100
@@ -1,6 +1,6 @@
 Format: 1.0
 Source: osc
-Version: 0.156.0
+Version: 0.157.1
 Binary: osc
 Maintainer: Adrian Schroeter <[email protected]>
 Architecture: any


Reply via email to