Hello community,

here is the log from the commit of package openSUSE-release-tools for 
openSUSE:Factory checked in at 2018-02-09 15:46:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/openSUSE-release-tools (Old)
 and      /work/SRC/openSUSE:Factory/.openSUSE-release-tools.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "openSUSE-release-tools"

Fri Feb  9 15:46:40 2018 rev:52 rq:573915 version:20180207.878b87b

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/openSUSE-release-tools/openSUSE-release-tools.changes
    2018-02-07 18:42:05.994254052 +0100
+++ 
/work/SRC/openSUSE:Factory/.openSUSE-release-tools.new/openSUSE-release-tools.changes
       2018-02-09 15:46:47.217026716 +0100
@@ -1,0 +2,25 @@
+Wed Feb 07 22:26:00 UTC 2018 - opensuse-releaset...@opensuse.org
+
+- Update to version 20180207.878b87b:
+  * osc-staging: select: reword documentation to include XML reference.
+  * osc-staging: select: mention additional supplemented request values.
+  * osc-staging: select: mention quick strategy in documentation.
+  * osc-staging: select: add filter-by example using hashtag in description.
+
+-------------------------------------------------------------------
+Wed Feb 07 03:15:11 UTC 2018 - opensuse-releaset...@opensuse.org
+
+- Update to version 20180206.56df1cf:
+  * osclib/conf: include Leap for Factory during pkglistgen.
+  * pkglistgen: include some hints about the difference between solv files.
+  * pkglistgen: integrate drop list creation into update_and_solve.
+  * pkglistgen: do_dump_solv(): handle old-style product repo format.
+  * pkglistgen: do_create_droplist(): print to file when output_dir available.
+  * pkglistgen: provide update_merge() to combine free and nonfree solv.
+  * osclib/util: provide project_list_family* and project_version().
+  * osclib/stagingapi: get_staging_projects(): utilize project_list_prefix().
+  * osclib/core: provide project_list_prefix().
+  * osclib/conf: add download-baseurl for Leap and Factory.
+  * osclib/conf: support version in project pattern as value replacement.
+
+-------------------------------------------------------------------

Old:
----
  openSUSE-release-tools-20180206.faa028a.obscpio

New:
----
  openSUSE-release-tools-20180207.878b87b.obscpio

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

Other differences:
------------------
++++++ openSUSE-release-tools.spec ++++++
--- /var/tmp/diff_new_pack.6jVX9f/_old  2018-02-09 15:46:48.600977019 +0100
+++ /var/tmp/diff_new_pack.6jVX9f/_new  2018-02-09 15:46:48.600977019 +0100
@@ -20,7 +20,7 @@
 %define source_dir osc-plugin-factory
 %define announcer_filename factory-package-news
 Name:           openSUSE-release-tools
-Version:        20180206.faa028a
+Version:        20180207.878b87b
 Release:        0
 Summary:        Tools to aid in staging and release work for openSUSE/SUSE
 License:        GPL-2.0+ AND MIT

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.6jVX9f/_old  2018-02-09 15:46:48.648975296 +0100
+++ /var/tmp/diff_new_pack.6jVX9f/_new  2018-02-09 15:46:48.652975152 +0100
@@ -1,6 +1,6 @@
 <servicedata>
   <service name="tar_scm">
     <param 
name="url">https://github.com/openSUSE/osc-plugin-factory.git</param>
-    <param 
name="changesrevision">faa028a805bdebf740dda3e38ac261e9e4f4f489</param>
+    <param 
name="changesrevision">b2c2fee6f5b0a0e812eccff9dd1e446a489025e9</param>
   </service>
 </servicedata>

