Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package osc for openSUSE:Factory checked in 
at 2021-12-02 22:30:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/osc (Old)
 and      /work/SRC/openSUSE:Factory/.osc.new.31177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "osc"

Thu Dec  2 22:30:18 2021 rev:158 rq:935127 version:0.175.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/osc/osc.changes  2021-07-21 19:07:51.007444770 
+0200
+++ /work/SRC/openSUSE:Factory/.osc.new.31177/osc.changes       2021-12-02 
22:31:14.634445112 +0100
@@ -1,0 +2,19 @@
+Thu Dec  2 08:18:20 UTC 2021 - Marco Strigl <marco.str...@suse.com>
+
+- 0.175.0:
+  * do not crash when running "osc search --binary --verbose foo"
+  * don't run source services when building outside of an OSC package working 
copy
+  * fix XDG_CONFIG_HOME
+  * offer a force ("f") choice in metafile.edit's error handling code path
+  * fix XPath used in search requests
+  * add support for creating a workflow token via "osc token"
+  * handle missing os.sysconf more gracefully
+  * detachbranch: remove _link when link target got removed
+  * improve error message in case of an URLError
+  * fix downloading from mirrors
+  * avoid sending entire projects on "osc mr"
+  * fix hdmrd5 check of local cached files
+  * improve logic for conffile mode handling
+ 
+
+-------------------------------------------------------------------

Old:
----
  osc-0.174.0.tar.gz

New:
----
  osc-0.175.0.tar.gz

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

Other differences:
------------------
++++++ osc.spec ++++++
--- /var/tmp/diff_new_pack.3D82Eb/_old  2021-12-02 22:31:15.342442506 +0100
+++ /var/tmp/diff_new_pack.3D82Eb/_new  2021-12-02 22:31:15.342442506 +0100
@@ -27,7 +27,7 @@
 %define use_python python
 %endif
 
-%define version_unconverted 0.174.0
+%define version_unconverted 0.175.0
 %define osc_plugin_dir %{_prefix}/lib/osc-plugins
 %define macros_file macros.osc
 %if ! %{defined _rpmmacrodir}
@@ -35,7 +35,7 @@
 %endif
 
 Name:           osc
-Version:        0.174.0
+Version:        0.175.0
 Release:        0
 Summary:        Open Build Service Commander
 License:        GPL-2.0-or-later

++++++ PKGBUILD ++++++
--- /var/tmp/diff_new_pack.3D82Eb/_old  2021-12-02 22:31:15.378442373 +0100
+++ /var/tmp/diff_new_pack.3D82Eb/_new  2021-12-02 22:31:15.378442373 +0100
@@ -1,5 +1,5 @@
 pkgname=osc
-pkgver=0.174.0
+pkgver=0.175.0
 pkgrel=0
 pkgdesc="Open Build Service client"
 arch=('x86_64')

++++++ _service ++++++
--- /var/tmp/diff_new_pack.3D82Eb/_old  2021-12-02 22:31:15.398442299 +0100
+++ /var/tmp/diff_new_pack.3D82Eb/_new  2021-12-02 22:31:15.398442299 +0100
@@ -1,7 +1,7 @@
 <services>
   <service name="tar_scm" mode="disabled">
-    <param name="version">0.174.0</param>
-    <param name="revision">0.174.0</param>
+    <param name="version">0.175.0</param>
+    <param name="revision">0.175.0</param>
     <param name="url">git://github.com/openSUSE/osc.git</param>
     <param name="scm">git</param>
   </service>

++++++ debian.changelog ++++++
--- /var/tmp/diff_new_pack.3D82Eb/_old  2021-12-02 22:31:15.438442152 +0100
+++ /var/tmp/diff_new_pack.3D82Eb/_new  2021-12-02 22:31:15.442442137 +0100
@@ -1,4 +1,4 @@
-osc (0.174.0-0) unstable; urgency=low
+osc (0.175.0-0) unstable; urgency=low
   - Update to 0.174.0:
     - fix password deletion via "osc config -d <apiurl> pass"
     - support changing the password store via "osc config <apiurl>

