[calm - Cygwin server-side packaging maintenance script] branch master, updated. 20200220-16-gb3b0168

Jon TURNEY via Cygwin-apps-cvs <[email protected]>
Newsgroups gmane.os.cygwin.cvs.apps
Message-ID <[email protected]>


https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=b3b01689707ae685e5eebf2310b0052edd08502c

commit b3b01689707ae685e5eebf2310b0052edd08502c
Author: Jon Turney <[email protected]>
Date:   Wed Feb 19 18:58:43 2020 +0000

    Extend test to cover hint adjustment at upload

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=7ebf8eaf0eddb588ecd536586717cd5015c365ef

commit 7ebf8eaf0eddb588ecd536586717cd5015c365ef
Author: Jon Turney <[email protected]>
Date:   Tue Feb 18 19:03:41 2020 +0000

    Add a tool for adding homepage: to '-src.hint' files
    
    Also perform similar adjustment to '-src.hint' files at upload.

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=93c56730ba3f297e3a83b99d9ceabd77da7afbf3

commit 93c56730ba3f297e3a83b99d9ceabd77da7afbf3
Author: Jon Turney <[email protected]>
Date:   Tue Feb 18 20:54:06 2020 +0000

    Add support for a homepage: key in source package hint
    
    Report it in json dump
    Report it on package summary package

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=c2e8e9abc448e040ed93f58d6ec2238f30f54613

commit c2e8e9abc448e040ed93f58d6ec2238f30f54613
Author: Jon Turney <[email protected]>
Date:   Tue Feb 18 17:52:42 2020 +0000

    Update tests for separate source .hint
    
    Note a change to the json output, where rpm-doc no longer has a version
    999-1, as a source package doesn't exist for it, only an install package
    (because source versions are no longer implicitly created for all
    install versions)

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=38618a7717cd7e087015107528903ffc4f2087bf

commit 38618a7717cd7e087015107528903ffc4f2087bf
Author: Jon Turney <[email protected]>
Date:   Tue Feb 18 17:56:20 2020 +0000

    Revert "Disable testing of replacement hint upload"
    
    This reverts commit 26ece0fb8604df395679003a08327667aff28011.
    
    This is now working again.

https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=b64e51cab8ffb44c63c23de40ded81031f724e0e

commit b64e51cab8ffb44c63c23de40ded81031f724e0e
Author: Jon Turney <[email protected]>
Date:   Mon Feb 17 15:20:57 2020 +0000

    Use separate .hint for source and install packages
    
    This makes keeping track of stale hints much simpler and more reliable
    
    Add a tool to add missing -src.hint to the relarea, by copying (if
    install package also exists) or moving (if it doesn't) the corresponding
    .hint
    
    Fix up uploads which don't have a -src.hint, by copying or moving the
    corresponding .hint likewise.


Diff:
---
 calm/fix-missing-src-hint-info.py                  |  65 +++++++++++++
 calm/fix-missing-src-hint.py                       |  72 +++++++++++++++
 calm/fixes.py                                      | 102 +++++++++++++++++++++
 calm/hint.py                                       |   9 +-
 calm/package.py                                    |  34 +++----
 calm/pkg2html.py                                   |   3 +
 calm/uploads.py                                    |  21 +++++
 test/testdata/conflict/homedir.expected            |   3 +-
 test/testdata/conflict/rel_area.expected           |  78 +++++++++++++---
 test/testdata/conflict/vault.expected              |   5 +-
 .../noarch/release/obs-a/obs-a-1.0-1-src.expected  |   1 +
 .../noarch/release/obs-b/obs-b-1.0-1-src.expected  |   1 +
 .../perl-Net-SMTP-SSL-1.01-1-src.expected          |   5 +
 .../perl-Net-SMTP-SSL-1.02-1-src.expected          |   5 +
 .../perl-Net-SMTP-SSL-1.03-1-src.expected          |   5 +
 .../release/test-c/test-c-1.0-1-src.expected       |   4 +
 .../release/test-d/test-d-1.0-1-src.expected       |   1 +
 .../release/test-e/test-e-1.0-1-src.expected       |   1 +
 .../x86/release/arc/arc-4.32.7-10-src.expected     |   8 ++
 .../release/corrupt/corrupt-2.0.0-1-src.expected   |   3 +
 .../x86/release/cygwin/cygwin-2.2.0-1-src.expected |   4 +
 .../x86/release/cygwin/cygwin-2.2.1-1-src.expected |   4 +
 .../release/cygwin/cygwin-2.3.0-0.3-src.expected   |   7 ++
 .../release/keychain/keychain-2.6.8-1-src.expected |  12 +++
 .../release/keychain/keychain-2.7.1-1-src.expected |  12 +++
 .../libtextcat/libtextcat-2.2-2-src.expected       |  11 +++
 .../mDNSResponder-379.32.1-1-src.expected          |  10 ++
 .../release/openssh/openssh-7.2p2-1-src.expected   |   5 +
 .../per-version-incomplete-36-1-src.expected       |   3 +
 ...ersion-replacement-hint-only-1.0-1-src.expected |   4 +
 .../per-version/per-version-4.0-1-src.expected     |   4 +
 .../per-version/per-version-4.8-1-src.expected     |   4 +
 .../x86/release/rpm-doc/rpm-doc-4.1-2-src.expected |   2 +
 .../staleversion/staleversion-240-1-src.expected   |   4 +
 .../staleversion/staleversion-242-0-src.expected   |   4 +
 .../staleversion/staleversion-243-0-src.expected   |   4 +
 .../staleversion/staleversion-250-0-src.expected   |   4 +
 .../staleversion/staleversion-251-0-src.expected   |   4 +
 .../staleversion/staleversion-260-0-src.expected   |   5 +
 .../testpackage/testpackage-0.1-1-src.expected     |   3 +
 .../testpackage/testpackage-1.0-1-src.tar.bz2      | Bin 195 -> 266 bytes
 test/testdata/process_arch/homedir.expected        |   2 +-
 test/testdata/process_arch/packages.json.expected  |   4 +-
 test/testdata/process_arch/rel_area.expected       |  79 +++++++++++++---
 test/testdata/process_arch/setup.ini.expected      |  16 ++--
 test/testdata/process_arch/vault.expected          |  13 ++-
 .../noarch/release/obs-a/obs-a-1.0-1-src.hint      |   2 +
 .../noarch/release/obs-b/obs-b-1.0-1-src.hint      |   2 +
 .../perl-Net-SMTP-SSL-1.01-1-src.hint              |   5 +
 .../perl-Net-SMTP-SSL-1.02-1-src.hint              |   5 +
 .../perl-Net-SMTP-SSL-1.03-1-src.hint              |   5 +
 .../noarch/release/test-c/test-c-1.0-1-src.hint    |   4 +
 .../noarch/release/test-d/test-d-1.0-1-src.hint    |   3 +
 .../noarch/release/test-e/test-e-1.0-1-src.hint    |   3 +
 .../relarea/x86/release/arc/arc-4.32.7-10-src.hint |   8 ++
 .../x86/release/corrupt/corrupt-2.0.0-1-src.hint   |   3 +
 .../x86/release/cygwin/cygwin-2.2.0-1-src.hint     |   4 +
 .../x86/release/cygwin/cygwin-2.2.1-1-src.hint     |   4 +
 .../x86/release/cygwin/cygwin-2.3.0-0.3-src.hint   |   7 ++
 .../x86/release/keychain/keychain-2.6.8-1-src.hint |  12 +++
 .../x86/release/keychain/keychain-2.7.1-1-src.hint |  12 +++
 .../release/libtextcat/libtextcat-2.2-2-src.hint   |  10 ++
 .../mDNSResponder-379.32.1-1-src.hint              |  11 +++
 .../x86/release/openssh/openssh-7.2p2-1-src.hint   |   5 +
 .../per-version-incomplete-36-1-src.hint           |   3 +
 ...er-version-replacement-hint-only-1.0-1-src.hint |   4 +
 .../release/per-version/per-version-4.0-1-src.hint |   4 +
 .../release/per-version/per-version-4.8-1-src.hint |   4 +
 .../x86/release/rpm-doc/rpm-doc-4.1-2-src.hint     |   2 +
 .../staleversion/staleversion-240-1-src.hint       |   4 +
 .../staleversion/staleversion-242-0-src.hint       |   4 +
 .../staleversion/staleversion-243-0-src.hint       |   4 +
 .../staleversion/staleversion-250-0-src.hint       |   4 +
 .../staleversion/staleversion-251-0-src.hint       |   4 +
 .../staleversion/staleversion-260-0-src.hint       |   5 +
 .../release/testpackage/testpackage-0.1-1-src.hint |   3 +
 test/testdata/uploads/move.expected                |   5 +-
 test/testdata/uploads/pkglist.expected             |   3 +-
 78 files changed, 737 insertions(+), 71 deletions(-)

diff --git a/calm/fix-missing-src-hint-info.py b/calm/fix-missing-src-hint-info.py
new file mode 100644
index 0000000..44da470
--- /dev/null
+++ b/calm/fix-missing-src-hint-info.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2020 Jon Turney
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+
+import argparse
+import logging
+import os
+import re
+import sys
+
+from . import common_constants
+from . import fixes
+
+
+def fix_hints(relarea):
+    for (dirpath, subdirs, files) in os.walk(relarea):
+        for f in files:
+            match = re.match(r'^(.*)-src\.tar\.(bz2|gz|lzma|xz)$', f)
+            if match:
+                hf = match.group(1) + '-src.hint'
+                if hf not in files:
+                    logging.error('hint %s missing' % hf)
+                    continue
+
+                fixes.fix_homepage_src_hint(dirpath, hf, f)
+
+
+#
+#
+#
+
+if __name__ == "__main__":
+    relarea_default = common_constants.FTP
+
+    parser = argparse.ArgumentParser(description='src hint improver')
+    parser.add_argument('-v', '--verbose', action='count', dest='verbose', help='verbose output', default=0)
+    parser.add_argument('--releasearea', action='store', metavar='DIR', help="release directory (default: " + relarea_default + ")", default=relarea_default, dest='relarea')
+    (args) = parser.parse_args()
+
+    if args.verbose:
+        logging.getLogger().setLevel(logging.INFO)
+
+    logging.basicConfig(format=os.path.basename(sys.argv[0]) + ': %(message)s')
+
+    fix_hints(args.relarea)
diff --git a/calm/fix-missing-src-hint.py b/calm/fix-missing-src-hint.py
new file mode 100644
index 0000000..46d2f19
--- /dev/null
+++ b/calm/fix-missing-src-hint.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2020 Jon Turney
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+import argparse
+import logging
+import os
+import re
+import shutil
+import sys
+
+from . import common_constants
+
+#
+#
+#
+
+
+def fix_hints(relarea):
+    for (dirpath, subdirs, files) in os.walk(relarea):
+        for f in files:
+            match = re.match(r'^(.*)-src\.tar\.(bz2|gz|lzma|xz)$', f)
+            if match:
+                pvr = match.group(1)
+                old = pvr + '.hint'
+                new = pvr + '-src.hint'
+                if (old in files) and (new not in files):
+                    logging.info("copying '%s' to '%s'" % (old, new))
+                    shutil.copy2(os.path.join(dirpath, old), os.path.join(dirpath, new))
+                    if f.replace('-src', '') not in files:
+                        logging.info("removing '%s'" % (old))
+                        os.rename(os.path.join(dirpath, old), os.path.join(dirpath, old + '.bak'))
+
+
+#
+#
+#
+
+
+if __name__ == "__main__":
+    relarea_default = common_constants.FTP
+
+    parser = argparse.ArgumentParser(description='src hint creator')
+    parser.add_argument('-v', '--verbose', action='count', dest='verbose', help='verbose output', default=0)
+    parser.add_argument('--releasearea', action='store', metavar='DIR', help="release directory (default: " + relarea_default + ")", default=relarea_default, dest='relarea')
+    (args) = parser.parse_args()
+
+    if args.verbose:
+        logging.getLogger().setLevel(logging.INFO)
+
+    logging.basicConfig(format=os.path.basename(sys.argv[0]) + ': %(message)s')
+
+    fix_hints(args.relarea)
diff --git a/calm/fixes.py b/calm/fixes.py
new file mode 100644
index 0000000..e6f5340
--- /dev/null
+++ b/calm/fixes.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2020 Jon Turney
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+#
+
+import logging
+import os
+import re
+import shutil
+import tarfile
+
+from . import hint
+
+
+def read_cygport(dirpath, tf):
+    try:
+        with tarfile.open(os.path.join(dirpath, tf)) as a:
+            cygports = [m for m in a.getmembers() if m.name.endswith('.cygport')]
+
+            if len(cygports) != 1:
+                logging.info('srcpkg %s contains %d .cygport files' % (tf, len(cygports)))
+                return None
+
+            f = a.extractfile(cygports[0])
+            content = f.read()
+
+    except tarfile.ReadError:
+        logging.error("srcpkg %s is not a valid compressed archive" % tf)
+        return None
+
+    try:
+        content = content.decode()
+    except UnicodeDecodeError:
+        logging.error("utf8 decode error for .cygport in srcpkg %s" % tf)
+        content = content.decode(errors='replace')
+
+    # fold any line-continuations
+    content = content.replace('\\\n', '')
+
+    return content
+
+
+def fix_homepage_src_hint(dirpath, hf, tf):
+    pn = os.path.basename(dirpath)
+    hintfile = os.path.join(dirpath, hf)
+    hints = hint.hint_file_parse(hintfile, hint.spvr)
+
+    hints.pop('parse-warnings', None)
+    if 'parse-errors' in hints:
+        logging.error('invalid hints %s' % hf)
+        return
+
+    # already present?
+    if 'homepage' in hints:
+        return
+
+    # crack open corresponding -src.tar and parse homepage out from .cygport
+    logging.debug('examining %s' % tf)
+    content = read_cygport(dirpath, tf)
+
+    homepage = None
+    if content:
+        for l in content.splitlines():
+            match = re.match(r'^\s*HOMEPAGE\s*=\s*("|)([^"].*)\1', l)
+            if match:
+                if homepage:
+                    logging.warning('multiple HOMEPAGE lines in .cygport in srcpkg %s', tf)
+                homepage = match.group(2)
+                homepage = re.sub(r'\$({|)(PN|ORIG_PN|NAME)(|})', pn, homepage)
+
+    if homepage and '$' in homepage:
+        logging.warning('unknown shell parameter expansions in HOMEPAGE in .cygport in srcpkg %s', tf)
+        homepage = None
+
+    if not homepage:
+        logging.info('cannot determine homepage: from srcpkg %s' % tf)
+        return
+
+    logging.info('adding homepage:%s to hints for srcpkg %s' % (homepage, tf))
+
+    # write updated hints
+    hints['homepage'] = homepage
+    shutil.copy2(hintfile, hintfile + '.bak')
+    hint.hint_file_write(hintfile, hints)
diff --git a/calm/hint.py b/calm/hint.py
index 19b16ff..6e709f0 100755
--- a/calm/hint.py
+++ b/calm/hint.py
@@ -37,7 +37,7 @@ import argparse
 keytypes = ['multilineval', 'val', 'optval', 'noval']
 
 # kinds of hint file, and their allowed keys
-pvr, override = range(2)
+pvr, override, spvr = range(3)
 
 hintkeys = {}
 
@@ -60,6 +60,11 @@ hintkeys[pvr] = {
     'notes': 'val',    # tool notes; not significant to calm itself
 }
 
+hintkeys[spvr] = hintkeys[pvr].copy()
+hintkeys[spvr].update({
+    'homepage': 'val',
+})
+
 hintkeys[override] = {
     'curr': 'val',
     'keep': 'val',
@@ -281,7 +286,7 @@ def hint_file_parse(fn, kind):
 
             # for the pvr kind, 'category' and 'sdesc' must be present
             # XXX: genini also requires 'requires' but that seems wrong
-            if kind == pvr:
+            if kind != override:
                 mandatory = ['category', 'sdesc']
                 for k in mandatory:
                     if k not in hints:
diff --git a/calm/package.py b/calm/package.py
index dca89b2..c57ad91 100755
--- a/calm/package.py
+++ b/calm/package.py
@@ -225,7 +225,10 @@ def read_package_dir(packages, basedir, dirpath, files, remove=[], upload=False)
             fl['all'].append(f)
             files.remove(f)
         elif re.match(r'^' + re.escape(p) + r'.*\.hint$', f):
-            fl['all'].append(f)
+            if f.endswith('-src.hint'):
+                fl[Kind.source].append(f)
+            else:
+                fl[Kind.binary].append(f)
             files.remove(f)
         elif re.match(r'^' + re.escape(p) + r'.*\.tar\.(bz2|gz|lzma|xz)$', f):
             if '-src.tar' in f:
@@ -372,10 +375,10 @@ def read_one_package(packages, p, relpath, dirpath, files, remove, kind):
     hints = {}
     actual_tars = {}
     for vr in vr_list:
-        hint_fn = '%s-%s.hint' % (p, vr)
+        hint_fn = '%s-%s%s.hint' % (p, vr, '-src' if kind == Kind.source else '')
         if hint_fn in files:
             # is there a PVR.hint file?
-            pvr_hint = read_hints(p, os.path.join(dirpath, hint_fn), hint.pvr)
+            pvr_hint = read_hints(p, os.path.join(dirpath, hint_fn), hint.pvr if kind == Kind.binary else hint.spvr)
             if not pvr_hint:
                 logging.error("error parsing %s" % (os.path.join(dirpath, hint_fn)))
                 return True
@@ -1187,6 +1190,9 @@ def write_repo_json(args, packages, f):
             'arches': arches,
         }
 
+        if 'homepage' in po.version_hints[bv]:
+            d['homepage'] = po.version_hints[bv]['homepage']
+
         if pkg_maintainers[po.orig_name] and ('ORPHANED' not in pkg_maintainers[po.orig_name]):
             d['maintainers'] = sorted(pkg_maintainers[po.orig_name])
 
@@ -1403,26 +1409,8 @@ def stale_packages(packages):
 
         for v in po.hints:
             # if there's a pvr.hint without a fresh source or install of the
-            # same version, move it as well (this is complicated as the hint may
-            # be used by both a binary and source package; give the source
-            # package ownership, if it exists)
-
-            if po.kind == Kind.source:
-                if ((po.orig_name in packages) and
-                    (v in packages[po.orig_name].vermap) and
-                    ('install' in packages[po.orig_name].vermap[v])):
-                    sourceless = packages[po.orig_name].tar(v, 'install').sourceless
-                else:
-                    sourceless = False
-            else:
-                if 'install' in po.vermap.get(v, {}):
-                    sourceless = po.tar(v, 'install').sourceless
-                else:
-                    sourceless = False
-
-            binary_owns_hint = ('external-source' in po.hints[v].hints) or sourceless
-
-            if all_stale.get(v, True) and ((po.kind == Kind.binary) == binary_owns_hint):
+            # same version, move it as well
+            if all_stale.get(v, True):
                 stale.add(po.hints[v].path, po.hints[v].fn)
                 logging.debug("package '%s' version '%s' hint is stale" % (pn, v))
 
diff --git a/calm/pkg2html.py b/calm/pkg2html.py
index b6c5490..f554f39 100755
--- a/calm/pkg2html.py
+++ b/calm/pkg2html.py
@@ -233,6 +233,9 @@ def update_package_listings(args, packages):
                     if po.kind == package.Kind.source:
                         es = p
                         print('<span class="detail">install package(s)</span>: %s<br><br>' % ', '.join([linkify_package(p) for p in sorted(po.is_used_by)]), file=f)
+                        homepage = po.version_hints[po.best_version].get('homepage', None)
+                        if homepage:
+                            print('<span class="detail">homepage</span>: <a href="%s">%s</a><br><br>' % (homepage, homepage), file=f)
                     else:
                         es = po.version_hints[bv].get('external-source', p + '-src')
                         print('<span class="detail">source package</span>: %s<br><br>' % linkify_package(es), file=f)
diff --git a/calm/uploads.py b/calm/uploads.py
index 747b0dc..1794257 100644
--- a/calm/uploads.py
+++ b/calm/uploads.py
@@ -30,11 +30,13 @@ import filecmp
 import os
 import logging
 import re
+import shutil
 import tarfile
 import time
 
 from .movelist import MoveList
 from . import common_constants
+from . import fixes
 from . import package
 
 # reminders will be issued weekly
@@ -169,6 +171,25 @@ def scan(m, all_packages, arch, args):
                 files.remove(old)
                 files.append(new)
 
+        for f in sorted(files):
+            match = re.match(r'^([^-].*)-src\.tar\.(bz2|gz|lzma|xz)$', f)
+            if match:
+                pvr = match.group(1)
+                old = pvr + '.hint'
+                new = pvr + '-src.hint'
+                # see if we can fix-up missing -src.hint file
+                if (old in files) and (new not in files):
+                    logging.warning("copying '%s' to '%s'" % (old, new))
+                    shutil.copy2(os.path.join(dirpath, old), os.path.join(dirpath, new))
+                    files.append(new)
+                    if f.replace('-src', '') not in files:
+                        logging.info("ignoring '%s'" % (old))
+                        files.remove(old)
+
+                # see if we can fix-up missing homepage: in -src.hint file
+                if (new in files):
+                    fixes.fix_homepage_src_hint(dirpath, new, f)
+
         # filter out files we don't need to consider
         for f in sorted(files):
             fn = os.path.join(dirpath, f)
diff --git a/test/testdata/conflict/homedir.expected b/test/testdata/conflict/homedir.expected
index 729c6b9..a1264c1 100644
--- a/test/testdata/conflict/homedir.expected
+++ b/test/testdata/conflict/homedir.expected
@@ -2,6 +2,7 @@
  'Blooey McFooey': [],
  'Blooey McFooey/x86': [],
  'Blooey McFooey/x86/release': [],
- 'Blooey McFooey/x86/release/staleversion': ['staleversion-230-1-src.tar.xz',
+ 'Blooey McFooey/x86/release/staleversion': ['staleversion-230-1-src.hint',
+                                             'staleversion-230-1-src.tar.xz',
                                              'staleversion-230-1.hint',
                                              'staleversion-230-1.tar.xz']}
diff --git a/test/testdata/conflict/rel_area.expected b/test/testdata/conflict/rel_area.expected
index baf726d..db7d029 100644
--- a/test/testdata/conflict/rel_area.expected
+++ b/test/testdata/conflict/rel_area.expected
@@ -1,37 +1,70 @@
 {'.': [],
  'noarch': ['sha512.sum'],
  'noarch/release': ['sha512.sum'],
- 'noarch/release/obs-a': ['obs-a-1.0-1-src.tar.xz', 'obs-a-1.0-1.hint', 'obs-a-1.0-1.tar.xz', 'sha512.sum'],
- 'noarch/release/obs-b': ['obs-b-1.0-1-src.tar.xz', 'obs-b-1.0-1.hint', 'obs-b-1.0-1.tar.xz', 'sha512.sum'],
- 'noarch/release/perl-Net-SMTP-SSL': ['perl-Net-SMTP-SSL-1.01-1-src.tar.xz',
+ 'noarch/release/obs-a': ['obs-a-1.0-1-src.hint',
+                          'obs-a-1.0-1-src.tar.xz',
+                          'obs-a-1.0-1.hint',
+                          'obs-a-1.0-1.tar.xz',
+                          'sha512.sum'],
+ 'noarch/release/obs-b': ['obs-b-1.0-1-src.hint',
+                          'obs-b-1.0-1-src.tar.xz',
+                          'obs-b-1.0-1.hint',
+                          'obs-b-1.0-1.tar.xz',
+                          'sha512.sum'],
+ 'noarch/release/perl-Net-SMTP-SSL': ['perl-Net-SMTP-SSL-1.01-1-src.hint',
+                                      'perl-Net-SMTP-SSL-1.01-1-src.tar.xz',
                                       'perl-Net-SMTP-SSL-1.01-1.hint',
                                       'perl-Net-SMTP-SSL-1.01-1.tar.xz',
+                                      'perl-Net-SMTP-SSL-1.02-1-src.hint',
                                       'perl-Net-SMTP-SSL-1.02-1-src.tar.xz',
                                       'perl-Net-SMTP-SSL-1.02-1.hint',
                                       'perl-Net-SMTP-SSL-1.02-1.tar.xz',
+                                      'perl-Net-SMTP-SSL-1.03-1-src.hint',
                                       'perl-Net-SMTP-SSL-1.03-1-src.tar.xz',
                                       'perl-Net-SMTP-SSL-1.03-1.hint',
                                       'perl-Net-SMTP-SSL-1.03-1.tar.xz',
                                       'sha512.sum'],
- 'noarch/release/test-c': ['sha512.sum', 'test-c-1.0-1-src.tar.xz', 'test-c-1.0-1.hint', 'test-c-1.0-1.tar.xz'],
- 'noarch/release/test-d': ['sha512.sum', 'test-d-1.0-1-src.tar.xz', 'test-d-1.0-1.hint', 'test-d-1.0-1.tar.xz'],
- 'noarch/release/test-e': ['sha512.sum', 'test-e-1.0-1-src.tar.xz', 'test-e-1.0-1.hint', 'test-e-1.0-1.tar.xz'],
+ 'noarch/release/test-c': ['sha512.sum',
+                           'test-c-1.0-1-src.hint',
+                           'test-c-1.0-1-src.tar.xz',
+                           'test-c-1.0-1.hint',
+                           'test-c-1.0-1.tar.xz'],
+ 'noarch/release/test-d': ['sha512.sum',
+                           'test-d-1.0-1-src.hint',
+                           'test-d-1.0-1-src.tar.xz',
+                           'test-d-1.0-1.hint',
+                           'test-d-1.0-1.tar.xz'],
+ 'noarch/release/test-e': ['sha512.sum',
+                           'test-e-1.0-1-src.hint',
+                           'test-e-1.0-1-src.tar.xz',
+                           'test-e-1.0-1.hint',
+                           'test-e-1.0-1.tar.xz'],
  'x86': ['sha512.sum'],
  'x86/release': ['sha512.sum'],
- 'x86/release/arc': ['arc-4.32.7-10-src.tar.bz2', 'arc-4.32.7-10.hint', 'arc-4.32.7-10.tar.bz2'],
+ 'x86/release/arc': ['arc-4.32.7-10-src.hint',
+                     'arc-4.32.7-10-src.tar.bz2',
+                     'arc-4.32.7-10.hint',
+                     'arc-4.32.7-10.tar.bz2'],
  'x86/release/base-cygwin': ['base-cygwin-3.6-1.hint',
                              'base-cygwin-3.6-1.tar.xz',
                              'base-cygwin-3.8-1.hint',
                              'base-cygwin-3.8-1.tar.xz',
                              'sha512.sum'],
- 'x86/release/corrupt': ['corrupt-2.0.0-1-src.tar.xz', 'corrupt-2.0.0-1.hint', 'corrupt-2.0.0-1.tar.xz', 'sha512.sum'],
+ 'x86/release/corrupt': ['corrupt-2.0.0-1-src.hint',
+                         'corrupt-2.0.0-1-src.tar.xz',
+                         'corrupt-2.0.0-1.hint',
+                         'corrupt-2.0.0-1.tar.xz',
+                         'sha512.sum'],
  'x86/release/cygwin': ['.this-should-be-ignored',
+                        'cygwin-2.2.0-1-src.hint',
                         'cygwin-2.2.0-1-src.tar.xz',
                         'cygwin-2.2.0-1.hint',
                         'cygwin-2.2.0-1.tar.xz',
+                        'cygwin-2.2.1-1-src.hint',
                         'cygwin-2.2.1-1-src.tar.xz',
                         'cygwin-2.2.1-1.hint',
                         'cygwin-2.2.1-1.tar.xz',
+                        'cygwin-2.3.0-0.3-src.hint',
                         'cygwin-2.3.0-0.3-src.tar.xz',
                         'cygwin-2.3.0-0.3.hint',
                         'cygwin-2.3.0-0.3.tar.xz',
@@ -54,9 +87,11 @@
                                      'override.hint',
                                      'sha512.sum'],
  'x86/release/invalid': ['invalid-0.hint', 'sha512.sum'],
- 'x86/release/keychain': ['keychain-2.6.8-1-src.tar.bz2',
+ 'x86/release/keychain': ['keychain-2.6.8-1-src.hint',
+                          'keychain-2.6.8-1-src.tar.bz2',
                           'keychain-2.6.8-1.hint',
                           'keychain-2.6.8-1.tar.bz2',
+                          'keychain-2.7.1-1-src.hint',
                           'keychain-2.7.1-1-src.tar.bz2',
                           'keychain-2.7.1-1.hint',
                           'keychain-2.7.1-1.tar.bz2',
@@ -64,7 +99,8 @@
  'x86/release/libspiro': ['libspiro-20071029-1.hint', 'sha512.sum'],
  'x86/release/libspiro/libspiro-devel': ['libspiro-devel-20071029-1.hint', 'sha512.sum'],
  'x86/release/libspiro/libspiro0': ['libspiro0-20071029-1.hint', 'sha512.sum'],
- 'x86/release/libtextcat': ['libtextcat-2.2-2-src.tar.bz2',
+ 'x86/release/libtextcat': ['libtextcat-2.2-2-src.hint',
+                            'libtextcat-2.2-2-src.tar.bz2',
                             'libtextcat-2.2-2.hint',
                             'libtextcat-2.2-2.tar.bz2',
                             'sha512.sum'],
@@ -72,7 +108,8 @@
                                              'libtextcat-devel-2.2-2.tar.bz2',
                                              'sha512.sum'],
  'x86/release/libtextcat/libtextcat0': ['libtextcat0-2.2-2.hint', 'libtextcat0-2.2-2.tar.bz2', 'sha512.sum'],
- 'x86/release/mDNSResponder': ['mDNSResponder-379.32.1-1-src.tar.bz2',
+ 'x86/release/mDNSResponder': ['mDNSResponder-379.32.1-1-src.hint',
+                               'mDNSResponder-379.32.1-1-src.tar.bz2',
                                'mDNSResponder-379.32.1-1.hint',
                                'mDNSResponder-379.32.1-1.tar.bz2',
                                'sha512.sum'],
@@ -83,30 +120,39 @@
  'x86/release/mingw64-i686-binutils': ['mingw64-i686-binutils-2.29.1.787c9873-1.hint', 'sha512.sum'],
  'x86/release/mingw64-i686-binutils/mingw64-i686-binutils-debuginfo': ['mingw64-i686-binutils-debuginfo-2.29.1.787c9873-1.hint',
                                                                        'sha512.sum'],
- 'x86/release/openssh': ['openssh-7.2p2-1-src.tar.xz', 'openssh-7.2p2-1.hint', 'openssh-7.2p2-1.tar.xz', 'sha512.sum'],
+ 'x86/release/openssh': ['openssh-7.2p2-1-src.hint',
+                         'openssh-7.2p2-1-src.tar.xz',
+                         'openssh-7.2p2-1.hint',
+                         'openssh-7.2p2-1.tar.xz',
+                         'sha512.sum'],
  'x86/release/per-version': ['override.hint',
+                             'per-version-4.0-1-src.hint',
                              'per-version-4.0-1-src.tar.xz',
                              'per-version-4.0-1.hint',
                              'per-version-4.0-1.tar.xz',
+                             'per-version-4.8-1-src.hint',
                              'per-version-4.8-1-src.tar.xz',
                              'per-version-4.8-1.hint',
                              'per-version-4.8-1.tar.xz',
                              'sha512.sum'],
  'x86/release/per-version-incomplete': ['override.hint',
+                                        'per-version-incomplete-36-1-src.hint',
                                         'per-version-incomplete-36-1-src.tar.xz',
                                         'per-version-incomplete-36-1.hint',
                                         'per-version-incomplete-36-1.tar.xz',
                                         'per-version-incomplete-39-1-src.tar.xz',
                                         'per-version-incomplete-39-1.tar.xz',
                                         'sha512.sum'],
- 'x86/release/per-version-replacement-hint-only': ['per-version-replacement-hint-only-1.0-1-src.tar.xz',
+ 'x86/release/per-version-replacement-hint-only': ['per-version-replacement-hint-only-1.0-1-src.hint',
+                                                   'per-version-replacement-hint-only-1.0-1-src.tar.xz',
                                                    'per-version-replacement-hint-only-1.0-1.hint',
                                                    'per-version-replacement-hint-only-1.0-1.tar.xz',
                                                    'sha512.sum'],
  'x86/release/proj': ['proj-4.8.0-1.hint', 'sha512.sum'],
  'x86/release/proj/libproj-devel': ['libproj-devel-4.8.0-1.hint', 'sha512.sum'],
  'x86/release/proj/libproj1': ['libproj1-4.8.0-1.hint', 'sha512.sum'],
- 'x86/release/rpm-doc': ['rpm-doc-4.1-2-src.tar.bz2',
+ 'x86/release/rpm-doc': ['rpm-doc-4.1-2-src.hint',
+                         'rpm-doc-4.1-2-src.tar.bz2',
                          'rpm-doc-4.1-2.hint',
                          'rpm-doc-4.1-2.tar.bz2',
                          'rpm-doc-999-1.hint',
@@ -115,16 +161,20 @@
  'x86/release/splint': ['sha512.sum', 'splint-3.1.2-1.hint'],
  'x86/release/staleversion': ['override.hint',
                               'sha512.sum',
+                              'staleversion-243-0-src.hint',
                               'staleversion-243-0-src.tar.xz',
                               'staleversion-243-0.hint',
                               'staleversion-243-0.tar.xz',
+                              'staleversion-250-0-src.hint',
                               'staleversion-250-0-src.tar.xz',
                               'staleversion-250-0.hint',
                               'staleversion-250-0.tar.xz',
+                              'staleversion-260-0-src.hint',
                               'staleversion-260-0-src.tar.xz',
                               'staleversion-260-0.hint',
                               'staleversion-260-0.tar.xz'],
  'x86/release/testpackage': ['sha512.sum',
+                             'testpackage-0.1-1-src.hint',
                              'testpackage-0.1-1-src.tar.bz2',
                              'testpackage-0.1-1.hint',
                              'testpackage-0.1-1.tar.bz2']}
diff --git a/test/testdata/conflict/vault.expected b/test/testdata/conflict/vault.expected
index 6f418e2..e5cb944 100644
--- a/test/testdata/conflict/vault.expected
+++ b/test/testdata/conflict/vault.expected
@@ -1,12 +1,15 @@
 {'.': [],
  'x86': [],
  'x86/release': [],
- 'x86/release/staleversion': ['staleversion-240-1-src.tar.xz',
+ 'x86/release/staleversion': ['staleversion-240-1-src.hint',
+                              'staleversion-240-1-src.tar.xz',
                               'staleversion-240-1.hint',
                               'staleversion-240-1.tar.xz',
+                              'staleversion-242-0-src.hint',
                               'staleversion-242-0-src.tar.xz',
                               'staleversion-242-0.hint',
                               'staleversion-242-0.tar.xz',
+                              'staleversion-251-0-src.hint',
                               'staleversion-251-0-src.tar.xz',
                               'staleversion-251-0.hint',
                               'staleversion-251-0.tar.xz']}
diff --git a/test/testdata/hints/noarch/release/obs-a/obs-a-1.0-1-src.expected b/test/testdata/hints/noarch/release/obs-a/obs-a-1.0-1-src.expected
new file mode 100644
index 0000000..250a5fe
--- /dev/null
+++ b/test/testdata/hints/noarch/release/obs-a/obs-a-1.0-1-src.expected
@@ -0,0 +1 @@
+OrderedDict([('category', 'Devel'), ('sdesc', '"obsolete package A"')])
diff --git a/test/testdata/hints/noarch/release/obs-b/obs-b-1.0-1-src.expected b/test/testdata/hints/noarch/release/obs-b/obs-b-1.0-1-src.expected
new file mode 100644
index 0000000..f1c61cd
--- /dev/null
+++ b/test/testdata/hints/noarch/release/obs-b/obs-b-1.0-1-src.expected
@@ -0,0 +1 @@
+OrderedDict([('category', 'Devel'), ('sdesc', '"obsolete package B"')])
diff --git a/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1-src.expected b/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1-src.expected
new file mode 100644
index 0000000..9516e05
--- /dev/null
+++ b/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1-src.expected
@@ -0,0 +1,5 @@
+{'category': 'Perl',
+ 'requires': '',
+ 'sdesc': '"Perl distribution Net-SMTP-SSL"',
+ 'ldesc': '"Implements the same API as Net::SMTP, but uses IO::Socket::SSL for\n'
+          'its network operations in order to support encrypted connections."'}
diff --git a/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1-src.expected b/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1-src.expected
new file mode 100644
index 0000000..9516e05
--- /dev/null
+++ b/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1-src.expected
@@ -0,0 +1,5 @@
+{'category': 'Perl',
+ 'requires': '',
+ 'sdesc': '"Perl distribution Net-SMTP-SSL"',
+ 'ldesc': '"Implements the same API as Net::SMTP, but uses IO::Socket::SSL for\n'
+          'its network operations in order to support encrypted connections."'}
diff --git a/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1-src.expected b/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1-src.expected
new file mode 100644
index 0000000..9516e05
--- /dev/null
+++ b/test/testdata/hints/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1-src.expected
@@ -0,0 +1,5 @@
+{'category': 'Perl',
+ 'requires': '',
+ 'sdesc': '"Perl distribution Net-SMTP-SSL"',
+ 'ldesc': '"Implements the same API as Net::SMTP, but uses IO::Socket::SSL for\n'
+          'its network operations in order to support encrypted connections."'}
diff --git a/test/testdata/hints/noarch/release/test-c/test-c-1.0-1-src.expected b/test/testdata/hints/noarch/release/test-c/test-c-1.0-1-src.expected
new file mode 100644
index 0000000..c8024d7
--- /dev/null
+++ b/test/testdata/hints/noarch/release/test-c/test-c-1.0-1-src.expected
@@ -0,0 +1,4 @@
+{'category': 'Devel',
+ 'sdesc': '"test package C"',
+ 'obsoletes': 'obs-a, obs-b',
+ 'depends': 'test-d (>= 1.0), test-e'}
diff --git a/test/testdata/hints/noarch/release/test-d/test-d-1.0-1-src.expected b/test/testdata/hints/noarch/release/test-d/test-d-1.0-1-src.expected
new file mode 100644
index 0000000..584681a
--- /dev/null
+++ b/test/testdata/hints/noarch/release/test-d/test-d-1.0-1-src.expected
@@ -0,0 +1 @@
+OrderedDict([('category', 'Devel'), ('sdesc', '"test package D"'), ('version', '1.0.42590-1')])
diff --git a/test/testdata/hints/noarch/release/test-e/test-e-1.0-1-src.expected b/test/testdata/hints/noarch/release/test-e/test-e-1.0-1-src.expected
new file mode 100644
index 0000000..e7414e7
--- /dev/null
+++ b/test/testdata/hints/noarch/release/test-e/test-e-1.0-1-src.expected
@@ -0,0 +1 @@
+OrderedDict([('category', 'Devel'), ('sdesc', '"test package E"'), ('build-depends', 'libtextcat-devel')])
diff --git a/test/testdata/hints/x86/release/arc/arc-4.32.7-10-src.expected b/test/testdata/hints/x86/release/arc/arc-4.32.7-10-src.expected
new file mode 100644
index 0000000..d0cd27b
--- /dev/null
+++ b/test/testdata/hints/x86/release/arc/arc-4.32.7-10-src.expected
@@ -0,0 +1,8 @@
+{'sdesc': '"The ARC archive utility"',
+ 'ldesc': '"This program is based on the MSDOS ARC program, version 5.21, plus a\n'
+          'few enhancements. ARC performs Huffman Squeezing on data. The Huffman\n'
+          'Squeeze algorithm was removed from MSDOS ARC after version 5.12. It\n'
+          'turns out to be more efficient than Lempel-Ziv style compression when\n'
+          'compressing graphic images. Squeeze analysis is always done now, and\n'
+          'the best of packing, squeezing, or crunching is used."',
+ 'category': 'Archive'}
diff --git a/test/testdata/hints/x86/release/corrupt/corrupt-2.0.0-1-src.expected b/test/testdata/hints/x86/release/corrupt/corrupt-2.0.0-1-src.expected
new file mode 100644
index 0000000..945213b
--- /dev/null
+++ b/test/testdata/hints/x86/release/corrupt/corrupt-2.0.0-1-src.expected
@@ -0,0 +1,3 @@
+{'sdesc': '"A corrupt package"',
+ 'ldesc': '"A package containing corrupt archives"',
+ 'category': 'Devel'}
diff --git a/test/testdata/hints/x86/release/cygwin/cygwin-2.2.0-1-src.expected b/test/testdata/hints/x86/release/cygwin/cygwin-2.2.0-1-src.expected
new file mode 100644
index 0000000..24a09e5
--- /dev/null
+++ b/test/testdata/hints/x86/release/cygwin/cygwin-2.2.0-1-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"The UNIX emulation engine"',
+ 'ldesc': '"The UNIX emulation engine"',
+ 'category': 'Base',
+ 'requires': 'base-cygwin'}
diff --git a/test/testdata/hints/x86/release/cygwin/cygwin-2.2.1-1-src.expected b/test/testdata/hints/x86/release/cygwin/cygwin-2.2.1-1-src.expected
new file mode 100644
index 0000000..24a09e5
--- /dev/null
+++ b/test/testdata/hints/x86/release/cygwin/cygwin-2.2.1-1-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"The UNIX emulation engine"',
+ 'ldesc': '"The UNIX emulation engine"',
+ 'category': 'Base',
+ 'requires': 'base-cygwin'}
diff --git a/test/testdata/hints/x86/release/cygwin/cygwin-2.3.0-0.3-src.expected b/test/testdata/hints/x86/release/cygwin/cygwin-2.3.0-0.3-src.expected
new file mode 100644
index 0000000..4c2d9d7
--- /dev/null
+++ b/test/testdata/hints/x86/release/cygwin/cygwin-2.3.0-0.3-src.expected
@@ -0,0 +1,7 @@
+{'sdesc': '"The UNIX emulation engine"',
+ 'ldesc': '"The UNIX emulation engine"',
+ 'category': 'Base',
+ 'requires': 'base-cygwin',
+ 'provides': 'cygwin-api0_291',
+ 'conflicts': 'fruit-juice',
+ 'test': ''}
diff --git a/test/testdata/hints/x86/release/keychain/keychain-2.6.8-1-src.expected b/test/testdata/hints/x86/release/keychain/keychain-2.6.8-1-src.expected
new file mode 100644
index 0000000..4113a2d
--- /dev/null
+++ b/test/testdata/hints/x86/release/keychain/keychain-2.6.8-1-src.expected
@@ -0,0 +1,12 @@
+{'sdesc': '"Key manager for OpenSSH"',
+ 'ldesc': '"Keychain is an OpenSSH key manager, typically run from\n'
+          '~/.bash_profile. When keychain is run, it checks for a running\n'
+          'ssh-agent, otherwise it starts one. It saves the ssh-agent environment\n'
+          'variables to ~/.keychain/$HOSTNAME-sh, so that subsequent logins\n'
+          'and non-interactive shells such as cron jobs can source the file and\n'
+          'make passwordless ssh connections. In addition, when keychain runs, it\n'
+          'verifies that the key files specified on the command-line are known to\n'
+          'ssh-agent, otherwise it loads them, prompting you for a password if\n'
+          'necessary"',
+ 'category': 'Utils',
+ 'requires': 'openssh'}
diff --git a/test/testdata/hints/x86/release/keychain/keychain-2.7.1-1-src.expected b/test/testdata/hints/x86/release/keychain/keychain-2.7.1-1-src.expected
new file mode 100644
index 0000000..4113a2d
--- /dev/null
+++ b/test/testdata/hints/x86/release/keychain/keychain-2.7.1-1-src.expected
@@ -0,0 +1,12 @@
+{'sdesc': '"Key manager for OpenSSH"',
+ 'ldesc': '"Keychain is an OpenSSH key manager, typically run from\n'
+          '~/.bash_profile. When keychain is run, it checks for a running\n'
+          'ssh-agent, otherwise it starts one. It saves the ssh-agent environment\n'
+          'variables to ~/.keychain/$HOSTNAME-sh, so that subsequent logins\n'
+          'and non-interactive shells such as cron jobs can source the file and\n'
+          'make passwordless ssh connections. In addition, when keychain runs, it\n'
+          'verifies that the key files specified on the command-line are known to\n'
+          'ssh-agent, otherwise it loads them, prompting you for a password if\n'
+          'necessary"',
+ 'category': 'Utils',
+ 'requires': 'openssh'}
diff --git a/test/testdata/hints/x86/release/libtextcat/libtextcat-2.2-2-src.expected b/test/testdata/hints/x86/release/libtextcat/libtextcat-2.2-2-src.expected
new file mode 100644
index 0000000..498e7e5
--- /dev/null
+++ b/test/testdata/hints/x86/release/libtextcat/libtextcat-2.2-2-src.expected
@@ -0,0 +1,11 @@
+{'sdesc': '"Text Classification Library (language guessing in C)"',
+ 'ldesc': '"Libtextcat is a library with functions that implement the\n'
+          'classification technique described in Cavnar & Trenkle, "N-Gram-Based\n'
+          'Text Categorization". It was primarily developed for language\n'
+          'guessing, a task on which it is known to perform with near-perfect\n'
+          'accuracy.\n'
+          'BSD License.\n'
+          'http://software.wise-guys.nl/libtextcat/"',
+ 'category': 'Text',
+ 'requires': 'libtextcat0',
+ 'parse-errors': ['embedded quote at line 7']}
diff --git a/test/testdata/hints/x86/release/mDNSResponder/mDNSResponder-379.32.1-1-src.expected b/test/testdata/hints/x86/release/mDNSResponder/mDNSResponder-379.32.1-1-src.expected
new file mode 100644
index 0000000..f02a324
--- /dev/null
+++ b/test/testdata/hints/x86/release/mDNSResponder/mDNSResponder-379.32.1-1-src.expected
@@ -0,0 +1,10 @@
+{'category': 'Net',
+ 'requires': 'libdns_sd1',
+ 'sdesc': '"Bonjour Zeroconf implementation"',
+ 'ldesc': '"Bonjour, also known as zero-configuration networking, enables\n'
+          'automatic discovery of computers, devices, and services on IP networks using\n'
+          'industry standard IP protocols."',
+ 'message': 'mDNSResponder "The Cygwin mDNSResponder package contains only clients.\n'
+            "If you do not already have the 'Bonjour Service' installed (it comes with\n"
+            'a number of popular Windows programs), then you can download it at\n'
+            'http://support.apple.com/kb/DL999"'}
diff --git a/test/testdata/hints/x86/release/openssh/openssh-7.2p2-1-src.expected b/test/testdata/hints/x86/release/openssh/openssh-7.2p2-1-src.expected
new file mode 100644
index 0000000..8eeefad
--- /dev/null
+++ b/test/testdata/hints/x86/release/openssh/openssh-7.2p2-1-src.expected
@@ -0,0 +1,5 @@
+{'category': 'Net',
+ 'sdesc': '"The OpenSSH server and client programs"',
+ 'ldesc': '"OpenSSH is a program for logging into a remote machine and for\n'
+          '\texecuting commands on a remote machine.  It can replace rlogin and rsh,\n'
+          '\tproviding encrypted communication between two machines."'}
diff --git a/test/testdata/hints/x86/release/per-version-incomplete/per-version-incomplete-36-1-src.expected b/test/testdata/hints/x86/release/per-version-incomplete/per-version-incomplete-36-1-src.expected
new file mode 100644
index 0000000..e59d0d2
--- /dev/null
+++ b/test/testdata/hints/x86/release/per-version-incomplete/per-version-incomplete-36-1-src.expected
@@ -0,0 +1,3 @@
+{'sdesc': '"Per-version hint test package"',
+ 'ldesc': '"Per-version hint test package with missing hint data for some versions"',
+ 'category': 'Base'}
diff --git a/test/testdata/hints/x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src.expected b/test/testdata/hints/x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src.expected
new file mode 100644
index 0000000..d6a1e1f
--- /dev/null
+++ b/test/testdata/hints/x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Per-version hint test package"',
+ 'ldesc': '"Per-version hint test package"',
+ 'category': 'Base',
+ 'requires': 'cygwin'}
diff --git a/test/testdata/hints/x86/release/per-version/per-version-4.0-1-src.expected b/test/testdata/hints/x86/release/per-version/per-version-4.0-1-src.expected
new file mode 100644
index 0000000..d6a1e1f
--- /dev/null
+++ b/test/testdata/hints/x86/release/per-version/per-version-4.0-1-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Per-version hint test package"',
+ 'ldesc': '"Per-version hint test package"',
+ 'category': 'Base',
+ 'requires': 'cygwin'}
diff --git a/test/testdata/hints/x86/release/per-version/per-version-4.8-1-src.expected b/test/testdata/hints/x86/release/per-version/per-version-4.8-1-src.expected
new file mode 100644
index 0000000..40a138b
--- /dev/null
+++ b/test/testdata/hints/x86/release/per-version/per-version-4.8-1-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Per-version hint test package"',
+ 'ldesc': '"Per-version hint test package"',
+ 'category': 'Base',
+ 'requires': 'base-cygwin'}
diff --git a/test/testdata/hints/x86/release/rpm-doc/rpm-doc-4.1-2-src.expected b/test/testdata/hints/x86/release/rpm-doc/rpm-doc-4.1-2-src.expected
new file mode 100644
index 0000000..a47a381
--- /dev/null
+++ b/test/testdata/hints/x86/release/rpm-doc/rpm-doc-4.1-2-src.expected
@@ -0,0 +1,2 @@
+{'sdesc': '"Obsolete package for RPM package management system manual pages (extra text to so repr is not one line)"',
+ 'category': '_obsolete'}
diff --git a/test/testdata/hints/x86/release/staleversion/staleversion-240-1-src.expected b/test/testdata/hints/x86/release/staleversion/staleversion-240-1-src.expected
new file mode 100644
index 0000000..f7cc4fd
--- /dev/null
+++ b/test/testdata/hints/x86/release/staleversion/staleversion-240-1-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Test package for stale version removal"',
+ 'ldesc': '"Test package for stale version removal"',
+ 'category': 'Shells Base',
+ 'requires': ''}
diff --git a/test/testdata/hints/x86/release/staleversion/staleversion-242-0-src.expected b/test/testdata/hints/x86/release/staleversion/staleversion-242-0-src.expected
new file mode 100644
index 0000000..f7cc4fd
--- /dev/null
+++ b/test/testdata/hints/x86/release/staleversion/staleversion-242-0-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Test package for stale version removal"',
+ 'ldesc': '"Test package for stale version removal"',
+ 'category': 'Shells Base',
+ 'requires': ''}
diff --git a/test/testdata/hints/x86/release/staleversion/staleversion-243-0-src.expected b/test/testdata/hints/x86/release/staleversion/staleversion-243-0-src.expected
new file mode 100644
index 0000000..f7cc4fd
--- /dev/null
+++ b/test/testdata/hints/x86/release/staleversion/staleversion-243-0-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Test package for stale version removal"',
+ 'ldesc': '"Test package for stale version removal"',
+ 'category': 'Shells Base',
+ 'requires': ''}
diff --git a/test/testdata/hints/x86/release/staleversion/staleversion-250-0-src.expected b/test/testdata/hints/x86/release/staleversion/staleversion-250-0-src.expected
new file mode 100644
index 0000000..f7cc4fd
--- /dev/null
+++ b/test/testdata/hints/x86/release/staleversion/staleversion-250-0-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Test package for stale version removal"',
+ 'ldesc': '"Test package for stale version removal"',
+ 'category': 'Shells Base',
+ 'requires': ''}
diff --git a/test/testdata/hints/x86/release/staleversion/staleversion-251-0-src.expected b/test/testdata/hints/x86/release/staleversion/staleversion-251-0-src.expected
new file mode 100644
index 0000000..f7cc4fd
--- /dev/null
+++ b/test/testdata/hints/x86/release/staleversion/staleversion-251-0-src.expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Test package for stale version removal"',
+ 'ldesc': '"Test package for stale version removal"',
+ 'category': 'Shells Base',
+ 'requires': ''}
diff --git a/test/testdata/hints/x86/release/staleversion/staleversion-260-0-src.expected b/test/testdata/hints/x86/release/staleversion/staleversion-260-0-src.expected
new file mode 100644
index 0000000..a876af9
--- /dev/null
+++ b/test/testdata/hints/x86/release/staleversion/staleversion-260-0-src.expected
@@ -0,0 +1,5 @@
+{'sdesc': '"Test package for stale version removal"',
+ 'ldesc': '"Test package for stale version removal"',
+ 'category': 'Shells Base',
+ 'requires': '',
+ 'test': ''}
diff --git a/test/testdata/hints/x86/release/testpackage/testpackage-0.1-1-src.expected b/test/testdata/hints/x86/release/testpackage/testpackage-0.1-1-src.expected
new file mode 100644
index 0000000..aa3c772
--- /dev/null
+++ b/test/testdata/hints/x86/release/testpackage/testpackage-0.1-1-src.expected
@@ -0,0 +1,3 @@
+{'sdesc': '"A test package (stuff & other stuff)"',
+ 'ldesc': '"A test package (stuff & other stuff)"',
+ 'category': 'Devel'}
diff --git a/test/testdata/homes/Blooey McFooey/x86/release/testpackage/testpackage-1.0-1-src.tar.bz2 b/test/testdata/homes/Blooey McFooey/x86/release/testpackage/testpackage-1.0-1-src.tar.bz2
index a1145fb..495f0ad 100644
Binary files a/test/testdata/homes/Blooey McFooey/x86/release/testpackage/testpackage-1.0-1-src.tar.bz2 and b/test/testdata/homes/Blooey McFooey/x86/release/testpackage/testpackage-1.0-1-src.tar.bz2 differ
diff --git a/test/testdata/process_arch/homedir.expected b/test/testdata/process_arch/homedir.expected
index 8b90c99..42e9902 100644
--- a/test/testdata/process_arch/homedir.expected
+++ b/test/testdata/process_arch/homedir.expected
@@ -12,7 +12,7 @@
  'Blooey McFooey/x86/release/not-ready': ['-not-ready-0.9-1.tar.bz2', 'not-ready-1.0-1.tar.bz2', 'setup.hint'],
  'Blooey McFooey/x86/release/per-version': [],
  'Blooey McFooey/x86/release/per-version-replacement-hint-only': [],
