nix flake init: Add a '--template' flag
The initial contents of the flake is specified by the 'templates.<name>' or 'defaultTemplate' output of another flake. E.g. outputs = { self }: { templates = { nixos-container = { path = ./nixos-container; description = "An example of a NixOS container"; }; }; }; allows $ nix flake init -t templates#nixos-container Also add a command 'nix flake new', which is identical to 'nix flake init' except that it initializes a specified directory rather than the current directory.
This commit is contained in:
parent
dc305500c3
commit
810b2c6a48
8 changed files with 258 additions and 41 deletions
|
@ -320,6 +320,8 @@ Value & AttrCursor::forceValue()
|
||||||
if (root->db && (!cachedValue || std::get_if<placeholder_t>(&cachedValue->second))) {
|
if (root->db && (!cachedValue || std::get_if<placeholder_t>(&cachedValue->second))) {
|
||||||
if (v.type == tString)
|
if (v.type == tString)
|
||||||
cachedValue = {root->db->setString(getKey(), v.string.s), v.string.s};
|
cachedValue = {root->db->setString(getKey(), v.string.s), v.string.s};
|
||||||
|
else if (v.type == tPath)
|
||||||
|
cachedValue = {root->db->setString(getKey(), v.path), v.path};
|
||||||
else if (v.type == tBool)
|
else if (v.type == tBool)
|
||||||
cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean};
|
cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean};
|
||||||
else if (v.type == tAttrs)
|
else if (v.type == tAttrs)
|
||||||
|
@ -434,10 +436,10 @@ std::string AttrCursor::getString()
|
||||||
|
|
||||||
auto & v = forceValue();
|
auto & v = forceValue();
|
||||||
|
|
||||||
if (v.type != tString)
|
if (v.type != tString && v.type != tPath)
|
||||||
throw TypeError("'%s' is not a string", getAttrPathStr());
|
throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type));
|
||||||
|
|
||||||
return v.string.s;
|
return v.type == tString ? v.string.s : v.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttrCursor::getBool()
|
bool AttrCursor::getBool()
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
{
|
|
||||||
description = "A flake for building Hello World";
|
|
||||||
|
|
||||||
outputs = { self, nixpkgs }: {
|
|
||||||
|
|
||||||
packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
|
|
||||||
|
|
||||||
defaultPackage.x86_64-linux = self.packages.x86_64-linux.hello;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
192
src/nix/flake.cc
192
src/nix/flake.cc
|
@ -207,6 +207,8 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
auto flake = lockFlake();
|
auto flake = lockFlake();
|
||||||
|
|
||||||
|
// FIXME: rewrite to use EvalCache.
|
||||||
|
|
||||||
auto checkSystemName = [&](const std::string & system, const Pos & pos) {
|
auto checkSystemName = [&](const std::string & system, const Pos & pos) {
|
||||||
// FIXME: what's the format of "system"?
|
// FIXME: what's the format of "system"?
|
||||||
if (system.find('-') == std::string::npos)
|
if (system.find('-') == std::string::npos)
|
||||||
|
@ -320,6 +322,40 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto checkTemplate = [&](const std::string & attrPath, Value & v, const Pos & pos) {
|
||||||
|
try {
|
||||||
|
Activity act(*logger, lvlChatty, actUnknown,
|
||||||
|
fmt("checking template '%s'", attrPath));
|
||||||
|
|
||||||
|
state->forceAttrs(v, pos);
|
||||||
|
|
||||||
|
if (auto attr = v.attrs->get(state->symbols.create("path"))) {
|
||||||
|
if (attr->name == state->symbols.create("path")) {
|
||||||
|
PathSet context;
|
||||||
|
auto path = state->coerceToPath(*attr->pos, *attr->value, context);
|
||||||
|
if (!store->isInStore(path))
|
||||||
|
throw Error("template '%s' has a bad 'path' attribute");
|
||||||
|
// TODO: recursively check the flake in 'path'.
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
throw Error("template '%s' lacks attribute 'path'", attrPath);
|
||||||
|
|
||||||
|
if (auto attr = v.attrs->get(state->symbols.create("description")))
|
||||||
|
state->forceStringNoCtx(*attr->value, *attr->pos);
|
||||||
|
else
|
||||||
|
throw Error("template '%s' lacks attribute 'description'", attrPath);
|
||||||
|
|
||||||
|
for (auto & attr : *v.attrs) {
|
||||||
|
std::string name(attr.name);
|
||||||
|
if (name != "path" && name != "description")
|
||||||
|
throw Error("template '%s' has unsupported attribute '%s'", attrPath, name);
|
||||||
|
}
|
||||||
|
} catch (Error & e) {
|
||||||
|
e.addPrefix(fmt("while checking the template '" ANSI_BOLD "%s" ANSI_NORMAL "' at %s:\n", attrPath, pos));
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
|
Activity act(*logger, lvlInfo, actUnknown, "evaluating flake");
|
||||||
|
|
||||||
|
@ -432,6 +468,16 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
else if (name == "hydraJobs")
|
else if (name == "hydraJobs")
|
||||||
checkHydraJobs(name, vOutput, pos);
|
checkHydraJobs(name, vOutput, pos);
|
||||||
|
|
||||||
|
else if (name == "defaultTemplate")
|
||||||
|
checkTemplate(name, vOutput, pos);
|
||||||
|
|
||||||
|
else if (name == "templates") {
|
||||||
|
state->forceAttrs(vOutput, pos);
|
||||||
|
for (auto & attr : *vOutput.attrs)
|
||||||
|
checkTemplate(fmt("%s.%s", name, attr.name),
|
||||||
|
*attr.value, *attr.pos);
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
warn("unknown flake output '%s'", name);
|
warn("unknown flake output '%s'", name);
|
||||||
|
|
||||||
|
@ -449,29 +495,135 @@ struct CmdFlakeCheck : FlakeCommand
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CmdFlakeInit : virtual Args, Command
|
struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||||
|
{
|
||||||
|
std::string templateUrl = "templates";
|
||||||
|
Path destDir;
|
||||||
|
|
||||||
|
CmdFlakeInitCommon()
|
||||||
|
{
|
||||||
|
addFlag({
|
||||||
|
.longName = "template",
|
||||||
|
.shortName = 't',
|
||||||
|
.description = "the template to use",
|
||||||
|
.labels = {"template"},
|
||||||
|
.handler = {&templateUrl},
|
||||||
|
.completer = {[&](size_t, std::string_view prefix) {
|
||||||
|
completeFlakeRef(prefix);
|
||||||
|
}}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(nix::ref<nix::Store> store) override
|
||||||
|
{
|
||||||
|
auto flakeDir = absPath(destDir);
|
||||||
|
|
||||||
|
auto evalState = getEvalState();
|
||||||
|
|
||||||
|
auto [templateFlakeRef, templateName] = parseFlakeRefWithFragment(templateUrl, absPath("."));
|
||||||
|
|
||||||
|
auto installable = InstallableFlake(
|
||||||
|
evalState, std::move(templateFlakeRef),
|
||||||
|
Strings{templateName == "" ? "defaultTemplate" : templateName},
|
||||||
|
Strings{"templates."}, { .writeLockFile = false });
|
||||||
|
|
||||||
|
auto cursor = installable.getCursor(*evalState, true);
|
||||||
|
|
||||||
|
auto templateDir = cursor.first->getAttr("path")->getString();
|
||||||
|
|
||||||
|
assert(store->isInStore(templateDir));
|
||||||
|
|
||||||
|
std::vector<Path> files;
|
||||||
|
|
||||||
|
std::function<void(const Path & from, const Path & to)> copyDir;
|
||||||
|
copyDir = [&](const Path & from, const Path & to)
|
||||||
|
{
|
||||||
|
createDirs(to);
|
||||||
|
|
||||||
|
for (auto & entry : readDirectory(from)) {
|
||||||
|
auto from2 = from + "/" + entry.name;
|
||||||
|
auto to2 = to + "/" + entry.name;
|
||||||
|
auto st = lstat(from2);
|
||||||
|
if (S_ISDIR(st.st_mode))
|
||||||
|
copyDir(from2, to2);
|
||||||
|
else if (S_ISREG(st.st_mode)) {
|
||||||
|
auto contents = readFile(from2);
|
||||||
|
if (pathExists(to2)) {
|
||||||
|
auto contents2 = readFile(to2);
|
||||||
|
if (contents != contents2)
|
||||||
|
throw Error("refusing to overwrite existing file '%s'", to2);
|
||||||
|
} else
|
||||||
|
writeFile(to2, contents);
|
||||||
|
}
|
||||||
|
else if (S_ISLNK(st.st_mode)) {
|
||||||
|
auto target = readLink(from2);
|
||||||
|
if (pathExists(to2)) {
|
||||||
|
if (readLink(to2) != target)
|
||||||
|
throw Error("refusing to overwrite existing symlink '%s'", to2);
|
||||||
|
} else
|
||||||
|
createSymlink(target, to2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw Error("file '%s' has unsupported type", from2);
|
||||||
|
files.push_back(to2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
copyDir(templateDir, flakeDir);
|
||||||
|
|
||||||
|
if (pathExists(flakeDir + "/.git")) {
|
||||||
|
Strings args = { "-C", flakeDir, "add", "--intent-to-add", "--" };
|
||||||
|
for (auto & s : files) args.push_back(s);
|
||||||
|
runProgram("git", true, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CmdFlakeInit : CmdFlakeInitCommon
|
||||||
{
|
{
|
||||||
std::string description() override
|
std::string description() override
|
||||||
{
|
{
|
||||||
return "create a skeleton 'flake.nix' file in the current directory";
|
return "create a flake in the current directory from a template";
|
||||||
}
|
}
|
||||||
|
|
||||||
void run() override
|
Examples examples() override
|
||||||
{
|
{
|
||||||
Path flakeDir = absPath(".");
|
return {
|
||||||
|
Example{
|
||||||
|
"To create a flake using the default template:",
|
||||||
|
"nix flake init"
|
||||||
|
},
|
||||||
|
Example{
|
||||||
|
"To see available templates:",
|
||||||
|
"nix flake show templates"
|
||||||
|
},
|
||||||
|
Example{
|
||||||
|
"To create a flake from a specific template:",
|
||||||
|
"nix flake init -t templates#nixos-container"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Path flakePath = flakeDir + "/flake.nix";
|
CmdFlakeInit()
|
||||||
|
{
|
||||||
|
destDir = ".";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (pathExists(flakePath))
|
struct CmdFlakeNew : CmdFlakeInitCommon
|
||||||
throw Error("file '%s' already exists", flakePath);
|
{
|
||||||
|
std::string description() override
|
||||||
|
{
|
||||||
|
return "create a flake in the specified directory from a template";
|
||||||
|
}
|
||||||
|
|
||||||
writeFile(flakePath,
|
CmdFlakeNew()
|
||||||
#include "flake-template.nix.gen.hh"
|
{
|
||||||
);
|
expectArgs({
|
||||||
|
.label = "dest-dir",
|
||||||
if (pathExists(flakeDir + "/.git"))
|
.handler = {&destDir},
|
||||||
runProgram("git", true,
|
.completer = completePath
|
||||||
{ "-C", flakeDir, "add", "--intent-to-add", "flake.nix" });
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -662,7 +814,8 @@ struct CmdFlakeShow : FlakeCommand
|
||||||
|| attrPath[0] == "devShell"
|
|| attrPath[0] == "devShell"
|
||||||
|| attrPath[0] == "nixosConfigurations"
|
|| attrPath[0] == "nixosConfigurations"
|
||||||
|| attrPath[0] == "nixosModules"
|
|| attrPath[0] == "nixosModules"
|
||||||
|| attrPath[0] == "defaultApp"))
|
|| attrPath[0] == "defaultApp"
|
||||||
|
|| attrPath[0] == "templates"))
|
||||||
|| ((attrPath.size() == 1 || attrPath.size() == 2)
|
|| ((attrPath.size() == 1 || attrPath.size() == 2)
|
||||||
&& (attrPath[0] == "checks"
|
&& (attrPath[0] == "checks"
|
||||||
|| attrPath[0] == "packages"
|
|| attrPath[0] == "packages"
|
||||||
|
@ -714,6 +867,14 @@ struct CmdFlakeShow : FlakeCommand
|
||||||
logger->stdout("%s: app", headerPrefix);
|
logger->stdout("%s: app", headerPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (
|
||||||
|
(attrPath.size() == 1 && attrPath[0] == "defaultTemplate") ||
|
||||||
|
(attrPath.size() == 2 && attrPath[0] == "templates"))
|
||||||
|
{
|
||||||
|
auto description = visitor.getAttr("description")->getString();
|
||||||
|
logger->stdout("%s: template: " ANSI_BOLD "%s" ANSI_NORMAL, headerPrefix, description);
|
||||||
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
logger->stdout("%s: %s",
|
logger->stdout("%s: %s",
|
||||||
headerPrefix,
|
headerPrefix,
|
||||||
|
@ -743,6 +904,7 @@ struct CmdFlake : virtual MultiCommand, virtual Command
|
||||||
{"list-inputs", []() { return make_ref<CmdFlakeListInputs>(); }},
|
{"list-inputs", []() { return make_ref<CmdFlakeListInputs>(); }},
|
||||||
{"check", []() { return make_ref<CmdFlakeCheck>(); }},
|
{"check", []() { return make_ref<CmdFlakeCheck>(); }},
|
||||||
{"init", []() { return make_ref<CmdFlakeInit>(); }},
|
{"init", []() { return make_ref<CmdFlakeInit>(); }},
|
||||||
|
{"new", []() { return make_ref<CmdFlakeNew>(); }},
|
||||||
{"clone", []() { return make_ref<CmdFlakeClone>(); }},
|
{"clone", []() { return make_ref<CmdFlakeClone>(); }},
|
||||||
{"archive", []() { return make_ref<CmdFlakeArchive>(); }},
|
{"archive", []() { return make_ref<CmdFlakeArchive>(); }},
|
||||||
{"show", []() { return make_ref<CmdFlakeShow>(); }},
|
{"show", []() { return make_ref<CmdFlakeShow>(); }},
|
||||||
|
|
|
@ -237,7 +237,7 @@ App Installable::toApp(EvalState & state)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
||||||
Installable::getCursor(EvalState & state, bool useEvalCache)
|
Installable::getCursors(EvalState & state, bool useEvalCache)
|
||||||
{
|
{
|
||||||
auto evalCache =
|
auto evalCache =
|
||||||
std::make_shared<nix::eval_cache::EvalCache>(false, Hash(), state,
|
std::make_shared<nix::eval_cache::EvalCache>(false, Hash(), state,
|
||||||
|
@ -245,6 +245,15 @@ Installable::getCursor(EvalState & state, bool useEvalCache)
|
||||||
return {{evalCache->getRoot(), ""}};
|
return {{evalCache->getRoot(), ""}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>
|
||||||
|
Installable::getCursor(EvalState & state, bool useEvalCache)
|
||||||
|
{
|
||||||
|
auto cursors = getCursors(state, useEvalCache);
|
||||||
|
if (cursors.empty())
|
||||||
|
throw Error("cannot find flake attribute '%s'", what());
|
||||||
|
return cursors[0];
|
||||||
|
}
|
||||||
|
|
||||||
struct InstallableStorePath : Installable
|
struct InstallableStorePath : Installable
|
||||||
{
|
{
|
||||||
ref<Store> store;
|
ref<Store> store;
|
||||||
|
@ -474,7 +483,7 @@ std::pair<Value *, Pos> InstallableFlake::toValue(EvalState & state)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
||||||
InstallableFlake::getCursor(EvalState & state, bool useEvalCache)
|
InstallableFlake::getCursors(EvalState & state, bool useEvalCache)
|
||||||
{
|
{
|
||||||
auto evalCache = openEvalCache(state,
|
auto evalCache = openEvalCache(state,
|
||||||
std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)),
|
std::make_shared<flake::LockedFlake>(lockFlake(state, flakeRef, lockFlags)),
|
||||||
|
|
|
@ -56,6 +56,9 @@ struct Installable
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
virtual std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
||||||
|
getCursors(EvalState & state, bool useEvalCache);
|
||||||
|
|
||||||
|
std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>
|
||||||
getCursor(EvalState & state, bool useEvalCache);
|
getCursor(EvalState & state, bool useEvalCache);
|
||||||
|
|
||||||
virtual FlakeRef nixpkgsFlakeRef() const
|
virtual FlakeRef nixpkgsFlakeRef() const
|
||||||
|
@ -109,7 +112,7 @@ struct InstallableFlake : InstallableValue
|
||||||
std::pair<Value *, Pos> toValue(EvalState & state) override;
|
std::pair<Value *, Pos> toValue(EvalState & state) override;
|
||||||
|
|
||||||
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>>
|
||||||
getCursor(EvalState & state, bool useEvalCache) override;
|
getCursors(EvalState & state, bool useEvalCache) override;
|
||||||
|
|
||||||
std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
|
std::shared_ptr<flake::LockedFlake> getLockedFlake() const;
|
||||||
|
|
||||||
|
|
|
@ -29,5 +29,3 @@ $(eval $(call install-symlink, $(bindir)/nix, $(libexecdir)/nix/build-remote))
|
||||||
src/nix-env/user-env.cc: src/nix-env/buildenv.nix.gen.hh
|
src/nix-env/user-env.cc: src/nix-env/buildenv.nix.gen.hh
|
||||||
|
|
||||||
src/nix/develop.cc: src/nix/get-env.sh.gen.hh
|
src/nix/develop.cc: src/nix/get-env.sh.gen.hh
|
||||||
|
|
||||||
$(d)/flake.cc: $(d)/flake-template.nix.gen.hh
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ struct CmdSearch : InstallableCommand, MixJSON
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto & [cursor, prefix] : installable->getCursor(*state, true))
|
for (auto & [cursor, prefix] : installable->getCursors(*state, true))
|
||||||
visit(*cursor, parseAttrPath(*state, prefix));
|
visit(*cursor, parseAttrPath(*state, prefix));
|
||||||
|
|
||||||
if (!json && !results)
|
if (!json && !results)
|
||||||
|
|
|
@ -20,12 +20,14 @@ flake2Dir=$TEST_ROOT/flake2
|
||||||
flake3Dir=$TEST_ROOT/flake3
|
flake3Dir=$TEST_ROOT/flake3
|
||||||
flake4Dir=$TEST_ROOT/flake4
|
flake4Dir=$TEST_ROOT/flake4
|
||||||
flake5Dir=$TEST_ROOT/flake5
|
flake5Dir=$TEST_ROOT/flake5
|
||||||
|
flake6Dir=$TEST_ROOT/flake6
|
||||||
flake7Dir=$TEST_ROOT/flake7
|
flake7Dir=$TEST_ROOT/flake7
|
||||||
|
templatesDir=$TEST_ROOT/templates
|
||||||
nonFlakeDir=$TEST_ROOT/nonFlake
|
nonFlakeDir=$TEST_ROOT/nonFlake
|
||||||
flakeA=$TEST_ROOT/flakeA
|
flakeA=$TEST_ROOT/flakeA
|
||||||
flakeB=$TEST_ROOT/flakeB
|
flakeB=$TEST_ROOT/flakeB
|
||||||
|
|
||||||
for repo in $flake1Dir $flake2Dir $flake3Dir $flake7Dir $nonFlakeDir $flakeA $flakeB; do
|
for repo in $flake1Dir $flake2Dir $flake3Dir $flake7Dir $templatesDir $nonFlakeDir $flakeA $flakeB; do
|
||||||
rm -rf $repo $repo.tmp
|
rm -rf $repo $repo.tmp
|
||||||
mkdir $repo
|
mkdir $repo
|
||||||
git -C $repo init
|
git -C $repo init
|
||||||
|
@ -145,13 +147,22 @@ cat > $registry <<EOF
|
||||||
"type": "indirect",
|
"type": "indirect",
|
||||||
"id": "flake1"
|
"id": "flake1"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{ "from": {
|
||||||
|
"type": "indirect",
|
||||||
|
"id": "templates"
|
||||||
|
},
|
||||||
|
"to": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "file://$templatesDir"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
# Test 'nix flake list'.
|
# Test 'nix flake list'.
|
||||||
[[ $(nix registry list | wc -l) == 6 ]]
|
[[ $(nix registry list | wc -l) == 7 ]]
|
||||||
|
|
||||||
# Test 'nix flake info'.
|
# Test 'nix flake info'.
|
||||||
nix flake info flake1 | grep -q 'URL: .*flake1.*'
|
nix flake info flake1 | grep -q 'URL: .*flake1.*'
|
||||||
|
@ -392,18 +403,61 @@ nix build -o $TEST_ROOT/result flake4/removeXyzzy#sth
|
||||||
|
|
||||||
# Testing the nix CLI
|
# Testing the nix CLI
|
||||||
nix registry add flake1 flake3
|
nix registry add flake1 flake3
|
||||||
[[ $(nix registry list | wc -l) == 7 ]]
|
[[ $(nix registry list | wc -l) == 8 ]]
|
||||||
nix registry pin flake1
|
nix registry pin flake1
|
||||||
[[ $(nix registry list | wc -l) == 7 ]]
|
[[ $(nix registry list | wc -l) == 8 ]]
|
||||||
nix registry remove flake1
|
nix registry remove flake1
|
||||||
[[ $(nix registry list | wc -l) == 6 ]]
|
[[ $(nix registry list | wc -l) == 7 ]]
|
||||||
|
|
||||||
# Test 'nix flake init'.
|
# Test 'nix flake init'.
|
||||||
|
cat > $templatesDir/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
description = "Some templates";
|
||||||
|
|
||||||
|
outputs = { self }: {
|
||||||
|
templates = {
|
||||||
|
trivial = {
|
||||||
|
path = ./trivial;
|
||||||
|
description = "A trivial flake";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
defaultTemplate = self.templates.trivial;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
mkdir $templatesDir/trivial
|
||||||
|
|
||||||
|
cat > $templatesDir/trivial/flake.nix <<EOF
|
||||||
|
{
|
||||||
|
description = "A flake for building Hello World";
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs }: {
|
||||||
|
packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
|
||||||
|
defaultPackage.x86_64-linux = self.packages.x86_64-linux.hello;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
git -C $templatesDir add flake.nix trivial/flake.nix
|
||||||
|
git -C $templatesDir commit -m 'Initial'
|
||||||
|
|
||||||
|
nix flake check templates
|
||||||
|
nix flake show templates
|
||||||
|
|
||||||
(cd $flake7Dir && nix flake init)
|
(cd $flake7Dir && nix flake init)
|
||||||
|
(cd $flake7Dir && nix flake init) # check idempotence
|
||||||
git -C $flake7Dir add flake.nix
|
git -C $flake7Dir add flake.nix
|
||||||
nix flake check $flake7Dir
|
nix flake check $flake7Dir
|
||||||
|
nix flake show $flake7Dir
|
||||||
git -C $flake7Dir commit -a -m 'Initial'
|
git -C $flake7Dir commit -a -m 'Initial'
|
||||||
|
|
||||||
|
# Test 'nix flake new'.
|
||||||
|
rm -rf $flake6Dir
|
||||||
|
nix flake new -t templates#trivial $flake6Dir
|
||||||
|
nix flake new -t templates#trivial $flake6Dir # check idempotence
|
||||||
|
nix flake check $flake6Dir
|
||||||
|
|
||||||
# Test 'nix flake clone'.
|
# Test 'nix flake clone'.
|
||||||
rm -rf $TEST_ROOT/flake1-v2
|
rm -rf $TEST_ROOT/flake1-v2
|
||||||
nix flake clone flake1 --dest $TEST_ROOT/flake1-v2
|
nix flake clone flake1 --dest $TEST_ROOT/flake1-v2
|
||||||
|
@ -663,4 +717,4 @@ git -C $flakeB commit -a -m 'Foo'
|
||||||
[[ $(nix eval --update-input b $flakeA#foo) = 1912 ]]
|
[[ $(nix eval --update-input b $flakeA#foo) = 1912 ]]
|
||||||
|
|
||||||
# Test list-inputs with circular dependencies
|
# Test list-inputs with circular dependencies
|
||||||
nix flake list-inputs $flakeA
|
nix flake list-inputs $flakeA
|
||||||
|
|
Loading…
Reference in a new issue