++++++ osc-0.174.0.tar.gz -> osc-0.175.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/NEWS new/osc-0.175.0/NEWS
--- old/osc-0.174.0/NEWS        2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/NEWS        2021-12-02 08:48:19.000000000 +0100
@@ -1,3 +1,18 @@
+0.175.0
+  - do not crash when running "osc search --binary --verbose foo"
+  - don't run source services when building outside of an OSC package working 
copy
+  - fix XDG_CONFIG_HOME
+  - offer a force ("f") choice in metafile.edit's error handling code path
+  - fix XPath used in search requests
+  - add support for creating a workflow token via "osc token"
+  - handle missing os.sysconf more gracefully
+  - detachbranch: remove _link when link target got removed
+  - improve error message in case of an URLError
+  - fix downloading from mirrors
+  - avoid sending entire projects on "osc mr"
+  - fix hdmrd5 check of local cached files
+  - improve logic for conffile mode handling
+
 0.174.0
   - fix password deletion via "osc config -d <apiurl> pass"
   - support changing the password store via "osc config <apiurl>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/babysitter.py 
new/osc-0.175.0/osc/babysitter.py
--- old/osc-0.174.0/osc/babysitter.py   2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/osc/babysitter.py   2021-12-02 08:48:19.000000000 +0100
@@ -139,7 +139,11 @@
     except HTTPException as e:
         print(e, file=sys.stderr)
     except URLError as e:
-        print('Failed to reach a server:\n', e.reason, file=sys.stderr)
+        msg = 'Failed to reach a server'
+        if hasattr(e, '_osc_host_port'):
+            msg += ' (%s)' % e._osc_host_port
+        msg += ':\n'
+        print(msg, e.reason, file=sys.stderr)
     except IOError as e:
         # ignore broken pipe
         if e.errno != errno.EPIPE:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/build.py new/osc-0.175.0/osc/build.py
--- old/osc-0.174.0/osc/build.py        2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/osc/build.py        2021-12-02 08:48:19.000000000 +0100
@@ -157,6 +157,7 @@
         self.keys = []
         self.prjkeys = []
         self.pathes = []
+        self.urls = {}
         self.modules = []
         for node in root.findall('module'):
             self.modules.append(node.text)
@@ -174,7 +175,12 @@
                 self.projects[p.project] = 1
             self.deps.append(p)
         for node in root.findall('path'):
+            # old simple list for compatibility
+            # XXX: really old? This is currently used for kiwi builds
             self.pathes.append(node.get('project')+"/"+node.get('repository'))
+            # a hash providing the matching URL for specific repos for newer 
OBS instances
+            if node.get('url'):
+                self.urls[node.get('project')+"/"+node.get('repository')] = 
node.get('url') + '/%(arch)s/%(filename)s'
 
         self.vminstall_list = [ dep.name for dep in self.deps if dep.vminstall 
]
         self.preinstall_list = [ dep.name for dep in self.deps if 
dep.preinstall ]
@@ -790,6 +796,9 @@
     if opts.noinit:
         buildargs.append('--noinit')
 
+    if not is_package_dir('.'):
+        opts.noservice = True
+
     # check for source services
     if not opts.offline and not opts.noservice:
         p = osc.core.Package(os.curdir)
@@ -1021,7 +1030,9 @@
             else:
                 urllist = config['urllist']
 
-        # OBS 1.5 and before has no downloadurl defined in buildinfo
+        # OBS 1.5 and before has no downloadurl defined in buildinfo, but it 
is obsolete again meanwhile.
+        # we have now specific download repositories per repository. Could be 
removed IMHO, since the api fallback
+        # is there. In worst case it could fetch the wrong rpm...
         if bi.downloadurl:
             urllist.append(bi.downloadurl + 
'/%(extproject)s/%(extrepository)s/%(arch)s/%(filename)s')
     if opts.disable_cpio_bulk_download:
@@ -1277,6 +1288,8 @@
 
     for i in bi.deps:
         if i.hdrmd5:
+            if not i.name.startswith('container:') and i.pacsuffix != 'rpm':
+                continue
             from .util import packagequery
             if i.name.startswith('container:'):
                 hdrmd5 = dgst(i.fullfilename)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/commandline.py 
new/osc-0.175.0/osc/commandline.py
--- old/osc-0.174.0/osc/commandline.py  2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/osc/commandline.py  2021-12-02 08:48:19.000000000 +0100
@@ -131,7 +131,7 @@
         return optparser
 
 
-    def postoptparse(self, try_again = True):
+    def postoptparse(self):
         """merge commandline options into the config"""
         try:
             conf.get_config(override_conffile = self.options.conffile,
@@ -152,19 +152,16 @@
                 apiurl = self.options.apiurl
             conf.interactive_config_setup(e.file, apiurl)
             print('done', file=sys.stderr)
-            if try_again:
-                self.postoptparse(try_again = False)
+            self.postoptparse()
         except oscerr.ConfigMissingApiurl as e:
             print(e.msg, file=sys.stderr)
             conf.interactive_config_setup(e.file, e.url, initial=False)
-            if try_again:
-                self.postoptparse(try_again = False)
+            self.postoptparse()
         except oscerr.ConfigMissingCredentialsError as e:
             print(e.msg)
             print('Please enter new credentials.')
             conf.interactive_config_setup(e.file, e.url, initial=False)
-            if try_again:
-                self.postoptparse(try_again = False)
+            self.postoptparse()
 
         self.options.verbose = conf.config['verbose']
         self.download_progress = None
@@ -771,9 +768,11 @@
     @cmdln.option('-d', '--delete', metavar='TOKENID',
                         help='Delete a token')
     @cmdln.option('-o', '--operation', metavar='OPERATION',
-                        help='Default is "runservice", but "branch", "release" 
or "rebuild" can also be used')
+                        help='Default is "runservice", but "branch", 
"release", "rebuild", or "workflow" can also be used')
     @cmdln.option('-t', '--trigger', metavar='TOKENSTRING',
                         help='Trigger the action of a token')
+    @cmdln.option('', '--scm-token', metavar ='SCM_TOKEN',
+                        help='The scm\'s access token (only in combination 
with a --operation=workflow option)')
     def do_token(self, subcmd, opts, *args):
         """${cmd_name}: Show and manage authentication token
 
@@ -790,18 +789,28 @@
 
         args = slash_split(args)
 
+        if opts.scm_token and opts.operation != 'workflow':
+            msg = 'The --scm-token option requires a --operation=workflow 
option'
+            raise oscerr.WrongOptions(msg)
+
         apiurl = self.get_api_url()
-        url = apiurl + "/person/" + conf.get_apiurl_usr(apiurl) + "/token"
+        url_path = ['person', conf.get_apiurl_usr(apiurl), 'token']
 
         if opts.create:
+            if opts.operation == 'workflow' and not opts.scm_token:
+                msg = 'The --operation=workflow option requires a 
--scm-token=<token> option'
+                raise oscerr.WrongOptions(msg)
             print("Create a new token")
-            url += "?cmd=create"
+            query = {'cmd': 'create'}
             if opts.operation:
-                url += "&operation=" + opts.operation
+                query['operation'] = opts.operation
+            if opts.scm_token:
+                query['scm_token'] = opts.scm_token
             if len(args) > 1:
-                url += "&project=" + args[0]
-                url += "&package=" + args[1]
+                query['project'] = args[0]
+                query['package'] = args[1]
 
+            url = makeurl(apiurl, url_path, query)
             f = http_POST(url)
             while True:
                 buf = f.read(16384)
@@ -811,15 +820,17 @@
 
         elif opts.delete:
             print("Delete token")
-            url += "/" + opts.delete
+            url_path.append(opts.delete)
+            url = makeurl(apiurl, url_path)
             http_DELETE(url)
         elif opts.trigger:
             print("Trigger token")
             operation = opts.operation or "runservice"
-            url = apiurl + "/trigger/" + operation
+            query = {}
             if len(args) > 1:
-                url += "?project=" + args[0]
-                url += "&package=" + args[1]
+                query['project'] = args[0]
+                query['package'] = args[1]
+            url = makeurl(apiurl, ['trigger', operation], query)
             req = URLRequest(url)
             req.get_method = lambda: "POST"
             req.add_header('Content-Type', 'application/octet-stream')
@@ -830,6 +841,7 @@
             if args and args[0] in ['create', 'delete', 'trigger']:
                 raise oscerr.WrongArgs("Did you mean --" + args[0] + "?")
             # just list token
+            url = makeurl(apiurl, url_path)
             for data in streamfile(url, http_GET):
                 sys.stdout.write(decode_it(data))
 
@@ -2653,7 +2665,7 @@
                     sr_actions = rq.get_actions('submit')
                     for action in sr_actions:
                         u = makeurl(apiurl, ['/search/package'], {
-                              'match' : "([devel/[@project='%s' and 
@package='%s']])" % (action.tgt_project, action.tgt_package)
+                              'match' : "([devel[@project='%s' and 
@package='%s']])" % (action.tgt_project, action.tgt_package)
                               })
                         f = http_GET(u)
                         root = ET.parse(f).getroot()
@@ -2840,7 +2852,14 @@
             li = Linkinfo()
             li.read(root.find('linkinfo'))
             if li.islink() and li.haserror():
-                raise oscerr.LinkExpandError(project, package, li.error)
+                try:
+                    show_package_meta(apiurl, li.project, li.package)
+                except HTTPError as e:
+                    if e.code == 404:
+                        print("Link target got removed, dropping link. 
WARNING: latest submissions in link target might be lost!")
+                        delete_files(apiurl, project, package, ['_link'])
+                    else:
+                        raise oscerr.LinkExpandError(project, package, 
li.error)
             elif not li.islink():
                 print('package \'%s/%s\' is no link' % (project, package), 
file=sys.stderr)
             else:
@@ -3320,6 +3339,8 @@
 
         if len(args) == 0 and (is_project_dir(os.curdir) or 
is_package_dir(os.curdir)):
             source_project = store_read_project(os.curdir)
+            if is_package_dir(os.curdir):
+                source_packages = [store_read_package(os.curdir)]
         elif len(args) == 0:
             raise oscerr.WrongArgs('Too few arguments.')
         if len(args) > 0:
@@ -7627,7 +7648,7 @@
 
         if list_patchinfos:
             u = makeurl(apiurl, ['/search/package'], {
-                'match' : "([kind='patchinfo' and issue/[@state='OPEN' and 
owner/@login='%s']])" % user
+                'match' : "([kind='patchinfo' and issue[@state='OPEN' and 
owner/@login='%s']])" % user
                  })
             f = http_GET(u)
             root = ET.parse(f).getroot()
@@ -7960,10 +7981,16 @@
                     result.append(s)
 
                 if opts.verbose:
-                    title = node.findtext('title').strip()
-                    if len(title) > 60:
-                        title = title[:61] + '...'
-                    result.append(title)
+                    if opts.binary:
+                        result.append(node.get('repository') or '-')
+                        result.append(node.get('arch') or '-')
+                        result.append(node.get('version') or '-')
+                        result.append(node.get('release') or '-')
+                    else:
+                        title = node.findtext('title').strip()
+                        if len(title) > 60:
+                            title = title[:61] + '...'
+                        result.append(title)
 
                 if opts.repos_baseurl:
                     # FIXME: no hardcoded URL of instance
@@ -7995,7 +8022,11 @@
                 headline.append('Rev')
                 headline.append('Srcmd5')
             if opts.verbose:
-                headline.append('# Title')
+                if opts.binary:
+                    headline.extend(['# Repository', '# Arch', '# Version',
+                                     '# Release'])
+                else:
+                    headline.append('# Title')
             if opts.repos_baseurl:
                 headline.append('# URL')
             if opts.binary:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/conf.py new/osc-0.175.0/osc/conf.py
--- old/osc-0.174.0/osc/conf.py 2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/osc/conf.py 2021-12-02 08:48:19.000000000 +0100
@@ -38,6 +38,7 @@
 
 import bz2
 import base64
+import errno
 import os
 import re
 import sys
@@ -87,13 +88,26 @@
 def _get_processors():
     """
     get number of processors (online) based on
-    SC_NPROCESSORS_ONLN (returns 1 if config name does not exist).
+    SC_NPROCESSORS_ONLN (returns 1 if config name/os.sysconf does not exist).
     """
     try:
         return os.sysconf('SC_NPROCESSORS_ONLN')
-    except ValueError as e:
+    except (AttributeError, ValueError):
         return 1
 
+
+def _identify_osccookiejar():
+    if os.path.isfile(os.path.join(os.path.expanduser("~"), '.osc_cookiejar')):
+        # For backwards compatibility, use the old location if it exists
+        return '~/.osc_cookiejar'
+
+    if os.getenv('XDG_STATE_HOME', '') != '':
+        osc_state_dir = os.path.join(os.getenv('XDG_STATE_HOME'), 'osc')
+    else:
+        osc_state_dir = os.path.join(os.path.expanduser("~"), '.local', 
'state', 'osc')
+
+    return os.path.join(osc_state_dir, 'cookiejar')
+
 DEFAULTS = {'apiurl': 'https://api.opensuse.org',
             'user': None,
             'pass': None,
@@ -136,7 +150,7 @@
             'post_mortem': '0',
             'use_keyring': '0',
             'gnome_keyring': '0',
-            'cookiejar': '~/.osc_cookiejar',
+            'cookiejar': _identify_osccookiejar(),
             # fallback for osc build option --no-verify
             'no_verify': '0',
             # enable project tracking by default
@@ -638,6 +652,8 @@
         AbstractHTTPHandler.__init__ = urllib2_debug_init
 
     cookie_file = os.path.expanduser(config['cookiejar'])
+    if not os.path.exists(os.path.dirname(cookie_file)):
+        os.makedirs(os.path.dirname(cookie_file), mode=0o700)
     global cookiejar
     cookiejar = LWPCookieJar(cookie_file)
     try:
@@ -881,7 +897,15 @@
     # okay, we made sure that oscrc exists
 
     # make sure it is not world readable, it may contain a password.
-    os.chmod(conffile, 0o600)
+    conffile_stat = os.stat(conffile)
+    if conffile_stat.st_mode != 0o600:
+        try:
+            os.chmod(conffile, 0o600)
+        except OSError as e:
+            if e.errno == errno.EROFS:
+                print('Warning: file \'%s\' may have an insecure mode.', 
conffile)
+            else:
+                raise e
 
     cp = get_configParser(conffile)
 
@@ -1043,9 +1067,12 @@
     if 'OSC_CONFIG' in os.environ:
         return os.environ.get('OSC_CONFIG')
     if os.path.exists(os.path.expanduser('~/.oscrc')):
-        conffile = '~/.oscrc'
+        return '~/.oscrc'
+
+    if os.environ.get('XDG_CONFIG_HOME', '') != '':
+        conffile = os.environ.get('XDG_CONFIG_HOME') + '/osc/oscrc'
     else:
-        conffile = os.environ.get('XDG_CONFIG_HOME', '~/.config') + 
'/osc/oscrc'
+        conffile = '~/.config/osc/oscrc'
 
     return conffile
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/core.py new/osc-0.175.0/osc/core.py
--- old/osc-0.174.0/osc/core.py 2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/osc/core.py 2021-12-02 08:48:19.000000000 +0100
@@ -5,7 +5,7 @@
 
 from __future__ import print_function
 
-__version__ = '0.174'
+__version__ = '0.175.0'
 
 # __store_version__ is to be incremented when the format of the working copy
 # "store" changes in an incompatible way. Please add any needed migration
@@ -33,7 +33,7 @@
 
 try:
     from urllib.parse import urlsplit, urlunsplit, urlparse, quote_plus, 
urlencode, unquote
-    from urllib.error import HTTPError
+    from urllib.error import HTTPError, URLError
     from urllib.request import pathname2url, install_opener, urlopen
     from urllib.request import Request as URLRequest
     from io import StringIO
@@ -42,7 +42,7 @@
     #python 2.x
     from urlparse import urlsplit, urlunsplit, urlparse
     from urllib import pathname2url, quote_plus, urlencode, unquote
-    from urllib2 import HTTPError, install_opener, urlopen
+    from urllib2 import HTTPError, URLError, install_opener, urlopen
     from urllib2 import Request as URLRequest
     from cStringIO import StringIO
     from httplib import IncompleteRead
@@ -540,7 +540,7 @@
 
     def islink(self):
         """returns True if the linkinfo is not empty, otherwise False"""
-        if self.xsrcmd5 or self.lsrcmd5:
+        if self.xsrcmd5 or self.lsrcmd5 or self.error is not None:
             return True
         return False
 
@@ -1300,7 +1300,7 @@
             self.to_be_added.remove(n)
             self.write_addlist()
         elif state == 'C':
-            # don't remove "merge files" (*.r, *.mine...)
+            # don't remove "merge files" (*.mine, *.new...)
             # that's why we don't use clear_from_conflictlist
             self.in_conflict.remove(n)
             self.write_conflictlist()
@@ -1336,15 +1336,10 @@
             filename = os.path.join(self.dir, n)
             storefilename = os.path.join(self.storedir, n)
             myfilename = os.path.join(self.dir, n + '.mine')
-            if self.islinkrepair() or self.ispulled():
-                upfilename = os.path.join(self.dir, n + '.new')
-            else:
-                upfilename = os.path.join(self.dir, n + '.r' + self.rev)
+            upfilename = os.path.join(self.dir, n + '.new')
 
             try:
                 os.unlink(myfilename)
-                # the working copy may be updated, so the .r* ending may be 
obsolete...
-                # then we don't care
                 os.unlink(upfilename)
                 if self.islinkrepair() or self.ispulled():
                     os.unlink(os.path.join(self.dir, n + '.old'))
@@ -1683,7 +1678,7 @@
         filename = os.path.join(self.dir, n)
         storefilename = os.path.join(self.storedir, n)
         myfilename = os.path.join(self.dir, n + '.mine')
-        upfilename = os.path.join(self.dir, n + '.r' + self.rev)
+        upfilename = os.path.join(self.dir, n + '.new')
         origfile_tmp = os.path.join(self.storedir, '_in_update', '%s.copy' % n)
         origfile = os.path.join(self.storedir, '_in_update', n)
         shutil.copyfile(filename, origfile_tmp)
@@ -2167,8 +2162,11 @@
             url = ET.SubElement(root, 'url')
         url.text = self.url
 
-        u = makeurl(self.apiurl, ['source', self.prjname, self.name, '_meta'])
-        mf = metafile(u, ET.tostring(root, encoding=ET_ENCODING))
+        delegate = lambda force=False: make_meta_url('pkg',
+                                                     (self.prjname, self.name),
+                                                     self.apiurl, force=force)
+        url_factory = metafile._URLFactory(delegate)
+        mf = metafile(url_factory, ET.tostring(root, encoding=ET_ENCODING))
 
         if not force:
             print('*' * 36, 'old', '*' * 36)
@@ -3404,6 +3402,9 @@
             req.add_header('Content-Length', str(content_length))
         try:
             return urlopen(req)
+        except URLError as e:
+            e._osc_host_port = req.host
+            raise
         finally:
             if hasattr(conf.cookiejar, 'save'):
                 conf.cookiejar.save(ignore_discard=True)
@@ -3679,10 +3680,29 @@
 
 class metafile:
     """metafile that can be manipulated and is stored back after 
manipulation."""
+
+    class _URLFactory:
+        # private class which might go away again...
+        def __init__(self, delegate, force_supported=True):
+            self._delegate = delegate 
+            self._force_supported = force_supported
+
+        def is_force_supported(self):
+            return self._force_supported
+
+        def __call__(self, **kwargs):
+            return self._delegate(**kwargs)
+
     def __init__(self, url, input, change_is_required=False, file_ext='.xml'):
         import tempfile
 
-        self.url = url
+        if isinstance(url, self._URLFactory):
+            self._url_factory = url
+        else:
+            delegate = lambda **kwargs: url
+            # force is not supported for a raw url
+            self._url_factory = self._URLFactory(delegate, False)
+        self.url = self._url_factory()
         self.change_is_required = change_is_required
         (fd, self.filename) = tempfile.mkstemp(prefix = 'osc_metafile.', 
suffix = file_ext)
 
@@ -3716,8 +3736,11 @@
 
     def edit(self):
         try:
+            try_force = False
             while True:
-                run_editor(self.filename)
+                if not try_force:
+                    run_editor(self.filename)
+                try_force = False
                 try:
                     self.sync()
                     break
@@ -3733,8 +3756,18 @@
                     summary = root.find('summary')
                     if summary is not None:
                         print(summary.text, file=sys.stderr)
-                    ri = raw_input('Try again? ([y/N]): ')
-                    if ri not in ['y', 'Y']:
+                    if self._url_factory.is_force_supported():
+                        prompt = 'Try again? ([y/N/f]): '
+                    else:
+                        prompt = 'Try again? ([y/N): '
+
+                    ri = raw_input(prompt)
+                    if ri in ('y', 'Y'):
+                        self.url = self._url_factory()
+                    elif ri in ('f', 'F') and 
self._url_factory.is_force_supported():
+                        self.url = self._url_factory(force='1')
+                        try_force = True
+                    else:
                         break
         finally:
             self.discard()
@@ -3871,8 +3904,12 @@
             print('  osc meta pkg %s %s -e' % (unquote(project), package))
             return
 
-    url = make_meta_url(metatype, path_args, apiurl, force, 
remove_linking_repositories, msg)
-    f = metafile(url, data, change_is_required, 
metatypes[metatype]['file_ext'])
+    delegate = lambda force=force: make_meta_url(metatype, path_args, apiurl,
+                                                 force,
+                                                 remove_linking_repositories,
+                                                 msg)
+    url_factory = metafile._URLFactory(delegate)
+    f = metafile(url_factory, data, change_is_required, 
metatypes[metatype]['file_ext'])
 
     if edit:
         f.edit()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/fetch.py new/osc-0.175.0/osc/fetch.py
--- old/osc-0.174.0/osc/fetch.py        2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/osc/fetch.py        2021-12-02 08:48:19.000000000 +0100
@@ -36,6 +36,7 @@
             self.progress_obj = create_text_meter(use_pb_fallback=False)
 
         self.cachedir = cachedir
+        # generic download URL lists
         self.urllist = urllist
         self.modules = modules
         self.http_debug = http_debug
@@ -193,20 +194,31 @@
                 print(e, file=sys.stderr)
                 sys.exit(1)
 
+    def _build_urllist(self, buildinfo, pac):
+        urllist = self.urllist
+        key = '%s/%s' % (pac.project, pac.repository)
+        project_repo_url = buildinfo.urls.get(key)
+        if project_repo_url is not None:
+            urllist = [project_repo_url]
+        return urllist
+
     def run(self, buildinfo):
         cached = 0
         all = len(buildinfo.deps)
         for i in buildinfo.deps:
-            i.makeurls(self.cachedir, self.urllist)
+            urllist = self._build_urllist(buildinfo, i)
+            i.makeurls(self.cachedir, urllist)
             # find container extension by looking in the cache
             if i.name.startswith('container:') and 
i.fullfilename.endswith('.tar.xz'):
                 for ext in ['.tar.xz', '.tar.gz', '.tar']:
                     if os.path.exists(i.fullfilename[:-7] + ext):
                         i.canonname = i.canonname[:-7] + ext
-                        i.makeurls(self.cachedir, self.urllist)
+                        i.makeurls(self.cachedir, urllist)
 
             if os.path.exists(i.fullfilename):
                 cached += 1
+                if not i.name.startswith('container:') and i.pacsuffix != 
'rpm':
+                    continue
                 if i.hdrmd5:
                     from .util import packagequery
                     if i.name.startswith('container:'):
@@ -216,6 +228,7 @@
                     if not hdrmd5 or hdrmd5 != i.hdrmd5:
                         os.unlink(i.fullfilename)
                         cached -= 1
+
         miss = 0
         needed = all - cached
         if all:
@@ -223,7 +236,6 @@
         print("%.1f%% cache miss. %d/%d dependencies cached.\n" % (miss, 
cached, all))
         done = 1
         for i in buildinfo.deps:
-            i.makeurls(self.cachedir, self.urllist)
             if not os.path.exists(i.fullfilename):
                 if self.offline:
                     raise oscerr.OscIOError(None,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/util/debquery.py 
new/osc-0.175.0/osc/util/debquery.py
--- old/osc-0.174.0/osc/util/debquery.py        2021-07-21 10:43:53.000000000 
+0200
+++ new/osc-0.175.0/osc/util/debquery.py        2021-12-02 08:48:19.000000000 
+0100
@@ -16,6 +16,13 @@
 except ImportError:
     HAVE_LZMA = False
 
+HAVE_ZSTD = True
+try:
+    # Note: zstd is not supporting stream compression types
+    import zstandard
+except ImportError:
+    HAVE_ZSTD = False
+
 
 if (not hasattr(itertools, 'zip_longest')
     and hasattr(itertools, 'izip_longest')):
@@ -52,13 +59,23 @@
             tar = tarfile.open(name='control.tar.gz', fileobj=control)
         else:
             control = arfile.get_file(b'control.tar.xz')
+            if control:
+               if not HAVE_LZMA:
+                   raise DebError(self.__path, 'can\'t open control.tar.xz 
without python-lzma')
+               decompressed = lzma.decompress(control.read())
+               tar = tarfile.open(name="control.tar.xz",
+                                  fileobj=BytesIO(decompressed))
+            else:
+                control = arfile.get_file(b'control.tar.zst')
+                if control:
+                    if not HAVE_ZSTD:
+                        raise DebError(self.__path, 'can\'t open 
control.tar.zst without python-zstandard')
+                    with 
zstandard.ZstdDecompressor().stream_reader(BytesIO(control.read())) as reader:
+                        decompressed = reader.read()
+                    tar = tarfile.open(name="control.tar.zst",
+                                       fileobj=BytesIO(decompressed))
             if control is None:
                 raise DebError(self.__path, 'missing control.tar')
-            if not HAVE_LZMA:
-                raise DebError(self.__path, 'can\'t open control.tar.xz 
without python-lzma')
-            decompressed = lzma.decompress(control.read())
-            tar = tarfile.open(name="control.tar.xz",
-                               fileobj=BytesIO(decompressed))
         try:
             name = './control'
             # workaround for python2.4's tarfile module
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/osc/util/packagequery.py 
new/osc-0.175.0/osc/util/packagequery.py
--- old/osc-0.174.0/osc/util/packagequery.py    2021-07-21 10:43:53.000000000 
+0200
+++ new/osc-0.175.0/osc/util/packagequery.py    2021-12-02 08:48:19.000000000 
+0100
@@ -87,7 +87,7 @@
         f = open(filename, 'rb')
         magic = f.read(7)
         f.seek(0)
-        if magic[:4] == '\xed\xab\xee\xdb':
+        if magic[:4] == b'\xed\xab\xee\xdb':
             from . import rpmquery
             f.close()
             return rpmquery.RpmQuery.queryhdrmd5(filename)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osc-0.174.0/tests/common.py 
new/osc-0.175.0/tests/common.py
--- old/osc-0.174.0/tests/common.py     2021-07-21 10:43:53.000000000 +0200
+++ new/osc-0.175.0/tests/common.py     2021-12-02 08:48:19.000000000 +0100
@@ -182,6 +182,7 @@
 
 class OscTestCase(unittest.TestCase):
     def setUp(self, copytree=True):
+        os.chdir(os.path.dirname(__file__))
         oscrc = os.path.join(self._get_fixtures_dir(), 'oscrc')
         osc.core.conf.get_config(override_conffile=oscrc,
                                  override_no_keyring=True, 
override_no_gnome_keyring=True)

++++++ osc.dsc ++++++
--- /var/tmp/diff_new_pack.3D82Eb/_old  2021-12-02 22:31:15.774440914 +0100
+++ /var/tmp/diff_new_pack.3D82Eb/_new  2021-12-02 22:31:15.774440914 +0100
@@ -1,6 +1,6 @@
 Format: 1.0
 Source: osc
-Version: 0.174.0-0
+Version: 0.175.0-0
 Binary: osc
 Maintainer: Adrian Schroeter <adr...@suse.de>
 Architecture: any

Reply via email to