aboutsummaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
* populate: stop if a flake's URL can't be foundtv9 hours4-6/+27
| | | | | | | | | | | | | | The URLs of flakes went into nix flake lock's and nix flake metadata's arguments as command substitutions, whose failure doesn't stop a script under set -e. After "error: source p is not a directory", nix flake lock ran with an empty URL, which Nix takes for the current directory: on a remote target, the login directory, which ended up in the world-readable store, .ssh included. URLs get assigned first now, so failing to find one stops populate. A phase's unexpected lists what populate is expected not to print, whether it succeeds or not; notdir expects populate not to go on locking.
* populate: refer to flakes as git+file: only with a usable .gittv9 hours4-3/+59
| | | | | | | | | | | | | Writing the lock file of a git+file: flake, Nix runs Git, with the repository's configuration and hooks, which may run commands. A .git in a source's directory can come from anywhere, e.g. one planted in a materialized flake, or one a file source keeps. So drawing inputs refers to a flake as git+file: only if git_problems finds nothing wrong with its .git directory, the way git sources check their work trees, and else as path:. lock-foreign-git plants a .git in a materialized flake and in a file source that keeps it, whose configuration names an fsmonitor command.
* populate: check the hooks and submodules of Git work treestv9 hours5-55/+171
| | | | | | | | | | | | | | | | git submodule update uses the .git of a submodule as it finds it in the work tree: a repository of its own, with configuration that runs commands, or a file naming a repository elsewhere. So git_problems also requires each .git below the work tree to be a file naming a repository in .git/modules. And it refuses hooks in .git/hooks, which populate's Git doesn't run, but Nix's does, writing the lock file of a flake in a git source. It's a shell function now, taking the work tree at run time, so drawing inputs can use it too. git-submodule plants a submodule's .git in the work tree: a repository of its own whose configuration names a filter, and a file naming a repository elsewhere. The fixture withsub has gitsrc as its submodule sub.
* populate: keep URLs, refs, and names from being taken for optionstv9 hours3-7/+33
| | | | | | | | | | A git source's url and ref are strings, and git clone, git remote, and git fetch took ones starting with - for options, e.g. --upload-pack, which runs a command where the repository is local. They come after -- now, and so does a pass source's name for git log and pass show. git-ref-option gives a ref that git fetch would take for --upload-pack.
* tests: run populate with /dev/null as inputtv15 hours1-2/+4
| | | | | | | | | | The test driver runs commands in a shell whose input is the console it talks through, /dev/hvc0, which is a terminal. ssh -t, which writeDeploy's allocateTTY passes for remote targets, allocates a terminal then, and reads the console, so the deploy-*-allocateTTY scenarios of remote and sudo targets hang. Populate and writeDeploy read nothing, so their input is /dev/null, and ssh allocates no terminal, as these scenarios expect.
* tests: add a smoke testtv16 hours1-2/+45
| | | | | | | | | | nix-build tests -A smoke runs 19 scenarios in a single VM test: each source type, each kind of target, flakes drawing inputs both ways, the sentinel, prune, the checks of source names and target paths, and writeDeploy. That's quick enough to run after every change, while the complete tests stay what a change has to pass in the end. nix-build tests doesn't build it, because the complete tests run the same scenarios.
* populate, overlay: mark populate's scripts as shell, drop unused libHEADmastertv17 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 symlinkstv17 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 writeDeploytv17 hours5-6/+41
| | | | | | | | | 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 sourcestv17 hours4-18/+69
| | | | | | | | 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.
* CHANGELOG: add 1.31.0v1.31.0tv28 hours1-0/+29
|
* populate: name the target alike in all messagestv17 hours2-29/+37
| | | | | | | | | | | | | 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 spamtv18 hours1-2/+2
|
* populate: name the target's user in messages unless it's roottv26 hours2-8/+17
| | | | | | | 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 messagestv26 hours2-26/+19
| | | | | | | | | 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 doestv26 hours2-9/+17
| | | | | | | 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.
* tests: check the canaries' modification times and new neighbourstv27 hours1-5/+9
| | | | | | | The canary manifest records modification times, so changing a canary's time shows, as rsync does to a hard-linked file it takes for unchanged. And entries beside the target directories whose names start like the canaries' count as canaries, so a file created next to one shows, too.
* populate: fail on inputs drawn that the flake doesn't havetv27 hours4-3/+125
| | | | | | | | | | | | | | | 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 elsewheretv27 hours3-13/+144
| | | | | | | | | | | | | | | | | | | | | | | | | | 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 elsewheretv27 hours4-3/+194
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* tests: move combinations no code path tells apart to exhaustive teststv28 hours3-21/+72
| | | | | | | | | | | | | | | | | | | | | The matrices cross every option of a source type with every other one, also where the code handling one never looks at the other. Scenarios for such combinations are exhaustive, and run in their own tests, which nix-build tests doesn't build, but nix-build tests -A exhaustive does: - file and git: drawing inputs combined with rsync's or Git's options, since drawing inputs happens after delivery. - flake: materialize combined with how the flake gets there, except for flakes in Git work trees and in subdirectories, since materializing copies what got delivered. - flake-input: materialize for inputs other than dep. - deploy: /etc/nixos/flake.nix combined with deploying a flake, since it only matters without one. - edge-cases: generated flakes where only delivery matters, and remote targets where drawing inputs alone matters, which happens on the target alike for every kind of target. That's 181 of 707 scenarios.
* tests: check output, test rsync versions, close gaps in what's assertedtv28 hours6-24/+207
| | | | | | | | | | | | | | | | | | | | | | Several checks would pass with the feature they cover broken, or cover it only by chance: - Phases can state what a succeeding populate prints. That covers the warnings of insecureLinks, the lines pruning prints, the one about a replaced symlink, and what rsync logs about each item. - The insecureLinks scenarios take their expectations from the version of rsync, so with an rsync older than 3.5.0 they pass without the check ever running. New tests, rsync-3-4-1 and rsync-3-5-0, run them with these versions, which tests/rsync.nix builds from their release tarballs, with ACLs and extended attributes, which backups use. - Pruning has a leftover upload to remove, and a source that stops having inputs to root leaves no empty directory of roots. - A full clone has every commit from the start, so the fetch for a commit it lacks never runs. A git scenario deploys a commit that appears on the server after cloning. - The jq test also runs the Nix function that finds a flake's subdirectory on the target, over both shapes of nix flake metadata's output.
* populate: draw inputs below drawn inputs at any depthtv28 hours2-16/+65
| | | | | | | | | | | | | | | | | | | | | 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 misreadtv28 hours2-40/+74
| | | | | | | | | | | | | | | | | | | 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 pathstv28 hours4-57/+154
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 populatetv28 hours4-6/+50
| | | | | | | | | | | | | | | | 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 applytv28 hours5-44/+153
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 ↵tv28 hours6-59/+387
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 directorytv28 hours6-69/+610
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 patchestv28 hours7-156/+714
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 urltv37 hours4-53/+53
| | | | | | | | | | | 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 insecureLinkstv43 hours6-1/+114
| | | | | | | | | | | | | | | | | | | | | | 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 itemtv44 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 shapestv2 days5-67/+206
| | | | | | | | | 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.
* tests: deploy an older commit first in the git scenariostv2 days2-8/+21
| | | | | | | The git scenarios deployed only the commit a clone checks out anyway, so populate never fetched, reset, or updated submodules in a full clone, and fetchAlways made no observable difference. They deploy HEAD's parent first now.
* tests: check re-locking of generated flakes and git+file: referencestv2 days2-0/+28
| | | | | | | | Deploying the same sources twice doesn't show whether generated flakes get locked again, and the git scenarios' results are the same whether a Git work tree is referred to as git+file: or path:. A feature scenario changes what a source contains between two deploys, and the git scenarios check the reference.
* populate flake-input: remove uploads left behindtv2 days2-0/+22
| | | | | | | | | 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 validlytv2 days2-7/+25
| | | | | | | | | | 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 sizetv2 days3-1/+37
| | | | | | | | | 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:tv2 days3-11/+41
| | | | | | | | | | | 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 flakestv2 days3-0/+27
| | | | | | | | | 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 correctlytv2 days3-0/+36
| | | | | | | | | 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 failurestv2 days2-5/+32
| | | | | | | | | | 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 storetv2 days2-1/+23
| | | | | | | | 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 rsynctv2 days2-0/+37
| | | | | | | | | | | | | 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 pinstv2 days4-141/+283
| | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* tests: add edge cases of flakestv2 days5-7/+147
| | | | | | | | | | | | | | | | | A new test, edge-cases, covers paths that work but have no scenario yet: a flake given by an indirect reference, which the target fetches by its locked reference; a remote flake in a subdirectory; a flake in a subdirectory drawing inputs from sources; a dirty Git work tree; a flake whose lock file needs updating; drawing inputs from a source that isn't a directory; nested names of missing inputs; several sources sharing one flake; and an input locked to a path that the target has. The deploying machine gets a registry entry for the indirect reference. Resolving it fails if the global registry can't be downloaded, which it can't in the VM, and disabling the global registry with flake-registry needs flakes, so the deploying machine enables them, like any deploying machine using indirect references does. The target doesn't, so checks for flake support on targets still mean something.
* tests: isolate flake scenarios, check eval errors against controlstv2 days3-22/+98
| | | | | | | | | | | | | | | | | | | | | | | Several weaknesses let checks pass although the feature under test is broken: - Nix restores fetched inputs from its fetcher cache, so evaluating a delivered flake offline after collecting garbage succeeds even if populate rooted none of its inputs. nix_eval uses an empty cache directory. - Scenarios share target directories and stores, so store paths and roots of earlier scenarios stand in for missing ones, and uploads of flakes never run in a passing scenario. Scenarios of the flake, flake-input, and features tests are isolated now: they start without target directories and with a collected store on both machines. - Phases expecting evaluation to fail pass on any evaluation failure, e.g. a misspelt option. Each such phase has a control now: sources differing only in what makes evaluation fail, which must evaluate. Further, populate runs with a time limit, so a hang fails its scenario instead of the whole test, phases can run steps on the deploying machine before and after, and evaluating the scenarios fails if the remote target counts as local for whoever evaluates them.
* README: explain ports of buildTarget and targettv2 days1-0/+4
|
* README: explain that extraOptions are separate argumentstv2 days1-1/+2
|