Commit Graph
288 Commits
Author SHA1 Message Date
vhaudiquet 84405a6762 interrupt: add the passive interrupt core
The library holds only the state its own types need when a Ctrl+C
arrives: the interrupted flag flows check to stand down, the cleanup
hook registry for resources that must not outlive the process (the
ephemeral build chroot), and the live view's reporter slot. The
signal handling itself is CLI wiring and lands separately: nothing
here installs handlers, prints or exits, so a library consumer
embedding these types keeps its own signal disposition.
2026-09-22 10:43:49 +02:00
vhaudiquet 8250a0e3b1 ci: publish the crate to crates.io on a v* tag
CI / build (push) Successful in 3m15s
CI / test (push) Skipped
CI / publish (push) Skipped
CI / snap (push) Failing after 7m34s
Trusted publishing is GitHub-Actions-only, so authentication goes
through a crates.io API token stored as the CARGO_REGISTRY_TOKEN
secret, scoped to the pkh crate. The job gates on the build job and
fails loudly when the tag does not match the version in Cargo.toml,
since cargo publish ships the declared version regardless of the
tag name.
2026-09-21 23:14:27 +02:00
vhaudiquet edfd7ed5ed snap: declare the dual license and ship the license texts
CI / build (push) Successful in 3m11s
CI / test (push) Skipped
CI / snap (push) Failing after 7m18s
The store listing carries the crate's MIT OR GPL-2.0-only
expression, and both texts ride along in the snap under
/usr/share/doc/pkh: the MIT grant requires the notice to
accompany copies, and GPL-2 requires the license text with
distribution.
2026-09-21 22:41:09 +02:00
vhaudiquet 6545d327e4 docs: add example gif
CI / build (push) Successful in 3m13s
CI / test (push) Skipped
CI / snap (push) Failing after 7m23s
2026-09-21 21:33:52 +02:00
vhaudiquet b118a54bff deps: describe the crate and dual-license it MIT or GPL-2.0-only
CI / build (push) Successful in 3m2s
CI / test (push) Skipped
CI / snap (push) Failing after 7m15s
Publishing to crates.io requires a description and a license; the
repository and readme give the crates.io page the right links. The
license texts ship as LICENSE-MIT and LICENSE-GPL.

Dual licensing is valid while no lintian-derived code is in tree:
shelling out to lintian is mere aggregation. When derived lint
collections are implemented they must land in a separate GPL-2-only
crate, since their copyright belongs to lintian's authors and
cannot carry an MIT grant; the core crate stays dual.
2026-09-21 20:46:46 +02:00
vhaudiquet 43f8a9e275 docs: remove roadmap, consolidate README
CI / build (push) Successful in 3m2s
CI / test (push) Skipped
CI / snap (push) Successful in 6m9s
2026-09-21 18:20:26 +02:00
vhaudiquet ff41edbd47 ui: create the rolling pane lazily, on its first line
DebUi seeded both widgets with a "(starting...)" placeholder,
replaced as soon as real content arrived during a build. pkh put
reports through the same view but runs no subprocess, so nothing
ever fed the pane: its seed line stayed on screen for the whole
upload, stacked under the per-file byte progress.

Drop the seeds and add the pane bar to the terminal only when the
first classified line arrives; a phase change (and the final
suspend) takes it off again. Flows without subprocess output now
render the status bar alone.
2026-09-21 15:20:17 +02:00
vhaudiquet 9e0b6a37a6 put: degrade to the anonymous FTP queue when the SSH transport fails
CI / test (push) Skipped
CI / build (push) Successful in 3m0s
CI / snap (push) Successful in 6m6s
pkh put only spoke SFTP to the PPA queue, so a failure of the SSH
transport itself (TCP, banner exchange) failed the upload even though
dput happily pushes the same files: its plain ppa: profile goes over
the anonymous FTP queue of ppa.launchpad.net, the same destination
over another port.

Classify the SSH connection failures: Transport (the connection never
came up: resolution, TCP, banner or key exchange) degrades to that FTP
queue — the upload order (payload first, .changes last), the
reverse-order DELE cleanup of a failed upload and the per-chunk
progress reporting all mirror the SFTP path, sharing cleanup_list.
Refused failures (host key not accepted, no matching authentication)
stay errors: silently switching transport would bypass the refusal.

