[calm - Cygwin server-side packaging maintenance script] branch master, updated. 20250329-66-gc44d33c
Jon Turney via Cygwin-apps-cvs <[email protected]> Mon, 15 Jun 2026 13:15:53 +0000 (GMT)
| Newsgroups | gmane.os.cygwin.cvs.apps |
|---|---|
| Message-ID | <[email protected]> |
Diff:
---
calm/calm.py | 4 +-
calm/mksetupini.py | 4 +-
calm/package.py | 274 ++++++++++++++++------------
calm/pkg2html.py | 27 +--
calm/reports.py | 14 +-
calm/setup_exe.py | 2 +-
calm/spelling.py | 5 +-
test/testdata/mksetupini/setup.ini.expected | 2 +
test/testdata/uploads/pkglist.expected | 72 ++++----
9 files changed, 222 insertions(+), 182 deletions(-)
diff --git a/calm/calm.py b/calm/calm.py
index 6b9218b..9cd9d3f 100755
--- a/calm/calm.py
+++ b/calm/calm.py
@@ -219,8 +219,8 @@ def _announce_upload(args, scan_result, maintainer, r):
srcpkg = po
assert len(po.versions()) == 1
version = list(po.versions())[0]
- ldesc = po.version_hints[version]['ldesc'].strip('"')
- test = 'test' in po.version_hints[version]
+ ldesc = po.hints(version)['ldesc'].strip('"')
+ test = 'test' in po.hints(version)
# not totally clear how we should name source packages, so omit them for
# the moment
diff --git a/calm/mksetupini.py b/calm/mksetupini.py
index 8b9888d..2018be4 100755
--- a/calm/mksetupini.py
+++ b/calm/mksetupini.py
@@ -89,8 +89,8 @@ def stats(packages):
histogram[c.lower()] = 0
for p in packages.values():
- if 'category' in p.hints:
- for c in p.hints['category'].split():
+ if 'category' in p.hints(p.bv):
+ for c in p.hints(p.bv)['category'].split():
histogram.setdefault(c.lower(), 0)
histogram[c.lower()] += 1
diff --git a/calm/package.py b/calm/package.py
index 120f25a..df10c6a 100755
--- a/calm/package.py
+++ b/calm/package.py
@@ -26,7 +26,6 @@
#
import copy
-import difflib
import hashlib
import json
import logging
@@ -97,10 +96,9 @@ class RepoPath():
# information we keep about a package
class Package(object):
def __init__(self):
- self.tarfiles = {}
- self.hints = {}
+ self._tarfiles = {}
+ self._hints = {}
self.is_used_by = set()
- self.version_hints = {}
self.override_hints = {}
self.not_for_output = False
self.auth_path = set()
@@ -108,16 +106,31 @@ class Package(object):
def __repr__(self):
return "Package('%s', %s, %s, %s, %s)" % (
self.name,
- pprint.pformat(self.tarfiles),
- pprint.pformat(self.version_hints),
+ pprint.pformat(self._tarfiles),
+ pprint.pformat(self._hints),
pprint.pformat(self.override_hints),
self.not_for_output)
+ # accesses all data for an edition of the package
+ def edition(self, vr):
+ return (self._tarfiles[vr], self._hints[vr].hints)
+
+ # access the tar archive
def tar(self, vr):
- return self.tarfiles[vr]
+ return self._tarfiles[vr]
+
+ # access the hints
+ def hints(self, vr):
+ return self._hints[vr].hints
+ # access the hint object
+ def hint_data(self, vr):
+ return self._hints[vr]
+
+ # iterate over editions of the package
+ # XXX: also need a filtered-by arch version of this
def versions(self):
- return self.tarfiles.keys()
+ return self._tarfiles.keys()
def srcpackage(self, vr, suffix=True):
if self.kind == Kind.source:
@@ -125,8 +138,10 @@ class Package(object):
else:
# source tarfile is in the external-source package, if specified,
# otherwise it's in the sibling source package
- hints = self.version_hints.get(vr, {})
- spn = hints.get('external-source', self.name + '-src')
+ spn = self.name + '-src'
+ hints = self._hints.get(vr, None)
+ if hints:
+ spn = hints.hints.get('external-source', spn)
# strip '-src' suffix?
if not suffix:
@@ -153,7 +168,11 @@ class Tar(object):
class Hint(object):
def __init__(self):
self.repopath = RepoPath() # pathname of hint file
- self.hints = {} # XXX: duplicates version_hints, for the moment
+ self.mtime = 0 # mtime of hint file
+ self.hints = {}
+
+ def __repr__(self):
+ return "Hint('%s', %s)" % (self.repopath.fn, pprint.pformat(self.hints))
#
@@ -408,6 +427,7 @@ def collect_files_package_dir(collected, basedir, dirpath, files):
#
def read_one_package(packages, p, basedir, files, kind, strict):
warnings = False
+ error = False
if not re.match(r'^[\w\-._+]*$', p):
logging.error("package '%s' name contains illegal characters" % p)
@@ -480,7 +500,8 @@ def read_one_package(packages, p, basedir, files, kind, strict):
match = re.match(r'^' + re.escape(p) + r'-(.+)-(\d[0-9a-zA-Z._+]*)' + arch_re + r'\.(tar' + common_constants.PACKAGE_COMPRESSIONS_RE + r'|hint)$', f)
if not match:
logging.error("file '%s' in package '%s' doesn't follow naming convention" % (rp.fn, p))
- return True
+ error = True
+ continue
else:
v = match.group(1)
r = match.group(2)
@@ -517,18 +538,21 @@ def read_one_package(packages, p, basedir, files, kind, strict):
if not re.search(r'-src.*\.tar', f):
if kind == Kind.source:
logging.error("source package '%s' has install archives" % (p))
- return True
+ error = True
+ continue
else:
if kind == Kind.binary:
logging.error("package '%s' has source archives" % (p))
- return True
+ error = True
+ continue
# for each version, a package can contain at most one tar file (of
# the appropriate type). Warn if we have too many (for e.g. both a
# .xz and .bz2 install tar file).
if vr in tars:
logging.error("package '%s' has more than one tar file for version '%s'" % (p, vr))
- return True
+ error = True
+ continue
# collect the attributes for each tar file
t = Tar()
@@ -551,7 +575,8 @@ def read_one_package(packages, p, basedir, files, kind, strict):
hrp = RepoPath(rp.arch, rp.path, hint_fn)
if hrp not in files:
logging.error("package %s has packages for version %s, but no %s" % (p, vr, hint_fn))
- return True
+ error = True
+ continue
else:
# for each version, a package can contain at most one hint
@@ -559,15 +584,18 @@ def read_one_package(packages, p, basedir, files, kind, strict):
# archtag).
if vr in hint_files:
logging.error("package '%s' has more than one hint file for version '%s'" % (p, vr))
- return True
+ error = True
+ continue
hint_files[vr] = rp
# collect the superpackage names for authorization purposes
auth_path.add(rp.path.split(os.sep, 1)[0])
+ if error:
+ return True
+
# determine hints for each version we've encountered
- version_hints = {}
- hints = {}
+ actual_hints = {}
actual_tars = {}
for vr in vr_list:
rp = hint_files[vr]
@@ -576,7 +604,9 @@ def read_one_package(packages, p, basedir, files, kind, strict):
pvr_hint = read_hints(p, rp.abspath(basedir), hint.pvr if kind == Kind.binary else hint.spvr, strict)
if not pvr_hint:
logging.error("error parsing %s" % (rp.fn))
- return True
+ error = True
+ continue
+
warnings = clean_hints(p, pvr_hint, warnings)
# apply a version override
@@ -601,17 +631,19 @@ def read_one_package(packages, p, basedir, files, kind, strict):
hintobj.hints = pvr_hint
hintobj.mtime = os.path.getmtime(rp.abspath(basedir))
- version_hints[ovr] = pvr_hint
- hints[ovr] = hintobj
+ actual_hints[ovr] = hintobj
if vr in tars:
actual_tars[ovr] = tars[vr]
+ if error:
+ return True
+
+ # XXX: assert actual_tars.keys() == actual_hints.keys()
packages[pn] = Package()
packages[pn].name = pn
- packages[pn].version_hints = version_hints
packages[pn].override_hints = override_hints
- packages[pn].tarfiles = actual_tars
- packages[pn].hints = hints
+ packages[pn]._tarfiles = actual_tars
+ packages[pn]._hints = actual_hints
packages[pn].auth_path = auth_path
packages[pn].kind = kind
# since we are kind of inventing the source package names, and don't
@@ -681,6 +713,8 @@ def upgrade_oldstyle_obsoletes(packages, missing_obsolete):
for p in sorted(packages):
if packages[p].kind == Kind.binary:
for vr in sorted(packages[p].versions(), key=lambda v: SetupVersion(v), reverse=True):
+ (tar, hints) = packages[p].edition(vr)
+
# we only really want to consider packages where the current
# version is obsolete.
#
@@ -690,11 +724,10 @@ def upgrade_oldstyle_obsoletes(packages, missing_obsolete):
#
# as a proxy for that, stop considering versions of this package
# when one isn't obsolete, don't consider older versions
- if not (packages[p].tar(vr).is_empty and
- '_obsolete' in packages[p].version_hints[vr]['category']):
+ if not (tar.is_empty and '_obsolete' in hints['category']):
break
- requires = packages[p].version_hints[vr].get('depends', [])
+ requires = hints.get('depends', [])
requires = deplist_without_versions(requires)
o = None
@@ -712,7 +745,7 @@ def upgrade_oldstyle_obsoletes(packages, missing_obsolete):
else:
# ignore self-destruct packages
- provides = packages[p].version_hints[vr].get('provides', [])
+ provides = hints.get('provides', [])
if '_self-destruct' in provides:
continue
@@ -767,7 +800,8 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
for p in packages:
valid_requires.add(p)
- for hints in packages[p].version_hints.values():
+ for vr in packages[p].versions():
+ hints = packages[p].hints(vr)
valid_requires.update(hints.get('obsoletes', []))
valid_requires.update(hints.get('provides', []))
@@ -791,7 +825,8 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# perform various package validations
for p in sorted(packages.keys()):
- for (v, hints) in packages[p].version_hints.items():
+ for v in packages[p].versions():
+ hints = packages[p].hints(v)
for (c, okmissing, valid, nonexistent) in [
('depends', 'missing-depended-package', valid_requires, past_mistakes.nonexistent_provides),
('obsoletes', 'missing-obsoleted-package', valid_obsoletes, []),
@@ -839,15 +874,16 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
for mo in [past_mistakes.missing_obsolete, missing_obsolete_extra]:
for p in mo:
if p in packages:
- for v in packages[p].version_hints:
+ for v in packages[p].versions():
+ hints = packages[p].hints(v)
- obsoletes = packages[p].version_hints[v].get('obsoletes', [])
+ obsoletes = hints.get('obsoletes', [])
def add_needed_obsoletes(needed):
for n in sorted(needed):
if n not in obsoletes:
obsoletes.append(n)
- packages[p].version_hints[v]['obsoletes'] = obsoletes
+ hints['obsoletes'] = obsoletes
logging.info("added 'obsoletes: %s' to package '%s' version '%s'" % (n, p, v))
logging.info("this should be in fixed in the cygport packaging")
@@ -866,19 +902,21 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# occur since we might have synthesized the depends: from the requires:
# in read_hints(), so fix that up here.
for p in sorted(packages):
- for hints in packages[p].version_hints.values():
+ for v in packages[p].versions():
+ hints = packages[p].hints(v)
obsoletes = hints.get('obsoletes', [])
if obsoletes:
for o in deplist_without_versions(obsoletes):
if o in packages:
packages[o].obsolete = True
- for (ov, ohints) in packages[o].version_hints.items():
+ for ov in packages[o].versions():
+ ohints = packages[o].hints(ov)
if 'depends' in ohints:
depends = ohints['depends']
if p in depends:
depends = [d for d in depends if d != p]
- packages[o].version_hints[ov]['depends'] = depends
+ ohints['depends'] = depends
logging.debug("removed obsoleting '%s' from the depends: of package '%s'" % (p, o))
else:
logging.debug("can't ensure package '%s' doesn't depends: on obsoleting '%s'" % (o, p))
@@ -890,7 +928,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
if not packages[p].tar(vr).is_empty:
has_nonempty_install = True
- obsolete = any(['_obsolete' in packages[p].version_hints[vr].get('category', '') for vr in packages[p].version_hints])
+ obsolete = any(['_obsolete' in packages[p].hints(vr).get('category', '') for vr in packages[p].versions()])
# if the package has no non-empty install tarfiles, and no dependencies
# installing it will do nothing (and making it appear in the package
@@ -907,7 +945,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# identify a 'best' version to take certain information from: this is
# the curr version, if we have one, otherwise, the highest version.
for v in sorted(packages[p].versions(), key=lambda v: SetupVersion(v), reverse=True):
- if 'test' not in packages[p].version_hints[v]:
+ if 'test' not in packages[p].hints(v):
packages[p].best_version = v
break
else:
@@ -925,12 +963,12 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
mtimes[vr] = packages[p].tar(vr).mtime
cv = None
- nontest_versions = [v for v in sorted(packages[p].versions(), key=lambda v: SetupVersion(v), reverse=True) if 'test' not in packages[p].version_hints.get(v, {})]
+ nontest_versions = [v for v in sorted(packages[p].versions(), key=lambda v: SetupVersion(v), reverse=True) if 'test' not in packages[p].hints(v)]
if len(nontest_versions) >= 1:
cv = nontest_versions[0]
for v in sorted(packages[p].versions(), key=lambda v: mtimes[v], reverse=True):
- if 'test' in packages[p].version_hints[v]:
+ if 'test' in packages[p].hints(v):
continue
if cv not in packages[p].versions():
@@ -962,8 +1000,8 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# warn if replace-versions lists a version which is also
# available to install (as this doesn't work as expected)
- if rv in packages[p].version_hints:
- if ('test' in packages[p].version_hints[rv]) == ('test' in packages[p].version_hints[bv]):
+ if rv in packages[p].versions():
+ if ('test' in packages[p].hints(rv)) == ('test' in packages[p].hints(bv)):
logging.warning("package '%s' replace-versions: lists version '%s', which is also available to install" % (p, rv))
# If the install tarball is empty, we should probably either be marked
@@ -973,7 +1011,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
if packages[p].tar(vr).is_empty:
# this classification relies on obsoleting packages
# not being present in depends
- if packages[p].version_hints[vr].get('depends', []):
+ if packages[p].hints(vr).get('depends', []):
# also allow '_obsolete' because old obsoletion
# packages depend on their replacement, but are not
# obsoleted by it
@@ -981,9 +1019,9 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
else:
expected_categories = ['_obsolete']
- if all(c not in packages[p].version_hints[vr].get('category', '').lower() for c in expected_categories):
+ if all(c not in packages[p].hints(vr).get('category', '').lower() for c in expected_categories):
if ((vr in past_mistakes.empty_but_not_obsolete.get(p, [])) or
- ('empty-obsolete' in packages[p].version_hints[vr].get('disable-check', ''))):
+ ('empty-obsolete' in packages[p].hints(vr).get('disable-check', ''))):
lvl = logging.DEBUG
else:
lvl = logging.ERROR
@@ -994,7 +1032,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
for vr in packages[p].versions():
if packages[p].tar(vr).is_empty:
if ((vr in past_mistakes.empty_source.get(p, [])) and
- '_obsolete' in packages[p].version_hints[vr].get('category', '')):
+ '_obsolete' in packages[p].hints(vr).get('category', '')):
lvl = logging.DEBUG
else:
error = True
@@ -1006,7 +1044,8 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# the set of packages which build-depends: on it (build_rdepends), and
# the set of packages which obsoletes: it (obsoleted_by)
for p in packages:
- for hints in packages[p].version_hints.values():
+ for vr in packages[p].versions():
+ hints = packages[p].hints(vr)
for k, a in [
('depends', 'rdepends'),
('build-depends', 'build_rdepends'),
@@ -1049,7 +1088,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# (this is needed if we are going to compare best_version
# between install and source packages for some information,
# as we do in some places...)
- if ('test' in packages[p].version_hints[v]) != ('test' in packages[es_p].version_hints[v]):
+ if ('test' in packages[p].hints(v)) != ('test' in packages[es_p].hints(v)):
logging.error("package '%s' version '%s' test: label mismatches source package '%s'" % (p, v, es_p))
if missing_source:
@@ -1079,7 +1118,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
if packages[p].tar(v).is_empty:
continue
- if '_obsolete' in packages[p].version_hints[v].get('category', ''):
+ if '_obsolete' in packages[p].hints(v).get('category', ''):
continue
if not packages[p].tar(v).is_used:
@@ -1099,7 +1138,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# ignore obsolete packages
if packages[install_p].obsolete:
continue
- if any(['_obsolete' in packages[install_p].version_hints[vr].get('category', '') for vr in packages[install_p].version_hints]):
+ if any(['_obsolete' in packages[install_p].hints(vr).get('category', '') for vr in packages[install_p].versions()]):
continue
# ignore runtime library packages, as we may keep old versions of
@@ -1115,7 +1154,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# ignore packages where best_version is a test version (i.e doesn't
# have a current version, is test only), since the check we are
# doing here is 'same current version'
- if 'test' not in packages[install_p].version_hints[packages[install_p].best_version]:
+ if 'test' not in packages[install_p].hints(packages[install_p].best_version):
continue
# ignore packages which have a different external-source:
@@ -1126,7 +1165,7 @@ def validate_packages(args, packages, valid_provides_extra=None, missing_obsolet
# ignore specific packages we disable this check for
if ((install_p in past_mistakes.nonunique_versions) or
- ('unique-version' in packages[install_p].version_hints[packages[install_p].best_version].get('disable-check', ''))):
+ ('unique-version' in packages[install_p].hints(packages[install_p].best_version).get('disable-check', ''))):
continue
versions[packages[install_p].best_version].append(install_p)
@@ -1165,14 +1204,14 @@ def assign_importance(packages):
# package the normal importance
for po in packages.values():
bv = po.best_version
- es = po.version_hints[bv].get('external-source', None)
+ es = po.hints(bv).get('external-source', None)
if po.build_rdepends or any(packages[p].srcpackage(packages[p].best_version) != es for p in po.rdepends):
po.importance = Importance.normal
# recursively give dependencies of base packages the basedep importance
def recursive_basedep(p):
bv = p.best_version
- requires = p.version_hints[bv].get('depends', [])
+ requires = p.hints(bv).get('depends', [])
requires = deplist_without_versions(requires)
for r in requires:
if r in packages:
@@ -1182,14 +1221,14 @@ def assign_importance(packages):
for po in packages.values():
bv = po.best_version
- categories = po.version_hints[bv]['category'].lower().split()
+ categories = po.hints(bv)['category'].lower().split()
if 'base' in categories:
recursive_basedep(po)
# base packages have base importance
for po in packages.values():
bv = po.best_version
- categories = po.version_hints[bv]['category'].lower().split()
+ categories = po.hints(bv)['category'].lower().split()
if 'base' in categories:
po.importance = Importance.base
@@ -1217,7 +1256,7 @@ def validate_package_maintainers(args, packages):
# ignore obsolete packages
if packages[p].obsolete:
continue
- if any(['_obsolete' in packages[p].version_hints[vr].get('category', '') for vr in packages[p].version_hints]):
+ if any(['_obsolete' in packages[p].hints(vr).get('category', '') for vr in packages[p].versions()]):
continue
# source which is superseded by a different package, but retained due to
# old install versions can be unmaintained and non-obsolete
@@ -1254,11 +1293,11 @@ def packages_warnings(args, packages, *modified):
for m in modified:
for p in sorted(m):
for v in packages[p].versions():
- if 'test' not in packages[p].version_hints[v]:
+ if 'test' not in packages[p].hints(v):
break
else:
# warn if no non-test ('curr') version exists
- if (('missing-curr' not in packages[p].version_hints[packages[p].best_version].get('disable-check', '')) and
+ if (('missing-curr' not in packages[p].hints(packages[p].best_version).get('disable-check', '')) and
('missing-curr' not in getattr(args, 'disable_check', []))):
logging.warning("package '%s' doesn't have any non-test versions (i.e. no curr: version)" % (p))
@@ -1289,15 +1328,15 @@ def write_setup_ini(args, packages, arch):
print("arch: %s" % arch, file=f)
print("setup-timestamp: %d" % tz, file=f)
- if args.setup_version:
- # this token exists in the lexer, but not in the grammar up until
- # 2.878 (when it was removed), so will cause a parse error with
- # versions prior to that.
- print("include-setup: setup <2.878 not supported", file=f)
+ # this token exists in the lexer, but not in the grammar up until
+ # 2.878 (when it was removed), so will cause a parse error with
+ # versions prior to that.
+ print("include-setup: setup <2.878 not supported", file=f)
- # not implemented until 2.890, ignored by earlier versions
- print("setup-minimum-version: 2.903", file=f)
+ # not implemented until 2.890, ignored by earlier versions
+ print("setup-minimum-version: 2.903", file=f)
+ if args.setup_version:
# for setup to check if a setup upgrade is possible
print("setup-version: %s" % args.setup_version, file=f)
@@ -1316,13 +1355,13 @@ def write_setup_ini(args, packages, arch):
print("\n@ %s" % pn, file=f)
bv = po.best_version
- print("sdesc: %s" % po.version_hints[bv]['sdesc'], file=f)
+ print("sdesc: %s" % po.hints(bv)['sdesc'], file=f)
- if 'ldesc' in po.version_hints[bv]:
- print("ldesc: %s" % po.version_hints[bv]['ldesc'], file=f)
+ if 'ldesc' in po.hints(bv):
+ print("ldesc: %s" % po.hints(bv)['ldesc'], file=f)
# mark orphaned packages with the 'unmaintained' pseudo-category
- category = po.version_hints[bv]['category']
+ category = po.hints(bv)['category']
if po.orphaned:
category += ' unmaintained'
# for historical reasons, category names must start with a capital
@@ -1330,8 +1369,8 @@ def write_setup_ini(args, packages, arch):
category = ' '.join(map(upper_first_character, category.split()))
print("category: %s" % category, file=f)
- if 'message' in po.version_hints[bv]:
- print("message: %s" % po.version_hints[bv]['message'], file=f)
+ if 'message' in po.hints(bv):
+ print("message: %s" % po.hints(bv)['message'], file=f)
if 'replace-versions' in po.override_hints:
print("replace-versions: %s" % po.override_hints['replace-versions'], file=f)
@@ -1347,7 +1386,7 @@ def write_setup_ini(args, packages, arch):
# due to a historic bug in setup (fixed in 78e4c7d7), we keep the
# [curr] version first, to ensure that dependencies are used
# correctly.
- nontest_versions = [v for v in sorted(po.versions(), key=lambda v: SetupVersion(v), reverse=True) if 'test' not in po.version_hints.get(v, {})]
+ nontest_versions = [v for v in sorted(po.versions(), key=lambda v: SetupVersion(v), reverse=True) if 'test' not in po.hints(v)]
curr_version = None
if len(nontest_versions) >= 1:
curr_version = nontest_versions[0]
@@ -1362,7 +1401,7 @@ def write_setup_ini(args, packages, arch):
# ditto the 'test' version
test_version = None
- test_versions = [v for v in sorted(po.versions(), key=lambda v: SetupVersion(v), reverse=True) if 'test' in po.version_hints.get(v, {})]
+ test_versions = [v for v in sorted(po.versions(), key=lambda v: SetupVersion(v), reverse=True) if 'test' in po.hints(v)]
if len(test_versions) >= 1:
test_version = test_versions[0]
@@ -1388,7 +1427,7 @@ def write_setup_ini(args, packages, arch):
continue
# test versions receive the test label
- if 'test' in po.version_hints.get(version, {}):
+ if (version in po.versions()) and ('test' in po.hints(version)):
level = "test"
else:
level = "prev"
@@ -1417,7 +1456,7 @@ def write_setup_ini(args, packages, arch):
if po.kind == Kind.source:
tar_line(po, 'source', version, f)
- src_hints = po.version_hints.get(version, {})
+ src_hints = po.hints(version)
bd = src_hints.get('build-depends', [])
# Ideally, we'd transform dependency atoms which aren't
@@ -1434,11 +1473,11 @@ def write_setup_ini(args, packages, arch):
# otherwise, Kind.binary
is_empty = False
+ hints = {}
if version in po.versions():
tar_line(po, 'install', version, f)
is_empty = po.tar(version).is_empty
-
- hints = po.version_hints.get(version, {})
+ hints = po.hints(version)
# follow external-source
s = po.srcpackage(version)
@@ -1518,7 +1557,7 @@ def write_repo_json(args, packages, f):
if p in packages:
return packages[p]
- # will lead to AttributeError as has no version_hints
+ # will lead to AttributeError as has no hints method
return None
bv = po.best_version
@@ -1527,8 +1566,8 @@ def write_repo_json(args, packages, f):
continue
versions = {}
- for vr in sorted(po.version_hints.keys(), key=lambda v: SetupVersion(v)):
- key = 'test' if 'test' in po.version_hints[vr] else 'stable'
+ for vr in sorted(po.versions(), key=lambda v: SetupVersion(v)):
+ key = 'test' if 'test' in po.hints(vr) else 'stable'
versions[key] = versions.get(key, []) + [vr]
up_to_date = getattr(po, 'up_to_date', 1)
@@ -1536,7 +1575,7 @@ def write_repo_json(args, packages, f):
d = {
'name': po.orig_name,
'versions': versions,
- 'summary': po.version_hints[bv]['sdesc'].strip('"'),
+ 'summary': po.hints(bv)['sdesc'].strip('"'),
'arches': arches,
'importance': str(po.importance),
'up_to_date': 'no' if up_to_date < 0 else 'yes' if up_to_date == 0 else 'unknown',
@@ -1547,7 +1586,7 @@ def write_repo_json(args, packages, f):
spl = []
for sp in sorted(po.is_used_by):
- hints = package(sp).version_hints[package(sp).best_version]
+ hints = package(sp).hints(package(sp).best_version)
sp = {'name': sp, 'categories': hints.get('category', '').split()}
for k in ['depends', 'provides', 'obsoletes']:
if hints.get(k, None):
@@ -1556,8 +1595,8 @@ def write_repo_json(args, packages, f):
d['subpackages'] = spl
for k in ['homepage', 'license', 'build-depends']:
- if k in po.version_hints[bv]:
- d[k] = po.version_hints[bv][k]
+ if k in po.hints(bv):
+ d[k] = po.hints(bv)[k]
build_recipe = _find_build_recipe_file(args, po.orig_name)
if build_recipe:
@@ -1602,30 +1641,20 @@ def merge(a, *l):
return None
if True:
- for vr in b[p].tarfiles:
- if vr in c[p].tarfiles:
+ for vr in b[p]._tarfiles:
+ if vr in c[p]._tarfiles:
logging.error("package '%s' has duplicate tarfile for version %s" % (p, vr))
return None
else:
- c[p].tarfiles[vr] = b[p].tarfiles[vr]
-
- # hints from b override hints from a, but warn if they have
- # changed
- for vr in b[p].version_hints:
- c[p].version_hints[vr] = b[p].version_hints[vr]
- if vr in c[p].version_hints:
- if c[p].version_hints[vr] != b[p].version_hints[vr]:
- diff = '\n'.join(difflib.ndiff(
- pprint.pformat(c[p].version_hints[vr]).splitlines(),
- pprint.pformat(b[p].version_hints[vr]).splitlines()))
-
- logging.warning("package '%s' version '%s' hints changed\n%s" % (p, vr, diff))
+ c[p]._tarfiles[vr] = b[p]._tarfiles[vr]
# overrides from b take precedence
c[p].override_hints.update(b[p].override_hints)
# merge hint file lists
- c[p].hints.update(b[p].hints)
+ # XXX: warn about changes?
+ # XXX: report changes against previous version?
+ c[p]._hints.update(b[p]._hints)
# merge auth_path sets
c[p].auth_path.update(b[p].auth_path)
@@ -1646,21 +1675,23 @@ def delete(packages, path, fn):
# (which still doesn't know if it's the source or binary package)
pn = path.split(os.sep)[-1]
+ # XXX: danger! this could leave us with different sets of keys for the
+ # _tarfiles and _hints dicts! perhaps this should take a list of vrs to
+ # remove, so we can ensure that never happens?
for p in packages:
if packages[p].orig_name == pn:
- for vr in packages[p].tarfiles:
- if packages[p].tarfiles[vr].repopath.fn == fn:
- del packages[p].tarfiles[vr]
+ for vr in packages[p]._tarfiles:
+ if packages[p]._tarfiles[vr].repopath.fn == fn:
+ del packages[p]._tarfiles[vr]
break
- for h in packages[p].hints:
- if packages[p].hints[h].repopath.fn == fn:
- del packages[p].hints[h]
- del packages[p].version_hints[h]
+ for h in packages[p]._hints:
+ if packages[p]._hints[h].repopath.fn == fn:
+ del packages[p]._hints[h]
break
# if nothing remains, also remove from package set
- if not packages[p].tarfiles and not packages[p].hints:
+ if not packages[p]._tarfiles and not packages[p]._hints:
ex_packages.append(p)
# (modify package set outside of iteration over it)
@@ -1707,7 +1738,7 @@ def mark_fn(packages, po, v, certain_age, obs_threshold, vault_requests):
# different source package which depend on them, and are over a certain
# age
#
- es = po.version_hints[bv].get('external-source', None)
+ es = po.hints(bv).get('external-source', None)
if (re.match(common_constants.SOVERSION_PACKAGE_RE, pn) and
not any(packages[p].srcpackage(packages[p].best_version) != es for p in po.rdepends)):
if es and (packages[es].best_version != bv):
@@ -1719,10 +1750,10 @@ def mark_fn(packages, po, v, certain_age, obs_threshold, vault_requests):
# - package is an old-style obsoletion, over a certain age, and not marked
# as self-destruct
#
- if '_obsolete' in po.version_hints[v]['category']:
+ if '_obsolete' in po.hints(v)['category']:
mtime = po.tar(v).mtime
if mtime < obs_threshold:
- provides = po.version_hints[v].get('provides', [])
+ provides = po.hints(v).get('provides', [])
if '_self-destruct' not in provides:
logging.debug("obsolete package '%s' version '%s' mtime '%s' is over cut-off age" % (pn, v, time.strftime("%F %T %Z", time.localtime(mtime))))
return (Freshness.conditional, False)
@@ -1730,7 +1761,7 @@ def mark_fn(packages, po, v, certain_age, obs_threshold, vault_requests):
es = po.srcpackage(v, suffix=False)
# - if package depends on anything in expired_provides
#
- requires = po.version_hints[v].get('depends', [])
+ requires = po.hints(v).get('depends', [])
if any(ep in requires for ep in past_mistakes.expired_provides) and es.startswith('python') and not es.startswith('python-pyqt5'):
logging.debug("package '%s' version '%s' not retained as it requires a provide known to be expired" % (pn, v))
return (Freshness.conditional, False)
@@ -1775,7 +1806,7 @@ def stale_packages(packages, vault_requests):
# keep-count: override hint, (defaulting to DEFAULT_KEEP_COUNT)
keep_count = int(po.override_hints.get('keep-count', common_constants.DEFAULT_KEEP_COUNT))
for v in sorted(po.versions(), key=lambda v: SetupVersion(v), reverse=True):
- if 'test' not in po.version_hints[v]:
+ if 'test' not in po.hints(v):
if keep_count <= 0:
break
mark_package_fresh(packages, pn, v)
@@ -1788,7 +1819,7 @@ def stale_packages(packages, vault_requests):
# 'keep-superseded-test' is present).
keep_count = int(po.override_hints.get('keep-count-test', common_constants.DEFAULT_KEEP_COUNT_TEST))
for v in sorted(po.versions(), key=lambda v: SetupVersion(v), reverse=True):
- if 'test' in po.version_hints[v]:
+ if 'test' in po.hints(v):
if keep_count <= 0:
break
mark_package_fresh(packages, pn, v)
@@ -1825,7 +1856,7 @@ def stale_packages(packages, vault_requests):
# also look over the other install packages generated by the
# source...
if others:
- es = po.version_hints[v].get('external-source', None)
+ es = po.hints(v).get('external-source', None)
if es:
es_po = packages[es]
# ... if the source package version doesn't count as kept ...
@@ -1880,12 +1911,15 @@ def stale_packages(packages, vault_requests):
else:
all_stale[v] = False
- for v in po.hints:
+ # we use _hints.keys() rather than versions() here so we notice that
+ # there are hints to remove in the case when a tar file has been
+ # explicitly removed by a remove file
+ for v in po._hints.keys():
# if there's a pvr.hint without a fresh source or install of the
# same version (including version: overrides), move it as well
- ov = po.hints[v].hints.get('original-version', v)
+ ov = po.hints(v).get('original-version', v)
if all_stale.get(v, True) and all_stale.get(ov, True):
- stale.add(*po.hints[v].repopath.move())
+ stale.add(*po.hint_data(v).repopath.move())
logging.debug("package '%s' version '%s' hint is stale" % (pn, v))
# clean up freshness mark
diff --git a/calm/pkg2html.py b/calm/pkg2html.py
index b57bbf2..314c6f6 100755
--- a/calm/pkg2html.py
+++ b/calm/pkg2html.py
@@ -76,7 +76,7 @@ SUMMARY_REWRITE_INTERVAL = (24 * 60 * 60)
# get sdesc for a package
#
def sdesc(po, bv):
- header = po.version_hints[bv]['sdesc']
+ header = po.hints(bv)['sdesc']
header = header.strip('"')
return html.escape(header, quote=False)
@@ -85,8 +85,8 @@ def sdesc(po, bv):
# ditto for ldesc
#
def ldesc(po, bv):
- if 'ldesc' in po.version_hints[bv]:
- header = po.version_hints[bv]['ldesc']
+ if 'ldesc' in po.hints(bv):
+ header = po.hints(bv)['ldesc']
else:
return sdesc(po, bv)
@@ -177,7 +177,7 @@ def update_package_listings(args, packages):
# - or, hints have changed since it was written
# - or, SUMMARY_REWRITE_INTERVAL has elapsed since it was last written
# - or, forced
- hint_mtime = po.hints[bv].mtime
+ hint_mtime = po.hint_data(bv).mtime
summary_mtime = 0
if os.path.exists(summary):
@@ -222,7 +222,7 @@ def update_package_listings(args, packages):
details_table = {}
details_table['summary'] = sdesc(po, bv)
details_table['description'] = ldesc(po, bv)
- details_table['categories'] = po.version_hints[bv].get('category', '')
+ details_table['categories'] = po.hints(bv).get('category', '')
class PackageData(NamedTuple):
is_attr: bool = False
@@ -243,7 +243,7 @@ def update_package_listings(args, packages):
for key in details:
# XXX: multiarch TODO:
- # access to per-arch version_hints ???
+ # access to per-arch & version hints ???
pos = {}
for arch in common_constants.ARCHES:
pos[arch] = po
@@ -257,7 +257,7 @@ def update_package_listings(args, packages):
if details[key].is_attr:
value[arch] = getattr(pos[arch], key, set())
else:
- t = pos[arch].version_hints[pos[arch].best_version].get(key, [])
+ t = pos[arch].hints(pos[arch].best_version).get(key, [])
value[arch] = set(t)
values.update(value[arch])
@@ -281,11 +281,11 @@ def update_package_listings(args, packages):
install_packages = po.is_used_by
details_table['install package(s)'] = ', '.join([linkify_package(p) for p in sorted(install_packages)])
- homepage = po.version_hints[po.best_version].get('homepage', None)
+ homepage = po.hints(po.best_version).get('homepage', None)
if homepage:
details_table['homepage'] = '<a href="%s">%s</a>' % (homepage, homepage)
- lic = po.version_hints[po.best_version].get('license', None)
+ lic = po.hints(po.best_version).get('license', None)
if lic:
details_table['license'] = '%s <span class="smaller">(<a href="https://spdx.org/licenses/">SPDX</a>)</span>' % (lic)
else:
@@ -367,7 +367,7 @@ def update_package_listings(args, packages):
else:
target = "%s-%s-src" % (p.orig_name, v)
item.link = "../%s/%s/%s" % (p.tar(v).arch, pn, target)
- item.status = 'test' if 'test' in p.version_hints[v] else 'stable'
+ item.status = 'test' if 'test' in p.hints(v) else 'stable'
item.ts = tsformat(p.tar(v).mtime)
item.arch = p.tar(v).arch
return item
@@ -710,12 +710,16 @@ def write_package_listings(args, packages):
if __name__ == "__main__":
htdocs_default = os.path.join(common_constants.HTDOCS, 'packages')
+ pkglist_default = common_constants.PKGMAINT
relarea_default = common_constants.FTP
+ repodir_default = '/git/cygwin-packages'
parser = argparse.ArgumentParser(description='Write HTML package listings')
parser.add_argument('--force', action='store_true', help="overwrite existing files")
parser.add_argument('--htdocs', action='store', metavar='DIR', help="htdocs output directory (default: " + htdocs_default + ")", default=htdocs_default)
+ parser.add_argument('--pkglist', action='store', metavar='FILE', help="package maintainer list (default: " + pkglist_default + ")", default=pkglist_default)
parser.add_argument('--releasearea', action='store', metavar='DIR', help="release directory (default: " + relarea_default + ")", default=relarea_default, dest='rel_area')
+ parser.add_argument('--repodir', action='store', metavar='DIR', help="packaging repositories directory (default: " + repodir_default + ")", default=repodir_default)
parser.add_argument('-n', '--dry-run', action='store_true', dest='dryrun', help="don't do anything")
parser.add_argument('-v', '--verbose', action='count', dest='verbose', help='verbose output')
(args) = parser.parse_args()
@@ -726,4 +730,5 @@ if __name__ == "__main__":
logging.basicConfig(format=os.path.basename(sys.argv[0]) + ': %(message)s')
packages, _ = package.read_packages(args.rel_area)
- write_doc_inc(args)
+ package.validate_packages(args, packages)
+ update_package_listings(args, packages)
diff --git a/calm/reports.py b/calm/reports.py
index 467bff7..9c0c577 100644
--- a/calm/reports.py
+++ b/calm/reports.py
@@ -201,7 +201,7 @@ def deprecated(args, packages, reportlist):
continue
bv = po.best_version
- es = po.version_hints[bv].get('external-source', None)
+ es = po.hints(bv).get('external-source', None)
if not es:
continue
@@ -227,7 +227,7 @@ def deprecated(args, packages, reportlist):
continue
# current version has the dependency of interest
- dpl = package.deplist_without_versions(packages[d].version_hints[bv]['depends'])
+ dpl = package.deplist_without_versions(packages[d].hints(bv)['depends'])
if p not in dpl:
continue
@@ -295,7 +295,7 @@ def unstable(args, packages, reportlist):
continue
latest_v = sorted(po.versions(), key=lambda v: SetupVersion(v), reverse=True)[0]
- if 'test' not in po.version_hints[latest_v]:
+ if 'test' not in po.hints(latest_v):
continue
unstablep = types.SimpleNamespace()
@@ -414,7 +414,7 @@ def provides_rebuild(args, packages, fn, provide_package, reportlist):
if pp_package:
pp_bv = pp_package.best_version
- pp_provide = pp_package.version_hints[pp_bv]['provides'][0]
+ pp_provide = pp_package.hints(pp_bv)['provides'][0]
# provide_base is the start of the provide, up-to and including the
# first '_' (assumed to be followed by digits and maybe separators), so
# it doesn't accidentally match the package name we probably get without
@@ -425,7 +425,7 @@ def provides_rebuild(args, packages, fn, provide_package, reportlist):
po = packages[p]
bv = po.best_version
- depends = packages[p].version_hints[bv]['depends']
+ depends = packages[p].hints(bv)['depends']
depends = package.deplist_without_versions(depends)
for d in depends:
@@ -475,7 +475,7 @@ def python_rebuild(args, packages, fn, reportlist):
if not py_package:
return
- latest_py = py_package.version_hints[py_package.best_version]['depends'][0]
+ latest_py = py_package.hints(py_package.best_version)['depends'][0]
modules = {}
@@ -486,7 +486,7 @@ def python_rebuild(args, packages, fn, reportlist):
if po.obsoleted_by:
continue
- depends = packages[p].version_hints[bv]['depends']
+ depends = packages[p].hints(bv)['depends']
depends = package.deplist_without_versions(depends)
for d in depends:
diff --git a/calm/setup_exe.py b/calm/setup_exe.py
index dd09bbd..43c8117 100755
--- a/calm/setup_exe.py
+++ b/calm/setup_exe.py
@@ -45,7 +45,7 @@ import re
def extract_version(fn):
# check the file exists
if not os.path.exists(fn):
- raise FileNotFoundError
+ return None
# canonicalize the pathname
fn = os.path.realpath(fn)
diff --git a/calm/spelling.py b/calm/spelling.py
index 77464d7..a6d5c91 100644
--- a/calm/spelling.py
+++ b/calm/spelling.py
@@ -119,9 +119,10 @@ def spellcheck_hints(args, packages):
continue
# spell-check the spell-checkable keys
+ po = packages[p]
for k in ['sdesc', 'ldesc', 'message']:
- if k in packages[p].hints:
- chkr.set_text(packages[p].hints[k])
+ if k in po.hints(po.bv):
+ chkr.set_text(po.hints(po.bv)[k])
# XXX: this is doing all the work to generate suggestions, which
# we then ignore, so could be written much more efficiently
for err in chkr:
diff --git a/test/testdata/mksetupini/setup.ini.expected b/test/testdata/mksetupini/setup.ini.expected
index 09cb18e..6a7a354 100644
--- a/test/testdata/mksetupini/setup.ini.expected
+++ b/test/testdata/mksetupini/setup.ini.expected
@@ -8,6 +8,8 @@
'release: repo-label\n'
'arch: x86_64\n'
'setup-timestamp: 1680890562\n'
+ 'include-setup: setup <2.878 not supported\n'
+ 'setup-minimum-version: 2.903\n'
'\n'
'@ arc\n'
'sdesc: "The ARC archive utility"\n'
diff --git a/test/testdata/uploads/pkglist.expected b/test/testdata/uploads/pkglist.expected
index 59e9289..adcb22a 100644
--- a/test/testdata/uploads/pkglist.expected
+++ b/test/testdata/uploads/pkglist.expected
@@ -1,37 +1,35 @@
-{'testpackage': Package('testpackage', {'1.0-1': Tar('testpackage-1.0-1.tar.bz2', 'x86_64/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',
- 'depends': ['cygwin']}}, {}, False),
- 'testpackage-src': Package('testpackage-src', {'1.0-1': Tar('testpackage-1.0-1-src.tar.bz2', 'x86_64/release/testpackage', 'acfd77df3347e6432ccf29c12989964bc680a158d574f85dfa7ef222759f411006c7bd2773e37c5abdee628bea769b2da9aae213db615cd91402fd385373933d', 266, False)}, {'1.0-1': {'sdesc': '"A test package"',
- 'ldesc': '"A test package\n'
- "It's description might contains some unicode junk\n"
- 'Like it’s you’re Markup Language™ Nokogiri’s tool―that '
- 'Bézier."',
- 'category': 'Devel',
- 'homepage': 'http://homepage.url',
- 'parse-warnings': ["key 'license' missing"],
- 'depends': []}}, {}, False),
- 'testpackage-subpackage': Package('testpackage-subpackage', {'1.0-1': Tar('testpackage-subpackage-1.0-1.tar.bz2', 'x86_64/release/testpackage/testpackage-subpackage', 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83', 195, False)}, {'1.0-1': {'sdesc': '"A test subpackage"',
- 'ldesc': '"A test subpackage"',
- 'category': 'Devel',
- 'external-source': 'testpackage-src',
- 'depends': []}}, {}, False),
- 'testpackage-zstd': Package('testpackage-zstd', {'1.0-1': Tar('testpackage-zstd-1.0-1.tar.zst', 'x86_64/release/testpackage-zstd', '044066c54c036190f9b0496ccf31f74748d209cce961352e19631876d5abd79ef6d2b34edfb955b8d1a7a781294ee0636bb1305afe410b34562367a2cb77988d', 98, False)}, {'1.0-1': {'category': 'Base',
- 'sdesc': '"test package (zstd compressed)"',
- 'ldesc': '"test package (zstd compressed)"',
- 'depends': []}}, {}, False),
- 'testpackage-zstd-src': Package('testpackage-zstd-src', {'1.0-1': Tar('testpackage-zstd-1.0-1-src.tar.zst', 'x86_64/release/testpackage-zstd', '90561ec4dad76268773856cbdda891b0e7b53f26492777f1ff76757844cb47124396feb76f1e30bc1baa680f1d788de21d89e612faeb30b5039b210ca9186434', 313, False)}, {'1.0-1': {'category': 'Base',
- 'build-depends': ['cygport'],
- 'sdesc': '"test package (zstd compressed)"',
- 'ldesc': '"test package (zstd compressed)"',
- 'homepage': 'http://zstd.testpkg.invalid',
- 'skip': '',
- 'parse-warnings': ["key 'license' missing"],
- 'depends': []}}, {}, False),
- 'testpackage2-subpackage': Package('testpackage2-subpackage', {'1.0-1': Tar('testpackage2-subpackage-1.0-1.tar.bz2', 'x86_64/release/testpackage2/testpackage2-subpackage', 'c4bf8e28d71b532e2b741e2931906dec0f0a70d4d051c0503476f864a5228f43765ae3342aafcebfd5a1738073537726b2bfbbd89c6da939a5f46d95aca3feaf', 46, True)}, {'1.0-1': {'sdesc': '"A test subpackage 2"',
- 'ldesc': '"A test subpackage 2"',
- 'category': 'Devel',
- 'depends': []}}, {}, False)}
+{'testpackage': Package('testpackage', {'1.0-1': Tar('testpackage-1.0-1.tar.bz2', 'x86_64/release/testpackage', 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83', 195, False)}, {'1.0-1': Hint('testpackage-1.0-1.hint', {'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',
+ 'depends': ['cygwin']})}, {}, False),
+ 'testpackage-src': Package('testpackage-src', {'1.0-1': Tar('testpackage-1.0-1-src.tar.bz2', 'x86_64/release/testpackage', 'acfd77df3347e6432ccf29c12989964bc680a158d574f85dfa7ef222759f411006c7bd2773e37c5abdee628bea769b2da9aae213db615cd91402fd385373933d', 266, False)}, {'1.0-1': Hint('testpackage-1.0-1-src.hint', {'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',
+ 'homepage': 'http://homepage.url',
+ 'parse-warnings': ["key 'license' missing"],
+ 'depends': []})}, {}, False),
+ 'testpackage-subpackage': Package('testpackage-subpackage', {'1.0-1': Tar('testpackage-subpackage-1.0-1.tar.bz2', 'x86_64/release/testpackage/testpackage-subpackage', 'aff488008bee3486e25b539fe6ccd1397bd3c5c0ba2ee2cf34af279554baa195af7493ee51d6f8510735c9a2ea54436d776a71e768165716762aec286abbbf83', 195, False)}, {'1.0-1': Hint('testpackage-subpackage-1.0-1.hint', {'sdesc': '"A test subpackage"',
+ 'ldesc': '"A test subpackage"',
+ 'category': 'Devel',
+ 'external-source': 'testpackage-src',
+ 'depends': []})}, {}, False),
+ 'testpackage-zstd': Package('testpackage-zstd', {'1.0-1': Tar('testpackage-zstd-1.0-1.tar.zst', 'x86_64/release/testpackage-zstd', '044066c54c036190f9b0496ccf31f74748d209cce961352e19631876d5abd79ef6d2b34edfb955b8d1a7a781294ee0636bb1305afe410b34562367a2cb77988d', 98, False)}, {'1.0-1': Hint('testpackage-zstd-1.0-1.hint', {'category': 'Base',
+ 'sdesc': '"test package (zstd compressed)"',
+ 'ldesc': '"test package (zstd compressed)"',
+ 'depends': []})}, {}, False),
+ 'testpackage-zstd-src': Package('testpackage-zstd-src', {'1.0-1': Tar('testpackage-zstd-1.0-1-src.tar.zst', 'x86_64/release/testpackage-zstd', '90561ec4dad76268773856cbdda891b0e7b53f26492777f1ff76757844cb47124396feb76f1e30bc1baa680f1d788de21d89e612faeb30b5039b210ca9186434', 313, False)}, {'1.0-1': Hint('testpackage-zstd-1.0-1-src.hint', {'category': 'Base',
+ 'build-depends': ['cygport'],
+ 'sdesc': '"test package (zstd compressed)"',
+ 'ldesc': '"test package (zstd compressed)"',
+ 'homepage': 'http://zstd.testpkg.invalid',
+ 'skip': '',
+ 'parse-warnings': ["key 'license' missing"],
+ 'depends': []})}, {}, False),
+ 'testpackage2-subpackage': Package('testpackage2-subpackage', {'1.0-1': Tar('testpackage2-subpackage-1.0-1.tar.bz2', 'x86_64/release/testpackage2/testpackage2-subpackage', 'c4bf8e28d71b532e2b741e2931906dec0f0a70d4d051c0503476f864a5228f43765ae3342aafcebfd5a1738073537726b2bfbbd89c6da939a5f46d95aca3feaf', 46, True)}, {'1.0-1': Hint('testpackage2-subpackage-1.0-1.hint', {'sdesc': '"A test subpackage 2"',
+ 'ldesc': '"A test subpackage 2"',
+ 'category': 'Devel',
+ 'depends': []})}, {}, False)}