syncinstall refactor: new options for package output handling, artifact/workdir reuse, many fixes - #46
syncinstall refactor: new options for package output handling, artifact/workdir reuse, many fixes#46ZoomRmc wants to merge 4 commits into
syncinstall refactor: new options for package output handling, artifact/workdir reuse, many fixes#46Conversation
commit 72ff226a256c07a6c63b004a06039bc70b6e4afc
Author: Zoom <zoomrmc+git@gmail.com>
Date: Thu May 7 17:28:34 2026 +0400
Refactors 1-6
commit f5c9baeb3f74c98b86b23e96ddcc68022e07b071
Author: Zoom <zoomrmc+git@gmail.com>
Date: Wed May 6 06:43:51 2026 +0400
Simplify
commit e1c3ce4909ad71991315a971d38ee98bfda5800b
Author: Zoom <zoomrmc+git@gmail.com>
Date: Wed May 6 04:53:18 2026 +0400
removed useInternalPkgdest
Bloat, integration with makepkg better done via PreserveBuilt
commit 76d6e0dac9d8b11d5053cafa4d640c1803bf5013
Author: Zoom <zoomrmc+git@gmail.com>
Date: Tue May 5 02:28:29 2026 +0400
makepkg integration: fixups, cleanup scaffolding
syncinstall: fix reusableBuildResult double-scan
When reuseLookup is already populated, reuseBuildArtifacts was called
anyway, scanning the same directory a second time. Now the fallback
scan only runs when reuseLookup is empty.
syncinstall: suppress "packages are saved to" when savedTo is empty
When UseInternalPkgdest=false and PKGDEST is unset, savedTo is "" and
there is no single output directory to report.The message is now
gated on savedTo.len > 0.
syncinstall: emit per-base "packages are saved to" message from buildLoop
When UseInternalPkgdest=false and PKGDEST is unset, makepkg writes
each archive alongside its PKGBUILD. There is no single directory
available at the cleanup site, so the message is now printed in
buildLoop immediately after discoverBuildArtifacts confirms the
archives exist, using outputDir (which equals buildPath in this case).
syncinstall: pre-filter archive candidates by package name
packageArchiveCandidates gains an optional names parameter.
commit c6ec8f36c1b76bc41d293b8c878c155944c5602d
Author: Zoom <zoomrmc+git@gmail.com>
Date: Sun May 3 03:37:05 2026 +0400
add PackageOutputDir, fix cleanup semantics
CleanupPolicy: renamed worktree→full (default, remove everything),
added worktree (clean workspace, keep artifacts)
Added `config.packageOutputDir`: separate path for PKGDEST override when
`UseInternalPkgdest` is true. Defaults to "" = TmpDir (backward compatible).
Enables tmpfs workspace + persistent package storage.
Cleanup: `Full` clears artifacts, `Worktree` keeps them, `None` keeps
everything.
commit c1530f2deec5a02afe8a85341076cc7c63f06358
Author: Zoom <zoomrmc+git@gmail.com>
Date: Sun May 3 02:15:55 2026 +0400
artifact store: batch-validation, refactor
Move store lookup and validation to handleInstall (once per invocation),
thread through `installGroupFromSources` to eliminate NxM re-scans from
`installNext` x `installGroupFromSources` nesting.
Convert `buildNext` from recursive closure to iterative for-loop.
Fix within-run reuse when `UseInternalPkgdest` is false: compute `reuseDir`
from `resolveEffectivePkgdest` instead of always scanning staging.
commit 23b1efd99fd1bdc012a16f5f7182fa183fd923bc
Author: Zoom <zoomrmc+git@gmail.com>
Date: Sun May 3 01:27:49 2026 +0400
makepkg integration: PKGDEST gate, artifact store, cleanup
Add resolveEffectivePkgdest() to read the user's PKGDEST from makepkg.conf
before the override block. Introduce `UseInternalPkgdest` config gate (default
true): when false, omit the PKGDEST= override and scan the user's output
directory instead of the staging dir.
Add cleanup policy settings:
`KeepBuildDirOnFailure`, `KeepBuiltPackagesOnFailure`
(default to false), `CleanupAfterInstall` (Worktree|Full|None).
Error paths in `handleInstall` and `installGroupFromSources` now use
these. Current behaviour unchanged with defaults.
Refactor config tuples to objects
commit 5a29d46ff1b96d8c9f556a042c4fd812099ccf7a
Author: Zoom <zoomrmc+git@gmail.com>
Date: Fri May 1 23:55:54 2026 +0400
Discover and reuse staged build artifacts
commit 07287e0286acd2c81d1b0f801e8cd044a6a58d3c
Author: Zoom <zoomrmc+git@gmail.com>
Date: Fri May 1 23:35:36 2026 +0400
discover built package artifacts from makepkg output
- `handleInstall` refactored, extracted the AUR fetcher - Made `findDependencies` iterative, removing recursive calls - Replaced recursive install ordering with an iterative builder using sets - Optimized artifact lookup with expected stem sets and a single directory scan - Consolidated package target Argument construction - Reduced multi-pass target/RPC filtering in AUR/pacman resolution - Fix cleanup policy derivation: CleanupAfterInstall=Worktree with packageOutputDir unset would silently destroy package archives: clearPaths called removeTmpDirQuiet which chased firstCreatedTmpDir and recursively removed the entire tmpRoot prefix. - InstallArtifacts gains installFiles: HashSet[string], computed once in prepareArtifacts; cleanupArtifacts reads it directly, eliminating the per-call set rebuild that previously occurred at every early-exit and success path in installGroupFromSources.
|
It seems to build OK and my system updated after running pakku -Syu, but despite updating rmlint-git from the AUR it tries to update it every time I run Syu again, so that part doesn't seem to be working quite right yet from a quick first check. For testing purposes I would suggest you should come up with various scenarios and combinations of actions, especially relating to the Pakku command options and config possibilities where you have altered the code. This may mean installing a few small AUR packages and trying out some different options in /etc/pacman.conf and /etc/pakku.conf, possibly downgrading some packages deliberately so they will be updated, that kind of thing. What LLM did you use, it may be helpful to credit the source in that respect? |
This is unexpected and embarrassing if in deed so, as it's the core functionality. What's your config, specifically, what's changed from the defaults? If the package is indeed installed it shouldn't ever be listed again. As already mentioned, for me it works correctly. Also, rmlint-git fails to build for me on a fully up-to-date system, are you sure you got the package built?
I don't think it matters much, because I'd be responsible anyway. Also, it was a convoluted process involving several models (via different interfaces) to cross-check and/or suggest changes. It would be nice to discuss this with you directly, what's the best way to reach you? You can ping me at Matrix (see profile). |
|
This is an open source project so it would be helpful for any future contributors to know what LLM's you used for any significant inputs so they could go back and ask it for more details about what it did if needed for example - if you just searched online and got an AI summary once or twice then that's hardly relevant, but you seemed to infer above there was more than that, and not all AI's have the same capabilities Also for much the same reason, it's best to keep any discussion about the project here in public view, the messages here reach me as directly as any other means. |
Sorry, I don't really understand your point. Without the context of the actual session there's zero difference in which model you're asking, they would be inferring everything from the code and the prompt anew anyway. If one needs to understand the code they can ask whatever. PR-related questions should be addressed to me. To answer your question directly: Deepseek flash and pro, OpenAI Codex were used interchangeably via agents, Claude used via the web interface. Due to the convoluted and staged nature of the workflow you can't really get any meaningful info about any particular model's capabilities from this PR. FWIW, I can tell you they all stumble and need constant steering. |
|
Ok, I've successfully installed It shows how little do I use devel packages so I never noticed this issue before. Here's the issue filed: #47 |
syncinstall.nimrefactorFirst of all, some disclaimers are in order. This PR is far more intrusive than I'd like, sorry. It's also LLM-assisted, which is also a reason for its scope reaching wider than I usually deem fitting. I'm still getting used to this workflow and my approach is far from ideal. I tried to leave most of the commit history just so it's clear it's not a blind one-shot slop and that all the changes passed through human review, though it's chaotic and leaks some things rejected from the final state.
This PR marked as draft as the master branch is live and pakku doesn't have a dev/staging branch. This doesn't mean it's not ready. I've been using this branch for my personal machines since May without any problems, though more testing would be great. Advice on how to safely move forward is wanted.
Why
This PR refactors
syncinstall.nim(plus touches a couple lines in other places). The initial goal was to introduce tighter integration with system's makepkg and fixing some annoyances with the working directory cleanup and artifact handling.While working on the features it became obvious that the code is written in a peculiar way which overutilizes closures, recursion and is not that easy to follow if you're just diving into the project. So most of the refactor was done just to improve readability for myself. While doing so it became clear that the process also uncovers some minor bugs and inefficiencies so I've doubled down.
What's changed in short
resolve -> order -> build/reuse -> prepare artifacts -> install -> cleanup.New features
This lists the changes with links to relevant procs and compares with the master branch.
New config options:
PackageOutputDir—buildLoopnow writes makepkg output toconfig.packageOutputDirwhen set, instead of always using the tmp workspace (internalPkgdestinbuildLoop). Master hard-codedstagingDir = config.tmpRootInitialasPKGDESTwith no override.CleanupAfterInstall = Full | Worktree | None—cleanupSpec()derives worktree/archive/tmp-prefix removal from policy. Master had exactly one cleanup mode, wired 1:1 to install success via akeepBuiltArtifacts: boolthat only ever meant "install failed, keep everything."PreserveBuilt = Pkgdest—installGroupFromSourcesgains aneffectivePkgdest-based branch (config.preserveBuilt == PreserveBuilt.pkgdest) copying archives to the user's resolvedPKGDEST(viacommon.resolveEffectivePkgdest) before pacman runs.KeepBuildDirOnFailure/KeepBuiltPackagesOnFailure— drivecleanupSpecForFailure(buildFailure, ...). Master always deletes build artifacts unconditionally on build failure (cleanupBuiltArtifacts(true)ininstallGroupFromSources).Cross-run artifact reuse
findReusableArtifacts()scansPackageOutputDirand the configuredPreserveBuiltdestination before building each base (called frombuildAllBases) and skips the build entirely if a matching archive is already present. No equivalent existed in master, nothing is ever reused.Structural refactoring
InstallMode, are now enum encoded instead of being stringly-typed.findDependencies(tail-recursive,while true:loop in the new file).orderInstallation(recursive accumulator →while remaining.len > 0:).installGroupFromSources(master's local recursivebuildNext) →buildAllBases, a plainfor index in 0 ..< basePackages.len.checkNextinsideconfirmViewAndImportKeys) → top-levelcheckNextwith afor pkgInfos in flatBasePackages:loop.keysLoop,editFileLoopAll→while true:/for file in files:loops.handleInstall(master's recursiveinstallNext) →for index in 0 ..< basePackages.len:with earlybreak.handle,dbs,satisfied,nodepsCount, etc. inside master'sfindDependencies(checkDependencyCycle,findInSatisfied,findInAdditional,findInDatabaseWithGroups,findInDatabase,findInDatabases) and inside master'shandleInstall(checkSatisfied) are now top-levelfuncs that take those values as explicit parameters.exec()overloads (ExecMode = emNormal | emSilent | emRedirect, with adropPrivsflag and optionalcwd) replace the repeatedforkWait/forkWaitRedirect+ manual fd close/open +dropPrivilegesAndChdir/dropPrivRedirectAndChdirtemplate pairs scattered througheditFileLoop,viewDiffLoop,editLoop,keysLoop,buildLoop,readConfExt,buildFromSources, and the git-tagging step (nowtagBuiltBases). One specific defect this removes is double-forking inkeysLoop: master's PGP import path isforkWait(() => dropPrivilegesAndChdir(...): forkWait(() => execResult(...)))(a fork inside a fork) while the newkeysLoopcallsexec(...)once per import attempt.Correctness fixes and optimisations
Conflict detection compared a package's conflicts against itself instead of against the other package. Master's
filterIgnoresAndConflicts/nonConflicingPkgInfos:this checks whether
pconflicts withp's own reference — never a meaningful check againstb.The new
filterIgnoresAndConflicts:checks both directions against the other package's reference, which is the actually-intended symmetric conflict test.
printAllWarningsrebuilt seq->tableinstalledTableonce per package, inside the warning loop. Master:The new
printAllWarningstakesinstalledTableas a parameter, built once by the caller (handleInstall/resolveBuildTargets). Same result, O(n) fewer table rebuilds.Build artifacts are now verified to exist rather than assumed. Master's
formatArchiveFilejust string-formats an expected path (name-version-arch.ext) and hands it to the installer without checking the file is actually there. The newfindArtifactsInDirdoes a singlewalkDirscan matching real files against expected stems and only returns success if every expected package base was actually found on disk, printing a clear error otherwise (buildLoop).As part of the same scan,
.pkg.tar.*.sigsidecar files are explicitly excluded from matching (the "no further.after the extension" check inartifactStemFromFilename). Master has no equivalent filtering.canonicalRenamescan no longer leak from a failed install group.handleInstall's per-base loop only mergesinstallResult.canonicalRenamesinto the running table after checkinginstallResult.code == 0. A mid-loop failure stops contributing renames beforebreak.buildFromSourcesin master takescommonArgs: seq[Argument]and never reads it. Dropped.Most uses of sequtils templates changed from closure-based
map/any/filterto their slightly more efficient-Itcounterparts or changed to loops, where this removes transient sequence allocation.Style fixes
funcfromprocopenArrayinstead ofseqIsContainerconcept +requireNonEmptytemplate allows some slight hardening with assertions.Configinsrc/config.nimfrom tuple to object enables using Nim's default object values to simplify init.Invariants checked with assertions
Unfortunately, pakku doesn't have any tests for the module. Testing is another topic entirely, but the least I could do is to sprkinle some assertions throughout the code, so during any further work dumb logic mistakes would visibly trigger them. This wouldn't be easy without untangling the code mentioned above. Just to remind,
asserts in Nim are compiled away and are no-ops in release mode,doAssertstatements stay.LLM-generated summary:
buildAllBases:assert results.len + skippedCount == basePackages.len— every input base is built, reused, or explicitly counted as skipped.installGroupFromSources:assert build.results.len + build.skipped <= basePackages.lenandassert build.code == 0 or build.results.len + build.skipped < basePackages.len— a failed build run cannot be mistaken for a complete one.prepareArtifacts:assert installFiles.len == install.len,assert install.len <= artifacts.len, andassert aname notin renames, "duplicate canonicalization key"— install targets/files stay aligned, can't exceed discovered artifacts, and split-package rename keys can't collide.installGroupFromSources:assert installWithReason.len > 0andassert pacmanUpgradeParams.len > 0 and pacmanDatabaseParams.len > 0— the install-helper subprocess is never invoked with an empty payload.obtainAurPackageInfos:doAssert target.rpcInfo.isSomeand severalassert target.sync.foundInfos.../assert target.sync.foundInfos[0].pkg.isSomeinobtainPacmanBuildTargets.Compatibility
CleanupAfterInstall = Full,PreserveBuilt = Disabled,PackageOutputDir = "").Other gains
This should go to the optimisations above, but just another arguent in favour of the refactor. Even though this PR is pretty big and adds several new features, the compiled and stripped release build loses ~ 37KB, mostly from dropping excessive closures, object reuse and less container back-and-forth churn. Haven't measured allocations, but they should be down considerably. Not that it matters much for the end users, but I claim this is evidence this PR moves in the right direction.