forked from lix-project/lix
Start of new Nix command-line interface
This commit is contained in:
parent
0db9e6cd1a
commit
cd2196b089
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -73,9 +73,6 @@ Makefile.config
|
||||||
# /src/nix-env/
|
# /src/nix-env/
|
||||||
/src/nix-env/nix-env
|
/src/nix-env/nix-env
|
||||||
|
|
||||||
# /src/nix-hash/
|
|
||||||
/src/nix-hash/nix-hash
|
|
||||||
|
|
||||||
# /src/nix-instantiate/
|
# /src/nix-instantiate/
|
||||||
/src/nix-instantiate/nix-instantiate
|
/src/nix-instantiate/nix-instantiate
|
||||||
|
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ makefiles = \
|
||||||
src/libstore/local.mk \
|
src/libstore/local.mk \
|
||||||
src/libmain/local.mk \
|
src/libmain/local.mk \
|
||||||
src/libexpr/local.mk \
|
src/libexpr/local.mk \
|
||||||
src/nix-hash/local.mk \
|
src/nix/local.mk \
|
||||||
src/nix-store/local.mk \
|
src/nix-store/local.mk \
|
||||||
src/nix-instantiate/local.mk \
|
src/nix-instantiate/local.mk \
|
||||||
src/nix-env/local.mk \
|
src/nix-env/local.mk \
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
MixCommonArgs::MixCommonArgs(const string & programName)
|
MixCommonArgs::MixCommonArgs(const string & programName)
|
||||||
|
: programName(programName)
|
||||||
{
|
{
|
||||||
mkFlag('v', "verbose", "increase verbosity level", []() {
|
mkFlag('v', "verbose", "increase verbosity level", []() {
|
||||||
verbosity = (Verbosity) (verbosity + 1);
|
verbosity = (Verbosity) (verbosity + 1);
|
||||||
|
|
|
@ -6,6 +6,7 @@ namespace nix {
|
||||||
|
|
||||||
struct MixCommonArgs : virtual Args
|
struct MixCommonArgs : virtual Args
|
||||||
{
|
{
|
||||||
|
string programName;
|
||||||
MixCommonArgs(const string & programName);
|
MixCommonArgs(const string & programName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,8 @@ public:
|
||||||
*dest = ss;
|
*dest = ss;
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
friend class MultiCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
Strings argvToStrings(int argc, char * * argv);
|
Strings argvToStrings(int argc, char * * argv);
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
programs += nix-hash
|
|
||||||
|
|
||||||
nix-hash_DIR := $(d)
|
|
||||||
|
|
||||||
nix-hash_SOURCES := $(d)/nix-hash.cc
|
|
||||||
|
|
||||||
nix-hash_LIBS = libmain libstore libutil libformat
|
|
|
@ -1,63 +0,0 @@
|
||||||
#include "hash.hh"
|
|
||||||
#include "shared.hh"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace nix;
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * * argv)
|
|
||||||
{
|
|
||||||
HashType ht = htMD5;
|
|
||||||
bool flat = false;
|
|
||||||
bool base32 = false;
|
|
||||||
bool truncate = false;
|
|
||||||
enum { opHash, opTo32, opTo16 } op = opHash;
|
|
||||||
|
|
||||||
Strings ss;
|
|
||||||
|
|
||||||
return handleExceptions(argv[0], [&]() {
|
|
||||||
initNix();
|
|
||||||
|
|
||||||
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
|
||||||
if (*arg == "--help")
|
|
||||||
showManPage("nix-hash");
|
|
||||||
else if (*arg == "--version")
|
|
||||||
printVersion("nix-hash");
|
|
||||||
else if (*arg == "--flat") flat = true;
|
|
||||||
else if (*arg == "--base32") base32 = true;
|
|
||||||
else if (*arg == "--truncate") truncate = true;
|
|
||||||
else if (*arg == "--type") {
|
|
||||||
string s = getArg(*arg, arg, end);
|
|
||||||
ht = parseHashType(s);
|
|
||||||
if (ht == htUnknown)
|
|
||||||
throw UsageError(format("unknown hash type ‘%1%’") % s);
|
|
||||||
}
|
|
||||||
else if (*arg == "--to-base16") op = opTo16;
|
|
||||||
else if (*arg == "--to-base32") op = opTo32;
|
|
||||||
else if (*arg != "" && arg->at(0) == '-')
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
ss.push_back(*arg);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (op == opHash) {
|
|
||||||
for (auto & i : ss) {
|
|
||||||
Hash h = flat ? hashFile(ht, i) : hashPath(ht, i).first;
|
|
||||||
if (truncate && h.hashSize > 20) h = compressHash(h, 20);
|
|
||||||
std::cout << format("%1%\n") %
|
|
||||||
(base32 ? printHash32(h) : printHash(h));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
for (auto & i : ss) {
|
|
||||||
Hash h = parseHash16or32(ht, i);
|
|
||||||
std::cout << format("%1%\n") %
|
|
||||||
(op == opTo16 ? printHash(h) : printHash32(h));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
65
src/nix/command.cc
Normal file
65
src/nix/command.cc
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#include "command.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
Commands * RegisterCommand::commands = 0;
|
||||||
|
|
||||||
|
MultiCommand::MultiCommand(const Commands & _commands)
|
||||||
|
: commands(_commands)
|
||||||
|
{
|
||||||
|
expectedArgs.push_back(ExpectedArg{"command", 1, [=](Strings ss) {
|
||||||
|
assert(!command);
|
||||||
|
auto i = commands.find(ss.front());
|
||||||
|
if (i == commands.end())
|
||||||
|
throw UsageError(format("‘%1%’ is not a recognised command") % ss.front());
|
||||||
|
command = i->second;
|
||||||
|
}});
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiCommand::printHelp(const string & programName, std::ostream & out)
|
||||||
|
{
|
||||||
|
if (command) {
|
||||||
|
command->printHelp(programName + " " + command->name(), out);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "Usage: " << programName << " <COMMAND> <FLAGS>... <ARGS>...\n";
|
||||||
|
|
||||||
|
out << "\n";
|
||||||
|
out << "Common flags:\n";
|
||||||
|
printFlags(out);
|
||||||
|
|
||||||
|
out << "\n";
|
||||||
|
out << "Available commands:\n";
|
||||||
|
|
||||||
|
Table2 table;
|
||||||
|
for (auto & command : commands)
|
||||||
|
table.push_back(std::make_pair(command.second->name(), command.second->description()));
|
||||||
|
printTable(out, table);
|
||||||
|
|
||||||
|
out << "\n";
|
||||||
|
out << "For full documentation, run ‘man " << programName << "’ or ‘man " << programName << "-<COMMAND>’.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MultiCommand::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||||
|
{
|
||||||
|
if (Args::processFlag(pos, end)) return true;
|
||||||
|
if (command && command->processFlag(pos, end)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MultiCommand::processArgs(const Strings & args, bool finish)
|
||||||
|
{
|
||||||
|
if (command)
|
||||||
|
return command->processArgs(args, finish);
|
||||||
|
else
|
||||||
|
return Args::processArgs(args, finish);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StoreCommand::run()
|
||||||
|
{
|
||||||
|
run(openStore(reserveSpace));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
59
src/nix/command.hh
Normal file
59
src/nix/command.hh
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "args.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
/* A command is an argument parser that can be executed by calling its
|
||||||
|
run() method. */
|
||||||
|
struct Command : virtual Args
|
||||||
|
{
|
||||||
|
virtual std::string name() = 0;
|
||||||
|
virtual void prepare() { };
|
||||||
|
virtual void run() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Store;
|
||||||
|
|
||||||
|
/* A command that require a Nix store. */
|
||||||
|
struct StoreCommand : virtual Command
|
||||||
|
{
|
||||||
|
bool reserveSpace;
|
||||||
|
StoreCommand(bool reserveSpace = true)
|
||||||
|
: reserveSpace(reserveSpace) { };
|
||||||
|
void run() override;
|
||||||
|
virtual void run(ref<Store>) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string, ref<Command>> Commands;
|
||||||
|
|
||||||
|
/* An argument parser that supports multiple subcommands,
|
||||||
|
i.e. ‘<command> <subcommand>’. */
|
||||||
|
struct MultiCommand : virtual Args
|
||||||
|
{
|
||||||
|
Commands commands;
|
||||||
|
|
||||||
|
std::shared_ptr<Command> command;
|
||||||
|
|
||||||
|
MultiCommand(const Commands & commands);
|
||||||
|
|
||||||
|
void printHelp(const string & programName, std::ostream & out) override;
|
||||||
|
|
||||||
|
bool processFlag(Strings::iterator & pos, Strings::iterator end) override;
|
||||||
|
|
||||||
|
bool processArgs(const Strings & args, bool finish) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A helper class for registering commands globally. */
|
||||||
|
struct RegisterCommand
|
||||||
|
{
|
||||||
|
static Commands * commands;
|
||||||
|
|
||||||
|
RegisterCommand(ref<Command> command)
|
||||||
|
{
|
||||||
|
if (!commands) commands = new Commands;
|
||||||
|
commands->emplace(command->name(), command);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
140
src/nix/hash.cc
Normal file
140
src/nix/hash.cc
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#include "command.hh"
|
||||||
|
#include "hash.hh"
|
||||||
|
#include "legacy.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
|
||||||
|
using namespace nix;
|
||||||
|
|
||||||
|
struct CmdHash : Command
|
||||||
|
{
|
||||||
|
enum Mode { mFile, mPath };
|
||||||
|
Mode mode;
|
||||||
|
bool base32 = false;
|
||||||
|
bool truncate = false;
|
||||||
|
HashType ht = htSHA512;
|
||||||
|
Strings paths;
|
||||||
|
|
||||||
|
CmdHash(Mode mode) : mode(mode)
|
||||||
|
{
|
||||||
|
mkFlag(0, "base32", "print hash in base-32", &base32);
|
||||||
|
mkFlag(0, "base16", "print hash in base-16", &base32, false);
|
||||||
|
mkHashTypeFlag("type", &ht);
|
||||||
|
expectArgs("paths", &paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name() override
|
||||||
|
{
|
||||||
|
return mode == mFile ? "hash-file" : "hash-path";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() override
|
||||||
|
{
|
||||||
|
return mode == mFile
|
||||||
|
? "print cryptographic hash of a regular file"
|
||||||
|
: "print cryptographic hash of the NAR serialisation of a path";
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
for (auto path : paths) {
|
||||||
|
Hash h = mode == mFile ? hashFile(ht, path) : hashPath(ht, path).first;
|
||||||
|
if (truncate && h.hashSize > 20) h = compressHash(h, 20);
|
||||||
|
std::cout << format("%1%\n") %
|
||||||
|
(base32 ? printHash32(h) : printHash(h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static RegisterCommand r1(make_ref<Command, CmdHash>(CmdHash::mFile));
|
||||||
|
static RegisterCommand r2(make_ref<Command, CmdHash>(CmdHash::mPath));
|
||||||
|
|
||||||
|
struct CmdToBase : Command
|
||||||
|
{
|
||||||
|
bool toBase32;
|
||||||
|
HashType ht = htSHA512;
|
||||||
|
Strings args;
|
||||||
|
|
||||||
|
CmdToBase(bool toBase32) : toBase32(toBase32)
|
||||||
|
{
|
||||||
|
mkHashTypeFlag("type", &ht);
|
||||||
|
expectArgs("strings", &args);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name() override
|
||||||
|
{
|
||||||
|
return toBase32 ? "to-base32" : "to-base16";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string description() override
|
||||||
|
{
|
||||||
|
return toBase32
|
||||||
|
? "convert a hash to base-32 representation"
|
||||||
|
: "convert a hash to base-32 representation";
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
for (auto s : args) {
|
||||||
|
Hash h = parseHash16or32(ht, s);
|
||||||
|
std::cout << format("%1%\n") %
|
||||||
|
(toBase32 ? printHash32(h) : printHash(h));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static RegisterCommand r3(make_ref<Command, CmdToBase>(false));
|
||||||
|
static RegisterCommand r4(make_ref<Command, CmdToBase>(true));
|
||||||
|
|
||||||
|
/* Legacy nix-hash command. */
|
||||||
|
static int compatNixHash(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
HashType ht = htMD5;
|
||||||
|
bool flat = false;
|
||||||
|
bool base32 = false;
|
||||||
|
bool truncate = false;
|
||||||
|
enum { opHash, opTo32, opTo16 } op = opHash;
|
||||||
|
Strings ss;
|
||||||
|
|
||||||
|
parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) {
|
||||||
|
if (*arg == "--help")
|
||||||
|
showManPage("nix-hash");
|
||||||
|
else if (*arg == "--version")
|
||||||
|
printVersion("nix-hash");
|
||||||
|
else if (*arg == "--flat") flat = true;
|
||||||
|
else if (*arg == "--base32") base32 = true;
|
||||||
|
else if (*arg == "--truncate") truncate = true;
|
||||||
|
else if (*arg == "--type") {
|
||||||
|
string s = getArg(*arg, arg, end);
|
||||||
|
ht = parseHashType(s);
|
||||||
|
if (ht == htUnknown)
|
||||||
|
throw UsageError(format("unknown hash type ‘%1%’") % s);
|
||||||
|
}
|
||||||
|
else if (*arg == "--to-base16") op = opTo16;
|
||||||
|
else if (*arg == "--to-base32") op = opTo32;
|
||||||
|
else if (*arg != "" && arg->at(0) == '-')
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
ss.push_back(*arg);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (op == opHash) {
|
||||||
|
CmdHash cmd(flat ? CmdHash::mFile : CmdHash::mPath);
|
||||||
|
cmd.ht = ht;
|
||||||
|
cmd.base32 = base32;
|
||||||
|
cmd.truncate = truncate;
|
||||||
|
cmd.paths = ss;
|
||||||
|
cmd.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
CmdToBase cmd(op == opTo32);
|
||||||
|
cmd.args = ss;
|
||||||
|
cmd.ht = ht;
|
||||||
|
cmd.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegisterLegacyCommand s1("nix-hash", compatNixHash);
|
7
src/nix/legacy.cc
Normal file
7
src/nix/legacy.cc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#include "legacy.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
RegisterLegacyCommand::Commands * RegisterLegacyCommand::commands = 0;
|
||||||
|
|
||||||
|
}
|
22
src/nix/legacy.hh
Normal file
22
src/nix/legacy.hh
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
typedef std::function<void(int, char * *)> MainFunction;
|
||||||
|
|
||||||
|
struct RegisterLegacyCommand
|
||||||
|
{
|
||||||
|
typedef std::map<std::string, MainFunction> Commands;
|
||||||
|
static Commands * commands;
|
||||||
|
|
||||||
|
RegisterLegacyCommand(const std::string & name, MainFunction fun)
|
||||||
|
{
|
||||||
|
if (!commands) commands = new Commands;
|
||||||
|
(*commands)[name] = fun;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
9
src/nix/local.mk
Normal file
9
src/nix/local.mk
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
programs += nix
|
||||||
|
|
||||||
|
nix_DIR := $(d)
|
||||||
|
|
||||||
|
nix_SOURCES := $(wildcard $(d)/*.cc)
|
||||||
|
|
||||||
|
nix_LIBS = libexpr libmain libstore libutil libformat
|
||||||
|
|
||||||
|
$(eval $(call install-symlink, nix, $(bindir)/nix-hash))
|
55
src/nix/main.cc
Normal file
55
src/nix/main.cc
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "command.hh"
|
||||||
|
#include "common-args.hh"
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "legacy.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
struct NixArgs : virtual MultiCommand, virtual MixCommonArgs
|
||||||
|
{
|
||||||
|
NixArgs() : MultiCommand(*RegisterCommand::commands), MixCommonArgs("nix")
|
||||||
|
{
|
||||||
|
mkFlag('h', "help", "show usage information", [=]() {
|
||||||
|
printHelp(programName, std::cout);
|
||||||
|
throw Exit();
|
||||||
|
});
|
||||||
|
|
||||||
|
mkFlag(0, "version", "show version information", std::bind(printVersion, programName));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void mainWrapped(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
initNix();
|
||||||
|
initGC();
|
||||||
|
|
||||||
|
string programName = baseNameOf(argv[0]);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto legacy = (*RegisterLegacyCommand::commands)[programName];
|
||||||
|
if (legacy) return legacy(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
NixArgs args;
|
||||||
|
|
||||||
|
args.parseCmdline(argvToStrings(argc, argv));
|
||||||
|
|
||||||
|
assert(args.command);
|
||||||
|
|
||||||
|
args.command->prepare();
|
||||||
|
args.command->run();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
return nix::handleExceptions(argv[0], [&]() {
|
||||||
|
nix::mainWrapped(argc, argv);
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in a new issue