The FTP client is suppaftp's blocking stream, with the time bounds it
does not carry by itself: the control channel's reads and writes, the
data channel's writes and connect (through a custom passive stream
builder), and the NAT workaround for PASV replies announcing an
unroutable address. The queue endpoints (host, port) join
data/launchpad.yml next to the SFTP ones, and the FTP transport is
covered by unit tests against an in-process fake queue plus a live
control-channel handshake with the real server (ignored, network).
2026-09-21 14:34:04 +02:00
vhaudiquet ac19fd9d65 deps: add suppaftp and parking_lot
suppaftp 12 is the FTP client behind the put FTP fallback transport:
the maintained continuation of rust-ftp (4.2M downloads, releases this
month), used with its default features only — a plain blocking FTP
stream, no TLS, no async. It brings just lazy-regex into the tree;
chrono is shared.

parking_lot replaces std sync mutex unwrapping in test code, per the
project rule.
2026-09-21 14:34:04 +02:00
vhaudiquet 02e1f739c3 chlog,cli,docs: offer suite-aliased series in the chlog selector
The chlog series selector only appeared when the changelog's current
distribution resolved to a known series; a Debian package targeting
'unstable' (or 'stable', 'testing', ...) fell through to keeping the
current series, silently, with no menu.

Resolve the changelog distribution through the suite aliases first
(unstable identifies the same series as sid, which resolves to the
Debian series list). The selector offers an aliased series as
'<suite> (<series>)' — 'unstable (sid)' — preselected, but selects
the suite name: what a changelog distribution field expects, instead
of the codename. Every other label and free-typed input selects
itself, unchanged.

Reflect the selector in the README roadmap checklist.
2026-09-21 11:52:39 +02:00
vhaudiquet 8c6f6f4028 distro_info: match changelog suite names with their series
Debian packages conventionally target 'unstable' in their
debian/changelog distribution field, but the series data (the
distro-info CSVs) only knows codenames: the suite is the alias
'unstable' of the series 'sid', a mapping the debian-distro-info tool
resolves internally without exposing it in its data.

Add a per-dist suite_aliases reference-data key (debian: unstable ->
sid), with two helpers on top: resolve_suite_alias, identifying a
changelog suite name with its series codename and the dist that
codename belongs to, and series_suite_alias, the inverse direction.
The two names identify the same series.
2026-09-21 11:52:39 +02:00
vhaudiquet 37e0b5c978 pull: fetch every component tarball of multi-orig packages
Sources listed with "3.0 (quilt)" extra components (node-jest, php-*,
...) carry one tarball per bundled module next to the main orig, named
<package>_<uver>.orig-<component>.tar.<ext>. fetch_orig_tarball picked
the single file matching ".orig.tar." — which cannot even match the
component naming — so a git pull only fetched the main orig. The later
dpkg-source -b quilt verification then failed with "can't find file to
patch" on the first patch touching a component directory.