++++++ openSUSE-release-tools-20180206.faa028a.obscpio -> 
openSUSE-release-tools-20180207.878b87b.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20180206.faa028a/osc-staging.py 
new/openSUSE-release-tools-20180207.878b87b/osc-staging.py
--- old/openSUSE-release-tools-20180206.faa028a/osc-staging.py  2018-02-07 
04:01:04.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/osc-staging.py  2018-02-07 
23:20:07.000000000 +0100
@@ -237,12 +237,19 @@
         Requests may either be the target package or the request ID.
 
         When using --filter-by or --group-by the xpath will be applied to the
-        request node as returned by OBS. Several values will supplement the
-        normal request node.
+        request node as returned by OBS. Use the following on a current request
+        to see the XML structure.
+
+        osc api /request/1337
+
+        A number of additional values will supplement the normal request node.
 
         - ./action/target/@devel_project: the devel project for the package
+        - ./action/target/@devel_project_super: super devel project if relevant
         - ./action/target/@ring: the ring to which the package belongs
-        - ./@ignored: either false or the provided message
+        - ./@aged: either True or False based on splitter-request-age-threshold
+        - ./@nonfree: set to nonfree if targetting nonfree sub project
+        - ./@ignored: either False or the provided message
 
         Some useful examples:
 
@@ -250,6 +257,7 @@
         --filter-by './action/target/[@devel_project="YaST:Head"]'
         --filter-by './action/target[starts-with(@ring, "1")]'
         --filter-by '@id!="1234567"'
+        --filter-by 'contains(description, "#Portus")'
 
         --group-by='./action/target/@devel_project'
         --group-by='./action/target/@ring'
@@ -278,6 +286,7 @@
         Built in strategies may be specified as well. For example:
 
         select --strategy devel
+        select --strategy quick
         select --strategy special
         select --strategy super
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20180206.faa028a/osclib/conf.py 
new/openSUSE-release-tools-20180207.878b87b/osclib/conf.py
--- old/openSUSE-release-tools-20180206.faa028a/osclib/conf.py  2018-02-07 
04:01:04.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/osclib/conf.py  2018-02-07 
23:20:07.000000000 +0100
@@ -47,12 +47,14 @@
         'lock-ns': 'openSUSE',
         'delreq-review': 'factory-maintainers',
         'main-repo': 'standard',
+        'download-baseurl': 'http://download.opensuse.org/tumbleweed/',
         # check_source.py
         'devel-project-enforce': 'True',
         'review-team': 'opensuse-review-team',
         'repo-checker': 'repo-checker',
+        'pkglistgen-product-family-include': 'openSUSE:Leap:N',
     },
