This is the mail archive of the
cygwin-apps-cvs
mailing list for the cygwin-apps project.
[calm - Cygwin server-side packaging maintenance script] branch master, updated. 20160705-20-g437f6ad
- From: jturney at sourceware dot org
- To: cygwin-apps-cvs at sourceware dot org
- Date: 15 Sep 2016 16:25:10 -0000
- Subject: [calm - Cygwin server-side packaging maintenance script] branch master, updated. 20160705-20-g437f6ad
https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=437f6ad4ddddd43a6c39ba6bd0e02ff2cf08cdaa
commit 437f6ad4ddddd43a6c39ba6bd0e02ff2cf08cdaa
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date: Wed Sep 14 19:22:51 2016 +0100
Report conflicting movelists as an error
We probably want to told when we are uploading a package which is
immediately going to be automatically removed as stale.
Uploading a package at the same time as a marking it for removal doesn't
make any sense, so report that as an error.
Update per-version testpackage to avoid this error.
https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=66fee615aab7089942299bbac9dd97fdcd1c2ddb
commit 66fee615aab7089942299bbac9dd97fdcd1c2ddb
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date: Tue Sep 13 16:58:39 2016 +0100
Add staleversion test package
Add an additional staleversion package to test the handling of stale
versions in the release area
https://sourceware.org/git/gitweb.cgi?p=cygwin-apps/calm.git;h=2a73f7ead10a2e4756c3ed199c8dc65109cdd435
commit 2a73f7ead10a2e4756c3ed199c8dc65109cdd435
Author: Jon Turney <jon.turney@dronecode.org.uk>
Date: Tue Sep 13 14:58:10 2016 +0100
Move stale package versions to the vault
Move stale package versions to the vault. A package version is not stale if
any of the following is true:
* The version is used as curr:, prev: or test: (due to either being
explictly listed in override.hint or implictly chosen)
* The version is listed as keep: in override.hint
* It's one of the highest n versions
* The first version which is less than t days old, and all higher versions.
where:
n is given by keep-count: in override.hint
t is given by keep-days: in override.hint
These tunables currently default to 0, so no more packages are kept than
would be kept by stalepkgs, although these defaults might change in future.
We track the freshness or staleness of install and source packages
separately. Unlike stalepkgs, a fresh empty install file does not cause the
corresponding source package to be considered fresh. Also remove any
pvr.hint which is stale.
Add the --no-stale option to disable.
First we check for stale pkgs in release area. stale pkgs arising due to
more fresh pckages being uploaded are reported as a part of the upload.
Avoid doing unnecessary work if nothing is stale.
Update tests
Diff:
---
calm/calm.py | 116 +++++++++++++++++++-
calm/common_constants.py | 4 +
calm/package.py | 98 +++++++++++++++++
calm/uploads.py | 10 ++
test/test_calm.py | 1 +
.../hints/x86/release/staleversion/expected | 4 +
.../x86/release/per-version/override.hint | 2 +
test/testdata/htdocs.expected/x86/packages.inc | 1 +
.../htdocs.expected/x86/staleversion/.htaccess | 3 +
.../x86/staleversion/staleversion-240-1 | 7 +
.../x86/staleversion/staleversion-240-1-src | 7 +
.../x86/staleversion/staleversion-242-0 | 7 +
.../x86/staleversion/staleversion-242-0-src | 7 +
.../x86/staleversion/staleversion-243-0 | 7 +
.../x86/staleversion/staleversion-243-0-src | 7 +
.../x86/staleversion/staleversion-250-0 | 7 +
.../x86/staleversion/staleversion-250-0-src | 7 +
.../x86/staleversion/staleversion-251-0 | 7 +
.../x86/staleversion/staleversion-251-0-src | 7 +
.../x86/staleversion/staleversion-260-0 | 7 +
.../x86/staleversion/staleversion-260-0-src | 7 +
test/testdata/inifile/setup.ini.expected | 22 ++++
test/testdata/pkglist/cygwin-pkg-maint | 1 +
test/testdata/pkglist/expected | 2 +-
test/testdata/process_arch/htdocs.expected | 7 +
test/testdata/process_arch/rel_area.expected | 9 ++
test/testdata/process_arch/setup.ini.expected | 28 +++++
test/testdata/process_arch/vault.expected | 11 ++-
.../relarea/x86/release/staleversion/override.hint | 3 +
.../relarea/x86/release/staleversion/setup.hint | 4 +
.../staleversion/staleversion-240-1-src.tar.xz | Bin 0 -> 228 bytes
.../release/staleversion/staleversion-240-1.tar.xz | Bin 0 -> 228 bytes
.../staleversion/staleversion-242-0-src.tar.xz | Bin 0 -> 228 bytes
.../release/staleversion/staleversion-242-0.tar.xz | Bin 0 -> 228 bytes
.../staleversion/staleversion-243-0-src.tar.xz | Bin 0 -> 228 bytes
.../release/staleversion/staleversion-243-0.tar.xz | Bin 0 -> 228 bytes
.../staleversion/staleversion-250-0-src.tar.xz | Bin 0 -> 228 bytes
.../release/staleversion/staleversion-250-0.tar.xz | Bin 0 -> 228 bytes
.../staleversion/staleversion-251-0-src.tar.xz | Bin 0 -> 228 bytes
.../release/staleversion/staleversion-251-0.tar.xz | Bin 0 -> 228 bytes
.../staleversion/staleversion-260-0-src.tar.xz | Bin 0 -> 228 bytes
.../release/staleversion/staleversion-260-0.tar.xz | Bin 0 -> 228 bytes
42 files changed, 406 insertions(+), 4 deletions(-)
diff --git a/calm/calm.py b/calm/calm.py
index 3f7f374..0d41602 100755
--- a/calm/calm.py
+++ b/calm/calm.py
@@ -30,6 +30,7 @@
# - read and validate packages from release area
# - stop if there are errors
# otherwise,
+# identify and move stale packages
# for each maintainer
# - read and validate any package uploads
# - build a list of files to move and remove
@@ -37,19 +38,21 @@
# -- merge package sets
# -- remove from the package set files which are to be removed
# -- validate merged package set
+# -- identify stale packages
# -- process remove list
# - on failure
# -- mail maintainer with errors
# -- empty move list
# -- discard merged package sets
# - on success
-# -- process move list
+# -- process move lists
# -- mail maintainer with movelist
# -- continue with merged package sets
# write package listings
# write setup.ini file
#
+from collections import defaultdict
from contextlib import ExitStack
import argparse
import logging
@@ -98,6 +101,17 @@ def process(args):
if error:
return None
+ # packages can be stale due to changes made directly in the release
+ # area, so first check here if there are any stale packages to vault
+ if args.stale:
+ stale_to_vault = remove_stale_packages(args, packages)
+ if stale_to_vault:
+ for arch in common_constants.ARCHES + ['noarch']:
+ logging.info("vaulting %d old files for arch %s, which are no longer accessible by installer" % (len(stale_to_vault[arch]), arch))
+ uploads.move_to_vault(args, stale_to_vault[arch])
+ else:
+ return None
+
# read maintainer list
mlist = maintainers.Maintainer.read(args)
@@ -164,8 +178,31 @@ def process(args):
logging.error("error while validating merged %s packages for %s" % (arch, name))
valid = False
+ # if an error occurred ...
if not valid:
- # discard move list and merged_packages
+ # ... discard move list and merged_packages
+ continue
+
+ # check for packages which are stale as a result of this upload,
+ # which we will want in the same report
+ if args.stale:
+ stale_to_vault = remove_stale_packages(args, merged_packages)
+
+ # if an error occurred ...
+ if not stale_to_vault:
+ # ... discard move list and merged_packages
+ continue
+
+ # check for conflicting movelists
+ conflicts = False
+ for arch in common_constants.ARCHES + ['noarch']:
+ conflicts = conflicts or report_movelist_conflicts(scan_result[arch].to_relarea, scan_result[arch].to_vault, "manually")
+ if args.stale:
+ conflicts = conflicts or report_movelist_conflicts(scan_result[arch].to_relarea, stale_to_vault[arch], "automatically")
+
+ # if an error occurred ...
+ if conflicts:
+ # ... discard move list and merged_packages
continue
# for each arch and noarch
@@ -178,6 +215,13 @@ def process(args):
uploads.move_to_relarea(m, args, scan_result[arch].to_relarea)
# for each arch
+ if args.stale:
+ for arch in common_constants.ARCHES + ['noarch']:
+ if stale_to_vault[arch]:
+ logging.info("vaulting %d old files for arch %s, which are no longer accessible by installer" % (len(stale_to_vault[arch]), arch))
+ uploads.move_to_vault(args, stale_to_vault[arch])
+
+ # for each arch
for arch in common_constants.ARCHES:
# use merged package list
packages[arch] = merged_packages[arch]
@@ -190,6 +234,72 @@ def process(args):
#
+# remove stale packages
+#
+
+def remove_stale_packages(args, packages):
+ to_vault = {}
+ to_vault['noarch'] = defaultdict(list)
+
+ for arch in common_constants.ARCHES:
+ logging.debug("checking for stale packages for arch %s" % (arch))
+
+ # find stale packages
+ to_vault[arch] = package.stale_packages(packages[arch])
+
+ # remove stale packages from package set
+ for p in to_vault[arch]:
+ for f in to_vault[arch][p]:
+ package.delete(packages[arch], p, f)
+
+ # if there are no stale packages, we don't have anything to do
+ if not any([to_vault[a] for a in to_vault]):
+ logging.debug("nothing is stale")
+ return to_vault
+
+ # re-validate package sets
+ # (this shouldn't fail, but we check just to sure...)
+ error = False
+ for arch in common_constants.ARCHES:
+ if not package.validate_packages(args, packages[arch]):
+ logging.error("%s package set has errors after removing stale packages" % arch)
+ error = True
+
+ if error:
+ return None
+
+ # since noarch packages are included in the package set for both arch, we
+ # will build (hopefully) identical move lists for those packages for each
+ # arch.
+ #
+ # de-duplicate these package moves, as rather awkward workaround for that
+ for path in list(to_vault[common_constants.ARCHES[0]]):
+ if path.startswith('noarch'):
+ to_vault['noarch'][path] = to_vault[common_constants.ARCHES[0]][path]
+ for arch in common_constants.ARCHES:
+ del to_vault[arch][path]
+
+ return to_vault
+
+
+#
+# report movelist conflicts
+#
+
+def report_movelist_conflicts(a, b, reason):
+ conflicts = False
+
+ n = uploads.movelist_intersect(a, b)
+ if n:
+ for p in n:
+ for f in n[p]:
+ logging.error("%s/%s is both uploaded and %s vaulted" % (p, f, reason))
+ conflicts = True
+
+ return conflicts
+
+
+#
#
#
@@ -315,6 +425,8 @@ def main():
parser.add_argument('--release', action='store', help='value for setup-release key (default: cygwin)', default='cygwin')
parser.add_argument('--releasearea', action='store', metavar='DIR', help="release directory (default: " + relarea_default + ")", default=relarea_default, dest='rel_area')
parser.add_argument('--setupdir', action='store', metavar='DIR', help="setup executable directory (default: " + setupdir_default + ")", default=setupdir_default)
+ parser.add_argument('--no-stale', action='store_false', dest='stale', help="don't vault stale packages")
+ parser.set_defaults(stale=True)
parser.add_argument('-n', '--dry-run', action='store_true', dest='dryrun', help="don't do anything")
parser.add_argument('--vault', action='store', metavar='DIR', help="vault directory (default: " + vault_default + ")", default=vault_default, dest='vault')
parser.add_argument('-v', '--verbose', action='count', dest='verbose', help='verbose output')
diff --git a/calm/common_constants.py b/calm/common_constants.py
index de4bf46..b4ffd92 100644
--- a/calm/common_constants.py
+++ b/calm/common_constants.py
@@ -59,6 +59,10 @@ VAULT = '/sourceware/snapshot-tmp/cygwin'
# SMTP smarthost
MAILHOST = 'localhost'
+# defaults for package freshness
+DEFAULT_KEEP_COUNT = 0
+DEFAULT_KEEP_DAYS = 0
+
# different values to be used when we are not running on sourceware.org, but my
# test system...
if os.uname()[1] == 'tambora':
diff --git a/calm/package.py b/calm/package.py
index 27d6457..a5881e3 100755
--- a/calm/package.py
+++ b/calm/package.py
@@ -251,6 +251,7 @@ def read_package(packages, basedir, dirpath, files, strict=False):
tars[f] = Tar()
tars[f].size = os.path.getsize(os.path.join(dirpath, f))
tars[f].is_empty = tarfile_is_empty(os.path.join(dirpath, f))
+ tars[f].mtime = os.path.getmtime(os.path.join(dirpath, f))
if f in sha512:
tars[f].sha512 = sha512[f]
@@ -260,6 +261,7 @@ def read_package(packages, basedir, dirpath, files, strict=False):
# determine hints for each version we've encountered
version_hints = {}
+ hint_files = {}
for vr in vr_list:
hint_fn = '%s-%s.hint' % (p, vr)
if hint_fn in files:
@@ -269,6 +271,7 @@ def read_package(packages, basedir, dirpath, files, strict=False):
return True
warnings = clean_hints(p, pvr_hint, strict_lvl, warnings)
files.remove(hint_fn)
+ hint_files[vr] = hint_fn
elif legacy:
# otherwise, use setup.hint
pvr_hint = hints
@@ -293,6 +296,7 @@ def read_package(packages, basedir, dirpath, files, strict=False):
packages[p].version_hints = version_hints
packages[p].override_hints = override_hints
packages[p].tars = tars
+ packages[p].hint_files = hint_files
packages[p].path = relpath
packages[p].skip = any(['skip' in version_hints[vr] for vr in vr_list])
@@ -777,6 +781,9 @@ def merge(a, *l):
# overrides from b take precedence
c[p].override_hints.update(b[p].override_hints)
+ # merge hint file lists
+ c[p].hint_files.update(b[p].hint_files)
+
# skip if both a and b are skip
c[p].skip = a[p].skip and b[p].skip
@@ -827,6 +834,97 @@ def is_in_package_list(ppath, plist):
#
+# helper function to mark a package version as fresh (not stale)
+#
+
+def mark_package_fresh(packages, p, v):
+ if 'install' in packages[p].vermap[v]:
+ packages[p].tars[packages[p].vermap[v]['install']].fresh = True
+
+ if 'source' in packages[p].vermap[v]:
+ packages[p].tars[packages[p].vermap[v]['source']].fresh = True
+ return
+
+ # unless the install tarfile is empty ...
+ if packages[p].tars[packages[p].vermap[v]['install']].is_empty:
+ return
+
+ # ... mark any corresponding external-source package version as also fresh
+ if 'external-source' in packages[p].version_hints[v]:
+ es_p = packages[p].version_hints[v]['external-source']
+ if es_p in packages:
+ if 'source' in packages[es_p].vermap[v]:
+ packages[es_p].tars[packages[es_p].vermap[v]['source']].fresh = True
+
+
+#
+# construct a move list of stale packages
+#
+
+def stale_packages(packages):
+ for pn, po in packages.items():
+ # mark any versions used by stability levels as fresh
+ for level in ['curr', 'prev', 'test']:
+ if level in po.stability:
+ v = po.stability[level]
+ mark_package_fresh(packages, pn, v)
+
+ # mark any versions explicitly listed in the keep: override hint
+ for v in po.override_hints.get('keep', '').split():
+ mark_package_fresh(packages, pn, v)
+
+ # mark as fresh the highest n versions, where n is given by the
+ # keep-count: override hint, (defaulting to DEFAULT_KEEP_COUNT)
+ keep_count = po.override_hints.get('keep-count', common_constants.DEFAULT_KEEP_COUNT)
+ for v in sorted(po.vermap.keys(), key=lambda v: SetupVersion(v), reverse=True)[0:keep_count]:
+ mark_package_fresh(packages, pn, v)
+
+ # mark as fresh all versions after the first one which is newer than
+ # the keep-days: override hint, (defaulting to DEFAULT_KEEP_DAYS)
+ # (as opposed to checking the mtime for each version to determine if
+ # it is included)
+ keep_days = po.override_hints.get('keep-days', common_constants.DEFAULT_KEEP_DAYS)
+ newer = False
+ for v in sorted(po.vermap.keys(), key=lambda v: SetupVersion(v)):
+ if not newer:
+ if 'install' in po.vermap[v]:
+ if po.tars[po.vermap[v]['install']].mtime > (time.time() - (keep_days * 24 * 60 * 60)):
+ newer = True
+
+ if newer:
+ mark_package_fresh(packages, pn, v)
+
+ # build a move list of stale versions
+ stale = defaultdict(list)
+ for pn, po in packages.items():
+ for v in sorted(po.vermap.keys(), key=lambda v: SetupVersion(v)):
+ all_stale = True
+ for category in ['source', 'install']:
+ if category in po.vermap[v]:
+ if not getattr(po.tars[po.vermap[v][category]], 'fresh', False):
+ stale[po.path].append(po.vermap[v][category])
+ logging.debug("package '%s' version '%s' %s is stale" % (pn, v, category))
+ else:
+ all_stale = False
+
+ # if there's a pvr.hint without a fresh source or install of the
+ # same version, move it as well
+ if all_stale:
+ if v in po.hint_files:
+ stale[po.path].append(po.hint_files[v])
+ logging.debug("package '%s' version '%s' hint is stale" % (pn, v))
+
+ # clean up freshness mark
+ for v in po.vermap:
+ for c in po.vermap[v]:
+ try:
+ delattr(po.tars[po.vermap[v][c]], 'fresh')
+ except AttributeError:
+ pass
+
+ return stale
+
+#
#
#
if __name__ == "__main__":
diff --git a/calm/uploads.py b/calm/uploads.py
index 8364ff0..9d44bfe 100644
--- a/calm/uploads.py
+++ b/calm/uploads.py
@@ -267,6 +267,16 @@ def move_to_vault(args, movelist):
move(args, movelist, args.rel_area, args.vault)
+# compute the intersection of a pair of movelists
+def movelist_intersect(a, b):
+ i = defaultdict(list)
+ for p in a.keys() & b.keys():
+ pi = set(a[p]) & set(b[p])
+ if pi:
+ i[p] = pi
+ return i
+
+
#
#
#
diff --git a/test/test_calm.py b/test/test_calm.py
index 7cbe9f2..2c29719 100755
--- a/test/test_calm.py
+++ b/test/test_calm.py
@@ -251,6 +251,7 @@ class CalmTest(unittest.TestCase):
setattr(args, 'pkglist', 'testdata/pkglist/cygwin-pkg-maint')
setattr(args, 'release', 'trial')
setattr(args, 'setup_version', '3.1415')
+ setattr(args, 'stale', True)
shutil.copytree('testdata/relarea', getattr(args, 'rel_area'))
shutil.copytree('testdata/homes', getattr(args, 'homedir'))
diff --git a/test/testdata/hints/x86/release/staleversion/expected b/test/testdata/hints/x86/release/staleversion/expected
new file mode 100644
index 0000000..f7cc4fd
--- /dev/null
+++ b/test/testdata/hints/x86/release/staleversion/expected
@@ -0,0 +1,4 @@
+{'sdesc': '"Test package for stale version removal"',
+ 'ldesc': '"Test package for stale version removal"',
+ 'category': 'Shells Base',
+ 'requires': ''}
diff --git a/test/testdata/homes/Blooey McFooey/x86/release/per-version/override.hint b/test/testdata/homes/Blooey McFooey/x86/release/per-version/override.hint
new file mode 100644
index 0000000..aeb41e4
--- /dev/null
+++ b/test/testdata/homes/Blooey McFooey/x86/release/per-version/override.hint
@@ -0,0 +1,2 @@
+curr: 4.8-1
+test: 5.0-1
diff --git a/test/testdata/htdocs.expected/x86/packages.inc b/test/testdata/htdocs.expected/x86/packages.inc
index cfb3c5f..6fecc3d 100755
--- a/test/testdata/htdocs.expected/x86/packages.inc
+++ b/test/testdata/htdocs.expected/x86/packages.inc
@@ -20,6 +20,7 @@
<tr><td><a href="x86/per-version">per-version</a></td><td>Per-version hint test package</td></tr>
<tr><td><a href="x86/perl-Net-SMTP-SSL">perl-Net-SMTP-SSL</a></td><td>Perl distribution Net-SMTP-SSL</td></tr>
<tr><td><a href="x86/rpm-doc">rpm-doc</a></td><td>Obsolete package for RPM package management system manual pages</td></tr>
+<tr><td><a href="x86/staleversion">staleversion</a></td><td>Test package for stale version removal</td></tr>
<tr><td><a href="x86/testpackage">testpackage</a></td><td>A test package</td></tr>
</table>
</div>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/.htaccess b/test/testdata/htdocs.expected/x86/staleversion/.htaccess
new file mode 100644
index 0000000..3196d64
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/.htaccess
@@ -0,0 +1,3 @@
+Options Indexes
+IndexOptions -FancyIndexing
+AddType text/html 1 2 3 4 5 6 7 8 9
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-240-1 b/test/testdata/htdocs.expected/x86/staleversion/staleversion-240-1
new file mode 100644
index 0000000..75c36c3
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-240-1
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (installed binaries and support files)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-240-1-src b/test/testdata/htdocs.expected/x86/staleversion/staleversion-240-1-src
new file mode 100644
index 0000000..da129ec
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-240-1-src
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (source code)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-242-0 b/test/testdata/htdocs.expected/x86/staleversion/staleversion-242-0
new file mode 100644
index 0000000..75c36c3
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-242-0
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (installed binaries and support files)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-242-0-src b/test/testdata/htdocs.expected/x86/staleversion/staleversion-242-0-src
new file mode 100644
index 0000000..da129ec
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-242-0-src
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (source code)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-243-0 b/test/testdata/htdocs.expected/x86/staleversion/staleversion-243-0
new file mode 100644
index 0000000..75c36c3
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-243-0
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (installed binaries and support files)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-243-0-src b/test/testdata/htdocs.expected/x86/staleversion/staleversion-243-0-src
new file mode 100644
index 0000000..da129ec
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-243-0-src
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (source code)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-250-0 b/test/testdata/htdocs.expected/x86/staleversion/staleversion-250-0
new file mode 100644
index 0000000..75c36c3
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-250-0
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (installed binaries and support files)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-250-0-src b/test/testdata/htdocs.expected/x86/staleversion/staleversion-250-0-src
new file mode 100644
index 0000000..da129ec
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-250-0-src
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (source code)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-251-0 b/test/testdata/htdocs.expected/x86/staleversion/staleversion-251-0
new file mode 100644
index 0000000..75c36c3
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-251-0
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (installed binaries and support files)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-251-0-src b/test/testdata/htdocs.expected/x86/staleversion/staleversion-251-0-src
new file mode 100644
index 0000000..da129ec
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-251-0-src
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (source code)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-260-0 b/test/testdata/htdocs.expected/x86/staleversion/staleversion-260-0
new file mode 100644
index 0000000..75c36c3
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-260-0
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (installed binaries and support files)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/htdocs.expected/x86/staleversion/staleversion-260-0-src b/test/testdata/htdocs.expected/x86/staleversion/staleversion-260-0-src
new file mode 100644
index 0000000..da129ec
--- /dev/null
+++ b/test/testdata/htdocs.expected/x86/staleversion/staleversion-260-0-src
@@ -0,0 +1,7 @@
+<html>
+<h1>staleversion: Test package for stale version removal (source code)</h1>
+<tt><pre>
+ 2015-10-11 14:45 26 test/test.1
+ 2015-10-11 14:45 31 test/test.2
+</pre></tt>
+</html>
diff --git a/test/testdata/inifile/setup.ini.expected b/test/testdata/inifile/setup.ini.expected
index 2ef3c93..22bab0f 100644
--- a/test/testdata/inifile/setup.ini.expected
+++ b/test/testdata/inifile/setup.ini.expected
@@ -233,6 +233,28 @@
'source: x86/release/rpm-doc/rpm-doc-4.1-2-src.tar.bz2 42 '
'28c70b843fe01d90a3eeab4a3617551d236cd0b7d69668d1b1b6c8b14a9fd050e4039c192894c93bdf31575771c58c1fea2a41c24c8da22d10080d8b032b6369\n'
'\n'
+ '@ staleversion\n'
+ 'sdesc: "Test package for stale version removal"\n'
+ 'ldesc: "Test package for stale version removal"\n'
+ 'category: Shells Base\n'
+ 'version: 250-0\n'
+ 'install: x86/release/staleversion/staleversion-250-0.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ 'source: x86/release/staleversion/staleversion-250-0-src.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ '[prev]\n'
+ 'version: 243-0\n'
+ 'install: x86/release/staleversion/staleversion-243-0.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ 'source: x86/release/staleversion/staleversion-243-0-src.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ '[test]\n'
+ 'version: 260-0\n'
+ 'install: x86/release/staleversion/staleversion-260-0.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ 'source: x86/release/staleversion/staleversion-260-0-src.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ '\n'
'@ testpackage\n'
'sdesc: "A test package"\n'
'ldesc: "A test package"\n'
diff --git a/test/testdata/pkglist/cygwin-pkg-maint b/test/testdata/pkglist/cygwin-pkg-maint
index 9557e0a..6067d55 100644
--- a/test/testdata/pkglist/cygwin-pkg-maint
+++ b/test/testdata/pkglist/cygwin-pkg-maint
@@ -2118,6 +2118,7 @@ sqlite3 Jan Nijtmans
squid Dr. Volker Zell
ssh-pageant Michael Wild
ssmtp Corinna Vinschen
+staleversion Blooey McFooey
startup-notification Yaakov Selkowitz
steghide Jari Aalto
step Yaakov Selkowitz
diff --git a/test/testdata/pkglist/expected b/test/testdata/pkglist/expected
index 3a5ea77..0610a6c 100644
--- a/test/testdata/pkglist/expected
+++ b/test/testdata/pkglist/expected
@@ -3,7 +3,7 @@
'Adam Dinwoodie': maintainers.Maintainer('Adam Dinwoodie', [], ['git']),
'Alexey Sokolov': maintainers.Maintainer('Alexey Sokolov', [], ['znc']),
'Andrew Schulman': maintainers.Maintainer('Andrew Schulman', [], ['atool', 'autossh', 'bc', 'discus', 'fish', 'lftp', 'libargp', 'nosleep', 'orpie', 'pinfo', 'ploticus', 'ploticus-doc', 'screen', 'sitecopy', 'sng', 'socat', 'stow', 'stunnel', 'time', 'unison2.27', 'unison2.32', 'unison2.40', 'unison2.45', 'unison2.48']),
- 'Blooey McFooey': maintainers.Maintainer('Blooey McFooey', [], ['corrupt', 'perl-Net-SMTP-SSL', 'per-version', 'per-version-incomplete', 'testpackage']),
+ 'Blooey McFooey': maintainers.Maintainer('Blooey McFooey', [], ['corrupt', 'perl-Net-SMTP-SSL', 'per-version', 'per-version-incomplete', 'staleversion', 'testpackage']),
'Bob Heckel': maintainers.Maintainer('Bob Heckel', [], ['libgc', 'w3m']),
'Charles Wilson': maintainers.Maintainer('Charles Wilson', [], ['alternatives', 'autobuild', 'cygutils', 'gcc-tools-epoch1-autoconf', 'gcc-tools-epoch1-automake', 'gcc-tools-epoch2-autoconf', 'gcc-tools-epoch2-automake', 'inetutils', 'libassuan', 'libksba', 'libustr', 'libXpm-noX', 'mingw-binutils', 'mingw-bzip2', 'mingw-gcc', 'mingw-libgcrypt', 'mingw-libgpg-error', 'mingw-pthreads', 'mingw-xz', 'mingw-zlib', 'nfrotz', 'pinentry', 'pth', 'rsh', 'run2', 'rxvt', 'sunrpc', 'tcp_wrappers', 'xsri']),
'Chris J. Breisch': maintainers.Maintainer('Chris J. Breisch', [], ['man-db']),
diff --git a/test/testdata/process_arch/htdocs.expected b/test/testdata/process_arch/htdocs.expected
index 4e5e9e2..3dd3b28 100644
--- a/test/testdata/process_arch/htdocs.expected
+++ b/test/testdata/process_arch/htdocs.expected
@@ -33,5 +33,12 @@
'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/testpackage': ['.htaccess', 'testpackage-1.0-1', 'testpackage-1.0-1-src'],
'x86/testpackage-subpackage': ['.htaccess', 'testpackage-subpackage-1.0-1']}
diff --git a/test/testdata/process_arch/rel_area.expected b/test/testdata/process_arch/rel_area.expected
index ae4e2d7..67d9b4c 100644
--- a/test/testdata/process_arch/rel_area.expected
+++ b/test/testdata/process_arch/rel_area.expected
@@ -80,5 +80,14 @@
'setup.hint',
'sha512.sum'],
'x86/release/splint': ['setup.hint', 'sha512.sum'],
+ 'x86/release/staleversion': ['override.hint',
+ 'setup.hint',
+ 'sha512.sum',
+ 'staleversion-243-0-src.tar.xz',
+ 'staleversion-243-0.tar.xz',
+ 'staleversion-250-0-src.tar.xz',
+ 'staleversion-250-0.tar.xz',
+ 'staleversion-260-0-src.tar.xz',
+ 'staleversion-260-0.tar.xz'],
'x86/release/testpackage': ['setup.hint', 'sha512.sum', 'testpackage-1.0-1-src.tar.bz2', 'testpackage-1.0-1.tar.bz2'],
'x86/release/testpackage/testpackage-subpackage': ['setup.hint', 'testpackage-subpackage-1.0-1.tar.bz2']}
diff --git a/test/testdata/process_arch/setup.ini.expected b/test/testdata/process_arch/setup.ini.expected
index 7de15aa..de165ea 100644
--- a/test/testdata/process_arch/setup.ini.expected
+++ b/test/testdata/process_arch/setup.ini.expected
@@ -208,6 +208,12 @@
'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
'source: x86/release/per-version/per-version-4.0-1-src.tar.xz 228 '
'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ '[test]\n'
+ 'version: 5.0-1\n'
+ 'install: x86/release/per-version/per-version-5.0-1.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ 'source: x86/release/per-version/per-version-5.0-1-src.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
'\n'
'@ perl-Net-SMTP-SSL\n'
'sdesc: "Perl distribution Net-SMTP-SSL"\n'
@@ -239,6 +245,28 @@
'source: x86/release/rpm-doc/rpm-doc-4.1-2-src.tar.bz2 42 '
'28c70b843fe01d90a3eeab4a3617551d236cd0b7d69668d1b1b6c8b14a9fd050e4039c192894c93bdf31575771c58c1fea2a41c24c8da22d10080d8b032b6369\n'
'\n'
+ '@ staleversion\n'
+ 'sdesc: "Test package for stale version removal"\n'
+ 'ldesc: "Test package for stale version removal"\n'
+ 'category: Shells Base\n'
+ 'version: 250-0\n'
+ 'install: x86/release/staleversion/staleversion-250-0.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ 'source: x86/release/staleversion/staleversion-250-0-src.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ '[prev]\n'
+ 'version: 243-0\n'
+ 'install: x86/release/staleversion/staleversion-243-0.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ 'source: x86/release/staleversion/staleversion-243-0-src.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ '[test]\n'
+ 'version: 260-0\n'
+ 'install: x86/release/staleversion/staleversion-260-0.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ 'source: x86/release/staleversion/staleversion-260-0-src.tar.xz 228 '
+ 'e675b0ac4bc2c3e1c4971bc56d77b0cd53a9bdf5632873a235d7582e29dfd3e8a7bb04b28f6cdee3e6b3d14c25ed39392538e3f628a9bfda6c905646ebc3c225\n'
+ '\n'
'@ testpackage\n'
'sdesc: "A test package"\n'
'ldesc: "A test package\n'
diff --git a/test/testdata/process_arch/vault.expected b/test/testdata/process_arch/vault.expected
index a87938b..cf4e9f0 100644
--- a/test/testdata/process_arch/vault.expected
+++ b/test/testdata/process_arch/vault.expected
@@ -1 +1,10 @@
-{'.': [], 'x86': [], 'x86/release': [], 'x86/release/testpackage': ['testpackage-0.1-1.tar.bz2']}
+{'.': [],
+ 'x86': [],
+ 'x86/release': [],
+ 'x86/release/staleversion': ['staleversion-240-1-src.tar.xz',
+ 'staleversion-240-1.tar.xz',
+ 'staleversion-242-0-src.tar.xz',
+ 'staleversion-242-0.tar.xz',
+ 'staleversion-251-0-src.tar.xz',
+ 'staleversion-251-0.tar.xz'],
+ 'x86/release/testpackage': ['testpackage-0.1-1.tar.bz2']}
diff --git a/test/testdata/relarea/x86/release/staleversion/override.hint b/test/testdata/relarea/x86/release/staleversion/override.hint
new file mode 100644
index 0000000..2c59b48
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/override.hint
@@ -0,0 +1,3 @@
+test: 260-0
+curr: 250-0
+prev: 243-0
diff --git a/test/testdata/relarea/x86/release/staleversion/setup.hint b/test/testdata/relarea/x86/release/staleversion/setup.hint
new file mode 100644
index 0000000..7f7f48a
--- /dev/null
+++ b/test/testdata/relarea/x86/release/staleversion/setup.hint
@@ -0,0 +1,4 @@
+sdesc: "Test package for stale version removal"
+ldesc: "Test package for stale version removal"
+category: Shells Base
+requires:
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-240-1-src.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-240-1-src.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-240-1-src.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-240-1.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-240-1.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-240-1.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-242-0-src.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-242-0-src.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-242-0-src.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-242-0.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-242-0.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-242-0.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-243-0-src.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-243-0-src.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-243-0-src.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-243-0.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-243-0.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-243-0.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-250-0-src.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-250-0-src.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-250-0-src.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-250-0.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-250-0.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-250-0.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-251-0-src.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-251-0-src.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-251-0-src.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-251-0.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-251-0.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-251-0.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-260-0-src.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-260-0-src.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-260-0-src.tar.xz differ
diff --git a/test/testdata/relarea/x86/release/staleversion/staleversion-260-0.tar.xz b/test/testdata/relarea/x86/release/staleversion/staleversion-260-0.tar.xz
new file mode 100644
index 0000000..0e6f1e8
Binary files /dev/null and b/test/testdata/relarea/x86/release/staleversion/staleversion-260-0.tar.xz differ