Select the files with the existing build::changes::is_orig_tarball
helper (mirroring dpkg's \.orig(-.+)?\.tar\. strip pattern) and fetch
all of them, pristine-tar checkout first with a checksummed archive
download fallback, per tarball.

The end-to-end test now asserts every stanza-listed orig lands in the
package dir instead of just any *.orig.tar.* file, and gains a
node-jest (trixie, 24 components) regression case.

Verified live: pkh pull node-jest -d debian fetches all 15 origs of the
sid ds7 repack, and dpkg-source -b builds the debian.tar.xz and dsc
without touching the series.
2026-09-21 11:28:55 +02:00
vhaudiquet 6c0b200241 deps: commit the Cargo.lock
A binary crate should pin its dependency graph: without the lockfile
in git, source and snap builds float transitive versions, so a
0.1.0 artifact rebuilt later would not be the same binary.
2026-09-21 01:36:40 +02:00
vhaudiquet 4edf331444 docs: refresh command list, workflow example, roadmap and install
The command block is now the actual pkh --help output (new, lint and
prune were missing). The example workflow used pkh commit, a
subcommand that does not exist; commits go through git until
chlog/pkh commit land. The roadmap now reflects what is implemented
(pull -v, deb --mode local, lint, prune, new) and an installation
section documents the source build and its system dependencies.
2026-09-21 01:36:39 +02:00
vhaudiquet fa121f08ec cli: expose --version on the root command
The flag was disabled in the initial commit, leaving the binary with
no way to report its number — wrong for a release. clap scopes the
automatic version flag to the root command (-V/--version), so the
per-subcommand -v target-version options of pull and chlog are
unaffected.
2026-09-21 01:36:39 +02:00
vhaudiquet ac83a939e3 snap: confine classically and carry the full packaging toolchain
CI / build (push) Successful in 2m50s
CI / test (push) Skipped
CI / snap (push) Successful in 5m55s
A devmode snap is a smoke test, not a distribution channel: pkh
drives the whole host packaging stack (unshare chroots, overlay
mounts, dpkg/quilt/lintian across arbitrary paths), which only
classic confinement can express.

The snap now bundles every host-side tool pkh execs (git, gnupg,
dpkg-dev, quilt, pristine-tar, mmdebstrap, lintian, fakeroot,
util-linux, mount, schroot, openssh, tar/xz/bzip2), with apt and
dpkg deliberately left to the host: a core24 apt managing a newer
host's package database is exactly the skew classic snaps must
avoid. Tools running only inside the build chroot stay out; pkh
provisions those itself.

Release metadata comes from Cargo.toml instead of the git hash, and
grade is stable, so a build of any commit packs as the declared
version.

Classic-mode correctness: noble's mount/umount are staged from the
split mount package, fakeroot is exposed via symlink since
update-alternatives does not run at staging, and every bundled ELF
is patched to the core24 loader with a DT_RPATH resolving the base
and $ORIGIN. Without this the host loader would pin the snap to
hosts with a matching glibc, and the host ld.so.cache would mix
host libraries with base ones.
2026-09-21 01:22:10 +02:00
vhaudiquet 1145ca55eb docs: drop the pkh context roadmap items
The subcommand is gone from the CLI; context survives only as the
internal build backend, so there is no user-facing surface left to
track on the roadmap.
2026-09-21 00:10:45 +02:00
vhaudiquet b99f945b98 cli: remove the pkh context subcommand
The context management interface never worked reliably, and keeping
it exposed presents a feature that is not ready. Contexts remain in
the library as the execution backend for pkh deb (unshare chroots
and friends); only the CLI surface goes.
2026-09-21 00:10:45 +02:00
vhaudiquet ae5b0042e4 context: name temp dirs atomically, not probe-then-create
CI / build (push) Successful in 2m58s
CI / test (push) Skipped
CI / snap (push) Successful in 4m39s
create_temp_dir probed for a free pkh-<seconds> name and then created
the directory, so two contexts arriving together could both observe a
free name and unpack into the same directory — observed as two e2e
tests started within the same second failing on 'File exists when
hard linking' during the chroot tarball unpack.

Name with sub-second precision and create atomically: a losing race
gets AlreadyExists and falls through to the next attempt, which
removes the probe window instead of narrowing it. The schroot and
ssh drivers already use mktemp -d and need no change.
2026-09-20 19:47:24 +02:00
vhaudiquet 5b0cc08d8f deb,quirks: scope deb entries per series with an entry list
One deb block per package cannot express two series needing different
rules. Make pull and deb lists of entries, each with its own series
scope: every matching entry applies, in file order, so a stonking
entry can carry its own dependency rules next to the resolute one.
Thread the series through find_package_directory for the
package_directory lookup, which keeps its deb-then-pull fallback.
2026-09-20 19:40:19 +02:00
vhaudiquet ff1f8c7ccd deb,quirks: generic dependency rules for build-dep workarounds
CI / build (push) Successful in 3m3s
CI / test (push) Skipped
CI / snap (push) Successful in 4m38s
The resolute linux and linux-riscv controls declare llvm-21-dev
unqualified while their other llvm pieces are :native, so the dpkg
cross rules resolve it against the host architecture — whose
dependency closure needs python3:riscv64, conflicting with the
python3 the control itself declares :native. No resolver can install
that set; sbuild fails on it identically.

Give the deb quirks a dependencies rule set rather than a one-off
native-qualification knob: replace rewrites a declared dependency by
name with a full dependency string (qualifier, version and
restrictions included), inject adds dependencies resolved as if
declared, drop ignores declared ones. Entries are scoped by series so
they can be dropped when the upstream packaging catches up, and rule
names that match nothing are warned about so stale quirks surface.

Ship the llvm-21-dev entry for the resolute kernels: resolve it as
llvm-21-dev:native, keeping the declared <!stage1> restriction.
2026-09-20 19:10:06 +02:00
vhaudiquet 31fe6dc524 context: run commands in the C locale by default
Subprocesses inherit the session environment, so a translated host
locale leaked into builds: perl-based packaging tools
(dpkg-architecture, dpkg-parsechangelog, quilt, ...) warned about
missing locale settings, change their output with the environment,
and dpkg-buildpackage treats some of that output as data.

Default every command to LANG=C and LC_ALL=C; a caller can still
override explicitly through envs().
2026-09-20 19:06:04 +02:00
vhaudiquet 5592d5a6e4 test: cross-build linux-riscv from resolute, noble known-broken
The e2e pulled linux-riscv from questing, which went EOL in July
2026 and has since been removed from the mirrors entirely — not even
old-releases carries a Release file for it, so the chroot bootstrap
cannot resolve the series and the e2e can no longer run.

Point it at resolute (26.04), the current LTS: linux-riscv is
packaged there like in every supported series, and an LTS stays
pullable for years where an interim series turns the test stale
within months.

Keep a noble fixture next to it, also not run by default: noble-era
controls declare their build tools unqualified (the :native idiom
landed in later series), so exact dpkg semantics demand
host-architecture instances of them (python3:riscv64, gcc-13:riscv64,
...), and the two-architecture install set is unsolvable — t64
libraries conflict with their own foreign-arch variant, and the
riscv64 toolchain instances drag depends chains that do not resolve
from the chroot sources.
2026-09-20 19:05:59 +02:00
vhaudiquet bb719e7c80 apt/keyring: keep the keyring cache readable
A fresh chroot download failed with mmdebstrap unable to copy the
keyrings: its unshare-mode hooks run under an identity that cannot
read the invoking user's private directories, so the 0700 cache
directory the module created broke the trusted.gpg.d setup hook with
'Permission denied' (builds reusing an already-cached tarball never
hit the path).

Create the cache 0755 and chmod the keyrings 0644 instead. The
planting guard does not weaken: cached keyrings are trusted as-is,
and validate_keyring_dir keeps refusing directories that are not
owned by the current user or are writable by group or others — read
access for the bootstrap tool is not a planting vector. Legacy 0700
cache directories are validated as before, then widened.
2026-09-20 18:14:28 +02:00
vhaudiquet af9845c480 deb: install build-deps per dpkg cross semantics
Replace the apt-get build-dep passes with a native resolver: the
Build-* clauses are evaluated against the context's package state by
crate::debian::deps (the dpkg-checkbuilddeps equivalent), and the
unsatisfied ones install through explicitly architecture-qualified
names.

apt's --host-architecture build-dep resolution is coarser than the
checker it feeds: unqualified Multi-Arch: same libraries only ever
get the host-architecture variant, and there is no way to also
satisfy the build-architecture needs of a cross build without a
native re-resolution pass — which installs co-install partners that
break unpacking for -dev packages whose variants conflict on
arch-differing files (curl-config; the libcurl4-gnutls-dev
regression). The resolver now applies the same dpkg rules as the
checker, preferring the runnable build-architecture variant of
Multi-Arch: foreign tools, and passes virtual names through to apt.

Build-Conflicts are now checked before anything installs, which the
build-dep passes never did, and a failed dose3 diagnosis no longer
masks the resolver error (a latent flaw of the passes: binary-only
builds have no .dsc for dose-builddebcheck to read).

An end-to-end test pins the expected failure: a cross build whose
build-dependencies cannot satisfy dpkg's cross semantics aborts,
naming the dependency.
2026-09-20 18:04:13 +02:00
vhaudiquet 02cb5306f3 debian: test the cross build-dep lookup against dpkg
The Facts lookup already implemented Dpkg::Deps::KnownFacts
_find_package, but nothing pinned its cross-compilation behaviour:
with host != build, an unqualified dependency resolves against the
HOST architecture instance (or any instance of a Multi-Arch: foreign
package, or an Architecture: all one) and never against the
build-architecture instance of a Multi-Arch: no/same package.

Cover the matrix with unit tests and, like the source-build checker,
with a differential sweep against real dpkg-checkbuilddeps on a
synthetic admindir with -a <host>: the checker and the real tool
agree on every fixture, including the quirks (:native aborting on
Multi-Arch: foreign instances, first-match version binding).
2026-09-20 18:04:05 +02:00
vhaudiquet 5c026a7050 docs: add AGENTS.md with the tree conventions
CI / build (push) Successful in 3m12s
CI / test (push) Skipped
CI / snap (push) Successful in 4m32s
Codify what the history already does so agents and new contributors do
not have to reverse-engineer it: the fmt/clippy gates mirroring CI's
-Dwarnings, the <scope>: <summary> commit format with the per-module
scope table, and the library-side invariants (missing_docs, report
ports, data/*.yml embeds, README parity for user-facing changes).
2026-09-20 16:30:15 +02:00
vhaudiquet 9238aa961f chlog: fall back to the changelog history when no version tag exists
CI / build (push) Successful in 2m56s
CI / test (push) Skipped
CI / snap (push) Successful in 4m30s
get_commits_since_version silently returned an empty change list when
the previous version carried no tag. Walk the history back to the last
commit that modified the changelog itself and use it as the boundary
instead, so entries stay correct in repositories that commit their
changelogs without tagging them.

Tag detection remains the preferred path. Before falling back to the
changelog commit, the version recorded by the committed changelog is
probed for a tag: an uncommitted newer entry on top (e.g. UNRELEASED
from a previous run) does not hide the previous version's tag.
2026-09-20 00:38:15 +02:00
vhaudiquet d1056fbbbf ui: ellipsize fake-terminal pane lines wider than the terminal
Overflowing log lines in the pkh deb / pkh build rolling pane used to
wrap onto a second line, corrupting the pane layout. Truncate them to
the terminal width (minus the pane prefix) by display width and append
an ellipsis instead; lines are left whole when the terminal size is
unknown.
2026-09-20 00:15:37 +02:00
vhaudiquet a0e74073bf lint: add pkh lint, wrapping lintian for parity plus pkh-native checks
CI / build (push) Successful in 2m55s
CI / test (push) Skipped
CI / snap (push) Successful in 4m32s
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.
2026-09-19 23:45:31 +02:00
vhaudiquet 4f5246ccd3 chlog: number Ubuntu backports with the per-release SRU scheme
CI / build (push) Successful in 2m56s
CI / test (push) Skipped
CI / snap (push) Successful in 4m35s
--backport was Debian-only: ~bpo is backports.debian.org's scheme and
its number the Debian release, so Ubuntu targets were rejected outright.
Ubuntu backports have their own documented scheme (Ubuntu version-
strings): the development release's version with a per-release ~YY.MM.1
appended, sorting before it (3.1-1ubuntu2 backported to 22.04 becomes
3.1-1ubuntu2~22.04.1; native 3.1 becomes 3.1~22.04.1) and independent of
the version the target release carries. The .N increments for
subsequent per-release SRU uploads.

backport_series_number becomes backport_suffix_for_series: the release
number comes from the new generic get_series_release_number (version
column of the target series' own distro-info data, leading token kept —
"12" for bookworm, "26.04" out of resolute's "26.04 LTS"; empty column
as on sid/experimental means None), and the suffix is picked per vendor:
~bpoNN+ for Debian (plain integer releases only), ~YY.MM. for Ubuntu.
Unnumbered series still error before anything is written.

Also serialize the changelog tests that mutate the process-global
DEBFULLNAME/DEBEMAIL variables behind a tokio Mutex: run in parallel
they raced each other's identity reads, which started failing
intermittently as generate_entry tests accumulated.
2026-09-19 21:32:02 +02:00
vhaudiquet dd2438a72c chlog: number regular uploads after the target series' vendor
A flagless entry (no --backport/--nmu/--rebuild) targeting an Ubuntu
series was numbered the Debian way: 1.0-1 became 1.0-2 with distribution
noble, and getting the conventional 1.0-1ubuntu1 required hand-editing
the version. The bump now derives from the vendor of the target series
(distro-info): Ubuntu series get the ubuntu suffix convention (1.0-1
becomes 1.0-1ubuntu1, and re-bumping an already-Ubuntu changelog
increments the counter instead of the revision), Debian series keep the
plain revision bump, and series that cannot be resolved to a vendor
(UNRELEASED, unknown) fall back to it too. There is no reverse sync, so
the Ubuntu-to-Debian direction needs no special casing.

Runs with an explicit --series now consult distro-info once, where they
previously queried it not at all; the interactive flow already did for
the series selector. EntryKind::Ubuntu remains the library-level way to
force the numbering regardless of the series.
2026-09-19 20:58:44 +02:00
vhaudiquet 012df20961 chlog: number entries as backport, NMU or no-change rebuild
The version flags were never reachable: --backport was declared but not
read, and compute_new_version's NMU/rebuild numbering sat behind a TODO
asking for CLI wiring (the old positional-bool signature always received
false). generate_entry now takes an EntryKind selected by three mutually
exclusive flags, and is async because the backport numbering derives the
Debian release number of the target series from distro-info:

- --backport: 1.0-1 becomes 1.0-1~bpo12+1 (12 = release number of the
  target series, backport suite names accepted too). Re-running on an
  already-numbered version bumps the counter; series without a numeric
  Debian release (sid, Ubuntu series, UNRELEASED) are rejected before
  anything is written.
- --nmu: 1.0-1 becomes 1.0-1.1 (native 1.0 becomes 1.0+nmu1).
- --rebuild: 1.0-1 becomes 1.0-1build1.

An explicit --version overrides all three. compute_new_version went
from four positional bools to a private Bump enum; backport numbering
reuses increment_suffix with a '~bpoNN+' suffix. The CLI prints the
computed new version before opening the editor.
2026-09-19 20:56:03 +02:00
vhaudiquet 47bb7c608e deb: resolve cross pkg-config against the target multiarch
CI / build (push) Successful in 2m54s
CI / test (push) Skipped
CI / snap (push) Successful in 4m32s
In-tree tools locate their libraries with the *host* pkg-config during
cross builds (the kernel's tools/build feature checks derive their
cflags/ldflags from 'pkg-config --cflags/--libs'), whose search path
only covers the build architecture's pkgconfig dirs. Cross builds of
linux-riscv died in rtla's Makefile.config: libtraceevent/libtracefs
were reported missing although the riscv64 -dev packages were
installed, because pkg-config never saw their .pc files.

The host-arch -dev packages that used to make those checks pass came
from the unscoped arch-indep build-dep pass, whose native
re-resolution b34e86d correctly scoped to the host arch — removing the
accidental co-install along with the bug it papered over. Export
PKG_CONFIG_LIBDIR for the target multiarch instead, so the checks
resolve target-arch libraries directly: no native build-dep bloat and
no wrong-arch linking.
2026-09-19 13:07:46 +02:00
vhaudiquet 6caedce61a report: reproduce the pre-refactor CLI output through the ports
Instead of carrying raw UI in core, the ports now represent everything
the CLI used to do inline:

- Prompter::present shows context outside of a question (the wizard
  summary screen, the vendoring notice spacing); TerminalPrompter
  prints it on stdout exactly like the println!s it replaces, server
  embeds forward it as a display event.
- generate_entry returns the generated entry (package, versions,
  series, path) instead of printing; the CLI renders the same lines.
- BuildTarget carries a flow-composed display line and a tee_log flag:
  the terminal adapter renders it verbatim ("Building source package
  ...", "Building ... for series/arch", "Uploading ... to ...") and
  uploads open no build log.
- The unmet build-dependency diagnostics are rendered by the CLI from
  the typed error, in the original order (details, then summary).
- --verbose constructs no live view at all (an idle widget used to
  linger), and the re-vendor offer only logs when it is actually
  asked, so headless runs print the error exactly once.
2026-09-19 00:52:31 +02:00
vhaudiquet bd8f814a53 Revert "package_info: drop the ANSI color from the not-found warning"
This reverts commit 4fae02bc85.
2026-09-19 00:39:29 +02:00
vhaudiquet 4fae02bc85 package_info: drop the ANSI color from the not-found warning
The location embedded in the log record was styled with crossterm: a
remote consumer of pkh's log records would receive ANSI codes inside
the message text. Plain text is the logger's business to style.
2026-09-18 20:55:56 +02:00
vhaudiquet c2dae4f3f9 lift main.rs business logic into the library
The chlog target-series resolution becomes changelog::series_candidates
(UNRELEASED pinning, development-series default and fallbacks modeled
by SeriesCandidates), PPA references get package_info::split_ppa
(shared by pull and deb, now also rejecting empty parts), and SSH
endpoints get context::ContextConfig::from_endpoint — so a library
consumer can resolve series, validate PPAs and build context
configurations without reimplementing the CLI's rules. All three carry
unit tests; main.rs keeps only parsing of flags and error handling.
2026-09-18 20:51:36 +02:00
vhaudiquet 0421a91e01 changelog: report through the log instead of printing to stdout
generate_entry's status messages become log lines, and the unmet
build-dependency diagnostics travel inside the UnmetBuildDependencies
error (its Display carries the full report) instead of being printed
to stderr by the library: the caller renders both like any other
outcome.
2026-09-18 20:44:05 +02:00
vhaudiquet 54cb04ba27 put: report through the view and ask the host-key question through the Prompter
put() loses its MultiProgress parameter: the summary, pre-flight and
connection spinners become view messages, the per-file SFTP transfer
reports determinate progress through view.progress (upload_file takes
a byte-count callback instead of an indicatif bar), and the display is
released through view.suspend on every exit path. The hardcoded
trust-on-first-use prompt in the SSH host-key verification becomes the
Prompter::accept_host_key port (fail-closed by default; the terminal
prompter prints the authenticity banner and confirms), so a remote
frontend can surface its own host-key dialog.
2026-09-18 20:42:17 +02:00
vhaudiquet bb76e41908 new: drive the wizard and verification offers through the Prompter port
The interactive half of pkh new no longer touches the terminal prompt
module directly: run() takes a Prompter, picks the wizard or the plain
resolve path through interactive(), and every select/text/confirm
question (including the verification offers) goes through the port.
Cancellations propagate as Err, preserving Ctrl+C-aborts; the summary
and vendoring-notice prints become log lines. A builder-server embed
can now drive the whole scaffold wizard over its own wire format by
implementing Prompter.
2026-09-18 20:38:05 +02:00
vhaudiquet d64e472845 report: grow the Prompter port and move display_path out of the ui module
Prompter gains interactive(), select() and text() (with the Validator
type), and confirm() now propagates cancellation as Err so flows abort
instead of silently taking a default when the user hits Ctrl+C. The
terminal prompter implements the full port; the port also re-exports
the path display helper, which is pure presentation formatting used by
events and messages rather than terminal code.
2026-09-18 20:34:33 +02:00
vhaudiquet 052c02cdc3 deb: drive build_binary_package through the BuildView port
The binary build joins the source build on the reporting ports:
build_binary_package takes a DebBuildOptions struct (replacing eleven
positional arguments), reports target, phases, progress and the
outcome through the environment-agnostic BuildView, and the Phase enum
with its default classifiers moves from the terminal widget into the
deb module (announced through the enter_phase helper). DebUi loses its
inherent event methods and only implements the port; tee logging and
the SIGINT behavior are unchanged.

No behavior change for the CLI; headless consumers pass report::Quiet.
2026-09-18 20:22:45 +02:00
vhaudiquet 27b1083b15 report: add BuildView/Prompter ports and drive pkh build through them
Core flows no longer reach into the terminal UI: build_source_package
takes a BuildSourceOptions struct (source tree, domain options, view,
prompter) and reports phases, messages and outcomes through the
environment-agnostic ports in the new report module. The classifiers
move from ui/logfmt to the core logfmt module, DebUi becomes a
BuildView adapter, the re-vendor retry asks the prompter instead of
checking for a TTY, and artifact/success printing moves to the CLI.

Headless consumers pass report::Quiet; an embedding (e.g. a builder
server forwarding events to a web frontend) implements BuildView and
maps the plain-data events onto its own wire format.
2026-09-18 20:02:56 +02:00
vhaudiquet a7d2cfdc6e ci: pin upload-artifact to v3
CI / build (push) Successful in 2m57s
CI / test (push) Skipped
CI / snap (push) Successful in 4m29s
v4's GHES check refuses to run on any non-github.com server, so the
snap artifact upload always failed on gitea; v3 uses the artifact API
gitea implements.
2026-09-18 18:07:54 +02:00
vhaudiquet ff635b305b ci: install nodejs in the snap job so JS-based actions can run
CI / build (push) Successful in 2m55s
CI / test (push) Skipped
CI / snap (push) Failing after 4m19s
2026-09-18 16:33:16 +02:00
vhaudiquet 781ed204c2 clippy: write the changelog body loop as while let (rust 1.98)
CI / build (push) Successful in 2m53s
CI / test (push) Skipped
CI / snap (push) Failing after 9s
2026-09-18 15:43:12 +02:00
vhaudiquet 0235ec6457 new: port the python template bodies to manifests
CI / build (push) Failing after 2m55s
CI / test (push) Skipped
CI / snap (push) Skipped
2026-09-18 15:20:22 +02:00
vhaudiquet fa399f64b2 new: port the meson, cmake and autotools template bodies to manifests 2026-09-18 15:08:27 +02:00
vhaudiquet e6f2012835 new: port the rust template bodies to manifests 2026-09-18 15:05:44 +02:00