aboutsummaryrefslogtreecommitdiffstats
path: root/pkgs
Commit message (Collapse)AuthorAgeFilesLines
* populate, overlay: mark populate's scripts as shell, drop unused libHEADmastertv8 hours2-6/+2
| | | | | | The scripts populate writes with writeDash get /* sh */ markers like the other shell code, and the overlay doesn't import krops' lib, which it doesn't use.
* populate: omit the times of directories and symlinkstv8 hours1-0/+4
| | | | | | | rsync sets the modification time of each directory whose contents change, and logs a line for it. Nothing relies on these times, nor on the times of symlinks, so --omit-dir-times and --omit-link-times leave them alone, and the log lists only what got transferred or deleted.
* krops: add allocateTTY to writeDeploytv8 hours1-3/+8
| | | | | | | | | With allocateTTY, nixos-rebuild runs with a terminal, so it shows colours and progress: on remote targets, ssh gets -t, which allocates a terminal if its own input is one, and on the local target, expect's unbuffer provides one. The nixos-rebuild stand-in records whether its output is a terminal.
* populate: follow branches and tags of git sourcestv8 hours1-17/+24
| | | | | | | | A ref that consists of 4 to 40 hex digits is a commit, which populate fetches only if the work tree lacks it, unless fetchAlways is set. Any other ref is a branch or tag, which populate fetches on every run, resetting the work tree to the commit fetched. Resetting to the name itself resolves to a local branch, which fetching doesn't move.
* populate: name the target alike in all messagestv9 hours1-20/+20
| | | | | | | | | | | | | What populate prints names paths on the target in different ways: populating as host:path, also for the local target, pruning and the errors about the sentinel by targetName, and replacing a symlink or a Git work tree by the path alone. All of them use targetName now: the path, prefixed by the host if the target isn't local, and by the user if that isn't root. Replacing a symlink or a Git work tree quotes the path and ends with an ellipsis, like populating and pruning do. The tests expect the names that way, and rsync-log also expects the line naming the source being populated.
* populate: reduce log spamtv10 hours1-2/+2
|
* populate: name the target's user in messages unless it's roottv17 hours1-5/+12
| | | | | | | Messages naming the target, i.e. pruning's lines and the errors about the sentinel, name the user as well, as user@host:path, unless the user is root, the usual one, so deploying as another user, e.g. with sudo, shows.
* populate prune: name the target by its host, like populate's messagestv17 hours1-21/+16
| | | | | | | | | Pruning names the target as user@host:path, like rsync's destination, but nothing else populate prints names the user: the errors about the sentinel name the host, and the commands it runs on the target name the host, with the user as ssh's option. Pruning names the target like those do, as host:path, and the errors about the sentinel use the same function for it.
* populate prune: name the target like populating doestv17 hours1-8/+12
| | | | | | | Pruning prints the path of each entry it removes, without the target's user and host, while rsync, when populating, names the target as user@host:path. Pruning names it the same way, so the lines say which machine they're about.
* populate: fail on inputs drawn that the flake doesn't havetv18 hours2-0/+98
| | | | | | | | | | | | | | | Nix ignores an input that --override-input names but the flake doesn't have, with a warning, so a misspelt input name in inputs draws nothing, and the source keeps using its own input. Before changing anything, populate locks the flake of each source that draws inputs, with an empty flake in place of each input drawn, which may be unreachable, and fails, naming the source and the input, unless the flake has each input drawn. Below an input drawn from a source, the path continues in the flake of that source. An edge case misspells an input of the source's flake, and one below an input drawn from a source, both ways of drawing inputs.
* populate: never write through files or change hard links elsewheretv18 hours1-13/+42
| | | | | | | | | | | | | | | | | | | | | | | | | | Populate writes some files in place, and makes files writable, which reaches beyond the target directory where such a file is a symlink or a hard link to one elsewhere: - The key of a derived copy gets written to a new file, which then replaces it, instead of written through a symlink at its place. - Lock files get copied to a new file before Nix rewrites them, instead of to flake.lock.populate, which a source may contain as a symlink. - Before rsync syncs a source, each file with other hard links gets replaced by a copy of its own. rsync fixes the mode and time of a file it takes for unchanged in place, which changes every hard link to it: one elsewhere, e.g. in /etc/nixos, or a backup's. - Removing state makes only directories writable, which is what removing what's in them needs, instead of everything, including files that are hard links to ones elsewhere. - The sentinel file only gets created if it's missing, instead of touched on every run. - A link only counts as pointing into the store if its resolved path is in the store, so a link like /nix/store/../.. gets replaced. Safety scenarios cover a symlink in place of a key, symlinks in a source named like the lock file's copies, a hard link to a read-only file outside in the target directory, and in stale state.
* populate git: refuse work trees whose .git names places elsewheretv18 hours1-2/+93
| | | | | | | | | | | | | | | | | | | | | | | | | | | | A .git directory names places elsewhere in more ways than being a symlink or a file: core.worktree, symlinks to a configuration, to objects, or to refs elsewhere, a commondir file naming another repository, and linked work trees. Git's commands follow them, so fetching, resetting, setting the remote's URL, and cleaning change what is elsewhere: with core.worktree, git clean removes everything in the work tree it names. And Git runs commands the configuration names, like core.fsmonitor, and hooks. Populate only uses a work tree whose .git directory has no symlinks, no commondir file, no linked work trees, and only configuration that git clone and populate write, where submodules' repositories may have their work tree in the work tree. Otherwise populating fails with an error telling what's wrong, unless the new option reclone replaces the work tree by a fresh clone. Git runs without hooks and without fsmonitor in any case. The work tree also gets reset to the commit if HEAD is there already: a lock file rewritten in place, or created and staged by Nix, stays otherwise once the source stops drawing inputs. A safety scenario refuses work trees with core.worktree, a symlinked configuration, a commondir file, and core.fsmonitor, replaces them with reclone, and checks that a hook doesn't run. A git scenario stops drawing inputs and checks that the work tree is clean.
* populate: draw inputs below drawn inputs at any depthtv20 hours1-16/+26
| | | | | | | | | | | | | | | | | | | | | An input below an input that gets drawn from a source is an input of the flake in that source. If that flake draws the input on the way from another source itself, the path goes on in the flake of that one, and so forth. Populate follows the path one source deep only, so x.inputs.dep = { follows = "b"; inputs.p.inputs.z.follows = "c"; } has no effect if b draws p from a source: Nix ignores overrides below an input that follows another one, without warning. Populate follows such paths through the sources, for generated flakes as well as for rewritten lock files. Where the way leads through a generated flake, it names the generated flake's inputs, which are its source and the sources that one draws from. So a source with a rewritten lock file can also draw an input below one it draws from a source with a generated flake. Edge cases cover an input two sources deep, both ways of drawing inputs, and a source with a rewritten lock file drawing from one with a generated flake.
* krops writeDeploy: deploy every flake by a URL Nix can't misreadtv20 hours1-15/+39
| | | | | | | | | | | | | | | | | | | nixos-rebuild gets generated flakes as path: URLs, but other flakes by their bare paths, which Nix takes for the enclosing Git work tree, if the target directory lies in one. A file source there fails to deploy, because the work tree doesn't track it. Every flake gets deployed by a URL: a Git work tree as git+file:, with submodules if it has any, like populate refers to it, and anything else as path:. The path gets resolved on the build target, because Nix refuses URLs with symlinks on the way, which the target directory may be, and percent-encoded. --build-host and --target-host name no user if the target has none, instead of failing to evaluate. The deploy test also deploys flakes from file and git sources. Its scenarios evaluate without LOGNAME.
* populate: cope with unusual names and pathstv20 hours1-47/+72
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Names and paths with characters that mean something to shells, to find, or in URLs get handled as what they are, or refused: - Pruning, and removing state that sources don't need anymore, list entries with find instead of a loop reading names, which strips blanks at the ends of names and splits names at newlines. So an entry named "trail " gets pruned instead of reported as pruned and left. - Pruning doesn't make entries writable before removing them, which would change the mode of files elsewhere that are hard links to files therein. - Source names are portable file names: letters, digits, and ._-, not starting with -. nixpkgs' writers accept nothing else in the names of the scripts populating the sources, which contain the source names, and fail with an assertion that doesn't mention the source. - Paths get percent-encoded where they go into URLs for Nix, which refuses blanks there and takes ? and # for delimiters. - rsync gets the target path protected from the target's shell (--protect-args), which expands wildcards in it otherwise: a file source delivered to /var/src/a?c ends up in /var/src/abc if that exists. A safety scenario deploys every kind of state to a target path with a blank, wildcards, #, and %. An edge case prunes entries with blanks at the ends of their names, with a newline, and with wildcards, and the scenario pruning links also prunes hard links to a read-only file outside, and lists what's left in the C locale, where ls sorts .populate first. The scenario with unusual source names also draws inputs from a source named self.
* populate: stop the ssh master also when a signal ends populatetv20 hours1-1/+9
| | | | | | | | | | | | | | | | The shell doesn't run the EXIT trap when a signal ends it, so an interrupted deploy leaves the ssh master, for an hour, and populate's temporary directory. Populate traps HUP, INT, and TERM and exits, which runs the EXIT trap. The shell runs a trap once the command it waits for ends. A signal to the process group, like the one of an interrupt key, of a closed terminal, or of timeout, ends that command as well. A signal to populate alone takes effect after the step that is running. Phases of scenarios can end populate after some seconds. An edge case does so while a pipe source's command sleeps, and checks that neither the ssh master nor the temporary directory remain.
* populate file: check the .rsync-filter files that really applytv20 hours1-32/+90
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | rsync reads .rsync-filter files in the directories above a source as well, and their rules apply to the transfer. The check for files that rsync 3.5.0 and later can't read only starts if the source itself contains one, so a subdirectory of a repository with a filter file at its top gets synced without it, silently. The check also starts for filter files above the source. The check's dry run is the transfer it stands for, as far as filtering goes: - It gets the source's exclude and filters, so it doesn't enter directories the transfer skips. - It doesn't run for transfers that apply no .rsync-filter files, i.e. uploads of flakes and patches. - A filter file the user may not read anyway doesn't count: rsync fails on its own when it gets to transfer that file, and --insecure-links changes nothing about it. - rsync prints bytes it takes for unprintable as \#ooo, which depends on the locale. File names get decoded before checking that they exist, so files below, e.g., directories with umlauts in their names don't pass for missing in the C locale. - If rsync doesn't tell which filter files it reads at all, populate warns that it can't tell either. The README mentions that --insecure-links also affects the way to the target path on local targets, and that only rsync 3.5.0 ignores filter files below directories that may be entered but not read. Phases of scenarios can set environment variables for populate. New file scenarios sync a subdirectory whose filter file is above it, and a source with a filter file below a directory with an umlaut in its name, in the C locale.
* populate flake-input: fail on failures, reuse the store, leave out replaced ↵tv20 hours2-57/+150
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | inputs Delivering flakes and flake inputs gets more robust: - With fetchOnTarget, the inputs get collected before the pipeline that links them, so populate fails if the target can't fetch one, instead of linking the flake without its inputs and succeeding. - What the lock file pins gets taken from the store if it's there: the store path is the one of a directory named source with the locked hash, which nix-store --print-fixed-path computes. builtins.fetchTree contacts where the input comes from even then, so redeploying unchanged sources fails without that if a server is unreachable. - With fetchOnTarget, a delivered input that is itself locked to a local path the target lacks fails with populate's error naming the input, like its inputs do. - Inputs that get drawn from other sources are left out, with all they pin: Nix archives an empty flake in their place. So nothing gets fetched, copied, and rooted that no evaluation uses, and a pin that is unreachable doesn't matter if it gets replaced anyway. - flake-input sources get the option requireInputs. By default, populating fails if the inputs that the input's own lock file pins can't be delivered, e.g. because the lock file lacks an input its flake.nix has. With false, populate warns and delivers the input with what Nix locks now, or else without its inputs. A remote flake that the target fetches entirely on its own collects its inputs like everything else does. The Nix function finding its subdirectory moves next to the jq programs. New edge cases cover each of these.
* populate: stay inside the target directorytv20 hours1-54/+154
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Populate replaces what's at the target paths of sources, removes what sources don't deliver anymore, and prunes. Nothing of that may reach beyond the target directory, whatever names sources have and whatever the target directory contains: - Source names that aren't file names in the target directory don't evaluate: the empty name, ., .., .populate, and names with slashes or control characters. E.g. a git source named "" removes the target directory, and a file source named .. syncs into its parent. - Target paths that aren't absolute, that are the root directory, or that contain .. don't evaluate. - A symlink at the target path of a source gets replaced, not followed, and populate says so. rsync-based and flake sources do that already. git sources replace the link as well, and also a work tree whose .git is a symlink or a file naming a repository elsewhere, instead of fetching, resetting, and cleaning there. derivation sources replace a link that doesn't point into the store, instead of failing. - Populate refuses to use the sentinel, or a state directory therein, if it is a symlink, instead of changing and removing what it points to. - What populate removes recursively gets removed as a link if it is one: chmod -R follows a link named on the command line. - Flake and flake-input sources that get patched, get their lock file rewritten, or are materialized replace a symlink at their target path like every source does, and say so. - Nix rewrites lock files in place, which changes other hard links to them as well, e.g. in a backup or outside the target directory, and what a lock file that is a symlink points to. Populate replaces a lock file by a copy of its own before rewriting it. The target directory itself may be a symlink. Nix refuses path: URLs with symlinks on the way, so the flakes step resolves the paths it hands to Nix. Backups work on a sentinel that is still a file, which becomes a directory, like for everything else that keeps state. The tests create canaries outside the target directories: a file and a directory beside them, and a directory elsewhere with a read-only directory and a Git work tree with uncommitted changes. The check of every phase of every scenario fails if a canary changed, or if a store path that the target directory links to doesn't match its hash anymore. A new test, safety, points links at the canaries: at the target path of every source type, inside what sources replace, in place of populate's state, and among what it removes and prunes. It also covers the names and target paths that don't evaluate, a target directory that is a symlink, and a lock file with another hard link.
* populate: draw inputs by rewriting lock files, add materialize and patchestv20 hours2-47/+258
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Sources drawing inputs from other sources get the lock file of their flake rewritten with nix flake lock --override-input, so the flake in the source itself uses the other sources, and needs no generated flake to be found. file and git sources get their lock file rewritten in place. flake and flake-input sources get delivered as a copy with the rewritten lock file, which gets added to the store with nix-store --add-fixed, and the target path links to that. With rewriteLock set to false, and for symlink sources, the source stays as it is and gets a generated flake in .populate/flakes/<name>, which writeDeploy's flake parameter uses. flake and flake-input sources get two more options: - patches: patches on the deploying machine, which get uploaded to .populate/patches/<name> and applied in order with patch -p1 on the target, in the directory the target path shows. - materialize: the target path becomes a writable copy instead of a link into the store. Sources that get patched, rewritten, or materialized get delivered to .populate/derived/<name>/original, which also roots the delivered store path, and the flakes step derives the target path from there. Copies get made again only if what they derive from changes, which a key in .populate/derived/<name> records. The matrices of the file, flake, flake-input, and git tests cover both ways of drawing inputs, those of flake and flake-input materialize, the deploy test a source with a rewritten lock file, and features and edge cases run the scenarios drawing inputs both ways. New features cover patches, a patch that doesn't apply, patches in a subdirectory, reusing copies, and materializing.
* populate flake, flake-input: take the flake reference as urltv29 hours1-8/+8
| | | | | | | | | | | Flake and flake-input sources take the flake reference as attribute url, like git sources take their repository, and like inputs in flake.nix: something.flake = "github:owner/something"; otherthing.flake = { url = "github:owner/otherthing"; inputs.nixpkgs.follows = "nixpkgs"; };
* populate file: add insecureLinkstv35 hours1-0/+55
| | | | | | | | | | | | | | | | | | | | | | rsync 3.5.0 opens merge files, including per-directory .rsync-filter files, walking the path one directory at a time, refusing symlinks that neither root nor the user running rsync owns, and opening each directory for reading. It treats the files it can't open that way as missing, without saying so. That happens, e.g., below a home directory with mode 711, which the user may enter but not read, or behind another user's symlink. Such a source then got synced without its .rsync-filter rules: excluded files got transferred, and --delete-excluded deleted nothing. Before syncing with rsync 3.5.0 or later a source containing .rsync-filter files, populate asks rsync which of them it reads: a dry run with --debug=FILTER2. If it reports an existing one as missing, the file source type's new insecureLinks option decides: with null, the default, populate fails with an error naming the file; with true, rsync reads such files anyway (--insecure-links); with false, rsync syncs without them. Both print a warning. File scenarios sync a source through a symlink owned by nobody, with each setting.
* populate: log what rsync changes about each itemtv35 hours1-0/+4
| | | | | | rsync logged only the names of the items it transferred. It logs what changed about each item now (--itemize-changes), along with its size as transferred and in total.
* tests: run populate's jq programs over lock files of both shapestv43 hours2-66/+71
| | | | | | | | | Depending on the version of Nix, lock files name subdirectories as attribute dir or as query parameter dir of the URL. The VM tests run one version, so only one shape gets covered there. The jq programs for flakes move to pkgs/populate/flake-jq.nix, and a new test, jq, runs them without VMs over lock files of both shapes, with follows, removed and cyclic follows, and inputs given by relative paths.
* populate flake-input: remove uploads left behindtv43 hours1-0/+5
| | | | | | | | | Uploads an interrupted run left behind in .populate/flake-uploads only got removed before the same source uploaded again. Delivering a flake or flake input removes its upload directory now, and the empty .populate/flake-inputs once the last roots are gone. An edge case leaves an upload behind between two deploys.
* populate: name inputs of generated flakes validlytv43 hours1-7/+14
| | | | | | | | | | Generated flakes used source names as input names, but Nix accepts fewer names there than populate does, e.g. not alt-1.0 or self. Following such a source failed late, at locking, with an error mentioning neither krops nor the source. Names Nix doesn't accept get replaced by ones derived from them. An edge case follows a source named alt-1.0.
* populate pipe: deliver changed output of the same sizetv43 hours1-1/+3
| | | | | | | | | pipe sources get a fixed modification time, so rsync's quick check took changed output of the same size, e.g. a new commit hash or token, for unchanged, and didn't deliver it. pipe sources get synced comparing checksums now. An edge case changes a pipe source's output without changing its size.
* populate, krops writeDeploy: refer to generated flakes as path:tv43 hours2-2/+7
| | | | | | | | | | | Generated flakes got locked with a bare nix flake lock in their directory, and writeDeploy deployed them by their path. Nix takes both for the enclosing Git work tree, if the target directory lies in one, e.g. a home directory kept in Git, and fails, because generated flakes aren't tracked there. Both refer to generated flakes as path: now. An edge case deploys into a Git work tree, and the deploy test covers deploying generated flakes.
* populate: draw inputs from sources that aren't flakestv43 hours1-0/+5
| | | | | | | | | Generated flakes declared every source they draw inputs from as a flake, so drawing an input declared with flake = false from a source without flake.nix failed, although the README says it works. Such sources get declared with flake = false now. An edge case draws a non-flake input from a source without flake.nix.
* populate: place overrides on sources with generated flakes correctlytv43 hours1-0/+3
| | | | | | | | | An override below an input drawn from a source that has a generated flake itself got placed on that generated flake, which has no such input, so Nix ignored it with a warning. Generated flakes have their source as input of the same name, so the override goes below that. An edge case overrides an input of a source with a generated flake.
* populate: stop the ssh master also after failurestv43 hours1-5/+8
| | | | | | | | | | Populate stopped the ssh master at the end of its script, which a failure skips. The master then stays for an hour, with its control socket gone along with populate's temporary directory. Populate stops it on exit now, before removing that directory. An edge case checks that no master remains after a failing and after a succeeding deploy.
* populate flake-input: replace symlinks pointing outside the storetv43 hours1-1/+7
| | | | | | | | nix-store --add-root only replaces symlinks pointing into the store, so a symlink pointing elsewhere at the target path, e.g. one a symlink source left there, made delivering a flake fail. Populate removes such links. An edge case switches a symlink source to a flake source.
* populate: replace symlinks before syncing with rsynctv43 hours1-0/+18
| | | | | | | | | | | | | rsync follows a symlink at the target path, so a source switching from the flake or flake-input type to file, pass, passage, or pipe got written into the store path the link points to, and one switching from the symlink type into what that link points to, e.g. another source. Populate removes a symlink at the target path before syncing with rsync. The roots in .populate/flake-inputs/<name> of a source that is neither a flake nor a flake-input source anymore get removed as well. An edge case switches a flake source to a file source.
* populate flake-input: deliver the inputs the input's own lock file pinstv44 hours1-138/+174
| | | | | | | | | | | | | | | | | | | | | | | | | | | | A flake-input source delivers an input as its own flake, which evaluating it uses with its own lock file. Populate, however, took the input's inputs from the parent flake's lock file: on the target, by walking the lock file, and on the deploying machine, from the parent's nix flake archive. That had several consequences: - An empty follows path, which removes an input, or two inputs following each other made the walk loop forever. - Copying left out inputs that follow other inputs, and rejected names through them, e.g. dep/inner where dep's inner follows another input. - Inputs given by relative paths, e.g. path:./lib, which have no lock entry of their own to fetch, broke fetching on the target and flake-input sources. - Where the parent overrides an input's inputs, the input's own lock file pins other versions than the delivered ones. Populate now resolves the name through the parent's lock file, follows included and guarded against cycles, to what to fetch: a locked reference, or the flake itself, which inputs given by relative paths are part of. It fetches that, on the deploying machine or on the target, and then the inputs the input's own lock file pins, using nix flake archive. An input without a lock file comes without its inputs. New edge cases cover lock files with empty and cyclic follows, names through follows, the delivered closure, and relative path inputs.
* krops writeDeploy: pass --no-flake if /etc/nixos/flake.nix existstv45 hours1-1/+4
| | | | | | | | | | | nixos-rebuild deploys /etc/nixos/flake.nix instead of NIX_PATH if that file exists, so deploying anything but a flake fails on such targets. Without writeDeploy's flake parameter, nixos-rebuild gets --no-flake if /etc/nixos/flake.nix exists on the build target. nixos-rebuild versions predating flakes neither know --no-flake nor look for that file, so they don't get it. The deploy VM test covers targets with and without that file.
* krops writeDeploy: pass --use-remote-sudo only with a separate build targettv45 hours1-1/+2
| | | | | | | | | | | | For targets using sudo, writeDeploy runs nixos-rebuild on the target via sudo, so --use-remote-sudo has no effect there. It only matters when nixos-rebuild runs on a separate build target and activates the system on the target, so writeDeploy passes it only then. A new VM test, deploy, runs writeDeploy with a stand-in for nixos-rebuild, which records the user it runs as, NIX_PATH, and its arguments, for deploying flakes and other sources, with and without a separate build target, to every kind of target.
* populate: add prunetv46 hours2-5/+47
| | | | | | | | | | | | | | | | | | | Populate never removes what it delivered for sources that aren't configured anymore. For flake and flake-input sources, that keeps their garbage collector roots, so what they delivered never gets collected. With prune, populate removes everything from the target directory that isn't a source, except .populate, after syncing the sources. It also removes the roots in .populate/flake-inputs of names that aren't flake or flake-input sources, and uploads left behind by interrupted runs. Pruning is opt-in, because the target directory may contain other things worth keeping, or be shared by deployments with different sources. writeDeploy, writeTest, and writeCommand pass prune on to populate. A feature scenario deploys sources, deploys fewer without pruning, then with pruning, and checks that the removed sources' entries and roots are gone, while the remaining sources and .populate stay.
* populate: stop the ssh master only if there is onetv47 hours1-1/+4
| | | | | | | Populate ends by stopping the ssh master, which fails if no source started one, e.g. for local targets, which populate doesn't reach via ssh. Populate then exits with ssh's exit status, though all sources got delivered. Populate now checks for a master first.
* populate flake-input: support subdirectories named in URLstv47 hours1-7/+41
| | | | | | | | Depending on the version of Nix, flake references and lock entries name the subdirectory containing a flake either as attribute dir or as query parameter dir of their URL. fetchTree supports neither, so populate looks for both: it takes the subdirectory from either, from the locked or the original reference, and removes both before fetching.
* populate flake: support fetchOnTargettv2 days1-22/+183
| | | | | | | | | | | | | | | | | | With fetchOnTarget, the target fetches the flake's inputs using the arguments recorded in the lock file, like it does for flake-input sources. The flake itself has no lock entry, so the target fetches it by its locked reference, unless that refers to the deploying machine, e.g. a path or a Git work tree. Then the flake's tree gets transferred using rsync and added to the target's store using nix-store --add-fixed, which yields the same store path as on the deploying machine, because flake store paths are content-addressed by their NAR hash. Adding paths like this needs neither signatures nor a trusted user, so this works for targets using sudo. The transfer gets skipped if the target's store has the flake already, and populate fails if the added path differs from the expected one. rsync' gets a filterFiles option, so the flake's tree gets transferred without applying .rsync-filter files, which would change it.
* populate: add flake-input source typetv2 days1-9/+11
| | | | | | | The flake-input source type delivers an input of a flake, as recorded in the flake's lock file, and the flake source type delivers the flake itself. fetchOnTarget belongs to flake-input, because only a locked input can be fetched on the target.
* krops writeDeploy: deploy generated flakestv2 days1-1/+12
| | | | | The flake parameter names a source. If the source draws inputs from other sources, its generated flake gets deployed.
* krops writeDeploy: add flake parametertv2 days1-2/+8
| | | | | | With flake set, nixos-rebuild deploys that flake from the build target's source directory, with flakes enabled for the command. The deployment fails with an error message unless Nix on the build target supports flakes.
* populate: generate flakes for inputs drawn from sourcestv2 days1-5/+131
| | | | | | | | | | | | | | For each source that draws inputs from other sources, populate generates a flake in .populate/flakes/<name>, which re-exports the outputs of the source's flake with those inputs drawn from the other sources. The source itself stays as it is, so NIX_PATH still refers to it. Generated flakes refer to each other's generated flakes, so a source's own declarations apply wherever it gets drawn from, and get generated in dependency order. Evaluation fails for sources drawing inputs from missing sources, from themselves, or from each other. Generated flakes get locked on every run, and get removed once their sources no longer draw inputs from other sources.
* populate flake: add fetchOnTargettv2 days1-18/+80
| | | | | | | | | | With fetchOnTarget, the target fetches the input and its own inputs itself, using fetchTree with the arguments recorded in the flake's lock file. Only nix flake metadata runs on the deploying machine, so the inputs get downloaded once, by the target. This needs Nix with flake support on the target, which populate checks before fetching. Because nothing gets copied, this also works for targets using sudo.
* populate: add flake source typetv2 days1-1/+97
| | | | | | | | | | | | Deliver a flake, or one of its locked inputs, to the target: archive the flake locally, copy the selected input together with its own inputs into the target's store, and link it at the target path, registered as garbage collector root. The result can be used in NIX_PATH as well as by flakes evaluated on the target, without network access. nix copy runs with a separate ssh wrapper without the control socket, because Nix waits for its LocalCommand, which may not run over a multiplexed connection.
* populate: export TMPDIRtv2 days1-0/+1
| | | | | | | Each job and the ssh wrapper run as separate scripts, which only see TMPDIR if it's exported. Without TMPDIR in the caller's environment, jobs fail, and the ssh wrapper's control socket ends up at the root directory.
* populate backup: fix error messagetv2 days1-1/+1
|
* populate: derive socket name from target hosttv2026-01-011-2/+2
|
* populate: use ssh control socket1.30.0tv2025-12-091-6/+12
|