Compare commits
2 Commits
derivation
...
nix-init-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc711c6956 | ||
|
|
401b09b7fe |
138
src/nix/flake.cc
138
src/nix/flake.cc
@@ -638,142 +638,6 @@ struct CmdFlakeCheck : FlakeCommand
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||
{
|
||||
std::string templateUrl = "templates";
|
||||
Path destDir;
|
||||
|
||||
const Strings attrsPathPrefixes{"templates."};
|
||||
const LockFlags lockFlags{ .writeLockFile = false };
|
||||
|
||||
CmdFlakeInitCommon()
|
||||
{
|
||||
addFlag({
|
||||
.longName = "template",
|
||||
.shortName = 't',
|
||||
.description = "The template to use.",
|
||||
.labels = {"template"},
|
||||
.handler = {&templateUrl},
|
||||
.completer = {[&](size_t, std::string_view prefix) {
|
||||
completeFlakeRefWithFragment(
|
||||
getEvalState(),
|
||||
lockFlags,
|
||||
attrsPathPrefixes,
|
||||
{"defaultTemplate"},
|
||||
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(nullptr,
|
||||
evalState, std::move(templateFlakeRef),
|
||||
Strings{templateName == "" ? "defaultTemplate" : templateName},
|
||||
Strings(attrsPathPrefixes), lockFlags);
|
||||
|
||||
auto [cursor, attrPath] = installable.getCursor(*evalState);
|
||||
|
||||
auto templateDir = cursor->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", "--force", "--" };
|
||||
for (auto & s : files) args.push_back(s);
|
||||
runProgram("git", true, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdFlakeInit : CmdFlakeInitCommon
|
||||
{
|
||||
std::string description() override
|
||||
{
|
||||
return "create a flake in the current directory from a template";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "flake-init.md"
|
||||
;
|
||||
}
|
||||
|
||||
CmdFlakeInit()
|
||||
{
|
||||
destDir = ".";
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdFlakeNew : CmdFlakeInitCommon
|
||||
{
|
||||
std::string description() override
|
||||
{
|
||||
return "create a flake in the specified directory from a template";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "flake-new.md"
|
||||
;
|
||||
}
|
||||
|
||||
CmdFlakeNew()
|
||||
{
|
||||
expectArgs({
|
||||
.label = "dest-dir",
|
||||
.handler = {&destDir},
|
||||
.completer = completePath
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdFlakeClone : FlakeCommand
|
||||
{
|
||||
Path destDir;
|
||||
@@ -1125,8 +989,6 @@ struct CmdFlake : NixMultiCommand
|
||||
{"metadata", []() { return make_ref<CmdFlakeMetadata>(); }},
|
||||
{"info", []() { return make_ref<CmdFlakeInfo>(); }},
|
||||
{"check", []() { return make_ref<CmdFlakeCheck>(); }},
|
||||
{"init", []() { return make_ref<CmdFlakeInit>(); }},
|
||||
{"new", []() { return make_ref<CmdFlakeNew>(); }},
|
||||
{"clone", []() { return make_ref<CmdFlakeClone>(); }},
|
||||
{"archive", []() { return make_ref<CmdFlakeArchive>(); }},
|
||||
{"show", []() { return make_ref<CmdFlakeShow>(); }},
|
||||
|
||||
@@ -106,26 +106,28 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||
});
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<std::string>> aliases = {
|
||||
{"add-to-store", {"store", "add-path"}},
|
||||
{"cat-nar", {"nar", "cat"}},
|
||||
{"cat-store", {"store", "cat"}},
|
||||
{"copy-sigs", {"store", "copy-sigs"}},
|
||||
{"dev-shell", {"develop"}},
|
||||
{"diff-closures", {"store", "diff-closures"}},
|
||||
{"dump-path", {"store", "dump-path"}},
|
||||
{"hash-file", {"hash", "file"}},
|
||||
{"hash-path", {"hash", "path"}},
|
||||
{"ls-nar", {"nar", "ls"}},
|
||||
{"ls-store", {"store", "ls"}},
|
||||
{"make-content-addressable", {"store", "make-content-addressable"}},
|
||||
{"optimise-store", {"store", "optimise"}},
|
||||
{"ping-store", {"store", "ping"}},
|
||||
{"sign-paths", {"store", "sign"}},
|
||||
{"to-base16", {"hash", "to-base16"}},
|
||||
{"to-base32", {"hash", "to-base32"}},
|
||||
{"to-base64", {"hash", "to-base64"}},
|
||||
{"verify", {"store", "verify"}},
|
||||
std::map<std::vector<std::string>, std::vector<std::string>> aliases = {
|
||||
{{"add-to-store"}, {"store", "add-path"}},
|
||||
{{"cat-nar"}, {"nar", "cat"}},
|
||||
{{"cat-store"}, {"store", "cat"}},
|
||||
{{"copy-sigs"}, {"store", "copy-sigs"}},
|
||||
{{"dev-shell"}, {"develop"}},
|
||||
{{"diff-closures"}, {"store", "diff-closures"}},
|
||||
{{"dump-path"}, {"store", "dump-path"}},
|
||||
{{"hash-file"}, {"hash", "file"}},
|
||||
{{"hash-path"}, {"hash", "path"}},
|
||||
{{"ls-nar"}, {"nar", "ls"}},
|
||||
{{"ls-store"}, {"store", "ls"}},
|
||||
{{"make-content-addressable"}, {"store", "make-content-addressable"}},
|
||||
{{"optimise-store"}, {"store", "optimise"}},
|
||||
{{"ping-store"}, {"store", "ping"}},
|
||||
{{"sign-paths"}, {"store", "sign"}},
|
||||
{{"to-base16"}, {"hash", "to-base16"}},
|
||||
{{"to-base32"}, {"hash", "to-base32"}},
|
||||
{{"to-base64"}, {"hash", "to-base64"}},
|
||||
{{"verify"}, {"store", "verify"}},
|
||||
{{"flake", "init"}, {"init"}},
|
||||
{{"flake", "new"}, {"new"}},
|
||||
};
|
||||
|
||||
bool aliasUsed = false;
|
||||
@@ -134,14 +136,33 @@ struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||
{
|
||||
if (aliasUsed || command || pos == args.end()) return pos;
|
||||
auto arg = *pos;
|
||||
auto i = aliases.find(arg);
|
||||
if (i == aliases.end()) return pos;
|
||||
warn("'%s' is a deprecated alias for '%s'",
|
||||
arg, concatStringsSep(" ", i->second));
|
||||
pos = args.erase(pos);
|
||||
for (auto j = i->second.rbegin(); j != i->second.rend(); ++j)
|
||||
pos = args.insert(pos, *j);
|
||||
aliasUsed = true;
|
||||
|
||||
// Loop through the aliases to see whether the current cli corresponds
|
||||
// to one of them.
|
||||
for (auto & [from, to] : aliases) {
|
||||
auto i = pos;
|
||||
bool isCurrentAlias = true;
|
||||
// Is the current alias a prefix of the args?
|
||||
for (auto & fromItem : from) {
|
||||
if (i == args.end() || *i != fromItem) {
|
||||
// The current alias doesn’t match the args
|
||||
isCurrentAlias = false;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// If we went through to the end of the previous loop, then we match
|
||||
// the currently considered alias.
|
||||
// So rewrite the alias in the current args.
|
||||
if (isCurrentAlias) {
|
||||
warn("'%s' is a deprecated alias for '%s'",
|
||||
concatStringsSep(" ", from), concatStringsSep(" ", to));
|
||||
pos = args.erase(pos, i);
|
||||
pos = args.insert(pos, to.begin(), to.end());
|
||||
aliasUsed = true;
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
150
src/nix/new.cc
Normal file
150
src/nix/new.cc
Normal file
@@ -0,0 +1,150 @@
|
||||
#include "command.hh"
|
||||
#include "common-args.hh"
|
||||
#include "shared.hh"
|
||||
#include "store-api.hh"
|
||||
#include "local-fs-store.hh"
|
||||
#include "fs-accessor.hh"
|
||||
#include "eval-cache.hh"
|
||||
|
||||
using namespace nix;
|
||||
using namespace nix::flake;
|
||||
|
||||
struct CmdFlakeInitCommon : virtual Args, EvalCommand
|
||||
{
|
||||
std::string templateUrl = "templates";
|
||||
Path destDir;
|
||||
|
||||
const Strings attrsPathPrefixes{"templates."};
|
||||
const LockFlags lockFlags{ .writeLockFile = false };
|
||||
|
||||
CmdFlakeInitCommon()
|
||||
{
|
||||
addFlag({
|
||||
.longName = "template",
|
||||
.shortName = 't',
|
||||
.description = "The template to use.",
|
||||
.labels = {"template"},
|
||||
.handler = {&templateUrl},
|
||||
.completer = {[&](size_t, std::string_view prefix) {
|
||||
completeFlakeRefWithFragment(
|
||||
getEvalState(),
|
||||
lockFlags,
|
||||
attrsPathPrefixes,
|
||||
{"defaultTemplate"},
|
||||
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(nullptr,
|
||||
evalState, std::move(templateFlakeRef),
|
||||
Strings{templateName == "" ? "defaultTemplate" : templateName},
|
||||
Strings(attrsPathPrefixes), lockFlags);
|
||||
|
||||
auto [cursor, attrPath] = installable.getCursor(*evalState);
|
||||
|
||||
auto templateDir = cursor->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", "--force", "--" };
|
||||
for (auto & s : files) args.push_back(s);
|
||||
runProgram("git", true, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdFlakeInit : CmdFlakeInitCommon
|
||||
{
|
||||
std::string description() override
|
||||
{
|
||||
return "create a flake in the current directory from a template";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "init.md"
|
||||
;
|
||||
}
|
||||
|
||||
CmdFlakeInit()
|
||||
{
|
||||
destDir = ".";
|
||||
}
|
||||
};
|
||||
|
||||
struct CmdFlakeNew : CmdFlakeInitCommon
|
||||
{
|
||||
std::string description() override
|
||||
{
|
||||
return "create a flake in the specified directory from a template";
|
||||
}
|
||||
|
||||
std::string doc() override
|
||||
{
|
||||
return
|
||||
#include "new.md"
|
||||
;
|
||||
}
|
||||
|
||||
CmdFlakeNew()
|
||||
{
|
||||
expectArgs({
|
||||
.label = "dest-dir",
|
||||
.handler = {&destDir},
|
||||
.completer = completePath
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
static auto r0 = registerCommand<CmdFlakeInit>("init");
|
||||
static auto r1 = registerCommand<CmdFlakeNew>("new");
|
||||
|
||||
Reference in New Issue
Block a user