-    r'openSUSE:(?P<project>Leap:[\d.]+)': {
+    r'openSUSE:(?P<project>Leap:(?P<version>[\d.]+))': {
         'staging': 'openSUSE:%(project)s:Staging',
         'staging-group': 'factory-staging',
         'staging-archs': 'i586 x86_64',
@@ -67,6 +69,7 @@
         'lock-ns': 'openSUSE',
         'delreq-review': None,
         'main-repo': 'standard',
+        'download-baseurl': 
'http://download.opensuse.org/distribution/leap/%(version)s/',
         # check_source.py
         # review-team optionally added by leaper.py.
         'repo-checker': 'repo-checker',
@@ -188,6 +191,8 @@
                         defaults[k] = v % {'project': project}
                     elif isinstance(v, basestring) and '%(project.lower)s' in 
v:
                         defaults[k] = v % {'project.lower': project.lower()}
+                    elif isinstance(v, basestring) and '%(version)s' in v:
+                        defaults[k] = v % {'version': match.group('version')}
                     else:
                         defaults[k] = v
                 break
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20180206.faa028a/osclib/core.py 
new/openSUSE-release-tools-20180207.878b87b/osclib/core.py
--- old/openSUSE-release-tools-20180206.faa028a/osclib/core.py  2018-02-07 
04:01:04.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/osclib/core.py  2018-02-07 
23:20:07.000000000 +0100
@@ -3,6 +3,7 @@
 from dateutil.parser import parse as date_parse
 import re
 from xml.etree import cElementTree as ET
+from lxml import etree as ETL
 from urllib2 import HTTPError
 
 from osc.core import get_binarylist
@@ -173,3 +174,10 @@
         created = request.find('history').get('when')
     created = date_parse(created)
     return datetime.utcnow() - created
+
+def project_list_prefix(apiurl, prefix):
+    """Get a list of project with the same prefix."""
+    query = {'match': 'starts-with(@name, "{}")'.format(prefix)}
+    url = makeurl(apiurl, ['search', 'project', 'id'], query)
+    root = ETL.parse(http_GET(url)).getroot()
+    return root.xpath('project/@name')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20180206.faa028a/osclib/stagingapi.py 
new/openSUSE-release-tools-20180207.878b87b/osclib/stagingapi.py
--- old/openSUSE-release-tools-20180206.faa028a/osclib/stagingapi.py    
2018-02-07 04:01:04.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/osclib/stagingapi.py    
2018-02-07 23:20:07.000000000 +0100
@@ -49,6 +49,7 @@
 
 from osclib.cache import Cache
 from osclib.core import devel_project_get
+from osclib.core import project_list_prefix
 from osclib.comments import CommentAPI
 from osclib.ignore_command import IgnoreCommand
 from osclib.memoize import memoize
@@ -333,17 +334,10 @@
         :return list of known staging projects
         """
 
-        projects = []
+        projects = project_list_prefix(self.apiurl, self.cstaging + ':')
+        if not include_dvd:
+            projects = filter(lambda p: not p.endswith(':DVD'), projects)
 
-        query = "id?match=starts-with(@name,'{}:')".format(self.cstaging)
-        url = self.makeurl(['search', 'project', query])
-        projxml = http_GET(url)
-        root = ET.parse(projxml).getroot()
-        for val in root.findall('project'):
-            project = val.get('name')
-            if not include_dvd and project.endswith(':DVD'):
-                continue
-            projects.append(project)
         return projects
 
     def extract_staging_short(self, p):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20180206.faa028a/osclib/util.py 
new/openSUSE-release-tools-20180207.878b87b/osclib/util.py
--- old/openSUSE-release-tools-20180206.faa028a/osclib/util.py  1970-01-01 
01:00:00.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/osclib/util.py  2018-02-07 
23:20:07.000000000 +0100
@@ -0,0 +1,78 @@
+from osclib.core import project_list_prefix
+
+
+def project_list_family(apiurl, project):
+    """
+    Determine the available projects within the same product family.
+
+    Skips < SLE-12 due to format change.
+    """
+    if project == 'openSUSE:Factory':
+        return [project]
+
+    count_original = project.count(':')
+    if project.startswith('SUSE:SLE'):
+        project = ':'.join(project.split(':')[:2])
+        family_filter = lambda p: p.endswith(':GA') and not 
p.startswith('SUSE:SLE-11')
+    else:
+        family_filter = lambda p: p.count(':') == count_original
+
+    prefix = ':'.join(project.split(':')[:-1])
+    projects = project_list_prefix(apiurl, prefix)
+
+    return filter(family_filter, projects)
+
+def project_list_family_prior(apiurl, project, include_self=False):
+    """
+    Determine the available projects within the same product family released
+    prior to the specified project.
+    """
+    projects = project_list_family(apiurl, project)
+    past = False
+    prior = []
+    for entry in sorted(projects, key=project_list_family_sorter, 
reverse=True):
+        if entry == project:
+            past = True
+            if not include_self:
+                continue
+
+        if past:
+            prior.append(entry)
+
+    return prior
+
+def project_list_family_sorter(project):
+    """Extract key to be used as sorter (oldest to newest)."""
+    version = project_version(project)
+
+    if version >= 42:
+        version -= 42
+
+    if project.endswith(':Update'):
+        version += 0.01
+
+    return version
+
+def project_version(project):
+    """
+    Extract a float representation of the project version.
+
+    For example:
+    - openSUSE:Leap:15.0 -> 15.0
+    - openSUSE:Leap:42.3 -> 42.3
+    - SUSE:SLE-15:GA     -> 15.0
+    - SUSE:SLE-15-SP1:GA -> 15.1
+    """
+    if ':Leap:' in project:
+        return float(project.split(':')[2])
+
+    if ':SLE-' in project:
+        version = project.split(':')[1]
+        parts = version.split('-')
+        version = float(parts[1])
+        if len(parts) > 2:
+            # Add each service pack as a tenth.
+            version += float(parts[2][2:]) / 10
+        return version
+
+    return None
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20180206.faa028a/pkglistgen.py 
new/openSUSE-release-tools-20180207.878b87b/pkglistgen.py
--- old/openSUSE-release-tools-20180206.faa028a/pkglistgen.py   2018-02-07 
04:01:04.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/pkglistgen.py   2018-02-07 
23:20:07.000000000 +0100
@@ -40,6 +40,8 @@
 from osc import conf
 from osclib.conf import Config
 from osclib.stagingapi import StagingAPI
+from osclib.util import project_list_family
+from osclib.util import project_list_family_prior
 from xdg.BaseDirectory import save_cache_path
 import glob
 import solv
@@ -754,6 +756,32 @@
                 fh.close()
         return global_update
 
+    def update_merge(self, nonfree):
+        """Merge free and nonfree solv files or copy free to merged"""
+        for prp in self.tool.repos:
+            project, repo = prp.split('/')
+            for arch in self.tool.architectures:
+                solv_file = os.path.join(
+                    CACHEDIR, 'repo-{}-{}-{}.solv'.format(project, repo, arch))
+                solv_file_merged = os.path.join(
+                    CACHEDIR, 'repo-{}-{}-{}.merged.solv'.format(project, 
repo, arch))
+
+                if not nonfree:
+                    shutil.copyfile(solv_file, solv_file_merged)
+                    continue
+
+                solv_file_nonfree = os.path.join(
+                    CACHEDIR, 'repo-{}-{}-{}.solv'.format(nonfree, repo, arch))
+                self.solv_merge(solv_file, solv_file_nonfree, solv_file_merged)
+
+    def solv_merge(self, solv1, solv2, solv_merged):
+        with open(solv_merged, 'w') as handle:
+            p = subprocess.Popen(['mergesolv', solv1, solv2], stdout=handle)
+            p.communicate()
+
+        if p.returncode:
+            raise Exception('failed to create merged solv file')
+
     def do_create_droplist(self, subcmd, opts, *oldsolv):
         """${cmd_name}: generate list of obsolete packages
 
@@ -785,7 +813,7 @@
                     r = pool.add_repo(prp)
                     r.add_solv(fn)
 
-                sysrepo = 
pool.add_repo(os.path.basename(old).replace('.repo.solv', ''))
+                sysrepo = 
pool.add_repo(os.path.basename(old).replace('.merged.solv', ''))
                 sysrepo.add_solv(old)
 
                 pool.createwhatprovides()
@@ -811,16 +839,24 @@
                 # mark it explicitly to avoid having 2 pools while GC is not 
run
                 del pool
 
+        ofh = sys.stdout
+        if self.options.output_dir:
+            name = os.path.join(self.options.output_dir, 
'obsoletepackages.inc')
+            ofh = open(name, 'w')
+
         for reponame in sorted(set(drops.values())):
-            print("<!-- %s -->" % reponame)
+            print("<!-- %s -->" % reponame, file=ofh)
             for p in sorted(drops):
                 if drops[p] != reponame: continue
-                print("  <obsoletepackage>%s</obsoletepackage>" % p)
+                print("  <obsoletepackage>%s</obsoletepackage>" % p, file=ofh)
 
     @cmdln.option('--overwrite', action='store_true', help='overwrite if 
output file exists')
     def do_dump_solv(self, subcmd, opts, baseurl):
         """${cmd_name}: fetch repomd and dump solv
 
+        Dumps solv from published repository. Use solve to generate from
+        pre-published repository.
+
         If an output directory is specified, a file named according
         to the build is created there. Otherwise the solv file is
         dumped to stdout.
@@ -832,19 +868,11 @@
         name = None
         ofh = sys.stdout
         if self.options.output_dir:
-            url = urlparse.urljoin(baseurl, 'media.1/media')
-            with requests.get(url) as media:
-                for i, line in enumerate(media.iter_lines()):
-                    if i != 1:
-                        continue
-                    name = line
-            if name is None or '-Build' not in name:
-                raise Exception('media.1/media includes no build number')
-
-            name = '{}/{}.solv'.format(self.options.output_dir, name)
+            build, repo_style = self.dump_solv_build(baseurl)
+            name = '{}/{}.solv'.format(self.options.output_dir, build)
             if not opts.overwrite and os.path.exists(name):
                 logger.info("%s exists", name)
-                return
+                return name
             ofh = open(name + '.new', 'w')
 
         pool = solv.Pool()
@@ -852,7 +880,8 @@
 
         repo = pool.add_repo(''.join(random.choice(string.letters) for _ in 
range(5)))
         f = tempfile.TemporaryFile()
-        url = urlparse.urljoin(baseurl, 'repodata/repomd.xml')
+        path_prefix = 'suse/' if name and repo_style == 'build' else ''
+        url = urlparse.urljoin(baseurl, path_prefix + 'repodata/repomd.xml')
         repomd = requests.get(url)
         ns = { 'r': 'http://linux.duke.edu/metadata/repo' }
         root = ET.fromstring(repomd.content)
@@ -860,7 +889,7 @@
         f.write(repomd.content)
         os.lseek(f.fileno(), 0, os.SEEK_SET)
         repo.add_repomdxml(f, 0)
-        url = urlparse.urljoin(baseurl, location)
+        url = urlparse.urljoin(baseurl, path_prefix + location)
         with requests.get(url, stream=True) as primary:
             content = gzip.GzipFile(fileobj=StringIO(primary.content))
             os.lseek(f.fileno(), 0, os.SEEK_SET)
@@ -873,6 +902,28 @@
 
         if name is not None:
             os.rename(name + '.new', name)
+            return name
+
+    def dump_solv_build(self, baseurl):
+        """Determine repo format and build string from remote repository."""
+        url = urlparse.urljoin(baseurl, 'media.1/media')
+        with requests.get(url) as media:
+            for i, line in enumerate(media.iter_lines()):
+                if i != 1:
+                    continue
+                name = line
+
+        if name is not None and '-Build' in name:
+            return name, 'media'
+
+        url = urlparse.urljoin(baseurl, 'media.1/build')
+        with requests.get(url) as build:
+            name = build.content.strip()
+
+        if name is not None and '-Build' in name:
+            return name, 'build'
+
+        raise Exception('media.1/{media,build} includes no build number')
 
     @cmdln.option('--ignore-unresolvable', action='store_true', help='ignore 
unresolvable and missing packges')
     @cmdln.option('--ignore-recommended', action='store_true', help='do not 
include recommended packages automatically')
@@ -882,6 +933,9 @@
     def do_solve(self, subcmd, opts):
         """${cmd_name}: Solve groups
 
+        Generates solv from pre-published repository contained in local cache.
+        Use dump_solv to extract solv from published repository.
+
         ${cmd_usage}
         ${cmd_option_list}
         """
@@ -980,14 +1034,14 @@
 
         if opts.scope == 'target':
             self.options.repos = ['/'.join([target_project, main_repo])]
-            self.update_and_solve_target(apiurl, target_project, 
target_config, main_repo, opts)
+            self.update_and_solve_target(apiurl, target_project, 
target_config, main_repo, opts, drop_list=True)
             return
         elif opts.scope == 'ports':
             # TODO Continue supporting #1297, but should be abstracted.
             main_repo = 'ports'
             opts.project += ':Ports'
             self.options.repos = ['/'.join([opts.project, main_repo])]
-            self.update_and_solve_target(apiurl, target_project, 
target_config, main_repo, opts)
+            self.update_and_solve_target(apiurl, target_project, 
target_config, main_repo, opts, drop_list=True)
             return
         elif opts.scope == 'rings':
             opts.project = api.rings[1]
@@ -1022,7 +1076,7 @@
             return
 
     def update_and_solve_target(self, apiurl, target_project, target_config, 
main_repo, opts,
-                                skip_release=False):
+                                skip_release=False, drop_list=False):
         print('[{}] {}/{}: update and solve'.format(opts.scope, opts.project, 
main_repo))
 
         group = target_config.get('pkglistgen-group', '000package-groups')
@@ -1083,6 +1137,26 @@
         print('-> do_update')
         self.do_update('update', opts)
 
+        nonfree = target_config.get('nonfree')
+        if nonfree and drop_list:
+            print('-> do_update nonfree')
+
+            # Switch to nonfree repo (ugly, but that's how the code was setup).
+            self.options.repos_ = self.options.repos
+            self.options.repos = ['/'.join([nonfree, main_repo])]
+            self.postoptparse()
+
+            opts_nonfree = copy.deepcopy(opts)
+            opts_nonfree.project = nonfree
+            self.do_update('update', opts_nonfree)
+
+            # Switch repo back to main target project.
+            self.options.repos = self.options.repos_
+            self.postoptparse()
+
+        print('-> update_merge')
+        self.update_merge(nonfree if drop_list else False)
+
         print('-> do_solve')
         opts.ignore_unresolvable = 
bool(target_config.get('pkglistgen-ignore-unresolvable'))
         opts.ignore_recommended = 
bool(target_config.get('pkglistgen-ignore-recommended'))
@@ -1091,6 +1165,26 @@
         opts.locales_from = target_config.get('pkglistgen-locales-from')
         self.do_solve('solve', opts)
 
+        if drop_list:
+            # Ensure solv files from all releases in product family are 
updated.
+            print('-> solv_cache_update')
+            cache_dir_solv = save_cache_path('opensuse-packagelists', 'solv')
+            family_include = 
target_config.get('pkglistgen-product-family-include')
+            solv_prior = self.solv_cache_update(
+                apiurl, cache_dir_solv, target_project, family_include, opts)
+
+            # Include pre-final release solv files for target project. These
+            # files will only exist from previous runs.
+            cache_dir_solv_current = os.path.join(cache_dir_solv, 
target_project)
+            solv_prior.update(glob.glob(os.path.join(cache_dir_solv_current, 
'*.merged.solv')))
+            for solv_file in solv_prior:
+                logger.debug(solv_file.replace(cache_dir_solv, ''))
+
+            print('-> do_create_droplist')
+            # Reset to product after solv_cache_update().
+            self.options.output_dir = product_dir
+            self.do_create_droplist('create_droplist', opts, *solv_prior)
+
         delete_products = target_config.get('pkglistgen-delete-products', 
'').split(' ')
         self.unlink_list(product_dir, delete_products)
 
@@ -1117,6 +1211,55 @@
             self.build_stub(release_dir, 'spec')
             self.commit_package(release_dir)
 
+    def solv_cache_update(self, apiurl, cache_dir_solv, target_project, 
family_include, opts):
+        """Dump solv files (do_dump_solv) for all products in family."""
+        prior = set()
+
+        project_family = project_list_family_prior(apiurl, target_project, 
include_self=True)
+        if family_include:
+            # Include projects from a different family if desired.
+            project_family.extend(project_list_family(apiurl, family_include))
+
+        for project in project_family:
+            config = Config(project)
+            project_config = conf.config[project]
+
+            baseurl = project_config.get('download-baseurl')
+            if not baseurl:
+                logger.warning('no baseurl configured for {}'.format(project))
+                continue
+
+            urls = [urlparse.urljoin(baseurl, 'repo/oss/')]
+            if project_config.get('nonfree'):
+                urls.append(urlparse.urljoin(baseurl, 'repo/non-oss/'))
+
+            names = []
+            for url in urls:
+                print('-> do_dump_solv for {}/{}'.format(
+                    project, os.path.basename(os.path.normpath(url))))
+                logger.debug(url)
+
+                self.options.output_dir = os.path.join(cache_dir_solv, project)
+                if not os.path.exists(self.options.output_dir):
+                    os.makedirs(self.options.output_dir)
+
+                opts.overwrite = False
+                names.append(self.do_dump_solv('dump_solv', opts, url))
+
+            if not len(names):
+                logger.warning('no solv files were dumped for 
{}'.format(project))
+                continue
+
+            # Merge nonfree solv with free solv or copy free solv as merged.
+            merged = names[0].replace('.solv', '.merged.solv')
+            if len(names) == 2:
+                self.solv_merge(names[0], names[1], merged)
+            else:
+                shutil.copyfile(names[0], merged)
+            prior.add(merged)
+
+        return prior
+
     def move_list(self, file_list, destination):
         for name in file_list:
             os.rename(name, os.path.join(destination, os.path.basename(name)))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/openSUSE-release-tools-20180206.faa028a/tests/obs.py 
new/openSUSE-release-tools-20180207.878b87b/tests/obs.py
--- old/openSUSE-release-tools-20180206.faa028a/tests/obs.py    2018-02-07 
04:01:04.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/tests/obs.py    2018-02-07 
23:20:07.000000000 +0100
@@ -19,6 +19,7 @@
 import re
 import string
 import time
+import urllib
 import urllib2
 import urlparse
 import xml.etree.cElementTree as ET
@@ -810,7 +811,8 @@
     @GET('/search/project/id')
     def search_project_id(self, request, uri, headers):
         """Return a search result /search/project/id."""
-        assert urlparse.urlparse(uri).query == 
"match=starts-with(@name,'openSUSE:Factory:Staging:')"
+        assert urlparse.urlparse(uri).query == urllib.urlencode(
+            {'match': 'starts-with(@name, "openSUSE:Factory:Staging:")'})
 
         response = (404, headers, '<result>Not found</result>')
         try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/openSUSE-release-tools-20180206.faa028a/tests/util_tests.py 
new/openSUSE-release-tools-20180207.878b87b/tests/util_tests.py
--- old/openSUSE-release-tools-20180206.faa028a/tests/util_tests.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/openSUSE-release-tools-20180207.878b87b/tests/util_tests.py     
2018-02-07 23:20:07.000000000 +0100
@@ -0,0 +1,81 @@
+from osclib.util import project_list_family
+from osclib.util import project_list_family_prior
+from osclib.util import project_list_family_sorter
+from osclib.util import project_list_prefix
+from osclib import util
+import unittest
+
+
+class TestUtil(unittest.TestCase):
+    def setUp(self):
+        util._project_list_prefix = util.project_list_prefix
+
+        def project_list_prefix_replacement(apiurl, prefix):
+            if prefix == 'openSUSE:Leap':
+                return [
+                    'openSUSE:Leap:15.0',
+                    'openSUSE:Leap:15.0:Update',
+                    'openSUSE:Leap:15.0:NonFree',
+                    'openSUSE:Leap:15.0:NonFree:Update',
+                    'openSUSE:Leap:42.2',
+                    'openSUSE:Leap:42.3',
+                    'openSUSE:Leap:42.3:Update',
+                    'openSUSE:Leap:42.3:NonFree',
+                    'openSUSE:Leap:42.3:NonFree:Update',
+                ]
+            elif prefix == 'SUSE':
+                return [
+                    'SUSE:SLE-10',
+                    'SUSE:SLE-10:SP2',
+                    'SUSE:SLE-11',
+                    'SUSE:SLE-11:GA',
+                    'SUSE:SLE-11:SP1',
+                    'SUSE:SLE-11:SP1:Update',
+                    'SUSE:SLE-12:GA',
+                    'SUSE:SLE-12-SP1:GA',
+                    'SUSE:SLE-12-SP1:Update',
+                    'SUSE:SLE-15:GA',
+                ]
+
+            return []
+
+        util.project_list_prefix = project_list_prefix_replacement
+
+    def tearDown(self):
+        util.project_list_prefix = util._project_list_prefix
+
+    def test_project_list_family(self):
+        self.assertEqual(project_list_family(None, 'openSUSE:Factory'), 
['openSUSE:Factory'])
+
+        expected = ['openSUSE:Leap:15.0', 'openSUSE:Leap:42.2', 
'openSUSE:Leap:42.3']
+        self.assertEqual(expected, project_list_family(None, 
'openSUSE:Leap:15.0'))
+        self.assertEqual(expected, project_list_family(None, 
'openSUSE:Leap:42.3'))
+
+        expected = ['SUSE:SLE-12:GA', 'SUSE:SLE-12-SP1:GA', 'SUSE:SLE-15:GA']
+        self.assertEqual(expected, project_list_family(None, 'SUSE:SLE-15:GA'))
+        self.assertEqual(expected, project_list_family(None, 
'SUSE:SLE-15-SP1:GA'))
+
+    def test_project_list_family_sorter(self):
+        projects = sorted(project_list_family(None, 'openSUSE:Leap:15.0'), 
key=project_list_family_sorter)
+        self.assertEqual(projects[0], 'openSUSE:Leap:42.2')
+        self.assertEqual(projects[2], 'openSUSE:Leap:15.0')
+
+        projects = sorted(project_list_family(None, 'SUSE:SLE-15:GA'), 
key=project_list_family_sorter)
+        self.assertEqual(projects[0], 'SUSE:SLE-12:GA')
+        self.assertEqual(projects[2], 'SUSE:SLE-15:GA')
+
+    def test_project_list_family_prior(self):
+        projects = project_list_family_prior(None, 'openSUSE:Leap:15.0', 
include_self=True)
+        self.assertEqual(projects, ['openSUSE:Leap:15.0', 
'openSUSE:Leap:42.3', 'openSUSE:Leap:42.2'])
+
+        projects = project_list_family_prior(None, 'openSUSE:Leap:15.0')
+        self.assertEqual(projects, ['openSUSE:Leap:42.3', 
'openSUSE:Leap:42.2'])
+
+        projects = project_list_family_prior(None, 'openSUSE:Leap:42.3')
+        self.assertEqual(projects, ['openSUSE:Leap:42.2'])
+
+        projects = project_list_family_prior(None, 'SUSE:SLE-15:GA')
+        self.assertEqual(projects, ['SUSE:SLE-12-SP1:GA', 'SUSE:SLE-12:GA'])
+
+        projects = project_list_family_prior(None, 'SUSE:SLE-12-SP1:GA')
+        self.assertEqual(projects, ['SUSE:SLE-12:GA'])

++++++ openSUSE-release-tools.obsinfo ++++++
--- /var/tmp/diff_new_pack.6jVX9f/_old  2018-02-09 15:46:49.236954183 +0100
+++ /var/tmp/diff_new_pack.6jVX9f/_new  2018-02-09 15:46:49.236954183 +0100
@@ -1,5 +1,5 @@
 name: openSUSE-release-tools
-version: 20180206.faa028a
-mtime: 1517972464
-commit: faa028a805bdebf740dda3e38ac261e9e4f4f489
+version: 20180207.878b87b
+mtime: 1518042007
+commit: 878b87b2a96b4a8546437979af947df0a75d5531
 


Reply via email to