Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/cygwin-apps/calm.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Turney <jon.turney@dronecode.org.uk>2019-06-07 19:36:20 +0300
committerJon Turney <jon.turney@dronecode.org.uk>2019-07-04 14:44:26 +0300
commitf0cf563288d3b0e17bb53b570395a4fd23b13f19 (patch)
treef570a4c650a1d6ca856a02750052050bfa124d8c
parentdec704d7feb89f1a173c03f82369adc0256d72c8 (diff)
Create a separate package object for the source package
Create separate package objects for the binary and source packages. This is generally a simplification to the data model. One slight wrinkle is that stale file detection needs to be aware that .hint files may now be used by both a binary and source packages, and so should only be removed if both packages are stale. (Since the source package cannot be stale if the binary package isn't, we solve this by making the source package control the staleness of the hint, in that case [except for archives which are sourceless for permitted reasons, which we now explicitly annotate as such]). 'external-source' is now always followed, rather than checking for the source for a given version in the current package first. This exposes a handful of (migrated) hints which contain an unnecessary external-source. Write separate package summary pages for source packages Always create binary packages when uploading to allow replacement hints, otherwise, only create a package if there's archives for it to contain to avoid creating empty packages from the relarea. Note: since we don't put source packages into a separate namespace, there is a potential collision if both 'foo' (source package 'foo-src'), and 'foo-src' (source package 'foo-src-src') exist. That would be daft, and there aren't currently any examples of this. Forbid package names ending in '-src' to avoid such problems.
-rw-r--r--TODO1
-rwxr-xr-xcalm/package.py331
-rw-r--r--calm/past_mistakes.py4
-rwxr-xr-xcalm/pkg2html.py76
-rw-r--r--calm/uploads.py2
-rwxr-xr-xtest/test_calm.py3
-rw-r--r--test/testdata/htdocs.expected/dirtree.expected101
-rw-r--r--[-rwxr-xr-x]test/testdata/htdocs.expected/packages.inc0
-rwxr-xr-xtest/testdata/htdocs.expected/summary/arc-src.html35
-rw-r--r--test/testdata/htdocs.expected/summary/arc.html3
-rw-r--r--test/testdata/htdocs.expected/summary/base-cygwin.html2
-rwxr-xr-xtest/testdata/htdocs.expected/summary/corrupt-src.html30
-rw-r--r--test/testdata/htdocs.expected/summary/corrupt.html3
-rw-r--r--test/testdata/htdocs.expected/summary/cygwin-debuginfo.html2
-rw-r--r--test/testdata/htdocs.expected/summary/cygwin-devel.html2
-rwxr-xr-xtest/testdata/htdocs.expected/summary/cygwin-src.html32
-rw-r--r--test/testdata/htdocs.expected/summary/cygwin.html5
-rwxr-xr-xtest/testdata/htdocs.expected/summary/keychain-src.html39
-rw-r--r--test/testdata/htdocs.expected/summary/keychain.html4
-rw-r--r--test/testdata/htdocs.expected/summary/libdns_sd-devel.html2
-rw-r--r--test/testdata/htdocs.expected/summary/libdns_sd1.html2
-rwxr-xr-xtest/testdata/htdocs.expected/summary/mDNSResponder-src.html32
-rw-r--r--test/testdata/htdocs.expected/summary/mDNSResponder.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/obs-a-src.html30
-rw-r--r--test/testdata/htdocs.expected/summary/obs-a.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/obs-b-src.html30
-rw-r--r--test/testdata/htdocs.expected/summary/obs-b.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/openssh-src.html32
-rw-r--r--test/testdata/htdocs.expected/summary/openssh.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/per-version-replacement-hint-only-src.html30
-rw-r--r--test/testdata/htdocs.expected/summary/per-version-replacement-hint-only.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/per-version-src.html31
-rw-r--r--test/testdata/htdocs.expected/summary/per-version.html4
-rwxr-xr-xtest/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL-src.html33
-rw-r--r--test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL.html5
-rwxr-xr-xtest/testdata/htdocs.expected/summary/rpm-doc-src.html26
-rw-r--r--test/testdata/htdocs.expected/summary/rpm-doc.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/staleversion-src.html35
-rw-r--r--test/testdata/htdocs.expected/summary/staleversion.html8
-rwxr-xr-xtest/testdata/htdocs.expected/summary/test-c-src.html30
-rw-r--r--test/testdata/htdocs.expected/summary/test-c.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/test-d-src.html30
-rw-r--r--test/testdata/htdocs.expected/summary/test-d.html3
-rwxr-xr-xtest/testdata/htdocs.expected/summary/test-e-src.html31
-rw-r--r--test/testdata/htdocs.expected/summary/test-e.html4
-rwxr-xr-xtest/testdata/htdocs.expected/summary/testpackage-src.html30
-rw-r--r--test/testdata/htdocs.expected/summary/testpackage.html3
-rw-r--r--test/testdata/htdocs.expected/x86/arc-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/arc-src/arc-4.32.7-10-src13
-rw-r--r--test/testdata/htdocs.expected/x86/corrupt-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/corrupt-src/corrupt-2.0.0-1-src14
-rw-r--r--test/testdata/htdocs.expected/x86/cygwin-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.0-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.1-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.3.0-0.3-src13
-rw-r--r--test/testdata/htdocs.expected/x86/keychain-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/keychain-src/keychain-2.6.8-1-src14
-rw-r--r--test/testdata/htdocs.expected/x86/keychain-src/keychain-2.7.1-1-src16
-rw-r--r--test/testdata/htdocs.expected/x86/mDNSResponder-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/mDNSResponder-src/mDNSResponder-379.32.1-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/obs-a-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/obs-a-src/obs-a-1.0-1-src12
-rw-r--r--test/testdata/htdocs.expected/x86/obs-b-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/obs-b-src/obs-b-1.0-1-src12
-rw-r--r--test/testdata/htdocs.expected/x86/openssh-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/openssh-src/openssh-7.2p2-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/per-version-replacement-hint-only-1.0-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/per-version-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/per-version-src/per-version-4.0-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/per-version-src/per-version-4.8-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.01-1-src14
-rw-r--r--test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.02-1-src14
-rw-r--r--test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.03-1-src14
-rw-r--r--test/testdata/htdocs.expected/x86/rpm-doc-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/rpm-doc-src/rpm-doc-4.1-2-src11
-rw-r--r--test/testdata/htdocs.expected/x86/staleversion-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/staleversion-src/staleversion-240-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86/staleversion-src/staleversion-242-0-src13
-rw-r--r--test/testdata/htdocs.expected/x86/staleversion-src/staleversion-243-0-src13
-rw-r--r--test/testdata/htdocs.expected/x86/staleversion-src/staleversion-250-0-src13
-rw-r--r--test/testdata/htdocs.expected/x86/staleversion-src/staleversion-251-0-src13
-rw-r--r--test/testdata/htdocs.expected/x86/staleversion-src/staleversion-260-0-src13
-rw-r--r--test/testdata/htdocs.expected/x86/test-c-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/test-c-src/test-c-1.0-1-src12
-rw-r--r--test/testdata/htdocs.expected/x86/test-d-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/test-d-src/test-d-1.0-1-src12
-rw-r--r--test/testdata/htdocs.expected/x86/test-e-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/test-e-src/test-e-1.0-1-src12
-rw-r--r--test/testdata/htdocs.expected/x86/testpackage-src/.htaccess2
-rw-r--r--test/testdata/htdocs.expected/x86/testpackage-src/testpackage-0.1-1-src13
-rw-r--r--test/testdata/htdocs.expected/x86_64/.htaccess1
-rw-r--r--test/testdata/process_arch/htdocs.expected120
-rw-r--r--test/testdata/uploads/pkglist.expected13
95 files changed, 1387 insertions, 273 deletions
diff --git a/TODO b/TODO
index 9d1ddd1..c7c6f26 100644
--- a/TODO
+++ b/TODO
@@ -10,3 +10,4 @@
* atomically update .ini/.sig (rename of containing directory, if we put release/ was somewhere else?)
* report changes in override.hint like we used to for setup.hint
* maintainers.py should only re-read cygwin-pkg-maint if it's changed
+* empty install packages should only come in two variants: no dependencies and in _obsolete category, or with dependencies and in 'meta' category
diff --git a/calm/package.py b/calm/package.py
index 7a60cc5..ef03e11 100755
--- a/calm/package.py
+++ b/calm/package.py
@@ -26,6 +26,7 @@
#
from collections import defaultdict
+from enum import Enum, unique
import copy
import difflib
import hashlib
@@ -46,6 +47,12 @@ from . import maintainers
from . import past_mistakes
+# kinds of packages @unique
+class Kind(Enum):
+ binary = 1 # aka 'install'
+ source = 2
+
+
# information we keep about a package
class Package(object):
def __init__(self):
@@ -106,7 +113,7 @@ def read_packages(rel_area, arch):
logging.debug('reading packages from %s' % releasedir)
for (dirpath, subdirs, files) in os.walk(releasedir, followlinks=True):
- read_package(packages[root], rel_area, dirpath, files)
+ read_package_dir(packages[root], rel_area, dirpath, files)
logging.debug("%d packages read from %s" % (len(packages[root]), releasedir))
@@ -173,23 +180,100 @@ def clean_hints(p, hints, warnings):
#
-# read a single package
+# read a single package directory
+#
+# (may contain at most one source package and one binary package)
+# (return True if problems, False otherwise)
#
-def read_package(packages, basedir, dirpath, files, remove=[]):
+
+def read_package_dir(packages, basedir, dirpath, files, remove=[], upload=False):
relpath = os.path.relpath(dirpath, basedir)
- warnings = False
- if any([f.endswith('.hint') for f in files]):
- # the package name is always the directory name
- p = os.path.basename(dirpath)
+ # the package name is always the directory name
+ p = os.path.basename(dirpath)
+
+ # no .hint files
+ if not any([f.endswith('.hint') for f in files]):
+ if (relpath.count(os.path.sep) > 1):
+ for s in ['md5.sum', 'sha512.sum']:
+ if s in files:
+ files.remove(s)
+
+ if len(files) > 0:
+ logging.error("no .hint files in %s but has files: %s" % (dirpath, ', '.join(files)))
+ return True
+
+ return False
+
+ # discard obsolete md5.sum
+ if 'md5.sum' in files:
+ files.remove('md5.sum')
+
+ # ignore dotfiles and backup files
+ for f in files[:]:
+ if f.startswith('.') or f.endswith('.bak'):
+ files.remove(f)
+
+ # classify files for which kind of package they belong to
+ fl = {}
+ for kind in list(Kind) + ['all']:
+ fl[kind] = []
+
+ for f in files[:]:
+ if f == 'sha512.sum' or f == 'override.hint':
+ fl['all'].append(f)
+ files.remove(f)
+ elif re.match(r'^' + re.escape(p) + r'.*\.hint$', f):
+ fl['all'].append(f)
+ files.remove(f)
+ elif re.match(r'^' + re.escape(p) + r'.*\.tar\.(bz2|gz|lzma|xz)$', f):
+ if '-src.tar' in f:
+ fl[Kind.source].append(f)
+ else:
+ fl[Kind.binary].append(f)
+ files.remove(f)
+
+ # read package
+ result = False
+ for kind in Kind:
+ # always create binary packages when uploading to allow replacement
+ # hints, otherwise, only create a package if there's archives for it to
+ # contain
+ if fl[kind] or (upload and kind == Kind.binary):
+ result = read_one_package(packages, p, relpath, dirpath, fl[kind] + fl['all'], remove, kind) or result
+
+ # warn about unexpected files, including tarfiles which don't match the
+ # package name
+ if files:
+ logging.error("unexpected files in %s: %s" % (p, ', '.join(files)))
+ result = True
+
+ return result
+
+
+#
+# read a single package
+#
+def read_one_package(packages, p, relpath, dirpath, files, remove, kind):
+ warnings = False
if not re.match(r'^[\w\-._+]*$', p):
logging.error("package '%s' name contains illegal characters" % p)
return True
+ # assumption: no real package names end with '-src'
+ #
+ # enforce this, because source and install package names exist in a
+ # single namespace currently, and otherwise there could be a collision
+ if p.endswith('-src'):
+ logging.error("package '%s' name ends with '-src'" % p)
+ return True
+
# check for duplicate package names at different paths
(_, _, pkgpath) = relpath.split(os.sep, 2)
- if p in packages:
+ pn = p + ('-src' if kind == Kind.source else '')
+
+ if pn in packages:
logging.error("duplicate package name at paths %s and %s" %
(relpath, packages[p].pkgpath))
return True
@@ -229,10 +313,6 @@ def read_package(packages, basedir, dirpath, files, remove=[]):
else:
logging.warning("bad line '%s' in sha512.sum for package '%s'" % (l.strip(), p))
- # discard obsolete md5.sum
- if 'md5.sum' in files:
- files.remove('md5.sum')
-
# build a list of version-releases (since replacement pvr.hint files are
# allowed to be uploaded, we must consider both .tar and .hint files for
# that), and collect the attributes for each tar file
@@ -240,18 +320,11 @@ def read_package(packages, basedir, dirpath, files, remove=[]):
vr_list = set()
for f in list(files):
- match = re.match(r'^' + re.escape(p) + r'.*\.(tar\.(bz2|gz|lzma|xz)|hint)$', f)
- if not match:
- continue
-
- if not f.endswith('.hint'):
- files.remove(f)
-
# warn if filename doesn't follow P-V-R naming convention
#
# P must match the package name, V can contain anything, R must
# start with a number
- match = re.match(r'^' + re.escape(p) + r'-(.+)-(\d[0-9a-zA-Z.]*)(-src|)\.' + match.group(1) + '$', f)
+ match = re.match(r'^' + re.escape(p) + r'-(.+)-(\d[0-9a-zA-Z.]*)(-src|)\.(tar\.(bz2|gz|lzma|xz)|hint)$', f)
if not match:
logging.error("file '%s' in package '%s' doesn't follow naming convention" % (f, p))
return True
@@ -308,7 +381,6 @@ def read_package(packages, basedir, dirpath, files, remove=[]):
logging.error("error parsing %s" % (os.path.join(dirpath, hint_fn)))
return True
warnings = clean_hints(p, pvr_hint, warnings)
- files.remove(hint_fn)
else:
# it's an error to not have a pvr.hint
logging.error("package %s has packages for version %s, but no %s" % (p, vr, hint_fn))
@@ -320,6 +392,10 @@ def read_package(packages, basedir, dirpath, files, remove=[]):
else:
ovr = vr
+ # external source will always point to a source package
+ if 'external-source' in pvr_hint:
+ pvr_hint['external-source'] += '-src'
+
hintobj = Hint()
hintobj.path = relpath
hintobj.fn = hint_fn
@@ -329,34 +405,18 @@ def read_package(packages, basedir, dirpath, files, remove=[]):
hints[ovr] = hintobj
actual_tars[ovr] = tars[vr]
- # ignore dotfiles and backup files
- for f in files[:]:
- if f.startswith('.') or f.endswith('.bak'):
- files.remove(f)
-
- # warn about unexpected files, including tarfiles which don't match the
- # package name
- if files:
- logging.error("unexpected files in %s: %s" % (p, ', '.join(files)))
- warnings = True
-
- packages[p].version_hints = version_hints
- packages[p].override_hints = override_hints
- packages[p].tars = actual_tars
- packages[p].hints = hints
- packages[p].pkgpath = pkgpath
- packages[p].skip = any(['skip' in version_hints[vr] for vr in version_hints])
-
- elif (relpath.count(os.path.sep) > 1):
- for s in ['md5.sum', 'sha512.sum']:
- if s in files:
- files.remove(s)
-
- if len(files) > 0:
- logging.error("no .hint files in %s but has files: %s" % (dirpath, ', '.join(files)))
- warnings = True
+ packages[pn].version_hints = version_hints
+ packages[pn].override_hints = override_hints
+ packages[pn].tars = actual_tars
+ packages[pn].hints = hints
+ packages[pn].pkgpath = pkgpath
+ packages[pn].skip = any(['skip' in version_hints[vr] for vr in version_hints])
+ packages[pn].kind = kind
+ # since we are kind of inventing the source package names, and don't
+ # want to report them, keep track of the real name
+ packages[pn].orig_name = p
- return warnings
+ return warnings
#
@@ -487,6 +547,7 @@ def validate_packages(args, packages):
packages[p].vermap = {}
is_empty = {}
+ has_source = False
has_install = False
has_nonempty_install = False
@@ -495,6 +556,7 @@ def validate_packages(args, packages):
# categorize each tarfile as either 'source' or 'install'
if re.search(r'-src.*\.tar', t):
category = 'source'
+ has_source = True
else:
category = 'install'
has_install = True
@@ -516,6 +578,16 @@ def validate_packages(args, packages):
packages[p].vermap[vr][category] = t
packages[p].vermap[vr]['mtime'] = tar.mtime
+ # check that package only contains tar archives of the appropriate type
+ if packages[p].kind == Kind.source:
+ if has_install:
+ logging.error("source package '%s' has install archives" % (p))
+ error = True
+ elif packages[p].kind == Kind.binary:
+ if has_source:
+ logging.error("package '%s' has source archives" % (p))
+ error = True
+
obsolete = any(['_obsolete' in packages[p].version_hints[vr].get('category', '') for vr in packages[p].version_hints])
# if the package has no install tarfiles (i.e. is source only), make
@@ -695,15 +767,21 @@ def validate_packages(args, packages):
('empty-obsolete' in packages[p].version_hints[vr].get('disable-check', ''))):
lvl = logging.DEBUG
else:
- lvl = logging.ERROR
- error = True
- logging.log(lvl, "package '%s' version '%s' has empty install tar file and no source, but it's not in the _obsolete category" % (p, vr))
-
- for vr in packages[p].version_hints:
- if 'build-depends' in packages[p].version_hints[vr]:
- if 'source' not in packages[p].vermap[vr]:
- logging.error("package '%s' version '%s' has build-depends but no source" % (p, vr))
- error = True
+ if 'external-source' in packages[p].version_hints[vr]:
+ lvl = logging.ERROR
+ error = True
+ else:
+ lvl = logging.WARNING
+ logging.log(lvl, "package '%s' version '%s' has empty install tar file, but it's not in the _obsolete category" % (p, vr))
+
+ # the presence of build-depends only makes sense if this is a source
+ # package, or it has a sibling source package, with which is shares hints
+ if packages[p].kind != Kind.source:
+ for vr in packages[p].version_hints:
+ if 'build-depends' in packages[p].version_hints[vr]:
+ if 'external-source' in packages[p].version_hints[vr]:
+ logging.error("package '%s' version '%s' has build-depends but isn't a source package" % (p, vr))
+ error = True
# make another pass to verify a source tarfile exists for every install
# tarfile version
@@ -712,43 +790,39 @@ def validate_packages(args, packages):
if 'install' not in packages[p].vermap[v]:
continue
- # unless the install tarfile is empty
- if packages[p].tar(v, 'install').is_empty:
- continue
-
- # source tarfile may be either in this package or in the
- # external-source package
- #
- # mark the source tarfile as being used by an install tarfile
- if 'source' in packages[p].vermap[v]:
- packages[p].tar(v, 'source').is_used = True
- packages[p].is_used_by.add(p)
- continue
+ sourceless = False
+ missing_source = True
+ # source tarfile is in the external-source package, if specified,
+ # otherwise it's in the sibling source package
if 'external-source' in packages[p].version_hints[v]:
es_p = packages[p].version_hints[v]['external-source']
- if es_p in packages:
- if v in packages[es_p].vermap and 'source' in packages[es_p].vermap[v]:
- packages[es_p].tar(v, 'source').is_used = True
- packages[es_p].is_used_by.add(p)
- continue
-
- # this is a bodge to follow external-source: which hasn't been
- # updated following a source package de-duplication
- es_p = es_p + '-src'
- if es_p in packages:
- if 'source' in packages[es_p].vermap[v]:
- logging.warning("package '%s' version '%s' external-source: should be %s" % (p, v, es_p))
- packages[es_p].tar(v, 'source').is_used = True
- packages[es_p].is_used_by.add(p)
- continue
-
- # unless this package is marked as 'self-source'
- if p in past_mistakes.self_source:
- continue
+ else:
+ es_p = p + '-src'
- logging.error("package '%s' version '%s' is missing source" % (p, v))
- error = True
+ # mark the source tarfile as being used by an install tarfile
+ if es_p in packages:
+ if v in packages[es_p].vermap and 'source' in packages[es_p].vermap[v]:
+ packages[es_p].tar(v, 'source').is_used = True
+ packages[es_p].is_used_by.add(p)
+ missing_source = False
+
+ if missing_source:
+ # unless the install tarfile is empty
+ if packages[p].tar(v, 'install').is_empty:
+ sourceless = True
+ missing_source = False
+
+ # unless this package is marked as 'self-source'
+ if p in past_mistakes.self_source:
+ sourceless = True
+ missing_source = False
+
+ # ... it's an error for this package to be missing source
+ packages[p].tar(v, 'install').sourceless = sourceless
+ if missing_source:
+ logging.error("package '%s' version '%s' is missing source" % (p, v))
+ error = True
# make another pass to verify that each non-empty source tarfile version has
# at least one corresponding non-empty install tarfile, in some package.
@@ -808,7 +882,7 @@ def validate_packages(args, packages):
most_common = False
error = True
- logging.error("install packages from source package '%s' have non-unique current versions %s" % (source_p, ', '.join(reversed(out))))
+ logging.error("install packages from source package '%s' have non-unique current versions %s" % (packages[source_p].orig_name, ', '.join(reversed(out))))
# validate that all packages are in the package maintainers list
error = validate_package_maintainers(args, packages) or error
@@ -838,13 +912,19 @@ def validate_package_maintainers(args, packages):
if not is_in_package_list(packages[p].pkgpath, all_packages):
logging.error("package '%s' on path '%s', which doesn't start with a package in the package list" % (p, packages[p].pkgpath))
error = True
+ # source which is superseded by a different package, but retained due to
+ # old install versions can be unmaintained and non-obsolete
+ if packages[p].kind == Kind.source:
+ continue
# validate that the source package has a maintainer
bv = packages[p].best_version
- es = packages[p].version_hints[bv].get('external-source', p)
- if es not in all_packages and p not in all_packages:
- if bv not in past_mistakes.maint_anomalies.get(p, []):
- logging.error("package '%s' is not obsolete, but has no maintainer" % (p))
- error = True
+ if bv:
+ es = packages[p].version_hints[bv].get('external-source', p)
+ es_pn = packages[es].orig_name
+ if es_pn not in all_packages and p not in all_packages:
+ if bv not in past_mistakes.maint_anomalies.get(p, []):
+ logging.error("package '%s' is not obsolete, but has no maintainer" % (p))
+ error = True
return error
@@ -889,7 +969,7 @@ def write_setup_ini(args, packages, arch):
# for each package
for p in sorted(packages.keys(), key=sort_key):
# do nothing if 'skip'
- if packages[p].skip and not p.endswith('-src'):
+ if packages[p].skip:
continue
# write package data
@@ -977,26 +1057,33 @@ def write_setup_ini(args, packages, arch):
print("[%s]" % tag, file=f)
print("version: %s" % version, file=f)
+ is_empty = False
if 'install' in packages[p].vermap.get(version, {}):
tar_line(packages[p], 'install', version, f)
+ is_empty = packages[p].tar(version, 'install').is_empty
hints = packages[p].version_hints[version]
- # look for corresponding source in this package first
- if 'source' in packages[p].vermap[version]:
- tar_line(packages[p], 'source', version, f)
- # if that doesn't exist, follow external-source
- elif 'external-source' in hints:
+ # follow external-source
+ if 'external-source' in hints:
s = hints['external-source']
- # external-source points to a real source package (-src)
- if s.endswith('-src'):
- print("Source: %s" % (s), file=f)
- # external-source points to a source file in another package
+ else:
+ s = p + '-src'
+ if s not in packages:
+ s = None
+
+ # external-source points to a source file in another package
+ if s:
+ if 'source' in packages[s].vermap.get(version, {}):
+ tar_line(packages[s], 'source', version, f)
else:
- if 'source' in packages[s].vermap.get(version, {}):
- tar_line(packages[s], 'source', version, f)
- else:
- logging.warning("package '%s' version '%s' has no source in external-source '%s'" % (p, version, s))
+ if not (is_empty or packages[s].orig_name in past_mistakes.self_source):
+ logging.warning("package '%s' version '%s' has no source in '%s'" % (p, version, packages[s].orig_name))
+
+ # external-source should also be capable of pointing to a 'real'
+ # source package (if cygport could generate such a thing), in
+ # which case we should emit a 'Source:' line, and the package is
+ # also itself emitted.
if hints.get('depends', '') or requires:
print("depends2: %s" % hints.get('depends', ''), file=f)
@@ -1066,7 +1153,7 @@ def write_repo_json(args, packages, f):
bv = po.best_version
- if po.version_hints[bv].get('external-source', None):
+ if po.kind != Kind.source:
continue
versions = {}
@@ -1284,8 +1371,26 @@ 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
- if all_stale.get(v, True):
+ # 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):
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/past_mistakes.py b/calm/past_mistakes.py
index 31bcb0d..0eceb76 100644
--- a/calm/past_mistakes.py
+++ b/calm/past_mistakes.py
@@ -155,6 +155,7 @@ empty_but_not_obsolete = [
mtime_anomalies = [
'gcc-java',
'gcc-tools-epoch2-autoconf',
+ 'gcc-tools-epoch2-autoconf-src',
'gv-debuginfo',
'libgcj-common',
'libgcj16',
@@ -167,10 +168,13 @@ mtime_anomalies = [
'subversion-perl',
'subversion-python',
'subversion-ruby',
+ 'subversion-src',
'subversion-tools',
]
# packages with maintainer anomalies
+#
+# don't add to this list, fix the package (e.g. by obsoleting it)
maint_anomalies = {
'libelf0': ['0.8.13-2'], # libelf is called libelf0 in x86 arch
'libelf0-devel': ['0.8.13-2'],
diff --git a/calm/pkg2html.py b/calm/pkg2html.py
index 35043dd..9216139 100755
--- a/calm/pkg2html.py
+++ b/calm/pkg2html.py
@@ -129,7 +129,8 @@ def update_package_listings(args, packages):
def linkify_package(p):
if p in package_list:
- return '<a href="%s.html">%s</a>' % (p, p)
+ pn = arch_package(packages, p).orig_name
+ return '<a href="%s.html">%s</a>' % (p, pn)
logging.debug('package linkification failed for %s' % p)
return p
@@ -159,7 +160,15 @@ def update_package_listings(args, packages):
continue
bv = po.best_version
- title = "Cygwin Package Summary for %s" % p
+
+ if po.kind == package.Kind.source:
+ pn = po.orig_name
+ title = "Cygwin Package Summary for %s (source)" % pn
+ kind = "Source Package"
+ else:
+ pn = p
+ title = "Cygwin Package Summary for %s" % p
+ kind = "Package"
print(textwrap.dedent('''\
<!DOCTYPE html>
@@ -173,31 +182,41 @@ def update_package_listings(args, packages):
<!--#include virtual="/navbar.html" -->
<div id="main">
<!--#include virtual="/top.html" -->
- <h1>Package: %s</h1>''' % (title, p)), file=f)
+ <h1>%s: %s</h1>''' % (title, kind, pn)), file=f)
print('<span class="detail">summary</span>: %s<br><br>' % sdesc(po, bv), file=f)
print('<span class="detail">description</span>: %s<br><br>' % ldesc(po, bv), file=f)
print('<span class="detail">categories</span>: %s<br><br>' % po.version_hints[bv].get('category', ''), file=f)
- for key in ['depends', 'obsoletes', 'provides', 'conflicts', 'build-depends']:
+ if po.kind == package.Kind.source:
+ details = ['build-depends']
+ else:
+ details = ['depends', 'obsoletes', 'provides', 'conflicts']
+
+ for key in details:
value = po.version_hints[bv].get(key, None)
if value:
print('<span class="detail">%s</span>: %s<br><br>' % (key, ', '.join([linkify_package(p) for p in value.split(', ')])), file=f)
- es = po.version_hints[bv].get('external-source', None)
- if es:
- print('<span class="detail">source</span>: %s<br><br>' % linkify_package(es), file=f)
- else:
- print('<span class="detail">binaries</span>: %s<br><br>' % ', '.join([linkify_package(p) for p in sorted(po.is_used_by)]), file=f)
+ if po.kind == package.Kind.source:
es = p
-
- if 'ORPHANED' in pkg_maintainers[es]:
+ 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)
+ 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)
+
+ es_po = arch_package(packages, es)
+ if not es_po:
+ es_po = po
+ m_pn = es_po.orig_name
+ if 'ORPHANED' in pkg_maintainers[m_pn]:
m = 'ORPHANED'
else:
- m = ', '.join(sorted(pkg_maintainers[es]))
+ m = ', '.join(sorted(pkg_maintainers[m_pn]))
if m:
print('<span class="detail">maintainer(s)</span>: %s ' % m, file=f)
+
print(textwrap.dedent('''\
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>'''), file=f)
@@ -218,7 +237,7 @@ def update_package_listings(args, packages):
t = p.vermap[v][category]
size = int(math.ceil(p.tar(v, category).size / 1024))
name = v if category == 'install' else v + ' (source)'
- target = "%s-%s" % (pn, v) + ('' if category == 'install' else '-src')
+ target = "%s-%s" % (p.orig_name, v) + ('' if category == 'install' else '-src')
test = 'test' if 'test' in p.version_hints[v] else 'stable'
print('<tr><td>%s</td><td class="right">%d kB</td><td>[<a href="../%s/%s/%s">list of files</a>]</td><td>%s</td></tr>' % (name, size, arch, pn, target, test), file=f)
@@ -261,9 +280,27 @@ def update_package_listings(args, packages):
print('<table class="pkglist">', file=index)
+ # This list contains all packages in any arch, but in the interests
+ # of keeping the size down, we only list (i) all install packages,
+ # and (ii) source package where there isn't an install package of
+ # the same name. Source packages sort by their original package
+ # name.
+ package_list = {}
+ for arch in packages:
+ for p in packages[arch]:
+ if packages[arch][p].kind == package.Kind.binary:
+ package_list[p] = p
+
+ for arch in packages:
+ for p in packages[arch]:
+ if packages[arch][p].kind == package.Kind.source and packages[arch][p].orig_name not in package_list:
+ package_list[packages[arch][p].orig_name] = p
+
first = ' class="pkgname"'
jump = ''
- for p in sorted(package_list, key=package.sort_key):
+ for k in sorted(package_list, key=package.sort_key):
+ p = package_list[k]
+
if p.endswith('-debuginfo'):
continue
@@ -274,6 +311,13 @@ def update_package_listings(args, packages):
bv = po.best_version
header = sdesc(po, bv)
+ if po.kind == package.Kind.source:
+ pn = po.orig_name
+ if 'source' not in header:
+ header += ' (source)'
+ else:
+ pn = p
+
anchor = ''
if jump != p[0].lower():
jump = p[0].lower()
@@ -281,7 +325,7 @@ def update_package_listings(args, packages):
anchor = ' id="%s"' % (jump)
print('<tr%s><td%s><a href="summary/%s.html">%s</a></td><td>%s</td></tr>' %
- (anchor, first, p, p, header),
+ (anchor, first, p, pn, header),
file=index)
first = ''
@@ -371,7 +415,7 @@ def write_arch_listing(args, packages, arch):
header = p + ": " + sdesc(packages[p], bv)
if fver.endswith('-src'):
- header = header + " (source code)"
+ header = header + " (source)"
print(textwrap.dedent('''\
<!DOCTYPE html>
diff --git a/calm/uploads.py b/calm/uploads.py
index 587aa9b..9914a16 100644
--- a/calm/uploads.py
+++ b/calm/uploads.py
@@ -257,7 +257,7 @@ def scan(m, all_packages, arch, args):
# read and validate package
if files:
- if package.read_package(packages, m.homedir(), dirpath, files, remove=removed_files):
+ if package.read_package_dir(packages, m.homedir(), dirpath, files, remove=removed_files, upload=True):
error = True
# always consider timestamp as checked during a dry-run, so it is never
diff --git a/test/test_calm.py b/test/test_calm.py
index 8f909e3..ef4f79f 100755
--- a/test/test_calm.py
+++ b/test/test_calm.py
@@ -39,6 +39,7 @@ import unittest
from calm.version import SetupVersion
import calm.calm
+import calm.common_constants as common_constants
import calm.hint as hint
import calm.maintainers as maintainers
import calm.package as package
@@ -165,6 +166,8 @@ class CalmTest(unittest.TestCase):
setattr(args, 'pkglist', 'testdata/pkglist/cygwin-pkg-maint')
packages = {}
+ for arch in common_constants.ARCHES:
+ packages[arch] = {}
packages[args.arch] = package.read_packages(args.rel_area, args.arch)
package.validate_packages(args, packages[args.arch])
pkg2html.update_package_listings(args, packages)
diff --git a/test/testdata/htdocs.expected/dirtree.expected b/test/testdata/htdocs.expected/dirtree.expected
index b3bd5d4..bdeef8e 100644
--- a/test/testdata/htdocs.expected/dirtree.expected
+++ b/test/testdata/htdocs.expected/dirtree.expected
@@ -1,79 +1,102 @@
{'.': ['packages.inc'],
- 'summary': ['arc.html',
+ 'summary': ['arc-src.html',
+ 'arc.html',
'base-cygwin.html',
+ 'corrupt-src.html',
'corrupt.html',
'cygwin-debuginfo.html',
'cygwin-devel.html',
+ 'cygwin-src.html',
'cygwin.html',
+ 'keychain-src.html',
'keychain.html',
'libdns_sd-devel.html',
'libdns_sd1.html',
+ 'mDNSResponder-src.html',
'mDNSResponder.html',
+ 'obs-a-src.html',
'obs-a.html',
+ 'obs-b-src.html',
'obs-b.html',
+ 'openssh-src.html',
'openssh.html',
+ 'per-version-replacement-hint-only-src.html',
'per-version-replacement-hint-only.html',
+ 'per-version-src.html',
'per-version.html',
+ 'perl-Net-SMTP-SSL-src.html',
'perl-Net-SMTP-SSL.html',
+ 'rpm-doc-src.html',
'rpm-doc.html',
+ 'staleversion-src.html',
'staleversion.html',
+ 'test-c-src.html',
'test-c.html',
+ 'test-d-src.html',
'test-d.html',
+ 'test-e-src.html',
'test-e.html',
+ 'testpackage-src.html',
'testpackage.html'],
'x86': ['.htaccess'],
- 'x86/arc': ['.htaccess', 'arc-4.32.7-10', 'arc-4.32.7-10-src'],
+ 'x86/arc': ['.htaccess', 'arc-4.32.7-10'],
+ 'x86/arc-src': ['.htaccess', 'arc-4.32.7-10-src'],
'x86/base-cygwin': ['.htaccess', 'base-cygwin-3.6-1', 'base-cygwin-3.8-1'],
- 'x86/corrupt': ['.htaccess', 'corrupt-2.0.0-1', 'corrupt-2.0.0-1-src'],
- 'x86/cygwin': ['.htaccess',
- 'cygwin-2.2.0-1',
- 'cygwin-2.2.0-1-src',
- 'cygwin-2.2.1-1',
- 'cygwin-2.2.1-1-src',
- 'cygwin-2.3.0-0.3',
- 'cygwin-2.3.0-0.3-src'],
+ 'x86/corrupt': ['.htaccess', 'corrupt-2.0.0-1'],
+ 'x86/corrupt-src': ['.htaccess', 'corrupt-2.0.0-1-src'],
+ 'x86/cygwin': ['.htaccess', 'cygwin-2.2.0-1', 'cygwin-2.2.1-1', 'cygwin-2.3.0-0.3'],
'x86/cygwin-debuginfo': ['.htaccess',
'cygwin-debuginfo-2.2.0-1',
'cygwin-debuginfo-2.2.1-1',
'cygwin-debuginfo-2.3.0-0.3'],
'x86/cygwin-devel': ['.htaccess', 'cygwin-devel-2.2.0-1', 'cygwin-devel-2.2.1-1', 'cygwin-devel-2.3.0-0.3'],
- 'x86/keychain': ['.htaccess', 'keychain-2.6.8-1', 'keychain-2.6.8-1-src', 'keychain-2.7.1-1', 'keychain-2.7.1-1-src'],
+ 'x86/cygwin-src': ['.htaccess', 'cygwin-2.2.0-1-src', 'cygwin-2.2.1-1-src', 'cygwin-2.3.0-0.3-src'],
+ 'x86/keychain': ['.htaccess', 'keychain-2.6.8-1', 'keychain-2.7.1-1'],
+ 'x86/keychain-src': ['.htaccess', 'keychain-2.6.8-1-src', 'keychain-2.7.1-1-src'],
'x86/libdns_sd-devel': ['.htaccess', 'libdns_sd-devel-379.32.1-1'],
'x86/libdns_sd1': ['.htaccess', 'libdns_sd1-379.32.1-1'],
- 'x86/mDNSResponder': ['.htaccess', 'mDNSResponder-379.32.1-1', 'mDNSResponder-379.32.1-1-src'],
- 'x86/obs-a': ['.htaccess', 'obs-a-1.0-1', 'obs-a-1.0-1-src'],
- 'x86/obs-b': ['.htaccess', 'obs-b-1.0-1', 'obs-b-1.0-1-src'],
- 'x86/openssh': ['.htaccess', 'openssh-7.2p2-1', 'openssh-7.2p2-1-src'],
- 'x86/per-version': ['.htaccess',
- 'per-version-4.0-1',
- 'per-version-4.0-1-src',
- 'per-version-4.8-1',
- 'per-version-4.8-1-src'],
- 'x86/per-version-replacement-hint-only': ['.htaccess',
- 'per-version-replacement-hint-only-1.0-1',
- 'per-version-replacement-hint-only-1.0-1-src'],
+ 'x86/mDNSResponder': ['.htaccess', 'mDNSResponder-379.32.1-1'],
+ 'x86/mDNSResponder-src': ['.htaccess', 'mDNSResponder-379.32.1-1-src'],
+ 'x86/obs-a': ['.htaccess', 'obs-a-1.0-1'],
+ 'x86/obs-a-src': ['.htaccess', 'obs-a-1.0-1-src'],
+ 'x86/obs-b': ['.htaccess', 'obs-b-1.0-1'],
+ 'x86/obs-b-src': ['.htaccess', 'obs-b-1.0-1-src'],
+ 'x86/openssh': ['.htaccess', 'openssh-7.2p2-1'],
+ 'x86/openssh-src': ['.htaccess', 'openssh-7.2p2-1-src'],
+ 'x86/per-version': ['.htaccess', 'per-version-4.0-1', 'per-version-4.8-1'],
+ 'x86/per-version-replacement-hint-only': ['.htaccess', 'per-version-replacement-hint-only-1.0-1'],
+ 'x86/per-version-replacement-hint-only-src': ['.htaccess', 'per-version-replacement-hint-only-1.0-1-src'],
+ 'x86/per-version-src': ['.htaccess', 'per-version-4.0-1-src', 'per-version-4.8-1-src'],
'x86/perl-Net-SMTP-SSL': ['.htaccess',
'perl-Net-SMTP-SSL-1.01-1',
- 'perl-Net-SMTP-SSL-1.01-1-src',
'perl-Net-SMTP-SSL-1.02-1',
- 'perl-Net-SMTP-SSL-1.02-1-src',
- 'perl-Net-SMTP-SSL-1.03-1',
- 'perl-Net-SMTP-SSL-1.03-1-src'],
- 'x86/rpm-doc': ['.htaccess', 'rpm-doc-4.1-2', 'rpm-doc-4.1-2-src', 'rpm-doc-999-1'],
+ 'perl-Net-SMTP-SSL-1.03-1'],
+ 'x86/perl-Net-SMTP-SSL-src': ['.htaccess',
+ 'perl-Net-SMTP-SSL-1.01-1-src',
+ 'perl-Net-SMTP-SSL-1.02-1-src',
+ 'perl-Net-SMTP-SSL-1.03-1-src'],
+ 'x86/rpm-doc': ['.htaccess', 'rpm-doc-4.1-2', 'rpm-doc-999-1'],
+ 'x86/rpm-doc-src': ['.htaccess', 'rpm-doc-4.1-2-src'],
'x86/staleversion': ['.htaccess',
'staleversion-240-1',
- 'staleversion-240-1-src',
'staleversion-242-0',
- 'staleversion-242-0-src',
'staleversion-243-0',
- 'staleversion-243-0-src',
'staleversion-250-0',
- 'staleversion-250-0-src',
'staleversion-251-0',
- 'staleversion-251-0-src',
- 'staleversion-260-0',
- 'staleversion-260-0-src'],
- 'x86/test-c': ['.htaccess', 'test-c-1.0-1', 'test-c-1.0-1-src'],
- 'x86/test-d': ['.htaccess', 'test-d-1.0-1', 'test-d-1.0-1-src'],
- 'x86/test-e': ['.htaccess', 'test-e-1.0-1', 'test-e-1.0-1-src'],
- 'x86/testpackage': ['.htaccess', 'testpackage-0.1-1', 'testpackage-0.1-1-src']}
+ 'staleversion-260-0'],
+ 'x86/staleversion-src': ['.htaccess',
+ 'staleversion-240-1-src',
+ 'staleversion-242-0-src',
+ 'staleversion-243-0-src',
+ 'staleversion-250-0-src',
+ 'staleversion-251-0-src',
+ 'staleversion-260-0-src'],
+ 'x86/test-c': ['.htaccess', 'test-c-1.0-1'],
+ 'x86/test-c-src': ['.htaccess', 'test-c-1.0-1-src'],
+ 'x86/test-d': ['.htaccess', 'test-d-1.0-1'],
+ 'x86/test-d-src': ['.htaccess', 'test-d-1.0-1-src'],
+ 'x86/test-e': ['.htaccess', 'test-e-1.0-1'],
+ 'x86/test-e-src': ['.htaccess', 'test-e-1.0-1-src'],
+ 'x86/testpackage': ['.htaccess', 'testpackage-0.1-1'],
+ 'x86/testpackage-src': ['.htaccess', 'testpackage-0.1-1-src'],
+ 'x86_64': ['.htaccess']}
diff --git a/test/testdata/htdocs.expected/packages.inc b/test/testdata/htdocs.expected/packages.inc
index 25a317f..25a317f 100755..100644
--- a/test/testdata/htdocs.expected/packages.inc
+++ b/test/testdata/htdocs.expected/packages.inc
diff --git a/test/testdata/htdocs.expected/summary/arc-src.html b/test/testdata/htdocs.expected/summary/arc-src.html
new file mode 100755
index 0000000..3623e01
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/arc-src.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for arc (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: arc</h1>
+<span class="detail">summary</span>: The ARC archive utility<br><br>
+<span class="detail">description</span>: 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.<br><br>
+<span class="detail">categories</span>: Archive<br><br>
+<span class="detail">install package(s)</span>: <a href="arc.html">arc</a><br><br>
+<span class="detail">maintainer(s)</span>: Jari Aalto
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>4.32.7-10 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/arc-src/arc-4.32.7-10-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/arc.html b/test/testdata/htdocs.expected/summary/arc.html
index 009b8f5..0cfcb9e 100644
--- a/test/testdata/htdocs.expected/summary/arc.html
+++ b/test/testdata/htdocs.expected/summary/arc.html
@@ -18,7 +18,7 @@ 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.<br><br>
<span class="detail">categories</span>: Archive<br><br>
-<span class="detail">binaries</span>: <a href="arc.html">arc</a><br><br>
+<span class="detail">source package</span>: <a href="arc-src.html">arc</a><br><br>
<span class="detail">maintainer(s)</span>: Jari Aalto
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -28,7 +28,6 @@ the best of packing, squeezing, or crunching is used.<br><br>
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>4.32.7-10</td><td class="right">1 kB</td><td>[<a href="../x86/arc/arc-4.32.7-10">list of files</a>]</td><td>stable</td></tr>
-<tr><td>4.32.7-10 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/arc/arc-4.32.7-10-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/base-cygwin.html b/test/testdata/htdocs.expected/summary/base-cygwin.html
index 0ce7e9e..9dbd8fa 100644
--- a/test/testdata/htdocs.expected/summary/base-cygwin.html
+++ b/test/testdata/htdocs.expected/summary/base-cygwin.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: Initial base installation helper script<br><br>
<span class="detail">description</span>: Initial base installation helper script.<br><br>
<span class="detail">categories</span>: Base<br><br>
-<span class="detail">binaries</span>: <br><br>
+<span class="detail">source package</span>: base-cygwin-src<br><br>
<span class="detail">maintainer(s)</span>: Corinna Vinschen
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
diff --git a/test/testdata/htdocs.expected/summary/corrupt-src.html b/test/testdata/htdocs.expected/summary/corrupt-src.html
new file mode 100755
index 0000000..167c266
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/corrupt-src.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for corrupt (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: corrupt</h1>
+<span class="detail">summary</span>: A corrupt package<br><br>
+<span class="detail">description</span>: A package containing corrupt archives<br><br>
+<span class="detail">categories</span>: Devel<br><br>
+<span class="detail">install package(s)</span>: <a href="corrupt.html">corrupt</a><br><br>
+<span class="detail">maintainer(s)</span>: Blooey McFooey
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>2.0.0-1 (source)</td><td class="right">354 kB</td><td>[<a href="../x86/corrupt-src/corrupt-2.0.0-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/corrupt.html b/test/testdata/htdocs.expected/summary/corrupt.html
index d7016dc..f12513c 100644
--- a/test/testdata/htdocs.expected/summary/corrupt.html
+++ b/test/testdata/htdocs.expected/summary/corrupt.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: A corrupt package<br><br>
<span class="detail">description</span>: A package containing corrupt archives<br><br>
<span class="detail">categories</span>: Devel<br><br>
-<span class="detail">binaries</span>: <a href="corrupt.html">corrupt</a><br><br>
+<span class="detail">source package</span>: <a href="corrupt-src.html">corrupt</a><br><br>
<span class="detail">maintainer(s)</span>: Blooey McFooey
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -23,7 +23,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>2.0.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/corrupt/corrupt-2.0.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>2.0.0-1 (source)</td><td class="right">354 kB</td><td>[<a href="../x86/corrupt/corrupt-2.0.0-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/cygwin-debuginfo.html b/test/testdata/htdocs.expected/summary/cygwin-debuginfo.html
index 0d613d6..2cab7d3 100644
--- a/test/testdata/htdocs.expected/summary/cygwin-debuginfo.html
+++ b/test/testdata/htdocs.expected/summary/cygwin-debuginfo.html
@@ -15,7 +15,7 @@
cygwin package with gdb.<br><br>
<span class="detail">categories</span>: Debug<br><br>
<span class="detail">depends</span>: <a href="cygwin-debuginfo.html">cygwin-debuginfo</a><br><br>
-<span class="detail">source</span>: <a href="cygwin.html">cygwin</a><br><br>
+<span class="detail">source package</span>: <a href="cygwin-src.html">cygwin</a><br><br>
<span class="detail">maintainer(s)</span>: Corinna Vinschen, Yaakov Selkowitz
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
diff --git a/test/testdata/htdocs.expected/summary/cygwin-devel.html b/test/testdata/htdocs.expected/summary/cygwin-devel.html
index 2435a15..f9f3c8a 100644
--- a/test/testdata/htdocs.expected/summary/cygwin-devel.html
+++ b/test/testdata/htdocs.expected/summary/cygwin-devel.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: Core development files<br><br>
<span class="detail">description</span>: Core development files required to build Cygwin packages<br><br>
<span class="detail">categories</span>: Devel<br><br>
-<span class="detail">source</span>: <a href="cygwin.html">cygwin</a><br><br>
+<span class="detail">source package</span>: <a href="cygwin-src.html">cygwin</a><br><br>
<span class="detail">maintainer(s)</span>: Corinna Vinschen, Yaakov Selkowitz
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
diff --git a/test/testdata/htdocs.expected/summary/cygwin-src.html b/test/testdata/htdocs.expected/summary/cygwin-src.html
new file mode 100755
index 0000000..23bf0be
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/cygwin-src.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for cygwin (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: cygwin</h1>
+<span class="detail">summary</span>: The UNIX emulation engine<br><br>
+<span class="detail">description</span>: The UNIX emulation engine<br><br>
+<span class="detail">categories</span>: Base<br><br>
+<span class="detail">install package(s)</span>: <a href="cygwin.html">cygwin</a>, <a href="cygwin-debuginfo.html">cygwin-debuginfo</a>, <a href="cygwin-devel.html">cygwin-devel</a><br><br>
+<span class="detail">maintainer(s)</span>: Corinna Vinschen, Yaakov Selkowitz
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>2.2.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin-src/cygwin-2.2.0-1-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>2.2.1-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin-src/cygwin-2.2.1-1-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>2.3.0-0.3 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin-src/cygwin-2.3.0-0.3-src">list of files</a>]</td><td>test</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/cygwin.html b/test/testdata/htdocs.expected/summary/cygwin.html
index c7c16de..14bd73a 100644
--- a/test/testdata/htdocs.expected/summary/cygwin.html
+++ b/test/testdata/htdocs.expected/summary/cygwin.html
@@ -14,7 +14,7 @@
<span class="detail">description</span>: The UNIX emulation engine<br><br>
<span class="detail">categories</span>: Base<br><br>
<span class="detail">depends</span>: <a href="base-cygwin.html">base-cygwin</a><br><br>
-<span class="detail">binaries</span>: <a href="cygwin.html">cygwin</a>, <a href="cygwin-debuginfo.html">cygwin-debuginfo</a>, <a href="cygwin-devel.html">cygwin-devel</a><br><br>
+<span class="detail">source package</span>: <a href="cygwin-src.html">cygwin</a><br><br>
<span class="detail">maintainer(s)</span>: Corinna Vinschen, Yaakov Selkowitz
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -24,11 +24,8 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>2.2.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin/cygwin-2.2.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>2.2.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin/cygwin-2.2.0-1-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>2.2.1-1</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin/cygwin-2.2.1-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>2.2.1-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin/cygwin-2.2.1-1-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>2.3.0-0.3</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin/cygwin-2.3.0-0.3">list of files</a>]</td><td>test</td></tr>
-<tr><td>2.3.0-0.3 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/cygwin/cygwin-2.3.0-0.3-src">list of files</a>]</td><td>test</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/keychain-src.html b/test/testdata/htdocs.expected/summary/keychain-src.html
new file mode 100755
index 0000000..52e97d4
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/keychain-src.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for keychain (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: keychain</h1>
+<span class="detail">summary</span>: Key manager for OpenSSH<br><br>
+<span class="detail">description</span>: 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<br><br>
+<span class="detail">categories</span>: Utils<br><br>
+<span class="detail">install package(s)</span>: <a href="keychain.html">keychain</a><br><br>
+<span class="detail">maintainer(s)</span>: Jari Aalto
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>2.6.8-1 (source)</td><td class="right">36 kB</td><td>[<a href="../x86/keychain-src/keychain-2.6.8-1-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>2.7.1-1 (source)</td><td class="right">132 kB</td><td>[<a href="../x86/keychain-src/keychain-2.7.1-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/keychain.html b/test/testdata/htdocs.expected/summary/keychain.html
index 96f30f7..8daabe0 100644
--- a/test/testdata/htdocs.expected/summary/keychain.html
+++ b/test/testdata/htdocs.expected/summary/keychain.html
@@ -22,7 +22,7 @@ ssh-agent, otherwise it loads them, prompting you for a password if
necessary<br><br>
<span class="detail">categories</span>: Utils<br><br>
<span class="detail">depends</span>: <a href="openssh.html">openssh</a><br><br>
-<span class="detail">binaries</span>: <a href="keychain.html">keychain</a><br><br>
+<span class="detail">source package</span>: <a href="keychain-src.html">keychain</a><br><br>
<span class="detail">maintainer(s)</span>: Jari Aalto
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -32,9 +32,7 @@ necessary<br><br>
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>2.6.8-1</td><td class="right">30 kB</td><td>[<a href="../x86/keychain/keychain-2.6.8-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>2.6.8-1 (source)</td><td class="right">36 kB</td><td>[<a href="../x86/keychain/keychain-2.6.8-1-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>2.7.1-1</td><td class="right">32 kB</td><td>[<a href="../x86/keychain/keychain-2.7.1-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>2.7.1-1 (source)</td><td class="right">132 kB</td><td>[<a href="../x86/keychain/keychain-2.7.1-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/libdns_sd-devel.html b/test/testdata/htdocs.expected/summary/libdns_sd-devel.html
index e28d111..58b060e 100644
--- a/test/testdata/htdocs.expected/summary/libdns_sd-devel.html
+++ b/test/testdata/htdocs.expected/summary/libdns_sd-devel.html
@@ -16,7 +16,7 @@ automatic discovery of computers, devices, and services on IP networks using
industry standard IP protocols.<br><br>
<span class="detail">categories</span>: Net<br><br>
<span class="detail">depends</span>: <a href="libdns_sd1.html">libdns_sd1</a><br><br>
-<span class="detail">source</span>: <a href="mDNSResponder.html">mDNSResponder</a><br><br>
+<span class="detail">source package</span>: <a href="mDNSResponder-src.html">mDNSResponder</a><br><br>
<span class="detail">maintainer(s)</span>: Yaakov Selkowitz
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
diff --git a/test/testdata/htdocs.expected/summary/libdns_sd1.html b/test/testdata/htdocs.expected/summary/libdns_sd1.html
index 8fe51cd..10de4bf 100644
--- a/test/testdata/htdocs.expected/summary/libdns_sd1.html
+++ b/test/testdata/htdocs.expected/summary/libdns_sd1.html
@@ -15,7 +15,7 @@
automatic discovery of computers, devices, and services on IP networks using
industry standard IP protocols.<br><br>
<span class="detail">categories</span>: Net<br><br>
-<span class="detail">source</span>: <a href="mDNSResponder.html">mDNSResponder</a><br><br>
+<span class="detail">source package</span>: <a href="mDNSResponder-src.html">mDNSResponder</a><br><br>
<span class="detail">maintainer(s)</span>: Yaakov Selkowitz
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
diff --git a/test/testdata/htdocs.expected/summary/mDNSResponder-src.html b/test/testdata/htdocs.expected/summary/mDNSResponder-src.html
new file mode 100755
index 0000000..744f519
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/mDNSResponder-src.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for mDNSResponder (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: mDNSResponder</h1>
+<span class="detail">summary</span>: Bonjour Zeroconf implementation<br><br>
+<span class="detail">description</span>: Bonjour, also known as zero-configuration networking, enables
+automatic discovery of computers, devices, and services on IP networks using
+industry standard IP protocols.<br><br>
+<span class="detail">categories</span>: Net<br><br>
+<span class="detail">install package(s)</span>: <a href="libdns_sd-devel.html">libdns_sd-devel</a>, <a href="libdns_sd1.html">libdns_sd1</a>, <a href="mDNSResponder.html">mDNSResponder</a><br><br>
+<span class="detail">maintainer(s)</span>: Yaakov Selkowitz
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>379.32.1-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/mDNSResponder-src/mDNSResponder-379.32.1-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/mDNSResponder.html b/test/testdata/htdocs.expected/summary/mDNSResponder.html
index eac93f9..fee2fd7 100644
--- a/test/testdata/htdocs.expected/summary/mDNSResponder.html
+++ b/test/testdata/htdocs.expected/summary/mDNSResponder.html
@@ -16,7 +16,7 @@ automatic discovery of computers, devices, and services on IP networks using
industry standard IP protocols.<br><br>
<span class="detail">categories</span>: Net<br><br>
<span class="detail">depends</span>: <a href="libdns_sd1.html">libdns_sd1</a><br><br>
-<span class="detail">binaries</span>: <a href="libdns_sd-devel.html">libdns_sd-devel</a>, <a href="libdns_sd1.html">libdns_sd1</a>, <a href="mDNSResponder.html">mDNSResponder</a><br><br>
+<span class="detail">source package</span>: <a href="mDNSResponder-src.html">mDNSResponder</a><br><br>
<span class="detail">maintainer(s)</span>: Yaakov Selkowitz
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -26,7 +26,6 @@ industry standard IP protocols.<br><br>
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>379.32.1-1</td><td class="right">1 kB</td><td>[<a href="../x86/mDNSResponder/mDNSResponder-379.32.1-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>379.32.1-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/mDNSResponder/mDNSResponder-379.32.1-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/obs-a-src.html b/test/testdata/htdocs.expected/summary/obs-a-src.html
new file mode 100755
index 0000000..03847a9
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/obs-a-src.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for obs-a (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: obs-a</h1>
+<span class="detail">summary</span>: obsolete package A<br><br>
+<span class="detail">description</span>: obsolete package A<br><br>
+<span class="detail">categories</span>: Devel<br><br>
+<span class="detail">install package(s)</span>: <a href="obs-a.html">obs-a</a><br><br>
+<span class="detail">maintainer(s)</span>: ORPHANED
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/obs-a-src/obs-a-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/obs-a.html b/test/testdata/htdocs.expected/summary/obs-a.html
index b3f5ac7..e769792 100644
--- a/test/testdata/htdocs.expected/summary/obs-a.html
+++ b/test/testdata/htdocs.expected/summary/obs-a.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: obsolete package A<br><br>
<span class="detail">description</span>: obsolete package A<br><br>
<span class="detail">categories</span>: Devel<br><br>
-<span class="detail">binaries</span>: <a href="obs-a.html">obs-a</a><br><br>
+<span class="detail">source package</span>: <a href="obs-a-src.html">obs-a</a><br><br>
<span class="detail">maintainer(s)</span>: ORPHANED
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -23,7 +23,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>1.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/obs-a/obs-a-1.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/obs-a/obs-a-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/obs-b-src.html b/test/testdata/htdocs.expected/summary/obs-b-src.html
new file mode 100755
index 0000000..c55f882
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/obs-b-src.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for obs-b (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: obs-b</h1>
+<span class="detail">summary</span>: obsolete package B<br><br>
+<span class="detail">description</span>: obsolete package B<br><br>
+<span class="detail">categories</span>: Devel<br><br>
+<span class="detail">install package(s)</span>: <a href="obs-b.html">obs-b</a><br><br>
+<span class="detail">maintainer(s)</span>: ORPHANED
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/obs-b-src/obs-b-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/obs-b.html b/test/testdata/htdocs.expected/summary/obs-b.html
index 436fa94..3eea36d 100644
--- a/test/testdata/htdocs.expected/summary/obs-b.html
+++ b/test/testdata/htdocs.expected/summary/obs-b.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: obsolete package B<br><br>
<span class="detail">description</span>: obsolete package B<br><br>
<span class="detail">categories</span>: Devel<br><br>
-<span class="detail">binaries</span>: <a href="obs-b.html">obs-b</a><br><br>
+<span class="detail">source package</span>: <a href="obs-b-src.html">obs-b</a><br><br>
<span class="detail">maintainer(s)</span>: ORPHANED
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -23,7 +23,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>1.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/obs-b/obs-b-1.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/obs-b/obs-b-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/openssh-src.html b/test/testdata/htdocs.expected/summary/openssh-src.html
new file mode 100755
index 0000000..ddac058
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/openssh-src.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for openssh (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: openssh</h1>
+<span class="detail">summary</span>: The OpenSSH server and client programs<br><br>
+<span class="detail">description</span>: 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.<br><br>
+<span class="detail">categories</span>: Net<br><br>
+<span class="detail">install package(s)</span>: <a href="openssh.html">openssh</a><br><br>
+<span class="detail">maintainer(s)</span>: Corinna Vinschen
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>7.2p2-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/openssh-src/openssh-7.2p2-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/openssh.html b/test/testdata/htdocs.expected/summary/openssh.html
index a2f3b78..de87c5a 100644
--- a/test/testdata/htdocs.expected/summary/openssh.html
+++ b/test/testdata/htdocs.expected/summary/openssh.html
@@ -15,7 +15,7 @@
executing commands on a remote machine. It can replace rlogin and rsh,
providing encrypted communication between two machines.<br><br>
<span class="detail">categories</span>: Net<br><br>
-<span class="detail">binaries</span>: <a href="openssh.html">openssh</a><br><br>
+<span class="detail">source package</span>: <a href="openssh-src.html">openssh</a><br><br>
<span class="detail">maintainer(s)</span>: Corinna Vinschen
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -25,7 +25,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>7.2p2-1</td><td class="right">1 kB</td><td>[<a href="../x86/openssh/openssh-7.2p2-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>7.2p2-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/openssh/openssh-7.2p2-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/per-version-replacement-hint-only-src.html b/test/testdata/htdocs.expected/summary/per-version-replacement-hint-only-src.html
new file mode 100755
index 0000000..d4f7ab6
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/per-version-replacement-hint-only-src.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for per-version-replacement-hint-only (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: per-version-replacement-hint-only</h1>
+<span class="detail">summary</span>: Per-version hint test package<br><br>
+<span class="detail">description</span>: Per-version hint test package<br><br>
+<span class="detail">categories</span>: Base<br><br>
+<span class="detail">install package(s)</span>: <a href="per-version-replacement-hint-only.html">per-version-replacement-hint-only</a><br><br>
+<span class="detail">maintainer(s)</span>: Blooey McFooey
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/per-version-replacement-hint-only-src/per-version-replacement-hint-only-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/per-version-replacement-hint-only.html b/test/testdata/htdocs.expected/summary/per-version-replacement-hint-only.html
index 8ab2a7f..ed019b7 100644
--- a/test/testdata/htdocs.expected/summary/per-version-replacement-hint-only.html
+++ b/test/testdata/htdocs.expected/summary/per-version-replacement-hint-only.html
@@ -14,7 +14,7 @@
<span class="detail">description</span>: Per-version hint test package<br><br>
<span class="detail">categories</span>: Base<br><br>
<span class="detail">depends</span>: <a href="cygwin.html">cygwin</a><br><br>
-<span class="detail">binaries</span>: <a href="per-version-replacement-hint-only.html">per-version-replacement-hint-only</a><br><br>
+<span class="detail">source package</span>: <a href="per-version-replacement-hint-only-src.html">per-version-replacement-hint-only</a><br><br>
<span class="detail">maintainer(s)</span>: Blooey McFooey
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -24,7 +24,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>1.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/per-version-replacement-hint-only/per-version-replacement-hint-only-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/per-version-src.html b/test/testdata/htdocs.expected/summary/per-version-src.html
new file mode 100755
index 0000000..5e5d61e
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/per-version-src.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for per-version (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: per-version</h1>
+<span class="detail">summary</span>: Per-version hint test package<br><br>
+<span class="detail">description</span>: Per-version hint test package<br><br>
+<span class="detail">categories</span>: Base<br><br>
+<span class="detail">install package(s)</span>: <a href="per-version.html">per-version</a><br><br>
+<span class="detail">maintainer(s)</span>: Blooey McFooey
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>4.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/per-version-src/per-version-4.0-1-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>4.8-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/per-version-src/per-version-4.8-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/per-version.html b/test/testdata/htdocs.expected/summary/per-version.html
index 3fef454..cb8d1b4 100644
--- a/test/testdata/htdocs.expected/summary/per-version.html
+++ b/test/testdata/htdocs.expected/summary/per-version.html
@@ -14,7 +14,7 @@
<span class="detail">description</span>: Per-version hint test package<br><br>
<span class="detail">categories</span>: Base<br><br>
<span class="detail">depends</span>: <a href="base-cygwin.html">base-cygwin</a><br><br>
-<span class="detail">binaries</span>: <a href="per-version.html">per-version</a><br><br>
+<span class="detail">source package</span>: <a href="per-version-src.html">per-version</a><br><br>
<span class="detail">maintainer(s)</span>: Blooey McFooey
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -24,9 +24,7 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>4.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/per-version/per-version-4.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>4.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/per-version/per-version-4.0-1-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>4.8-1</td><td class="right">1 kB</td><td>[<a href="../x86/per-version/per-version-4.8-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>4.8-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/per-version/per-version-4.8-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL-src.html b/test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL-src.html
new file mode 100755
index 0000000..512831d
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL-src.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for perl-Net-SMTP-SSL (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: perl-Net-SMTP-SSL</h1>
+<span class="detail">summary</span>: Perl distribution Net-SMTP-SSL<br><br>
+<span class="detail">description</span>: Implements the same API as Net::SMTP, but uses IO::Socket::SSL for
+its network operations in order to support encrypted connections.<br><br>
+<span class="detail">categories</span>: Perl<br><br>
+<span class="detail">install package(s)</span>: <a href="perl-Net-SMTP-SSL.html">perl-Net-SMTP-SSL</a><br><br>
+<span class="detail">maintainer(s)</span>: Blooey McFooey, Yaakov Selkowitz
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>1.01-1 (source)</td><td class="right">3 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.01-1-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>1.02-1 (source)</td><td class="right">3 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.02-1-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>1.03-1 (source)</td><td class="right">3 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.03-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL.html b/test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL.html
index 68f5b81..83f27cb 100644
--- a/test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL.html
+++ b/test/testdata/htdocs.expected/summary/perl-Net-SMTP-SSL.html
@@ -14,7 +14,7 @@
<span class="detail">description</span>: Implements the same API as Net::SMTP, but uses IO::Socket::SSL for
its network operations in order to support encrypted connections.<br><br>
<span class="detail">categories</span>: Perl<br><br>
-<span class="detail">binaries</span>: <a href="perl-Net-SMTP-SSL.html">perl-Net-SMTP-SSL</a><br><br>
+<span class="detail">source package</span>: <a href="perl-Net-SMTP-SSL-src.html">perl-Net-SMTP-SSL</a><br><br>
<span class="detail">maintainer(s)</span>: Blooey McFooey, Yaakov Selkowitz
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -24,11 +24,8 @@ its network operations in order to support encrypted connections.<br><br>
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>1.01-1</td><td class="right">4 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.01-1 (source)</td><td class="right">3 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.01-1-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>1.02-1</td><td class="right">4 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.02-1 (source)</td><td class="right">3 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.02-1-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>1.03-1</td><td class="right">4 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.03-1 (source)</td><td class="right">3 kB</td><td>[<a href="../x86/perl-Net-SMTP-SSL/perl-Net-SMTP-SSL-1.03-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/rpm-doc-src.html b/test/testdata/htdocs.expected/summary/rpm-doc-src.html
new file mode 100755
index 0000000..733c6e8
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/rpm-doc-src.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for rpm-doc (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: rpm-doc</h1>
+<span class="detail">summary</span>: Obsolete package for RPM package management system manual pages (extra text to so repr is not one line)<br><br>
+<span class="detail">description</span>: Obsolete package for RPM package management system manual pages (extra text to so repr is not one line)<br><br>
+<span class="detail">categories</span>: _obsolete<br><br>
+<span class="detail">install package(s)</span>: <a href="rpm-doc.html">rpm-doc</a><br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>4.1-2 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/rpm-doc-src/rpm-doc-4.1-2-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/rpm-doc.html b/test/testdata/htdocs.expected/summary/rpm-doc.html
index f56be56..0da1339 100644
--- a/test/testdata/htdocs.expected/summary/rpm-doc.html
+++ b/test/testdata/htdocs.expected/summary/rpm-doc.html
@@ -13,13 +13,12 @@
<span class="detail">summary</span>: Obsolete package for RPM package management system manual pages (extra text to so repr is not one line)<br><br>
<span class="detail">description</span>: Obsolete package for RPM package management system manual pages (extra text to so repr is not one line)<br><br>
<span class="detail">categories</span>: _obsolete<br><br>
-<span class="detail">binaries</span>: <a href="rpm-doc.html">rpm-doc</a><br><br>
+<span class="detail">source package</span>: <a href="rpm-doc-src.html">rpm-doc</a><br><br>
<ul>
<li><span class="detail">x86</span></li>
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>4.1-2</td><td class="right">50 kB</td><td>[<a href="../x86/rpm-doc/rpm-doc-4.1-2">list of files</a>]</td><td>stable</td></tr>
-<tr><td>4.1-2 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/rpm-doc/rpm-doc-4.1-2-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>999-1</td><td class="right">1 kB</td><td>[<a href="../x86/rpm-doc/rpm-doc-999-1">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
diff --git a/test/testdata/htdocs.expected/summary/staleversion-src.html b/test/testdata/htdocs.expected/summary/staleversion-src.html
new file mode 100755
index 0000000..9f1006d
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/staleversion-src.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for staleversion (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: staleversion</h1>
+<span class="detail">summary</span>: Test package for stale version removal<br><br>
+<span class="detail">description</span>: Test package for stale version removal<br><br>
+<span class="detail">categories</span>: Shells Base<br><br>
+<span class="detail">install package(s)</span>: <a href="staleversion.html">staleversion</a><br><br>
+<span class="detail">maintainer(s)</span>: Blooey McFooey
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>240-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion-src/staleversion-240-1-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>242-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion-src/staleversion-242-0-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>243-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion-src/staleversion-243-0-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>250-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion-src/staleversion-250-0-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>251-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion-src/staleversion-251-0-src">list of files</a>]</td><td>stable</td></tr>
+<tr><td>260-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion-src/staleversion-260-0-src">list of files</a>]</td><td>test</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/staleversion.html b/test/testdata/htdocs.expected/summary/staleversion.html
index 0f59ea2..e75eb27 100644
--- a/test/testdata/htdocs.expected/summary/staleversion.html
+++ b/test/testdata/htdocs.expected/summary/staleversion.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: Test package for stale version removal<br><br>
<span class="detail">description</span>: Test package for stale version removal<br><br>
<span class="detail">categories</span>: Shells Base<br><br>
-<span class="detail">binaries</span>: <a href="staleversion.html">staleversion</a><br><br>
+<span class="detail">source package</span>: <a href="staleversion-src.html">staleversion</a><br><br>
<span class="detail">maintainer(s)</span>: Blooey McFooey
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -23,17 +23,11 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>240-1</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-240-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>240-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-240-1-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>242-0</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-242-0">list of files</a>]</td><td>stable</td></tr>
-<tr><td>242-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-242-0-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>243-0</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-243-0">list of files</a>]</td><td>stable</td></tr>
-<tr><td>243-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-243-0-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>250-0</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-250-0">list of files</a>]</td><td>stable</td></tr>
-<tr><td>250-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-250-0-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>251-0</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-251-0">list of files</a>]</td><td>stable</td></tr>
-<tr><td>251-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-251-0-src">list of files</a>]</td><td>stable</td></tr>
<tr><td>260-0</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-260-0">list of files</a>]</td><td>test</td></tr>
-<tr><td>260-0 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/staleversion/staleversion-260-0-src">list of files</a>]</td><td>test</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/test-c-src.html b/test/testdata/htdocs.expected/summary/test-c-src.html
new file mode 100755
index 0000000..3218aee
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/test-c-src.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for test-c (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: test-c</h1>
+<span class="detail">summary</span>: test package C<br><br>
+<span class="detail">description</span>: test package C<br><br>
+<span class="detail">categories</span>: Devel<br><br>
+<span class="detail">install package(s)</span>: <a href="test-c.html">test-c</a><br><br>
+<span class="detail">maintainer(s)</span>: ORPHANED
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/test-c-src/test-c-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/test-c.html b/test/testdata/htdocs.expected/summary/test-c.html
index 188f4b0..f779106 100644
--- a/test/testdata/htdocs.expected/summary/test-c.html
+++ b/test/testdata/htdocs.expected/summary/test-c.html
@@ -15,7 +15,7 @@
<span class="detail">categories</span>: Devel<br><br>
<span class="detail">depends</span>: test-d (>= 1.0), <a href="test-e.html">test-e</a><br><br>
<span class="detail">obsoletes</span>: <a href="obs-a.html">obs-a</a>, <a href="obs-b.html">obs-b</a><br><br>
-<span class="detail">binaries</span>: <a href="test-c.html">test-c</a><br><br>
+<span class="detail">source package</span>: <a href="test-c-src.html">test-c</a><br><br>
<span class="detail">maintainer(s)</span>: ORPHANED
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -25,7 +25,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>1.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/test-c/test-c-1.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/test-c/test-c-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/test-d-src.html b/test/testdata/htdocs.expected/summary/test-d-src.html
new file mode 100755
index 0000000..a80cc86
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/test-d-src.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for test-d (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: test-d</h1>
+<span class="detail">summary</span>: test package D<br><br>
+<span class="detail">description</span>: test package D<br><br>
+<span class="detail">categories</span>: Devel<br><br>
+<span class="detail">install package(s)</span>: <a href="test-d.html">test-d</a><br><br>
+<span class="detail">maintainer(s)</span>: ORPHANED
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>1.0.42590-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/test-d-src/test-d-1.0.42590-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/test-d.html b/test/testdata/htdocs.expected/summary/test-d.html
index ba3ee0e..1aa2f6b 100644
--- a/test/testdata/htdocs.expected/summary/test-d.html
+++ b/test/testdata/htdocs.expected/summary/test-d.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: test package D<br><br>
<span class="detail">description</span>: test package D<br><br>
<span class="detail">categories</span>: Devel<br><br>
-<span class="detail">binaries</span>: <a href="test-d.html">test-d</a><br><br>
+<span class="detail">source package</span>: <a href="test-d-src.html">test-d</a><br><br>
<span class="detail">maintainer(s)</span>: ORPHANED
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -23,7 +23,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>1.0.42590-1</td><td class="right">1 kB</td><td>[<a href="../x86/test-d/test-d-1.0.42590-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.0.42590-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/test-d/test-d-1.0.42590-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/test-e-src.html b/test/testdata/htdocs.expected/summary/test-e-src.html
new file mode 100755
index 0000000..84da327
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/test-e-src.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for test-e (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: test-e</h1>
+<span class="detail">summary</span>: test package E<br><br>
+<span class="detail">description</span>: test package E<br><br>
+<span class="detail">categories</span>: Devel<br><br>
+<span class="detail">build-depends</span>: libtextcat-devel<br><br>
+<span class="detail">install package(s)</span>: <a href="test-e.html">test-e</a><br><br>
+<span class="detail">maintainer(s)</span>: ORPHANED
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/test-e-src/test-e-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/test-e.html b/test/testdata/htdocs.expected/summary/test-e.html
index 1360f7d..c71f753 100644
--- a/test/testdata/htdocs.expected/summary/test-e.html
+++ b/test/testdata/htdocs.expected/summary/test-e.html
@@ -13,8 +13,7 @@
<span class="detail">summary</span>: test package E<br><br>
<span class="detail">description</span>: test package E<br><br>
<span class="detail">categories</span>: Devel<br><br>
-<span class="detail">build-depends</span>: libtextcat-devel<br><br>
-<span class="detail">binaries</span>: <a href="test-e.html">test-e</a><br><br>
+<span class="detail">source package</span>: <a href="test-e-src.html">test-e</a><br><br>
<span class="detail">maintainer(s)</span>: ORPHANED
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -24,7 +23,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>1.0-1</td><td class="right">1 kB</td><td>[<a href="../x86/test-e/test-e-1.0-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>1.0-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/test-e/test-e-1.0-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/summary/testpackage-src.html b/test/testdata/htdocs.expected/summary/testpackage-src.html
new file mode 100755
index 0000000..8d132db
--- /dev/null
+++ b/test/testdata/htdocs.expected/summary/testpackage-src.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<link rel="stylesheet" type="text/css" href="../../style.css"/>
+<title>Cygwin Package Summary for testpackage (source)</title>
+</head>
+<body>
+<!--#include virtual="/navbar.html" -->
+<div id="main">
+<!--#include virtual="/top.html" -->
+<h1>Source Package: testpackage</h1>
+<span class="detail">summary</span>: A test package (stuff &amp; other stuff)<br><br>
+<span class="detail">description</span>: A test package (stuff &amp; other stuff)<br><br>
+<span class="detail">categories</span>: Devel<br><br>
+<span class="detail">install package(s)</span>: <a href="testpackage.html">testpackage</a><br><br>
+<span class="detail">maintainer(s)</span>: Blooey McFooey
+<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
+<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
+<br><br>
+<ul>
+<li><span class="detail">x86</span></li>
+<table class="pkgtable">
+<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
+<tr><td>0.1-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/testpackage-src/testpackage-0.1-1-src">list of files</a>]</td><td>stable</td></tr>
+</table><br>
+</ul>
+</div>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/summary/testpackage.html b/test/testdata/htdocs.expected/summary/testpackage.html
index 6f6daff..6d18cd8 100644
--- a/test/testdata/htdocs.expected/summary/testpackage.html
+++ b/test/testdata/htdocs.expected/summary/testpackage.html
@@ -13,7 +13,7 @@
<span class="detail">summary</span>: A test package (stuff &amp; other stuff)<br><br>
<span class="detail">description</span>: A test package (stuff &amp; other stuff)<br><br>
<span class="detail">categories</span>: Devel<br><br>
-<span class="detail">binaries</span>: <a href="testpackage.html">testpackage</a><br><br>
+<span class="detail">source package</span>: <a href="testpackage-src.html">testpackage</a><br><br>
<span class="detail">maintainer(s)</span>: Blooey McFooey
<span class="smaller">(Use <a href="/lists.html#cygwin">the mailing list</a> to report bugs or ask questions.
<a href="/problems.html#personal-email">Do not contact the maintainer(s) directly</a>.)</span>
@@ -23,7 +23,6 @@
<table class="pkgtable">
<tr><th>Version</th><th>Package Size</th><th>Files</th><th>Status</th></tr>
<tr><td>0.1-1</td><td class="right">1 kB</td><td>[<a href="../x86/testpackage/testpackage-0.1-1">list of files</a>]</td><td>stable</td></tr>
-<tr><td>0.1-1 (source)</td><td class="right">1 kB</td><td>[<a href="../x86/testpackage/testpackage-0.1-1-src">list of files</a>]</td><td>stable</td></tr>
</table><br>
</ul>
</div>
diff --git a/test/testdata/htdocs.expected/x86/arc-src/.htaccess b/test/testdata/htdocs.expected/x86/arc-src/.htaccess
new file mode 100644
index 0000000..c846ada
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/arc-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/arc-src/$ /packages/summary/arc-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/arc-src/arc-4.32.7-10-src b/test/testdata/htdocs.expected/x86/arc-src/arc-4.32.7-10-src
new file mode 100644
index 0000000..583e28d
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/arc-src/arc-4.32.7-10-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>arc-src: The ARC archive utility (source)</title>
+</head>
+<body>
+<h1>arc-src: The ARC archive utility (source)</h1>
+<pre>
+ 2016-11-24 22:47 1786 cc1BOI4Z
+ 2016-11-24 18:14 1786 ccbdRcNC
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/corrupt-src/.htaccess b/test/testdata/htdocs.expected/x86/corrupt-src/.htaccess
new file mode 100644
index 0000000..7389214
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/corrupt-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/corrupt-src/$ /packages/summary/corrupt-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/corrupt-src/corrupt-2.0.0-1-src b/test/testdata/htdocs.expected/x86/corrupt-src/corrupt-2.0.0-1-src
new file mode 100644
index 0000000..46032cf
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/corrupt-src/corrupt-2.0.0-1-src
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>corrupt-src: A corrupt package (source)</title>
+</head>
+<body>
+<h1>corrupt-src: A corrupt package (source)</h1>
+<pre>
+ 2016-06-11 10:34 0 perl-Business-ISBN-2.011-1.src/
+ 2016-06-11 10:34 364175 perl-Business-ISBN-2.011-1.src/Business-ISBN-2.011.tar.gz
+package is corrupted
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/cygwin-src/.htaccess b/test/testdata/htdocs.expected/x86/cygwin-src/.htaccess
new file mode 100644
index 0000000..0f3a4c0
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/cygwin-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/cygwin-src/$ /packages/summary/cygwin-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.0-1-src b/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.0-1-src
new file mode 100644
index 0000000..9a42632
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.0-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>cygwin-src: The UNIX emulation engine (source)</title>
+</head>
+<body>
+<h1>cygwin-src: The UNIX emulation engine (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.1-1-src b/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.1-1-src
new file mode 100644
index 0000000..9a42632
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.2.1-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>cygwin-src: The UNIX emulation engine (source)</title>
+</head>
+<body>
+<h1>cygwin-src: The UNIX emulation engine (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.3.0-0.3-src b/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.3.0-0.3-src
new file mode 100644
index 0000000..9a42632
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/cygwin-src/cygwin-2.3.0-0.3-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>cygwin-src: The UNIX emulation engine (source)</title>
+</head>
+<body>
+<h1>cygwin-src: The UNIX emulation engine (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/keychain-src/.htaccess b/test/testdata/htdocs.expected/x86/keychain-src/.htaccess
new file mode 100644
index 0000000..b1467ae
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/keychain-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/keychain-src/$ /packages/summary/keychain-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/keychain-src/keychain-2.6.8-1-src b/test/testdata/htdocs.expected/x86/keychain-src/keychain-2.6.8-1-src
new file mode 100644
index 0000000..bdc08ce
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/keychain-src/keychain-2.6.8-1-src
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>keychain-src: Key manager for OpenSSH (source)</title>
+</head>
+<body>
+<h1>keychain-src: Key manager for OpenSSH (source)</h1>
+<pre>
+ 2006-11-09 04:59 3051 keychain-2.6.8-1.patch
+ 2006-11-09 04:59 5621 keychain-2.6.8-1.sh
+ 2006-11-09 04:59 31531 keychain-2.6.8.tar.bz2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/keychain-src/keychain-2.7.1-1-src b/test/testdata/htdocs.expected/x86/keychain-src/keychain-2.7.1-1-src
new file mode 100644
index 0000000..239531c
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/keychain-src/keychain-2.7.1-1-src
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>keychain-src: Key manager for OpenSSH (source)</title>
+</head>
+<body>
+<h1>keychain-src: Key manager for OpenSSH (source)</h1>
+<pre>
+ 2012-10-10 05:40 24455 keychain-2.7.1-1-cygwin.patch
+ 2012-10-10 05:40 270 keychain-2.7.1-1-cygwin.patch.sig
+ 2012-10-10 05:40 320093 keychain-2.7.1-1.sh
+ 2012-10-10 05:40 260 keychain-2.7.1-1.sh.sig
+ 2012-10-10 05:40 65211 keychain_2.7.1.orig.tar.gz
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/mDNSResponder-src/.htaccess b/test/testdata/htdocs.expected/x86/mDNSResponder-src/.htaccess
new file mode 100644
index 0000000..a47ee41
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/mDNSResponder-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/mDNSResponder-src/$ /packages/summary/mDNSResponder-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/mDNSResponder-src/mDNSResponder-379.32.1-1-src b/test/testdata/htdocs.expected/x86/mDNSResponder-src/mDNSResponder-379.32.1-1-src
new file mode 100644
index 0000000..6b9e6ce
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/mDNSResponder-src/mDNSResponder-379.32.1-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>mDNSResponder-src: Bonjour Zeroconf implementation (source)</title>
+</head>
+<body>
+<h1>mDNSResponder-src: Bonjour Zeroconf implementation (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/obs-a-src/.htaccess b/test/testdata/htdocs.expected/x86/obs-a-src/.htaccess
new file mode 100644
index 0000000..8728151
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/obs-a-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/obs-a-src/$ /packages/summary/obs-a-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/obs-a-src/obs-a-1.0-1-src b/test/testdata/htdocs.expected/x86/obs-a-src/obs-a-1.0-1-src
new file mode 100644
index 0000000..e33509d
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/obs-a-src/obs-a-1.0-1-src
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>obs-a-src: obsolete package A (source)</title>
+</head>
+<body>
+<h1>obs-a-src: obsolete package A (source)</h1>
+<pre>
+ 2017-05-22 13:04 82 test-a-1.0-1.hint
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/obs-b-src/.htaccess b/test/testdata/htdocs.expected/x86/obs-b-src/.htaccess
new file mode 100644
index 0000000..d8e7f90
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/obs-b-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/obs-b-src/$ /packages/summary/obs-b-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/obs-b-src/obs-b-1.0-1-src b/test/testdata/htdocs.expected/x86/obs-b-src/obs-b-1.0-1-src
new file mode 100644
index 0000000..ad1d017
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/obs-b-src/obs-b-1.0-1-src
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>obs-b-src: obsolete package B (source)</title>
+</head>
+<body>
+<h1>obs-b-src: obsolete package B (source)</h1>
+<pre>
+ 2017-05-22 13:04 82 test-a-1.0-1.hint
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/openssh-src/.htaccess b/test/testdata/htdocs.expected/x86/openssh-src/.htaccess
new file mode 100644
index 0000000..efcc95b
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/openssh-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/openssh-src/$ /packages/summary/openssh-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/openssh-src/openssh-7.2p2-1-src b/test/testdata/htdocs.expected/x86/openssh-src/openssh-7.2p2-1-src
new file mode 100644
index 0000000..11ab8f7
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/openssh-src/openssh-7.2p2-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>openssh-src: The OpenSSH server and client programs (source)</title>
+</head>
+<body>
+<h1>openssh-src: The OpenSSH server and client programs (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/.htaccess b/test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/.htaccess
new file mode 100644
index 0000000..146cc84
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/per-version-replacement-hint-only-src/$ /packages/summary/per-version-replacement-hint-only-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/per-version-replacement-hint-only-1.0-1-src b/test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/per-version-replacement-hint-only-1.0-1-src
new file mode 100644
index 0000000..bef865b
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/per-version-replacement-hint-only-src/per-version-replacement-hint-only-1.0-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>per-version-replacement-hint-only-src: Per-version hint test package (source)</title>
+</head>
+<body>
+<h1>per-version-replacement-hint-only-src: Per-version hint test package (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/per-version-src/.htaccess b/test/testdata/htdocs.expected/x86/per-version-src/.htaccess
new file mode 100644
index 0000000..dc4da58
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/per-version-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/per-version-src/$ /packages/summary/per-version-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/per-version-src/per-version-4.0-1-src b/test/testdata/htdocs.expected/x86/per-version-src/per-version-4.0-1-src
new file mode 100644
index 0000000..a43c063
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/per-version-src/per-version-4.0-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>per-version-src: Per-version hint test package (source)</title>
+</head>
+<body>
+<h1>per-version-src: Per-version hint test package (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/per-version-src/per-version-4.8-1-src b/test/testdata/htdocs.expected/x86/per-version-src/per-version-4.8-1-src
new file mode 100644
index 0000000..a43c063
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/per-version-src/per-version-4.8-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>per-version-src: Per-version hint test package (source)</title>
+</head>
+<body>
+<h1>per-version-src: Per-version hint test package (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/.htaccess b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/.htaccess
new file mode 100644
index 0000000..7934f37
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/perl-Net-SMTP-SSL-src/$ /packages/summary/perl-Net-SMTP-SSL-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.01-1-src b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.01-1-src
new file mode 100644
index 0000000..806be54
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.01-1-src
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>perl-Net-SMTP-SSL-src: Perl distribution Net-SMTP-SSL (source)</title>
+</head>
+<body>
+<h1>perl-Net-SMTP-SSL-src: Perl distribution Net-SMTP-SSL (source)</h1>
+<pre>
+ 2015-06-26 19:10 0 perl-Net-SMTP-SSL-1.03-1.src/
+ 2015-06-26 19:10 2271 perl-Net-SMTP-SSL-1.03-1.src/Net-SMTP-SSL-1.03.tar.gz
+ 2015-06-26 19:10 296 perl-Net-SMTP-SSL-1.03-1.src/perl-Net-SMTP-SSL.cygport
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.02-1-src b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.02-1-src
new file mode 100644
index 0000000..806be54
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.02-1-src
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>perl-Net-SMTP-SSL-src: Perl distribution Net-SMTP-SSL (source)</title>
+</head>
+<body>
+<h1>perl-Net-SMTP-SSL-src: Perl distribution Net-SMTP-SSL (source)</h1>
+<pre>
+ 2015-06-26 19:10 0 perl-Net-SMTP-SSL-1.03-1.src/
+ 2015-06-26 19:10 2271 perl-Net-SMTP-SSL-1.03-1.src/Net-SMTP-SSL-1.03.tar.gz
+ 2015-06-26 19:10 296 perl-Net-SMTP-SSL-1.03-1.src/perl-Net-SMTP-SSL.cygport
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.03-1-src b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.03-1-src
new file mode 100644
index 0000000..806be54
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/perl-Net-SMTP-SSL-src/perl-Net-SMTP-SSL-1.03-1-src
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>perl-Net-SMTP-SSL-src: Perl distribution Net-SMTP-SSL (source)</title>
+</head>
+<body>
+<h1>perl-Net-SMTP-SSL-src: Perl distribution Net-SMTP-SSL (source)</h1>
+<pre>
+ 2015-06-26 19:10 0 perl-Net-SMTP-SSL-1.03-1.src/
+ 2015-06-26 19:10 2271 perl-Net-SMTP-SSL-1.03-1.src/Net-SMTP-SSL-1.03.tar.gz
+ 2015-06-26 19:10 296 perl-Net-SMTP-SSL-1.03-1.src/perl-Net-SMTP-SSL.cygport
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/rpm-doc-src/.htaccess b/test/testdata/htdocs.expected/x86/rpm-doc-src/.htaccess
new file mode 100644
index 0000000..c588cef
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/rpm-doc-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/rpm-doc-src/$ /packages/summary/rpm-doc-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/rpm-doc-src/rpm-doc-4.1-2-src b/test/testdata/htdocs.expected/x86/rpm-doc-src/rpm-doc-4.1-2-src
new file mode 100644
index 0000000..fb29610
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/rpm-doc-src/rpm-doc-4.1-2-src
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>rpm-doc-src: Obsolete package for RPM package management system manual pages (extra text to so repr is not one line) (source)</title>
+</head>
+<body>
+<h1>rpm-doc-src: Obsolete package for RPM package management system manual pages (extra text to so repr is not one line) (source)</h1>
+<pre>
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion-src/.htaccess b/test/testdata/htdocs.expected/x86/staleversion-src/.htaccess
new file mode 100644
index 0000000..b6ffc09
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/staleversion-src/$ /packages/summary/staleversion-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-240-1-src b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-240-1-src
new file mode 100644
index 0000000..c7e0926
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-240-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>staleversion-src: Test package for stale version removal (source)</title>
+</head>
+<body>
+<h1>staleversion-src: Test package for stale version removal (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-242-0-src b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-242-0-src
new file mode 100644
index 0000000..c7e0926
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-242-0-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>staleversion-src: Test package for stale version removal (source)</title>
+</head>
+<body>
+<h1>staleversion-src: Test package for stale version removal (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-243-0-src b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-243-0-src
new file mode 100644
index 0000000..c7e0926
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-243-0-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>staleversion-src: Test package for stale version removal (source)</title>
+</head>
+<body>
+<h1>staleversion-src: Test package for stale version removal (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-250-0-src b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-250-0-src
new file mode 100644
index 0000000..c7e0926
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-250-0-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>staleversion-src: Test package for stale version removal (source)</title>
+</head>
+<body>
+<h1>staleversion-src: Test package for stale version removal (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-251-0-src b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-251-0-src
new file mode 100644
index 0000000..c7e0926
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-251-0-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>staleversion-src: Test package for stale version removal (source)</title>
+</head>
+<body>
+<h1>staleversion-src: Test package for stale version removal (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-260-0-src b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-260-0-src
new file mode 100644
index 0000000..c7e0926
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion-src/staleversion-260-0-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>staleversion-src: Test package for stale version removal (source)</title>
+</head>
+<body>
+<h1>staleversion-src: Test package for stale version removal (source)</h1>
+<pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/test-c-src/.htaccess b/test/testdata/htdocs.expected/x86/test-c-src/.htaccess
new file mode 100644
index 0000000..a134807
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/test-c-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/test-c-src/$ /packages/summary/test-c-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/test-c-src/test-c-1.0-1-src b/test/testdata/htdocs.expected/x86/test-c-src/test-c-1.0-1-src
new file mode 100644
index 0000000..e3bd985
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/test-c-src/test-c-1.0-1-src
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>test-c-src: test package C (source)</title>
+</head>
+<body>
+<h1>test-c-src: test package C (source)</h1>
+<pre>
+ 2017-05-22 13:27 82 test-c-0.5-1.hint
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/test-d-src/.htaccess b/test/testdata/htdocs.expected/x86/test-d-src/.htaccess
new file mode 100644
index 0000000..b58f463
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/test-d-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/test-d-src/$ /packages/summary/test-d-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/test-d-src/test-d-1.0-1-src b/test/testdata/htdocs.expected/x86/test-d-src/test-d-1.0-1-src
new file mode 100644
index 0000000..1551c3f
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/test-d-src/test-d-1.0-1-src
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>test-d-src: test package D (source)</title>
+</head>
+<body>
+<h1>test-d-src: test package D (source)</h1>
+<pre>
+ 2017-05-22 18:17 40 test-d-1.0-1.hint
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/test-e-src/.htaccess b/test/testdata/htdocs.expected/x86/test-e-src/.htaccess
new file mode 100644
index 0000000..ac45df5
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/test-e-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/test-e-src/$ /packages/summary/test-e-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/test-e-src/test-e-1.0-1-src b/test/testdata/htdocs.expected/x86/test-e-src/test-e-1.0-1-src
new file mode 100644
index 0000000..a1b7a2a
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/test-e-src/test-e-1.0-1-src
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>test-e-src: test package E (source)</title>
+</head>
+<body>
+<h1>test-e-src: test package E (source)</h1>
+<pre>
+ 2017-05-22 18:17 40 test-d-1.0-1.hint
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/testpackage-src/.htaccess b/test/testdata/htdocs.expected/x86/testpackage-src/.htaccess
new file mode 100644
index 0000000..def9360
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/testpackage-src/.htaccess
@@ -0,0 +1,2 @@
+RedirectMatch temp /packages/x86/testpackage-src/$ /packages/summary/testpackage-src.html
+ForceType text/html
diff --git a/test/testdata/htdocs.expected/x86/testpackage-src/testpackage-0.1-1-src b/test/testdata/htdocs.expected/x86/testpackage-src/testpackage-0.1-1-src
new file mode 100644
index 0000000..ea726da
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/testpackage-src/testpackage-0.1-1-src
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>testpackage-src: A test package (stuff &amp; other stuff) (source)</title>
+</head>
+<body>
+<h1>testpackage-src: A test package (stuff &amp; other stuff) (source)</h1>
+<pre>
+ 2016-11-24 22:47 1786 cc1BOI4Z
+ 2016-11-24 18:14 1786 ccbdRcNC
+</pre>
+</body>
+</html>
diff --git a/test/testdata/htdocs.expected/x86_64/.htaccess b/test/testdata/htdocs.expected/x86_64/.htaccess
new file mode 100644
index 0000000..dce07bf
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86_64/.htaccess
@@ -0,0 +1 @@
+Redirect temp /packages/x86_64/index.html https://cygwin.com/packages/package_list.html
diff --git a/test/testdata/process_arch/htdocs.expected b/test/testdata/process_arch/htdocs.expected
index bc09e7d..c82995c 100644
--- a/test/testdata/process_arch/htdocs.expected
+++ b/test/testdata/process_arch/htdocs.expected
@@ -1,90 +1,110 @@
{'.': ['packages.inc'],
- 'summary': ['arc.html',
+ 'summary': ['arc-src.html',
+ 'arc.html',
'base-cygwin.html',
+ 'corrupt-src.html',
'corrupt.html',
'cygwin-debuginfo.html',
'cygwin-devel.html',
+ 'cygwin-src.html',
'cygwin.html',
+ 'keychain-src.html',
'keychain.html',
'libdns_sd-devel.html',
'libdns_sd1.html',
+ 'mDNSResponder-src.html',
'mDNSResponder.html',
+ 'obs-a-src.html',
'obs-a.html',
+ 'obs-b-src.html',
'obs-b.html',
+ 'openssh-src.html',
'openssh.html',
+ 'per-version-replacement-hint-only-src.html',
'per-version-replacement-hint-only.html',
+ 'per-version-src.html',
'per-version.html',
+ 'perl-Net-SMTP-SSL-src.html',
'perl-Net-SMTP-SSL.html',
+ 'rpm-doc-src.html',
'rpm-doc.html',
+ 'staleversion-src.html',
'staleversion.html',
+ 'test-c-src.html',
'test-c.html',
+ 'test-d-src.html',
'test-d.html',
+ 'test-e-src.html',
'test-e.html',
+ 'testpackage-src.html',
'testpackage-subpackage.html',
'testpackage.html'],
'x86': ['.htaccess'],
- 'x86/arc': ['.htaccess', 'arc-4.32.7-10', 'arc-4.32.7-10-src'],
+ 'x86/arc': ['.htaccess', 'arc-4.32.7-10'],
+ 'x86/arc-src': ['.htaccess', 'arc-4.32.7-10-src'],
'x86/base-cygwin': ['.htaccess', 'base-cygwin-3.6-1', 'base-cygwin-3.8-1'],
- 'x86/corrupt': ['.htaccess', 'corrupt-2.0.0-1', 'corrupt-2.0.0-1-src'],
- 'x86/cygwin': ['.htaccess',
- 'cygwin-2.2.0-1',
- 'cygwin-2.2.0-1-src',
- 'cygwin-2.2.1-1',
- 'cygwin-2.2.1-1-src',
- 'cygwin-2.3.0-0.3',
- 'cygwin-2.3.0-0.3-src'],
+ 'x86/corrupt': ['.htaccess', 'corrupt-2.0.0-1'],
+ 'x86/corrupt-src': ['.htaccess', 'corrupt-2.0.0-1-src'],
+ 'x86/cygwin': ['.htaccess', 'cygwin-2.2.0-1', 'cygwin-2.2.1-1', 'cygwin-2.3.0-0.3'],
'x86/cygwin-debuginfo': ['.htaccess',
'cygwin-debuginfo-2.2.0-1',
'cygwin-debuginfo-2.2.1-1',
'cygwin-debuginfo-2.3.0-0.3'],
'x86/cygwin-devel': ['.htaccess', 'cygwin-devel-2.2.0-1', 'cygwin-devel-2.2.1-1', 'cygwin-devel-2.3.0-0.3'],
- 'x86/keychain': ['.htaccess', 'keychain-2.6.8-1', 'keychain-2.6.8-1-src', 'keychain-2.7.1-1', 'keychain-2.7.1-1-src'],
+ 'x86/cygwin-src': ['.htaccess', 'cygwin-2.2.0-1-src', 'cygwin-2.2.1-1-src', 'cygwin-2.3.0-0.3-src'],
+ 'x86/keychain': ['.htaccess', 'keychain-2.6.8-1', 'keychain-2.7.1-1'],
+ 'x86/keychain-src': ['.htaccess', 'keychain-2.6.8-1-src', 'keychain-2.7.1-1-src'],
'x86/libdns_sd-devel': ['.htaccess', 'libdns_sd-devel-379.32.1-1'],
'x86/libdns_sd1': ['.htaccess', 'libdns_sd1-379.32.1-1'],
- 'x86/mDNSResponder': ['.htaccess', 'mDNSResponder-379.32.1-1', 'mDNSResponder-379.32.1-1-src'],
- 'x86/obs-a': ['.htaccess', 'obs-a-1.0-1', 'obs-a-1.0-1-src'],
- 'x86/obs-b': ['.htaccess', 'obs-b-1.0-1', 'obs-b-1.0-1-src'],
- 'x86/openssh': ['.htaccess', 'openssh-7.2p2-1', 'openssh-7.2p2-1-src'],
- 'x86/per-version': ['.htaccess',
- 'per-version-4.0-1',
- 'per-version-4.0-1-src',
- 'per-version-4.8-1',
- 'per-version-4.8-1-src',
- 'per-version-5.0-1',
- 'per-version-5.0-1-src'],
- 'x86/per-version-replacement-hint-only': ['.htaccess',
- 'per-version-replacement-hint-only-1.0-1',
- 'per-version-replacement-hint-only-1.0-1-src'],
+ 'x86/mDNSResponder': ['.htaccess', 'mDNSResponder-379.32.1-1'],
+ 'x86/mDNSResponder-src': ['.htaccess', 'mDNSResponder-379.32.1-1-src'],
+ 'x86/obs-a': ['.htaccess', 'obs-a-1.0-1'],
+ 'x86/obs-a-src': ['.htaccess', 'obs-a-1.0-1-src'],
+ 'x86/obs-b': ['.htaccess', 'obs-b-1.0-1'],
+ 'x86/obs-b-src': ['.htaccess', 'obs-b-1.0-1-src'],
+ 'x86/openssh': ['.htaccess', 'openssh-7.2p2-1'],
+ 'x86/openssh-src': ['.htaccess', 'openssh-7.2p2-1-src'],
+ 'x86/per-version': ['.htaccess', 'per-version-4.0-1', 'per-version-4.8-1', 'per-version-5.0-1'],
+ 'x86/per-version-replacement-hint-only': ['.htaccess', 'per-version-replacement-hint-only-1.0-1'],
+ 'x86/per-version-replacement-hint-only-src': ['.htaccess', 'per-version-replacement-hint-only-1.0-1-src'],
+ 'x86/per-version-src': ['.htaccess', 'per-version-4.0-1-src', 'per-version-4.8-1-src', 'per-version-5.0-1-src'],
'x86/perl-Net-SMTP-SSL': ['.htaccess',
'perl-Net-SMTP-SSL-1.02-1',
- 'perl-Net-SMTP-SSL-1.02-1-src',
'perl-Net-SMTP-SSL-1.03-1',
- 'perl-Net-SMTP-SSL-1.03-1-src',
- 'perl-Net-SMTP-SSL-1.03-2',
- 'perl-Net-SMTP-SSL-1.03-2-src'],
- 'x86/rpm-doc': ['.htaccess', 'rpm-doc-4.1-2', 'rpm-doc-4.1-2-src', 'rpm-doc-999-1'],
- 'x86/staleversion': ['.htaccess',
- 'staleversion-243-0',
- 'staleversion-243-0-src',
- 'staleversion-250-0',
- 'staleversion-250-0-src',
- 'staleversion-260-0',
- 'staleversion-260-0-src'],
- 'x86/test-c': ['.htaccess', 'test-c-1.0-1', 'test-c-1.0-1-src'],
- 'x86/test-d': ['.htaccess', 'test-d-1.0-1', 'test-d-1.0-1-src'],
- 'x86/test-e': ['.htaccess', 'test-e-1.0-1', 'test-e-1.0-1-src'],
- 'x86/testpackage': ['.htaccess', 'testpackage-1.0-1', 'testpackage-1.0-1-src'],
+ 'perl-Net-SMTP-SSL-1.03-2'],
+ 'x86/perl-Net-SMTP-SSL-src': ['.htaccess',
+ 'perl-Net-SMTP-SSL-1.02-1-src',
+ 'perl-Net-SMTP-SSL-1.03-1-src',
+ 'perl-Net-SMTP-SSL-1.03-2-src'],
+ 'x86/rpm-doc': ['.htaccess', 'rpm-doc-4.1-2', 'rpm-doc-999-1'],
+ 'x86/rpm-doc-src': ['.htaccess', 'rpm-doc-4.1-2-src'],
+ 'x86/staleversion': ['.htaccess', 'staleversion-243-0', 'staleversion-250-0', 'staleversion-260-0'],
+ 'x86/staleversion-src': ['.htaccess', 'staleversion-243-0-src', 'staleversion-250-0-src', 'staleversion-260-0-src'],
+ 'x86/test-c': ['.htaccess', 'test-c-1.0-1'],
+ 'x86/test-c-src': ['.htaccess', 'test-c-1.0-1-src'],
+ 'x86/test-d': ['.htaccess', 'test-d-1.0-1'],
+ 'x86/test-d-src': ['.htaccess', 'test-d-1.0-1-src'],
+ 'x86/test-e': ['.htaccess', 'test-e-1.0-1'],
+ 'x86/test-e-src': ['.htaccess', 'test-e-1.0-1-src'],
+ 'x86/testpackage': ['.htaccess', 'testpackage-1.0-1'],
+ 'x86/testpackage-src': ['.htaccess', 'testpackage-1.0-1-src'],
'x86/testpackage-subpackage': ['.htaccess', 'testpackage-subpackage-1.0-1'],
'x86_64': ['.htaccess'],
- 'x86_64/obs-a': ['.htaccess', 'obs-a-1.0-1', 'obs-a-1.0-1-src'],
- 'x86_64/obs-b': ['.htaccess', 'obs-b-1.0-1', 'obs-b-1.0-1-src'],
+ 'x86_64/obs-a': ['.htaccess', 'obs-a-1.0-1'],
+ 'x86_64/obs-a-src': ['.htaccess', 'obs-a-1.0-1-src'],
+ 'x86_64/obs-b': ['.htaccess', 'obs-b-1.0-1'],
+ 'x86_64/obs-b-src': ['.htaccess', 'obs-b-1.0-1-src'],
'x86_64/perl-Net-SMTP-SSL': ['.htaccess',
'perl-Net-SMTP-SSL-1.02-1',
- 'perl-Net-SMTP-SSL-1.02-1-src',
'perl-Net-SMTP-SSL-1.03-1',
- 'perl-Net-SMTP-SSL-1.03-1-src',
- 'perl-Net-SMTP-SSL-1.03-2',
- 'perl-Net-SMTP-SSL-1.03-2-src'],
- 'x86_64/test-c': ['.htaccess', 'test-c-1.0-1', 'test-c-1.0-1-src'],
- 'x86_64/test-d': ['.htaccess', 'test-d-1.0-1', 'test-d-1.0-1-src'],
- 'x86_64/test-e': ['.htaccess', 'test-e-1.0-1', 'test-e-1.0-1-src']}
+ 'perl-Net-SMTP-SSL-1.03-2'],
+ 'x86_64/perl-Net-SMTP-SSL-src': ['.htaccess',
+ 'perl-Net-SMTP-SSL-1.02-1-src',
+ 'perl-Net-SMTP-SSL-1.03-1-src',
+ 'perl-Net-SMTP-SSL-1.03-2-src'],
+ 'x86_64/test-c': ['.htaccess', 'test-c-1.0-1'],
+ 'x86_64/test-c-src': ['.htaccess', 'test-c-1.0-1-src'],
+ 'x86_64/test-d': ['.htaccess', 'test-d-1.0-1'],
+ 'x86_64/test-d-src': ['.htaccess', 'test-d-1.0-1-src'],
+ 'x86_64/test-e': ['.htaccess', 'test-e-1.0-1'],
+ 'x86_64/test-e-src': ['.htaccess', 'test-e-1.0-1-src']}
diff --git a/test/testdata/uploads/pkglist.expected b/test/testdata/uploads/pkglist.expected
index a9d9bfd..5595a50 100644
--- a/test/testdata/uploads/pkglist.expected
+++ b/test/testdata/uploads/pkglist.expected
@@ -1,5 +1,12 @@
-{'testpackage': 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),
- 'testpackage-1.0-1.tar.bz2': Tar('testpackage-1.0-1.tar.bz2', 'x86/release/testpackage', 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83', 195, False)}}, {'1.0-1': {'sdesc': '"A test package"',
+{'testpackage': Package('testpackage', {'1.0-1': {'testpackage-1.0-1.tar.bz2': Tar('testpackage-1.0-1.tar.bz2', 'x86/release/testpackage', 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83', 195, 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',
+ '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"',
'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 '
@@ -10,7 +17,7 @@
'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"',
'category': 'Devel',
- 'external-source': 'testpackage'}}, {}, False),
+ 'external-source': 'testpackage-src'}}, {}, False),
'testpackage2-subpackage': Package('testpackage2/testpackage2-subpackage', {'1.0-1': {'testpackage2-subpackage-1.0-1.tar.bz2': Tar('testpackage2-subpackage-1.0-1.tar.bz2', 'x86/release/testpackage2/testpackage2-subpackage', '6de201dfed1d45412509c65deb34690dc2d09c6aafccfe491fd2f440f92842b9c755b61dc7bcdd4cc0c9f18cf46c2b3a1241e99c4c2a33fff5555e7b2f0b6348', 14, True)}}, {'1.0-1': {'sdesc': '"A test subpackage 2"',
'ldesc': '"A test subpackage 2"',
'category': 'Devel'}}, {}, False)}