-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support managing submodules via inputs.self #7862
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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<std::string> 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<bool>{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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs a note, and docs, about the “self” input being special. |
||
auto inputPath(inputPathPrefix); | ||
inputPath.push_back(id); | ||
auto inputPathS = printInputPath(inputPath); | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -114,6 +114,8 @@ reference types: | |||||||
|
||||||||
* `ref`: A Git or Mercurial branch or tag name. | ||||||||
|
||||||||
* `submodules`: A boolean supporting Git submodules. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the default? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Finally, some attribute are typically not specified by the user, but | ||||||||
can occur in *locked* flake references and are available to Nix code: | ||||||||
|
||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <<EOF > flake.nix | ||
{ | ||
outputs = {self}: { | ||
sub = self.outPath; | ||
}; | ||
} | ||
EOF | ||
[ -e $(nix eval '.?submodules=1#sub' --raw)/sub/content ] | ||
|
||
# Case, CLI parameter | ||
cat <<EOF > flake.nix | ||
{ | ||
outputs = {self}: { | ||
sub = self.outPath; | ||
}; | ||
} | ||
EOF | ||
[ ! -e $(nix eval '.?submodules=0#sub' --raw)/sub/content ] | ||
|
||
# Case, flake.nix parameter | ||
cat <<EOF > flake.nix | ||
{ | ||
inputs.self.submodules = false; | ||
outputs = {self}: { | ||
sub = self.outPath; | ||
}; | ||
} | ||
EOF | ||
|
||
[ ! -e $(nix eval .#sub --raw)/sub/content ] | ||
|
||
# Case, flake.nix parameter | ||
cat <<EOF > flake.nix | ||
{ | ||
inputs.self.submodules = true; | ||
outputs = {self}: { | ||
sub = self.outPath; | ||
}; | ||
} | ||
EOF | ||
[ -e $(nix eval .#sub --raw)/sub/content ] | ||
|
||
# Case, CLI precedence | ||
cat <<EOF > 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 <<EOF > flake.nix | ||
{ | ||
inputs.self.submodules = false; | ||
outputs = {self}: { | ||
sub = self.outPath; | ||
}; | ||
} | ||
EOF | ||
[ -e $(nix eval '.?submodules=1#sub' --raw)/sub/content ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comparison is a little ad hoc. It should be described in more general terms. My understanding of the process is:
self
input isself
inputNone of this is specific to git or submodules, so it should be done through virtual methods.
Other than that, I think lazy trees #6530 should make this specific parameter conceptually redundant, and enable it by default, as submodules should be fetched lazily.
However, that's not a reason not to have this mechanism, as we'll need it for at least a
git-crypt
parameter.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A general mechanism (but also with
submodules
as the motivating case) is described and discussed in