mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-22 05:56:15 +02:00
Merge remote-tracking branch 'upstream/master' into overlayfs-store
This commit is contained in:
commit
245af3ea02
538 changed files with 14282 additions and 7312 deletions
|
@ -17,7 +17,7 @@ indent_style = space
|
|||
indent_size = 2
|
||||
|
||||
# Match c++/shell/perl, set indent to spaces with width of four
|
||||
[*.{hpp,cc,hh,sh,pl}]
|
||||
[*.{hpp,cc,hh,sh,pl,xs}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
|
|
7
.github/CODEOWNERS
vendored
7
.github/CODEOWNERS
vendored
|
@ -14,5 +14,12 @@
|
|||
/doc @fricklerhandwerk
|
||||
*.md @fricklerhandwerk
|
||||
|
||||
# Documentation of built-in functions
|
||||
src/libexpr/primops.cc @fricklerhandwerk @roberth
|
||||
# Documentation on experimental features
|
||||
src/libutil/experimental-features.cc @fricklerhandwerk
|
||||
# Documentation on configuration settings
|
||||
src/libstore/globals.hh @fricklerhandwerk
|
||||
|
||||
# Libstore layer
|
||||
/src/libstore @thufschmitt
|
||||
|
|
31
.github/labeler.yml
vendored
31
.github/labeler.yml
vendored
|
@ -1,23 +1,30 @@
|
|||
"documentation":
|
||||
- doc/manual/*
|
||||
- src/nix/**/*.md
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "doc/manual/*"
|
||||
- any-glob-to-any-file: "src/nix/**/*.md"
|
||||
|
||||
"store":
|
||||
- src/libstore/store-api.*
|
||||
- src/libstore/*-store.*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "src/libstore/store-api.*"
|
||||
- any-glob-to-any-file: "src/libstore/*-store.*"
|
||||
|
||||
"fetching":
|
||||
- src/libfetchers/**/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "src/libfetchers/**/*"
|
||||
|
||||
"repl":
|
||||
- src/libcmd/repl.*
|
||||
- src/nix/repl.*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "src/libcmd/repl.*"
|
||||
- any-glob-to-any-file: "src/nix/repl.*"
|
||||
|
||||
"new-cli":
|
||||
- src/nix/**/*
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: "src/nix/**/*"
|
||||
|
||||
"with-tests":
|
||||
# Unit tests
|
||||
- src/*/tests/**/*
|
||||
# Functional and integration tests
|
||||
- tests/functional/**/*
|
||||
- changed-files:
|
||||
# Unit tests
|
||||
- any-glob-to-any-file: "src/*/tests/**/*"
|
||||
# Functional and integration tests
|
||||
- any-glob-to-any-file: "tests/functional/**/*"
|
||||
|
||||
|
|
2
.github/workflows/backport.yml
vendored
2
.github/workflows/backport.yml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
|||
fetch-depth: 0
|
||||
- name: Create backport PRs
|
||||
# should be kept in sync with `version`
|
||||
uses: zeebe-io/backport-action@v1.4.0
|
||||
uses: zeebe-io/backport-action@v2.2.0
|
||||
with:
|
||||
# Config README: https://github.com/zeebe-io/backport-action#backport-action
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
|
@ -20,12 +20,12 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: cachix/install-nix-action@v23
|
||||
- uses: cachix/install-nix-action@v24
|
||||
with:
|
||||
# The sandbox would otherwise be disabled by default on Darwin
|
||||
extra_nix_config: "sandbox = true"
|
||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v13
|
||||
if: needs.check_secrets.outputs.cachix == 'true'
|
||||
with:
|
||||
name: '${{ env.CACHIX_NAME }}'
|
||||
|
@ -62,10 +62,10 @@ jobs:
|
|||
with:
|
||||
fetch-depth: 0
|
||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||
- uses: cachix/install-nix-action@v23
|
||||
- uses: cachix/install-nix-action@v24
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v13
|
||||
with:
|
||||
name: '${{ env.CACHIX_NAME }}'
|
||||
signingKey: '${{ secrets.CACHIX_SIGNING_KEY }}'
|
||||
|
@ -84,7 +84,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||
- uses: cachix/install-nix-action@v23
|
||||
- uses: cachix/install-nix-action@v24
|
||||
with:
|
||||
install_url: '${{needs.installer.outputs.installerURL}}'
|
||||
install_options: "--tarball-url-prefix https://${{ env.CACHIX_NAME }}.cachix.org/serve"
|
||||
|
@ -114,12 +114,12 @@ jobs:
|
|||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: cachix/install-nix-action@v23
|
||||
- uses: cachix/install-nix-action@v24
|
||||
with:
|
||||
install_url: https://releases.nixos.org/nix/nix-2.13.3/install
|
||||
- run: echo CACHIX_NAME="$(echo $GITHUB_REPOSITORY-install-tests | tr "[A-Z]/" "[a-z]-")" >> $GITHUB_ENV
|
||||
- run: echo NIX_VERSION="$(nix --experimental-features 'nix-command flakes' eval .\#default.version | tr -d \")" >> $GITHUB_ENV
|
||||
- uses: cachix/cachix-action@v12
|
||||
- uses: cachix/cachix-action@v13
|
||||
if: needs.check_secrets.outputs.cachix == 'true'
|
||||
with:
|
||||
name: '${{ env.CACHIX_NAME }}'
|
||||
|
|
2
.github/workflows/labels.yml
vendored
2
.github/workflows/labels.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'NixOS'
|
||||
steps:
|
||||
- uses: actions/labeler@v4
|
||||
- uses: actions/labeler@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sync-labels: false
|
||||
|
|
15
.gitignore
vendored
15
.gitignore
vendored
|
@ -21,12 +21,16 @@ perl/Makefile.config
|
|||
/doc/manual/language.json
|
||||
/doc/manual/xp-features.json
|
||||
/doc/manual/src/SUMMARY.md
|
||||
/doc/manual/src/SUMMARY-rl-next.md
|
||||
/doc/manual/src/store/types/*
|
||||
!/doc/manual/src/store/types/index.md.in
|
||||
/doc/manual/src/command-ref/new-cli
|
||||
/doc/manual/src/command-ref/conf-file.md
|
||||
/doc/manual/src/command-ref/experimental-features-shortlist.md
|
||||
/doc/manual/src/contributing/experimental-feature-descriptions.md
|
||||
/doc/manual/src/language/builtins.md
|
||||
/doc/manual/src/language/builtin-constants.md
|
||||
/doc/manual/src/release-notes/rl-next.md
|
||||
|
||||
# /scripts/
|
||||
/scripts/nix-profile.sh
|
||||
|
@ -41,18 +45,18 @@ perl/Makefile.config
|
|||
/src/libexpr/parser-tab.hh
|
||||
/src/libexpr/parser-tab.output
|
||||
/src/libexpr/nix.tbl
|
||||
/src/libexpr/tests/libnixexpr-tests
|
||||
/tests/unit/libexpr/libnixexpr-tests
|
||||
|
||||
# /src/libstore/
|
||||
*.gen.*
|
||||
/src/libstore/tests/libnixstore-tests
|
||||
/tests/unit/libstore/libnixstore-tests
|
||||
|
||||
# /src/libutil/
|
||||
/src/libutil/tests/libnixutil-tests
|
||||
/tests/unit/libutil/libnixutil-tests
|
||||
|
||||
/src/nix/nix
|
||||
|
||||
/src/nix/doc
|
||||
/src/nix/generated-doc
|
||||
|
||||
# /src/nix-env/
|
||||
/src/nix-env/nix-env
|
||||
|
@ -144,3 +148,6 @@ result
|
|||
|
||||
# clangd and possibly more
|
||||
.cache/
|
||||
|
||||
# Mac OS
|
||||
.DS_Store
|
||||
|
|
2
.version
2
.version
|
@ -1 +1 @@
|
|||
2.19.0
|
||||
2.20.0
|
||||
|
|
29
Makefile
29
Makefile
|
@ -1,5 +1,7 @@
|
|||
-include Makefile.config
|
||||
clean-files += Makefile.config
|
||||
include mk/build-dir.mk
|
||||
|
||||
-include $(buildprefix)Makefile.config
|
||||
clean-files += $(buildprefix)Makefile.config
|
||||
|
||||
ifeq ($(ENABLE_BUILD), yes)
|
||||
makefiles = \
|
||||
|
@ -19,17 +21,17 @@ makefiles = \
|
|||
misc/zsh/local.mk \
|
||||
misc/systemd/local.mk \
|
||||
misc/launchd/local.mk \
|
||||
misc/upstart/local.mk \
|
||||
doc/manual/local.mk \
|
||||
doc/internal-api/local.mk
|
||||
misc/upstart/local.mk
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_BUILD)_$(ENABLE_TESTS), yes_yes)
|
||||
UNIT_TEST_ENV = _NIX_TEST_UNIT_DATA=unit-test-data
|
||||
makefiles += \
|
||||
src/libutil/tests/local.mk \
|
||||
src/libstore/tests/local.mk \
|
||||
src/libexpr/tests/local.mk
|
||||
tests/unit/libutil/local.mk \
|
||||
tests/unit/libutil-support/local.mk \
|
||||
tests/unit/libstore/local.mk \
|
||||
tests/unit/libstore-support/local.mk \
|
||||
tests/unit/libexpr/local.mk \
|
||||
tests/unit/libexpr-support/local.mk
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_TESTS), yes)
|
||||
|
@ -56,4 +58,11 @@ endif
|
|||
|
||||
include mk/lib.mk
|
||||
|
||||
GLOBAL_CXXFLAGS += -g -Wall -include config.h -std=c++2a -I src
|
||||
# Must be included after `mk/lib.mk` so rules refer to variables defined
|
||||
# by the library. Rules are not "lazy" like variables, unfortunately.
|
||||
ifeq ($(ENABLE_BUILD), yes)
|
||||
$(eval $(call include-sub-makefile, doc/manual/local.mk))
|
||||
$(eval $(call include-sub-makefile, doc/internal-api/local.mk))
|
||||
endif
|
||||
|
||||
GLOBAL_CXXFLAGS += -g -Wall -include $(buildprefix)config.h -std=c++2a -I src
|
||||
|
|
|
@ -8,15 +8,19 @@ CXX = @CXX@
|
|||
CXXFLAGS = @CXXFLAGS@
|
||||
CXXLTO = @CXXLTO@
|
||||
EDITLINE_LIBS = @EDITLINE_LIBS@
|
||||
ENABLE_BUILD = @ENABLE_BUILD@
|
||||
ENABLE_S3 = @ENABLE_S3@
|
||||
ENABLE_TESTS = @ENABLE_TESTS@
|
||||
GTEST_LIBS = @GTEST_LIBS@
|
||||
HAVE_LIBCPUID = @HAVE_LIBCPUID@
|
||||
HAVE_SECCOMP = @HAVE_SECCOMP@
|
||||
HOST_OS = @host_os@
|
||||
INSTALL_UNIT_TESTS = @INSTALL_UNIT_TESTS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBARCHIVE_LIBS = @LIBARCHIVE_LIBS@
|
||||
LIBBROTLI_LIBS = @LIBBROTLI_LIBS@
|
||||
LIBCURL_LIBS = @LIBCURL_LIBS@
|
||||
LIBGIT2_LIBS = @LIBGIT2_LIBS@
|
||||
LIBSECCOMP_LIBS = @LIBSECCOMP_LIBS@
|
||||
LOWDOWN_LIBS = @LOWDOWN_LIBS@
|
||||
OPENSSL_LIBS = @OPENSSL_LIBS@
|
||||
|
@ -28,6 +32,8 @@ SODIUM_LIBS = @SODIUM_LIBS@
|
|||
SQLITE3_LIBS = @SQLITE3_LIBS@
|
||||
bash = @bash@
|
||||
bindir = @bindir@
|
||||
checkbindir = @checkbindir@
|
||||
checklibdir = @checklibdir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
doc_generate = @doc_generate@
|
||||
|
@ -35,6 +41,7 @@ docdir = @docdir@
|
|||
embedded_sandbox_shell = @embedded_sandbox_shell@
|
||||
exec_prefix = @exec_prefix@
|
||||
includedir = @includedir@
|
||||
internal_api_docs = @internal_api_docs@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localstatedir = @localstatedir@
|
||||
|
@ -46,6 +53,3 @@ sandbox_shell = @sandbox_shell@
|
|||
storedir = @storedir@
|
||||
sysconfdir = @sysconfdir@
|
||||
system = @system@
|
||||
ENABLE_BUILD = @ENABLE_BUILD@
|
||||
ENABLE_TESTS = @ENABLE_TESTS@
|
||||
internal_api_docs = @internal_api_docs@
|
||||
|
|
12
boehmgc-traceable_allocator-public.diff
Normal file
12
boehmgc-traceable_allocator-public.diff
Normal file
|
@ -0,0 +1,12 @@
|
|||
diff --git a/include/gc_allocator.h b/include/gc_allocator.h
|
||||
index 597c7f13..587286be 100644
|
||||
--- a/include/gc_allocator.h
|
||||
+++ b/include/gc_allocator.h
|
||||
@@ -312,6 +312,7 @@ public:
|
||||
|
||||
template<>
|
||||
class traceable_allocator<void> {
|
||||
+public:
|
||||
typedef size_t size_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
typedef void* pointer;
|
23
configure.ac
23
configure.ac
|
@ -68,6 +68,9 @@ case "$host_os" in
|
|||
esac
|
||||
|
||||
|
||||
ENSURE_NO_GCC_BUG_80431
|
||||
|
||||
|
||||
# Check for pubsetbuf.
|
||||
AC_MSG_CHECKING([for pubsetbuf])
|
||||
AC_LANG_PUSH(C++)
|
||||
|
@ -164,6 +167,18 @@ AC_ARG_ENABLE(tests, AS_HELP_STRING([--disable-tests],[Do not build the tests]),
|
|||
ENABLE_TESTS=$enableval, ENABLE_TESTS=yes)
|
||||
AC_SUBST(ENABLE_TESTS)
|
||||
|
||||
AC_ARG_ENABLE(install-unit-tests, AS_HELP_STRING([--enable-install-unit-tests],[Install the unit tests for running later (default no)]),
|
||||
INSTALL_UNIT_TESTS=$enableval, INSTALL_UNIT_TESTS=no)
|
||||
AC_SUBST(INSTALL_UNIT_TESTS)
|
||||
|
||||
AC_ARG_WITH(check-bin-dir, AS_HELP_STRING([--with-check-bin-dir=PATH],[path to install unit tests for running later (defaults to $libexecdir/nix)]),
|
||||
checkbindir=$withval, checkbindir=$libexecdir/nix)
|
||||
AC_SUBST(checkbindir)
|
||||
|
||||
AC_ARG_WITH(check-lib-dir, AS_HELP_STRING([--with-check-lib-dir=PATH],[path to install unit tests for running later (defaults to $libdir)]),
|
||||
checklibdir=$withval, checklibdir=$libdir)
|
||||
AC_SUBST(checklibdir)
|
||||
|
||||
# Building without API docs is the default as Nix' C++ interfaces are internal and unstable.
|
||||
AC_ARG_ENABLE(internal_api_docs, AS_HELP_STRING([--enable-internal-api-docs],[Build API docs for Nix's internal unstable C++ interfaces]),
|
||||
internal_api_docs=$enableval, internal_api_docs=no)
|
||||
|
@ -267,6 +282,8 @@ case "$host_os" in
|
|||
esac
|
||||
AC_SUBST(HAVE_SECCOMP, [$have_seccomp])
|
||||
|
||||
# Optional dependencies for better normalizing file system data
|
||||
AC_CHECK_HEADERS[sys/xattr.h]
|
||||
|
||||
# Look for aws-cpp-sdk-s3.
|
||||
AC_LANG_PUSH(C++)
|
||||
|
@ -332,9 +349,15 @@ AC_ARG_ENABLE(doc-gen, AS_HELP_STRING([--disable-doc-gen],[disable documentation
|
|||
doc_generate=$enableval, doc_generate=yes)
|
||||
AC_SUBST(doc_generate)
|
||||
|
||||
|
||||
# Look for lowdown library.
|
||||
PKG_CHECK_MODULES([LOWDOWN], [lowdown >= 0.9.0], [CXXFLAGS="$LOWDOWN_CFLAGS $CXXFLAGS"])
|
||||
|
||||
|
||||
# Look for libgit2.
|
||||
PKG_CHECK_MODULES([LIBGIT2], [libgit2])
|
||||
|
||||
|
||||
# Setuid installations.
|
||||
AC_CHECK_FUNCS([setresuid setreuid lchown])
|
||||
|
||||
|
|
|
@ -39,17 +39,21 @@ INPUT = \
|
|||
src/libcmd \
|
||||
src/libexpr \
|
||||
src/libexpr/flake \
|
||||
src/libexpr/tests \
|
||||
src/libexpr/tests/value \
|
||||
tests/unit/libexpr \
|
||||
tests/unit/libexpr/value \
|
||||
tests/unit/libexpr/test \
|
||||
tests/unit/libexpr/test/value \
|
||||
src/libexpr/value \
|
||||
src/libfetchers \
|
||||
src/libmain \
|
||||
src/libstore \
|
||||
src/libstore/build \
|
||||
src/libstore/builtins \
|
||||
src/libstore/tests \
|
||||
tests/unit/libstore \
|
||||
tests/unit/libstore/test \
|
||||
src/libutil \
|
||||
src/libutil/tests \
|
||||
tests/unit/libutil \
|
||||
tests/unit/libutil/test \
|
||||
src/nix \
|
||||
src/nix-env \
|
||||
src/nix-store
|
||||
|
|
40
doc/manual/_redirects
Normal file
40
doc/manual/_redirects
Normal file
|
@ -0,0 +1,40 @@
|
|||
# redirect rules for paths (server-side) to prevent link rot.
|
||||
# see ./redirects.js for redirects based on URL fragments (client-side)
|
||||
#
|
||||
# concrete user story this supports:
|
||||
# - user finds URL to the manual for Nix x.y
|
||||
# - Nix x.z (z > y) is the most recent release
|
||||
# - updating the version in the URL will show the right thing
|
||||
#
|
||||
# format documentation:
|
||||
# - https://docs.netlify.com/routing/redirects/#syntax-for-the-redirects-file
|
||||
# - https://docs.netlify.com/routing/redirects/redirect-options/
|
||||
#
|
||||
# conventions:
|
||||
# - always force (<CODE>!) since this allows re-using file names
|
||||
# - group related paths to ease readability
|
||||
# - keep in alphabetical/wildcards-last order, which will reduce version control conflicts
|
||||
# - redirects that should have been there but are missing can be inserted where they belong
|
||||
|
||||
/advanced-topics/advanced-topics /advanced-topics 301!
|
||||
|
||||
/command-ref/command-ref /command-ref 301!
|
||||
|
||||
/contributing/contributing /contributing 301!
|
||||
|
||||
/expressions/expression-language /language/ 301!
|
||||
/expressions/language-constructs /language/constructs 301!
|
||||
/expressions/language-operators /language/operators 301!
|
||||
/expressions/language-values /language/values 301!
|
||||
/expressions/* /language/:splat 301!
|
||||
|
||||
/installation/installation /installation 301!
|
||||
|
||||
/package-management/basic-package-mgmt /command-ref/nix-env 301!
|
||||
/package-management/channels /command-ref/nix-channel 301!
|
||||
/package-management/package-management /package-management 301!
|
||||
/package-management/s3-substituter /store/types/s3-binary-cache-store 301!
|
||||
|
||||
/protocols/protocols /protocols 301!
|
||||
|
||||
/release-notes/release-notes /release-notes 301!
|
|
@ -1,6 +1,6 @@
|
|||
let
|
||||
inherit (builtins) concatStringsSep attrValues mapAttrs;
|
||||
inherit (import ./utils.nix) optionalString squash;
|
||||
inherit (import <nix/utils.nix>) optionalString squash;
|
||||
in
|
||||
|
||||
builtinsInfo:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
let
|
||||
inherit (builtins) concatStringsSep attrValues mapAttrs;
|
||||
inherit (import ./utils.nix) optionalString squash;
|
||||
inherit (import <nix/utils.nix>) optionalString squash;
|
||||
in
|
||||
|
||||
builtinsInfo:
|
||||
|
@ -8,7 +8,15 @@ let
|
|||
showBuiltin = name: { doc, args, arity, experimental-feature }:
|
||||
let
|
||||
experimentalNotice = optionalString (experimental-feature != null) ''
|
||||
This function is only available if the [${experimental-feature}](@docroot@/contributing/experimental-features.md#xp-feature-${experimental-feature}) experimental feature is enabled.
|
||||
> **Note**
|
||||
>
|
||||
> This function is only available if the [`${experimental-feature}` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-${experimental-feature}) is enabled.
|
||||
>
|
||||
> For example, include the following in [`nix.conf`](@docroot@/command-ref/conf-file.md):
|
||||
>
|
||||
> ```
|
||||
> extra-experimental-features = ${experimental-feature}
|
||||
> ```
|
||||
'';
|
||||
in
|
||||
squash ''
|
||||
|
@ -17,10 +25,9 @@ let
|
|||
</dt>
|
||||
<dd>
|
||||
|
||||
${doc}
|
||||
|
||||
${experimentalNotice}
|
||||
|
||||
${doc}
|
||||
</dd>
|
||||
'';
|
||||
listArgs = args: concatStringsSep " " (map (s: "<var>${s}</var>") args);
|
||||
|
|
|
@ -1,9 +1,29 @@
|
|||
let
|
||||
inherit (builtins)
|
||||
attrNames attrValues fromJSON listToAttrs mapAttrs groupBy
|
||||
concatStringsSep concatMap length lessThan replaceStrings sort;
|
||||
inherit (import <nix/utils.nix>) attrsToList concatStrings optionalString filterAttrs trim squash unique;
|
||||
showStoreDocs = import ./generate-store-info.nix;
|
||||
attrNames
|
||||
attrValues
|
||||
concatMap
|
||||
concatStringsSep
|
||||
fromJSON
|
||||
groupBy
|
||||
length
|
||||
lessThan
|
||||
listToAttrs
|
||||
mapAttrs
|
||||
match
|
||||
replaceStrings
|
||||
sort
|
||||
;
|
||||
inherit (import <nix/utils.nix>)
|
||||
attrsToList
|
||||
concatStrings
|
||||
filterAttrs
|
||||
optionalString
|
||||
squash
|
||||
trim
|
||||
unique
|
||||
;
|
||||
showStoreDocs = import <nix/generate-store-info.nix>;
|
||||
in
|
||||
|
||||
inlineHTML: commandDump:
|
||||
|
@ -31,7 +51,7 @@ let
|
|||
|
||||
${maybeSubcommands}
|
||||
|
||||
${maybeStoreDocs}
|
||||
${maybeProse}
|
||||
|
||||
${maybeOptions}
|
||||
'';
|
||||
|
@ -71,25 +91,56 @@ let
|
|||
* [`${command} ${name}`](./${appendName filename name}.md) - ${subcmd.description}
|
||||
'';
|
||||
|
||||
# FIXME: this is a hack.
|
||||
# store parameters should not be part of command documentation to begin
|
||||
# with, but instead be rendered on separate pages.
|
||||
maybeStoreDocs = optionalString (details ? doc)
|
||||
(replaceStrings [ "@stores@" ] [ (showStoreDocs inlineHTML commandInfo.stores) ] details.doc);
|
||||
maybeProse =
|
||||
# FIXME: this is a horrible hack to keep `nix help-stores` working.
|
||||
# the correct answer to this is to remove that command and replace it
|
||||
# by statically generated manpages or the output of something like `nix
|
||||
# store info <store type>`.
|
||||
let
|
||||
help-stores = ''
|
||||
${index}
|
||||
|
||||
maybeOptions = let
|
||||
allVisibleOptions = filterAttrs
|
||||
(_: o: ! o.hiddenCategory)
|
||||
(details.flags // toplevel.flags);
|
||||
in optionalString (allVisibleOptions != {}) ''
|
||||
# Options
|
||||
${allStores}
|
||||
'';
|
||||
index = replaceStrings
|
||||
[ "@store-types@" "./local-store.md" "./local-daemon-store.md" ]
|
||||
[ storesOverview "#local-store" "#local-daemon-store" ]
|
||||
details.doc;
|
||||
storesOverview =
|
||||
let
|
||||
showEntry = store:
|
||||
"- [${store.name}](#${store.slug})";
|
||||
in
|
||||
concatStringsSep "\n" (map showEntry storesList) + "\n";
|
||||
allStores = concatStringsSep "\n" (attrValues storePages);
|
||||
storePages = listToAttrs
|
||||
(map (s: { name = s.filename; value = s.page; }) storesList);
|
||||
storesList = showStoreDocs {
|
||||
storeInfo = commandInfo.stores;
|
||||
inherit inlineHTML;
|
||||
};
|
||||
in
|
||||
optionalString (details ? doc) (
|
||||
if match "@store-types@" details.doc != [ ]
|
||||
then help-stores
|
||||
else details.doc
|
||||
);
|
||||
|
||||
${showOptions inlineHTML allVisibleOptions}
|
||||
maybeOptions =
|
||||
let
|
||||
allVisibleOptions = filterAttrs
|
||||
(_: o: ! o.hiddenCategory)
|
||||
(details.flags // toplevel.flags);
|
||||
in
|
||||
optionalString (allVisibleOptions != { }) ''
|
||||
# Options
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> See [`man nix.conf`](@docroot@/command-ref/conf-file.md#command-line-flags) for overriding configuration settings with command line flags.
|
||||
'';
|
||||
${showOptions inlineHTML allVisibleOptions}
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> See [`man nix.conf`](@docroot@/command-ref/conf-file.md#command-line-flags) for overriding configuration settings with command line flags.
|
||||
'';
|
||||
|
||||
showOptions = inlineHTML: allOptions:
|
||||
let
|
||||
|
@ -97,7 +148,7 @@ let
|
|||
${optionalString (cat != "") "## ${cat}"}
|
||||
|
||||
${concatStringsSep "\n" (attrValues (mapAttrs showOption opts))}
|
||||
'';
|
||||
'';
|
||||
showOption = name: option:
|
||||
let
|
||||
result = trim ''
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
let
|
||||
inherit (builtins) attrValues concatStringsSep isAttrs isBool mapAttrs;
|
||||
inherit (import ./utils.nix) concatStrings indent optionalString squash;
|
||||
inherit (import <nix/utils.nix>) concatStrings indent optionalString squash;
|
||||
in
|
||||
|
||||
# `inlineHTML` is a hack to accommodate inconsistent output from `lowdown`
|
||||
|
@ -20,10 +20,10 @@ let
|
|||
else "`${setting}`";
|
||||
# separate body to cleanly handle indentation
|
||||
body = ''
|
||||
${description}
|
||||
|
||||
${experimentalFeatureNote}
|
||||
|
||||
${description}
|
||||
|
||||
**Default:** ${showDefault documentDefault defaultValue}
|
||||
|
||||
${showAliases aliases}
|
||||
|
@ -31,18 +31,19 @@ let
|
|||
|
||||
experimentalFeatureNote = optionalString (experimentalFeature != null) ''
|
||||
> **Warning**
|
||||
>
|
||||
> This setting is part of an
|
||||
> [experimental feature](@docroot@/contributing/experimental-features.md).
|
||||
|
||||
To change this setting, you need to make sure the corresponding experimental feature,
|
||||
[`${experimentalFeature}`](@docroot@/contributing/experimental-features.md#xp-feature-${experimentalFeature}),
|
||||
is enabled.
|
||||
For example, include the following in [`nix.conf`](#):
|
||||
|
||||
```
|
||||
extra-experimental-features = ${experimentalFeature}
|
||||
${setting} = ...
|
||||
```
|
||||
>
|
||||
> To change this setting, make sure the
|
||||
> [`${experimentalFeature}` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-${experimentalFeature})
|
||||
> is enabled.
|
||||
> For example, include the following in [`nix.conf`](@docroot@/command-ref/conf-file.md):
|
||||
>
|
||||
> ```
|
||||
> extra-experimental-features = ${experimentalFeature}
|
||||
> ${setting} = ...
|
||||
> ```
|
||||
'';
|
||||
|
||||
showDefault = documentDefault: defaultValue:
|
||||
|
|
|
@ -1,45 +1,57 @@
|
|||
let
|
||||
inherit (builtins) attrValues mapAttrs;
|
||||
inherit (import ./utils.nix) concatStrings optionalString;
|
||||
showSettings = import ./generate-settings.nix;
|
||||
inherit (builtins) attrNames listToAttrs concatStringsSep readFile replaceStrings;
|
||||
inherit (import <nix/utils.nix>) optionalString filterAttrs trim squash toLower unique indent;
|
||||
showSettings = import <nix/generate-settings.nix>;
|
||||
in
|
||||
|
||||
inlineHTML: storesInfo:
|
||||
{
|
||||
# data structure describing all stores and their parameters
|
||||
storeInfo,
|
||||
# whether to add inline HTML tags
|
||||
# `lowdown` does not eat those for one of the output modes
|
||||
inlineHTML,
|
||||
}:
|
||||
|
||||
let
|
||||
|
||||
showStore = name: { settings, doc, experimentalFeature }:
|
||||
showStore = { name, slug }: { settings, doc, experimentalFeature }:
|
||||
let
|
||||
result = squash ''
|
||||
# ${name}
|
||||
|
||||
result = ''
|
||||
## ${name}
|
||||
${experimentalFeatureNote}
|
||||
|
||||
${doc}
|
||||
${doc}
|
||||
|
||||
${experimentalFeatureNote}
|
||||
## Settings
|
||||
|
||||
### Settings
|
||||
${showSettings { prefix = "store-${slug}"; inherit inlineHTML; } settings}
|
||||
'';
|
||||
|
||||
${showSettings { prefix = "store-${slug}"; inherit inlineHTML; } settings}
|
||||
'';
|
||||
experimentalFeatureNote = optionalString (experimentalFeature != null) ''
|
||||
> **Warning**
|
||||
>
|
||||
> This store is part of an
|
||||
> [experimental feature](@docroot@/contributing/experimental-features.md).
|
||||
>
|
||||
> To use this store, make sure the
|
||||
> [`${experimentalFeature}` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-${experimentalFeature})
|
||||
> is enabled.
|
||||
> For example, include the following in [`nix.conf`](@docroot@/command-ref/conf-file.md):
|
||||
>
|
||||
> ```
|
||||
> extra-experimental-features = ${experimentalFeature}
|
||||
> ```
|
||||
'';
|
||||
in result;
|
||||
|
||||
# markdown doesn't like spaces in URLs
|
||||
slug = builtins.replaceStrings [ " " ] [ "-" ] name;
|
||||
storesList = map
|
||||
(name: rec {
|
||||
inherit name;
|
||||
slug = replaceStrings [ " " ] [ "-" ] (toLower name);
|
||||
filename = "${slug}.md";
|
||||
page = showStore { inherit name slug; } storeInfo.${name};
|
||||
})
|
||||
(attrNames storeInfo);
|
||||
|
||||
experimentalFeatureNote = optionalString (experimentalFeature != null) ''
|
||||
> **Warning**
|
||||
> This store is part of an
|
||||
> [experimental feature](@docroot@/contributing/experimental-features.md).
|
||||
|
||||
To use this store, you need to make sure the corresponding experimental feature,
|
||||
[`${experimentalFeature}`](@docroot@/contributing/experimental-features.md#xp-feature-${experimentalFeature}),
|
||||
is enabled.
|
||||
For example, include the following in [`nix.conf`](#):
|
||||
|
||||
```
|
||||
extra-experimental-features = ${experimentalFeature}
|
||||
```
|
||||
'';
|
||||
in result;
|
||||
|
||||
in concatStrings (attrValues (mapAttrs showStore storesInfo))
|
||||
in storesList
|
||||
|
|
39
doc/manual/generate-store-types.nix
Normal file
39
doc/manual/generate-store-types.nix
Normal file
|
@ -0,0 +1,39 @@
|
|||
let
|
||||
inherit (builtins) attrNames listToAttrs concatStringsSep readFile replaceStrings;
|
||||
showSettings = import <nix/generate-settings.nix>;
|
||||
showStoreDocs = import <nix/generate-store-info.nix>;
|
||||
in
|
||||
|
||||
storeInfo:
|
||||
|
||||
let
|
||||
storesList = showStoreDocs {
|
||||
inherit storeInfo;
|
||||
inlineHTML = true;
|
||||
};
|
||||
|
||||
index =
|
||||
let
|
||||
showEntry = store:
|
||||
"- [${store.name}](./${store.filename})";
|
||||
in
|
||||
concatStringsSep "\n" (map showEntry storesList);
|
||||
|
||||
"index.md" = replaceStrings
|
||||
[ "@store-types@" ] [ index ]
|
||||
(readFile ./src/store/types/index.md.in);
|
||||
|
||||
tableOfContents =
|
||||
let
|
||||
showEntry = store:
|
||||
" - [${store.name}](store/types/${store.filename})";
|
||||
in
|
||||
concatStringsSep "\n" (map showEntry storesList) + "\n";
|
||||
|
||||
"SUMMARY.md" = tableOfContents;
|
||||
|
||||
storePages = listToAttrs
|
||||
(map (s: { name = s.filename; value = s.page; }) storesList);
|
||||
|
||||
in
|
||||
storePages // { inherit "index.md" "SUMMARY.md"; }
|
|
@ -1,5 +1,5 @@
|
|||
with builtins;
|
||||
with import ./utils.nix;
|
||||
with import <nix/utils.nix>;
|
||||
|
||||
let
|
||||
showExperimentalFeature = name: doc:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
with builtins;
|
||||
with import ./utils.nix;
|
||||
with import <nix/utils.nix>;
|
||||
|
||||
let
|
||||
showExperimentalFeature = name: doc:
|
||||
|
@ -8,4 +8,6 @@ let
|
|||
|
||||
${doc}
|
||||
'';
|
||||
in xps: (concatStringsSep "\n" (attrValues (mapAttrs showExperimentalFeature xps)))
|
||||
in
|
||||
|
||||
xps: (concatStringsSep "\n" (attrValues (mapAttrs showExperimentalFeature xps)))
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
ifeq ($(doc_generate),yes)
|
||||
|
||||
# The version of Nix used to generate the doc. Can also be
|
||||
# `$(nix_INSTALL_PATH)` or just `nix` (to grap ambient from the `PATH`),
|
||||
# if one prefers.
|
||||
doc_nix = $(nix_PATH)
|
||||
|
||||
MANUAL_SRCS := \
|
||||
$(call rwildcard, $(d)/src, *.md) \
|
||||
$(call rwildcard, $(d)/src, */*.md)
|
||||
|
@ -24,7 +29,7 @@ man-pages += $(foreach subcommand, \
|
|||
clean-files += $(d)/*.1 $(d)/*.5 $(d)/*.8
|
||||
|
||||
# Provide a dummy environment for nix, so that it will not access files outside the macOS sandbox.
|
||||
# Set cores to 0 because otherwise nix show-config resolves the cores based on the current machine
|
||||
# Set cores to 0 because otherwise `nix config show` resolves the cores based on the current machine
|
||||
dummy-env = env -i \
|
||||
HOME=/dummy \
|
||||
NIX_CONF_DIR=/dummy \
|
||||
|
@ -32,7 +37,7 @@ dummy-env = env -i \
|
|||
NIX_STATE_DIR=/dummy \
|
||||
NIX_CONFIG='cores = 0'
|
||||
|
||||
nix-eval = $(dummy-env) $(bindir)/nix eval --experimental-features nix-command -I nix=doc/manual --store dummy:// --impure --raw
|
||||
nix-eval = $(dummy-env) $(doc_nix) eval --experimental-features nix-command -I nix=doc/manual --store dummy:// --impure --raw
|
||||
|
||||
# re-implement mdBook's include directive to make it usable for terminal output and for proper @docroot@ substitution
|
||||
define process-includes
|
||||
|
@ -92,58 +97,83 @@ $(d)/nix-profiles.5: $(d)/src/command-ref/files/profiles.md
|
|||
$(trace-gen) lowdown -sT man --nroff-nolinks -M section=5 $^.tmp -o $@
|
||||
@rm $^.tmp
|
||||
|
||||
$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md
|
||||
$(d)/src/SUMMARY.md: $(d)/src/SUMMARY.md.in $(d)/src/SUMMARY-rl-next.md $(d)/src/store/types $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md
|
||||
@cp $< $@
|
||||
@$(call process-includes,$@,$@)
|
||||
|
||||
$(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/utils.nix $(d)/generate-manpage.nix $(d)/generate-settings.nix $(d)/generate-store-info.nix $(bindir)/nix
|
||||
$(d)/src/store/types: $(d)/nix.json $(d)/utils.nix $(d)/generate-store-info.nix $(d)/generate-store-types.nix $(d)/src/store/types/index.md.in $(doc_nix)
|
||||
@# FIXME: build out of tree!
|
||||
@rm -rf $@.tmp
|
||||
$(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-store-types.nix (builtins.fromJSON (builtins.readFile $<)).stores'
|
||||
@# do not destroy existing contents
|
||||
@mv $@.tmp/* $@/
|
||||
|
||||
$(d)/src/command-ref/new-cli: $(d)/nix.json $(d)/utils.nix $(d)/generate-manpage.nix $(d)/generate-settings.nix $(d)/generate-store-info.nix $(doc_nix)
|
||||
@rm -rf $@ $@.tmp
|
||||
$(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-manpage.nix true (builtins.readFile $<)'
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/utils.nix $(d)/generate-settings.nix $(d)/src/command-ref/conf-file-prefix.md $(d)/src/command-ref/experimental-features-shortlist.md $(bindir)/nix
|
||||
$(d)/src/command-ref/conf-file.md: $(d)/conf-file.json $(d)/utils.nix $(d)/generate-settings.nix $(d)/src/command-ref/conf-file-prefix.md $(d)/src/command-ref/experimental-features-shortlist.md $(doc_nix)
|
||||
@cat doc/manual/src/command-ref/conf-file-prefix.md > $@.tmp
|
||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-settings.nix { prefix = "opt-"; } (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp;
|
||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-settings.nix { prefix = "conf"; } (builtins.fromJSON (builtins.readFile $<))' >> $@.tmp;
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/nix.json: $(bindir)/nix
|
||||
$(trace-gen) $(dummy-env) $(bindir)/nix __dump-cli > $@.tmp
|
||||
$(d)/nix.json: $(doc_nix)
|
||||
$(trace-gen) $(dummy-env) $(doc_nix) __dump-cli > $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/conf-file.json: $(bindir)/nix
|
||||
$(trace-gen) $(dummy-env) $(bindir)/nix show-config --json --experimental-features nix-command > $@.tmp
|
||||
$(d)/conf-file.json: $(doc_nix)
|
||||
$(trace-gen) $(dummy-env) $(doc_nix) config show --json --experimental-features nix-command > $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/src/contributing/experimental-feature-descriptions.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(bindir)/nix
|
||||
$(d)/src/contributing/experimental-feature-descriptions.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features.nix $(doc_nix)
|
||||
@rm -rf $@ $@.tmp
|
||||
$(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-xp-features.nix (builtins.fromJSON (builtins.readFile $<))'
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/src/command-ref/experimental-features-shortlist.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features-shortlist.nix $(bindir)/nix
|
||||
$(d)/src/command-ref/experimental-features-shortlist.md: $(d)/xp-features.json $(d)/utils.nix $(d)/generate-xp-features-shortlist.nix $(doc_nix)
|
||||
@rm -rf $@ $@.tmp
|
||||
$(trace-gen) $(nix-eval) --write-to $@.tmp --expr 'import doc/manual/generate-xp-features-shortlist.nix (builtins.fromJSON (builtins.readFile $<))'
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/xp-features.json: $(bindir)/nix
|
||||
$(trace-gen) $(dummy-env) $(bindir)/nix __dump-xp-features > $@.tmp
|
||||
$(d)/xp-features.json: $(doc_nix)
|
||||
$(trace-gen) $(dummy-env) $(doc_nix) __dump-xp-features > $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/src/language/builtins.md: $(d)/language.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(bindir)/nix
|
||||
$(d)/src/language/builtins.md: $(d)/language.json $(d)/generate-builtins.nix $(d)/src/language/builtins-prefix.md $(doc_nix)
|
||||
@cat doc/manual/src/language/builtins-prefix.md > $@.tmp
|
||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtins.nix (builtins.fromJSON (builtins.readFile $<)).builtins' >> $@.tmp;
|
||||
@cat doc/manual/src/language/builtins-suffix.md >> $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/src/language/builtin-constants.md: $(d)/language.json $(d)/generate-builtin-constants.nix $(d)/src/language/builtin-constants-prefix.md $(bindir)/nix
|
||||
$(d)/src/language/builtin-constants.md: $(d)/language.json $(d)/generate-builtin-constants.nix $(d)/src/language/builtin-constants-prefix.md $(doc_nix)
|
||||
@cat doc/manual/src/language/builtin-constants-prefix.md > $@.tmp
|
||||
$(trace-gen) $(nix-eval) --expr 'import doc/manual/generate-builtin-constants.nix (builtins.fromJSON (builtins.readFile $<)).constants' >> $@.tmp;
|
||||
@cat doc/manual/src/language/builtin-constants-suffix.md >> $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
$(d)/language.json: $(bindir)/nix
|
||||
$(trace-gen) $(dummy-env) $(bindir)/nix __dump-language > $@.tmp
|
||||
$(d)/language.json: $(doc_nix)
|
||||
$(trace-gen) $(dummy-env) $(doc_nix) __dump-language > $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
# Generate "Upcoming release" notes (or clear it and remove from menu)
|
||||
$(d)/src/release-notes/rl-next.md: $(d)/rl-next $(d)/rl-next/*
|
||||
@if type -p changelog-d > /dev/null; then \
|
||||
echo " GEN " $@; \
|
||||
changelog-d doc/manual/rl-next > $@; \
|
||||
else \
|
||||
echo " NULL " $@; \
|
||||
true > $@; \
|
||||
fi
|
||||
|
||||
$(d)/src/SUMMARY-rl-next.md: $(d)/src/release-notes/rl-next.md
|
||||
$(trace-gen) true
|
||||
@if [ -s $< ]; then \
|
||||
echo ' - [Upcoming release](release-notes/rl-next.md)' > $@; \
|
||||
else \
|
||||
true > $@; \
|
||||
fi
|
||||
|
||||
# Generate the HTML manual.
|
||||
.PHONY: manual-html
|
||||
manual-html: $(docdir)/manual/index.html
|
||||
|
@ -177,7 +207,7 @@ doc/manual/generated/man1/nix3-manpages: $(d)/src/command-ref/new-cli
|
|||
# `@docroot@` is to be preserved for documenting the mechanism
|
||||
# FIXME: maybe contributing guides should live right next to the code
|
||||
# instead of in the manual
|
||||
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md $(d)/src/language/builtin-constants.md
|
||||
$(docdir)/manual/index.html: $(MANUAL_SRCS) $(d)/book.toml $(d)/anchors.jq $(d)/custom.css $(d)/src/SUMMARY.md $(d)/src/store/types $(d)/src/command-ref/new-cli $(d)/src/contributing/experimental-feature-descriptions.md $(d)/src/command-ref/conf-file.md $(d)/src/language/builtins.md $(d)/src/language/builtin-constants.md $(d)/src/release-notes/rl-next.md
|
||||
$(trace-gen) \
|
||||
tmp="$$(mktemp -d)"; \
|
||||
cp -r doc/manual "$$tmp"; \
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
// redirect rules for anchors ensure backwards compatibility of URLs.
|
||||
// this must be done on the client side, as web servers do not see the anchor part of the URL.
|
||||
// redirect rules for URL fragments (client-side) to prevent link rot.
|
||||
// this must be done on the client side, as web servers do not see the fragment part of the URL.
|
||||
// it will only work with JavaScript enabled in the browser, but this is the best we can do here.
|
||||
// see ./_redirects for path redirects (client-side)
|
||||
|
||||
// redirections are declared as follows:
|
||||
// redirects are declared as follows:
|
||||
// each entry has as its key a path matching the requested URL path, relative to the mdBook document root.
|
||||
//
|
||||
// IMPORTANT: it must specify the full path with file name and suffix
|
||||
|
|
2
doc/manual/rl-next/config
Normal file
2
doc/manual/rl-next/config
Normal file
|
@ -0,0 +1,2 @@
|
|||
organization: NixOS
|
||||
repository: nix
|
23
doc/manual/rl-next/hash-format-nix32.md
Normal file
23
doc/manual/rl-next/hash-format-nix32.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
synopsis: Rename hash format `base32` to `nix32`
|
||||
prs: 9452
|
||||
---
|
||||
|
||||
Hash format `base32` was renamed to `nix32` since it used a special nix-specific character set for
|
||||
[Base32](https://en.wikipedia.org/wiki/Base32).
|
||||
|
||||
## Deprecation: Use `nix32` instead of `base32` as `toHashFormat`
|
||||
|
||||
For the builtin `convertHash`, the `toHashFormat` parameter now accepts the same hash formats as the `--to`/`--from`
|
||||
parameters of the `nix hash conert` command: `"base16"`, `"nix32"`, `"base64"`, and `"sri"`. The former `"base32"` value
|
||||
remains as a deprecated alias for `"base32"`. Please convert your code from:
|
||||
|
||||
```nix
|
||||
builtins.convertHash { inherit hash hashAlgo; toHashFormat = "base32";}
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```nix
|
||||
builtins.convertHash { inherit hash hashAlgo; toHashFormat = "nix32";}
|
||||
```
|
8
doc/manual/rl-next/mounted-ssh-store.md
Normal file
8
doc/manual/rl-next/mounted-ssh-store.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
synopsis: Mounted SSH Store
|
||||
issues: 7890
|
||||
prs: 7912
|
||||
---
|
||||
|
||||
Introduced the store [`mounted-ssh-ng://`](@docroot@/command-ref/new-cli/nix3-help-stores.md).
|
||||
This store allows full access to a Nix store on a remote machine and additionally requires that the store be mounted in the local filesystem.
|
7
doc/manual/rl-next/nix-config-show.md
Normal file
7
doc/manual/rl-next/nix-config-show.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
synopsis: Rename to `nix config show`
|
||||
issues: 7672
|
||||
prs: 9477
|
||||
---
|
||||
|
||||
`nix show-config` was renamed to `nix config show`, and `nix doctor` was renamed to `nix config check`, to be more consistent with the rest of the command-line interface.
|
6
doc/manual/rl-next/nix-env-json-drv-path.md
Normal file
6
doc/manual/rl-next/nix-env-json-drv-path.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
synopsis: Fix `nix-env --query --drv-path --json`
|
||||
prs: 9257
|
||||
---
|
||||
|
||||
Fixed a bug where `nix-env --query` ignored `--drv-path` when `--json` was set.
|
47
doc/manual/rl-next/nix-hash-convert.md
Normal file
47
doc/manual/rl-next/nix-hash-convert.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
synopsis: Add `nix hash convert`
|
||||
prs: 9452
|
||||
---
|
||||
|
||||
New [`nix hash convert`](https://github.com/NixOS/nix/issues/8876) sub command with a fast track
|
||||
to stabilization! Examples:
|
||||
|
||||
- Convert the hash to `nix32`.
|
||||
|
||||
```bash
|
||||
$ nix hash convert --algo "sha1" --to nix32 "800d59cfcd3c05e900cb4e214be48f6b886a08df"
|
||||
vw46m23bizj4n8afrc0fj19wrp7mj3c0
|
||||
```
|
||||
`nix32` is a base32 encoding with a nix-specific character set.
|
||||
Explicitly specify the hashing algorithm (optional with SRI hashes) but detect hash format by the length of the input
|
||||
hash.
|
||||
- Convert the hash to the `sri` format that includes an algorithm specification:
|
||||
```bash
|
||||
nix hash convert --algo "sha1" "800d59cfcd3c05e900cb4e214be48f6b886a08df"
|
||||
sha1-gA1Zz808BekAy04hS+SPa4hqCN8=
|
||||
```
|
||||
or with an explicit `-to` format:
|
||||
```bash
|
||||
nix hash convert --algo "sha1" --to sri "800d59cfcd3c05e900cb4e214be48f6b886a08df"
|
||||
sha1-gA1Zz808BekAy04hS+SPa4hqCN8=
|
||||
```
|
||||
- Assert the input format of the hash:
|
||||
```bash
|
||||
nix hash convert --algo "sha256" --from nix32 "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0="
|
||||
error: input hash 'ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=' does not have the expected format '--from nix32'
|
||||
nix hash convert --algo "sha256" --from nix32 "1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s"
|
||||
sha256-ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=
|
||||
```
|
||||
|
||||
The `--to`/`--from`/`--algo` parameters have context-sensitive auto-completion.
|
||||
|
||||
## Related Deprecations
|
||||
|
||||
The following commands are still available but will emit a deprecation warning. Please convert your code to
|
||||
`nix hash convert`:
|
||||
|
||||
- `nix hash to-base16 $hash1 $hash2`: Use `nix hash convert --to base16 $hash1 $hash2` instead.
|
||||
- `nix hash to-base32 $hash1 $hash2`: Use `nix hash convert --to nix32 $hash1 $hash2` instead.
|
||||
- `nix hash to-base64 $hash1 $hash2`: Use `nix hash convert --to base64 $hash1 $hash2` instead.
|
||||
- `nix hash to-sri $hash1 $hash2`: : Use `nix hash convert --to sri $hash1 $hash2`
|
||||
or even just `nix hash convert $hash1 $hash2` instead.
|
42
doc/manual/rl-next/source-positions-in-errors.md
Normal file
42
doc/manual/rl-next/source-positions-in-errors.md
Normal file
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
synopsis: Source locations are printed more consistently in errors
|
||||
issues: 561
|
||||
prs: 9555
|
||||
---
|
||||
|
||||
Source location information is now included in error messages more
|
||||
consistently. Given this code:
|
||||
|
||||
```nix
|
||||
let
|
||||
attr = {foo = "bar";};
|
||||
key = {};
|
||||
in
|
||||
attr.${key}
|
||||
```
|
||||
|
||||
Previously, Nix would show this unhelpful message when attempting to evaluate
|
||||
it:
|
||||
|
||||
```
|
||||
error:
|
||||
… while evaluating an attribute name
|
||||
|
||||
error: value is a set while a string was expected
|
||||
```
|
||||
|
||||
Now, the error message displays where the problematic value was found:
|
||||
|
||||
```
|
||||
error:
|
||||
… while evaluating an attribute name
|
||||
|
||||
at bad.nix:4:11:
|
||||
|
||||
3| key = {};
|
||||
4| in attr.${key}
|
||||
| ^
|
||||
5|
|
||||
|
||||
error: value is a set while a string was expected
|
||||
```
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
- [Introduction](introduction.md)
|
||||
- [Quick Start](quick-start.md)
|
||||
- [Installation](installation/installation.md)
|
||||
- [Installation](installation/index.md)
|
||||
- [Supported Platforms](installation/supported-platforms.md)
|
||||
- [Installing a Binary Distribution](installation/installing-binary.md)
|
||||
- [Installing Nix from Source](installation/installing-source.md)
|
||||
|
@ -18,6 +18,10 @@
|
|||
- [Uninstalling Nix](installation/uninstall.md)
|
||||
- [Nix Store](store/index.md)
|
||||
- [File System Object](store/file-system-object.md)
|
||||
- [Store Object](store/store-object.md)
|
||||
- [Store Path](store/store-path.md)
|
||||
- [Store Types](store/types/index.md)
|
||||
{{#include ./store/types/SUMMARY.md}}
|
||||
- [Nix Language](language/index.md)
|
||||
- [Data Types](language/values.md)
|
||||
- [Language Constructs](language/constructs.md)
|
||||
|
@ -29,11 +33,11 @@
|
|||
- [Import From Derivation](language/import-from-derivation.md)
|
||||
- [Built-in Constants](language/builtin-constants.md)
|
||||
- [Built-in Functions](language/builtins.md)
|
||||
- [Package Management](package-management/package-management.md)
|
||||
- [Package Management](package-management/index.md)
|
||||
- [Profiles](package-management/profiles.md)
|
||||
- [Garbage Collection](package-management/garbage-collection.md)
|
||||
- [Garbage Collector Roots](package-management/garbage-collector-roots.md)
|
||||
- [Advanced Topics](advanced-topics/advanced-topics.md)
|
||||
- [Advanced Topics](advanced-topics/index.md)
|
||||
- [Sharing Packages Between Machines](package-management/sharing-packages.md)
|
||||
- [Serving a Nix store via HTTP](package-management/binary-cache-substituter.md)
|
||||
- [Copying Closures via SSH](package-management/copy-closure.md)
|
||||
|
@ -43,7 +47,7 @@
|
|||
- [Tuning Cores and Jobs](advanced-topics/cores-vs-jobs.md)
|
||||
- [Verifying Build Reproducibility](advanced-topics/diff-hook.md)
|
||||
- [Using the `post-build-hook`](advanced-topics/post-build-hook.md)
|
||||
- [Command Reference](command-ref/command-ref.md)
|
||||
- [Command Reference](command-ref/index.md)
|
||||
- [Common Options](command-ref/opt-common.md)
|
||||
- [Common Environment Variables](command-ref/env-common.md)
|
||||
- [Main Commands](command-ref/main-commands.md)
|
||||
|
@ -100,19 +104,20 @@
|
|||
- [Channels](command-ref/files/channels.md)
|
||||
- [Default Nix expression](command-ref/files/default-nix-expression.md)
|
||||
- [Architecture and Design](architecture/architecture.md)
|
||||
- [Protocols](protocols/protocols.md)
|
||||
- [Protocols](protocols/index.md)
|
||||
- [Serving Tarball Flakes](protocols/tarball-fetcher.md)
|
||||
- [Derivation "ATerm" file format](protocols/derivation-aterm.md)
|
||||
- [Glossary](glossary.md)
|
||||
- [Contributing](contributing/contributing.md)
|
||||
- [Contributing](contributing/index.md)
|
||||
- [Hacking](contributing/hacking.md)
|
||||
- [Testing](contributing/testing.md)
|
||||
- [Documentation](contributing/documentation.md)
|
||||
- [Experimental Features](contributing/experimental-features.md)
|
||||
- [CLI guideline](contributing/cli-guideline.md)
|
||||
- [C++ style guide](contributing/cxx.md)
|
||||
- [Release Notes](release-notes/release-notes.md)
|
||||
- [Release X.Y (202?-??-??)](release-notes/rl-next.md)
|
||||
- [Release Notes](release-notes/index.md)
|
||||
{{#include ./SUMMARY-rl-next.md}}
|
||||
- [Release 2.19 (2023-11-17)](release-notes/rl-2.19.md)
|
||||
- [Release 2.18 (2023-09-20)](release-notes/rl-2.18.md)
|
||||
- [Release 2.17 (2023-07-24)](release-notes/rl-2.17.md)
|
||||
- [Release 2.16 (2023-05-31)](release-notes/rl-2.16.md)
|
||||
|
|
|
@ -52,7 +52,7 @@ The following [concept map] shows its main components (rectangles), the objects
|
|||
'---------------'
|
||||
```
|
||||
|
||||
At the top is the [command line interface](../command-ref/command-ref.md) that drives the underlying layers.
|
||||
At the top is the [command line interface](../command-ref/index.md) that drives the underlying layers.
|
||||
|
||||
The [Nix language](../language/index.md) evaluator transforms Nix expressions into self-contained *build plans*, which are used to derive *build results* from referenced *build inputs*.
|
||||
|
||||
|
@ -63,7 +63,7 @@ The command line interface and Nix expressions are what users deal with most.
|
|||
> The Nix language itself does not have a notion of *packages* or *configurations*.
|
||||
> As far as we are concerned here, the inputs and results of a build plan are just data.
|
||||
|
||||
Underlying the command line interface and the Nix language evaluator is the [Nix store](../glossary.md#gloss-store), a mechanism to keep track of build plans, data, and references between them.
|
||||
Underlying the command line interface and the Nix language evaluator is the [Nix store](../store/index.md), a mechanism to keep track of build plans, data, and references between them.
|
||||
It can also execute build plans to produce new data, which are made available to the operating system as files.
|
||||
|
||||
A build plan itself is a series of *build tasks*, together with their build inputs.
|
||||
|
|
|
@ -87,7 +87,7 @@ impacted the most by bad user experience.
|
|||
and [aligning of text](#text-alignment).
|
||||
- [Autocomplete](#shell-completion) of options.
|
||||
|
||||
Examples of such commands: `nix doctor`, `nix edit`, `nix eval`, ...
|
||||
Examples of such commands: `nix edit`, `nix eval`, ...
|
||||
|
||||
- **Utility and scripting commands**
|
||||
|
||||
|
@ -426,7 +426,7 @@ This leads to the following guidelines:
|
|||
### Examples
|
||||
|
||||
|
||||
This is bad, because all keys must be assumed to be store implementations:
|
||||
This is bad, because all keys must be assumed to be store types:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
|
@ -73,6 +73,17 @@ It should therefore aim to be correct, consistent, complete, and easy to navigat
|
|||
|
||||
Non-trivial examples may need additional explanation, especially if they use concepts from outside the given context.
|
||||
|
||||
- Always explain code examples in the text.
|
||||
|
||||
Use comments in code samples very sparingly, for instance to highlight a particular aspect.
|
||||
Readers tend to glance over large amounts of code when scanning for information.
|
||||
|
||||
Especially beginners will likely find reading more complex-looking code strenuous and may therefore avoid it altogether.
|
||||
|
||||
If a code sample appears to require a lot of inline explanation, consider replacing it with a simpler one.
|
||||
If that's not possible, break the example down into multiple parts, explain them separately, and then show the combined result at the end.
|
||||
This should be a last resort, as that would amount to writing a [tutorial](https://diataxis.fr/tutorials/) on the given subject.
|
||||
|
||||
- Use British English.
|
||||
|
||||
This is a somewhat arbitrary choice to force consistency, and accounts for the fact that a majority of Nix users and developers are from Europe.
|
||||
|
@ -151,6 +162,24 @@ Please observe these guidelines to ease reviews:
|
|||
> This is a note.
|
||||
```
|
||||
|
||||
Highlight examples as such:
|
||||
|
||||
````
|
||||
> **Example**
|
||||
>
|
||||
> ```console
|
||||
> $ nix --version
|
||||
> ```
|
||||
````
|
||||
|
||||
Highlight syntax definiions as such, using [EBNF](https://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_form) notation:
|
||||
|
||||
````
|
||||
> **Syntax**
|
||||
>
|
||||
> *attribute-set* = `{` [ *attribute-name* `=` *expression* `;` ... ] `}`
|
||||
````
|
||||
|
||||
### The `@docroot@` variable
|
||||
|
||||
`@docroot@` provides a base path for links that occur in reusable snippets or other documentation that doesn't have a base path of its own.
|
||||
|
|
|
@ -10,7 +10,7 @@ $ cd nix
|
|||
|
||||
The following instructions assume you already have some version of Nix installed locally, so that you can use it to set up the development environment. If you don't have it installed, follow the [installation instructions].
|
||||
|
||||
[installation instructions]: ../installation/installation.md
|
||||
[installation instructions]: ../installation/index.md
|
||||
|
||||
## Building Nix with flakes
|
||||
|
||||
|
@ -146,6 +146,31 @@ $ nix build .#packages.aarch64-linux.default
|
|||
Cross-compiled builds are available for ARMv6 (`armv6l-linux`) and ARMv7 (`armv7l-linux`).
|
||||
Add more [system types](#system-type) to `crossSystems` in `flake.nix` to bootstrap Nix on unsupported platforms.
|
||||
|
||||
### Building for multiple platforms at once
|
||||
|
||||
It is useful to perform multiple cross and native builds on the same source tree,
|
||||
for example to ensure that better support for one platform doesn't break the build for another.
|
||||
In order to facilitate this, Nix has some support for being built out of tree – that is, placing build artefacts in a different directory than the source code:
|
||||
|
||||
1. Create a directory for the build, e.g.
|
||||
|
||||
```bash
|
||||
mkdir build
|
||||
```
|
||||
|
||||
2. Run the configure script from that directory, e.g.
|
||||
|
||||
```bash
|
||||
cd build
|
||||
../configure <configure flags>
|
||||
```
|
||||
|
||||
3. Run make from the source directory, but with the build directory specified, e.g.
|
||||
|
||||
```bash
|
||||
make builddir=build <make flags>
|
||||
```
|
||||
|
||||
## System type
|
||||
|
||||
Nix uses a string with he following format to identify the *system type* or *platform* it runs on:
|
||||
|
@ -210,7 +235,7 @@ See [supported compilation environments](#compilation-environments) and instruct
|
|||
To use the LSP with your editor, you first need to [set up `clangd`](https://clangd.llvm.org/installation#project-setup) by running:
|
||||
|
||||
```console
|
||||
make clean && bear -- make -j$NIX_BUILD_CORES install
|
||||
make clean && bear -- make -j$NIX_BUILD_CORES default check install
|
||||
```
|
||||
|
||||
Configure your editor to use the `clangd` from the shell, either by running it inside the development shell, or by using [nix-direnv](https://github.com/nix-community/nix-direnv) and [the appropriate editor plugin](https://github.com/direnv/direnv/wiki#editor-integration).
|
||||
|
@ -220,3 +245,82 @@ Configure your editor to use the `clangd` from the shell, either by running it i
|
|||
> For some editors (e.g. Visual Studio Code), you may need to install a [special extension](https://open-vsx.org/extension/llvm-vs-code-extensions/vscode-clangd) for the editor to interact with `clangd`.
|
||||
> Some other editors (e.g. Emacs, Vim) need a plugin to support LSP servers in general (e.g. [lsp-mode](https://github.com/emacs-lsp/lsp-mode) for Emacs and [vim-lsp](https://github.com/prabirshrestha/vim-lsp) for vim).
|
||||
> Editor-specific setup is typically opinionated, so we will not cover it here in more detail.
|
||||
|
||||
## Add a release note
|
||||
|
||||
`doc/manual/rl-next` contains release notes entries for all unreleased changes.
|
||||
|
||||
User-visible changes should come with a release note.
|
||||
|
||||
### Add an entry
|
||||
|
||||
Here's what a complete entry looks like. The file name is not incorporated in the document.
|
||||
|
||||
```
|
||||
---
|
||||
synopsis: Basically a title
|
||||
issues: 1234
|
||||
prs: 1238
|
||||
---
|
||||
|
||||
Here's one or more paragraphs that describe the change.
|
||||
|
||||
- It's markdown
|
||||
- Add references to the manual using @docroot@
|
||||
```
|
||||
|
||||
Significant changes should add the following header, which moves them to the top.
|
||||
|
||||
```
|
||||
significance: significant
|
||||
```
|
||||
|
||||
<!-- Keep an eye on https://codeberg.org/fgaz/changelog-d/issues/1 -->
|
||||
See also the [format documentation](https://github.com/haskell/cabal/blob/master/CONTRIBUTING.md#changelog).
|
||||
|
||||
### Build process
|
||||
|
||||
Releases have a precomputed `rl-MAJOR.MINOR.md`, and no `rl-next.md`.
|
||||
Set `buildUnreleasedNotes = true;` in `flake.nix` to build the release notes on the fly.
|
||||
|
||||
## Branches
|
||||
|
||||
- [`master`](https://github.com/NixOS/nix/commits/master)
|
||||
|
||||
The main development branch. All changes are approved and merged here.
|
||||
When developing a change, create a branch based on the latest `master`.
|
||||
|
||||
Maintainers try to [keep it in a release-worthy state](#reverting).
|
||||
|
||||
- [`maintenance-*.*`](https://github.com/NixOS/nix/branches/all?query=maintenance)
|
||||
|
||||
These branches are the subject of backports only, and are
|
||||
also [kept](#reverting) in a release-worthy state.
|
||||
|
||||
See [`maintainers/backporting.md`](https://github.com/NixOS/nix/blob/master/maintainers/backporting.md)
|
||||
|
||||
- [`latest-release`](https://github.com/NixOS/nix/tree/latest-release)
|
||||
|
||||
The latest patch release of the latest minor version.
|
||||
|
||||
See [`maintainers/release-process.md`](https://github.com/NixOS/nix/blob/master/maintainers/release-process.md)
|
||||
|
||||
- [`backport-*-to-*`](https://github.com/NixOS/nix/branches/all?query=backport)
|
||||
|
||||
Generally branches created by the backport action.
|
||||
|
||||
See [`maintainers/backporting.md`](https://github.com/NixOS/nix/blob/master/maintainers/backporting.md)
|
||||
|
||||
- [_other_](https://github.com/NixOS/nix/branches/all)
|
||||
|
||||
Branches that do not conform to the above patterns should be feature branches.
|
||||
|
||||
## Reverting
|
||||
|
||||
If a change turns out to be merged by mistake, or contain a regression, it may be reverted.
|
||||
A revert is not a rejection of the contribution, but merely part of an effective development process.
|
||||
It makes sure that development keeps running smoothly, with minimal uncertainty, and less overhead.
|
||||
If maintainers have to worry too much about avoiding reverts, they would not be able to merge as much.
|
||||
By embracing reverts as a good part of the development process, everyone wins.
|
||||
|
||||
However, taking a step back may be frustrating, so maintainers will be extra supportive on the next try.
|
||||
|
|
|
@ -20,6 +20,7 @@ The unit tests are defined using the [googletest] and [rapidcheck] frameworks.
|
|||
|
||||
[googletest]: https://google.github.io/googletest/
|
||||
[rapidcheck]: https://github.com/emil-e/rapidcheck
|
||||
[property testing]: https://en.wikipedia.org/wiki/Property_testing
|
||||
|
||||
### Source and header layout
|
||||
|
||||
|
@ -28,34 +29,50 @@ The unit tests are defined using the [googletest] and [rapidcheck] frameworks.
|
|||
> ```
|
||||
> src
|
||||
> ├── libexpr
|
||||
> │ ├── local.mk
|
||||
> │ ├── value/context.hh
|
||||
> │ ├── value/context.cc
|
||||
> │ …
|
||||
> │
|
||||
> ├── tests
|
||||
> │ │
|
||||
> │ …
|
||||
> └── tests
|
||||
> │ ├── value/context.hh
|
||||
> │ ├── value/context.cc
|
||||
> │ └── unit
|
||||
> │ ├── libutil
|
||||
> │ │ ├── local.mk
|
||||
> │ │ …
|
||||
> │ │ └── data
|
||||
> │ │ ├── git/tree.txt
|
||||
> │ │ …
|
||||
> │ │
|
||||
> │ …
|
||||
> │
|
||||
> ├── unit-test-data
|
||||
> │ ├── libstore
|
||||
> │ │ ├── worker-protocol/content-address.bin
|
||||
> │ │ …
|
||||
> │ …
|
||||
> │ ├── libexpr-support
|
||||
> │ │ ├── local.mk
|
||||
> │ │ └── tests
|
||||
> │ │ ├── value/context.hh
|
||||
> │ │ ├── value/context.cc
|
||||
> │ │ …
|
||||
> │ │
|
||||
> │ ├── libexpr
|
||||
> │ … ├── local.mk
|
||||
> │ ├── value/context.cc
|
||||
> │ …
|
||||
> …
|
||||
> ```
|
||||
|
||||
The unit tests for each Nix library (`libnixexpr`, `libnixstore`, etc..) live inside a directory `src/${library_shortname}/tests` within the directory for the library (`src/${library_shortname}`).
|
||||
The tests for each Nix library (`libnixexpr`, `libnixstore`, etc..) live inside a directory `tests/unit/${library_name_without-nix}`.
|
||||
Given a interface (header) and implementation pair in the original library, say, `src/libexpr/value/context.{hh,cc}`, we write tests for it in `tests/unit/libexpr/tests/value/context.cc`, and (possibly) declare/define additional interfaces for testing purposes in `tests/unit/libexpr-support/tests/value/context.{hh,cc}`.
|
||||
|
||||
The data is in `unit-test-data`, with one subdir per library, with the same name as where the code goes.
|
||||
For example, `libnixstore` code is in `src/libstore`, and its test data is in `unit-test-data/libstore`.
|
||||
The path to the `unit-test-data` directory is passed to the unit test executable with the environment variable `_NIX_TEST_UNIT_DATA`.
|
||||
Data for unit tests is stored in a `data` subdir of the directory for each unit test executable.
|
||||
For example, `libnixstore` code is in `src/libstore`, and its test data is in `tests/unit/libstore/data`.
|
||||
The path to the `tests/unit/data` directory is passed to the unit test executable with the environment variable `_NIX_TEST_UNIT_DATA`.
|
||||
Note that each executable only gets the data for its tests.
|
||||
|
||||
> **Note**
|
||||
> Due to the way googletest works, downstream unit test executables will actually include and re-run upstream library tests.
|
||||
> Therefore it is important that the same value for `_NIX_TEST_UNIT_DATA` be used with the tests for each library.
|
||||
> That is why we have the test data nested within a single `unit-test-data` directory.
|
||||
The unit test libraries are in `tests/unit/${library_name_without-nix}-lib`.
|
||||
All headers are in a `tests` subdirectory so they are included with `#include "tests/"`.
|
||||
|
||||
The use of all these separate directories for the unit tests might seem inconvenient, as for example the tests are not "right next to" the part of the code they are testing.
|
||||
But organizing the tests this way has one big benefit:
|
||||
there is no risk of any build-system wildcards for the library accidentally picking up test code that should not built and installed as part of the library.
|
||||
|
||||
### Running tests
|
||||
|
||||
|
@ -69,7 +86,7 @@ See [functional characterisation testing](#characterisation-testing-functional)
|
|||
Like with the functional characterisation, `_NIX_TEST_ACCEPT=1` is also used.
|
||||
For example:
|
||||
```shell-session
|
||||
$ _NIX_TEST_ACCEPT=1 make libstore-tests-exe_RUN
|
||||
$ _NIX_TEST_ACCEPT=1 make libstore-tests_RUN
|
||||
...
|
||||
[ SKIPPED ] WorkerProtoTest.string_read
|
||||
[ SKIPPED ] WorkerProtoTest.string_write
|
||||
|
@ -80,6 +97,18 @@ $ _NIX_TEST_ACCEPT=1 make libstore-tests-exe_RUN
|
|||
will regenerate the "golden master" expected result for the `libnixstore` characterisation tests.
|
||||
The characterisation tests will mark themselves "skipped" since they regenerated the expected result instead of actually testing anything.
|
||||
|
||||
### Unit test support libraries
|
||||
|
||||
There are headers and code which are not just used to test the library in question, but also downstream libraries.
|
||||
For example, we do [property testing] with the [rapidcheck] library.
|
||||
This requires writing `Arbitrary` "instances", which are used to describe how to generate values of a given type for the sake of running property tests.
|
||||
Because types contain other types, `Arbitrary` "instances" for some type are not just useful for testing that type, but also any other type that contains it.
|
||||
Downstream types frequently contain upstream types, so it is very important that we share arbitrary instances so that downstream libraries' property tests can also use them.
|
||||
|
||||
It is important that these testing libraries don't contain any actual tests themselves.
|
||||
On some platforms they would be run as part of every test executable that uses them, which is redundant.
|
||||
On other platforms they wouldn't be run at all.
|
||||
|
||||
## Functional tests
|
||||
|
||||
The functional tests reside under the `tests/functional` directory and are listed in `tests/functional/local.mk`.
|
||||
|
@ -133,17 +162,17 @@ ran test tests/functional/${testName}.sh... [PASS]
|
|||
or without `make`:
|
||||
|
||||
```shell-session
|
||||
$ ./mk/run-test.sh tests/functional/${testName}.sh
|
||||
$ ./mk/run-test.sh tests/functional/${testName}.sh tests/functional/init.sh
|
||||
ran test tests/functional/${testName}.sh... [PASS]
|
||||
```
|
||||
|
||||
To see the complete output, one can also run:
|
||||
|
||||
```shell-session
|
||||
$ ./mk/debug-test.sh tests/functional/${testName}.sh
|
||||
+ foo
|
||||
$ ./mk/debug-test.sh tests/functional/${testName}.sh tests/functional/init.sh
|
||||
+(${testName}.sh:1) foo
|
||||
output from foo
|
||||
+ bar
|
||||
+(${testName}.sh:2) bar
|
||||
output from bar
|
||||
...
|
||||
```
|
||||
|
@ -175,7 +204,7 @@ edit it like so:
|
|||
Then, running the test with `./mk/debug-test.sh` will drop you into GDB once the script reaches that point:
|
||||
|
||||
```shell-session
|
||||
$ ./mk/debug-test.sh tests/functional/${testName}.sh
|
||||
$ ./mk/debug-test.sh tests/functional/${testName}.sh tests/functional/init.sh
|
||||
...
|
||||
+ gdb blash blub
|
||||
GNU gdb (GDB) 12.1
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
- [store]{#gloss-store}
|
||||
|
||||
A collection of store objects, with operations to manipulate that collection.
|
||||
See [Nix Store] for details.
|
||||
See [Nix store](./store/index.md) for details.
|
||||
|
||||
There are many types of stores.
|
||||
See [`nix help-stores`](@docroot@/command-ref/new-cli/nix3-help-stores.md) for a complete list.
|
||||
|
@ -86,10 +86,13 @@
|
|||
|
||||
- [store path]{#gloss-store-path}
|
||||
|
||||
The location of a [store object] in the file system, i.e., an
|
||||
immediate child of the Nix store directory.
|
||||
The location of a [store object](@docroot@/store/index.md#store-object) in the file system, i.e., an immediate child of the Nix store directory.
|
||||
|
||||
Example: `/nix/store/a040m110amc4h71lds2jmr8qrkj2jhxd-git-2.38.1`
|
||||
> **Example**
|
||||
>
|
||||
> `/nix/store/a040m110amc4h71lds2jmr8qrkj2jhxd-git-2.38.1`
|
||||
|
||||
See [Store Path](@docroot@/store/store-path.md) for details.
|
||||
|
||||
[store path]: #gloss-store-path
|
||||
|
||||
|
|
|
@ -132,6 +132,32 @@ a = src-set.a; b = src-set.b; c = src-set.c;
|
|||
when used while defining local variables in a let-expression or while
|
||||
defining a set.
|
||||
|
||||
In a `let` expression, `inherit` can be used to selectively bring specific attributes of a set into scope. For example
|
||||
|
||||
|
||||
```nix
|
||||
let
|
||||
x = { a = 1; b = 2; };
|
||||
inherit (builtins) attrNames;
|
||||
in
|
||||
{
|
||||
names = attrNames x;
|
||||
}
|
||||
```
|
||||
|
||||
is equivalent to
|
||||
|
||||
```nix
|
||||
let
|
||||
x = { a = 1; b = 2; };
|
||||
in
|
||||
{
|
||||
names = builtins.attrNames x;
|
||||
}
|
||||
```
|
||||
|
||||
both evaluate to `{ names = [ "a" "b" ]; }`.
|
||||
|
||||
## Functions
|
||||
|
||||
Functions have the following form:
|
||||
|
@ -146,65 +172,65 @@ three kinds of patterns:
|
|||
|
||||
- If a pattern is a single identifier, then the function matches any
|
||||
argument. Example:
|
||||
|
||||
|
||||
```nix
|
||||
let negate = x: !x;
|
||||
concat = x: y: x + y;
|
||||
in if negate true then concat "foo" "bar" else ""
|
||||
```
|
||||
|
||||
|
||||
Note that `concat` is a function that takes one argument and returns
|
||||
a function that takes another argument. This allows partial
|
||||
parameterisation (i.e., only filling some of the arguments of a
|
||||
function); e.g.,
|
||||
|
||||
|
||||
```nix
|
||||
map (concat "foo") [ "bar" "bla" "abc" ]
|
||||
```
|
||||
|
||||
|
||||
evaluates to `[ "foobar" "foobla" "fooabc" ]`.
|
||||
|
||||
- A *set pattern* of the form `{ name1, name2, …, nameN }` matches a
|
||||
set containing the listed attributes, and binds the values of those
|
||||
attributes to variables in the function body. For example, the
|
||||
function
|
||||
|
||||
|
||||
```nix
|
||||
{ x, y, z }: z + y + x
|
||||
```
|
||||
|
||||
|
||||
can only be called with a set containing exactly the attributes `x`,
|
||||
`y` and `z`. No other attributes are allowed. If you want to allow
|
||||
additional arguments, you can use an ellipsis (`...`):
|
||||
|
||||
|
||||
```nix
|
||||
{ x, y, z, ... }: z + y + x
|
||||
```
|
||||
|
||||
|
||||
This works on any set that contains at least the three named
|
||||
attributes.
|
||||
|
||||
|
||||
It is possible to provide *default values* for attributes, in
|
||||
which case they are allowed to be missing. A default value is
|
||||
specified by writing `name ? e`, where *e* is an arbitrary
|
||||
expression. For example,
|
||||
|
||||
|
||||
```nix
|
||||
{ x, y ? "foo", z ? "bar" }: z + y + x
|
||||
```
|
||||
|
||||
|
||||
specifies a function that only requires an attribute named `x`, but
|
||||
optionally accepts `y` and `z`.
|
||||
|
||||
- An `@`-pattern provides a means of referring to the whole value
|
||||
being matched:
|
||||
|
||||
|
||||
```nix
|
||||
args@{ x, y, z, ... }: z + y + x + args.a
|
||||
```
|
||||
|
||||
|
||||
but can also be written as:
|
||||
|
||||
|
||||
```nix
|
||||
{ x, y, z, ... } @ args: z + y + x + args.a
|
||||
```
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
| Inequality | *expr* `!=` *expr* | none | 11 |
|
||||
| Logical conjunction (`AND`) | *bool* `&&` *bool* | left | 12 |
|
||||
| Logical disjunction (`OR`) | *bool* <code>\|\|</code> *bool* | left | 13 |
|
||||
| [Logical implication] | *bool* `->` *bool* | none | 14 |
|
||||
| [Logical implication] | *bool* `->` *bool* | right | 14 |
|
||||
|
||||
[string]: ./values.md#type-string
|
||||
[path]: ./values.md#type-path
|
||||
|
|
|
@ -116,6 +116,7 @@
|
|||
[store path]: ../glossary.md#gloss-store-path
|
||||
|
||||
Paths can include [string interpolation] and can themselves be [interpolated in other expressions].
|
||||
|
||||
[interpolated in other expressions]: ./string-interpolation.md#interpolated-expressions
|
||||
|
||||
At least one slash (`/`) must appear *before* any interpolated expression for the result to be recognized as a path.
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
# Quick Start
|
||||
|
||||
This chapter is for impatient people who don't like reading
|
||||
documentation. For more in-depth information you are kindly referred
|
||||
to subsequent chapters.
|
||||
This chapter is for impatient people who don't like reading documentation.
|
||||
For more in-depth information you are kindly referred to subsequent chapters.
|
||||
|
||||
1. Install Nix by running the following:
|
||||
1. Install Nix:
|
||||
|
||||
```console
|
||||
$ curl -L https://nixos.org/nix/install | sh
|
||||
|
@ -13,87 +12,33 @@ to subsequent chapters.
|
|||
The install script will use `sudo`, so make sure you have sufficient rights.
|
||||
On Linux, `--daemon` can be omitted for a single-user install.
|
||||
|
||||
For other installation methods, see [here](installation/installation.md).
|
||||
For other installation methods, see the detailed [installation instructions](installation/index.md).
|
||||
|
||||
1. See what installable packages are currently available in the
|
||||
channel:
|
||||
1. Run software without installing it permanently:
|
||||
|
||||
```console
|
||||
$ nix-env --query --available --attr-path
|
||||
nixpkgs.docbook_xml_dtd_43 docbook-xml-4.3
|
||||
nixpkgs.docbook_xml_dtd_45 docbook-xml-4.5
|
||||
nixpkgs.firefox firefox-33.0.2
|
||||
nixpkgs.hello hello-2.9
|
||||
nixpkgs.libxslt libxslt-1.1.28
|
||||
…
|
||||
$ nix-shell --packages cowsay lolcat
|
||||
```
|
||||
|
||||
1. Install some packages from the channel:
|
||||
This downloads the specified packages with all their dependencies, and drops you into a Bash shell where the commands provided by those packages are present.
|
||||
This will not affect your normal environment:
|
||||
|
||||
```console
|
||||
$ nix-env --install --attr nixpkgs.hello
|
||||
[nix-shell:~]$ cowsay Hello, Nix! | lolcat
|
||||
```
|
||||
|
||||
This should download pre-built packages; it should not build them
|
||||
locally (if it does, something went wrong).
|
||||
|
||||
1. Test that they work:
|
||||
Exiting the shell will make the programs disappear again:
|
||||
|
||||
```console
|
||||
$ which hello
|
||||
/home/eelco/.nix-profile/bin/hello
|
||||
$ hello
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
1. Uninstall a package:
|
||||
|
||||
```console
|
||||
$ nix-env --uninstall hello
|
||||
```
|
||||
|
||||
1. You can also test a package without installing it:
|
||||
|
||||
```console
|
||||
$ nix-shell --packages hello
|
||||
```
|
||||
|
||||
This builds or downloads GNU Hello and its dependencies, then drops
|
||||
you into a Bash shell where the `hello` command is present, all
|
||||
without affecting your normal environment:
|
||||
|
||||
```console
|
||||
[nix-shell:~]$ hello
|
||||
Hello, world!
|
||||
|
||||
[nix-shell:~]$ exit
|
||||
|
||||
$ hello
|
||||
hello: command not found
|
||||
$ lolcat
|
||||
lolcat: command not found
|
||||
```
|
||||
|
||||
1. To keep up-to-date with the channel, do:
|
||||
1. Search for more packages on <search.nixos.org> to try them out.
|
||||
|
||||
1. Free up storage space:
|
||||
|
||||
```console
|
||||
$ nix-channel --update nixpkgs
|
||||
$ nix-env --upgrade '*'
|
||||
```
|
||||
|
||||
The latter command will upgrade each installed package for which
|
||||
there is a “newer” version (as determined by comparing the version
|
||||
numbers).
|
||||
|
||||
1. If you're unhappy with the result of a `nix-env` action (e.g., an
|
||||
upgraded package turned out not to work properly), you can go back:
|
||||
|
||||
```console
|
||||
$ nix-env --rollback
|
||||
```
|
||||
|
||||
1. You should periodically run the Nix garbage collector to get rid of
|
||||
unused packages, since uninstalls or upgrades don't actually delete
|
||||
them:
|
||||
|
||||
```console
|
||||
$ nix-collect-garbage --delete-old
|
||||
$ nix-collect-garbage
|
||||
```
|
||||
|
|
77
doc/manual/src/release-notes/rl-2.19.md
Normal file
77
doc/manual/src/release-notes/rl-2.19.md
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Release 2.19 (2023-11-17)
|
||||
|
||||
- The experimental `nix` command can now act as a [shebang interpreter](@docroot@/command-ref/new-cli/nix.md#shebang-interpreter)
|
||||
by appending the contents of any `#! nix` lines and the script's location into a single call.
|
||||
|
||||
- [URL flake references](@docroot@/command-ref/new-cli/nix3-flake.md#flake-references) now support [percent-encoded](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1) characters.
|
||||
|
||||
- [Path-like flake references](@docroot@/command-ref/new-cli/nix3-flake.md#path-like-syntax) now accept arbitrary unicode characters (except `#` and `?`).
|
||||
|
||||
- The experimental feature `repl-flake` is no longer needed, as its functionality is now part of the `flakes` experimental feature. To get the previous behavior, use the `--file/--expr` flags accordingly.
|
||||
|
||||
- There is a new flake installable syntax `flakeref#.attrPath` where the "." prefix specifies that `attrPath` is interpreted from the root of the flake outputs, with no searching of default attribute prefixes like `packages.<SYSTEM>` or `legacyPackages.<SYSTEM>`.
|
||||
|
||||
- Nix adds `apple-virt` to the default system features on macOS systems that support virtualization. This is similar to what's done for the `kvm` system feature on Linux hosts.
|
||||
|
||||
- Add a new built-in function [`builtins.convertHash`](@docroot@/language/builtins.md#builtins-convertHash).
|
||||
|
||||
- `nix-shell` shebang lines now support single-quoted arguments.
|
||||
|
||||
- `builtins.fetchTree` is now its own experimental feature, [`fetch-tree`](@docroot@/contributing/experimental-features.md#xp-fetch-tree).
|
||||
This allows stabilising it independently of the rest of what is encompassed by [`flakes`](@docroot@/contributing/experimental-features.md#xp-fetch-tree).
|
||||
|
||||
- The interface for creating and updating lock files has been overhauled:
|
||||
|
||||
- [`nix flake lock`](@docroot@/command-ref/new-cli/nix3-flake-lock.md) only creates lock files and adds missing inputs now.
|
||||
It will *never* update existing inputs.
|
||||
|
||||
- [`nix flake update`](@docroot@/command-ref/new-cli/nix3-flake-update.md) does the same, but *will* update inputs.
|
||||
- Passing no arguments will update all inputs of the current flake, just like it already did.
|
||||
- Passing input names as arguments will ensure only those are updated. This replaces the functionality of `nix flake lock --update-input`
|
||||
- To operate on a flake outside the current directory, you must now pass `--flake path/to/flake`.
|
||||
|
||||
- The flake-specific flags `--recreate-lock-file` and `--update-input` have been removed from all commands operating on installables.
|
||||
They are superceded by `nix flake update`.
|
||||
|
||||
- Commit signature verification for the [`builtins.fetchGit`](@docroot@/language/builtins.md#builtins-fetchGit) is added as the new [`verified-fetches` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-verified-fetches).
|
||||
|
||||
- [`nix path-info --json`](@docroot@/command-ref/new-cli/nix3-path-info.md)
|
||||
(experimental) now returns a JSON map rather than JSON list.
|
||||
The `path` field of each object has instead become the key in the outer map, since it is unique.
|
||||
The `valid` field also goes away because we just use `null` instead.
|
||||
|
||||
- Old way:
|
||||
|
||||
```json5
|
||||
[
|
||||
{
|
||||
"path": "/nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15",
|
||||
"valid": true,
|
||||
// ...
|
||||
},
|
||||
{
|
||||
"path": "/nix/store/wffw7l0alvs3iw94cbgi1gmmbmw99sqb-home-manager-path",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
- New way
|
||||
|
||||
```json5
|
||||
{
|
||||
"/nix/store/8fv91097mbh5049i9rglc73dx6kjg3qk-bash-5.2-p15": {
|
||||
// ...
|
||||
},
|
||||
"/nix/store/wffw7l0alvs3iw94cbgi1gmmbmw99sqb-home-manager-path": null,
|
||||
}
|
||||
```
|
||||
|
||||
This makes it match `nix derivation show`, which also maps store paths to information.
|
||||
|
||||
- When Nix is installed using the [binary installer](@docroot@/installation/installing-binary.md), in supported shells (Bash, Zsh, Fish)
|
||||
[`XDG_DATA_DIRS`](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables) is now populated with the path to the `/share` subdirectory of the current profile.
|
||||
This means that command completion scripts, `.desktop` files, and similar artifacts installed via [`nix-env`](@docroot@/command-ref/nix-env.md) or [`nix profile`](@docroot@/command-ref/new-cli/nix3-profile.md)
|
||||
(experimental) can be found by any program that follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html).
|
||||
|
||||
- A new command `nix store add` has been added. It replaces `nix store add-file` and `nix store add-path` which are now deprecated.
|
|
@ -1,17 +0,0 @@
|
|||
# Release X.Y (202?-??-??)
|
||||
|
||||
- [URL flake references](@docroot@/command-ref/new-cli/nix3-flake.md#flake-references) now support [percent-encoded](https://datatracker.ietf.org/doc/html/rfc3986#section-2.1) characters.
|
||||
|
||||
- [Path-like flake references](@docroot@/command-ref/new-cli/nix3-flake.md#path-like-syntax) now accept arbitrary unicode characters (except `#` and `?`).
|
||||
|
||||
- The experimental feature `repl-flake` is no longer needed, as its functionality is now part of the `flakes` experimental feature. To get the previous behavior, use the `--file/--expr` flags accordingly.
|
||||
|
||||
- Introduce new flake installable syntax `flakeref#.attrPath` where the "." prefix denotes no searching of default attribute prefixes like `packages.<SYSTEM>` or `legacyPackages.<SYSTEM>`.
|
||||
|
||||
- Nix adds `apple-virt` to the default system features on macOS systems that support virtualization. This is similar to what's done for the `kvm` system feature on Linux hosts.
|
||||
|
||||
- Introduce a new built-in function [`builtins.convertHash`](@docroot@/language/builtins.md#builtins-convertHash).
|
||||
|
||||
- `nix-shell` shebang lines now support single-quoted arguments.
|
||||
|
||||
- `builtins.fetchTree` is now marked as stable.
|
|
@ -1,4 +1,5 @@
|
|||
# Nix Store
|
||||
|
||||
The *Nix store* is an abstraction used by Nix to store immutable filesystem artifacts (such as software packages) that can have dependencies (*references*) between them.
|
||||
There are multiple implementations of the Nix store, such as the actual filesystem (`/nix/store`) and binary caches.
|
||||
The *Nix store* is an abstraction to store immutable file system data (such as software packages) that can have dependencies on other such data.
|
||||
|
||||
There are [multiple types of Nix stores](./types/index.md) with different capabilities, such as the default one on the [local filesystem](./types/local-store.md) (`/nix/store`) or [binary caches](./types/http-binary-cache-store.md).
|
||||
|
|
10
doc/manual/src/store/store-object.md
Normal file
10
doc/manual/src/store/store-object.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
## Store Object
|
||||
|
||||
A Nix store is a collection of *store objects* with *references* between them.
|
||||
A store object consists of
|
||||
|
||||
- A [file system object](./file-system-object.md) as data
|
||||
- A set of [store paths](./store-path.md) as references to other store objects
|
||||
|
||||
Store objects are [immutable](https://en.wikipedia.org/wiki/Immutable_object):
|
||||
Once created, they do not change until they are deleted.
|
69
doc/manual/src/store/store-path.md
Normal file
69
doc/manual/src/store/store-path.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
# Store Path
|
||||
|
||||
Nix implements references to [store objects](./index.md#store-object) as *store paths*.
|
||||
|
||||
Think of a store path as an [opaque], [unique identifier]:
|
||||
The only way to obtain store path is by adding or building store objects.
|
||||
A store path will always reference exactly one store object.
|
||||
|
||||
[opaque]: https://en.m.wikipedia.org/wiki/Opaque_data_type
|
||||
[unique identifier]: https://en.m.wikipedia.org/wiki/Unique_identifier
|
||||
|
||||
Store paths are pairs of
|
||||
|
||||
- A 20-byte digest for identification
|
||||
- A symbolic name for people to read
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> - Digest: `b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z`
|
||||
> - Name: `firefox-33.1`
|
||||
|
||||
To make store objects accessible to operating system processes, stores have to expose store objects through the file system.
|
||||
|
||||
A store path is rendered to a file system path as the concatenation of
|
||||
|
||||
- [Store directory](#store-directory) (typically `/nix/store`)
|
||||
- Path separator (`/`)
|
||||
- Digest rendered in a custom variant of [Base32](https://en.wikipedia.org/wiki/Base32) (20 arbitrary bytes become 32 ASCII characters)
|
||||
- Hyphen (`-`)
|
||||
- Name
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```
|
||||
> /nix/store/b6gvzjyb2pg0kjfwrjmg1vfhh54ad73z-firefox-33.1
|
||||
> |--------| |------------------------------| |----------|
|
||||
> store directory digest name
|
||||
> ```
|
||||
|
||||
## Store Directory
|
||||
|
||||
Every [Nix store](./index.md) has a store directory.
|
||||
|
||||
Not every store can be accessed through the file system.
|
||||
But if the store has a file system representation, the store directory contains the store’s [file system objects], which can be addressed by [store paths](#store-path).
|
||||
|
||||
[file system objects]: ./file-system-object.md
|
||||
|
||||
This means a store path is not just derived from the referenced store object itself, but depends on the store the store object is in.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> The store directory defaults to `/nix/store`, but is in principle arbitrary.
|
||||
|
||||
It is important which store a given store object belongs to:
|
||||
Files in the store object can contain store paths, and processes may read these paths.
|
||||
Nix can only guarantee referential integrity if store paths do not cross store boundaries.
|
||||
|
||||
Therefore one can only copy store objects to a different store if
|
||||
|
||||
- The source and target stores' directories match
|
||||
|
||||
or
|
||||
|
||||
- The store object in question has no references, that is, contains no store paths
|
||||
|
||||
One cannot copy a store object to a store with a different store directory.
|
||||
Instead, it has to be rebuilt, together with all its dependencies.
|
||||
It is in general not enough to replace the store directory string in file contents, as this may render executables unusable by invalidating their internal offsets or checksums.
|
|
@ -1,6 +1,6 @@
|
|||
R"(
|
||||
Nix supports different types of stores:
|
||||
|
||||
Nix supports different types of stores. These are described below.
|
||||
@store-types@
|
||||
|
||||
## Store URL format
|
||||
|
||||
|
@ -29,18 +29,15 @@ supported settings for each store type are documented below.
|
|||
The special store URL `auto` causes Nix to automatically select a
|
||||
store as follows:
|
||||
|
||||
* Use the [local store](#local-store) `/nix/store` if `/nix/var/nix`
|
||||
* Use the [local store](./local-store.md) `/nix/store` if `/nix/var/nix`
|
||||
is writable by the current user.
|
||||
|
||||
* Otherwise, if `/nix/var/nix/daemon-socket/socket` exists, [connect
|
||||
to the Nix daemon listening on that socket](#local-daemon-store).
|
||||
to the Nix daemon listening on that socket](./local-daemon-store.md).
|
||||
|
||||
* Otherwise, on Linux only, use the [local chroot store](#local-store)
|
||||
* Otherwise, on Linux only, use the [local chroot store](./local-store.md)
|
||||
`~/.local/share/nix/root`, which will be created automatically if it
|
||||
does not exist.
|
||||
|
||||
* Otherwise, use the [local store](#local-store) `/nix/store`.
|
||||
* Otherwise, use the [local store](./local-store.md) `/nix/store`.
|
||||
|
||||
@stores@
|
||||
|
||||
)"
|
|
@ -1,5 +1,11 @@
|
|||
with builtins;
|
||||
|
||||
let
|
||||
lowerChars = stringToCharacters "abcdefghijklmnopqrstuvwxyz";
|
||||
upperChars = stringToCharacters "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
stringToCharacters = s: genList (p: substring p 1 s) (stringLength s);
|
||||
in
|
||||
|
||||
rec {
|
||||
splitLines = s: filter (x: !isList x) (split "\n" s);
|
||||
|
||||
|
@ -18,6 +24,8 @@ rec {
|
|||
in
|
||||
if replaced == string then string else replaceStringsRec from to replaced;
|
||||
|
||||
toLower = replaceStrings upperChars lowerChars;
|
||||
|
||||
squash = replaceStringsRec "\n\n\n" "\n\n";
|
||||
|
||||
trim = string:
|
||||
|
|
25
flake.lock
25
flake.lock
|
@ -16,6 +16,22 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libgit2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1697646580,
|
||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"lowdown-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
|
@ -34,16 +50,16 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1695283060,
|
||||
"narHash": "sha256-CJz71xhCLlRkdFUSQEL0pIAAfcnWFXMzd9vXhPrnrEg=",
|
||||
"lastModified": 1701355166,
|
||||
"narHash": "sha256-4V7XMI0Gd+y0zsi++cEHd99u3GNL0xSTGRmiWKzGnUQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "31ed632c692e6a36cfc18083b88ece892f863ed4",
|
||||
"rev": "36c4ac09e9bebcec1fa7b7539cddb0c9e837409c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.05-small",
|
||||
"ref": "staging-23.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
|
@ -67,6 +83,7 @@
|
|||
"root": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"libgit2": "libgit2",
|
||||
"lowdown-src": "lowdown-src",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
|
|
51
flake.nix
51
flake.nix
|
@ -1,18 +1,28 @@
|
|||
{
|
||||
description = "The purely functional package manager";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05-small";
|
||||
# TODO Go back to nixos-23.05-small once
|
||||
# https://github.com/NixOS/nixpkgs/pull/271202 is merged.
|
||||
#
|
||||
# Also, do not grab arbitrary further staging commits. This PR was
|
||||
# carefully made to be based on release-23.05 and just contain
|
||||
# rebuild-causing changes to packages that Nix actually uses.
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/staging-23.05";
|
||||
inputs.nixpkgs-regression.url = "github:NixOS/nixpkgs/215d4d0fd80ca5163643b03a33fde804a29cc1e2";
|
||||
inputs.lowdown-src = { url = "github:kristapsdz/lowdown"; flake = false; };
|
||||
inputs.flake-compat = { url = "github:edolstra/flake-compat"; flake = false; };
|
||||
inputs.libgit2 = { url = "github:libgit2/libgit2"; flake = false; };
|
||||
|
||||
outputs = { self, nixpkgs, nixpkgs-regression, lowdown-src, flake-compat }:
|
||||
outputs = { self, nixpkgs, nixpkgs-regression, lowdown-src, flake-compat, libgit2 }:
|
||||
|
||||
let
|
||||
inherit (nixpkgs) lib;
|
||||
|
||||
officialRelease = false;
|
||||
|
||||
# Set to true to build the release notes for the next release.
|
||||
buildUnreleasedNotes = false;
|
||||
|
||||
version = lib.fileContents ./.version + versionSuffix;
|
||||
versionSuffix =
|
||||
if officialRelease
|
||||
|
@ -89,7 +99,7 @@
|
|||
./misc
|
||||
./precompiled-headers.h
|
||||
./src
|
||||
./unit-test-data
|
||||
./tests/unit
|
||||
./COPYING
|
||||
./scripts/local.mk
|
||||
functionalTestFiles
|
||||
|
@ -162,12 +172,18 @@
|
|||
|
||||
testConfigureFlags = [
|
||||
"RAPIDCHECK_HEADERS=${lib.getDev rapidcheck}/extras/gtest/include"
|
||||
] ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
|
||||
"--enable-install-unit-tests"
|
||||
"--with-check-bin-dir=${builtins.placeholder "check"}/bin"
|
||||
"--with-check-lib-dir=${builtins.placeholder "check"}/lib"
|
||||
];
|
||||
|
||||
internalApiDocsConfigureFlags = [
|
||||
"--enable-internal-api-docs"
|
||||
];
|
||||
|
||||
changelog-d = pkgs.buildPackages.callPackage ./misc/changelog-d.nix { };
|
||||
|
||||
nativeBuildDeps =
|
||||
[
|
||||
buildPackages.bison
|
||||
|
@ -183,14 +199,23 @@
|
|||
buildPackages.git
|
||||
buildPackages.mercurial # FIXME: remove? only needed for tests
|
||||
buildPackages.jq # Also for custom mdBook preprocessor.
|
||||
buildPackages.openssh # only needed for tests (ssh-keygen)
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isLinux [(buildPackages.util-linuxMinimal or buildPackages.utillinuxMinimal)];
|
||||
++ lib.optionals stdenv.hostPlatform.isLinux [(buildPackages.util-linuxMinimal or buildPackages.utillinuxMinimal)]
|
||||
# Official releases don't have rl-next, so we don't need to compile a changelog
|
||||
++ lib.optional (!officialRelease && buildUnreleasedNotes) changelog-d
|
||||
;
|
||||
|
||||
buildDeps =
|
||||
[ curl
|
||||
bzip2 xz brotli editline
|
||||
openssl sqlite
|
||||
libarchive
|
||||
(pkgs.libgit2.overrideAttrs (attrs: {
|
||||
src = libgit2;
|
||||
version = libgit2.lastModifiedDate;
|
||||
cmakeFlags = (attrs.cmakeFlags or []) ++ ["-DUSE_SSH=exec"];
|
||||
}))
|
||||
boost
|
||||
lowdown-nix
|
||||
libsodium
|
||||
|
@ -219,6 +244,9 @@
|
|||
}).overrideAttrs(o: {
|
||||
patches = (o.patches or []) ++ [
|
||||
./boehmgc-coroutine-sp-fallback.diff
|
||||
|
||||
# https://github.com/ivmai/bdwgc/pull/586
|
||||
./boehmgc-traceable_allocator-public.diff
|
||||
];
|
||||
})
|
||||
)
|
||||
|
@ -401,7 +429,8 @@
|
|||
src = nixSrc;
|
||||
VERSION_SUFFIX = versionSuffix;
|
||||
|
||||
outputs = [ "out" "dev" "doc" ];
|
||||
outputs = [ "out" "dev" "doc" ]
|
||||
++ lib.optional (currentStdenv.hostPlatform != currentStdenv.buildPlatform) "check";
|
||||
|
||||
nativeBuildInputs = nativeBuildDeps;
|
||||
buildInputs = buildDeps
|
||||
|
@ -511,6 +540,8 @@
|
|||
# Binary package for various platforms.
|
||||
build = forAllSystems (system: self.packages.${system}.nix);
|
||||
|
||||
shellInputs = forAllSystems (system: self.devShells.${system}.default.inputDerivation);
|
||||
|
||||
buildStatic = lib.genAttrs linux64BitSystems (system: self.packages.${system}.nix-static);
|
||||
|
||||
buildCross = forAllCrossSystems (crossSystem:
|
||||
|
@ -662,6 +693,11 @@
|
|||
perlBindings = self.hydraJobs.perlBindings.${system};
|
||||
installTests = self.hydraJobs.installTests.${system};
|
||||
nixpkgsLibTests = self.hydraJobs.tests.nixpkgsLibTests.${system};
|
||||
rl-next =
|
||||
let pkgs = nixpkgsFor.${system}.native;
|
||||
in pkgs.buildPackages.runCommand "test-rl-next-release-notes" { } ''
|
||||
LANG=C.UTF-8 ${(commonDeps { inherit pkgs; }).changelog-d}/bin/changelog-d ${./doc/manual/rl-next} >$out
|
||||
'';
|
||||
} // (lib.optionalAttrs (builtins.elem system linux64BitSystems)) {
|
||||
dockerImage = self.hydraJobs.dockerImage.${system};
|
||||
});
|
||||
|
@ -707,13 +743,16 @@
|
|||
stdenv.mkDerivation {
|
||||
name = "nix";
|
||||
|
||||
outputs = [ "out" "dev" "doc" ];
|
||||
outputs = [ "out" "dev" "doc" ]
|
||||
++ lib.optional (stdenv.hostPlatform != stdenv.buildPlatform) "check";
|
||||
|
||||
nativeBuildInputs = nativeBuildDeps
|
||||
++ lib.optional stdenv.cc.isClang pkgs.buildPackages.bear
|
||||
++ lib.optional
|
||||
(stdenv.cc.isClang && stdenv.hostPlatform == stdenv.buildPlatform)
|
||||
pkgs.buildPackages.clang-tools
|
||||
# We want changelog-d in the shell even if the current build doesn't need it
|
||||
++ lib.optional (officialRelease || ! buildUnreleasedNotes) changelog-d
|
||||
;
|
||||
|
||||
buildInputs = buildDeps ++ propagatedDeps
|
||||
|
|
64
m4/gcc_bug_80431.m4
Normal file
64
m4/gcc_bug_80431.m4
Normal file
|
@ -0,0 +1,64 @@
|
|||
# Ensure that this bug is not present in the C++ toolchain we are using.
|
||||
#
|
||||
# URL for bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80431
|
||||
#
|
||||
# The test program is from that issue, with only a slight modification
|
||||
# to set an exit status instead of printing strings.
|
||||
AC_DEFUN([ENSURE_NO_GCC_BUG_80431],
|
||||
[
|
||||
AC_MSG_CHECKING([that GCC bug 80431 is fixed])
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[
|
||||
#include <cstdio>
|
||||
|
||||
static bool a = true;
|
||||
static bool b = true;
|
||||
|
||||
struct Options { };
|
||||
|
||||
struct Option
|
||||
{
|
||||
Option(Options * options)
|
||||
{
|
||||
a = false;
|
||||
}
|
||||
|
||||
~Option()
|
||||
{
|
||||
b = false;
|
||||
}
|
||||
};
|
||||
|
||||
struct MyOptions : Options { };
|
||||
|
||||
struct MyOptions2 : virtual MyOptions
|
||||
{
|
||||
Option foo{this};
|
||||
};
|
||||
]],
|
||||
[[
|
||||
{
|
||||
MyOptions2 opts;
|
||||
}
|
||||
return (a << 1) | b;
|
||||
]])],
|
||||
[status_80431=0],
|
||||
[status_80431=$?],
|
||||
[
|
||||
# Assume we're bug-free when cross-compiling
|
||||
])
|
||||
AC_LANG_POP(C++)
|
||||
AS_CASE([$status_80431],
|
||||
[0],[
|
||||
AC_MSG_RESULT(yes)
|
||||
],
|
||||
[2],[
|
||||
AC_MSG_RESULT(no)
|
||||
AC_MSG_ERROR(Cannot build Nix with C++ compiler with this bug)
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT(unexpected result $status_80431: not expected failure with bug, ignoring)
|
||||
])
|
||||
])
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
## 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.
|
||||
The team's main responsibility is to guide and direct 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.
|
||||
|
||||
|
|
179
maintainers/release-notes
Executable file
179
maintainers/release-notes
Executable file
|
@ -0,0 +1,179 @@
|
|||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash ../shell.nix -I nixpkgs=channel:nixos-unstable-small
|
||||
# ^^^^^^^
|
||||
# Only used for bash. shell.nix goes to the flake.
|
||||
|
||||
# --- CONFIGURATION ---
|
||||
|
||||
# This does double duty for
|
||||
# - including rl-next
|
||||
# - marking where to insert new links (right after)
|
||||
SUMMARY_MARKER_LINE='{{#include ./SUMMARY-rl-next.md}}'
|
||||
|
||||
# --- LIB ---
|
||||
|
||||
log() {
|
||||
echo 1>&2 "release-notes:" "$@"
|
||||
}
|
||||
logcmd() {
|
||||
local cmd="$1"
|
||||
shift
|
||||
logcmd2 "$cmd" "${*@Q}" "$cmd" "$@"
|
||||
}
|
||||
logcmd2() {
|
||||
local fakecmd="$1"
|
||||
local fakeargs="$2"
|
||||
shift
|
||||
shift
|
||||
printf 1>&2 "release-notes: \033[34;1m$fakecmd\033[0m "
|
||||
echo "$fakeargs" 1>&2
|
||||
"$@"
|
||||
}
|
||||
die() {
|
||||
# ANSI red
|
||||
printf 1>&2 "release-notes: \033[31;1merror:\033[0m"
|
||||
echo 1>&2 "" "$@"
|
||||
exit 1
|
||||
}
|
||||
confirm() {
|
||||
local answer
|
||||
echo 1>&2 "$@" "[y/n]"
|
||||
read -r answer
|
||||
case "$answer" in
|
||||
y|Y|yes|Yes|YES)
|
||||
return 0
|
||||
;;
|
||||
n|N|no|No|NO)
|
||||
return 1
|
||||
;;
|
||||
*)
|
||||
echo 1>&2 "please answer y or n"
|
||||
confirm "$@"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
report_done() {
|
||||
logcmd2 "git" "show" git -c pager.show=false show
|
||||
printf 1>&2 "release-notes: \033[32;1mdone\033[0m\n"
|
||||
}
|
||||
|
||||
# --- PARSE ARGS ---
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
die "Release notes takes no arguments, but make sure to set VERSION."
|
||||
fi
|
||||
|
||||
# --- CHECKS ---
|
||||
|
||||
if [[ ! -e flake.nix ]] || [[ ! -e .git ]]; then
|
||||
die "must run in repo root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# repo must be clean
|
||||
if ! git diff --quiet; then
|
||||
die "repo is dirty, please commit or stash changes"
|
||||
fi
|
||||
|
||||
if ! git diff --quiet --cached; then
|
||||
die "repo has staged changes, please commit or stash them"
|
||||
fi
|
||||
|
||||
if ! grep "$SUMMARY_MARKER_LINE" doc/manual/src/SUMMARY.md.in >/dev/null; then
|
||||
# would have been nice to catch this early, but won't be worth the extra infra
|
||||
die "SUMMARY.md.in is missing the marker line '$SUMMARY_MARKER_LINE', which would be used for inserting a new release notes page. Please fix the script."
|
||||
fi
|
||||
|
||||
if [[ ! -n "${VERSION:-}" ]]; then
|
||||
die "please set the VERSION environment variable before invoking this script"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# version_major_minor: MAJOR.MINOR
|
||||
# version_full: MAJOR.MINOR.PATCH
|
||||
# IS_PATCH: true if this is a patch release; append instead of create
|
||||
if grep -E '^[0-9]+\.[0-9]+$' <<< "$VERSION" >/dev/null; then
|
||||
log 'is minor'
|
||||
IS_PATCH=false
|
||||
version_full="$VERSION.0"
|
||||
version_major_minor="$VERSION"
|
||||
elif grep -E '^[0-9]+\.[0-9]+\.0$' <<< "$VERSION" >/dev/null; then
|
||||
log 'is minor (.0)'
|
||||
IS_PATCH=false
|
||||
version_full="$VERSION"
|
||||
version_major_minor="$(echo "$VERSION" | sed -e 's/\.0$//')"
|
||||
elif grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' <<< "$VERSION" >/dev/null; then
|
||||
log 'is patch'
|
||||
IS_PATCH=true
|
||||
version_full="$VERSION"
|
||||
version_major_minor="$(echo "$VERSION" | sed -e 's/\.[0-9]*$//')"
|
||||
else
|
||||
die "VERSION must be MAJOR.MINOR[.PATCH], where each is a number, e.g. 2.20 or 2.20.1 (VERSION was set to $VERSION)"
|
||||
fi
|
||||
|
||||
unset VERSION
|
||||
|
||||
log "version_major_minor=$version_major_minor"
|
||||
log "version_full=$version_full"
|
||||
log "IS_PATCH=$IS_PATCH"
|
||||
|
||||
basename=rl-${version_major_minor}.md
|
||||
file=doc/manual/src/release-notes/$basename
|
||||
|
||||
if ! $IS_PATCH; then
|
||||
if [[ -e $file ]]; then
|
||||
die "release notes file $file already exists. If you'd like to make a minor release, pass a patch version, e.g. 2.20.1"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- DEFAULTS ---
|
||||
|
||||
if [[ ! -n "${DATE:-}" ]]; then
|
||||
DATE="$(date +%Y-%m-%d)"
|
||||
log "DATE not set, using $DATE"
|
||||
fi
|
||||
|
||||
case "$DATE" in
|
||||
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9])
|
||||
;;
|
||||
*)
|
||||
die "DATE must be YYYY-MM-DD, e.g. 2021-12-31 (DATE was set to $DATE)"
|
||||
;;
|
||||
esac
|
||||
|
||||
# --- DO THE WORK ---
|
||||
|
||||
# menu
|
||||
title="Release $version_major_minor ($DATE)"
|
||||
# section on page
|
||||
section_title="Release $version_full ($DATE)"
|
||||
|
||||
(
|
||||
# TODO add minor number, and append?
|
||||
echo "# $section_title"
|
||||
echo
|
||||
changelog-d doc/manual/rl-next | sed -e 's/ *$//'
|
||||
) | tee -a $file
|
||||
|
||||
log "Wrote $file"
|
||||
|
||||
if ! $IS_PATCH; then
|
||||
NEW_SUMMARY_LINE=" - [$title](release-notes/$basename)"
|
||||
|
||||
# find the marker line, insert new link after it
|
||||
escaped_marker="$(echo "$SUMMARY_MARKER_LINE" | sed -e 's/\//\\\//g' -e 's/ /\\ /g')"
|
||||
escaped_line="$(echo "$NEW_SUMMARY_LINE" | sed -e 's/\//\\\//g' -e 's/ /\\ /g')"
|
||||
logcmd sed -i -e "/$escaped_marker/a $escaped_line" doc/manual/src/SUMMARY.md.in
|
||||
fi
|
||||
|
||||
for f in doc/manual/rl-next/*.md; do
|
||||
if [[ config != "$(basename $f)" ]]; then
|
||||
logcmd git rm $f
|
||||
fi
|
||||
done
|
||||
|
||||
logcmd git add $file doc/manual/src/SUMMARY.md.in
|
||||
logcmd git status
|
||||
logcmd git commit -m "release notes: $version_full"
|
||||
|
||||
report_done
|
|
@ -24,34 +24,23 @@ release:
|
|||
* In a checkout of the Nix repo, make sure you're on `master` and run
|
||||
`git pull`.
|
||||
|
||||
* Move the contents of `doc/manual/src/release-notes/rl-next.md`
|
||||
(except the first line) to
|
||||
`doc/manual/src/release-notes/rl-$VERSION.md` (where `$VERSION` is
|
||||
the contents of `.version` *without* the patch level, e.g. `2.12`
|
||||
rather than `2.12.0`).
|
||||
|
||||
* Add a header to `doc/manual/src/release-notes/rl-$VERSION.md` like
|
||||
|
||||
```
|
||||
# Release 2.12 (2022-12-06)
|
||||
```
|
||||
|
||||
* Proof-read / edit / rearrange the release notes. Breaking changes
|
||||
and highlights should go to the top.
|
||||
|
||||
* Add a link to the release notes to `doc/manual/src/SUMMARY.md.in`
|
||||
(*not* `SUMMARY.md`), e.g.
|
||||
|
||||
```
|
||||
- [Release 2.12 (2022-12-06)](release-notes/rl-2.12.md)
|
||||
```
|
||||
|
||||
* Run
|
||||
* Compile the release notes by running
|
||||
|
||||
```console
|
||||
$ git checkout -b release-notes
|
||||
$ git add doc/manual/src/release-notes/rl-$VERSION.md
|
||||
$ git commit -a -m '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
|
||||
```
|
||||
|
||||
|
@ -67,15 +56,17 @@ release:
|
|||
$ git checkout -b $VERSION-maintenance
|
||||
```
|
||||
|
||||
* Mark the release as stable:
|
||||
* Mark the release as official:
|
||||
|
||||
```console
|
||||
$ git cherry-pick f673551e71942a52b6d7ae66af8b67140904a76a
|
||||
$ sed -e 's/officialRelease = false;/officialRelease = true;/' -i flake.nix
|
||||
```
|
||||
|
||||
This removes the link to `rl-next.md` from the manual and sets
|
||||
`officialRelease = true` in `flake.nix`.
|
||||
|
||||
* Commit
|
||||
|
||||
* Push the release branch:
|
||||
|
||||
```console
|
||||
|
@ -159,6 +150,30 @@ release:
|
|||
|
||||
## 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.
|
||||
|
||||
|
|
31
misc/changelog-d.cabal.nix
Normal file
31
misc/changelog-d.cabal.nix
Normal file
|
@ -0,0 +1,31 @@
|
|||
{ mkDerivation, aeson, base, bytestring, cabal-install-parsers
|
||||
, Cabal-syntax, containers, directory, filepath, frontmatter
|
||||
, generic-lens-lite, lib, mtl, optparse-applicative, parsec, pretty
|
||||
, regex-applicative, text, pkgs
|
||||
}:
|
||||
let rev = "f30f6969e9cd8b56242309639d58acea21c99d06";
|
||||
in
|
||||
mkDerivation {
|
||||
pname = "changelog-d";
|
||||
version = "0.1";
|
||||
src = pkgs.fetchurl {
|
||||
name = "changelog-d-${rev}.tar.gz";
|
||||
url = "https://codeberg.org/roberth/changelog-d/archive/${rev}.tar.gz";
|
||||
hash = "sha256-8a2+i5u7YoszAgd5OIEW0eYUcP8yfhtoOIhLJkylYJ4=";
|
||||
} // { inherit rev; };
|
||||
isLibrary = false;
|
||||
isExecutable = true;
|
||||
libraryHaskellDepends = [
|
||||
aeson base bytestring cabal-install-parsers Cabal-syntax containers
|
||||
directory filepath frontmatter generic-lens-lite mtl parsec pretty
|
||||
regex-applicative text
|
||||
];
|
||||
executableHaskellDepends = [
|
||||
base bytestring Cabal-syntax directory filepath
|
||||
optparse-applicative
|
||||
];
|
||||
doHaddock = false;
|
||||
description = "Concatenate changelog entries into a single one";
|
||||
license = lib.licenses.gpl3Plus;
|
||||
mainProgram = "changelog-d";
|
||||
}
|
31
misc/changelog-d.nix
Normal file
31
misc/changelog-d.nix
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Taken temporarily from <nixpkgs/pkgs/by-name/ch/changelog-d/package.nix>
|
||||
{
|
||||
callPackage,
|
||||
lib,
|
||||
haskell,
|
||||
haskellPackages,
|
||||
}:
|
||||
|
||||
let
|
||||
hsPkg = haskellPackages.callPackage ./changelog-d.cabal.nix { };
|
||||
|
||||
addCompletions = haskellPackages.generateOptparseApplicativeCompletions ["changelog-d"];
|
||||
|
||||
haskellModifications =
|
||||
lib.flip lib.pipe [
|
||||
addCompletions
|
||||
haskell.lib.justStaticExecutables
|
||||
];
|
||||
|
||||
mkDerivationOverrides = finalAttrs: oldAttrs: {
|
||||
|
||||
version = oldAttrs.version + "-git-${lib.strings.substring 0 7 oldAttrs.src.rev}";
|
||||
|
||||
meta = oldAttrs.meta // {
|
||||
homepage = "https://codeberg.org/roberth/changelog-d";
|
||||
maintainers = [ lib.maintainers.roberth ];
|
||||
};
|
||||
|
||||
};
|
||||
in
|
||||
(haskellModifications hsPkg).overrideAttrs mkDerivationOverrides
|
10
mk/build-dir.mk
Normal file
10
mk/build-dir.mk
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Initialise support for build directories.
|
||||
builddir ?=
|
||||
|
||||
ifdef builddir
|
||||
buildprefix = $(builddir)/
|
||||
buildprefixrel = $(builddir)
|
||||
else
|
||||
buildprefix =
|
||||
buildprefixrel = .
|
||||
endif
|
|
@ -1,15 +1,27 @@
|
|||
test_dir=tests/functional
|
||||
# Remove overall test dir (at most one of the two should match) and
|
||||
# remove file extension.
|
||||
test_name=$(echo -n "$test" | sed \
|
||||
-e "s|^tests/unit/[^/]*/data/||" \
|
||||
-e "s|^tests/functional/||" \
|
||||
-e "s|\.sh$||" \
|
||||
)
|
||||
|
||||
test=$(echo -n "$test" | sed -e "s|^$test_dir/||")
|
||||
|
||||
TESTS_ENVIRONMENT=("TEST_NAME=${test%.*}" 'NIX_REMOTE=')
|
||||
TESTS_ENVIRONMENT=(
|
||||
"TEST_NAME=$test_name"
|
||||
'NIX_REMOTE='
|
||||
'PS4=+(${BASH_SOURCE[0]-$0}:$LINENO) '
|
||||
)
|
||||
|
||||
: ${BASH:=/usr/bin/env bash}
|
||||
|
||||
run () {
|
||||
cd "$(dirname $1)" && env "${TESTS_ENVIRONMENT[@]}" $BASH -x -e -u -o pipefail $(basename $1)
|
||||
}
|
||||
|
||||
init_test () {
|
||||
cd "$test_dir" && env "${TESTS_ENVIRONMENT[@]}" $BASH -e init.sh 2>/dev/null > /dev/null
|
||||
run "$init" 2>/dev/null > /dev/null
|
||||
}
|
||||
|
||||
run_test_proper () {
|
||||
cd "$test_dir/$(dirname $test)" && env "${TESTS_ENVIRONMENT[@]}" $BASH -e $(basename $test)
|
||||
run "$test"
|
||||
}
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
set -eu -o pipefail
|
||||
|
||||
test=$1
|
||||
init=${2-}
|
||||
|
||||
dir="$(dirname "${BASH_SOURCE[0]}")"
|
||||
source "$dir/common-test.sh"
|
||||
|
||||
(init_test)
|
||||
if [ -n "$init" ]; then
|
||||
(init_test)
|
||||
fi
|
||||
run_test_proper
|
||||
|
|
11
mk/install-dirs.mk
Normal file
11
mk/install-dirs.mk
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Default installation paths.
|
||||
prefix ?= /usr/local
|
||||
libdir ?= $(prefix)/lib
|
||||
bindir ?= $(prefix)/bin
|
||||
libexecdir ?= $(prefix)/libexec
|
||||
datadir ?= $(prefix)/share
|
||||
localstatedir ?= $(prefix)/var
|
||||
sysconfdir ?= $(prefix)/etc
|
||||
mandir ?= $(prefix)/share/man
|
||||
|
||||
DESTDIR ?=
|
32
mk/lib.mk
32
mk/lib.mk
|
@ -43,27 +43,6 @@ define newline
|
|||
endef
|
||||
|
||||
|
||||
# Default installation paths.
|
||||
prefix ?= /usr/local
|
||||
libdir ?= $(prefix)/lib
|
||||
bindir ?= $(prefix)/bin
|
||||
libexecdir ?= $(prefix)/libexec
|
||||
datadir ?= $(prefix)/share
|
||||
localstatedir ?= $(prefix)/var
|
||||
sysconfdir ?= $(prefix)/etc
|
||||
mandir ?= $(prefix)/share/man
|
||||
|
||||
|
||||
# Initialise support for build directories.
|
||||
builddir ?=
|
||||
|
||||
ifdef builddir
|
||||
buildprefix = $(builddir)/
|
||||
else
|
||||
buildprefix =
|
||||
endif
|
||||
|
||||
|
||||
# Pass -fPIC if we're building dynamic libraries.
|
||||
BUILD_SHARED_LIBS ?= 1
|
||||
|
||||
|
@ -94,6 +73,8 @@ ifeq ($(BUILD_DEBUG), 1)
|
|||
endif
|
||||
|
||||
|
||||
include mk/build-dir.mk
|
||||
include mk/install-dirs.mk
|
||||
include mk/functions.mk
|
||||
include mk/tracing.mk
|
||||
include mk/clean.mk
|
||||
|
@ -112,7 +93,7 @@ define include-sub-makefile
|
|||
include $(1)
|
||||
endef
|
||||
|
||||
$(foreach mf, $(makefiles), $(eval $(call include-sub-makefile, $(mf))))
|
||||
$(foreach mf, $(makefiles), $(eval $(call include-sub-makefile,$(mf))))
|
||||
|
||||
|
||||
# Instantiate stuff.
|
||||
|
@ -122,14 +103,15 @@ $(foreach script, $(bin-scripts), $(eval $(call install-program-in,$(script),$(b
|
|||
$(foreach script, $(bin-scripts), $(eval programs-list += $(script)))
|
||||
$(foreach script, $(noinst-scripts), $(eval programs-list += $(script)))
|
||||
$(foreach template, $(template-files), $(eval $(call instantiate-template,$(template))))
|
||||
install_test_init=tests/functional/init.sh
|
||||
$(foreach test, $(install-tests), \
|
||||
$(eval $(call run-install-test,$(test))) \
|
||||
$(eval $(call run-test,$(test),$(install_test_init))) \
|
||||
$(eval installcheck: $(test).test))
|
||||
$(foreach test-group, $(install-tests-groups), \
|
||||
$(eval $(call run-install-test-group,$(test-group))) \
|
||||
$(eval $(call run-test-group,$(test-group),$(install_test_init))) \
|
||||
$(eval installcheck: $(test-group).test-group) \
|
||||
$(foreach test, $($(test-group)-tests), \
|
||||
$(eval $(call run-install-test,$(test))) \
|
||||
$(eval $(call run-test,$(test),$(install_test_init))) \
|
||||
$(eval $(test-group).test-group: $(test).test)))
|
||||
|
||||
$(foreach file, $(man-pages), $(eval $(call install-data-in, $(file), $(mandir)/man$(patsubst .%,%,$(suffix $(file))))))
|
||||
|
|
|
@ -87,6 +87,6 @@ define build-program
|
|||
# Phony target to run this program (typically as a dependency of 'check').
|
||||
.PHONY: $(1)_RUN
|
||||
$(1)_RUN: $$($(1)_PATH)
|
||||
$(trace-test) $$(UNIT_TEST_ENV) $$($(1)_PATH)
|
||||
$(trace-test) $$($(1)_ENV) $$($(1)_PATH)
|
||||
|
||||
endef
|
||||
|
|
|
@ -8,6 +8,7 @@ yellow=""
|
|||
normal=""
|
||||
|
||||
test=$1
|
||||
init=${2-}
|
||||
|
||||
dir="$(dirname "${BASH_SOURCE[0]}")"
|
||||
source "$dir/common-test.sh"
|
||||
|
@ -21,7 +22,9 @@ if [ -t 1 ]; then
|
|||
fi
|
||||
|
||||
run_test () {
|
||||
(init_test 2>/dev/null > /dev/null)
|
||||
if [ -n "$init" ]; then
|
||||
(init_test 2>/dev/null > /dev/null)
|
||||
fi
|
||||
log="$(run_test_proper 2>&1)" && status=0 || status=$?
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ endef
|
|||
|
||||
ifneq ($(MAKECMDGOALS), clean)
|
||||
|
||||
%.h: %.h.in
|
||||
$(trace-gen) rm -f $@ && ./config.status --quiet --header=$@
|
||||
$(buildprefix)%.h: %.h.in
|
||||
$(trace-gen) rm -f $@ && cd $(buildprefixrel) && ./config.status --quiet --header=$(@:$(buildprefix)%=%)
|
||||
|
||||
%: %.in
|
||||
$(trace-gen) rm -f $@ && ./config.status --quiet --file=$@
|
||||
$(buildprefix)%: %.in
|
||||
$(trace-gen) rm -f $@ && cd $(buildprefixrel) && ./config.status --quiet --file=$(@:$(buildprefix)%=%)
|
||||
|
||||
endif
|
||||
|
|
21
mk/tests.mk
21
mk/tests.mk
|
@ -2,19 +2,22 @@
|
|||
|
||||
test-deps =
|
||||
|
||||
define run-install-test
|
||||
define run-bash
|
||||
|
||||
.PHONY: $1.test
|
||||
$1.test: $1 $(test-deps)
|
||||
@env BASH=$(bash) $(bash) mk/run-test.sh $1 < /dev/null
|
||||
|
||||
.PHONY: $1.test-debug
|
||||
$1.test-debug: $1 $(test-deps)
|
||||
@env BASH=$(bash) $(bash) mk/debug-test.sh $1 < /dev/null
|
||||
.PHONY: $1
|
||||
$1: $2
|
||||
@env BASH=$(bash) $(bash) $3 < /dev/null
|
||||
|
||||
endef
|
||||
|
||||
define run-install-test-group
|
||||
define run-test
|
||||
|
||||
$(eval $(call run-bash,$1.test,$1 $(test-deps),mk/run-test.sh $1 $2))
|
||||
$(eval $(call run-bash,$1.test-debug,$1 $(test-deps),mk/debug-test.sh $1 $2))
|
||||
|
||||
endef
|
||||
|
||||
define run-test-group
|
||||
|
||||
.PHONY: $1.test-group
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#undef do_close
|
||||
|
||||
#include "derivations.hh"
|
||||
#include "realisation.hh"
|
||||
#include "globals.hh"
|
||||
#include "store-api.hh"
|
||||
#include "util.hh"
|
||||
#include "crypto.hh"
|
||||
|
||||
#include <sodium.h>
|
||||
|
@ -78,7 +78,7 @@ SV * queryReferences(char * path)
|
|||
SV * queryPathHash(char * path)
|
||||
PPCODE:
|
||||
try {
|
||||
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string(HashFormat::Base32, true);
|
||||
auto s = store()->queryPathInfo(store()->parseStorePath(path))->narHash.to_string(HashFormat::Nix32, true);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -104,7 +104,7 @@ SV * queryPathInfo(char * path, int base32)
|
|||
XPUSHs(&PL_sv_undef);
|
||||
else
|
||||
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(*info->deriver).c_str(), 0)));
|
||||
auto s = info->narHash.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, true);
|
||||
auto s = info->narHash.to_string(base32 ? HashFormat::Nix32 : HashFormat::Base16, true);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
mXPUSHi(info->registrationTime);
|
||||
mXPUSHi(info->narSize);
|
||||
|
@ -205,8 +205,8 @@ void importPaths(int fd, int dontCheckSigs)
|
|||
SV * hashPath(char * algo, int base32, char * path)
|
||||
PPCODE:
|
||||
try {
|
||||
Hash h = hashPath(parseHashType(algo), path).first;
|
||||
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
Hash h = hashPath(parseHashAlgo(algo), path).first;
|
||||
auto s = h.to_string(base32 ? HashFormat::Nix32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -216,8 +216,8 @@ SV * hashPath(char * algo, int base32, char * path)
|
|||
SV * hashFile(char * algo, int base32, char * path)
|
||||
PPCODE:
|
||||
try {
|
||||
Hash h = hashFile(parseHashType(algo), path);
|
||||
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
Hash h = hashFile(parseHashAlgo(algo), path);
|
||||
auto s = h.to_string(base32 ? HashFormat::Nix32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -227,8 +227,8 @@ SV * hashFile(char * algo, int base32, char * path)
|
|||
SV * hashString(char * algo, int base32, char * s)
|
||||
PPCODE:
|
||||
try {
|
||||
Hash h = hashString(parseHashType(algo), s);
|
||||
auto s = h.to_string(base32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
Hash h = hashString(parseHashAlgo(algo), s);
|
||||
auto s = h.to_string(base32 ? HashFormat::Nix32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -238,8 +238,8 @@ SV * hashString(char * algo, int base32, char * s)
|
|||
SV * convertHash(char * algo, char * s, int toBase32)
|
||||
PPCODE:
|
||||
try {
|
||||
auto h = Hash::parseAny(s, parseHashType(algo));
|
||||
auto s = h.to_string(toBase32 ? HashFormat::Base32 : HashFormat::Base16, false);
|
||||
auto h = Hash::parseAny(s, parseHashAlgo(algo));
|
||||
auto s = h.to_string(toBase32 ? HashFormat::Nix32 : HashFormat::Base16, false);
|
||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -281,7 +281,7 @@ SV * addToStore(char * srcPath, int recursive, char * algo)
|
|||
PPCODE:
|
||||
try {
|
||||
auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat;
|
||||
auto path = store()->addToStore(std::string(baseNameOf(srcPath)), srcPath, method, parseHashType(algo));
|
||||
auto path = store()->addToStore(std::string(baseNameOf(srcPath)), srcPath, method, parseHashAlgo(algo));
|
||||
XPUSHs(sv_2mortal(newSVpv(store()->printStorePath(path).c_str(), 0)));
|
||||
} catch (Error & e) {
|
||||
croak("%s", e.what());
|
||||
|
@ -291,7 +291,7 @@ SV * addToStore(char * srcPath, int recursive, char * algo)
|
|||
SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
|
||||
PPCODE:
|
||||
try {
|
||||
auto h = Hash::parseAny(hash, parseHashType(algo));
|
||||
auto h = Hash::parseAny(hash, parseHashAlgo(algo));
|
||||
auto method = recursive ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat;
|
||||
auto path = store()->makeFixedOutputPath(name, FixedOutputInfo {
|
||||
.method = method,
|
||||
|
|
|
@ -19,6 +19,14 @@ set __ETC_PROFILE_NIX_SOURCED 1
|
|||
|
||||
set --export NIX_PROFILES "@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
||||
|
||||
# Populate bash completions, .desktop files, etc
|
||||
if test -z "$XDG_DATA_DIRS"
|
||||
# According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default
|
||||
set --export XDG_DATA_DIRS "/usr/local/share:/usr/share:/nix/var/nix/profiles/default/share"
|
||||
else
|
||||
set --export XDG_DATA_DIRS "$XDG_DATA_DIRS:/nix/var/nix/profiles/default/share"
|
||||
end
|
||||
|
||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||
if test -n "$NIX_SSH_CERT_FILE"
|
||||
: # Allow users to override the NIX_SSL_CERT_FILE
|
||||
|
|
|
@ -30,6 +30,14 @@ fi
|
|||
|
||||
export NIX_PROFILES="@localstatedir@/nix/profiles/default $NIX_LINK"
|
||||
|
||||
# Populate bash completions, .desktop files, etc
|
||||
if [ -z "${XDG_DATA_DIRS-}" ]; then
|
||||
# According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default
|
||||
export XDG_DATA_DIRS="/usr/local/share:/usr/share:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||
else
|
||||
export XDG_DATA_DIRS="$XDG_DATA_DIRS:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||
fi
|
||||
|
||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||
if [ -n "${NIX_SSL_CERT_FILE:-}" ]; then
|
||||
: # Allow users to override the NIX_SSL_CERT_FILE
|
||||
|
|
|
@ -20,6 +20,14 @@ if test -n "$HOME" && test -n "$USER"
|
|||
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
|
||||
set --export NIX_PROFILES "@localstatedir@/nix/profiles/default $HOME/.nix-profile"
|
||||
|
||||
# Populate bash completions, .desktop files, etc
|
||||
if test -z "$XDG_DATA_DIRS"
|
||||
# According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default
|
||||
set --export XDG_DATA_DIRS "/usr/local/share:/usr/share:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||
else
|
||||
set --export XDG_DATA_DIRS "$XDG_DATA_DIRS:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||
end
|
||||
|
||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||
if test -n "$NIX_SSH_CERT_FILE"
|
||||
: # Allow users to override the NIX_SSL_CERT_FILE
|
||||
|
|
|
@ -32,6 +32,14 @@ if [ -n "$HOME" ] && [ -n "$USER" ]; then
|
|||
# This part should be kept in sync with nixpkgs:nixos/modules/programs/environment.nix
|
||||
export NIX_PROFILES="@localstatedir@/nix/profiles/default $NIX_LINK"
|
||||
|
||||
# Populate bash completions, .desktop files, etc
|
||||
if [ -z "${XDG_DATA_DIRS-}" ]; then
|
||||
# According to XDG spec the default is /usr/local/share:/usr/share, don't set something that prevents that default
|
||||
export XDG_DATA_DIRS="/usr/local/share:/usr/share:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||
else
|
||||
export XDG_DATA_DIRS="$XDG_DATA_DIRS:$NIX_LINK/share:/nix/var/nix/profiles/default/share"
|
||||
fi
|
||||
|
||||
# Set $NIX_SSL_CERT_FILE so that Nixpkgs applications like curl work.
|
||||
if [ -e /etc/ssl/certs/ca-certificates.crt ]; then # NixOS, Ubuntu, Debian, Gentoo, Arch
|
||||
export NIX_SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
|
||||
|
|
|
@ -80,7 +80,7 @@ SingleDerivedPath SingleBuiltPath::discardOutputPath() const
|
|||
);
|
||||
}
|
||||
|
||||
nlohmann::json BuiltPath::Built::toJSON(const Store & store) const
|
||||
nlohmann::json BuiltPath::Built::toJSON(const StoreDirConfig & store) const
|
||||
{
|
||||
nlohmann::json res;
|
||||
res["drvPath"] = drvPath->toJSON(store);
|
||||
|
@ -90,7 +90,7 @@ nlohmann::json BuiltPath::Built::toJSON(const Store & store) const
|
|||
return res;
|
||||
}
|
||||
|
||||
nlohmann::json SingleBuiltPath::Built::toJSON(const Store & store) const
|
||||
nlohmann::json SingleBuiltPath::Built::toJSON(const StoreDirConfig & store) const
|
||||
{
|
||||
nlohmann::json res;
|
||||
res["drvPath"] = drvPath->toJSON(store);
|
||||
|
@ -100,14 +100,14 @@ nlohmann::json SingleBuiltPath::Built::toJSON(const Store & store) const
|
|||
return res;
|
||||
}
|
||||
|
||||
nlohmann::json SingleBuiltPath::toJSON(const Store & store) const
|
||||
nlohmann::json SingleBuiltPath::toJSON(const StoreDirConfig & store) const
|
||||
{
|
||||
return std::visit([&](const auto & buildable) {
|
||||
return buildable.toJSON(store);
|
||||
}, raw());
|
||||
}
|
||||
|
||||
nlohmann::json BuiltPath::toJSON(const Store & store) const
|
||||
nlohmann::json BuiltPath::toJSON(const StoreDirConfig & store) const
|
||||
{
|
||||
return std::visit([&](const auto & buildable) {
|
||||
return buildable.toJSON(store);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "derived-path.hh"
|
||||
#include "realisation.hh"
|
||||
|
||||
|
@ -11,9 +14,9 @@ struct SingleBuiltPathBuilt {
|
|||
|
||||
SingleDerivedPathBuilt discardOutputPath() const;
|
||||
|
||||
std::string to_string(const Store & store) const;
|
||||
static SingleBuiltPathBuilt parse(const Store & store, std::string_view, std::string_view);
|
||||
nlohmann::json toJSON(const Store & store) const;
|
||||
std::string to_string(const StoreDirConfig & store) const;
|
||||
static SingleBuiltPathBuilt parse(const StoreDirConfig & store, std::string_view, std::string_view);
|
||||
nlohmann::json toJSON(const StoreDirConfig & store) const;
|
||||
|
||||
DECLARE_CMP(SingleBuiltPathBuilt);
|
||||
};
|
||||
|
@ -38,8 +41,8 @@ struct SingleBuiltPath : _SingleBuiltPathRaw {
|
|||
|
||||
SingleDerivedPath discardOutputPath() const;
|
||||
|
||||
static SingleBuiltPath parse(const Store & store, std::string_view);
|
||||
nlohmann::json toJSON(const Store & store) const;
|
||||
static SingleBuiltPath parse(const StoreDirConfig & store, std::string_view);
|
||||
nlohmann::json toJSON(const StoreDirConfig & store) const;
|
||||
};
|
||||
|
||||
static inline ref<SingleBuiltPath> staticDrv(StorePath drvPath)
|
||||
|
@ -56,9 +59,9 @@ struct BuiltPathBuilt {
|
|||
ref<SingleBuiltPath> drvPath;
|
||||
std::map<std::string, StorePath> outputs;
|
||||
|
||||
std::string to_string(const Store & store) const;
|
||||
static BuiltPathBuilt parse(const Store & store, std::string_view, std::string_view);
|
||||
nlohmann::json toJSON(const Store & store) const;
|
||||
std::string to_string(const StoreDirConfig & store) const;
|
||||
static BuiltPathBuilt parse(const StoreDirConfig & store, std::string_view, std::string_view);
|
||||
nlohmann::json toJSON(const StoreDirConfig & store) const;
|
||||
|
||||
DECLARE_CMP(BuiltPathBuilt);
|
||||
};
|
||||
|
@ -86,7 +89,7 @@ struct BuiltPath : _BuiltPathRaw {
|
|||
StorePathSet outPaths() const;
|
||||
RealisedPath::Set toRealisedPaths(Store & store) const;
|
||||
|
||||
nlohmann::json toJSON(const Store & store) const;
|
||||
nlohmann::json toJSON(const StoreDirConfig & store) const;
|
||||
};
|
||||
|
||||
typedef std::vector<BuiltPath> BuiltPaths;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "command.hh"
|
||||
#include "markdown.hh"
|
||||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "derivations.hh"
|
||||
|
@ -34,6 +35,19 @@ nlohmann::json NixMultiCommand::toJSON()
|
|||
return MultiCommand::toJSON();
|
||||
}
|
||||
|
||||
void NixMultiCommand::run()
|
||||
{
|
||||
if (!command) {
|
||||
std::set<std::string> subCommandTextLines;
|
||||
for (auto & [name, _] : commands)
|
||||
subCommandTextLines.insert(fmt("- `%s`", name));
|
||||
std::string markdownError = fmt("`nix %s` requires a sub-command. Available sub-commands:\n\n%s\n",
|
||||
commandName, concatStringsSep("\n", subCommandTextLines));
|
||||
throw UsageError(renderMarkdownToTerminal(markdownError));
|
||||
}
|
||||
command->second->run();
|
||||
}
|
||||
|
||||
StoreCommand::StoreCommand()
|
||||
{
|
||||
}
|
||||
|
@ -175,7 +189,7 @@ void BuiltPathsCommand::run(ref<Store> store, Installables && installables)
|
|||
throw UsageError("'--all' does not expect arguments");
|
||||
// XXX: Only uses opaque paths, ignores all the realisations
|
||||
for (auto & p : store->queryAllValidPaths())
|
||||
paths.push_back(BuiltPath::Opaque{p});
|
||||
paths.emplace_back(BuiltPath::Opaque{p});
|
||||
} else {
|
||||
paths = Installable::toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
|
||||
if (recursive) {
|
||||
|
@ -188,7 +202,7 @@ void BuiltPathsCommand::run(ref<Store> store, Installables && installables)
|
|||
}
|
||||
store->computeFSClosure(pathsRoots, pathsClosure);
|
||||
for (auto & path : pathsClosure)
|
||||
paths.push_back(BuiltPath::Opaque{path});
|
||||
paths.emplace_back(BuiltPath::Opaque{path});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,13 @@ static constexpr Command::Category catNixInstallation = 102;
|
|||
|
||||
static constexpr auto installablesCategory = "Options that change the interpretation of [installables](@docroot@/command-ref/new-cli/nix.md#installables)";
|
||||
|
||||
struct NixMultiCommand : virtual MultiCommand, virtual Command
|
||||
struct NixMultiCommand : MultiCommand, virtual Command
|
||||
{
|
||||
nlohmann::json toJSON() override;
|
||||
|
||||
using MultiCommand::MultiCommand;
|
||||
|
||||
virtual void run() override;
|
||||
};
|
||||
|
||||
// For the overloaded run methods
|
||||
|
@ -326,6 +330,12 @@ struct MixEnvironment : virtual Args {
|
|||
void setEnviron();
|
||||
};
|
||||
|
||||
void completeFlakeInputPath(
|
||||
AddCompletions & completions,
|
||||
ref<EvalState> evalState,
|
||||
const std::vector<FlakeRef> & flakeRefs,
|
||||
std::string_view prefix);
|
||||
|
||||
void completeFlakeRef(AddCompletions & completions, ref<Store> store, std::string_view prefix);
|
||||
|
||||
void completeFlakeRefWithFragment(
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include "common-eval-args.hh"
|
||||
#include "shared.hh"
|
||||
#include "filetransfer.hh"
|
||||
#include "util.hh"
|
||||
#include "eval.hh"
|
||||
#include "fetchers.hh"
|
||||
#include "registry.hh"
|
||||
|
@ -142,7 +141,7 @@ MixEvalArgs::MixEvalArgs()
|
|||
.longName = "eval-store",
|
||||
.description =
|
||||
R"(
|
||||
The [URL of the Nix store](@docroot@/command-ref/new-cli/nix3-help-stores.md#store-url-format)
|
||||
The [URL of the Nix store](@docroot@/store/types/index.md#store-url-format)
|
||||
to use for evaluation, i.e. to store derivations (`.drv` files) and inputs referenced by them.
|
||||
)",
|
||||
.category = category,
|
||||
|
@ -165,7 +164,7 @@ Bindings * MixEvalArgs::getAutoArgs(EvalState & state)
|
|||
return res.finish();
|
||||
}
|
||||
|
||||
SourcePath lookupFileArg(EvalState & state, std::string_view s)
|
||||
SourcePath lookupFileArg(EvalState & state, std::string_view s, CanonPath baseDir)
|
||||
{
|
||||
if (EvalSettings::isPseudoUrl(s)) {
|
||||
auto storePath = fetchers::downloadTarball(
|
||||
|
@ -186,7 +185,7 @@ SourcePath lookupFileArg(EvalState & state, std::string_view s)
|
|||
}
|
||||
|
||||
else
|
||||
return state.rootPath(CanonPath::fromCwd(s));
|
||||
return state.rootPath(CanonPath(s, baseDir));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
///@file
|
||||
|
||||
#include "args.hh"
|
||||
#include "canon-path.hh"
|
||||
#include "common-args.hh"
|
||||
#include "search-path.hh"
|
||||
|
||||
|
@ -28,6 +29,6 @@ private:
|
|||
std::map<std::string, std::string> autoArgs;
|
||||
};
|
||||
|
||||
SourcePath lookupFileArg(EvalState & state, std::string_view s);
|
||||
SourcePath lookupFileArg(EvalState & state, std::string_view s, CanonPath baseDir = CanonPath::fromCwd());
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "util.hh"
|
||||
#include "editor-for.hh"
|
||||
#include "environment-variables.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
#include "globals.hh"
|
||||
#include "installable-value.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "util.hh"
|
||||
#include "command.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "common-eval-args.hh"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "installable-attr-path.hh"
|
||||
#include "installable-flake.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "users.hh"
|
||||
#include "util.hh"
|
||||
#include "command.hh"
|
||||
#include "attr-path.hh"
|
||||
|
@ -28,7 +29,7 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
static void completeFlakeInputPath(
|
||||
void completeFlakeInputPath(
|
||||
AddCompletions & completions,
|
||||
ref<EvalState> evalState,
|
||||
const std::vector<FlakeRef> & flakeRefs,
|
||||
|
@ -48,9 +49,18 @@ MixFlakeOptions::MixFlakeOptions()
|
|||
|
||||
addFlag({
|
||||
.longName = "recreate-lock-file",
|
||||
.description = "Recreate the flake's lock file from scratch.",
|
||||
.description = R"(
|
||||
Recreate the flake's lock file from scratch.
|
||||
|
||||
> **DEPRECATED**
|
||||
>
|
||||
> Use [`nix flake update`](@docroot@/command-ref/new-cli/nix3-flake-update.md) instead.
|
||||
)",
|
||||
.category = category,
|
||||
.handler = {&lockFlags.recreateLockFile, true}
|
||||
.handler = {[&]() {
|
||||
lockFlags.recreateLockFile = true;
|
||||
warn("'--recreate-lock-file' is deprecated and will be removed in a future version; use 'nix flake update' instead.");
|
||||
}}
|
||||
});
|
||||
|
||||
addFlag({
|
||||
|
@ -69,8 +79,13 @@ MixFlakeOptions::MixFlakeOptions()
|
|||
|
||||
addFlag({
|
||||
.longName = "no-registries",
|
||||
.description =
|
||||
"Don't allow lookups in the flake registries. This option is deprecated; use `--no-use-registries`.",
|
||||
.description = R"(
|
||||
Don't allow lookups in the flake registries.
|
||||
|
||||
> **DEPRECATED**
|
||||
>
|
||||
> Use [`--no-use-registries`](#opt-no-use-registries) instead.
|
||||
)",
|
||||
.category = category,
|
||||
.handler = {[&]() {
|
||||
lockFlags.useRegistries = false;
|
||||
|
@ -87,10 +102,17 @@ MixFlakeOptions::MixFlakeOptions()
|
|||
|
||||
addFlag({
|
||||
.longName = "update-input",
|
||||
.description = "Update a specific flake input (ignoring its previous entry in the lock file).",
|
||||
.description = R"(
|
||||
Update a specific flake input (ignoring its previous entry in the lock file).
|
||||
|
||||
> **DEPRECATED**
|
||||
>
|
||||
> Use [`nix flake update`](@docroot@/command-ref/new-cli/nix3-flake-update.md) instead.
|
||||
)",
|
||||
.category = category,
|
||||
.labels = {"input-path"},
|
||||
.handler = {[&](std::string s) {
|
||||
warn("'--update-input' is a deprecated alias for 'flake update' and will be removed in a future version.");
|
||||
lockFlags.inputUpdates.insert(flake::parseInputPath(s));
|
||||
}},
|
||||
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
||||
|
@ -107,7 +129,7 @@ MixFlakeOptions::MixFlakeOptions()
|
|||
lockFlags.writeLockFile = false;
|
||||
lockFlags.inputOverrides.insert_or_assign(
|
||||
flake::parseInputPath(inputPath),
|
||||
parseFlakeRef(flakeRef, absPath("."), true));
|
||||
parseFlakeRef(flakeRef, absPath(getCommandBaseDir()), true));
|
||||
}},
|
||||
.completer = {[&](AddCompletions & completions, size_t n, std::string_view prefix) {
|
||||
if (n == 0) {
|
||||
|
@ -149,7 +171,7 @@ MixFlakeOptions::MixFlakeOptions()
|
|||
auto evalState = getEvalState();
|
||||
auto flake = flake::lockFlake(
|
||||
*evalState,
|
||||
parseFlakeRef(flakeRef, absPath(".")),
|
||||
parseFlakeRef(flakeRef, absPath(getCommandBaseDir())),
|
||||
{ .writeLockFile = false });
|
||||
for (auto & [inputName, input] : flake.lockFile.root->inputs) {
|
||||
auto input2 = flake.lockFile.findInput({inputName}); // resolve 'follows' nodes
|
||||
|
@ -238,9 +260,10 @@ void SourceExprCommand::completeInstallable(AddCompletions & completions, std::s
|
|||
|
||||
evalSettings.pureEval = false;
|
||||
auto state = getEvalState();
|
||||
Expr *e = state->parseExprFromFile(
|
||||
resolveExprPath(state->checkSourcePath(lookupFileArg(*state, *file)))
|
||||
);
|
||||
auto e =
|
||||
state->parseExprFromFile(
|
||||
resolveExprPath(
|
||||
lookupFileArg(*state, *file)));
|
||||
|
||||
Value root;
|
||||
state->eval(e, root);
|
||||
|
@ -313,6 +336,8 @@ void completeFlakeRefWithFragment(
|
|||
prefixRoot = ".";
|
||||
}
|
||||
auto flakeRefS = std::string(prefix.substr(0, hash));
|
||||
|
||||
// TODO: ideally this would use the command base directory instead of assuming ".".
|
||||
auto flakeRef = parseFlakeRef(expandTilde(flakeRefS), absPath("."));
|
||||
|
||||
auto evalCache = openEvalCache(*evalState,
|
||||
|
@ -461,10 +486,12 @@ Installables SourceExprCommand::parseInstallables(
|
|||
auto e = state->parseStdin();
|
||||
state->eval(e, *vFile);
|
||||
}
|
||||
else if (file)
|
||||
state->evalFile(lookupFileArg(*state, *file), *vFile);
|
||||
else if (file) {
|
||||
state->evalFile(lookupFileArg(*state, *file, CanonPath::fromCwd(getCommandBaseDir())), *vFile);
|
||||
}
|
||||
else {
|
||||
auto e = state->parseExprFromString(*expr, state->rootPath(CanonPath::fromCwd()));
|
||||
CanonPath dir(CanonPath::fromCwd(getCommandBaseDir()));
|
||||
auto e = state->parseExprFromString(*expr, state->rootPath(dir));
|
||||
state->eval(e, *vFile);
|
||||
}
|
||||
|
||||
|
@ -499,7 +526,7 @@ Installables SourceExprCommand::parseInstallables(
|
|||
}
|
||||
|
||||
try {
|
||||
auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath("."));
|
||||
auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath(getCommandBaseDir()));
|
||||
result.push_back(make_ref<InstallableFlake>(
|
||||
this,
|
||||
getEvalState(),
|
||||
|
@ -683,7 +710,7 @@ BuiltPaths Installable::toBuiltPaths(
|
|||
|
||||
BuiltPaths res;
|
||||
for (auto & drvPath : Installable::toDerivations(store, installables, true))
|
||||
res.push_back(BuiltPath::Opaque{drvPath});
|
||||
res.emplace_back(BuiltPath::Opaque{drvPath});
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -773,7 +800,7 @@ std::vector<FlakeRef> RawInstallablesCommand::getFlakeRefsForCompletion()
|
|||
for (auto i : rawInstallables)
|
||||
res.push_back(parseFlakeRefWithFragment(
|
||||
expandTilde(i),
|
||||
absPath(".")).first);
|
||||
absPath(getCommandBaseDir())).first);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -795,7 +822,7 @@ std::vector<FlakeRef> InstallableCommand::getFlakeRefsForCompletion()
|
|||
return {
|
||||
parseFlakeRefWithFragment(
|
||||
expandTilde(_installable),
|
||||
absPath(".")).first
|
||||
absPath(getCommandBaseDir())).first
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "util.hh"
|
||||
#include "path.hh"
|
||||
#include "outputs-spec.hh"
|
||||
#include "derived-path.hh"
|
||||
|
|
|
@ -12,4 +12,4 @@ libcmd_LDFLAGS = $(EDITLINE_LIBS) $(LOWDOWN_LIBS) -pthread
|
|||
|
||||
libcmd_LIBS = libstore libutil libexpr libmain libfetchers
|
||||
|
||||
$(eval $(call install-file-in, $(d)/nix-cmd.pc, $(libdir)/pkgconfig, 0644))
|
||||
$(eval $(call install-file-in, $(buildprefix)$(d)/nix-cmd.pc, $(libdir)/pkgconfig, 0644))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "markdown.hh"
|
||||
#include "util.hh"
|
||||
#include "finally.hh"
|
||||
#include "terminal.hh"
|
||||
|
||||
#include <sys/queue.h>
|
||||
#include <lowdown.h>
|
||||
|
|
|
@ -22,6 +22,7 @@ extern "C" {
|
|||
#include "repl.hh"
|
||||
|
||||
#include "ansicolor.hh"
|
||||
#include "signals.hh"
|
||||
#include "shared.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-cache.hh"
|
||||
|
@ -36,11 +37,12 @@ extern "C" {
|
|||
#include "globals.hh"
|
||||
#include "flake/flake.hh"
|
||||
#include "flake/lockfile.hh"
|
||||
#include "users.hh"
|
||||
#include "terminal.hh"
|
||||
#include "editor-for.hh"
|
||||
#include "finally.hh"
|
||||
#include "markdown.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "progress-bar.hh"
|
||||
#include "print.hh"
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
|
@ -259,13 +261,11 @@ void NixRepl::mainLoop()
|
|||
rl_set_list_possib_func(listPossibleCallback);
|
||||
#endif
|
||||
|
||||
/* Stop the progress bar because it interferes with the display of
|
||||
the repl. */
|
||||
stopProgressBar();
|
||||
|
||||
std::string input;
|
||||
|
||||
while (true) {
|
||||
// Hide the progress bar while waiting for user input, so that it won't interfere.
|
||||
logger->pause();
|
||||
// When continuing input from previous lines, don't print a prompt, just align to the same
|
||||
// number of chars as the prompt.
|
||||
if (!getLine(input, input.empty() ? "nix-repl> " : " ")) {
|
||||
|
@ -275,6 +275,7 @@ void NixRepl::mainLoop()
|
|||
logger->cout("");
|
||||
break;
|
||||
}
|
||||
logger->resume();
|
||||
try {
|
||||
if (!removeWhitespace(input).empty() && !processLine(input)) return;
|
||||
} catch (ParseError & e) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "attr-path.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "users.hh"
|
||||
#include "eval-cache.hh"
|
||||
#include "sqlite.hh"
|
||||
#include "eval.hh"
|
||||
|
@ -21,7 +22,7 @@ struct AttrDb
|
|||
{
|
||||
std::atomic_bool failed{false};
|
||||
|
||||
const Store & cfg;
|
||||
const StoreDirConfig & cfg;
|
||||
|
||||
struct State
|
||||
{
|
||||
|
@ -38,7 +39,7 @@ struct AttrDb
|
|||
SymbolTable & symbols;
|
||||
|
||||
AttrDb(
|
||||
const Store & cfg,
|
||||
const StoreDirConfig & cfg,
|
||||
const Hash & fingerprint,
|
||||
SymbolTable & symbols)
|
||||
: cfg(cfg)
|
||||
|
@ -322,7 +323,7 @@ struct AttrDb
|
|||
};
|
||||
|
||||
static std::shared_ptr<AttrDb> makeAttrDb(
|
||||
const Store & cfg,
|
||||
const StoreDirConfig & cfg,
|
||||
const Hash & fingerprint,
|
||||
SymbolTable & symbols)
|
||||
{
|
||||
|
|
|
@ -103,8 +103,10 @@ void EvalState::forceValue(Value & v, Callable getPos)
|
|||
throw;
|
||||
}
|
||||
}
|
||||
else if (v.isApp())
|
||||
callFunction(*v.app.left, *v.app.right, v, noPos);
|
||||
else if (v.isApp()) {
|
||||
PosIdx pos = getPos();
|
||||
callFunction(*v.app.left, *v.app.right, v, pos);
|
||||
}
|
||||
else if (v.isBlackhole())
|
||||
error("infinite recursion encountered").atPos(getPos()).template debugThrow<EvalError>();
|
||||
}
|
||||
|
@ -121,9 +123,9 @@ template <typename Callable>
|
|||
[[gnu::always_inline]]
|
||||
inline void EvalState::forceAttrs(Value & v, Callable getPos, std::string_view errorCtx)
|
||||
{
|
||||
forceValue(v, noPos);
|
||||
PosIdx pos = getPos();
|
||||
forceValue(v, pos);
|
||||
if (v.type() != nAttrs) {
|
||||
PosIdx pos = getPos();
|
||||
error("value is %1% while a set was expected", showType(v)).withTrace(pos, errorCtx).debugThrow<TypeError>();
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +134,7 @@ inline void EvalState::forceAttrs(Value & v, Callable getPos, std::string_view e
|
|||
[[gnu::always_inline]]
|
||||
inline void EvalState::forceList(Value & v, const PosIdx pos, std::string_view errorCtx)
|
||||
{
|
||||
forceValue(v, noPos);
|
||||
forceValue(v, pos);
|
||||
if (!v.isList()) {
|
||||
error("value is %1% while a list was expected", showType(v)).withTrace(pos, errorCtx).debugThrow<TypeError>();
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "users.hh"
|
||||
#include "globals.hh"
|
||||
#include "profiles.hh"
|
||||
#include "eval.hh"
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "config.hh"
|
||||
|
||||
namespace nix {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "eval.hh"
|
||||
#include "eval-settings.hh"
|
||||
#include "hash.hh"
|
||||
#include "primops.hh"
|
||||
#include "types.hh"
|
||||
#include "util.hh"
|
||||
#include "store-api.hh"
|
||||
|
@ -13,7 +14,10 @@
|
|||
#include "profiles.hh"
|
||||
#include "print.hh"
|
||||
#include "fs-input-accessor.hh"
|
||||
#include "filtering-input-accessor.hh"
|
||||
#include "memory-input-accessor.hh"
|
||||
#include "signals.hh"
|
||||
#include "gc-small-vector.hh"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
@ -29,6 +33,7 @@
|
|||
|
||||
#include <sys/resource.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
|
||||
|
@ -340,7 +345,7 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
|
|||
} else {
|
||||
Value nameValue;
|
||||
name.expr->eval(state, env, nameValue);
|
||||
state.forceStringNoCtx(nameValue, noPos, "while evaluating an attribute name");
|
||||
state.forceStringNoCtx(nameValue, name.expr->getPos(), "while evaluating an attribute name");
|
||||
return state.symbols.create(nameValue.string_view());
|
||||
}
|
||||
}
|
||||
|
@ -505,7 +510,16 @@ EvalState::EvalState(
|
|||
, sOutputSpecified(symbols.create("outputSpecified"))
|
||||
, repair(NoRepair)
|
||||
, emptyBindings(0)
|
||||
, rootFS(makeFSInputAccessor(CanonPath::root))
|
||||
, rootFS(
|
||||
evalSettings.restrictEval || evalSettings.pureEval
|
||||
? ref<InputAccessor>(AllowListInputAccessor::create(makeFSInputAccessor(CanonPath::root), {},
|
||||
[](const CanonPath & path) -> RestrictedPathError {
|
||||
auto modeInformation = evalSettings.pureEval
|
||||
? "in pure evaluation mode (use '--impure' to override)"
|
||||
: "in restricted mode";
|
||||
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", path, modeInformation);
|
||||
}))
|
||||
: makeFSInputAccessor(CanonPath::root))
|
||||
, corepkgsFS(makeMemoryInputAccessor())
|
||||
, internalFS(makeMemoryInputAccessor())
|
||||
, derivationInternal{corepkgsFS->addFile(
|
||||
|
@ -530,6 +544,9 @@ EvalState::EvalState(
|
|||
, baseEnv(allocEnv(128))
|
||||
, staticBaseEnv{std::make_shared<StaticEnv>(false, nullptr)}
|
||||
{
|
||||
corepkgsFS->setPathDisplay("<nix", ">");
|
||||
internalFS->setPathDisplay("«nix-internal»", "");
|
||||
|
||||
countCalls = getEnv("NIX_COUNT_CALLS").value_or("0") != "0";
|
||||
|
||||
assert(gcInitialised);
|
||||
|
@ -544,28 +561,10 @@ EvalState::EvalState(
|
|||
searchPath.elements.emplace_back(SearchPath::Elem::parse(i));
|
||||
}
|
||||
|
||||
if (evalSettings.restrictEval || evalSettings.pureEval) {
|
||||
allowedPaths = PathSet();
|
||||
|
||||
for (auto & i : searchPath.elements) {
|
||||
auto r = resolveSearchPathPath(i.path);
|
||||
if (!r) continue;
|
||||
|
||||
auto path = std::move(*r);
|
||||
|
||||
if (store->isInStore(path)) {
|
||||
try {
|
||||
StorePathSet closure;
|
||||
store->computeFSClosure(store->toStorePath(path).first, closure);
|
||||
for (auto & path : closure)
|
||||
allowPath(path);
|
||||
} catch (InvalidPath &) {
|
||||
allowPath(path);
|
||||
}
|
||||
} else
|
||||
allowPath(path);
|
||||
}
|
||||
}
|
||||
/* Allow access to all paths in the search path. */
|
||||
if (rootFS.dynamic_pointer_cast<AllowListInputAccessor>())
|
||||
for (auto & i : searchPath.elements)
|
||||
resolveSearchPathPath(i.path, true);
|
||||
|
||||
corepkgsFS->addFile(
|
||||
CanonPath("fetchurl.nix"),
|
||||
|
@ -583,14 +582,14 @@ EvalState::~EvalState()
|
|||
|
||||
void EvalState::allowPath(const Path & path)
|
||||
{
|
||||
if (allowedPaths)
|
||||
allowedPaths->insert(path);
|
||||
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListInputAccessor>())
|
||||
rootFS2->allowPath(CanonPath(path));
|
||||
}
|
||||
|
||||
void EvalState::allowPath(const StorePath & storePath)
|
||||
{
|
||||
if (allowedPaths)
|
||||
allowedPaths->insert(store->toRealPath(storePath));
|
||||
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListInputAccessor>())
|
||||
rootFS2->allowPath(CanonPath(store->toRealPath(storePath)));
|
||||
}
|
||||
|
||||
void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value & v)
|
||||
|
@ -600,54 +599,6 @@ void EvalState::allowAndSetStorePathString(const StorePath & storePath, Value &
|
|||
mkStorePathString(storePath, v);
|
||||
}
|
||||
|
||||
SourcePath EvalState::checkSourcePath(const SourcePath & path_)
|
||||
{
|
||||
// Don't check non-rootFS accessors, they're in a different namespace.
|
||||
if (path_.accessor != ref<InputAccessor>(rootFS)) return path_;
|
||||
|
||||
if (!allowedPaths) return path_;
|
||||
|
||||
auto i = resolvedPaths.find(path_.path.abs());
|
||||
if (i != resolvedPaths.end())
|
||||
return i->second;
|
||||
|
||||
bool found = false;
|
||||
|
||||
/* First canonicalize the path without symlinks, so we make sure an
|
||||
* attacker can't append ../../... to a path that would be in allowedPaths
|
||||
* and thus leak symlink targets.
|
||||
*/
|
||||
Path abspath = canonPath(path_.path.abs());
|
||||
|
||||
for (auto & i : *allowedPaths) {
|
||||
if (isDirOrInDir(abspath, i)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
auto modeInformation = evalSettings.pureEval
|
||||
? "in pure eval mode (use '--impure' to override)"
|
||||
: "in restricted mode";
|
||||
throw RestrictedPathError("access to absolute path '%1%' is forbidden %2%", abspath, modeInformation);
|
||||
}
|
||||
|
||||
/* Resolve symlinks. */
|
||||
debug("checking access to '%s'", abspath);
|
||||
SourcePath path = rootPath(CanonPath(canonPath(abspath, true)));
|
||||
|
||||
for (auto & i : *allowedPaths) {
|
||||
if (isDirOrInDir(path.path.abs(), i)) {
|
||||
resolvedPaths.insert_or_assign(path_.path.abs(), path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
throw RestrictedPathError("access to canonical path '%1%' is forbidden in restricted mode", path);
|
||||
}
|
||||
|
||||
|
||||
void EvalState::checkURI(const std::string & uri)
|
||||
{
|
||||
if (!evalSettings.restrictEval) return;
|
||||
|
@ -667,12 +618,14 @@ void EvalState::checkURI(const std::string & uri)
|
|||
/* If the URI is a path, then check it against allowedPaths as
|
||||
well. */
|
||||
if (hasPrefix(uri, "/")) {
|
||||
checkSourcePath(rootPath(CanonPath(uri)));
|
||||
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListInputAccessor>())
|
||||
rootFS2->checkAccess(CanonPath(uri));
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasPrefix(uri, "file://")) {
|
||||
checkSourcePath(rootPath(CanonPath(std::string(uri, 7))));
|
||||
if (auto rootFS2 = rootFS.dynamic_pointer_cast<AllowListInputAccessor>())
|
||||
rootFS2->checkAccess(CanonPath(uri.substr(7)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -721,6 +674,23 @@ void EvalState::addConstant(const std::string & name, Value * v, Constant info)
|
|||
}
|
||||
|
||||
|
||||
void PrimOp::check()
|
||||
{
|
||||
if (arity > maxPrimOpArity) {
|
||||
throw Error("primop arity must not exceed %1%", maxPrimOpArity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Value::mkPrimOp(PrimOp * p)
|
||||
{
|
||||
p->check();
|
||||
clearValue();
|
||||
internalType = tPrimOp;
|
||||
primOp = p;
|
||||
}
|
||||
|
||||
|
||||
Value * EvalState::addPrimOp(PrimOp && primOp)
|
||||
{
|
||||
/* Hack to make constants lazy: turn them into a application of
|
||||
|
@ -1157,10 +1127,8 @@ Value * ExprPath::maybeThunk(EvalState & state, Env & env)
|
|||
}
|
||||
|
||||
|
||||
void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial)
|
||||
void EvalState::evalFile(const SourcePath & path, Value & v, bool mustBeTrivial)
|
||||
{
|
||||
auto path = checkSourcePath(path_);
|
||||
|
||||
FileEvalCache::iterator i;
|
||||
if ((i = fileEvalCache.find(path)) != fileEvalCache.end()) {
|
||||
v = i->second;
|
||||
|
@ -1181,7 +1149,7 @@ void EvalState::evalFile(const SourcePath & path_, Value & v, bool mustBeTrivial
|
|||
e = j->second;
|
||||
|
||||
if (!e)
|
||||
e = parseExprFromFile(checkSourcePath(resolvedPath));
|
||||
e = parseExprFromFile(resolvedPath);
|
||||
|
||||
fileParseCache[resolvedPath] = e;
|
||||
|
||||
|
@ -1490,7 +1458,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
|
|||
e->eval(state, env, vTmp);
|
||||
|
||||
for (auto & i : attrPath) {
|
||||
state.forceValue(*vAttrs, noPos);
|
||||
state.forceValue(*vAttrs, getPos());
|
||||
Bindings::iterator j;
|
||||
auto name = getName(i, state, env);
|
||||
if (vAttrs->type() != nAttrs ||
|
||||
|
@ -1659,7 +1627,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
|||
if (countCalls) primOpCalls[name]++;
|
||||
|
||||
try {
|
||||
vCur.primOp->fun(*this, noPos, args, vCur);
|
||||
vCur.primOp->fun(*this, vCur.determinePos(noPos), args, vCur);
|
||||
} catch (Error & e) {
|
||||
addErrorTrace(e, pos, "while calling the '%1%' builtin", name);
|
||||
throw;
|
||||
|
@ -1690,7 +1658,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
|||
/* We have all the arguments, so call the primop with
|
||||
the previous and new arguments. */
|
||||
|
||||
Value * vArgs[arity];
|
||||
Value * vArgs[maxPrimOpArity];
|
||||
auto n = argsDone;
|
||||
for (Value * arg = &vCur; arg->isPrimOpApp(); arg = arg->primOpApp.left)
|
||||
vArgs[--n] = arg->primOpApp.right;
|
||||
|
@ -1707,7 +1675,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
|||
// 1. Unify this and above code. Heavily redundant.
|
||||
// 2. Create a fake env (arg1, arg2, etc.) and a fake expr (arg1: arg2: etc: builtins.name arg1 arg2 etc)
|
||||
// so the debugger allows to inspect the wrong parameters passed to the builtin.
|
||||
primOp->primOp->fun(*this, noPos, vArgs, vCur);
|
||||
primOp->primOp->fun(*this, vCur.determinePos(noPos), vArgs, vCur);
|
||||
} catch (Error & e) {
|
||||
addErrorTrace(e, pos, "while calling the '%1%' builtin", name);
|
||||
throw;
|
||||
|
@ -1747,11 +1715,17 @@ void ExprCall::eval(EvalState & state, Env & env, Value & v)
|
|||
Value vFun;
|
||||
fun->eval(state, env, vFun);
|
||||
|
||||
Value * vArgs[args.size()];
|
||||
// Empirical arity of Nixpkgs lambdas by regex e.g. ([a-zA-Z]+:(\s|(/\*.*\/)|(#.*\n))*){5}
|
||||
// 2: over 4000
|
||||
// 3: about 300
|
||||
// 4: about 60
|
||||
// 5: under 10
|
||||
// This excluded attrset lambdas (`{...}:`). Contributions of mixed lambdas appears insignificant at ~150 total.
|
||||
SmallValueVector<4> vArgs(args.size());
|
||||
for (size_t i = 0; i < args.size(); ++i)
|
||||
vArgs[i] = args[i]->maybeThunk(state, env);
|
||||
|
||||
state.callFunction(vFun, args.size(), vArgs, v, pos);
|
||||
state.callFunction(vFun, args.size(), vArgs.data(), v, pos);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1809,7 +1783,7 @@ https://nixos.org/manual/nix/stable/language/constructs.html#functions.)", symbo
|
|||
}
|
||||
}
|
||||
|
||||
callFunction(fun, allocValue()->mkAttrs(attrs), res, noPos);
|
||||
callFunction(fun, allocValue()->mkAttrs(attrs), res, pos);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1845,7 +1819,7 @@ void ExprAssert::eval(EvalState & state, Env & env, Value & v)
|
|||
|
||||
void ExprOpNot::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
v.mkBool(!state.evalBool(env, e, noPos, "in the argument of the not operator")); // XXX: FIXME: !
|
||||
v.mkBool(!state.evalBool(env, e, getPos(), "in the argument of the not operator")); // XXX: FIXME: !
|
||||
}
|
||||
|
||||
|
||||
|
@ -1990,8 +1964,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
|||
return result;
|
||||
};
|
||||
|
||||
Value values[es->size()];
|
||||
Value * vTmpP = values;
|
||||
// List of returned strings. References to these Values must NOT be persisted.
|
||||
SmallTemporaryValueVector<conservativeStackReservation> values(es->size());
|
||||
Value * vTmpP = values.data();
|
||||
|
||||
for (auto & [i_pos, i] : *es) {
|
||||
Value & vTmp = *vTmpP++;
|
||||
|
@ -2285,7 +2260,7 @@ BackedStringView EvalState::coerceToString(
|
|||
std::string result;
|
||||
for (auto [n, v2] : enumerate(v.listItems())) {
|
||||
try {
|
||||
result += *coerceToString(noPos, *v2, context,
|
||||
result += *coerceToString(pos, *v2, context,
|
||||
"while evaluating one element of the list",
|
||||
coerceMore, copyToStore, canonicalizePath);
|
||||
} catch (Error & e) {
|
||||
|
@ -2432,8 +2407,8 @@ SingleDerivedPath EvalState::coerceToSingleDerivedPath(const PosIdx pos, Value &
|
|||
|
||||
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
|
||||
{
|
||||
forceValue(v1, noPos);
|
||||
forceValue(v2, noPos);
|
||||
forceValue(v1, pos);
|
||||
forceValue(v2, pos);
|
||||
|
||||
/* !!! Hack to support some old broken code that relies on pointer
|
||||
equality tests between sets. (Specifically, builderDefs calls
|
||||
|
|
|
@ -18,13 +18,18 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* We put a limit on primop arity because it lets us use a fixed size array on
|
||||
* the stack. 8 is already an impractical number of arguments. Use an attrset
|
||||
* argument for such overly complicated functions.
|
||||
*/
|
||||
constexpr size_t maxPrimOpArity = 8;
|
||||
|
||||
class Store;
|
||||
class EvalState;
|
||||
class StorePath;
|
||||
struct SingleDerivedPath;
|
||||
enum RepairFlag : bool;
|
||||
struct FSInputAccessor;
|
||||
struct MemoryInputAccessor;
|
||||
|
||||
|
||||
|
@ -71,6 +76,12 @@ struct PrimOp
|
|||
* Optional experimental for this to be gated on.
|
||||
*/
|
||||
std::optional<ExperimentalFeature> experimentalFeature;
|
||||
|
||||
/**
|
||||
* Validity check to be performed by functions that introduce primops,
|
||||
* such as RegisterPrimOp() and Value::mkPrimOp().
|
||||
*/
|
||||
void check();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -205,18 +216,12 @@ public:
|
|||
*/
|
||||
RepairFlag repair;
|
||||
|
||||
/**
|
||||
* The allowed filesystem paths in restricted or pure evaluation
|
||||
* mode.
|
||||
*/
|
||||
std::optional<PathSet> allowedPaths;
|
||||
|
||||
Bindings emptyBindings;
|
||||
|
||||
/**
|
||||
* The accessor for the root filesystem.
|
||||
*/
|
||||
const ref<FSInputAccessor> rootFS;
|
||||
const ref<InputAccessor> rootFS;
|
||||
|
||||
/**
|
||||
* The in-memory filesystem for <nix/...> paths.
|
||||
|
@ -384,12 +389,6 @@ public:
|
|||
*/
|
||||
void allowAndSetStorePathString(const StorePath & storePath, Value & v);
|
||||
|
||||
/**
|
||||
* Check whether access to a path is allowed and throw an error if
|
||||
* not. Otherwise return the canonicalised path.
|
||||
*/
|
||||
SourcePath checkSourcePath(const SourcePath & path);
|
||||
|
||||
void checkURI(const std::string & uri);
|
||||
|
||||
/**
|
||||
|
@ -433,13 +432,15 @@ public:
|
|||
SourcePath findFile(const SearchPath & searchPath, const std::string_view path, const PosIdx pos = noPos);
|
||||
|
||||
/**
|
||||
* Try to resolve a search path value (not the optional key part)
|
||||
* Try to resolve a search path value (not the optional key part).
|
||||
*
|
||||
* If the specified search path element is a URI, download it.
|
||||
*
|
||||
* If it is not found, return `std::nullopt`
|
||||
*/
|
||||
std::optional<std::string> resolveSearchPathPath(const SearchPath::Path & path);
|
||||
std::optional<std::string> resolveSearchPathPath(
|
||||
const SearchPath::Path & elem,
|
||||
bool initAccessControl = false);
|
||||
|
||||
/**
|
||||
* Evaluate an expression to normal form
|
||||
|
@ -744,6 +745,13 @@ public:
|
|||
*/
|
||||
[[nodiscard]] StringMap realiseContext(const NixStringContext & context);
|
||||
|
||||
/* Call the binary path filter predicate used builtins.path etc. */
|
||||
bool callPathFilter(
|
||||
Value * filterFun,
|
||||
const SourcePath & path,
|
||||
std::string_view pathArg,
|
||||
PosIdx pos);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
@ -827,7 +835,7 @@ std::string showType(const Value & v);
|
|||
/**
|
||||
* If `path` refers to a directory, then append "/default.nix".
|
||||
*/
|
||||
SourcePath resolveExprPath(const SourcePath & path);
|
||||
SourcePath resolveExprPath(SourcePath path);
|
||||
|
||||
struct InvalidPathError : EvalError
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "flake.hh"
|
||||
#include "users.hh"
|
||||
#include "globals.hh"
|
||||
#include "fetch-settings.hh"
|
||||
#include "flake.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "terminal.hh"
|
||||
#include "flake.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-settings.hh"
|
||||
|
@ -8,6 +9,7 @@
|
|||
#include "fetchers.hh"
|
||||
#include "finally.hh"
|
||||
#include "fetch-settings.hh"
|
||||
#include "value-to-json.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -140,8 +142,13 @@ static FlakeInput parseFlakeInput(EvalState & state,
|
|||
attrs.emplace(state.symbols[attr.name], (long unsigned int)attr.value->integer);
|
||||
break;
|
||||
default:
|
||||
throw TypeError("flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
|
||||
state.symbols[attr.name], showType(*attr.value));
|
||||
if (attr.name == state.symbols.create("publicKeys")) {
|
||||
experimentalFeatureSettings.require(Xp::VerifiedFetches);
|
||||
NixStringContext emptyContext = {};
|
||||
attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, emptyContext).dump());
|
||||
} else
|
||||
throw TypeError("flake input attribute '%s' is %s while a string, Boolean, or integer is expected",
|
||||
state.symbols[attr.name], showType(*attr.value));
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
@ -205,8 +212,16 @@ static Flake getFlake(
|
|||
auto [storePath, resolvedRef, lockedRef] = fetchOrSubstituteTree(
|
||||
state, originalRef, allowLookup, flakeCache);
|
||||
|
||||
// We need to guard against symlink attacks, but before we start doing
|
||||
// filesystem operations we should make sure there's a flake.nix in the
|
||||
// first place.
|
||||
auto unsafeFlakeDir = state.store->toRealPath(storePath) + "/" + lockedRef.subdir;
|
||||
auto unsafeFlakeFile = unsafeFlakeDir + "/flake.nix";
|
||||
if (!pathExists(unsafeFlakeFile))
|
||||
throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", lockedRef, lockedRef.subdir);
|
||||
|
||||
// Guard against symlink attacks.
|
||||
auto flakeDir = canonPath(state.store->toRealPath(storePath) + "/" + lockedRef.subdir, true);
|
||||
auto flakeDir = canonPath(unsafeFlakeDir, true);
|
||||
auto flakeFile = canonPath(flakeDir + "/flake.nix", true);
|
||||
if (!isInDir(flakeFile, state.store->toRealPath(storePath)))
|
||||
throw Error("'flake.nix' file of flake '%s' escapes from '%s'",
|
||||
|
@ -219,9 +234,6 @@ static Flake getFlake(
|
|||
.storePath = storePath,
|
||||
};
|
||||
|
||||
if (!pathExists(flakeFile))
|
||||
throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", lockedRef, lockedRef.subdir);
|
||||
|
||||
Value vInfo;
|
||||
state.evalFile(state.rootPath(CanonPath(flakeFile)), vInfo, true); // FIXME: symlink attack
|
||||
|
||||
|
@ -351,10 +363,13 @@ LockedFlake lockFlake(
|
|||
debug("old lock file: %s", oldLockFile);
|
||||
|
||||
std::map<InputPath, FlakeInput> overrides;
|
||||
std::set<InputPath> explicitCliOverrides;
|
||||
std::set<InputPath> overridesUsed, updatesUsed;
|
||||
|
||||
for (auto & i : lockFlags.inputOverrides)
|
||||
for (auto & i : lockFlags.inputOverrides) {
|
||||
overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second });
|
||||
explicitCliOverrides.insert(i.first);
|
||||
}
|
||||
|
||||
LockFile newLockFile;
|
||||
|
||||
|
@ -425,6 +440,7 @@ LockedFlake lockFlake(
|
|||
ancestors? */
|
||||
auto i = overrides.find(inputPath);
|
||||
bool hasOverride = i != overrides.end();
|
||||
bool hasCliOverride = explicitCliOverrides.contains(inputPath);
|
||||
if (hasOverride) {
|
||||
overridesUsed.insert(inputPath);
|
||||
// Respect the “flakeness” of the input even if we
|
||||
|
@ -447,8 +463,8 @@ LockedFlake lockFlake(
|
|||
|
||||
assert(input.ref);
|
||||
|
||||
/* Do we have an entry in the existing lock file? And we
|
||||
don't have a --update-input flag for this input? */
|
||||
/* Do we have an entry in the existing lock file?
|
||||
And the input is not in updateInputs? */
|
||||
std::shared_ptr<LockedNode> oldLock;
|
||||
|
||||
updatesUsed.insert(inputPath);
|
||||
|
@ -460,7 +476,7 @@ LockedFlake lockFlake(
|
|||
|
||||
if (oldLock
|
||||
&& oldLock->originalRef == *input.ref
|
||||
&& !hasOverride)
|
||||
&& !hasCliOverride)
|
||||
{
|
||||
debug("keeping existing input '%s'", inputPathS);
|
||||
|
||||
|
@ -472,9 +488,8 @@ LockedFlake lockFlake(
|
|||
|
||||
node->inputs.insert_or_assign(id, childNode);
|
||||
|
||||
/* If we have an --update-input flag for an input
|
||||
of this input, then we must fetch the flake to
|
||||
update it. */
|
||||
/* If we have this input in updateInputs, then we
|
||||
must fetch the flake to update it. */
|
||||
auto lb = lockFlags.inputUpdates.lower_bound(inputPath);
|
||||
|
||||
auto mustRefetch =
|
||||
|
@ -541,7 +556,7 @@ LockedFlake lockFlake(
|
|||
nuked the next time we update the lock
|
||||
file. That is, overrides are sticky unless you
|
||||
use --no-write-lock-file. */
|
||||
auto ref = input2.ref ? *input2.ref : *input.ref;
|
||||
auto ref = (input2.ref && explicitCliOverrides.contains(inputPath)) ? *input2.ref : *input.ref;
|
||||
|
||||
if (input.isFlake) {
|
||||
Path localPath = parentPath;
|
||||
|
@ -616,19 +631,14 @@ LockedFlake lockFlake(
|
|||
|
||||
for (auto & i : lockFlags.inputUpdates)
|
||||
if (!updatesUsed.count(i))
|
||||
warn("the flag '--update-input %s' does not match any input", printInputPath(i));
|
||||
warn("'%s' does not match any input of this flake", printInputPath(i));
|
||||
|
||||
/* Check 'follows' inputs. */
|
||||
newLockFile.check();
|
||||
|
||||
debug("new lock file: %s", newLockFile);
|
||||
|
||||
auto relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock";
|
||||
auto sourcePath = topRef.input.getSourcePath();
|
||||
auto outputLockFilePath = sourcePath ? std::optional{*sourcePath + "/" + relPath} : std::nullopt;
|
||||
if (lockFlags.outputLockFilePath) {
|
||||
outputLockFilePath = lockFlags.outputLockFilePath;
|
||||
}
|
||||
|
||||
/* Check whether we need to / can write the new lock file. */
|
||||
if (newLockFile != oldLockFile || lockFlags.outputLockFilePath) {
|
||||
|
@ -636,7 +646,7 @@ LockedFlake lockFlake(
|
|||
auto diff = LockFile::diff(oldLockFile, newLockFile);
|
||||
|
||||
if (lockFlags.writeLockFile) {
|
||||
if (outputLockFilePath) {
|
||||
if (sourcePath || lockFlags.outputLockFilePath) {
|
||||
if (auto unlockedInput = newLockFile.isUnlocked()) {
|
||||
if (fetchSettings.warnDirty)
|
||||
warn("will not write lock file of flake '%s' because it has an unlocked input ('%s')", topRef, *unlockedInput);
|
||||
|
@ -644,41 +654,48 @@ LockedFlake lockFlake(
|
|||
if (!lockFlags.updateLockFile)
|
||||
throw Error("flake '%s' requires lock file changes but they're not allowed due to '--no-update-lock-file'", topRef);
|
||||
|
||||
bool lockFileExists = pathExists(*outputLockFilePath);
|
||||
auto newLockFileS = fmt("%s\n", newLockFile);
|
||||
|
||||
if (lockFlags.outputLockFilePath) {
|
||||
if (lockFlags.commitLockFile)
|
||||
throw Error("'--commit-lock-file' and '--output-lock-file' are incompatible");
|
||||
writeFile(*lockFlags.outputLockFilePath, newLockFileS);
|
||||
} else {
|
||||
auto relPath = (topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock";
|
||||
auto outputLockFilePath = *sourcePath + "/" + relPath;
|
||||
|
||||
bool lockFileExists = pathExists(outputLockFilePath);
|
||||
|
||||
if (lockFileExists) {
|
||||
auto s = chomp(diff);
|
||||
if (s.empty())
|
||||
warn("updating lock file '%s'", *outputLockFilePath);
|
||||
else
|
||||
warn("updating lock file '%s':\n%s", *outputLockFilePath, s);
|
||||
} else
|
||||
warn("creating lock file '%s'", *outputLockFilePath);
|
||||
if (lockFileExists) {
|
||||
if (s.empty())
|
||||
warn("updating lock file '%s'", outputLockFilePath);
|
||||
else
|
||||
warn("updating lock file '%s':\n%s", outputLockFilePath, s);
|
||||
} else
|
||||
warn("creating lock file '%s': \n%s", outputLockFilePath, s);
|
||||
|
||||
newLockFile.write(*outputLockFilePath);
|
||||
std::optional<std::string> commitMessage = std::nullopt;
|
||||
|
||||
std::optional<std::string> commitMessage = std::nullopt;
|
||||
if (lockFlags.commitLockFile) {
|
||||
if (lockFlags.outputLockFilePath) {
|
||||
throw Error("--commit-lock-file and --output-lock-file are currently incompatible");
|
||||
}
|
||||
std::string cm;
|
||||
if (lockFlags.commitLockFile) {
|
||||
std::string cm;
|
||||
|
||||
cm = fetchSettings.commitLockFileSummary.get();
|
||||
cm = fetchSettings.commitLockFileSummary.get();
|
||||
|
||||
if (cm == "") {
|
||||
cm = fmt("%s: %s", relPath, lockFileExists ? "Update" : "Add");
|
||||
if (cm == "") {
|
||||
cm = fmt("%s: %s", relPath, lockFileExists ? "Update" : "Add");
|
||||
}
|
||||
|
||||
cm += "\n\nFlake lock file updates:\n\n";
|
||||
cm += filterANSIEscapes(diff, true);
|
||||
commitMessage = cm;
|
||||
}
|
||||
|
||||
cm += "\n\nFlake lock file updates:\n\n";
|
||||
cm += filterANSIEscapes(diff, true);
|
||||
commitMessage = cm;
|
||||
topRef.input.putFile(
|
||||
CanonPath((topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock"),
|
||||
newLockFileS, commitMessage);
|
||||
}
|
||||
|
||||
topRef.input.markChangedFile(
|
||||
(topRef.subdir == "" ? "" : topRef.subdir + "/") + "flake.lock",
|
||||
commitMessage);
|
||||
|
||||
/* Rewriting the lockfile changed the top-level
|
||||
repo, so we should re-read it. FIXME: we could
|
||||
also just clear the 'rev' field... */
|
||||
|
@ -887,7 +904,7 @@ Fingerprint LockedFlake::getFingerprint() const
|
|||
// FIXME: as an optimization, if the flake contains a lock file
|
||||
// and we haven't changed it, then it's sufficient to use
|
||||
// flake.sourceInfo.storePath for the fingerprint.
|
||||
return hashString(htSHA256,
|
||||
return hashString(HashAlgorithm::SHA256,
|
||||
fmt("%s;%s;%d;%d;%s",
|
||||
flake.storePath.to_string(),
|
||||
flake.lockedRef.subdir,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue