pkh covered the package lifecycle but never validated the packaging
itself: broken control stanzas, unparsable changelog versions or
uncommitted debian/ edits only surfaced at build or upload time. pkh
lint lints a source tree with day-one lintian parity plus a native Rust
engine for the checks lintian cannot have.
The wrapper reuses the pkh build output next to the tree when it matches
the current changelog entry and no tree content is newer (mtime walk,
skipping .git/.pc), else packs fresh with dpkg-source -b using weak gzip
compression (the artifact is ephemeral; xz dominated the run at 9.8 s
versus 2.7 s on a 111 MB tree) and symlinks quilt orig tarballs from the
tree's parent, which dpkg-source searches in cwd. Findings are parsed
from the installed lintian into a unified report, deduplicated by tag
name against the native engine, and rendered lintian-shaped
(<L>: <pkg> <type>: <tag> <details>) as text or JSON, colorized at
render time (--color auto/always/never). Exit codes follow lintian's
contract (0 clean, 1 findings at/above --fail-on, 2 runtime error);
lintian's own exit code is ignored because it uses 2 both for findings
and for runtime errors. -d/--dist maps to lintian --profile so the
target distro's rules apply even on a foreign host.
The native engine hosts the first workflow check lintian cannot know:
pkh-debian-changes-not-committed flags debian/ content that is not
committed to git, since the pkh flow builds and uploads the tree as-is.
Checks register in a static registry validated by a unit test, and the
wrapper's parser is pinned by golden tests captured from lintian 2.129
output. Strategies for lintian's Ubuntu blind spots (its vendor data
there is one file plus 14 disabled tags) are specced in
plans/pkh-lint.md, deliberately not implemented yet.
Extend the metadata writers to binary-only uploads and wire them into
the 'pkh deb' flow:
- build/binary.rs generates <pkg>_<ver>_<arch>.buildinfo/.changes
through any Context: debian/files consumption, encounter-order
Architecture accumulation (sorted in .buildinfo like dpkg-genbuildinfo),
sorted Binary lists, dpkg-formatted Description lines with udeb
suffixes, Installed-Build-Depends closure over the context status DB,
and binNMU handling (Source: pkg (prev), Binary-Only-Changes, previous
.dsc redistribution);
- artifact digests are computed inside the context via coreutils
(md5sum/sha1sum/sha256sum/stat) so chrooted/remote trees work;
- deb/local.rs runs the generation after 'rules binary', exports
SOURCE_DATE_EPOCH from the changelog (reproducibility), and resolves
vendor/profiles inside the context; deb/mod.rs retrieves the new
artifacts alongside the debs;
- reusable helpers added: FilesList::parse/render,
parse_changelog_entry_from_str, parse_previous_version_from_str,
installed_build_depends_from_content.
Differential gate: same tree built with real 'dpkg-buildpackage -b' and
with the pkh flow; .changes/.buildinfo compared field-by-field modulo
machine-dependent fields, artifact checksums included.
Replace dpkg-checkbuilddeps with a native implementation:
- full dependency grammar: comma clauses, | alternatives, << <= = >= >>
relations, :arch qualifiers (any/native/specific), [arch lists] and
<profile restriction> formulas per alternative;
- restriction reduction against active build profiles and the host arch
at parse time (reduce_restrictions semantics);
- evaluation against a parsed dpkg status database with Multi-Arch
semantics (foreign/allowed) and versioned Provides rules (unversioned
provides never satisfy versioned deps; versioned ones must satisfy the
relation);
- clause simplification with implication-based deduplication, rendering
dpkg-compatible 'unmet build dependencies/conflicts' diagnostics.
check_build_depends() consumes debian/control + CheckOpts (-A/-B/-I
equivalents). run_source_build performs the check when forced (-D
parity); source-only builds skip it entirely like dpkg-buildpackage,
and unsatisfied deps propagate as UnmetBuildDependencies -> exit 3.
Unit tests port the Dpkg_Deps.t reduction matrices; differential gate
runs 24 scenarios (alternatives, versions, arch/profile restrictions,
Multi-Arch, Provides, conflicts, -A/-B flags) against real
dpkg-checkbuilddeps comparing exit status and diagnostics.
Implement the documented dpkg ordering algorithm (Debian Policy 5.6.1):
numeric epoch, then upstream/revision compared as alternating non-digit
and digit chunks, with '~' ordering before anything including the empty
chunk and letters before non-letters in non-digit chunks.
Adds Ord/PartialOrd for DebianVersion, a free compare() and a
later_than() convenience.
Unit tests port all vectors from dpkg's scripts/t/Dpkg_Version.t plus
Ubuntu-flavored cases (security uploads, ~ppa1 backports). Differential
gate: every vector cross-checked against real 'dpkg --compare-versions'
for <<, <=, =, >= and >>.
Embed dpkg's factual cputable/ostable/tupletable/abitable data and
implement tuple/triplet/multiarch lookups, wildcard matching, arch
restriction evaluation and the full DEB_BUILD_*/DEB_HOST_*/DEB_TARGET_*
environment dump natively.
build/env.rs::arch_env now delegates to the native implementation
instead of shelling out to 'dpkg-architecture -f'.
Differential gate (build/mod.rs): arch_env(Some(a)) must equal real
'dpkg-architecture -f -a a' key-for-key for every architecture listed by
'dpkg-architecture -L', plus the native case. Data tables carry upstream
attribution comments; no dpkg code was transliterated.