diff options
36 files changed, 407 insertions, 688 deletions
diff --git a/doc/manual/change-authors.yml b/doc/manual/change-authors.yml index 8c07d7e90..98a135397 100644 --- a/doc/manual/change-authors.yml +++ b/doc/manual/change-authors.yml @@ -3,66 +3,109 @@ # # It's used for crediting people accurately in release notes. The release notes # script will link to forgejo, then to GitHub if forgejo is not present. +9999years: + display_name: wiggles + forgejo: rbt + github: 9999years + +Artturin: + github: Artturin + +DavHau: + github: DavHau + +Kha: + github: Kha + +Lunaphied: + forgejo: Lunaphied + github: Lunaphied + +Qyriad: + forgejo: Qyriad + github: Qyriad + +SharzyL: + github: SharzyL + +alois31: + forgejo: alois31 + github: alois31 + +artemist: + display_name: Artemis Tosini + forgejo: artemist + +edolstra: + display_name: Eelco Dolstra + github: edolstra + +ericson: + display_name: John Ericson + github: ericson2314 + horrors: display_name: eldritch horrors forgejo: pennae github: pennae -Qyriad: - forgejo: Qyriad - github: Qyriad +iFreilicht: + github: iFreilicht jade: forgejo: jade github: lf- -iFreilicht: - github: iFreilicht +lovesegfault: + github: lovesegfault ma27: forgejo: ma27 github: ma27 -Lunaphied: - forgejo: Lunaphied - github: Lunaphied - -9999years: - display_name: wiggles - github: 9999years - forgejo: rbt - matthewbauer: github: matthewbauer +midnightveil: + display_name: julia + forgejo: midnightveil + github: midnightveil + +ncfavier: + github: ncfavier + +puck: + display_name: puck + forgejo: puck + github: puckipedia + +r-vdp: + github: r-vdp + raito: display_name: Raito Bezarius - github: RaitoBezarius forgejo: raito + github: RaitoBezarius -winter: - github: winterqt - forgejo: winter - -Kha: - github: Kha - -Artturin: - github: Artturin +roberth: + display_name: Robert Hensing + github: roberth thufschmitt: display_name: Théophane Hufschmitt github: thufschmitt -edolstra: - display_name: Eelco Dolstra - github: edolstra +tomberek: + display_name: Tom Bereknyei + github: tomberek -roberth: - display_name: Robert Hensing - github: roberth +valentin: + display_name: Valentin Gagarin + github: fricklerhandwerk -midnightveil: - display_name: julia - forgejo: midnightveil - github: midnightveil +winter: + forgejo: winter + github: winterqt + +yshui: + github: yshui diff --git a/doc/manual/rl-next/addDrvOutputDependencies.md b/doc/manual/rl-next/addDrvOutputDependencies.md new file mode 100644 index 000000000..0442383ec --- /dev/null +++ b/doc/manual/rl-next/addDrvOutputDependencies.md @@ -0,0 +1,14 @@ +--- +synopsis: "Add a builtin `addDrvOutputDependencies`" +prs: 9216 +issues: 7910 +credits: [ericson, horrors] +category: Features +--- + +This builtin allows taking a `drvPath`-like string and turning it into a string +with context such that, when it lands in a derivation, it will create +dependencies on *all the outputs* in its closure (!). Although `drvPath` does this +today, this builtin starts forming a path to migrate to making `drvPath` have a +more normal and less surprising string context behaviour (see linked issue and +PR for more details). diff --git a/doc/manual/rl-next/always-allow-substitutes.md b/doc/manual/rl-next/always-allow-substitutes.md new file mode 100644 index 000000000..60b588fd7 --- /dev/null +++ b/doc/manual/rl-next/always-allow-substitutes.md @@ -0,0 +1,13 @@ +--- +synopsis: "Add an option `always-allow-substitutes` to ignore `allowSubstitutes` in derivations" +prs: 8047 +credits: [lovesegfault, horrors] +category: Improvements +--- + +You can set this setting to force a system to always allow substituting even +trivial derivations like `pkgs.writeText`. This is useful for +[`nix-fast-build --skip-cached`][skip-cached] and similar to be able to also +ignore trivial derivations. + +[skip-cached]: https://github.com/Mic92/nix-fast-build?tab=readme-ov-file#avoiding-redundant-package-downloads diff --git a/doc/manual/rl-next/cve-fod-fix.md b/doc/manual/rl-next/cve-fod-fix.md new file mode 100644 index 000000000..4499f639b --- /dev/null +++ b/doc/manual/rl-next/cve-fod-fix.md @@ -0,0 +1,21 @@ +--- +synopsis: "Fix CVE-2024-27297 (GHSA-2ffj-w4mj-pg37)" +cls: 266 +credits: [puck, jade, thufschmitt, tomberek, valentin] +category: Fixes +--- + +Since Lix fixed-output derivations run in the host network namespace (which we +wish to change in the future, see +[lix#285](https://git.lix.systems/lix-project/lix/issues/285)), they may open +abstract-namespace Unix sockets to each other and to programs on the host. Lix +contained a now-fixed time-of-check/time-of-use vulnerability where one +derivation could send writable handles to files in their final location in the +store to another over an abstract-namespace Unix socket, exit, then the other +derivation could wait for Lix to hash the paths and overwrite them. + +The impact of this vulnerability is that two malicious fixed-output derivations +could create a poisoned path for the sources to Bash or similarly important +software containing a backdoor, leading to local privilege execution. + +CppNix advisory: https://github.com/NixOS/nix/security/advisories/GHSA-2ffj-w4mj-pg37 diff --git a/doc/manual/rl-next/gc-roots-darwin.md b/doc/manual/rl-next/gc-roots-darwin.md new file mode 100644 index 000000000..e8e90a397 --- /dev/null +++ b/doc/manual/rl-next/gc-roots-darwin.md @@ -0,0 +1,8 @@ +--- +synopsis: Find GC roots using libproc on Darwin +cls: 723 +credits: artemist +category: Improvements +--- + +Previously, the garbage collector found runtime roots on Darwin by shelling out to `lsof -n -w -F n` then parsing the result. The version of `lsof` packaged in Nixpkgs is very slow on Darwin, so Lix now uses `libproc` directly to speed up GC root discovery, in some tests taking 250ms now instead of 40s. diff --git a/doc/manual/rl-next/macos-stack-size.md b/doc/manual/rl-next/macos-stack-size.md new file mode 100644 index 000000000..efbba1577 --- /dev/null +++ b/doc/manual/rl-next/macos-stack-size.md @@ -0,0 +1,9 @@ +--- +synopsis: Increase default stack size on macOS +prs: 9860 +credits: 9999years +category: Improvements +--- + +Increase the default stack size on macOS to the same value as on Linux, subject to system restrictions to maximum stack size. +This should reduce the number of stack overflow crashes on macOS when evaluating Nix code with deep call stacks. diff --git a/doc/manual/rl-next/more-logs.md b/doc/manual/rl-next/more-logs.md new file mode 100644 index 000000000..e239da5ad --- /dev/null +++ b/doc/manual/rl-next/more-logs.md @@ -0,0 +1,9 @@ +--- +synopsis: Show more log context for failed builds +prs: 9670 +credits: DavHau +category: Improvements +--- + +Show 25 lines of log tail instead of 10 for failed builds. +This increases the chances of having useful information in the shown logs. diff --git a/doc/manual/rl-next/nix-eval-derivations.md b/doc/manual/rl-next/nix-eval-derivations.md new file mode 100644 index 000000000..ae1952283 --- /dev/null +++ b/doc/manual/rl-next/nix-eval-derivations.md @@ -0,0 +1,9 @@ +--- +synopsis: Print derivation paths in `nix eval` +cls: 446 +credits: 9999years +category: Improvements +--- + +`nix eval` previously printed derivations as attribute sets, so commands that print derivations (e.g. `nix eval nixpkgs#bash`) would infinitely loop and segfault. +It now prints the `.drv` path the derivation generates instead. diff --git a/doc/manual/rl-next/nix-store-prefetch-unpack.md b/doc/manual/rl-next/nix-store-prefetch-unpack.md new file mode 100644 index 000000000..5627c2c75 --- /dev/null +++ b/doc/manual/rl-next/nix-store-prefetch-unpack.md @@ -0,0 +1,18 @@ +--- +synopsis: "Add an option `--unpack` to unpack archives in `nix store prefetch-file`" +prs: 9805 +cls: 224 +credits: [yshui, horrors] +category: Improvements +--- + +It is now possible to fetch an archive then NAR-hash it (as in, hash it in the +same manner as `builtins.fetchTarball` or fixed-output derivations with +recursive hash type) in one command. + +Example: + +``` +~ » nix store prefetch-file --name source --unpack https://git.lix.systems/lix-project/lix/archive/2.90-beta.1.tar.gz +Downloaded 'https://git.lix.systems/lix-project/lix/archive/2.90-beta.1.tar.gz' to '/nix/store/yvfqnq52ryjc3janw02ziv7kr6gd0cs1-source' (hash 'sha256-REWlo2RYHfJkxnmZTEJu3Cd/2VM+wjjpPy7Xi4BdDTQ='). +``` diff --git a/doc/manual/rl-next/print-in-repl.md b/doc/manual/rl-next/print-in-repl.md new file mode 100644 index 000000000..e0ac8e17f --- /dev/null +++ b/doc/manual/rl-next/print-in-repl.md @@ -0,0 +1,55 @@ +--- +synopsis: "REPL printing improvements" +prs: [9931, 10208] +cls: [375, 492] +credits: [9999years, horrors] +category: Improvements +--- + +The REPL printer has been improved to do the following: +- If a string is passed to `:print`, it is printed literally to the screen +- Structures will be printed as multiple lines when necessary + +Before: + +``` +nix-repl> { attrs = { a = { b = { c = { }; }; }; }; list = [ 1 ]; list' = [ 1 2 3 ]; } +{ attrs = { ... }; list = [ ... ]; list' = [ ... ]; } + +nix-repl> :p { attrs = { a = { b = { c = { }; }; }; }; list = [ 1 ]; list' = [ 1 2 3 ]; } +{ attrs = { a = { b = { c = { }; }; }; }; list = [ 1 ]; list' = [ 1 2 3 ]; } + +nix-repl> :p "meow" +"meow" +``` + +After: + +``` +nix-repl> { attrs = { a = { b = { c = { }; }; }; }; list = [ 1 ]; list' = [ 1 2 3 ]; } +{ + attrs = { ... }; + list = [ ... ]; + list' = [ ... ]; +} + +nix-repl> :p { attrs = { a = { b = { c = { }; }; }; }; list = [ 1 ]; list' = [ 1 2 3 ]; } +{ + attrs = { + a = { + b = { + c = { }; + }; + }; + }; + list = [ 1 ]; + list' = [ + 1 + 2 + 3 + ]; +} + +nix-repl> :p "meow" +meow +``` diff --git a/doc/manual/rl-next/print-value-in-installable-flake-error.md b/doc/manual/rl-next/print-value-in-installable-flake-error.md new file mode 100644 index 000000000..ae23b4dda --- /dev/null +++ b/doc/manual/rl-next/print-value-in-installable-flake-error.md @@ -0,0 +1,20 @@ +--- +synopsis: New-cli flake commands that expect derivations now print the failing value and its type +credits: Qyriad +category: Improvements +cls: 1177 +--- + +In errors like `flake output attribute 'legacyPackages.x86_64-linux.lib' is not a derivation or path`, the message now includes the failing value and type. + +Before: + +``` + error: flake output attribute 'nixosConfigurations.yuki.config' is not a derivation or path +```` + +After: + +``` + error: expected flake output attribute 'nixosConfigurations.yuki.config' to be a derivation or path but found a set: { appstream = «thunk»; assertions = «thunk»; boot = { bcache = «thunk»; binfmt = «thunk»; binfmtMiscRegistrations = «thunk»; blacklistedKernelModules = «thunk»; bootMount = «thunk»; bootspec = «thunk»; cleanTmpDir = «thunk»; consoleLogLevel = «thunk»; «43 attributes elided» }; «48 attributes elided» } +``` diff --git a/doc/manual/rl-next/repl-fix-history.md b/doc/manual/rl-next/repl-fix-history.md new file mode 100644 index 000000000..1517f68e7 --- /dev/null +++ b/doc/manual/rl-next/repl-fix-history.md @@ -0,0 +1,9 @@ +--- +synopsis: "`nix repl` history is saved more reliably" +cls: 1164 +credits: puck +--- + +`nix repl` now saves its history file after each line, rather than at the end +of the session; ensuring that it will remember what you typed even after it +crashes. diff --git a/doc/manual/rl-next/repl-interrupt.md b/doc/manual/rl-next/repl-interrupt.md index 61a8ab71e..da0bc698e 100644 --- a/doc/manual/rl-next/repl-interrupt.md +++ b/doc/manual/rl-next/repl-interrupt.md @@ -1,6 +1,8 @@ --- synopsis: Interrupting builds in the REPL works more than once cls: 1097 +category: Fixes +credits: alois31 --- Builds in the REPL can be interrupted by pressing Ctrl+C. diff --git a/doc/manual/rl-next/shebang-single-quotes.md b/doc/manual/rl-next/shebang-single-quotes.md new file mode 100644 index 000000000..f60caad84 --- /dev/null +++ b/doc/manual/rl-next/shebang-single-quotes.md @@ -0,0 +1,13 @@ +--- +synopsis: Allow single quotes in nix-shell shebangs +prs: 8470 +credits: [ncfavier, horrors] +category: Improvements +--- + +Example: + +```bash +#! /usr/bin/env nix-shell +#! nix-shell -i bash --packages 'terraform.withPlugins (plugins: [ plugins.openstack ])' +``` diff --git a/doc/manual/rl-next/ssh-ng-phase-reporting.md b/doc/manual/rl-next/ssh-ng-phase-reporting.md new file mode 100644 index 000000000..02f357410 --- /dev/null +++ b/doc/manual/rl-next/ssh-ng-phase-reporting.md @@ -0,0 +1,8 @@ +--- +synopsis: Include phase reporting in log file for ssh-ng builds +prs: 9280 +credits: r-vdp +category: Fixes +--- + +Store phase information of remote builds run via `ssh-ng` remotes in the local log file, matching logging behavior of local builds. diff --git a/doc/manual/rl-next/ssh-ng-substitute.md b/doc/manual/rl-next/ssh-ng-substitute.md new file mode 100644 index 000000000..20f79c106 --- /dev/null +++ b/doc/manual/rl-next/ssh-ng-substitute.md @@ -0,0 +1,9 @@ +--- +synopsis: Fix `ssh-ng://` remotes not respecting `--substitute-on-destination` +prs: 9600 +credits: SharzyL +category: Fixes +--- + +`nix copy ssh-ng://` now respects `--substitute-on-destination`, as does `nix-copy-closure` and other commands that operate on remote `ssh-ng` stores. +Previously this was always set by `builders-use-substitutes` setting. diff --git a/doc/manual/rl-next/warn-ignored-client-settings.md b/doc/manual/rl-next/warn-ignored-client-settings.md new file mode 100644 index 000000000..88edd27fb --- /dev/null +++ b/doc/manual/rl-next/warn-ignored-client-settings.md @@ -0,0 +1,9 @@ +--- +synopsis: Warn about ignored client settings +cls: 1026 +credits: jade +category: Improvements +--- + +Emit a warning for every client-provided setting the daemon ignores because the requesting client is not run by a trusted user. +Previously this was only a debug message. diff --git a/doc/manual/src/language/derivations.md b/doc/manual/src/language/derivations.md index c10e8149d..28e686889 100644 --- a/doc/manual/src/language/derivations.md +++ b/doc/manual/src/language/derivations.md @@ -125,7 +125,7 @@ The builder is executed as follows: directory (typically, `/nix/store`). - `NIX_ATTRS_JSON_FILE` & `NIX_ATTRS_SH_FILE` if `__structuredAttrs` - is set to `true` for the dervation. A detailed explanation of this + is set to `true` for the derivation. A detailed explanation of this behavior can be found in the [section about structured attrs](./advanced-attributes.md#adv-attr-structuredAttrs). diff --git a/maintainers/README.md b/maintainers/README.md deleted file mode 100644 index 0d520cb0c..000000000 --- a/maintainers/README.md +++ /dev/null @@ -1,146 +0,0 @@ -# Nix maintainers team - -## Motivation - -The team's main responsibility is to set a direction for the development of Nix and ensure that the code is in good shape. - -We aim to achieve this by improving the contributor experience and attracting more maintainers – that is, by helping other people contributing to Nix and eventually taking responsibility – in order to scale the development process to match users' needs. - -### Objectives - -- It is obvious what is worthwhile to work on. -- It is easy to find the right place in the code to make a change. -- It is clear what is expected of a pull request. -- It is predictable how to get a change merged and released. - -### Tasks - -- Establish, communicate, and maintain a technical roadmap -- Improve documentation targeted at contributors - - Record architecture and design decisions - - Elaborate contribution guides and abide to them - - Define and assert quality criteria for contributions -- Maintain the issue tracker and triage pull requests -- Help contributors succeed with pull requests that address roadmap milestones -- Manage the release lifecycle -- Regularly publish reports on work done -- Engage with third parties in the interest of the project -- Ensure the required maintainer capacity for all of the above - -## Members - -- Eelco Dolstra (@edolstra) – Team lead -- Théophane Hufschmitt (@thufschmitt) -- Valentin Gagarin (@fricklerhandwerk) -- Thomas Bereknyei (@tomberek) -- Robert Hensing (@roberth) -- John Ericson (@Ericson2314) - -## Meeting protocol - -The team meets twice a week: - -- Discussion meeting: [Fridays 13:00-14:00 CET](https://calendar.google.com/calendar/event?eid=MHNtOGVuNWtrZXNpZHR2bW1sM3QyN2ZjaGNfMjAyMjExMjVUMTIwMDAwWiBiOW81MmZvYnFqYWs4b3E4bGZraGczdDBxZ0Bn) - - 1. Triage issues and pull requests from the [No Status](#no-status) column (30 min) - 2. Discuss issues and pull requests from the [To discuss](#to-discuss) column (30 min) - -- Work meeting: [Mondays 13:00-15:00 CET](https://calendar.google.com/calendar/event?eid=NTM1MG1wNGJnOGpmOTZhYms3bTB1bnY5cWxfMjAyMjExMjFUMTIwMDAwWiBiOW81MmZvYnFqYWs4b3E4bGZraGczdDBxZ0Bn) - - 1. Code review on pull requests from [In review](#in-review). - 2. Other chores and tasks. - -Meeting notes are collected on a [collaborative scratchpad](https://pad.lassul.us/Cv7FpYx-Ri-4VjUykQOLAw), and published on Discourse under the [Nix category](https://discourse.nixos.org/c/dev/nix/50). - -## Project board protocol - -The team uses a [GitHub project board](https://github.com/orgs/NixOS/projects/19/views/1) for tracking its work. - -Items on the board progress through the following states: - -### No Status - -During the discussion meeting, the team triages new items. -To be considered, issues and pull requests must have a high-level description to provide the whole team with the necessary context at a glance. - -On every meeting, at least one item from each of the following categories is inspected: - -1. [critical](https://github.com/NixOS/nix/labels/critical) -2. [security](https://github.com/NixOS/nix/labels/security) -3. [regression](https://github.com/NixOS/nix/labels/regression) -4. [bug](https://github.com/NixOS/nix/issues?q=is%3Aopen+label%3Abug+sort%3Areactions-%2B1-desc) -5. [tests of existing functionality](https://github.com/NixOS/nix/issues?q=is%3Aopen+label%3Atests+-label%3Afeature+sort%3Areactions-%2B1-desc) - -- [oldest pull requests](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+sort%3Acreated-asc) -- [most popular pull requests](https://github.com/NixOS/nix/pulls?q=is%3Apr+is%3Aopen+sort%3Areactions-%2B1-desc) -- [oldest issues](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Acreated-asc) -- [most popular issues](https://github.com/NixOS/nix/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc) - -Team members can also add pull requests or issues they would like the whole team to consider. -To ensure process quality and reliability, all non-trivial pull requests must be triaged before merging. - -If there is disagreement on the general idea behind an issue or pull request, it is moved to [To discuss](#to-discuss). -Otherwise, the issue or pull request in questions get the label [`idea approved`](https://github.com/NixOS/nix/labels/idea%20approved). -For issues this means that an implementation is welcome and will be prioritised for review. -For pull requests this means that: -- Unfinished work is encouraged to be continued. -- A reviewer is assigned to take responsibility for getting the pull request merged. - The item is moved to the [Assigned](#assigned) column. -- If needed, the team can decide to do a collarorative review. - Then the item is moved to the [In review](#in-review) column, and review session is scheduled. - -What constitutes a trivial pull request is up to maintainers' judgement. - -### To discuss - -Pull requests and issues that are deemed important and controversial are discussed by the team during discussion meetings. - -This may be where the merit of the change itself or the implementation strategy is contested by a team member. - -As a general guideline, the order of items is determined as follows: - -- Prioritise pull requests over issues - - Contributors who took the time to implement concrete change proposals should not wait indefinitely. - -- Prioritise fixing bugs and testing over documentation, improvements or new features - - The team values stability and accessibility higher than raw functionality. - -- Interleave issues and PRs - - This way issues without attempts at a solution get a chance to get addressed. - -### In review - -Pull requests in this column are reviewed together during work meetings. -This is both for spreading implementation knowledge and for establishing common values in code reviews. - -When the overall direction is agreed upon, even when further changes are required, the pull request is assigned to one team member. -If significant changes are requested or reviewers cannot come to a conclusion in reasonable time, the pull request is [marked as draft](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#converting-a-pull-request-to-a-draft). - -### Assigned - -One team member is assigned to each of these pull requests. -They will communicate with the authors, and make the final approval once all remaining issues are addressed. - -If more substantive issues arise, the assignee can move the pull request back to [To discuss](#to-discuss) or [In review](#in-review) to involve the team again. - -### Flowchart - -The process is illustrated in the following diagram: - -```mermaid -flowchart TD - discuss[To discuss] - - review[To review] - - New --> |Disagreement on idea| discuss - New & discuss --> |Consensus on idea| review - - review --> |Consensus on implementation| Assigned - - Assigned --> |Implementation issues arise| review - Assigned --> |Remaining issues fixed| Merged -``` diff --git a/maintainers/backporting.md b/maintainers/backporting.md deleted file mode 100644 index 2424050c8..000000000 --- a/maintainers/backporting.md +++ /dev/null @@ -1,12 +0,0 @@ - -# Backporting - -To [automatically backport a pull request](https://github.com/NixOS/nix/blob/master/.github/workflows/backport.yml) to a release branch once it's merged, assign it a label of the form [`backport <branch>`](https://github.com/NixOS/nix/labels?q=backport). - -Since [GitHub Actions workflows will not trigger other workflows](https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow), checks on the automatic backport need to be triggered by another actor. -This is achieved by closing and reopening the backport pull request. - -This specifically affects the [`installer_test`] check. -Note that it only runs after the other tests, so it may take a while to appear. - -[`installer_test`]: https://github.com/NixOS/nix/blob/895dfc656a21f6252ddf48df0d1f215effa04ecb/.github/workflows/ci.yml#L70-L91 diff --git a/maintainers/release-process.md b/maintainers/release-process.md deleted file mode 100644 index f2b60d8e7..000000000 --- a/maintainers/release-process.md +++ /dev/null @@ -1,196 +0,0 @@ -# Nix release process - -## Release artifacts - -The release process is intended to create the following for each -release: - -* A Git tag - -* Binary tarballs in https://releases.nixos.org/?prefix=nix/ - -* Docker images - -* Closures in https://cache.nixos.org - -* (Optionally) Updated `fallback-paths.nix` in Nixpkgs - -* An updated manual on https://nixos.org/manual/nix/stable/ - -## Creating a new release from the `master` branch - -* Make sure that the [Hydra `master` jobset](https://hydra.nixos.org/jobset/nix/master) succeeds. - -* In a checkout of the Nix repo, make sure you're on `master` and run - `git pull`. - -* Compile the release notes by running - - ```console - $ git checkout -b release-notes - $ VERSION=X.YY ./maintainers/release-notes - ``` - - where `X.YY` is *without* the patch level, e.g. `2.12` rather than ~~`2.12.0`~~. - - A commit is created. - -* Proof-read / edit / rearrange the release notes if needed. Breaking changes - and highlights should go to the top. - -* Push. - - ```console - $ git push --set-upstream $REMOTE release-notes - ``` - -* Create a PR for `release-notes`. - -* Wait for the PR to be merged. - -* Create a branch for the release: - - ```console - $ git checkout master - $ git pull - $ git checkout -b $VERSION-maintenance - ``` - -* Mark the release as official: - - ```console - $ sed -e 's/officialRelease = false;/officialRelease = true;/' -i flake.nix - $ sed -e '/rl-next.md/ d' -i doc/manual/src/SUMMARY.md - ``` - - This removes the link to `rl-next.md` from the manual and sets - `officialRelease = true` in `flake.nix`. - -* Commit - -* Push the release branch: - - ```console - $ git push --set-upstream origin $VERSION-maintenance - ``` - -* Create a jobset for the release branch on Hydra as follows: - - * Go to the jobset of the previous release - (e.g. https://hydra.nixos.org/jobset/nix/maintenance-2.11). - - * Select `Actions -> Clone this jobset`. - - * Set identifier to `maintenance-$VERSION`. - - * Set description to `$VERSION release branch`. - - * Set flake URL to `github:NixOS/nix/$VERSION-maintenance`. - - * Hit `Create jobset`. - -* Wait for the new jobset to evaluate and build. If impatient, go to - the evaluation and select `Actions -> Bump builds to front of - queue`. - -* When the jobset evaluation has succeeded building, take note of the - evaluation ID (e.g. `1780832` in - `https://hydra.nixos.org/eval/1780832`). - -* Tag the release and upload the release artifacts to - [`releases.nixos.org`](https://releases.nixos.org/) and [Docker Hub](https://hub.docker.com/): - - ```console - $ IS_LATEST=1 ./maintainers/upload-release.pl <EVAL-ID> - ``` - - Note: `IS_LATEST=1` causes the `latest-release` branch to be - force-updated. This is used by the `nixos.org` website to get the - [latest Nix manual](https://nixos.org/manual/nixpkgs/unstable/). - - TODO: This script requires the right AWS credentials. Document. - - TODO: This script currently requires a - `/home/eelco/Dev/nix-pristine`. - - TODO: trigger nixos.org netlify: https://docs.netlify.com/configure-builds/build-hooks/ - -* Prepare for the next point release by editing `.version` to - e.g. - - ```console - $ echo 2.12.1 > .version - $ git commit -a -m 'Bump version' - $ git push - ``` - - Commit and push this to the maintenance branch. - -* Bump the version of `master`: - - ```console - $ git checkout master - $ git pull - $ NEW_VERSION=2.13.0 - $ echo $NEW_VERSION > .version - $ git checkout -b bump-$NEW_VERSION - $ git commit -a -m 'Bump version' - $ git push --set-upstream origin bump-$NEW_VERSION - ``` - - Make a pull request and auto-merge it. - -* Create a milestone for the next release, move all unresolved issues - from the previous milestone, and close the previous milestone. Set - the date for the next milestone 6 weeks from now. - -* Create a backport label. - -* Post an [announcement on Discourse](https://discourse.nixos.org/c/announcements/8), including the contents of - `rl-$VERSION.md`. - -## Creating a point release - -* Checkout. - - ```console - $ git checkout XX.YY-maintenance - ``` - -* Determine the next patch version. - - ```console - $ export VERSION=XX.YY.ZZ - ``` - -* Update release notes. - - ```console - $ ./maintainers/release-notes - ``` - -* Push. - - ```console - $ git push - ``` - -* Wait for the desired evaluation of the maintenance jobset to finish - building. - -* Run - - ```console - $ IS_LATEST=1 ./maintainers/upload-release.pl <EVAL-ID> - ``` - - Omit `IS_LATEST=1` when creating a point release that is not on the - most recent stable branch. This prevents `nixos.org` to going back - to an older release. - -* Bump the version number of the release branch as above (e.g. to - `2.12.2`). - -## Recovering from mistakes - -`upload-release.pl` should be idempotent. For instance a wrong `IS_LATEST` value can be fixed that way, by running the script on the actual latest release. diff --git a/maintainers/upload-release.pl b/maintainers/upload-release.pl deleted file mode 100755 index ebc536f12..000000000 --- a/maintainers/upload-release.pl +++ /dev/null @@ -1,256 +0,0 @@ -#! /usr/bin/env nix-shell -#! nix-shell -i perl -p perl perlPackages.LWPUserAgent perlPackages.LWPProtocolHttps perlPackages.FileSlurp perlPackages.NetAmazonS3 gnupg1 - -use strict; -use Data::Dumper; -use File::Basename; -use File::Path; -use File::Slurp; -use File::Copy; -use JSON::PP; -use LWP::UserAgent; -use Net::Amazon::S3; - -my $evalId = $ARGV[0] or die "Usage: $0 EVAL-ID\n"; - -my $releasesBucketName = "nix-releases"; -my $channelsBucketName = "nix-channels"; - -my $TMPDIR = $ENV{'TMPDIR'} // "/tmp"; - -my $isLatest = ($ENV{'IS_LATEST'} // "") eq "1"; - -# FIXME: cut&paste from nixos-channel-scripts. -sub fetch { - my ($url, $type) = @_; - - my $ua = LWP::UserAgent->new; - $ua->default_header('Accept', $type) if defined $type; - - my $response = $ua->get($url); - die "could not download $url: ", $response->status_line, "\n" unless $response->is_success; - - return $response->decoded_content; -} - -my $evalUrl = "https://hydra.nixos.org/eval/$evalId"; -my $evalInfo = decode_json(fetch($evalUrl, 'application/json')); -#print Dumper($evalInfo); -my $flakeUrl = $evalInfo->{flake} or die; -my $flakeInfo = decode_json(`nix flake metadata --json "$flakeUrl"` or die); -my $nixRev = $flakeInfo->{revision} or die; - -my $buildInfo = decode_json(fetch("$evalUrl/job/build.x86_64-linux", 'application/json')); -#print Dumper($buildInfo); - -my $releaseName = $buildInfo->{nixname}; -$releaseName =~ /nix-(.*)$/ or die; -my $version = $1; - -print STDERR "Flake URL is $flakeUrl, Nix revision is $nixRev, version is $version\n"; - -my $releaseDir = "nix/$releaseName"; - -my $tmpDir = "$TMPDIR/nix-release/$releaseName"; -File::Path::make_path($tmpDir); - -my $narCache = "$TMPDIR/nar-cache"; -File::Path::make_path($narCache); - -my $binaryCache = "https://cache.nixos.org/?local-nar-cache=$narCache"; - -# S3 setup. -my $aws_access_key_id = $ENV{'AWS_ACCESS_KEY_ID'} or die "No AWS_ACCESS_KEY_ID given."; -my $aws_secret_access_key = $ENV{'AWS_SECRET_ACCESS_KEY'} or die "No AWS_SECRET_ACCESS_KEY given."; - -my $s3 = Net::Amazon::S3->new( - { aws_access_key_id => $aws_access_key_id, - aws_secret_access_key => $aws_secret_access_key, - retry => 1, - host => "s3-eu-west-1.amazonaws.com", - }); - -my $releasesBucket = $s3->bucket($releasesBucketName) or die; - -my $s3_us = Net::Amazon::S3->new( - { aws_access_key_id => $aws_access_key_id, - aws_secret_access_key => $aws_secret_access_key, - retry => 1, - }); - -my $channelsBucket = $s3_us->bucket($channelsBucketName) or die; - -sub getStorePath { - my ($jobName, $output) = @_; - my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json')); - return $buildInfo->{buildoutputs}->{$output or "out"}->{path} or die "cannot get store path for '$jobName'"; -} - -sub copyManual { - my $manual = getStorePath("build.x86_64-linux", "doc"); - print "$manual\n"; - - my $manualNar = "$tmpDir/$releaseName-manual.nar.xz"; - print "$manualNar\n"; - - unless (-e $manualNar) { - system("NIX_REMOTE=$binaryCache nix store dump-path '$manual' | xz > '$manualNar'.tmp") == 0 - or die "unable to fetch $manual\n"; - rename("$manualNar.tmp", $manualNar) or die; - } - - unless (-e "$tmpDir/manual") { - system("xz -d < '$manualNar' | nix-store --restore $tmpDir/manual.tmp") == 0 - or die "unable to unpack $manualNar\n"; - rename("$tmpDir/manual.tmp/share/doc/nix/manual", "$tmpDir/manual") or die; - system("rm -rf '$tmpDir/manual.tmp'") == 0 or die; - } - - system("aws s3 sync '$tmpDir/manual' s3://$releasesBucketName/$releaseDir/manual") == 0 - or die "syncing manual to S3\n"; -} - -copyManual; - -sub downloadFile { - my ($jobName, $productNr, $dstName) = @_; - - my $buildInfo = decode_json(fetch("$evalUrl/job/$jobName", 'application/json')); - #print STDERR "$jobName: ", Dumper($buildInfo), "\n"; - - my $srcFile = $buildInfo->{buildproducts}->{$productNr}->{path} or die "job '$jobName' lacks product $productNr\n"; - $dstName //= basename($srcFile); - my $tmpFile = "$tmpDir/$dstName"; - - if (!-e $tmpFile) { - print STDERR "downloading $srcFile to $tmpFile...\n"; - - my $fileInfo = decode_json(`NIX_REMOTE=$binaryCache nix store ls --json '$srcFile'`); - - $srcFile = $fileInfo->{target} if $fileInfo->{type} eq 'symlink'; - - #print STDERR $srcFile, " ", Dumper($fileInfo), "\n"; - - system("NIX_REMOTE=$binaryCache nix store cat '$srcFile' > '$tmpFile'.tmp") == 0 - or die "unable to fetch $srcFile\n"; - rename("$tmpFile.tmp", $tmpFile) or die; - } - - my $sha256_expected = $buildInfo->{buildproducts}->{$productNr}->{sha256hash}; - my $sha256_actual = `nix hash file --base16 --type sha256 '$tmpFile'`; - chomp $sha256_actual; - if (defined($sha256_expected) && $sha256_expected ne $sha256_actual) { - print STDERR "file $tmpFile is corrupt, got $sha256_actual, expected $sha256_expected\n"; - exit 1; - } - - write_file("$tmpFile.sha256", $sha256_actual); - - return $sha256_expected; -} - -downloadFile("binaryTarball.i686-linux", "1"); -downloadFile("binaryTarball.x86_64-linux", "1"); -downloadFile("binaryTarball.aarch64-linux", "1"); -downloadFile("binaryTarball.x86_64-darwin", "1"); -downloadFile("binaryTarball.aarch64-darwin", "1"); -downloadFile("binaryTarballCross.x86_64-linux.armv6l-linux", "1"); -downloadFile("binaryTarballCross.x86_64-linux.armv7l-linux", "1"); -downloadFile("installerScript", "1"); - -# Upload docker images to dockerhub. -my $dockerManifest = ""; -my $dockerManifestLatest = ""; - -for my $platforms (["x86_64-linux", "amd64"], ["aarch64-linux", "arm64"]) { - my $system = $platforms->[0]; - my $dockerPlatform = $platforms->[1]; - my $fn = "nix-$version-docker-image-$dockerPlatform.tar.gz"; - downloadFile("dockerImage.$system", "1", $fn); - - print STDERR "loading docker image for $dockerPlatform...\n"; - system("docker load -i $tmpDir/$fn") == 0 or die; - - my $tag = "nixos/nix:$version-$dockerPlatform"; - my $latestTag = "nixos/nix:latest-$dockerPlatform"; - - print STDERR "tagging $version docker image for $dockerPlatform...\n"; - system("docker tag nix:$version $tag") == 0 or die; - - if ($isLatest) { - print STDERR "tagging latest docker image for $dockerPlatform...\n"; - system("docker tag nix:$version $latestTag") == 0 or die; - } - - print STDERR "pushing $version docker image for $dockerPlatform...\n"; - system("docker push -q $tag") == 0 or die; - - if ($isLatest) { - print STDERR "pushing latest docker image for $dockerPlatform...\n"; - system("docker push -q $latestTag") == 0 or die; - } - - $dockerManifest .= " --amend $tag"; - $dockerManifestLatest .= " --amend $latestTag" -} - -print STDERR "creating multi-platform docker manifest...\n"; -system("docker manifest rm nixos/nix:$version"); -system("docker manifest create nixos/nix:$version $dockerManifest") == 0 or die; -if ($isLatest) { - print STDERR "creating latest multi-platform docker manifest...\n"; - system("docker manifest rm nixos/nix:latest"); - system("docker manifest create nixos/nix:latest $dockerManifestLatest") == 0 or die; -} - -print STDERR "pushing multi-platform docker manifest...\n"; -system("docker manifest push nixos/nix:$version") == 0 or die; - -if ($isLatest) { - print STDERR "pushing latest multi-platform docker manifest...\n"; - system("docker manifest push nixos/nix:latest") == 0 or die; -} - -# Upload nix-fallback-paths.nix. -write_file("$tmpDir/fallback-paths.nix", - "{\n" . - " x86_64-linux = \"" . getStorePath("build.x86_64-linux") . "\";\n" . - " i686-linux = \"" . getStorePath("build.i686-linux") . "\";\n" . - " aarch64-linux = \"" . getStorePath("build.aarch64-linux") . "\";\n" . - " x86_64-darwin = \"" . getStorePath("build.x86_64-darwin") . "\";\n" . - " aarch64-darwin = \"" . getStorePath("build.aarch64-darwin") . "\";\n" . - "}\n"); - -# Upload release files to S3. -for my $fn (glob "$tmpDir/*") { - my $name = basename($fn); - next if $name eq "manual"; - my $dstKey = "$releaseDir/" . $name; - unless (defined $releasesBucket->head_key($dstKey)) { - print STDERR "uploading $fn to s3://$releasesBucketName/$dstKey...\n"; - - my $configuration = (); - $configuration->{content_type} = "application/octet-stream"; - - if ($fn =~ /.sha256|install|\.nix$/) { - $configuration->{content_type} = "text/plain"; - } - - $releasesBucket->add_key_filename($dstKey, $fn, $configuration) - or die $releasesBucket->err . ": " . $releasesBucket->errstr; - } -} - -# Update the "latest" symlink. -$channelsBucket->add_key( - "nix-latest/install", "", - { "x-amz-website-redirect-location" => "https://releases.nixos.org/$releaseDir/install" }) - or die $channelsBucket->err . ": " . $channelsBucket->errstr - if $isLatest; - -# Tag the release in Git. -chdir("/home/eelco/Dev/nix-pristine") or die; -system("git remote update origin") == 0 or die; -system("git tag --force --sign $version $nixRev -m 'Tagging release $version'") == 0 or die; -system("git push --tags") == 0 or die; -system("git push --force-with-lease origin $nixRev:refs/heads/latest-release") == 0 or die if $isLatest; diff --git a/misc/pre-commit.nix b/misc/pre-commit.nix index ea39bc21d..ed2b152a3 100644 --- a/misc/pre-commit.nix +++ b/misc/pre-commit.nix @@ -66,6 +66,18 @@ pre-commit-run { ${lib.getExe pkgs.build-release-notes} --change-authors doc/manual/change-authors.yml doc/manual/rl-next doc/manual/rl-next-dev ''; }; + change-authors-sorted = { + enable = true; + package = pkgs.yq; + files = ''^doc/manual/change-authors\.yml''; + entry = "${pkgs.writeShellScript "change-authors-sorted" '' + set -euo pipefail + shopt -s inherit_errexit + + echo "changes necessary to sort $1:" + diff -U3 <(${lib.getExe pkgs.yq} -y . "$1") <(${lib.getExe pkgs.yq} -Sy . "$1") + ''}"; + }; check-headers = { enable = true; package = pkgs.check-headers; diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc index 615f70945..46bdd411b 100644 --- a/src/libcmd/installable-flake.cc +++ b/src/libcmd/installable-flake.cc @@ -105,9 +105,14 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths() fmt("while evaluating the flake output attribute '%s'", attrPath))) { return { *derivedPathWithInfo }; + } else { + throw Error( + "expected flake output attribute '%s' to be a derivation or path but found %s: %s", + attrPath, + showType(v), + ValuePrinter(*this->state, v, errorPrintOptions) + ); } - else - throw Error("flake output attribute '%s' is not a derivation or path", attrPath); } auto drvPath = attr->forceDerivation(); diff --git a/src/libcmd/repl-interacter.cc b/src/libcmd/repl-interacter.cc index 829383add..41589cda1 100644 --- a/src/libcmd/repl-interacter.cc +++ b/src/libcmd/repl-interacter.cc @@ -1,6 +1,8 @@ #include <cstdio> #include <iostream> #include <string> +#include <string_view> +#include <cerrno> #ifdef READLINE #include <readline/history.h> @@ -175,14 +177,43 @@ bool ReadlineLikeInteracter::getLine(std::string & input, ReplPromptType promptT if (!s) return false; + + this->writeHistory(); input += s; input += '\n'; return true; } +void ReadlineLikeInteracter::writeHistory() +{ + int ret = write_history(historyFile.c_str()); + int writeHistErr = errno; + + if (ret == 0) { + return; + } + + // If the open fails, editline returns EOF. If the close fails, editline + // forwards the return value of fclose(), which is EOF on error. + // readline however, returns the errno. + // So if we didn't get exactly EOF, then consider the return value the error + // code; otherwise use the errno we saved above. + // https://github.com/troglobit/editline/issues/66 + if (ret != EOF) { + writeHistErr = ret; + } + + // In any of these cases, we should explicitly ignore the error, but log + // them so the user isn't confused why their history is getting eaten. + + std::string_view const errMsg(std::strerror(writeHistErr)); + warn("ignoring error writing repl history to %s: %s", this->historyFile, errMsg); + +} + ReadlineLikeInteracter::~ReadlineLikeInteracter() { - write_history(historyFile.c_str()); + this->writeHistory(); } AutomationInteracter::Guard AutomationInteracter::init(detail::ReplCompleterMixin *) diff --git a/src/libcmd/repl-interacter.hh b/src/libcmd/repl-interacter.hh index c31b1a1e6..8f815fceb 100644 --- a/src/libcmd/repl-interacter.hh +++ b/src/libcmd/repl-interacter.hh @@ -42,6 +42,11 @@ public: } virtual Guard init(detail::ReplCompleterMixin * repl) override; virtual bool getLine(std::string & input, ReplPromptType promptType) override; + /** Writes the current history to the history file. + * + * This function logs but ignores errors from readline's write_history(). + */ + virtual void writeHistory(); virtual ~ReadlineLikeInteracter() override; }; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 525c25560..46b6d57ed 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -90,7 +90,8 @@ struct NixRepl Strings loadedFiles; std::function<AnnotatedValues()> getValues; - const static int envSize = 32768; + // Uses 8MiB of memory. It's fine. + const static int envSize = 1 << 20; std::shared_ptr<StaticEnv> staticEnv; Env * env; int displ; @@ -375,6 +376,9 @@ StringSet NixRepl::completePrefix(const std::string & prefix) // Quietly ignore evaluation errors. } catch (BadURL & e) { // Quietly ignore BadURL flake-related errors. + } catch (SysError & e) { + // Quietly ignore system errors which can for example be raised by + // a non-existent file being `import`-ed. } } @@ -854,6 +858,11 @@ void NixRepl::loadReplOverlays() replInitFilesFunction->determinePos(noPos) ); + // n.b. this does in fact load the stuff into the environment twice (once + // from the superset of the environment returned by repl-overlays and once + // from the thing itself), but it's not fixable because clearEnv here could + // lead to dangling references to the old environment in thunks. + // https://git.lix.systems/lix-project/lix/issues/337#issuecomment-3745 addAttrsToScope(newAttrs); } diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc index 1eec8b316..36692aafb 100644 --- a/src/libexpr/primops/context.cc +++ b/src/libexpr/primops/context.cc @@ -36,7 +36,7 @@ static RegisterPrimOp primop_hasContext({ > **Example** > - > Many operations require a string context to be empty because they are intended only to work with "regular" strings, and also to help users avoid unintentionally loosing track of string context elements. + > Many operations require a string context to be empty because they are intended only to work with "regular" strings, and also to help users avoid unintentionally losing track of string context elements. > `builtins.hasContext` can help create better domain-specific errors in those case. > > ```nix @@ -137,14 +137,14 @@ static RegisterPrimOp primop_addDrvOutputDependencies({ .name = "__addDrvOutputDependencies", .args = {"s"}, .doc = R"( - Create a copy of the given string where a single consant string context element is turned into a "derivation deep" string context element. + Create a copy of the given string where a single constant string context element is turned into a "derivation deep" string context element. The store path that is the constant string context element should point to a valid derivation, and end in `.drv`. The original string context element must not be empty or have multiple elements, and it must not have any other type of element other than a constant or derivation deep element. The latter is supported so this function is idempotent. - This is the opposite of [`builtins.unsafeDiscardOutputDependency`](#builtins-addDrvOutputDependencies). + This is the opposite of [`builtins.unsafeDiscardOutputDependency`](#builtins-unsafeDiscardOutputDependency). )", .fun = prim_addDrvOutputDependencies }); diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc index 0c8ecac9d..672e1e0bc 100644 --- a/src/libfetchers/cache.cc +++ b/src/libfetchers/cache.cc @@ -34,7 +34,16 @@ struct CacheImpl : Cache auto state(_state.lock()); auto dbPath = getCacheDir() + "/nix/fetcher-cache-v1.sqlite"; - createDirs(dirOf(dbPath)); + // It would be silly to fail fetcher operations if e.g. the user has no + // XDG_CACHE_HOME and their HOME directory doesn't exist. + // We'll warn the user if that happens, but fallback to an in-memory + // backend for the SQLite database. + try { + createDirs(dirOf(dbPath)); + } catch (SysError const & ex) { + warn("ignoring error initializing Lix fetcher cache: %s", ex.what()); + dbPath = ":memory:"; + } state->db = SQLite(dbPath); state->db.isCache(); diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 3f24da276..5fa5deb7c 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -786,13 +786,6 @@ void DerivationGoal::tryLocalBuild() { } -static void chmod_(const Path & path, mode_t mode) -{ - if (chmod(path.c_str(), mode) == -1) - throw SysError("setting permissions on '%s'", path); -} - - /* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if it's a directory and we're not root (to be able to update the directory's parent link ".."). */ @@ -803,12 +796,12 @@ static void movePath(const Path & src, const Path & dst) bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR)); if (changePerm) - chmod_(src, st.st_mode | S_IWUSR); + chmodPath(src, st.st_mode | S_IWUSR); renameFile(src, dst); if (changePerm) - chmod_(dst, st.st_mode); + chmodPath(dst, st.st_mode); } diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index cdbd0f5a7..5c36a3ac2 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -272,12 +272,6 @@ void LocalDerivationGoal::tryLocalBuild() started(); } -static void chmod_(const Path & path, mode_t mode) -{ - if (chmod(path.c_str(), mode) == -1) - throw SysError("setting permissions on '%s'", path); -} - /* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if it's a directory and we're not root (to be able to update the @@ -289,12 +283,12 @@ static void movePath(const Path & src, const Path & dst) bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR)); if (changePerm) - chmod_(src, st.st_mode | S_IWUSR); + chmodPath(src, st.st_mode | S_IWUSR); renameFile(src, dst); if (changePerm) - chmod_(dst, st.st_mode); + chmodPath(dst, st.st_mode); } @@ -696,7 +690,7 @@ void LocalDerivationGoal::startBuilder() instead.) */ Path chrootTmpDir = chrootRootDir + "/tmp"; createDirs(chrootTmpDir); - chmod_(chrootTmpDir, 01777); + chmodPath(chrootTmpDir, 01777); /* Create a /etc/passwd with entries for the build user and the nobody account. The latter is kind of a hack to support @@ -721,7 +715,7 @@ void LocalDerivationGoal::startBuilder() build user. */ Path chrootStoreDir = chrootRootDir + worker.store.storeDir; createDirs(chrootStoreDir); - chmod_(chrootStoreDir, 01775); + chmodPath(chrootStoreDir, 01775); if (buildUser && chown(chrootStoreDir.c_str(), 0, buildUser->getGID()) == -1) throw SysError("cannot change ownership of '%1%'", chrootStoreDir); @@ -1862,7 +1856,7 @@ void LocalDerivationGoal::runChild() auto dst = chrootRootDir + i.first; createDirs(dirOf(dst)); writeFile(dst, std::string_view((const char *) sh, sizeof(sh))); - chmod_(dst, 0555); + chmodPath(dst, 0555); } else #endif doBind(i.second.source, chrootRootDir + i.first, i.second.optional); @@ -1900,7 +1894,7 @@ void LocalDerivationGoal::runChild() /* Make sure /dev/pts/ptmx is world-writable. With some Linux versions, it is created with permissions 0. */ - chmod_(chrootRootDir + "/dev/pts/ptmx", 0666); + chmodPath(chrootRootDir + "/dev/pts/ptmx", 0666); } else { if (errno != EINVAL) throw SysError("mounting /dev/pts"); @@ -1911,7 +1905,7 @@ void LocalDerivationGoal::runChild() /* Make /etc unwritable */ if (!parsedDrv->useUidRange()) - chmod_(chrootRootDir + "/etc", 0555); + chmodPath(chrootRootDir + "/etc", 0555); /* Unshare this mount namespace. This is necessary because pivot_root() below changes the root of the mount diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc index 00536c1e1..a18c54ebf 100644 --- a/src/libutil/archive.cc +++ b/src/libutil/archive.cc @@ -389,13 +389,4 @@ void copyNAR(Source & source, Sink & sink) } -void copyPath(const Path & from, const Path & to) -{ - auto source = sinkToSource([&](Sink & sink) { - dumpPath(from, sink); - }); - restorePath(to, *source); -} - - } diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh index 2cf164a41..017b6633c 100644 --- a/src/libutil/archive.hh +++ b/src/libutil/archive.hh @@ -124,8 +124,6 @@ void restorePath(const Path & path, Source & source); */ void copyNAR(Source & source, Sink & sink); -void copyPath(const Path & from, const Path & to); - inline constexpr std::string_view narVersionMagic1 = "nix-archive-1"; diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 924366580..323365d65 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -110,6 +110,8 @@ protected: public: BaseError(const BaseError &) = default; + BaseError & operator=(BaseError const & rhs) = default; + template<typename... Args> BaseError(unsigned int status, const Args & ... args) : err { .level = lvlError, .msg = HintFmt(args...), .status = status } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index bc2dd1802..2c0fcc897 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -184,6 +184,11 @@ Path canonPath(PathView path, bool resolveSymlinks) return s.empty() ? "/" : std::move(s); } +void chmodPath(const Path & path, mode_t mode) +{ + if (chmod(path.c_str(), mode) == -1) + throw SysError("setting permissions on '%s'", path); +} Path dirOf(const PathView path) { @@ -1799,8 +1804,7 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) bind(fdSocket.get(), path); - if (chmod(path.c_str(), mode) == -1) - throw SysError("changing permissions on '%1%'", path); + chmodPath(path.c_str(), mode); if (listen(fdSocket.get(), 100) == -1) throw SysError("cannot listen on socket '%1%'", path); diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 914d6cce0..14868776c 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -78,6 +78,13 @@ Path absPath(Path path, Path canonPath(PathView path, bool resolveSymlinks = false); /** + * Change the permissions of a path + * Not called `chmod` as it shadows and could be confused with + * `int chmod(char *, mode_t)`, which does not handle errors + */ +void chmodPath(const Path & path, mode_t mode); + +/** * @return The directory part of the given canonical path, i.e., * everything before the final `/`. If the path is the root or an * immediate child thereof (e.g., `/foo`), this means `/` |