- 'Blooey McFooey/x86/release/testpackage': [],
+ 'Blooey McFooey/x86/release/testpackage': ['testpackage-1.0-1-src.hint.bak'],
  'Blooey McFooey/x86/release/testpackage/testpackage-subpackage': [],
  'Blooey McFooey/x86/release/testpackage2': ['setup.hint', 'testpackage2-1.0-1.tar.bz2'],
  'Blooey McFooey/x86/release/testpackage2/testpackage2-subpackage': ['inprogress.SftpXFR.1234',
diff --git a/test/testdata/process_arch/packages.json.expected b/test/testdata/process_arch/packages.json.expected
index 010c8f3..d5c0a9b 100644
--- a/test/testdata/process_arch/packages.json.expected
+++ b/test/testdata/process_arch/packages.json.expected
@@ -306,8 +306,7 @@
  'not one line)",\n'
  '            "versions": {\n'
  '                "stable": [\n'
- '                    "4.1-2",\n'
- '                    "999-1"\n'
+ '                    "4.1-2"\n'
  '                ]\n'
  '            }\n'
  '        },\n'
@@ -409,6 +408,7 @@
  '            "arches": [\n'
  '                "x86"\n'
  '            ],\n'
+ '            "homepage": "http://homepage.url",\n'
  '            "maintainers": [\n'
  '                "Blooey McFooey"\n'
  '            ],\n'
diff --git a/test/testdata/process_arch/rel_area.expected b/test/testdata/process_arch/rel_area.expected
index d3d925c..6751999 100644
--- a/test/testdata/process_arch/rel_area.expected
+++ b/test/testdata/process_arch/rel_area.expected
@@ -1,37 +1,70 @@
 {'.': ['setup.ini'],
  'noarch': ['sha512.sum'],
  'noarch/release': ['sha512.sum'],
- 'noarch/release/obs-a': ['obs-a-1.0-1-src.tar.xz', 'obs-a-1.0-1.hint', 'obs-a-1.0-1.tar.xz', 'sha512.sum'],
- 'noarch/release/obs-b': ['obs-b-1.0-1-src.tar.xz', 'obs-b-1.0-1.hint', 'obs-b-1.0-1.tar.xz', 'sha512.sum'],
- 'noarch/release/perl-Net-SMTP-SSL': ['perl-Net-SMTP-SSL-1.02-1-src.tar.xz',
+ 'noarch/release/obs-a': ['obs-a-1.0-1-src.hint',
+                          'obs-a-1.0-1-src.tar.xz',
+                          'obs-a-1.0-1.hint',
+                          'obs-a-1.0-1.tar.xz',
+                          'sha512.sum'],
+ 'noarch/release/obs-b': ['obs-b-1.0-1-src.hint',
+                          'obs-b-1.0-1-src.tar.xz',
+                          'obs-b-1.0-1.hint',
+                          'obs-b-1.0-1.tar.xz',
+                          'sha512.sum'],
+ 'noarch/release/perl-Net-SMTP-SSL': ['perl-Net-SMTP-SSL-1.02-1-src.hint',
+                                      'perl-Net-SMTP-SSL-1.02-1-src.tar.xz',
                                       'perl-Net-SMTP-SSL-1.02-1.hint',
                                       'perl-Net-SMTP-SSL-1.02-1.tar.xz',
+                                      'perl-Net-SMTP-SSL-1.03-1-src.hint',
                                       'perl-Net-SMTP-SSL-1.03-1-src.tar.xz',
                                       'perl-Net-SMTP-SSL-1.03-1.hint',
                                       'perl-Net-SMTP-SSL-1.03-1.tar.xz',
+                                      'perl-Net-SMTP-SSL-1.03-2-src.hint',
                                       'perl-Net-SMTP-SSL-1.03-2-src.tar.xz',
                                       'perl-Net-SMTP-SSL-1.03-2.hint',
                                       'perl-Net-SMTP-SSL-1.03-2.tar.xz',
                                       'sha512.sum'],
- 'noarch/release/test-c': ['sha512.sum', 'test-c-1.0-1-src.tar.xz', 'test-c-1.0-1.hint', 'test-c-1.0-1.tar.xz'],
- 'noarch/release/test-d': ['sha512.sum', 'test-d-1.0-1-src.tar.xz', 'test-d-1.0-1.hint', 'test-d-1.0-1.tar.xz'],
- 'noarch/release/test-e': ['sha512.sum', 'test-e-1.0-1-src.tar.xz', 'test-e-1.0-1.hint', 'test-e-1.0-1.tar.xz'],
+ 'noarch/release/test-c': ['sha512.sum',
+                           'test-c-1.0-1-src.hint',
+                           'test-c-1.0-1-src.tar.xz',
+                           'test-c-1.0-1.hint',
+                           'test-c-1.0-1.tar.xz'],
+ 'noarch/release/test-d': ['sha512.sum',
+                           'test-d-1.0-1-src.hint',
+                           'test-d-1.0-1-src.tar.xz',
+                           'test-d-1.0-1.hint',
+                           'test-d-1.0-1.tar.xz'],
+ 'noarch/release/test-e': ['sha512.sum',
+                           'test-e-1.0-1-src.hint',
+                           'test-e-1.0-1-src.tar.xz',
+                           'test-e-1.0-1.hint',
+                           'test-e-1.0-1.tar.xz'],
  'x86': ['sha512.sum'],
  'x86/release': ['sha512.sum'],
- 'x86/release/arc': ['arc-4.32.7-10-src.tar.bz2', 'arc-4.32.7-10.hint', 'arc-4.32.7-10.tar.bz2'],
+ 'x86/release/arc': ['arc-4.32.7-10-src.hint',
+                     'arc-4.32.7-10-src.tar.bz2',
+                     'arc-4.32.7-10.hint',
+                     'arc-4.32.7-10.tar.bz2'],
  'x86/release/base-cygwin': ['base-cygwin-3.6-1.hint',
                              'base-cygwin-3.6-1.tar.xz',
                              'base-cygwin-3.8-1.hint',
                              'base-cygwin-3.8-1.tar.xz',
                              'sha512.sum'],
- 'x86/release/corrupt': ['corrupt-2.0.0-1-src.tar.xz', 'corrupt-2.0.0-1.hint', 'corrupt-2.0.0-1.tar.xz', 'sha512.sum'],
+ 'x86/release/corrupt': ['corrupt-2.0.0-1-src.hint',
+                         'corrupt-2.0.0-1-src.tar.xz',
+                         'corrupt-2.0.0-1.hint',
+                         'corrupt-2.0.0-1.tar.xz',
+                         'sha512.sum'],
  'x86/release/cygwin': ['.this-should-be-ignored',
+                        'cygwin-2.2.0-1-src.hint',
                         'cygwin-2.2.0-1-src.tar.xz',
                         'cygwin-2.2.0-1.hint',
                         'cygwin-2.2.0-1.tar.xz',
+                        'cygwin-2.2.1-1-src.hint',
                         'cygwin-2.2.1-1-src.tar.xz',
                         'cygwin-2.2.1-1.hint',
                         'cygwin-2.2.1-1.tar.xz',
+                        'cygwin-2.3.0-0.3-src.hint',
                         'cygwin-2.3.0-0.3-src.tar.xz',
                         'cygwin-2.3.0-0.3.hint',
                         'cygwin-2.3.0-0.3.tar.xz',
@@ -54,9 +87,11 @@
                                      'override.hint',
                                      'sha512.sum'],
  'x86/release/invalid': ['invalid-0.hint', 'sha512.sum'],
- 'x86/release/keychain': ['keychain-2.6.8-1-src.tar.bz2',
+ 'x86/release/keychain': ['keychain-2.6.8-1-src.hint',
+                          'keychain-2.6.8-1-src.tar.bz2',
                           'keychain-2.6.8-1.hint',
                           'keychain-2.6.8-1.tar.bz2',
+                          'keychain-2.7.1-1-src.hint',
                           'keychain-2.7.1-1-src.tar.bz2',
                           'keychain-2.7.1-1.hint',
                           'keychain-2.7.1-1.tar.bz2',
@@ -64,7 +99,8 @@
  'x86/release/libspiro': ['libspiro-20071029-1.hint', 'sha512.sum'],
  'x86/release/libspiro/libspiro-devel': ['libspiro-devel-20071029-1.hint', 'sha512.sum'],
  'x86/release/libspiro/libspiro0': ['libspiro0-20071029-1.hint', 'sha512.sum'],
- 'x86/release/libtextcat': ['libtextcat-2.2-2-src.tar.bz2',
+ 'x86/release/libtextcat': ['libtextcat-2.2-2-src.hint',
+                            'libtextcat-2.2-2-src.tar.bz2',
                             'libtextcat-2.2-2.hint',
                             'libtextcat-2.2-2.tar.bz2',
                             'sha512.sum'],
@@ -72,7 +108,8 @@
                                              'libtextcat-devel-2.2-2.tar.bz2',
                                              'sha512.sum'],
  'x86/release/libtextcat/libtextcat0': ['libtextcat0-2.2-2.hint', 'libtextcat0-2.2-2.tar.bz2', 'sha512.sum'],
- 'x86/release/mDNSResponder': ['mDNSResponder-379.32.1-1-src.tar.bz2',
+ 'x86/release/mDNSResponder': ['mDNSResponder-379.32.1-1-src.hint',
+                               'mDNSResponder-379.32.1-1-src.tar.bz2',
                                'mDNSResponder-379.32.1-1.hint',
                                'mDNSResponder-379.32.1-1.tar.bz2',
                                'sha512.sum'],
@@ -83,33 +120,43 @@
  'x86/release/mingw64-i686-binutils': ['mingw64-i686-binutils-2.29.1.787c9873-1.hint', 'sha512.sum'],
  'x86/release/mingw64-i686-binutils/mingw64-i686-binutils-debuginfo': ['mingw64-i686-binutils-debuginfo-2.29.1.787c9873-1.hint',
                                                                        'sha512.sum'],
- 'x86/release/openssh': ['openssh-7.2p2-1-src.tar.xz', 'openssh-7.2p2-1.hint', 'openssh-7.2p2-1.tar.xz', 'sha512.sum'],
+ 'x86/release/openssh': ['openssh-7.2p2-1-src.hint',
+                         'openssh-7.2p2-1-src.tar.xz',
+                         'openssh-7.2p2-1.hint',
+                         'openssh-7.2p2-1.tar.xz',
+                         'sha512.sum'],
  'x86/release/per-version': ['override.hint',
+                             'per-version-4.0-1-src.hint',
                              'per-version-4.0-1-src.tar.xz',
                              'per-version-4.0-1.hint',
                              'per-version-4.0-1.tar.xz',
+                             'per-version-4.8-1-src.hint',
                              'per-version-4.8-1-src.tar.xz',
                              'per-version-4.8-1.hint',
                              'per-version-4.8-1.tar.xz',
+                             'per-version-5.0-1-src.hint',
                              'per-version-5.0-1-src.tar.xz',
                              'per-version-5.0-1.hint',
                              'per-version-5.0-1.tar.xz',
                              'sha512.sum'],
  'x86/release/per-version-incomplete': ['override.hint',
+                                        'per-version-incomplete-36-1-src.hint',
                                         'per-version-incomplete-36-1-src.tar.xz',
                                         'per-version-incomplete-36-1.hint',
                                         'per-version-incomplete-36-1.tar.xz',
                                         'per-version-incomplete-39-1-src.tar.xz',
                                         'per-version-incomplete-39-1.tar.xz',
                                         'sha512.sum'],
- 'x86/release/per-version-replacement-hint-only': ['per-version-replacement-hint-only-1.0-1-src.tar.xz',
+ 'x86/release/per-version-replacement-hint-only': ['per-version-replacement-hint-only-1.0-1-src.hint',
+                                                   'per-version-replacement-hint-only-1.0-1-src.tar.xz',
                                                    'per-version-replacement-hint-only-1.0-1.hint',
                                                    'per-version-replacement-hint-only-1.0-1.tar.xz',
                                                    'sha512.sum'],
  'x86/release/proj': ['proj-4.8.0-1.hint', 'sha512.sum'],
  'x86/release/proj/libproj-devel': ['libproj-devel-4.8.0-1.hint', 'sha512.sum'],
  'x86/release/proj/libproj1': ['libproj1-4.8.0-1.hint', 'sha512.sum'],
- 'x86/release/rpm-doc': ['rpm-doc-4.1-2-src.tar.bz2',
+ 'x86/release/rpm-doc': ['rpm-doc-4.1-2-src.hint',
+                         'rpm-doc-4.1-2-src.tar.bz2',
                          'rpm-doc-4.1-2.hint',
                          'rpm-doc-4.1-2.tar.bz2',
                          'rpm-doc-999-1.hint',
@@ -118,16 +165,20 @@
  'x86/release/splint': ['sha512.sum', 'splint-3.1.2-1.hint'],
  'x86/release/staleversion': ['override.hint',
                               'sha512.sum',
+                              'staleversion-243-0-src.hint',
                               'staleversion-243-0-src.tar.xz',
                               'staleversion-243-0.hint',
                               'staleversion-243-0.tar.xz',
+                              'staleversion-250-0-src.hint',
                               'staleversion-250-0-src.tar.xz',
                               'staleversion-250-0.hint',
                               'staleversion-250-0.tar.xz',
+                              'staleversion-260-0-src.hint',
                               'staleversion-260-0-src.tar.xz',
                               'staleversion-260-0.hint',
                               'staleversion-260-0.tar.xz'],
  'x86/release/testpackage': ['sha512.sum',
+                             'testpackage-1.0-1-src.hint',
                              'testpackage-1.0-1-src.tar.bz2',
                              'testpackage-1.0-1.hint',
                              'testpackage-1.0-1.tar.bz2'],
diff --git a/test/testdata/process_arch/setup.ini.expected b/test/testdata/process_arch/setup.ini.expected
index 5ec1b8e..e150e61 100644
--- a/test/testdata/process_arch/setup.ini.expected
+++ b/test/testdata/process_arch/setup.ini.expected
@@ -253,16 +253,16 @@
  'depends2: base-cygwin\n'
  '\n'
  '@ per-version-replacement-hint-only\n'
- 'sdesc: "Per-version hint test package"\n'
- 'ldesc: "Per-version hint test package"\n'
+ 'sdesc: "Replacement per-version hint test package - updated"\n'
+ 'ldesc: "Replacement per-version hint test package - updated"\n'
  'category: Base\n'
- 'requires: cygwin\n'
+ 'requires: base-cygwin per-version\n'
  'version: 1.0-1\n'
  'install: x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1.tar.xz 228 '
  'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
  'source: x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src.tar.xz 228 '
  'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
- 'depends2: cygwin\n'
+ 'depends2: base-cygwin, per-version\n'
  '\n'
  '@ perl-Net-SMTP-SSL\n'
  'sdesc: "Perl distribution Net-SMTP-SSL"\n'
@@ -363,8 +363,8 @@
  'version: 1.0-1\n'
  'install: x86/release/testpackage/testpackage-1.0-1.tar.bz2 195 '
  'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83\n'
- 'source: x86/release/testpackage/testpackage-1.0-1-src.tar.bz2 195 '
- 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83\n'
+ 'source: x86/release/testpackage/testpackage-1.0-1-src.tar.bz2 266 '
+ 'acfd77df3347e6432ccf29c12989964bc680a158d574f85dfa7ef222759f411006c7bd2773e37c5abdee628bea769b2da9aae213db615cd91402fd385373933d\n'
  'depends2: cygwin\n'
  '\n'
  '@ testpackage-subpackage\n'
@@ -374,5 +374,5 @@
  'version: 1.0-1\n'
  'install: x86/release/testpackage/testpackage-subpackage/testpackage-subpackage-1.0-1.tar.bz2 195 '
  'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83\n'
- 'source: x86/release/testpackage/testpackage-1.0-1-src.tar.bz2 195 '
- 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83\n',)
+ 'source: x86/release/testpackage/testpackage-1.0-1-src.tar.bz2 266 '
+ 'acfd77df3347e6432ccf29c12989964bc680a158d574f85dfa7ef222759f411006c7bd2773e37c5abdee628bea769b2da9aae213db615cd91402fd385373933d\n',)
diff --git a/test/testdata/process_arch/vault.expected b/test/testdata/process_arch/vault.expected
index e14d68d..5276fcb 100644
--- a/test/testdata/process_arch/vault.expected
+++ b/test/testdata/process_arch/vault.expected
@@ -1,18 +1,25 @@
 {'.': [],
  'noarch': [],
  'noarch/release': [],
- 'noarch/release/perl-Net-SMTP-SSL': ['perl-Net-SMTP-SSL-1.01-1-src.tar.xz',
+ 'noarch/release/perl-Net-SMTP-SSL': ['perl-Net-SMTP-SSL-1.01-1-src.hint',
+                                      'perl-Net-SMTP-SSL-1.01-1-src.tar.xz',
                                       'perl-Net-SMTP-SSL-1.01-1.hint',
                                       'perl-Net-SMTP-SSL-1.01-1.tar.xz'],
  'x86': [],
  'x86/release': [],
- 'x86/release/staleversion': ['staleversion-240-1-src.tar.xz',
+ 'x86/release/staleversion': ['staleversion-240-1-src.hint',
+                              'staleversion-240-1-src.tar.xz',
                               'staleversion-240-1.hint',
                               'staleversion-240-1.tar.xz',
+                              'staleversion-242-0-src.hint',
                               'staleversion-242-0-src.tar.xz',
                               'staleversion-242-0.hint',
                               'staleversion-242-0.tar.xz',
+                              'staleversion-251-0-src.hint',
                               'staleversion-251-0-src.tar.xz',
                               'staleversion-251-0.hint',
                               'staleversion-251-0.tar.xz'],
- 'x86/release/testpackage': ['testpackage-0.1-1-src.tar.bz2', 'testpackage-0.1-1.hint', 'testpackage-0.1-1.tar.bz2']}
+ 'x86/release/testpackage': ['testpackage-0.1-1-src.hint',
+                             'testpackage-0.1-1-src.tar.bz2',
+                             'testpackage-0.1-1.hint',
+                             'testpackage-0.1-1.tar.bz2']}
diff --git a/test/testdata/relarea/noarch/release/obs-a/obs-a-1.0-1-src.hint b/test/testdata/relarea/noarch/release/obs-a/obs-a-1.0-1-src.hint
new file mode 100755
index 0000000..1e7ec26
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/obs-a/obs-a-1.0-1-src.hint
@@ -0,0 +1,2 @@
+category: Devel
+sdesc: "obsolete package A"
diff --git a/test/testdata/relarea/noarch/release/obs-b/obs-b-1.0-1-src.hint b/test/testdata/relarea/noarch/release/obs-b/obs-b-1.0-1-src.hint
new file mode 100755
index 0000000..cc7c23c
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/obs-b/obs-b-1.0-1-src.hint
@@ -0,0 +1,2 @@
+category: Devel
+sdesc: "obsolete package B"
diff --git a/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1-src.hint b/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1-src.hint
new file mode 100644
index 0000000..f91a0e1
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1-src.hint
@@ -0,0 +1,5 @@
+category: Perl
+requires:
+sdesc: "Perl distribution Net-SMTP-SSL"
+ldesc: "Implements the same API as Net::SMTP, but uses IO::Socket::SSL for
+its network operations in order to support encrypted connections."
diff --git a/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1-src.hint b/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1-src.hint
new file mode 100644
index 0000000..f91a0e1
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1-src.hint
@@ -0,0 +1,5 @@
+category: Perl
+requires:
+sdesc: "Perl distribution Net-SMTP-SSL"
+ldesc: "Implements the same API as Net::SMTP, but uses IO::Socket::SSL for
+its network operations in order to support encrypted connections."
diff --git a/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1-src.hint b/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1-src.hint
new file mode 100644
index 0000000..f91a0e1
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1-src.hint
@@ -0,0 +1,5 @@
+category: Perl
+requires:
+sdesc: "Perl distribution Net-SMTP-SSL"
+ldesc: "Implements the same API as Net::SMTP, but uses IO::Socket::SSL for
+its network operations in order to support encrypted connections."
diff --git a/test/testdata/relarea/noarch/release/test-c/test-c-1.0-1-src.hint b/test/testdata/relarea/noarch/release/test-c/test-c-1.0-1-src.hint
new file mode 100755
index 0000000..4610d7a
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/test-c/test-c-1.0-1-src.hint
@@ -0,0 +1,4 @@
+category: Devel
+sdesc: "test package C"
+obsoletes: obs-a obs-b
+depends: test-d (>= 1.0), test-e
diff --git a/test/testdata/relarea/noarch/release/test-d/test-d-1.0-1-src.hint b/test/testdata/relarea/noarch/release/test-d/test-d-1.0-1-src.hint
new file mode 100755
index 0000000..39cc9d0
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/test-d/test-d-1.0-1-src.hint
@@ -0,0 +1,3 @@
+category: Devel
+sdesc: "test package D"
+version: 1.0.42590-1
diff --git a/test/testdata/relarea/noarch/release/test-e/test-e-1.0-1-src.hint b/test/testdata/relarea/noarch/release/test-e/test-e-1.0-1-src.hint
new file mode 100755
index 0000000..d151b15
--- /dev/null
+++ b/test/testdata/relarea/noarch/release/test-e/test-e-1.0-1-src.hint
@@ -0,0 +1,3 @@
+category: Devel
+sdesc: "test package E"
+build-depends: libtextcat-devel
diff --git a/test/testdata/relarea/x86/release/arc/arc-4.32.7-10-src.hint b/test/testdata/relarea/x86/release/arc/arc-4.32.7-10-src.hint
new file mode 100644
index 0000000..718cb55
--- /dev/null
+++ b/test/testdata/relarea/x86/release/arc/arc-4.32.7-10-src.hint
@@ -0,0 +1,8 @@
+sdesc: "The ARC archive utility"
+ldesc: "This program is based on the MSDOS ARC program, version 5.21, plus a
+few enhancements. ARC performs Huffman Squeezing on data. The Huffman
+Squeeze algorithm was removed from MSDOS ARC after version 5.12. It
+turns out to be more efficient than Lempel-Ziv style compression when
+compressing graphic images. Squeeze analysis is always done now, and
+the best of packing, squeezing, or crunching is used."
+category: Archive
diff --git a/test/testdata/relarea/x86/release/corrupt/corrupt-2.0.0-1-src.hint b/test/testdata/relarea/x86/release/corrupt/corrupt-2.0.0-1-src.hint
new file mode 100644
index 0000000..fa85bcc
--- /dev/null
+++ b/test/testdata/relarea/x86/release/corrupt/corrupt-2.0.0-1-src.hint
@@ -0,0 +1,3 @@
+sdesc: "A corrupt package"
+ldesc: "A package containing corrupt archives"
+category: Devel
diff --git a/test/testdata/relarea/x86/release/cygwin/cygwin-2.2.0-1-src.hint b/test/testdata/relarea/x86/release/cygwin/cygwin-2.2.0-1-src.hint
new file mode 100644
index 0000000..be59e34
--- /dev/null
+++ b/test/testdata/relarea/x86/release/cygwin/cygwin-2.2.0-1-src.hint
@@ -0,0 +1,4 @@
+sdesc: "The UNIX emulation engine"
+ldesc: "The UNIX emulation engine"
+category: Base
+requires: base-cygwin
diff --git a/test/testdata/relarea/x86/release/cygwin/cygwin-2.2.1-1-src.hint b/test/testdata/relarea/x86/release/cygwin/cygwin-2.2.1-1-src.hint
new file mode 100644
index 0000000..be59e34
--- /dev/null
+++ b/test/testdata/relarea/x86/release/cygwin/cygwin-2.2.1-1-src.hint
@@ -0,0 +1,4 @@
+sdesc: "The UNIX emulation engine"
+ldesc: "The UNIX emulation engine"
+category: Base
+requires: base-cygwin
diff --git a/test/testdata/relarea/x86/release/cygwin/cygwin-2.3.0-0.3-src.hint b/test/testdata/relarea/x86/release/cygwin/cygwin-2.3.0-0.3-src.hint
new file mode 100644
index 0000000..9e3e36e
--- /dev/null
+++ b/test/testdata/relarea/x86/release/cygwin/cygwin-2.3.0-0.3-src.hint
@@ -0,0 +1,7 @@
+sdesc: "The UNIX emulation engine"
+ldesc: "The UNIX emulation engine"
+category: Base
+requires: base-cygwin
+provides: cygwin-api0_291
+conflicts: fruit-juice
+test:
diff --git a/test/testdata/relarea/x86/release/keychain/keychain-2.6.8-1-src.hint b/test/testdata/relarea/x86/release/keychain/keychain-2.6.8-1-src.hint
new file mode 100644
index 0000000..7870969
--- /dev/null
+++ b/test/testdata/relarea/x86/release/keychain/keychain-2.6.8-1-src.hint
@@ -0,0 +1,12 @@
+sdesc: "Key manager for OpenSSH"
+ldesc: "Keychain is an OpenSSH key manager, typically run from
+~/.bash_profile. When keychain is run, it checks for a running
+ssh-agent, otherwise it starts one. It saves the ssh-agent environment
+variables to ~/.keychain/$HOSTNAME-sh, so that subsequent logins
+and non-interactive shells such as cron jobs can source the file and
+make passwordless ssh connections. In addition, when keychain runs, it
+verifies that the key files specified on the command-line are known to
+ssh-agent, otherwise it loads them, prompting you for a password if
+necessary"
+category: Utils
+requires: openssh
diff --git a/test/testdata/relarea/x86/release/keychain/keychain-2.7.1-1-src.hint b/test/testdata/relarea/x86/release/keychain/keychain-2.7.1-1-src.hint
new file mode 100644
index 0000000..7870969
--- /dev/null
+++ b/test/testdata/relarea/x86/release/keychain/keychain-2.7.1-1-src.hint
@@ -0,0 +1,12 @@
+sdesc: "Key manager for OpenSSH"
+ldesc: "Keychain is an OpenSSH key manager, typically run from
+~/.bash_profile. When keychain is run, it checks for a running
+ssh-agent, otherwise it starts one. It saves the ssh-agent environment
+variables to ~/.keychain/$HOSTNAME-sh, so that subsequent logins
+and non-interactive shells such as cron jobs can source the file and
+make passwordless ssh connections. In addition, when keychain runs, it
+verifies that the key files specified on the command-line are known to
+ssh-agent, otherwise it loads them, prompting you for a password if
+necessary"
+category: Utils
+requires: openssh
diff --git a/test/testdata/relarea/x86/release/libtextcat/libtextcat-2.2-2-src.hint b/test/testdata/relarea/x86/release/libtextcat/libtextcat-2.2-2-src.hint
new file mode 100644
index 0000000..5145c2d
--- /dev/null
+++ b/test/testdata/relarea/x86/release/libtextcat/libtextcat-2.2-2-src.hint
@@ -0,0 +1,10 @@
+sdesc: "Text Classification Library (language guessing in C)"
+ldesc: "Libtextcat is a library with functions that implement the
+classification technique described in Cavnar & Trenkle, "N-Gram-Based
+Text Categorization". It was primarily developed for language
+guessing, a task on which it is known to perform with near-perfect
+accuracy. 
+BSD License.
+http://software.wise-guys.nl/libtextcat/"
+category: Text
+requires: libtextcat0
diff --git a/test/testdata/relarea/x86/release/mDNSResponder/mDNSResponder-379.32.1-1-src.hint b/test/testdata/relarea/x86/release/mDNSResponder/mDNSResponder-379.32.1-1-src.hint
new file mode 100644
index 0000000..e50938b
--- /dev/null
+++ b/test/testdata/relarea/x86/release/mDNSResponder/mDNSResponder-379.32.1-1-src.hint
@@ -0,0 +1,11 @@
+category: Net
+requires: libdns_sd1 
+sdesc: "Bonjour Zeroconf implementation"
+ldesc: "Bonjour, also known as zero-configuration networking, enables
+automatic discovery of computers, devices, and services on IP networks using
+industry standard IP protocols."
+
+message: mDNSResponder "The Cygwin mDNSResponder package contains only clients.
+If you do not already have the 'Bonjour Service' installed (it comes with
+a number of popular Windows programs), then you can download it at
+http://support.apple.com/kb/DL999"
diff --git a/test/testdata/relarea/x86/release/openssh/openssh-7.2p2-1-src.hint b/test/testdata/relarea/x86/release/openssh/openssh-7.2p2-1-src.hint
new file mode 100644
index 0000000..83aa11a
--- /dev/null
+++ b/test/testdata/relarea/x86/release/openssh/openssh-7.2p2-1-src.hint
@@ -0,0 +1,5 @@
+category: Net
+sdesc: "The OpenSSH server and client programs"
+ldesc: "OpenSSH is a program for logging into a remote machine and for
+	executing commands on a remote machine.  It can replace rlogin and rsh,
+	providing encrypted communication between two machines."
diff --git a/test/testdata/relarea/x86/release/per-version-incomplete/per-version-incomplete-36-1-src.hint b/test/testdata/relarea/x86/release/per-version-incomplete/per-version-incomplete-36-1-src.hint
new file mode 100644
index 0000000..db723c3
--- /dev/null
+++ b/test/testdata/relarea/x86/release/per-version-incomplete/per-version-incomplete-36-1-src.hint
@@ -0,0 +1,3 @@
+sdesc: "Per-version hint test package"
+ldesc: "Per-version hint test package with missing hint data for some versions"
+category: Base
diff --git a/test/testdata/relarea/x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src.hint b/test/testdata/relarea/x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src.hint
new file mode 100644
index 0000000..726738d
--- /dev/null
+++ b/test/testdata/relarea/x86/release/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Per-version hint test package"
+ldesc: "Per-version hint test package"
+category: Base
+requires: cygwin
diff --git a/test/testdata/relarea/x86/release/per-version/per-version-4.0-1-src.hint b/test/testdata/relarea/x86/release/per-version/per-version-4.0-1-src.hint
new file mode 100644
index 0000000..726738d
--- /dev/null
+++ b/test/testdata/relarea/x86/release/per-version/per-version-4.0-1-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Per-version hint test package"
+ldesc: "Per-version hint test package"
+category: Base
+requires: cygwin
diff --git a/test/testdata/relarea/x86/release/per-version/per-version-4.8-1-src.hint b/test/testdata/relarea/x86/release/per-version/per-version-4.8-1-src.hint
new file mode 100644
index 0000000..1f86c0b
--- /dev/null
+++ b/test/testdata/relarea/x86/release/per-version/per-version-4.8-1-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Per-version hint test package"
+ldesc: "Per-version hint test package"
+category: Base
+requires: base-cygwin
diff --git a/test/testdata/relarea/x86/release/rpm-doc/rpm-doc-4.1-2-src.hint b/test/testdata/relarea/x86/release/rpm-doc/rpm-doc-4.1-2-src.hint
new file mode 100644
index 0000000..087a6dd
--- /dev/null
+++ b/test/testdata/relarea/x86/release/rpm-doc/rpm-doc-4.1-2-src.hint
@@ -0,0 +1,2 @@
+sdesc: "Obsolete package for RPM package management system manual pages (extra text to so repr is not one line)"
+category: _obsolete
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-240-1-src.hint b/test/testdata/relarea/x86/release/staleversion/staleversion-240-1-src.hint
new file mode 100644
index 0000000..7f7f48a
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/staleversion-240-1-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Test package for stale version removal"
+ldesc: "Test package for stale version removal"
+category: Shells Base
+requires:
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-242-0-src.hint b/test/testdata/relarea/x86/release/staleversion/staleversion-242-0-src.hint
new file mode 100644
index 0000000..7f7f48a
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/staleversion-242-0-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Test package for stale version removal"
+ldesc: "Test package for stale version removal"
+category: Shells Base
+requires:
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-243-0-src.hint b/test/testdata/relarea/x86/release/staleversion/staleversion-243-0-src.hint
new file mode 100644
index 0000000..7f7f48a
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/staleversion-243-0-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Test package for stale version removal"
+ldesc: "Test package for stale version removal"
+category: Shells Base
+requires:
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-250-0-src.hint b/test/testdata/relarea/x86/release/staleversion/staleversion-250-0-src.hint
new file mode 100644
index 0000000..7f7f48a
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/staleversion-250-0-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Test package for stale version removal"
+ldesc: "Test package for stale version removal"
+category: Shells Base
+requires:
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-251-0-src.hint b/test/testdata/relarea/x86/release/staleversion/staleversion-251-0-src.hint
new file mode 100644
index 0000000..7f7f48a
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/staleversion-251-0-src.hint
@@ -0,0 +1,4 @@
+sdesc: "Test package for stale version removal"
+ldesc: "Test package for stale version removal"
+category: Shells Base
+requires:
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-260-0-src.hint b/test/testdata/relarea/x86/release/staleversion/staleversion-260-0-src.hint
new file mode 100644
index 0000000..5d7b35e
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/staleversion-260-0-src.hint
@@ -0,0 +1,5 @@
+sdesc: "Test package for stale version removal"
+ldesc: "Test package for stale version removal"
+category: Shells Base
+requires:
+test:
diff --git a/test/testdata/relarea/x86/release/testpackage/testpackage-0.1-1-src.hint b/test/testdata/relarea/x86/release/testpackage/testpackage-0.1-1-src.hint
new file mode 100644
index 0000000..abfbfd5
--- /dev/null
+++ b/test/testdata/relarea/x86/release/testpackage/testpackage-0.1-1-src.hint
@@ -0,0 +1,3 @@
+sdesc: "A test package (stuff & other stuff)"
+ldesc: "A test package (stuff & other stuff)"
+category: Devel
diff --git a/test/testdata/uploads/move.expected b/test/testdata/uploads/move.expected
index fda6084..bfb7728 100644
--- a/test/testdata/uploads/move.expected
+++ b/test/testdata/uploads/move.expected
@@ -1,4 +1,7 @@
-{'x86/release/testpackage': ['testpackage-1.0-1-src.tar.bz2', 'testpackage-1.0-1.hint', 'testpackage-1.0-1.tar.bz2'],
+{'x86/release/testpackage': ['testpackage-1.0-1-src.hint',
+                             'testpackage-1.0-1-src.tar.bz2',
+                             'testpackage-1.0-1.hint',
+                             'testpackage-1.0-1.tar.bz2'],
  'x86/release/testpackage/testpackage-subpackage': ['testpackage-subpackage-1.0-1.hint',
                                                     'testpackage-subpackage-1.0-1.tar.bz2'],
  'x86/release/testpackage2/testpackage2-subpackage': ['testpackage2-subpackage-1.0-1.hint',
diff --git a/test/testdata/uploads/pkglist.expected b/test/testdata/uploads/pkglist.expected
index a928e8d..99cdd09 100644
--- a/test/testdata/uploads/pkglist.expected
+++ b/test/testdata/uploads/pkglist.expected
@@ -6,13 +6,14 @@
            'category': 'Devel',
            'requires': 'cygwin',
            'depends': 'cygwin'}}, {}, False),
- 'testpackage-src': Package('testpackage', {'1.0-1': {'testpackage-1.0-1-src.tar.bz2': Tar('testpackage-1.0-1-src.tar.bz2', 'x86/release/testpackage', 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83', 195, False)}}, {'1.0-1': {'sdesc': '"A test package"',
+ 'testpackage-src': Package('testpackage', {'1.0-1': {'testpackage-1.0-1-src.tar.bz2': Tar('testpackage-1.0-1-src.tar.bz2', 'x86/release/testpackage', 'acfd77df3347e6432ccf29c12989964bc680a158d574f85dfa7ef222759f411006c7bd2773e37c5abdee628bea769b2da9aae213db615cd91402fd385373933d', 266, False)}}, {'1.0-1': {'sdesc': '"A test package"',
            'ldesc': '"A test package\n'
                     "It's description might contains some unicode junk\n"
                     'Like it’s you’re Markup Language™ Nokogiri’s tool―that '
                     'Bézier."',
            'category': 'Devel',
            'requires': 'cygwin',
+           'homepage': 'http://homepage.url',
            'depends': 'cygwin'}}, {}, True),
  'testpackage-subpackage': Package('testpackage/testpackage-subpackage', {'1.0-1': {'testpackage-subpackage-1.0-1.tar.bz2': Tar('testpackage-subpackage-1.0-1.tar.bz2', 'x86/release/testpackage/testpackage-subpackage', 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83', 195, False)}}, {'1.0-1': {'sdesc': '"A test subpackage"',
            'ldesc': '"A test subpackage"',
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.