From 6ebe06aa50a2492e59ab2d6712f597c3cba85802 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Sun, 19 Feb 2023 06:12:52 -0500 Subject: [PATCH 1/3] feat: support managing submodules via inputs.self Provides special handling for inputs.self. If submodule is set to true, will re-call getFlake as if the original reference was set. The intended behavior is for CLI management of the parameter overrides any direct flake.nix settings. --- src/libexpr/flake/flake.cc | 19 ++++++++++++++++++- src/libexpr/flake/flake.hh | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 336eb274d98..6e2cf7d8bb7 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -104,6 +104,7 @@ static FlakeInput parseFlakeInput(EvalState & state, auto sUrl = state.symbols.create("url"); auto sFlake = state.symbols.create("flake"); auto sFollows = state.symbols.create("follows"); + auto sSubmodules = state.symbols.create("submodules"); fetchers::Attrs attrs; std::optional url; @@ -117,6 +118,9 @@ static FlakeInput parseFlakeInput(EvalState & state, } else if (attr.name == sFlake) { expectType(state, nBool, *attr.value, attr.pos); input.isFlake = attr.value->boolean; + } else if (attr.name == sSubmodules) { + expectType(state, nBool, *attr.value, attr.pos); + input.hasSubmodules = attr.value->boolean; } else if (attr.name == sInputs) { input.overrides = parseFlakeInputs(state, attr.value, attr.pos, baseDir, lockRootPath); } else if (attr.name == sFollows) { @@ -229,8 +233,20 @@ static Flake getFlake( auto sInputs = state.symbols.create("inputs"); - if (auto inputs = vInfo.attrs->get(sInputs)) + if (auto inputs = vInfo.attrs->get(sInputs)) { flake.inputs = parseFlakeInputs(state, inputs->value, inputs->pos, flakeDir, lockRootPath); + if (originalRef.input.attrs.count("submodules") == 0) { + auto self = flake.inputs.find("self"); + if (self != flake.inputs.end() && self->second.hasSubmodules) { + auto newRef = originalRef; + newRef.input.attrs["submodules"] = nix::Explicit{true}; + // note: Called twice due to submodule handling in src/libfetcher (55cefd41d6) + warn("Loading submodules for %s because 'inputs.self.submodule' is true at %s", + originalRef.input.to_string(),state.positions[inputs->pos]); + return getFlake(state,newRef,allowLookup,flakeCache,lockRootPath); + } + } + } auto sOutputs = state.symbols.create("outputs"); @@ -405,6 +421,7 @@ LockedFlake lockFlake( necessary (i.e. if they're new or the flakeref changed from what's in the lock file). */ for (auto & [id, input2] : flakeInputs) { + if (id == "self") continue; auto inputPath(inputPathPrefix); inputPath.push_back(id); auto inputPathS = printInputPath(inputPath); diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh index 10301d8aae4..3142f0b6bcd 100644 --- a/src/libexpr/flake/flake.hh +++ b/src/libexpr/flake/flake.hh @@ -41,6 +41,7 @@ typedef std::map FlakeInputs; struct FlakeInput { std::optional ref; + bool hasSubmodules = false; bool isFlake = true; // true = process flake to get outputs, false = (fetched) static source path std::optional follows; FlakeInputs overrides; From 5fd671fd108a861124fab09b5c3e69ff74790d51 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Sun, 19 Feb 2023 08:01:21 -0500 Subject: [PATCH 2/3] test: add tests for submodule handling in flake.nix and CLI --- tests/flakes/submodules.sh | 118 +++++++++++++++++++++++++++++++++++++ tests/local.mk | 1 + 2 files changed, 119 insertions(+) create mode 100644 tests/flakes/submodules.sh diff --git a/tests/flakes/submodules.sh b/tests/flakes/submodules.sh new file mode 100644 index 00000000000..6ffd75b2610 --- /dev/null +++ b/tests/flakes/submodules.sh @@ -0,0 +1,118 @@ +source common.sh + +set -u + +if [[ -z $(type -p git) ]]; then + echo "Git not installed; skipping Git submodule tests" + exit 99 +fi + +clearStore + +rootRepo=$TEST_ROOT/gitSubmodulesRoot +subRepo=$TEST_ROOT/gitSubmodulesSub + +rm -rf ${rootRepo} ${subRepo} $TEST_HOME/.cache/nix + +# Submodules can't be fetched locally by default, which can cause +# information leakage vulnerabilities, but for these tests our +# submodule is intentionally local and it's all trusted, so we +# disable this restriction. Setting it per repo is not sufficient, as +# the repo-local config does not apply to the commands run from +# outside the repos by Nix. +export XDG_CONFIG_HOME=$TEST_HOME/.config +git config --global protocol.file.allow always + +initGitRepo() { + git init $1 + git -C $1 config user.email "foobar@example.com" + git -C $1 config user.name "Foobar" +} + +addGitContent() { + echo "lorem ipsum" > $1/content + git -C $1 add content + git -C $1 commit -m "Initial commit" +} + +initGitRepo $subRepo +addGitContent $subRepo + +initGitRepo $rootRepo + +git -C $rootRepo submodule init +git -C $rootRepo submodule add $subRepo sub +git -C $rootRepo add sub +git -C $rootRepo commit -m "Add submodule" + +rev=$(git -C $rootRepo rev-parse HEAD) + +cd $rootRepo + +touch flake.nix +git add flake.nix + +# Case, CLI parameter +cat < flake.nix +{ + outputs = {self}: { + sub = self.outPath; + }; +} +EOF +[ -e $(nix eval '.?submodules=1#sub' --raw)/sub/content ] + +# Case, CLI parameter +cat < flake.nix +{ + outputs = {self}: { + sub = self.outPath; + }; +} +EOF +[ ! -e $(nix eval '.?submodules=0#sub' --raw)/sub/content ] + +# Case, flake.nix parameter +cat < flake.nix +{ + inputs.self.submodules = false; + outputs = {self}: { + sub = self.outPath; + }; +} +EOF + +[ ! -e $(nix eval .#sub --raw)/sub/content ] + +# Case, flake.nix parameter +cat < flake.nix +{ + inputs.self.submodules = true; + outputs = {self}: { + sub = self.outPath; + }; +} +EOF +[ -e $(nix eval .#sub --raw)/sub/content ] + +# Case, CLI precedence +cat < flake.nix +{ + inputs.self.submodules = true; + outputs = {self}: { + sub = self.outPath; + }; +} +EOF +[ ! -e $(nix eval '.?submodules=0#sub' --raw)/sub/content ] + +# Case, CLI precedence +cat < flake.nix +{ + inputs.self.submodules = false; + outputs = {self}: { + sub = self.outPath; + }; +} +EOF +[ -e $(nix eval '.?submodules=1#sub' --raw)/sub/content ] diff --git a/tests/local.mk b/tests/local.mk index b3135fd4dfb..31872e87c89 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -10,6 +10,7 @@ nix_tests = \ flakes/unlocked-override.sh \ flakes/absolute-paths.sh \ flakes/build-paths.sh \ + flakes/submodules.sh \ ca/gc.sh \ gc.sh \ remote-store.sh \ From 6a053941b0fba501969aadac085a0deb6f7970b0 Mon Sep 17 00:00:00 2001 From: Tom Bereknyei Date: Sun, 19 Feb 2023 08:23:16 -0500 Subject: [PATCH 3/3] docs: add mention of submodule support for flake references --- src/nix/flake.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nix/flake.md b/src/nix/flake.md index 810e9ebeaf4..68cf20cd6ea 100644 --- a/src/nix/flake.md +++ b/src/nix/flake.md @@ -114,6 +114,8 @@ reference types: * `ref`: A Git or Mercurial branch or tag name. +* `submodules`: A boolean supporting Git submodules. + Finally, some attribute are typically not specified by the user, but can occur in *locked* flake references and are available to Nix code: