Start of new Nix command-line interface
This commit is contained in:
parent
0db9e6cd1a
commit
cd2196b089
14 changed files with 362 additions and 74 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -73,9 +73,6 @@ Makefile.config
|
|||
# /src/nix-env/
|
||||
/src/nix-env/nix-env
|
||||
|
||||
# /src/nix-hash/
|
||||
/src/nix-hash/nix-hash
|
||||
|
||||
# /src/nix-instantiate/
|
||||
/src/nix-instantiate/nix-instantiate
|
||||
|
||||
|
|
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ makefiles = \
|
|||
src/libstore/local.mk \
|
||||
src/libmain/local.mk \
|
||||
src/libexpr/local.mk \
|
||||
src/nix-hash/local.mk \
|
||||
src/nix/local.mk \
|
||||
src/nix-store/local.mk \
|
||||
src/nix-instantiate/local.mk \
|
||||
src/nix-env/local.mk \
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
namespace nix {
|
||||
|
||||
MixCommonArgs::MixCommonArgs(const string & programName)
|
||||
: programName(programName)
|
||||
{
|
||||
mkFlag('v', "verbose", "increase verbosity level", []() {
|
||||
verbosity = (Verbosity) (verbosity + 1);
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace nix {
|
|||
|
||||
struct MixCommonArgs : virtual Args
|
||||
{
|
||||
string programName;
|
||||
MixCommonArgs(const string & programName);
|
||||
};
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ public:
|
|||
*dest = ss;
|
||||
}});
|
||||
}
|
||||
|
||||
friend class MultiCommand;
|
||||
};
|
||||
|
||||
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