Repository navigation
Upgrading from 0.2.0
Every entry under Removed is also a break; its replacement is named there.
- Install PyYAML for a
yamlDB:pip install 'pkgforge[yaml]'. - Re-create every 0.2.0 file DB: a record lacks
kind,capsandpackage, so
loading it fails. Runpkgforge initdband stage again. - Call
pkgforge.cli.main(argv)where you calledpkgforge.main(argv), or use
pkgforge.Projectfrom a build script; import the entry functions from
pkgforge.entryand the exceptions frompkgforge.exceptions. - Rename
JsonlDb,YamlDb,SqliteDb,RpmSpecFiles,RpmSpecFilesPre419,
Debianandpkgforge.dbdump.EntriestoJSONLinesDb,YAMLDb,
SQLiteDb,RPMSpecFiles,RPMSpecFilesPre419,DebianFilesand
pkgforge.FileEntries, andlookup(name)toget(name). - Port a dump format of your own from
dump(entries, output, logger)to
render(entries, context),check_output(output)andwrite(rendered, output, *, force=False). - Rename a third-party backend or format whose
NAME, alias or suffix clashes
with another class's: the second one raisesValueError. - Rewrite an absolute
install/scan-Xpattern that names the install path
(-X /opt/app/build/tmp) relative to the source (-X /tmp), and
PathMatch(stmts, installroot=...)asPathMatch(stmts, root=...). - Replace
dbdump --stdinwithdbdump --db -,DUHO_TRACEBACKwith
PKGFORGE_TRACEBACK, and-f rpmspec(the%fileslines) with-f rpmspecfilesor-f rpm:rpmspecis the spec format. - Pass
--db-formatfor a file DB whose suffix does not name its format: its
content is not sniffed. - Run
pkgforge initdbbeforedbdumporcompacton a DB that does not exist
yet: both exit 2 for it. - Record owners and groups by account name, not number, and declare every
account outside Debian's base-passwd set in[[users]]or[[groups]]of a
pkgforge.cfg(create = falsefor one that exists on the target). - Replace
-O rpmprefix=...with-k/--kindand--caps. - For
dbdump -f debian, add apkgforge.cfgwith[package] name, delete
the namelessinstall,dirs,permissionsandfixpermsfiles the dump
wrote intodebian/, and runsh debian/fixperms debian(the debian
directory, not the package's) fromoverride_dh_fixperms. - Remove any tail after
--from a command line (pkgforge initdb -- junk):
it is now a usage error, exit 2, where it was ignored.
Added
-
pkgforge.cfg, a TOML project file read from--config/-c FILE(before the
subcommand), elsePKGFORGE_CONFIG(an empty value means no file), else
./pkgforge.cfg.db,db_formatandbuildrootin it are defaults below the
command line and the environment, and relative paths are relative to the
file.${package.name}and any other key of the file can be reused in its
text values ($${is a literal${). A YAML file's!includeand!loadare
refused. The whole file is validated before any command runs: a problem is one
pkgforge: error:line, status 2.pkgforge.configholds the schema
(ProjectConfigand one dataclass per table) andload(path);Project(..., config=, config_path=),Project.config,Project.config_pathand
Project.from_config(path)use it. -
[package](name,version,release,arch,summary,license,
homepage,maintainer,description, each checked when the file is read;
nameis a lowercase package name[a-z0-9][a-z0-9+.-]+) with
[package.rpm] requires,[package.debian] depends,sectionand
priority,[package.pacman] dependsand[package.apk] depends, and
[[packages]], the subpackages built from the same source. -
[defaults]and[[rules]]fill themode,owner,group,kind,caps
andpackagean entry leaves at-when it is recorded: the first rule whose
match(-Xstatements) fits the DB path, then[defaults](dir_mode,
exec_modeorfile_modeby type and execute bit,owner,group). A flag
wins.installwithout-mstages the file with the resolved mode, and
install --record-tree(andrecord_tree = truein a[[stage]]step)
chmods each child to its resolved mode, or records the child's mode from disk
when no rule or default gives one. -
owninpkgforge.cfgand--own PREFIX(repeatable) name the directories a
package owns: recording an entry at or below one also records each missing
ancestor directory down from the prefix.dbdump --dirs owned
(Project.dump(dirs=),own=ofpkgforge.dbdump.dump) keeps only the
directories at or below an owned prefix, so a manifest claims no directory the
distribution owns. -
Entry kinds and file capabilities: an entry records a
kind(file,
config,config-noreplace,doc,licenseorghost; unset isfile)
andcaps(onesetcapclause such ascap_net_bind_service=ep), set with
install -k/--kindand--caps,mkdir -k,symlink -k,[[rules]]and
[[stage]].pkgforge.entrygainsFileKind,normalize_kindand
normalize_caps.rpmspecfilesstarts a line with%config,
%config(noreplace),%doc,%licenseor%ghostand writes%caps(CAPS);
dbdump -f debianwritesP.conffiles(config files outside/etc),
not-installed(ghost files, sodh_missing --fail-missingaccepts them), a
setcapline per capability inP.postinst, and${pkgforge:Depends}in
P.substvarsnaminglibcap2-bin. Ghost entries are left out ofinstall,
dirsandfixperms. -
An entry records the
packageit ships in:-P/--package NAMEoninstall,
mkdirandsymlink,packagein[[rules]]and[[stage]], else the
[package]name. A name the configuration does not declare exits 2 before
anything is staged;pkgforge.entry.normalize_packagechecks one. -
[[users]]and[[groups]]declare the accounts the package's files belong
to (UserAccount,GroupAccount):name, and for a userdescription,
home,shelland supplementarygroups;create = falsemarks an account
that exists on the target.pkgforge.entry.BASE_USERSandBASE_GROUPSare
Debian's base-passwd names, which need no declaration. -
pkgforge sysfiles(Project.sysfiles) writes and records
/usr/lib/sysusers.d/NAME.conffor the accounts the package creates and
/usr/lib/tmpfiles.d/NAME.conffor its ghost directories;stageruns it.
rpm 4.19+ and debhelper act on the files when the package is installed, so a
file owned by a service user is staged without that user existing at build
time.dbdump -f debianleaves an entry owned by a created account out of
fixperms:P.postinstapplies it with a guardeddpkg-statoverride --update --add(an administrator's override is kept) andP.postrmremoves
it on purge. The Debian recipes needdh $@ --with installsysusers
(debhelper 13.10 or later). -
pkgforge stage [--init](Project.stage) runs the[[stage]]steps in
order: install a source at a destination, or record a directory, an empty file
or a symlink. Every source is checked before the first step runs. -
pkgforge mkdir [-p] DEST...andpkgforge symlink TARGET LINK
(Project.mkdir,Project.symlink) record a directory or a symbolic link
that has no source. -
pkgforge verify [-X STMT]... [-f text|json](Project.verify, returning
VerifyIssuetuples) checks the build root against the file DB before
rpmbuildordh_missingruns: a file or symlink no entry records
(unrecorded), an entry whose path is gone (missing, never for aghost),
a changed type (type) and a retargeted symlink (target). It exits 1 when
it finds any, and 2 with no file DB or no build root. -
dbdump -f rpmspec(RPMSpec) andrpmspec-pre419(RPMSpecPre419, for rpm
older than 4.19) write the whole spec frompkgforge.cfg: the preamble, a
%package -nblock per[[packages]]element, a%installthat runs
pkgforge stage --initand writes one%fileslist per package, the%post
that creates thetmpfiles.dpaths (and, below rpm 4.19, the%prethat
creates the accounts),%systemd_post,%systemd_preunand
%systemd_postun_with_restartfor the systemd units a package records
(*.service,*.socket,*.timerand*.pathdirectly in
/usr/lib/systemd/system; they expand to nothing without systemd-rpm-macros,
EL8: systemd), and one%files -fper package. Build it withrpmbuild -bb --define "pkgforge_config PATH" NAME.spec. It needs[package]name,
version,summaryandlicenseand asummaryper subpackage, and exits 2
naming what is missing; a description line whose first non-blank character is
%or#exits 2, since rpm would read it as a section, a conditional or a
comment. -
dbdump -f debian --skeleton(skeleton=TrueofProject.dumpand
pkgforge.dbdump.dump) also writescontrol,changelog,rules(a
debian/tmprecipe that runspkgforge stageand the dump) and
source/format, withBuild-Depends: debhelper-compat (= 13), dh-sequence-installsysusersand a stanza per package. It needs a directory
OUTPUT, the path ofpkgforge.cfgand[package]version,summaryand
maintainer; a${NAME}in thesummary,description,homepageor
maintainerof a package exits 2, since dpkg-gencontrol would replace it and
nothing escapes it. -
A spec or skeleton file that exists is kept, with a WARNING, so edits survive
regenerating;--force(force=True) replaces it.--forcewith a format
that writes no such file, and--skeletonwith a format that has no skeleton
or without a directory OUTPUT, exit 2.DumpFormat.SKELETONand
DumpFormat.KEEP_EXISTINGmark such a format. -
pkgforge package -f FORMAT [-o DIR] [--arch NAME] [--compression KIND]
(Project.package,pkgforge.package.build) builds one package per declared
package straight from the file DB and the build root, with the DB's modes and
owner names, and prints each path:deb:NAME_VERSION[-RELEASE]_ARCH.deb, withoutdpkg-deb, debhelper or
fakeroot, with the control file,conffiles,md5sumsand thepostinst,
prermandpostrmscripts debhelper would build from the same
pkgforge.cfg(sysusers, tmpfiles, the systemd units,dpkg-statoverride
for an account created at install time,setcap);--compressionxz
(default),gz,zstornone. A compressed member over 9999999999 bytes,
more than an ar header holds, exits 1.rpm:NAME-VERSION-RELEASE.ARCH.rpmthroughrpmbuild, from the spec
dbdump -f rpmspecwrites (rpmspec-pre419below rpm 4.19);--archis
passed as--target, and without the systemd rpm macros it logs a warning
and leaves the unit scriptlets out.arch:NAME-VERSION-PKGREL-ARCH.pkg.tar.zst(or.xz,.gz), without
makepkgor fakeroot. pacman ignores the owner names of a tar, so every
header isroot:rootand.INSTALLcreates the accounts and applies each
other owner, group, setuid mode and capability.apk:NAME-VERSION-rREL.apk(apk v2, unsigned:apk add --allow-untrusted), withoutabuild; its scripts create the accounts and
ghost directories and set capabilities.tar:NAME-VERSION[-RELEASE].tar[.gz|.xz|.zst],--compressiongz,
xz,zstornone.
A recorded path that is missing or of another type, or whose parent is a
symlink leading outside the build root, exits 2 before anything is written.
The files of a hardlinked set ship as one file and hardlinks to it. Payloads
are streamed, so memory does not grow with them (about 100 MiB of compressor
state for xz or zstd). A build is all or nothing: files are written beside
their final names and renamed into place once every package is built, and a
failure (Ctrl-C included) removes what the build created. With
SOURCE_DATE_EPOCHset, twodeb,arch,apkortarbuilds of one build
root are byte-identical. A format is aPackageFormatsubclass, selected by
NAMEor advertised in thepkgforge.package_formatsentry-point group, that
writes throughBuildContext.writer, aPackageWriter. -
A
zstdextra (pip install 'pkgforge[zstd]') provides zstd compression
below Python 3.14, which hascompression.zstd. -
pkgforge.Project, the Python API for build scripts:Project(buildroot, db=None, *, db_format=None, config=None, config_path=None)withinit,
load,entries,compact,install,scan,mkdir,symlink,stage,
sysfiles,dump,verifyandpackage. It does what the commands do,
takes and returns plain Python values, prints nothing and returns the records
it wrote (with no file DB, those are the only result).install(type=)takes
aFileTypeandexclude=statement text.pkgforge.FileRecordsand
pkgforge.StrPathare its types. -
pkgforge.dbdump.dump(db, fmt, output=None, *, exclude=(), own=None, config=None, config_path=None, skeleton=False, force=False)renders an
already-loaded DB;pkgforge.dbdump.Renderedis the result type and
pkgforge.dbdump.DumpContextthe context a format renders with. -
pkgforge.db.jsonl_line(path, entry)andpkgforge.db.parse_jsonl(text, source="text")write and read the JSON Lines records thejsonlbackend
stores. -
dbdump --db -reads the file DB as JSON Lines from standard input, so
pkgforge install --db - ... | pkgforge dbdump --db - -f rpmworks. Stdin
must be a pipe, a socket or a regular file: a terminal, a closed stdin or a
device such as/dev/nullexits 2 instead of dumping an empty manifest.
compactandscan --drop-stalerefuse--db -(exit 2). -
Third-party DB backends, dump formats and package formats are found through
the entry-point groupspkgforge.dbs,pkgforge.dump_formatsand
pkgforge.package_formats(name = module:Class): installing the package is
enough for--db-format NAME, a--dbsuffix,dbdump -f NAMEandpackage -f NAMEto select it.names()includes advertised names without loading
them. -
pkgforge.testing:check_db_provider(cls, directory)and
check_dump_format(cls, directory)run the checks every DB backend and dump
format must pass, so a third-party class is tested against the same contract
as the built-in ones.DB_PROVIDER_CHECKSandDUMP_FORMAT_CHECKShold the
individual checks. -
--debugprints the traceback of an error before its one-line
pkgforge: error:message, likePKGFORGE_TRACEBACK. -
The example
examples/pkgforge.cfgdeclares two packages,helloand
hello-doc;examples/hello.specandexamples/debian/are generated from
it. A guide page, "From pkgforge.cfg to packages", builds them with
rpmbuild,dpkg-buildpackageandpkgforge package, and tabulates what
each format needs, writes and runs at install time. -
--mode,--owner,--group,--typeand--dir-modetake the next word
as their value even when it is--, so-o -- t /lreads the owner from
disk like--owner=--. -
The agent help (
AGENT_HELP=1 pkgforge --help) lists the exit codes 0, 1, 2
and 130, and a failed MCP tool call reports its code, soverifywith
differences ends asexit code: 1.
Changed
- Requires
duho>=0.7.8,<0.8(was>=0.6.0,<0.7) andanycfg>=0.15.1,<0.16,
which readspkgforge.cfgand is imported only when a file is read. PyYAML is
the optionalyamlextra instead of a core dependency:pip install 'pkgforge[yaml]'to keep ayamlDB, which otherwise exits 1 with a message
naming the extra. The command line keeps its flags, its--helptext and its
0, 1 and 2 exit statuses. - Ctrl-C ends the command with status 130 and no output, or raises
KeyboardInterruptunderPKGFORGE_TRACEBACK. PKGFORGE_TRACEBACKreplacesDUHO_TRACEBACKas the switch that prints the
traceback before thepkgforge: error:line, andDUHO_TRACEBACKhas no
effect on pkgforge: setPKGFORGE_TRACEBACK=1where you set
DUHO_TRACEBACK=1. A closed output pipe is silent with status 1 either way.- A bad
-Ovalue reports duho's usage message, which still readsexpected KEY=VALUE, got 'novalue'. - The console script is
pkgforge.cli:main(waspkgforge:main);python -m pkgforgeruns the same.pkgforge.cliis the command line, not library API:
from Python, usepkgforge.Project. - The package root exports the library names only:
Project,VerifyIssue,
FileEntry,FileType,FileEntries,FileRecords,StrPath,
DbProvider,open_db,DumpFormat,PackageFormat, the exceptions and
__version__. Importapply_entry,entry_from_path,normalize_modeand
resolve_entryfrompkgforge.entry.import pkgforgeloads neitherduho
nor the command line. - Every exception class is in
pkgforge.exceptions(andpkgforge), not in
pkgforge.db,pkgforge.dbdumporpkgforge.exclude.
ExcludeSyntaxErroris aUsageErroronly (it was also an
argparse.ArgumentTypeError). - Classes with an acronym in the name spell it in capitals:
JsonlDbis
JSONLinesDb,YamlDbYAMLDb,SqliteDbSQLiteDb,RpmSpecFiles
RPMSpecFiles,RpmSpecFilesPre419RPMSpecFilesPre419, and thedebian
format classDebianisDebianFiles. Format and DB names, aliases and
suffixes are the same.pkgforge.dbdump.Entriesispkgforge.FileEntries. PathMatchStmtsubclassesargparse.Namespace(wasduho.NS), and
PathMatchtakesPathMatch(stmts, root=None): theinstallrootargument
is gone, and a path outsiderootraisesValueError.- On
installandscan, an absolute-Xpattern is relative to the input,
liketar --exclude, where 0.2.0 matched it against the install path:
install -X /tmp ./build /opt/appexcludes./build/tmp,install -X '/docs/**' app-1.0.tgz /optexcludes the archive'sdocs/members, and
scan -X /cache /usr/share/appexcludes/usr/share/app/cache. A pattern
that carries the destination (-X /opt/app/build/tmp) matches nothing: drop
that prefix. A pattern without a leading/matches at any depth, and
dbdumpmatches the DB paths, as in 0.2.0. -Xrejects a path in microseconds for glob patterns that took seconds (eight
**segments, or many*in one segment), does not warn about&&,~~or
||inside a[...]class, and matches faster over a large DB indbdump.- A dump format implements
render(entries, context),check_output(output)
andwrite(rendered, output, *, force=False), where 0.2.0 had
DumpFormat.dump(entries, output, logger)andrender(entries).contextis
apkgforge.dbdump.DumpContextholding the configuration, its path and the
OUTPUT, and-(standard output) is handled by thedbdumpcommand. A
format of your own moves itsdumpcode towrite, takes thecontext
argument, acceptsforceand drops its-case;PerEntryFormatgroups the
entries per package and itscheck_outputaccepts a directory. - A DB backend or dump format whose
NAME, alias or suffix another class holds
raisesValueErrorwhen the class is created and is not registered, where it
replaced the earlier class (for a suffix, the newer class won): rename the
new one.DbProvider.compact()drops removed paths, and the contract suite
fails a third-partycompactthat keeps them. - A file DB record has three more fields,
kind,capsandpackage, and the
sqlitetable their columns. A 0.2.0 DB fails to load withmissing field kind; this DB was written by an older pkgforge: run initdb and record again:
runpkgforge initdband stage again. - Every DB loader (
jsonl,yaml,sqlite) enforces one strict record
schema and fails with onepkgforge: error: <file>: <path>: ...line, status
1, where 0.2.0 coerced or defaulted: a number for a mode, owner or group, a
missing field, anulltype and an unknown field are refused. Re-record the
DB. - The file DB format is
--db-format, else the--dbsuffix, elsejsonl;
0.2.0 also read an unrecognized text file as YAML. A file whose content is
not in that format fails to load with an error that names the format and
suggests--db-format: pass--db-formatfor a file with another suffix. dbdumpandcompactexit 2 when no DB is configured or--dbnames a file
that does not exist (no file DB at PATH; run pkgforge initdb), where they
logged a WARNING and exited 0. An existing empty DB exits 0 with a WARNING.
Runpkgforge initdbfirst, or pass the right path.dbdumprefuses a DB entry that is not well formed, with onepkgforge: error:line naming the entry, status 2, and writes nothing: a key that is
not an absolute path with no./../empty segment, atypeother than
file,directoryorsymlink, a mode that is not 1-4 octal digits,-or
--, an owner or group that is not an account name,-or--, and a
kind,capsorpackagevalue that is not valid. Fix or re-record the
entry.installandscanrefuse an--owner/--groupthat is not an account
name ([A-Za-z_][A-Za-z0-9_.-]*,-or--), with status 2 before anything
is staged or recorded: a numeric owner such as1000is refused, so use the
account name.- An owner or group outside Debian's base-passwd set must be declared in
[[users]]or[[groups]]ofpkgforge.cfg, or recording it is exit 2;
0.2.0 recorded any name. The check covers-o/-g,[defaults],
[[rules]],[[stage]]and the names that--reads from disk, soscan --owner=--over files owned by an ordinary account needs that account
declared (create = false). installandscanwith no--db(or--db -) print their JSON Lines
records once the operation has succeeded, instead of one by one as they are
written.rpmspecis the name of the spec format, where 0.2.0 took it as an alias of
rpmspecfiles: use-f rpmspecfiles(or-f rpm) for the%fileslines.
A per-entry format (rpmspecfiles,rpmspecfiles-pre419) writes the entries
of one package into a file or-, and refuses a DB holding entries of two
packages (exit 2); given an existing directory it writesfiles-PACKAGE.txt
for every package ofpkgforge.cfg.dbdump -f debianwrites one set of files per package, named for it, where
0.2.0 wrote a namelessinstall,dirs,permissionsandfixperms:
PKG.install,PKG.dirs,PKG.conffiles,PKG.postinst,PKG.postrmand
PKG.substvarsfor[package]and each[[packages]]name, and once
not-installedandfixperms. It needs[package] nameinpkgforge.cfg
(exit 2 without it). Delete the nameless files the dump wrote into
debian/: debhelper readsdebian/PKG.NAMEfirst and ignores the nameless
file beside it, and compat 15 refuses it for a source with several binary
packages.fixpermstakes the debian directory, not the package's: runsh debian/fixperms debian.dbdump -f debianrefuses, before it writes anything (exit 2), to replace a
hand-written debhelper file: an existinginstall,dirs,not-installed,
postinst,postrmorfixpermswithout the line# Generated by pkgforge dbdump -f debian, a namelessinstall,dirs,conffiles,postinstor
postrmthat debhelper would ignore, and aPKG.conffileslisting a path the
dump would drop. Move such lines intopkgforge.cfgor the package-named file
and delete the stray one.
Removed
pkgforge.main,pkgforge.commandand thepkgforge.install,
pkgforge.scan,pkgforge.initdbandpkgforge.compactmodules, with
PkgForgeCmd,PkgForge,FileEntryArgs,FileEntryBaseArgs,
entry_from_args,parsepath,ExcludeArgsandpkgforge.dbdump.DbDump.
The commands are inpkgforge.cli(not library API) and the operations are
Projectmethods: replacepkgforge.main(argv)with
pkgforge.cli.main(argv), or callProjectfrom a build script.pkgforge.errors: import the exceptions frompkgforge.exceptionsor
pkgforge.- The
pkgforge.install.archive,decompress,staging,transfer,record
and_toolmodules and theInstallstaging methods (_resolve,_stage
and the like); staging isProject.install. - The backend submodules
pkgforge.db.jsonl,pkgforge.db.yaml,
pkgforge.db.sqlite,pkgforge.dbdump.rpmandpkgforge.dbdump.debian:
import the classes frompkgforge.dbandpkgforge.dbdump. DbProvider.lookup(name)andDumpFormat.lookup(name): callget(name).DumpFormat.dump(entries, output, logger): a format implementsrender,
check_outputandwrite(see Changed).- The
FileEntry.from_args,from_path,resolve_forandapplyclass
aliases: callentry_from_path,resolve_entryandapply_entry. - The
List[str]form ofnormalize_modeandnormalize_name, and anint
mode innormalize_mode: both take astr, and an int raisesUsageError. FileType._AUTO: use theAUTOstring.list(FileType)isfile,
directory,symlink.PathTest.GENERATORS,PathTest.factory,FilterTestRe,filetypetestand
metatestinpkgforge.exclude, andNAME_PATTERN,MODE_PATTERN,
CONTROL_PATTERNandRPM_EXPANSION_PATTERNinpkgforge.entry.PathMatch.unreachable(),log_unreachable()and the warning that an
absolute-Xpattern could match no install path.- The
RPMSpecFiles._quoteandRPMSpecFilesPre419._quoteclass hooks, which
rendernever called. - The
sniff_formatfunction, theDbProvider.sniffhook and thefor_read
argument ofopen_db:open_db(path, fmt=None)resolves by format name or
suffix only (see Changed). dbdump --stdin: use--db -.scan --type/-t, which was hidden and ignored:scanexits 2 for it.- The
--decompresstool-name aliasesgzip,gunzip,xz,unxz,
bzip2,bunzip2,zstd,unzstd,lzmaandunlzma: a kind is exactly
gz,xz,bz2,zstorlzma, in any case. - The archive destination-name fallback that cut a name at its last
taror
isosegment;.tar.zst,.tzst,.tar.lz4,.tar.lzma,.tlz,
.tar.lzand.cpioare listed suffixes. - The
permissionsartifact ofdbdump -f debian(and its section in
dbdump -f debian -): nothing consumed it, andfixpermsapplies the same
pins. meta.rpmprefix: a-O rpmprefix=...or ametaargument holding the key
is refused (exit 2). Use-k/--kindand--caps, orkindandcapsin
pkgforge.cfg.- The import-time binding of
PKGFORGE_DB,PKGFORGE_DB_FORMAT,
PKGFORGE_ROOT,PKGFORGE_INSTALL_METHODandPKGFORGE_INSTALL_RECORD_TREE
as class defaults:pkgforge.cli.main()reads them when it parses, and a
command class built directly in Python ignores the environment.
Fixed
- On Windows, a drive-qualified path (
mkdir D:/x) raisedValueError: Paths don't have the same drive. It is a usage error, exit 2, saying the path
resolves outside--buildroot. install --method moveof a directory onto another filesystem failed with
Invalid cross-device link(and a rollback could fail the same way). It
moves the tree file by file, keeping modes, mtimes and symlinks, and removes
the source.install --remove-source --method linkkept a file source and removed a
directory source. Both are removed; the staged hardlinks keep the data. The
source is kept only when it is the destination itself.- A failed
install -pleft the parent directories it had created. It removes
them before exiting with status 1; directories that already existed are never
touched. - An
Install(source=["/x"], destination="/usr/bin", ...)()command built from
Python withstrpaths raisedAttributeError.strand path-like values
are accepted, and anything else raisesUsageError. scan --drop-staleinto asqliteDB committed once per removed row; it
holds one connection for all its removals.- A
%(command)or a newline in a recorded owner, group or mode reached
rpmbuild's%fileslist, where it ran a command or injected a line;dbdump
refuses the entry (exit 2). - A DB key such as
/../../x, or a relative one, reached thedebian
fixpermsscript, where it chmod-ed or chown-ed a path outside the package
directory;dbdumprefuses it (exit 2). - An entry with no
type(or-, or an unknown value) rendered as a plain
%filespath, which made rpm ship the whole subtree;dbdumprefuses it. - A corrupt or truncated
.tar,.tar.gz,.tar.xzor.tar.bz2archive
ended in a traceback. It is onepkgforge: error: cannot extract ...line,
status 1. - A failing
bsdtaror decompressor (install -x) ended in a
CalledProcessErrortraceback. It is onepkgforge: error: <tool> failed (exit N): <its last message>line, status 1, and the tool reads standard
input only when the source is-. - A SQLite file DB that cannot be opened, written or read (an unwritable
directory, a locked or non-SQLite file, a schema mismatch, a corrupt
meta_json) ended in a traceback. It is onepkgforge: error: <path>: ...
line, status 1. - A JSON Lines or YAML file DB nested too deeply to parse ended in a
RecursionErrortraceback. It is a one-line error naming the file. - Under MCP,
dbdump --stdinoverwrote an existing OUTPUT with an empty
manifest andinstall -failed with anAttributeError, both reading the
protocol channel.dbdump --db -andinstall -return an error result
there. - A text DB was split on every Unicode line break, so a record holding U+2028,
U+2029 or U+0085 failed to load, and a.jsonlstarting with a byte-order mark
was appended to as YAML. Records split on\nonly and a leading BOM is
ignored. rpmspecfileswrote a symlink's recorded mode in%attr, and rpmbuild warned
Explicit %attr() mode not applicable to symlink; the mode is-.- A failed
dbdumpcould leave a truncated or mixed OUTPUT. Each file is
written to a sibling.<name>.pkgforge-tmpand renamed into place once every
write has succeeded.
Full Changelog: v0.2.0...v0.3.0