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…
	
	Add table
		Add a link
		
	
		Reference in a new issue