From e90569905ecdfe3225314f0e5f122263aa68efb2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 2 Sep 2013 15:18:15 +0200 Subject: [PATCH 01/70] Initial version of nix-repl This program interactively reads a Nix expression from the user, evaluates it, and prints the result. --- default.nix | 10 ++++++++++ nix-repl.cc | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 default.nix create mode 100644 nix-repl.cc diff --git a/default.nix b/default.nix new file mode 100644 index 000000000..55c9ed9e3 --- /dev/null +++ b/default.nix @@ -0,0 +1,10 @@ +with import { }; + +runCommand "nix-repl" + { buildInputs = [ readline nixUnstable boehmgc ]; } + '' + mkdir -p $out/bin + g++ -O3 -Wall -o $out/bin/nix-repl ${./nix-repl.cc} \ + -I${nixUnstable}/include/nix -L${nixUnstable}/lib/nix \ + -lexpr -lmain -lreadline + '' diff --git a/nix-repl.cc b/nix-repl.cc new file mode 100644 index 000000000..ea248b5ca --- /dev/null +++ b/nix-repl.cc @@ -0,0 +1,57 @@ +#include +#include + +#include +#include + +#include "shared.hh" +#include "eval.hh" + +using namespace std; +using namespace nix; + + +string programId = "nix-repl"; + + +void printHelp() +{ + std::cout << "Usage: nix-repl\n"; +} + + +bool getLine(string & line) +{ + char * s = readline ("nix-repl> "); + if (!s) return false; + line = chomp(string(s)); + free(s); + if (line != "") add_history(line.c_str()); + return true; +} + + +void run(nix::Strings args) +{ + EvalState state; + Path curDir = absPath("."); + + while (true) { + string line; + if (!getLine(line)) break; + + try { + Expr * e = state.parseExprFromString(line, curDir); + Value v; + state.eval(e, v); + state.strictForceValue(v); + std::cout << v << std::endl; + } catch (Error & e) { + printMsg(lvlError, e.msg()); + } + + std::cout << std::endl; + } + + std::cout << std::endl; +} From 287c88ca59c5eae2b33874acc6271ca30b7b7e52 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 2 Sep 2013 17:53:58 +0200 Subject: [PATCH 02/70] Support adding variables to the scope The command ":a " evaluates and adds the attributes in the resulting attribute set to the interpreter scope. For instance: nix-repl> :a import {} nix-repl> lib.range 0 10 [ 0 1 2 3 4 5 6 7 8 9 10 ] --- nix-repl.cc | 95 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index ea248b5ca..10e91ec53 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -6,6 +6,8 @@ #include "shared.hh" #include "eval.hh" +#include "eval-inline.hh" +#include "store-api.hh" using namespace std; using namespace nix; @@ -14,6 +16,23 @@ using namespace nix; string programId = "nix-repl"; +struct NixRepl +{ + string curDir; + EvalState state; + + StaticEnv staticEnv; + Env * env; + int displ; + + NixRepl(); + void mainLoop(); + void processLine(string line); + void addVar(const Symbol & name, Value * v); + Expr * parseString(string s); +}; + + void printHelp() { std::cout << "Usage: nix-repl\n"; @@ -22,7 +41,7 @@ void printHelp() bool getLine(string & line) { - char * s = readline ("nix-repl> "); + char * s = readline("nix-repl> "); if (!s) return false; line = chomp(string(s)); free(s); @@ -31,21 +50,33 @@ bool getLine(string & line) } -void run(nix::Strings args) +NixRepl::NixRepl() + : staticEnv(false, &state.staticBaseEnv) { - EvalState state; - Path curDir = absPath("."); + curDir = absPath("."); + + env = &state.allocEnv(32768); + env->up = &state.baseEnv; + displ = 0; + + store = openStore(); +} + + +void NixRepl::mainLoop() +{ + std::cerr << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; while (true) { string line; if (!getLine(line)) break; + /* Remove preceeding whitespace. */ + size_t n = line.find_first_not_of(" \n\r\t"); + if (n != string::npos) line = string(line, n); + try { - Expr * e = state.parseExprFromString(line, curDir); - Value v; - state.eval(e, v); - state.strictForceValue(v); - std::cout << v << std::endl; + processLine(line); } catch (Error & e) { printMsg(lvlError, e.msg()); } @@ -55,3 +86,49 @@ void run(nix::Strings args) std::cout << std::endl; } + + +void NixRepl::processLine(string line) +{ + if (string(line, 0, 2) == ":a") { + Expr * e = parseString(string(line, 2)); + Value v; + e->eval(state, *env, v); + state.forceAttrs(v); + foreach (Bindings::iterator, i, *v.attrs) + addVar(i->name, i->value); + } + + else if (string(line, 0, 1) == ":") { + throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); + } + + else { + Expr * e = parseString(line); + Value v; + e->eval(state, *env, v); + state.strictForceValue(v); + std::cout << v << std::endl; + } +} + + +void NixRepl::addVar(const Symbol & name, Value * v) +{ + staticEnv.vars[name] = displ; + env->values[displ++] = v; +} + + +Expr * NixRepl::parseString(string s) +{ + Expr * e = state.parseExprFromString(s, curDir, staticEnv); + return e; +} + + +void run(nix::Strings args) +{ + NixRepl repl; + repl.mainLoop(); +} From 3202206d1d906ea6279dadfe608ea92ea0aaf927 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 2 Sep 2013 16:00:48 +0000 Subject: [PATCH 03/70] Add a command :t for showing the type of an expression --- nix-repl.cc | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 10e91ec53..9858a034d 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -30,6 +30,7 @@ struct NixRepl void processLine(string line); void addVar(const Symbol & name, Value * v); Expr * parseString(string s); + void evalString(string s, Value & v); }; @@ -91,22 +92,26 @@ void NixRepl::mainLoop() void NixRepl::processLine(string line) { if (string(line, 0, 2) == ":a") { - Expr * e = parseString(string(line, 2)); Value v; - e->eval(state, *env, v); + evalString(string(line, 2), v); state.forceAttrs(v); foreach (Bindings::iterator, i, *v.attrs) addVar(i->name, i->value); } + else if (string(line, 0, 2) == ":t") { + Value v; + evalString(string(line, 2), v); + std::cout << showType(v) << std::endl; + } + else if (string(line, 0, 1) == ":") { throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); } else { - Expr * e = parseString(line); Value v; - e->eval(state, *env, v); + evalString(line, v); state.strictForceValue(v); std::cout << v << std::endl; } @@ -127,6 +132,14 @@ Expr * NixRepl::parseString(string s) } +void NixRepl::evalString(string s, Value & v) +{ + Expr * e = parseString(s); + e->eval(state, *env, v); + state.forceValue(v); +} + + void run(nix::Strings args) { NixRepl repl; From 0f6279d87421f19cd2c1e286163d7567f13dc77f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 2 Sep 2013 18:18:27 +0200 Subject: [PATCH 04/70] Add a command :l for loading a file into scope Example: nix-repl> :l nix-repl> lib.range 0 10 [ 0 1 2 3 4 5 6 7 8 9 10 ] nix-repl> :l nix-repl> config.boot.kernelModules [ "vboxdrv" "vboxnetadp" ... ] --- nix-repl.cc | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 9858a034d..0b8483449 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -8,6 +8,7 @@ #include "eval.hh" #include "eval-inline.hh" #include "store-api.hh" +#include "common-opts.hh" using namespace std; using namespace nix; @@ -28,7 +29,8 @@ struct NixRepl NixRepl(); void mainLoop(); void processLine(string line); - void addVar(const Symbol & name, Value * v); + void addAttrsToScope(Value & attrs); + void addVarToScope(const Symbol & name, Value * v); Expr * parseString(string s); void evalString(string s, Value & v); }; @@ -51,6 +53,15 @@ bool getLine(string & line) } +string removeWhitespace(string s) +{ + s = chomp(s); + size_t n = s.find_first_not_of(" \n\r\t"); + if (n != string::npos) s = string(s, n); + return s; +} + + NixRepl::NixRepl() : staticEnv(false, &state.staticBaseEnv) { @@ -72,12 +83,8 @@ void NixRepl::mainLoop() string line; if (!getLine(line)) break; - /* Remove preceeding whitespace. */ - size_t n = line.find_first_not_of(" \n\r\t"); - if (n != string::npos) line = string(line, n); - try { - processLine(line); + processLine(removeWhitespace(line)); } catch (Error & e) { printMsg(lvlError, e.msg()); } @@ -94,9 +101,17 @@ void NixRepl::processLine(string line) if (string(line, 0, 2) == ":a") { Value v; evalString(string(line, 2), v); - state.forceAttrs(v); - foreach (Bindings::iterator, i, *v.attrs) - addVar(i->name, i->value); + addAttrsToScope(v); + } + + else if (string(line, 0, 2) == ":l") { + state.resetFileCache(); + Path path = lookupFileArg(state, removeWhitespace(string(line, 2))); + Value v, v2; + state.evalFile(path, v); + Bindings bindings; + state.autoCallFunction(bindings, v, v2); + addAttrsToScope(v2); } else if (string(line, 0, 2) == ":t") { @@ -118,7 +133,15 @@ void NixRepl::processLine(string line) } -void NixRepl::addVar(const Symbol & name, Value * v) +void NixRepl::addAttrsToScope(Value & attrs) +{ + state.forceAttrs(attrs); + foreach (Bindings::iterator, i, *attrs.attrs) + addVarToScope(i->name, i->value); +} + + +void NixRepl::addVarToScope(const Symbol & name, Value * v) { staticEnv.vars[name] = displ; env->values[displ++] = v; From 504563ea4431f765028dc0ccacd5ee834d0d8a91 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 11:54:49 +0200 Subject: [PATCH 05/70] Fix build --- default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.nix b/default.nix index 55c9ed9e3..635ead71e 100644 --- a/default.nix +++ b/default.nix @@ -6,5 +6,5 @@ runCommand "nix-repl" mkdir -p $out/bin g++ -O3 -Wall -o $out/bin/nix-repl ${./nix-repl.cc} \ -I${nixUnstable}/include/nix -L${nixUnstable}/lib/nix \ - -lexpr -lmain -lreadline + -lexpr -lmain -lreadline -lgc '' From 4fb82d3d800be9a53631c3c8a3321a359306d835 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 13:01:02 +0200 Subject: [PATCH 06/70] Handle SIGINT to cancel the current line --- nix-repl.cc | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 0b8483449..bb2052117 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -1,6 +1,8 @@ #include #include +#include + #include #include @@ -42,13 +44,41 @@ void printHelp() } +/* Apparently, the only way to get readline() to return on Ctrl-C + (SIGINT) is to use siglongjmp(). That's fucked up... */ +static sigjmp_buf sigintJmpBuf; + + +static void sigintHandler(int signo) +{ + siglongjmp(sigintJmpBuf, 1); +} + + bool getLine(string & line) { - char * s = readline("nix-repl> "); - if (!s) return false; - line = chomp(string(s)); - free(s); - if (line != "") add_history(line.c_str()); + struct sigaction act, old; + act.sa_handler = sigintHandler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGINT, &act, &old)) + throw SysError("installing handler for SIGINT"); + + if (sigsetjmp(sigintJmpBuf, 1)) + line = ""; + else { + char * s = readline("nix-repl> "); + if (!s) return false; + line = chomp(string(s)); + free(s); + if (line != "") add_history(line.c_str()); + } + + _isInterrupted = 0; + + if (sigaction(SIGINT, &old, 0)) + throw SysError("restoring handler for SIGINT"); + return true; } @@ -98,6 +128,8 @@ void NixRepl::mainLoop() void NixRepl::processLine(string line) { + if (line == "") return; + if (string(line, 0, 2) == ":a") { Value v; evalString(string(line, 2), v); From 0b419c048b206e2fe68758ea1bd5fa7b1c29c521 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 13:14:28 +0200 Subject: [PATCH 07/70] Use readline history file --- nix-repl.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index bb2052117..bb18359c1 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -71,7 +71,10 @@ bool getLine(string & line) if (!s) return false; line = chomp(string(s)); free(s); - if (line != "") add_history(line.c_str()); + if (line != "") { + add_history(line.c_str()); + append_history(1, 0); + } } _isInterrupted = 0; @@ -109,6 +112,9 @@ void NixRepl::mainLoop() { std::cerr << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; + using_history(); + read_history(0); + while (true) { string line; if (!getLine(line)) break; From ad0dd359b4434db84bf6458715440cc15f896ddc Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 13:20:35 +0200 Subject: [PATCH 08/70] Don't exit on SIGINT during evaluation However, this may leave thunks in black-holed state, so it's not really safe. --- nix-repl.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nix-repl.cc b/nix-repl.cc index bb18359c1..45d743339 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -123,6 +123,8 @@ void NixRepl::mainLoop() processLine(removeWhitespace(line)); } catch (Error & e) { printMsg(lvlError, e.msg()); + } catch (Interrupted & e) { + printMsg(lvlError, e.msg()); } std::cout << std::endl; @@ -176,6 +178,7 @@ void NixRepl::addAttrsToScope(Value & attrs) state.forceAttrs(attrs); foreach (Bindings::iterator, i, *attrs.attrs) addVarToScope(i->name, i->value); + printMsg(lvlError, format("added %1% variables") % attrs.attrs->size()); } From c6712a007fc55398893995a3466d35ae0697db05 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 14:58:53 +0200 Subject: [PATCH 09/70] Add a command :b to build a derivation --- nix-repl.cc | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 45d743339..f41cf4d29 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -11,6 +11,8 @@ #include "eval-inline.hh" #include "store-api.hh" #include "common-opts.hh" +#include "get-drvs.hh" +#include "derivations.hh" using namespace std; using namespace nix; @@ -122,9 +124,9 @@ void NixRepl::mainLoop() try { processLine(removeWhitespace(line)); } catch (Error & e) { - printMsg(lvlError, e.msg()); + printMsg(lvlError, "error: " + e.msg()); } catch (Interrupted & e) { - printMsg(lvlError, e.msg()); + printMsg(lvlError, "error: " + e.msg()); } std::cout << std::endl; @@ -160,10 +162,29 @@ void NixRepl::processLine(string line) std::cout << showType(v) << std::endl; } - else if (string(line, 0, 1) == ":") { - throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); + else if (string(line, 0, 2) == ":b") { + Value v; + evalString(string(line, 2), v); + DrvInfo drvInfo; + if (!getDerivation(state, v, drvInfo, false)) + throw Error("expression does not evaluation to a derivation, so I can't build it"); + Path drvPath = drvInfo.queryDrvPath(state); + if (drvPath == "" || !store->isValidPath(drvPath)) + throw Error("expression did not evaluate to a valid derivation"); + /* We could do the build in this process using buildPaths(), + but doing it in a child makes it easier to recover from + problems / SIGINT. */ + if (system(("nix-store -r " + drvPath + " > /dev/null").c_str()) == -1) + throw SysError("starting nix-store"); + Derivation drv = parseDerivation(readFile(drvPath)); + std::cout << "this derivation produced the following outputs:" << std::endl; + foreach (DerivationOutputs::iterator, i, drv.outputs) + std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; } + else if (string(line, 0, 1) == ":") + throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); + else { Value v; evalString(line, v); @@ -178,7 +199,7 @@ void NixRepl::addAttrsToScope(Value & attrs) state.forceAttrs(attrs); foreach (Bindings::iterator, i, *attrs.attrs) addVarToScope(i->name, i->value); - printMsg(lvlError, format("added %1% variables") % attrs.attrs->size()); + std::cout << format("added %1% variables") % attrs.attrs->size() << std::endl; } From b5944ac4ffffde7f52d0bbe3f4a2d53bba70bb66 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 15:05:18 +0200 Subject: [PATCH 10/70] Add a command :s to start a nix-shell for a derivation --- nix-repl.cc | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index f41cf4d29..838928b35 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -140,13 +140,15 @@ void NixRepl::processLine(string line) { if (line == "") return; - if (string(line, 0, 2) == ":a") { + string command = string(line, 0, 2); + + if (command == ":a") { Value v; evalString(string(line, 2), v); addAttrsToScope(v); } - else if (string(line, 0, 2) == ":l") { + else if (command == ":l") { state.resetFileCache(); Path path = lookupFileArg(state, removeWhitespace(string(line, 2))); Value v, v2; @@ -156,13 +158,13 @@ void NixRepl::processLine(string line) addAttrsToScope(v2); } - else if (string(line, 0, 2) == ":t") { + else if (command == ":t") { Value v; evalString(string(line, 2), v); std::cout << showType(v) << std::endl; } - else if (string(line, 0, 2) == ":b") { + else if (command == ":b" || command == ":s") { Value v; evalString(string(line, 2), v); DrvInfo drvInfo; @@ -171,15 +173,21 @@ void NixRepl::processLine(string line) Path drvPath = drvInfo.queryDrvPath(state); if (drvPath == "" || !store->isValidPath(drvPath)) throw Error("expression did not evaluate to a valid derivation"); - /* We could do the build in this process using buildPaths(), - but doing it in a child makes it easier to recover from - problems / SIGINT. */ - if (system(("nix-store -r " + drvPath + " > /dev/null").c_str()) == -1) - throw SysError("starting nix-store"); - Derivation drv = parseDerivation(readFile(drvPath)); - std::cout << "this derivation produced the following outputs:" << std::endl; - foreach (DerivationOutputs::iterator, i, drv.outputs) - std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; + + if (command == ":b") { + /* We could do the build in this process using buildPaths(), + but doing it in a child makes it easier to recover from + problems / SIGINT. */ + if (system(("nix-store -r " + drvPath + " > /dev/null").c_str()) == -1) + throw SysError("starting nix-store"); + Derivation drv = parseDerivation(readFile(drvPath)); + std::cout << "this derivation produced the following outputs:" << std::endl; + foreach (DerivationOutputs::iterator, i, drv.outputs) + std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; + } else { + if (system(("nix-shell " + drvPath).c_str()) == -1) + throw SysError("starting nix-shell"); + } } else if (string(line, 0, 1) == ":") From cf4c29d90a1b0ec7f8cd7f0c5258be63a2e02058 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 15:20:06 +0200 Subject: [PATCH 11/70] Load files specified on the command line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example: $ nix-repl '' '' Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. Loading ‘’... Added 3337 variables. Loading ‘’... Added 7 variables. nix-repl> --- nix-repl.cc | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 838928b35..2ef23faa5 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -31,8 +31,9 @@ struct NixRepl int displ; NixRepl(); - void mainLoop(); + void mainLoop(const Strings & args); void processLine(string line); + void loadFile(const Path & path); void addAttrsToScope(Value & attrs); void addVarToScope(const Symbol & name, Value * v); Expr * parseString(string s); @@ -110,9 +111,15 @@ NixRepl::NixRepl() } -void NixRepl::mainLoop() +void NixRepl::mainLoop(const Strings & args) { - std::cerr << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; + std::cout << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; + + foreach (Strings::const_iterator, i, args) { + std::cout << format("Loading ‘%1%’...") % *i << std::endl; + loadFile(*i); + std::cout << std::endl; + } using_history(); read_history(0); @@ -150,12 +157,7 @@ void NixRepl::processLine(string line) else if (command == ":l") { state.resetFileCache(); - Path path = lookupFileArg(state, removeWhitespace(string(line, 2))); - Value v, v2; - state.evalFile(path, v); - Bindings bindings; - state.autoCallFunction(bindings, v, v2); - addAttrsToScope(v2); + loadFile(removeWhitespace(string(line, 2))); } else if (command == ":t") { @@ -202,12 +204,22 @@ void NixRepl::processLine(string line) } +void NixRepl::loadFile(const Path & path) +{ + Value v, v2; + state.evalFile(lookupFileArg(state, path), v); + Bindings bindings; + state.autoCallFunction(bindings, v, v2); + addAttrsToScope(v2); +} + + void NixRepl::addAttrsToScope(Value & attrs) { state.forceAttrs(attrs); foreach (Bindings::iterator, i, *attrs.attrs) addVarToScope(i->name, i->value); - std::cout << format("added %1% variables") % attrs.attrs->size() << std::endl; + std::cout << format("Added %1% variables.") % attrs.attrs->size() << std::endl; } @@ -233,8 +245,8 @@ void NixRepl::evalString(string s, Value & v) } -void run(nix::Strings args) +void run(Strings args) { NixRepl repl; - repl.mainLoop(); + repl.mainLoop(args); } From 0abdf4beaaa64c01ed3cfb4cc5fd78997116fac8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 19:51:59 +0200 Subject: [PATCH 12/70] Add basic variable name completion --- nix-repl.cc | 129 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 87 insertions(+), 42 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 2ef23faa5..f85eac124 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -29,9 +29,15 @@ struct NixRepl StaticEnv staticEnv; Env * env; int displ; + StringSet varNames; + + StringSet completions; + StringSet::iterator curCompletion; NixRepl(); void mainLoop(const Strings & args); + void completePrefix(string prefix); + bool getLine(string & line); void processLine(string line); void loadFile(const Path & path); void addAttrsToScope(Value & attrs); @@ -47,48 +53,6 @@ void printHelp() } -/* Apparently, the only way to get readline() to return on Ctrl-C - (SIGINT) is to use siglongjmp(). That's fucked up... */ -static sigjmp_buf sigintJmpBuf; - - -static void sigintHandler(int signo) -{ - siglongjmp(sigintJmpBuf, 1); -} - - -bool getLine(string & line) -{ - struct sigaction act, old; - act.sa_handler = sigintHandler; - sigfillset(&act.sa_mask); - act.sa_flags = 0; - if (sigaction(SIGINT, &act, &old)) - throw SysError("installing handler for SIGINT"); - - if (sigsetjmp(sigintJmpBuf, 1)) - line = ""; - else { - char * s = readline("nix-repl> "); - if (!s) return false; - line = chomp(string(s)); - free(s); - if (line != "") { - add_history(line.c_str()); - append_history(1, 0); - } - } - - _isInterrupted = 0; - - if (sigaction(SIGINT, &old, 0)) - throw SysError("restoring handler for SIGINT"); - - return true; -} - - string removeWhitespace(string s) { s = chomp(s); @@ -143,6 +107,86 @@ void NixRepl::mainLoop(const Strings & args) } +/* Apparently, the only way to get readline() to return on Ctrl-C + (SIGINT) is to use siglongjmp(). That's fucked up... */ +static sigjmp_buf sigintJmpBuf; + + +static void sigintHandler(int signo) +{ + siglongjmp(sigintJmpBuf, 1); +} + + +/* Oh, if only g++ had nested functions... */ +NixRepl * curRepl; + +char * completerThunk(const char * s, int state) +{ + string prefix(s); + + /* If the prefix has a slash in it, use readline's builtin filename + completer. */ + if (prefix.find('/') != string::npos) + return rl_filename_completion_function(s, state); + + /* Otherwise, return all symbols that start with the prefix. */ + if (state == 0) { + curRepl->completePrefix(s); + curRepl->curCompletion = curRepl->completions.begin(); + } + if (curRepl->curCompletion == curRepl->completions.end()) return 0; + return strdup((curRepl->curCompletion++)->c_str()); +} + + +bool NixRepl::getLine(string & line) +{ + struct sigaction act, old; + act.sa_handler = sigintHandler; + sigfillset(&act.sa_mask); + act.sa_flags = 0; + if (sigaction(SIGINT, &act, &old)) + throw SysError("installing handler for SIGINT"); + + if (sigsetjmp(sigintJmpBuf, 1)) + line = ""; + else { + curRepl = this; + rl_completion_entry_function = completerThunk; + + char * s = readline("nix-repl> "); + if (!s) return false; + line = chomp(string(s)); + free(s); + if (line != "") { + add_history(line.c_str()); + append_history(1, 0); + } + } + + _isInterrupted = 0; + + if (sigaction(SIGINT, &old, 0)) + throw SysError("restoring handler for SIGINT"); + + return true; +} + + +void NixRepl::completePrefix(string prefix) +{ + completions.clear(); + + StringSet::iterator i = varNames.lower_bound(prefix); + while (i != varNames.end()) { + if (string(*i, 0, prefix.size()) != prefix) break; + completions.insert(*i); + i++; + } +} + + void NixRepl::processLine(string line) { if (line == "") return; @@ -227,6 +271,7 @@ void NixRepl::addVarToScope(const Symbol & name, Value * v) { staticEnv.vars[name] = displ; env->values[displ++] = v; + varNames.insert((string) name); } From c6f2b89c0e3091e5020983c9a02f36b9c33c3f81 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 6 Sep 2013 21:00:36 +0200 Subject: [PATCH 13/70] Restore affinity --- default.nix | 3 ++- nix-repl.cc | 33 ++++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/default.nix b/default.nix index 635ead71e..eae1d56d0 100644 --- a/default.nix +++ b/default.nix @@ -4,7 +4,8 @@ runCommand "nix-repl" { buildInputs = [ readline nixUnstable boehmgc ]; } '' mkdir -p $out/bin - g++ -O3 -Wall -o $out/bin/nix-repl ${./nix-repl.cc} \ + g++ -O3 -Wall -std=c++0x \ + -o $out/bin/nix-repl ${./nix-repl.cc} \ -I${nixUnstable}/include/nix -L${nixUnstable}/lib/nix \ -lexpr -lmain -lreadline -lgc '' diff --git a/nix-repl.cc b/nix-repl.cc index f85eac124..15ac42dcc 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -13,6 +13,7 @@ #include "common-opts.hh" #include "get-drvs.hh" #include "derivations.hh" +#include "affinity.hh" using namespace std; using namespace nix; @@ -187,6 +188,27 @@ void NixRepl::completePrefix(string prefix) } +static int runProgram(const string & program, const Strings & args) +{ + std::vector cargs; /* careful with c_str()! */ + cargs.push_back(program.c_str()); + for (Strings::const_iterator i = args.begin(); i != args.end(); ++i) + cargs.push_back(i->c_str()); + cargs.push_back(0); + + Pid pid; + pid = fork(); + if (pid == -1) throw SysError("forking"); + if (pid == 0) { + restoreAffinity(); + execvp(program.c_str(), (char * *) &cargs[0]); + _exit(1); + } + + return pid.wait(true); +} + + void NixRepl::processLine(string line) { if (line == "") return; @@ -224,16 +246,13 @@ void NixRepl::processLine(string line) /* We could do the build in this process using buildPaths(), but doing it in a child makes it easier to recover from problems / SIGINT. */ - if (system(("nix-store -r " + drvPath + " > /dev/null").c_str()) == -1) - throw SysError("starting nix-store"); + if (runProgram("nix-store", Strings{"-r", drvPath}) != 0) return; Derivation drv = parseDerivation(readFile(drvPath)); - std::cout << "this derivation produced the following outputs:" << std::endl; + std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; foreach (DerivationOutputs::iterator, i, drv.outputs) std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; - } else { - if (system(("nix-shell " + drvPath).c_str()) == -1) - throw SysError("starting nix-shell"); - } + } else + runProgram("nix-shell", Strings{drvPath}); } else if (string(line, 0, 1) == ":") From 7e3625f924825db2ffa5e58d4b414d93d9af2465 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sat, 7 Sep 2013 00:35:54 +0200 Subject: [PATCH 14/70] Improved value display By default, we don't recurse into attribute sets or lists when printing a value. However, the new :p command does recurse. --- nix-repl.cc | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 15ac42dcc..d2179d77a 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -45,6 +45,7 @@ struct NixRepl void addVarToScope(const Symbol & name, Value * v); Expr * parseString(string s); void evalString(string s, Value & v); + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); }; @@ -255,14 +256,19 @@ void NixRepl::processLine(string line) runProgram("nix-shell", Strings{drvPath}); } + else if (command == ":p") { + Value v; + evalString(string(line, 2), v); + printValue(std::cout, v, 1000000000) << std::endl; + } + else if (string(line, 0, 1) == ":") throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); else { Value v; evalString(line, v); - state.strictForceValue(v); - std::cout << v << std::endl; + printValue(std::cout, v, 1) << std::endl; } } @@ -309,6 +315,114 @@ void NixRepl::evalString(string s, Value & v) } +// FIXME: lot of cut&paste from Nix's eval.cc. +std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth) +{ + str.flush(); + checkInterrupt(); + + state.forceValue(v); + + switch (v.type) { + + case tInt: + str << v.integer; + break; + + case tBool: + str << (v.boolean ? "true" : "false"); + break; + + case tString: + str << "\""; + for (const char * i = v.string.s; *i; i++) + if (*i == '\"' || *i == '\\') str << "\\" << *i; + else if (*i == '\n') str << "\\n"; + else if (*i == '\r') str << "\\r"; + else if (*i == '\t') str << "\\t"; + else str << *i; + str << "\""; + break; + + case tPath: + str << v.path; // !!! escaping? + break; + + case tNull: + str << "null"; + break; + + case tAttrs: { + bool isDrv = state.isDerivation(v); + if (isDrv) str << "(derivation "; + str << "{ "; + + if (maxDepth > 0) { + typedef std::map Sorted; + Sorted sorted; + foreach (Bindings::iterator, i, *v.attrs) + sorted[i->name] = i->value; + + /* If this is a derivation, then don't show the + self-references ("all", "out", etc.). */ + StringSet hidden; + if (isDrv) { + hidden.insert("all"); + Bindings::iterator i = v.attrs->find(state.sOutputs); + if (i == v.attrs->end()) + hidden.insert("out"); + else { + state.forceList(*i->value); + for (unsigned int j = 0; j < i->value->list.length; ++j) + hidden.insert(state.forceStringNoCtx(*i->value->list.elems[j])); + } + } + + foreach (Sorted::iterator, i, sorted) + if (hidden.find(i->first) == hidden.end()) + printValue(str << i->first << " = ", *i->second, maxDepth - 1) << "; "; + else + str << i->first << " = ...; "; + + } else + str << "... "; + + str << "}"; + if (isDrv) str << ")"; + break; + } + + case tList: + str << "[ "; + if (maxDepth > 0) + for (unsigned int n = 0; n < v.list.length; ++n) + printValue(str, *v.list.elems[n], maxDepth - 1) << " "; + else + str << "... "; + str << "]"; + break; + + case tLambda: + str << "«lambda»"; + break; + + case tPrimOp: + str << "«primop»"; + break; + + case tPrimOpApp: + str << "«primop-app»"; + break; + + default: + str << "«unknown»"; + break; + } + + return str; +} + + void run(Strings args) { NixRepl repl; From e587aec1235d7834d04d6d9f7997bc010ef99925 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 11:14:43 +0200 Subject: [PATCH 15/70] printValue: Don't show lists/attribute sets twice --- nix-repl.cc | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index d2179d77a..a6e5f78ec 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -45,7 +45,10 @@ struct NixRepl void addVarToScope(const Symbol & name, Value * v); Expr * parseString(string s); void evalString(string s, Value & v); + + typedef set ValuesSeen; std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth); + std::ostream & printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen); }; @@ -315,8 +318,15 @@ void NixRepl::evalString(string s, Value & v) } +std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth) +{ + ValuesSeen seen; + return printValue(str, v, maxDepth, seen); +} + + // FIXME: lot of cut&paste from Nix's eval.cc. -std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth) +std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen) { str.flush(); checkInterrupt(); @@ -353,6 +363,8 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int break; case tAttrs: { + seen.insert(&v); + bool isDrv = state.isDerivation(v); if (isDrv) str << "(derivation "; str << "{ "; @@ -379,10 +391,12 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int } foreach (Sorted::iterator, i, sorted) - if (hidden.find(i->first) == hidden.end()) - printValue(str << i->first << " = ", *i->second, maxDepth - 1) << "; "; + if (hidden.find(i->first) != hidden.end()) + str << i->first << " = «...»; "; + else if (seen.find(i->second) != seen.end()) + str << i->first << " = «repeated»; "; else - str << i->first << " = ...; "; + printValue(str << i->first << " = ", *i->second, maxDepth - 1, seen) << "; "; } else str << "... "; @@ -393,10 +407,16 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int } case tList: + seen.insert(&v); + str << "[ "; if (maxDepth > 0) - for (unsigned int n = 0; n < v.list.length; ++n) - printValue(str, *v.list.elems[n], maxDepth - 1) << " "; + for (unsigned int n = 0; n < v.list.length; ++n) { + if (seen.find(v.list.elems[n]) != seen.end()) + str << "«repeated» "; + else + printValue(str, *v.list.elems[n], maxDepth - 1, seen) << " "; + } else str << "... "; str << "]"; From 8e765b8876ff67879a6bd1a067bad526b14a4045 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 11:34:54 +0200 Subject: [PATCH 16/70] printValue: Show assertion errors inline --- nix-repl.cc | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index a6e5f78ec..f7eb6ab5c 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -390,13 +390,20 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } } - foreach (Sorted::iterator, i, sorted) + foreach (Sorted::iterator, i, sorted) { + str << i->first << " = "; if (hidden.find(i->first) != hidden.end()) - str << i->first << " = «...»; "; + str << "«...»"; else if (seen.find(i->second) != seen.end()) - str << i->first << " = «repeated»; "; + str << "«repeated»"; else - printValue(str << i->first << " = ", *i->second, maxDepth - 1, seen) << "; "; + try { + printValue(str, *i->second, maxDepth - 1, seen); + } catch (AssertionError & e) { + str << "«error: " << e.msg() << "»"; + } + str << "; "; + } } else str << "... "; @@ -413,9 +420,14 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m if (maxDepth > 0) for (unsigned int n = 0; n < v.list.length; ++n) { if (seen.find(v.list.elems[n]) != seen.end()) - str << "«repeated» "; + str << "«repeated»"; else - printValue(str, *v.list.elems[n], maxDepth - 1, seen) << " "; + try { + printValue(str, *v.list.elems[n], maxDepth - 1, seen); + } catch (AssertionError & e) { + str << "«error: " << e.msg() << "»"; + } + str << " "; } else str << "... "; From e133e91410d9486e022a1bc0372b822152b6654e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 12:00:33 +0200 Subject: [PATCH 17/70] Support tab-completion on attribute sets Example: $ nix-repl '' > config.services.xserver.desktop comletes to > config.services.xserver.desktopManager You also get suggestions if there are multiple matches: > config.services.xserver.desktopManager.kde4 config.services.xserver.desktopManager.kde4.enable config.services.xserver.desktopManager.kde4.phononBackends --- nix-repl.cc | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index f7eb6ab5c..9c22abbfa 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -183,11 +183,40 @@ void NixRepl::completePrefix(string prefix) { completions.clear(); - StringSet::iterator i = varNames.lower_bound(prefix); - while (i != varNames.end()) { - if (string(*i, 0, prefix.size()) != prefix) break; - completions.insert(*i); - i++; + size_t dot = prefix.rfind('.'); + + if (dot == string::npos) { + /* This is a variable name; look it up in the current scope. */ + StringSet::iterator i = varNames.lower_bound(prefix); + while (i != varNames.end()) { + if (string(*i, 0, prefix.size()) != prefix) break; + completions.insert(*i); + i++; + } + } else { + try { + /* This is an expression that should evaluate to an + attribute set. Evaluate it to get the names of the + attributes. */ + string expr(prefix, 0, dot); + string prefix2 = string(prefix, dot + 1); + + Expr * e = parseString(expr); + Value v; + e->eval(state, *env, v); + state.forceAttrs(v); + + foreach (Bindings::iterator, i, *v.attrs) { + string name = i->name; + if (string(name, 0, prefix2.size()) != prefix2) continue; + completions.insert(expr + "." + name); + } + + } catch (ParseError & e) { + // Quietly ignore parse errors. + }catch (EvalError & e) { + // Quietly ignore evaluation errors. + } } } From 4b33c2dd4cac95151ca5d99ceb3161fdb460ec0a Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 13:22:33 +0200 Subject: [PATCH 18/70] Add help (:?) --- nix-repl.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 9c22abbfa..72099f46e 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -248,7 +248,19 @@ void NixRepl::processLine(string line) string command = string(line, 0, 2); - if (command == ":a") { + if (command == ":?") { + cout << "The following commands are available:\n" + << "\n" + << " Evaluate and print expression\n" + << " :a Add attributes from resulting set to scope\n" + << " :b Build derivation\n" + << " :l Load Nix expression and add it to scope\n" + << " :p Evaluate and print expression recursively\n" + << " :s Build dependencies of derivation, then start nix-shell\n" + << " :t Describe result of evaluation\n"; + } + + else if (command == ":a") { Value v; evalString(string(line, 2), v); addAttrsToScope(v); From 3c67df928f8d311d7dfd565e8c3a16db9d6a0278 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 13:56:53 +0200 Subject: [PATCH 19/70] Add sugar for defining a variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ‘x = ’ is short for ‘:a { x = ; }’. Note that the right-hand side refers to the original scope, so you get: nix-repl> x = 1 nix-repl> x = x + 1 nix-repl> x 2 rather than an infinite recursion. --- nix-repl.cc | 55 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 72099f46e..bcd80ffc7 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -42,7 +42,7 @@ struct NixRepl void processLine(string line); void loadFile(const Path & path); void addAttrsToScope(Value & attrs); - void addVarToScope(const Symbol & name, Value * v); + void addVarToScope(const Symbol & name, Value & v); Expr * parseString(string s); void evalString(string s, Value & v); @@ -242,6 +242,19 @@ static int runProgram(const string & program, const Strings & args) } +bool isVarName(const string & s) +{ + // FIXME: not quite correct. + foreach (string::const_iterator, i, s) + if (!((*i >= 'a' && *i <= 'z') || + (*i >= 'A' && *i <= 'Z') || + (*i >= '0' && *i <= '9') || + *i == '_' || *i == '\'')) + return false; + return true; +} + + void NixRepl::processLine(string line) { if (line == "") return; @@ -251,13 +264,14 @@ void NixRepl::processLine(string line) if (command == ":?") { cout << "The following commands are available:\n" << "\n" - << " Evaluate and print expression\n" - << " :a Add attributes from resulting set to scope\n" - << " :b Build derivation\n" - << " :l Load Nix expression and add it to scope\n" - << " :p Evaluate and print expression recursively\n" - << " :s Build dependencies of derivation, then start nix-shell\n" - << " :t Describe result of evaluation\n"; + << " Evaluate and print expression\n" + << " = Bind expression to variable\n" + << " :a Add attributes from resulting set to scope\n" + << " :b Build derivation\n" + << " :l Load Nix expression and add it to scope\n" + << " :p Evaluate and print expression recursively\n" + << " :s Build dependencies of derivation, then start nix-shell\n" + << " :t Describe result of evaluation\n"; } else if (command == ":a") { @@ -310,9 +324,22 @@ void NixRepl::processLine(string line) throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); else { - Value v; - evalString(line, v); - printValue(std::cout, v, 1) << std::endl; + size_t p = line.find('='); + string name; + if (p != string::npos && + isVarName(name = removeWhitespace(string(line, 0, p)))) + { + Expr * e = parseString(string(line, p + 1)); + Value & v(*state.allocValue()); + v.type = tThunk; + v.thunk.env = env; + v.thunk.expr = e; + addVarToScope(state.symbols.create(name), v); + } else { + Value v; + evalString(line, v); + printValue(std::cout, v, 1) << std::endl; + } } } @@ -331,15 +358,15 @@ void NixRepl::addAttrsToScope(Value & attrs) { state.forceAttrs(attrs); foreach (Bindings::iterator, i, *attrs.attrs) - addVarToScope(i->name, i->value); + addVarToScope(i->name, *i->value); std::cout << format("Added %1% variables.") % attrs.attrs->size() << std::endl; } -void NixRepl::addVarToScope(const Symbol & name, Value * v) +void NixRepl::addVarToScope(const Symbol & name, Value & v) { staticEnv.vars[name] = displ; - env->values[displ++] = v; + env->values[displ++] = &v; varNames.insert((string) name); } From a5dffb3d3dcfff3b1d6c166451268ebb1cbde991 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 14:03:28 +0200 Subject: [PATCH 20/70] Temporary hack to parameterize nixpkgs --- default.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/default.nix b/default.nix index eae1d56d0..97162c6e8 100644 --- a/default.nix +++ b/default.nix @@ -1,4 +1,6 @@ -with import { }; +{ nixpkgs ? }: + +with import nixpkgs { }; runCommand "nix-repl" { buildInputs = [ readline nixUnstable boehmgc ]; } From 3567bdb514e6ba4e460b76dc1d1b1dd466214286 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 15:02:56 +0200 Subject: [PATCH 21/70] Add :quit command --- nix-repl.cc | 55 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index bcd80ffc7..a4d74055d 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -39,7 +39,7 @@ struct NixRepl void mainLoop(const Strings & args); void completePrefix(string prefix); bool getLine(string & line); - void processLine(string line); + bool processLine(string line); void loadFile(const Path & path); void addAttrsToScope(Value & attrs); void addVarToScope(const Symbol & name, Value & v); @@ -95,10 +95,13 @@ void NixRepl::mainLoop(const Strings & args) while (true) { string line; - if (!getLine(line)) break; + if (!getLine(line)) { + std::cout << std::endl; + break; + } try { - processLine(removeWhitespace(line)); + if (!processLine(removeWhitespace(line))) return; } catch (Error & e) { printMsg(lvlError, "error: " + e.msg()); } catch (Interrupted & e) { @@ -108,7 +111,6 @@ void NixRepl::mainLoop(const Strings & args) std::cout << std::endl; } - std::cout << std::endl; } @@ -255,11 +257,19 @@ bool isVarName(const string & s) } -void NixRepl::processLine(string line) +bool NixRepl::processLine(string line) { - if (line == "") return; + if (line == "") return true; - string command = string(line, 0, 2); + string command, arg; + + if (line[0] == ':') { + size_t p = line.find(' '); + command = string(line, 0, p); + if (p != string::npos) arg = removeWhitespace(string(line, p)); + } else { + arg = line; + } if (command == ":?") { cout << "The following commands are available:\n" @@ -270,30 +280,31 @@ void NixRepl::processLine(string line) << " :b Build derivation\n" << " :l Load Nix expression and add it to scope\n" << " :p Evaluate and print expression recursively\n" + << " :q Exit nix-repl\n" << " :s Build dependencies of derivation, then start nix-shell\n" << " :t Describe result of evaluation\n"; } else if (command == ":a") { Value v; - evalString(string(line, 2), v); + evalString(arg, v); addAttrsToScope(v); } else if (command == ":l") { state.resetFileCache(); - loadFile(removeWhitespace(string(line, 2))); + loadFile(arg); } else if (command == ":t") { Value v; - evalString(string(line, 2), v); + evalString(arg, v); std::cout << showType(v) << std::endl; } else if (command == ":b" || command == ":s") { Value v; - evalString(string(line, 2), v); + evalString(arg, v); DrvInfo drvInfo; if (!getDerivation(state, v, drvInfo, false)) throw Error("expression does not evaluation to a derivation, so I can't build it"); @@ -305,23 +316,27 @@ void NixRepl::processLine(string line) /* We could do the build in this process using buildPaths(), but doing it in a child makes it easier to recover from problems / SIGINT. */ - if (runProgram("nix-store", Strings{"-r", drvPath}) != 0) return; - Derivation drv = parseDerivation(readFile(drvPath)); - std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; - foreach (DerivationOutputs::iterator, i, drv.outputs) - std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; + if (runProgram("nix-store", Strings{"-r", drvPath}) == 0) { + Derivation drv = parseDerivation(readFile(drvPath)); + std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; + foreach (DerivationOutputs::iterator, i, drv.outputs) + std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; + } } else runProgram("nix-shell", Strings{drvPath}); } else if (command == ":p") { Value v; - evalString(string(line, 2), v); + evalString(arg, v); printValue(std::cout, v, 1000000000) << std::endl; } - else if (string(line, 0, 1) == ":") - throw Error(format("unknown command ‘%1%’") % string(line, 0, 2)); + else if (command == ":q" || command == ":quit") + return false; + + else if (command != "") + throw Error(format("unknown command ‘%1%’") % command); else { size_t p = line.find('='); @@ -341,6 +356,8 @@ void NixRepl::processLine(string line) printValue(std::cout, v, 1) << std::endl; } } + + return true; } From 03ef6b69be4711309fa04fa32681e03fde3d234f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 15:17:08 +0200 Subject: [PATCH 22/70] Add system argument --- default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default.nix b/default.nix index 97162c6e8..4c9cbcc0c 100644 --- a/default.nix +++ b/default.nix @@ -1,6 +1,6 @@ -{ nixpkgs ? }: +{ nixpkgs ? , system ? builtins.currentSystem }: -with import nixpkgs { }; +with import nixpkgs { inherit system; }; runCommand "nix-repl" { buildInputs = [ readline nixUnstable boehmgc ]; } From ddd22c37c58aa9d39a632c746a0617f6602d1815 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 16:02:35 +0200 Subject: [PATCH 23/70] Build on Mac OS X --- default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.nix b/default.nix index 4c9cbcc0c..c4a967bf5 100644 --- a/default.nix +++ b/default.nix @@ -9,5 +9,5 @@ runCommand "nix-repl" g++ -O3 -Wall -std=c++0x \ -o $out/bin/nix-repl ${./nix-repl.cc} \ -I${nixUnstable}/include/nix -L${nixUnstable}/lib/nix \ - -lexpr -lmain -lreadline -lgc + -lformat -lutil -lstore -lexpr -lmain -lreadline -lgc '' From adde4f0c8d720b9c9c43f6d0a2e789d7c68798bd Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 16:02:46 +0200 Subject: [PATCH 24/70] Add :reload command --- nix-repl.cc | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index a4d74055d..c0ba3a588 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -27,6 +27,8 @@ struct NixRepl string curDir; EvalState state; + Strings loadedFiles; + StaticEnv staticEnv; Env * env; int displ; @@ -41,6 +43,7 @@ struct NixRepl bool getLine(string & line); bool processLine(string line); void loadFile(const Path & path); + void reloadFiles(); void addAttrsToScope(Value & attrs); void addVarToScope(const Symbol & name, Value & v); Expr * parseString(string s); @@ -84,9 +87,11 @@ void NixRepl::mainLoop(const Strings & args) { std::cout << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; - foreach (Strings::const_iterator, i, args) { - std::cout << format("Loading ‘%1%’...") % *i << std::endl; - loadFile(*i); + foreach (Strings::const_iterator, i, args) + loadedFiles.push_back(*i); + + if (!loadedFiles.empty()) { + reloadFiles(); std::cout << std::endl; } @@ -110,7 +115,6 @@ void NixRepl::mainLoop(const Strings & args) std::cout << std::endl; } - } @@ -271,7 +275,7 @@ bool NixRepl::processLine(string line) arg = line; } - if (command == ":?") { + if (command == ":?" || command == ":help") { cout << "The following commands are available:\n" << "\n" << " Evaluate and print expression\n" @@ -281,21 +285,27 @@ bool NixRepl::processLine(string line) << " :l Load Nix expression and add it to scope\n" << " :p Evaluate and print expression recursively\n" << " :q Exit nix-repl\n" + << " :r Reload all files\n" << " :s Build dependencies of derivation, then start nix-shell\n" << " :t Describe result of evaluation\n"; } - else if (command == ":a") { + else if (command == ":a" || command == ":add") { Value v; evalString(arg, v); addAttrsToScope(v); } - else if (command == ":l") { + else if (command == ":l" || command == ":load") { state.resetFileCache(); loadFile(arg); } + else if (command == ":r" || command == ":reload") { + state.resetFileCache(); + reloadFiles(); + } + else if (command == ":t") { Value v; evalString(arg, v); @@ -326,7 +336,7 @@ bool NixRepl::processLine(string line) runProgram("nix-shell", Strings{drvPath}); } - else if (command == ":p") { + else if (command == ":p" || command == ":print") { Value v; evalString(arg, v); printValue(std::cout, v, 1000000000) << std::endl; @@ -363,6 +373,8 @@ bool NixRepl::processLine(string line) void NixRepl::loadFile(const Path & path) { + loadedFiles.remove(path); + loadedFiles.push_back(path); Value v, v2; state.evalFile(lookupFileArg(state, path), v); Bindings bindings; @@ -371,6 +383,19 @@ void NixRepl::loadFile(const Path & path) } +void NixRepl::reloadFiles() +{ + Strings old = loadedFiles; + loadedFiles.clear(); + + foreach (Strings::iterator, i, old) { + if (i != old.begin()) std::cout << std::endl; + std::cout << format("Loading ‘%1%’...") % *i << std::endl; + loadFile(*i); + } +} + + void NixRepl::addAttrsToScope(Value & attrs) { state.forceAttrs(attrs); From 498f8b048513bf3eee810c80f6795ab1ef32793f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 16:17:45 +0200 Subject: [PATCH 25/70] Add license --- COPYING | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 COPYING diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From e91160021f992169228bc59cfa509cfb66335e8c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 17:06:14 +0200 Subject: [PATCH 26/70] On reload, wipe the environment --- nix-repl.cc | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index c0ba3a588..012fdfe1e 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -29,6 +29,7 @@ struct NixRepl Strings loadedFiles; + const static int envSize = 32768; StaticEnv staticEnv; Env * env; int displ; @@ -43,6 +44,7 @@ struct NixRepl bool getLine(string & line); bool processLine(string line); void loadFile(const Path & path); + void initEnv(); void reloadFiles(); void addAttrsToScope(Value & attrs); void addVarToScope(const Symbol & name, Value & v); @@ -75,10 +77,6 @@ NixRepl::NixRepl() { curDir = absPath("."); - env = &state.allocEnv(32768); - env->up = &state.baseEnv; - displ = 0; - store = openStore(); } @@ -90,10 +88,8 @@ void NixRepl::mainLoop(const Strings & args) foreach (Strings::const_iterator, i, args) loadedFiles.push_back(*i); - if (!loadedFiles.empty()) { - reloadFiles(); - std::cout << std::endl; - } + reloadFiles(); + if (!loadedFiles.empty()) std::cout << std::endl; using_history(); read_history(0); @@ -383,8 +379,20 @@ void NixRepl::loadFile(const Path & path) } +void NixRepl::initEnv() +{ + env = &state.allocEnv(envSize); + env->up = &state.baseEnv; + displ = 0; + varNames.clear(); + staticEnv.vars.clear(); +} + + void NixRepl::reloadFiles() { + initEnv(); + Strings old = loadedFiles; loadedFiles.clear(); @@ -407,6 +415,8 @@ void NixRepl::addAttrsToScope(Value & attrs) void NixRepl::addVarToScope(const Symbol & name, Value & v) { + if (displ >= envSize) + throw Error("environment full; cannot add more variables"); staticEnv.vars[name] = displ; env->values[displ++] = &v; varNames.insert((string) name); From dc670a173ab22d344c5d77d502798f0296f572cc Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 17:22:42 +0200 Subject: [PATCH 27/70] Make tab-completion work on builtins --- nix-repl.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 012fdfe1e..98d27b435 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -384,8 +384,11 @@ void NixRepl::initEnv() env = &state.allocEnv(envSize); env->up = &state.baseEnv; displ = 0; - varNames.clear(); staticEnv.vars.clear(); + + varNames.clear(); + foreach (StaticEnv::Vars::iterator, i, state.staticBaseEnv.vars) + varNames.insert(i->first); } From ae50a5e7bee19cb6de331e847936ea8afa0ba8b6 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 18:09:46 +0200 Subject: [PATCH 28/70] Add a README --- README.md | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..af2d27a20 --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +nix-repl +======== + +`nix-repl` is a simple read–eval–print loop (REPL) for the Nix package +manager. + +Installation +------------ + +Assuming you have Nix installed, just do + + $ git clone https://github.com/edolstra/nix-repl.git + $ cd nix-repl + $ nix-env -f . -i nix-repl + +Example +------- + +Here is a typical `nix-repl` session: + + $ nix-repl + Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. + + nix-repl> 3 * 4 + 12 + + nix-repl> :l + Added 3337 variables. + + nix-repl> lib.range 1 5 + [ 1 2 3 4 5 ] + + nix-repl> :a lib + Added 299 variables. + + nix-repl> range 1 5 + [ 1 2 3 4 5 ] + + nix-repl> xs = range 1 5 + + nix-repl> map (x: x * x) xs + [ 1 4 9 16 25 ] + + nix-repl> :l + Added 7 variables. + + nix-repl> config.services.dhcpd + { configFile = null; enable = false; extraConfig = ""; interfaces = [ ... ]; machines = [ ... ]; } + + nix-repl> :p config.services.dhcpd + { configFile = null; enable = false; extraConfig = ""; interfaces = [ "eth0" ]; machines = [ ]; } + + nix-repl> config.fileSystems + { "/" = { ... }; "/boot" = { ... }; } + + nix-repl> mapAttrsToList (n: v: v.device) config.fileSystems + [ "/dev/disk/by-label/nixos" "/dev/disk/by-label/boot" ] + + nix-repl> :b libjson + these derivations will be built: + /nix/store/h910xqb36pysxcxkayb1zkr1zcvvk1zy-libjson_7.6.1.zip.drv + /nix/store/iv0rdx08di0fg704zyxklkvdz6i96lm8-libjson-7.6.1.drv + ... + this derivation produced the following outputs: + out -> /nix/store/ys6bvgfia81rjwqxjlgkwnx6jhsml8h9-libjson-7.6.1 + + nix-repl> :t makeFontsConf + a function + + nix-repl> :b makeFontsConf { fontDirectories = [ "${freefont_ttf}/share/fonts/truetype" ]; } + ... + this derivation produced the following outputs: + out -> /nix/store/jkw848xj0gkbhmvxi0hwpnhzn2716v3c-fonts.conf + + nix-repl> :s pan + # Builds dependencies of the ‘pan’ derivation, then starts a shell + # in which the environment variables of the derivation are set + + [nix-shell:/tmp/nix-repl]$ echo $src + /nix/store/0ibx15r02nnkwiclmfbpzrzjm2y204fh-pan-0.139.tar.bz2 + + [nix-shell:/tmp/nix-repl]$ exit + + nix-repl> + +Tab completion works on variables in scope and on attribute sets. For +example: + + $ nix-repl '' '' + Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. + + nix-repl> thunder => thunderbird + + nix-repl> + Display all 3634 possibilities? (y or n) + + nix-repl> lib + Display all 291 possibilities? (y or n) + + nix-repl> xorg.libX + xorg.libXdamage xorg.libXdmcp + + nix-repl> config.networking.use + config.networking.useDHCP config.networking.usePredictableInterfaceNames From 853d2e0aa42b1a7e5de6111c86dbd4a16e0fe411 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 18:10:57 +0200 Subject: [PATCH 29/70] Fix markdown --- README.md | 112 +++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index af2d27a20..01967e800 100644 --- a/README.md +++ b/README.md @@ -18,87 +18,87 @@ Example Here is a typical `nix-repl` session: - $ nix-repl - Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. + $ nix-repl + Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. - nix-repl> 3 * 4 - 12 + nix-repl> 3 * 4 + 12 - nix-repl> :l - Added 3337 variables. + nix-repl> :l + Added 3337 variables. - nix-repl> lib.range 1 5 - [ 1 2 3 4 5 ] + nix-repl> lib.range 1 5 + [ 1 2 3 4 5 ] - nix-repl> :a lib - Added 299 variables. + nix-repl> :a lib + Added 299 variables. - nix-repl> range 1 5 - [ 1 2 3 4 5 ] + nix-repl> range 1 5 + [ 1 2 3 4 5 ] - nix-repl> xs = range 1 5 + nix-repl> xs = range 1 5 - nix-repl> map (x: x * x) xs - [ 1 4 9 16 25 ] + nix-repl> map (x: x * x) xs + [ 1 4 9 16 25 ] - nix-repl> :l - Added 7 variables. + nix-repl> :l + Added 7 variables. - nix-repl> config.services.dhcpd - { configFile = null; enable = false; extraConfig = ""; interfaces = [ ... ]; machines = [ ... ]; } + nix-repl> config.services.dhcpd + { configFile = null; enable = false; extraConfig = ""; interfaces = [ ... ]; machines = [ ... ]; } - nix-repl> :p config.services.dhcpd - { configFile = null; enable = false; extraConfig = ""; interfaces = [ "eth0" ]; machines = [ ]; } + nix-repl> :p config.services.dhcpd + { configFile = null; enable = false; extraConfig = ""; interfaces = [ "eth0" ]; machines = [ ]; } - nix-repl> config.fileSystems - { "/" = { ... }; "/boot" = { ... }; } + nix-repl> config.fileSystems + { "/" = { ... }; "/boot" = { ... }; } - nix-repl> mapAttrsToList (n: v: v.device) config.fileSystems - [ "/dev/disk/by-label/nixos" "/dev/disk/by-label/boot" ] + nix-repl> mapAttrsToList (n: v: v.device) config.fileSystems + [ "/dev/disk/by-label/nixos" "/dev/disk/by-label/boot" ] - nix-repl> :b libjson - these derivations will be built: - /nix/store/h910xqb36pysxcxkayb1zkr1zcvvk1zy-libjson_7.6.1.zip.drv - /nix/store/iv0rdx08di0fg704zyxklkvdz6i96lm8-libjson-7.6.1.drv - ... - this derivation produced the following outputs: - out -> /nix/store/ys6bvgfia81rjwqxjlgkwnx6jhsml8h9-libjson-7.6.1 + nix-repl> :b libjson + these derivations will be built: + /nix/store/h910xqb36pysxcxkayb1zkr1zcvvk1zy-libjson_7.6.1.zip.drv + /nix/store/iv0rdx08di0fg704zyxklkvdz6i96lm8-libjson-7.6.1.drv + ... + this derivation produced the following outputs: + out -> /nix/store/ys6bvgfia81rjwqxjlgkwnx6jhsml8h9-libjson-7.6.1 - nix-repl> :t makeFontsConf - a function + nix-repl> :t makeFontsConf + a function - nix-repl> :b makeFontsConf { fontDirectories = [ "${freefont_ttf}/share/fonts/truetype" ]; } - ... - this derivation produced the following outputs: - out -> /nix/store/jkw848xj0gkbhmvxi0hwpnhzn2716v3c-fonts.conf + nix-repl> :b makeFontsConf { fontDirectories = [ "${freefont_ttf}/share/fonts/truetype" ]; } + ... + this derivation produced the following outputs: + out -> /nix/store/jkw848xj0gkbhmvxi0hwpnhzn2716v3c-fonts.conf - nix-repl> :s pan - # Builds dependencies of the ‘pan’ derivation, then starts a shell - # in which the environment variables of the derivation are set + nix-repl> :s pan + # Builds dependencies of the ‘pan’ derivation, then starts a shell + # in which the environment variables of the derivation are set - [nix-shell:/tmp/nix-repl]$ echo $src - /nix/store/0ibx15r02nnkwiclmfbpzrzjm2y204fh-pan-0.139.tar.bz2 + [nix-shell:/tmp/nix-repl]$ echo $src + /nix/store/0ibx15r02nnkwiclmfbpzrzjm2y204fh-pan-0.139.tar.bz2 - [nix-shell:/tmp/nix-repl]$ exit + [nix-shell:/tmp/nix-repl]$ exit - nix-repl> + nix-repl> Tab completion works on variables in scope and on attribute sets. For example: - $ nix-repl '' '' - Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. + $ nix-repl '' '' + Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. - nix-repl> thunder => thunderbird + nix-repl> thunder => thunderbird - nix-repl> - Display all 3634 possibilities? (y or n) + nix-repl> + Display all 3634 possibilities? (y or n) - nix-repl> lib - Display all 291 possibilities? (y or n) + nix-repl> lib + Display all 291 possibilities? (y or n) - nix-repl> xorg.libX - xorg.libXdamage xorg.libXdmcp + nix-repl> xorg.libX + xorg.libXdamage xorg.libXdmcp - nix-repl> config.networking.use - config.networking.useDHCP config.networking.usePredictableInterfaceNames + nix-repl> config.networking.use + config.networking.useDHCP config.networking.usePredictableInterfaceNames From 81d658fe4afda234028cd4551e12491db4303957 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 9 Sep 2013 18:11:47 +0200 Subject: [PATCH 30/70] Fix readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 01967e800..c5964fd5e 100644 --- a/README.md +++ b/README.md @@ -9,9 +9,9 @@ Installation Assuming you have Nix installed, just do - $ git clone https://github.com/edolstra/nix-repl.git - $ cd nix-repl - $ nix-env -f . -i nix-repl + $ git clone https://github.com/edolstra/nix-repl.git + $ cd nix-repl + $ nix-env -f . -i nix-repl Example ------- From 3beb6f6e763f56d791db0a99baf285e0ba745bc8 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Jan 2014 10:40:02 +0100 Subject: [PATCH 31/70] Show derivations more concisely --- nix-repl.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 98d27b435..78be0f98c 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -489,10 +489,18 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m seen.insert(&v); bool isDrv = state.isDerivation(v); - if (isDrv) str << "(derivation "; - str << "{ "; - if (maxDepth > 0) { + if (isDrv) { + str << "«derivation "; + Bindings::iterator i = v.attrs->find(state.sDrvPath); + PathSet context; + Path drvPath = i != v.attrs->end() ? state.coerceToPath(*i->value, context) : "???"; + str << drvPath << "»"; + } + + else if (maxDepth > 0) { + str << "{ "; + typedef std::map Sorted; Sorted sorted; foreach (Bindings::iterator, i, *v.attrs) @@ -528,11 +536,10 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m str << "; "; } + str << "}"; } else - str << "... "; + str << "{ ... }"; - str << "}"; - if (isDrv) str << ")"; break; } From 6a4a8208be10462b1051c689b26577dc36495632 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 28 Jan 2014 10:42:05 +0100 Subject: [PATCH 32/70] Fix building against current Nix --- nix-repl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 78be0f98c..1c7b2f514 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -311,10 +311,10 @@ bool NixRepl::processLine(string line) else if (command == ":b" || command == ":s") { Value v; evalString(arg, v); - DrvInfo drvInfo; + DrvInfo drvInfo(state); if (!getDerivation(state, v, drvInfo, false)) throw Error("expression does not evaluation to a derivation, so I can't build it"); - Path drvPath = drvInfo.queryDrvPath(state); + Path drvPath = drvInfo.queryDrvPath(); if (drvPath == "" || !store->isValidPath(drvPath)) throw Error("expression did not evaluate to a valid derivation"); From 22a47ab03c8a1bf81df3aa0d29a4d6a29aacc36f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 11 Apr 2014 12:50:46 +0200 Subject: [PATCH 33/70] Fix building against Nix 1.7 --- default.nix | 7 ++++--- nix-repl.cc | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/default.nix b/default.nix index c4a967bf5..435c16c09 100644 --- a/default.nix +++ b/default.nix @@ -3,11 +3,12 @@ with import nixpkgs { inherit system; }; runCommand "nix-repl" - { buildInputs = [ readline nixUnstable boehmgc ]; } + { buildInputs = [ readline nix boehmgc ]; } '' mkdir -p $out/bin g++ -O3 -Wall -std=c++0x \ -o $out/bin/nix-repl ${./nix-repl.cc} \ - -I${nixUnstable}/include/nix -L${nixUnstable}/lib/nix \ - -lformat -lutil -lstore -lexpr -lmain -lreadline -lgc + -I${nix}/include/nix \ + -lnixformat -lnixutil -lnixstore -lnixexpr -lnixmain -lreadline -lgc \ + -DNIX_VERSION=${(builtins.parseDrvName nix.name).version} '' diff --git a/nix-repl.cc b/nix-repl.cc index 1c7b2f514..ef9be417a 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -323,7 +323,7 @@ bool NixRepl::processLine(string line) but doing it in a child makes it easier to recover from problems / SIGINT. */ if (runProgram("nix-store", Strings{"-r", drvPath}) == 0) { - Derivation drv = parseDerivation(readFile(drvPath)); + Derivation drv = readDerivation(drvPath); std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; foreach (DerivationOutputs::iterator, i, drv.outputs) std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; @@ -494,7 +494,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m str << "«derivation "; Bindings::iterator i = v.attrs->find(state.sDrvPath); PathSet context; - Path drvPath = i != v.attrs->end() ? state.coerceToPath(*i->value, context) : "???"; + Path drvPath = i != v.attrs->end() ? state.coerceToPath(*i->pos, *i->value, context) : "???"; str << drvPath << "»"; } From 1734e8a1491ef831c83c2620b6b0f4a590b67c1f Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 11 Apr 2014 12:51:15 +0200 Subject: [PATCH 34/70] Fix crash in tab completion Fixes #1. Patch by Maxdamantus. --- nix-repl.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index ef9be417a..8049008d1 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -216,8 +216,10 @@ void NixRepl::completePrefix(string prefix) } catch (ParseError & e) { // Quietly ignore parse errors. - }catch (EvalError & e) { + } catch (EvalError & e) { // Quietly ignore evaluation errors. + } catch (UndefinedVarError & e) { + // Quietly ignore undefined variable errors. } } } From 66b2d18243d055bcbc6c3f7708960575d02db09c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 16 Jun 2014 10:05:09 -0400 Subject: [PATCH 35/70] Don't parse 'var == expr' as an assignment --- nix-repl.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nix-repl.cc b/nix-repl.cc index 8049008d1..ea188a1c7 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -350,6 +350,8 @@ bool NixRepl::processLine(string line) size_t p = line.find('='); string name; if (p != string::npos && + p < line.size() && + line[p + 1] != '=' && isVarName(name = removeWhitespace(string(line, 0, p)))) { Expr * e = parseString(string(line, p + 1)); From 2cf0e67761121a4ddceb69a932bc2e3c0cd6cb6c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 24 Jul 2014 17:46:58 +0200 Subject: [PATCH 36/70] Handle non-numeric version strings Fixes #2. --- default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.nix b/default.nix index 435c16c09..e7cdc2358 100644 --- a/default.nix +++ b/default.nix @@ -10,5 +10,5 @@ runCommand "nix-repl" -o $out/bin/nix-repl ${./nix-repl.cc} \ -I${nix}/include/nix \ -lnixformat -lnixutil -lnixstore -lnixexpr -lnixmain -lreadline -lgc \ - -DNIX_VERSION=${(builtins.parseDrvName nix.name).version} + -DNIX_VERSION=\"${(builtins.parseDrvName nix.name).version}\" '' From 02b66e97ba08ed68a73654556734aadfc9f41c89 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 24 Jul 2014 17:53:32 +0200 Subject: [PATCH 37/70] Fix building against current Nix master --- nix-repl.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index ea188a1c7..fadaf079a 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -73,7 +73,8 @@ string removeWhitespace(string s) NixRepl::NixRepl() - : staticEnv(false, &state.staticBaseEnv) + : state(Strings()) + , staticEnv(false, &state.staticBaseEnv) { curDir = absPath("."); From 89f9c0d41b29d18e2804677da856e84c86c83b45 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 26 Aug 2014 20:03:12 +0200 Subject: [PATCH 38/70] Fix building against current Nix master --- default.nix | 2 ++ nix-repl.cc | 30 +++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/default.nix b/default.nix index e7cdc2358..8690325e5 100644 --- a/default.nix +++ b/default.nix @@ -2,6 +2,8 @@ with import nixpkgs { inherit system; }; +let nix = nixUnstable; in + runCommand "nix-repl" { buildInputs = [ readline nix boehmgc ]; } '' diff --git a/nix-repl.cc b/nix-repl.cc index fadaf079a..bff54aa14 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -39,7 +39,7 @@ struct NixRepl StringSet::iterator curCompletion; NixRepl(); - void mainLoop(const Strings & args); + void mainLoop(const Strings & files); void completePrefix(string prefix); bool getLine(string & line); bool processLine(string line); @@ -73,7 +73,7 @@ string removeWhitespace(string s) NixRepl::NixRepl() - : state(Strings()) + : state(Strings()) , staticEnv(false, &state.staticBaseEnv) { curDir = absPath("."); @@ -82,11 +82,11 @@ NixRepl::NixRepl() } -void NixRepl::mainLoop(const Strings & args) +void NixRepl::mainLoop(const Strings & files) { std::cout << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; - foreach (Strings::const_iterator, i, args) + foreach (Strings::const_iterator, i, files) loadedFiles.push_back(*i); reloadFiles(); @@ -590,8 +590,24 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } -void run(Strings args) +int main(int argc, char * * argv) { - NixRepl repl; - repl.mainLoop(args); + return handleExceptions(argv[0], [&]() { + initNix(); + + Strings files; + + parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { + if (*arg == "--version") + printVersion("nix-repl"); + else if (*arg != "" && arg->at(0) == '-') + return false; + else + files.push_back(*arg); + return true; + }); + + NixRepl repl; + repl.mainLoop(files); + }); } From 71d61508f203e8d926a0365332ff218c1314f734 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 26 Aug 2014 20:05:08 +0200 Subject: [PATCH 39/70] Support -I flag --- nix-repl.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index bff54aa14..51d297d1d 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -38,7 +38,7 @@ struct NixRepl StringSet completions; StringSet::iterator curCompletion; - NixRepl(); + NixRepl(const Strings & searchPath); void mainLoop(const Strings & files); void completePrefix(string prefix); bool getLine(string & line); @@ -72,8 +72,8 @@ string removeWhitespace(string s) } -NixRepl::NixRepl() - : state(Strings()) +NixRepl::NixRepl(const Strings & searchPath) + : state(searchPath) , staticEnv(false, &state.staticBaseEnv) { curDir = absPath("."); @@ -595,11 +595,13 @@ int main(int argc, char * * argv) return handleExceptions(argv[0], [&]() { initNix(); - Strings files; + Strings files, searchPath; parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--version") printVersion("nix-repl"); + else if (parseSearchPathArg(arg, end, searchPath)) + ; else if (*arg != "" && arg->at(0) == '-') return false; else @@ -607,7 +609,7 @@ int main(int argc, char * * argv) return true; }); - NixRepl repl; + NixRepl repl(searchPath); repl.mainLoop(files); }); } From f92408136ed08804bab14b3e2a2def9b8effd7eb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 1 Dec 2014 10:07:10 +0100 Subject: [PATCH 40/70] Fix building against current Nix master --- nix-repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 51d297d1d..343d3f9f3 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -378,7 +378,7 @@ void NixRepl::loadFile(const Path & path) loadedFiles.push_back(path); Value v, v2; state.evalFile(lookupFileArg(state, path), v); - Bindings bindings; + Bindings & bindings(*state.allocBindings(0)); state.autoCallFunction(bindings, v, v2); addAttrsToScope(v2); } From 45c6405a30bd1b2cb8ad6a94b23be8b10cf52069 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 2 Jun 2015 13:23:53 +0200 Subject: [PATCH 41/70] Fix building against latest Nix Fixes #8. Fixes #9. --- nix-repl.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/nix-repl.cc b/nix-repl.cc index 343d3f9f3..8cfbfeff9 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -594,6 +594,7 @@ int main(int argc, char * * argv) { return handleExceptions(argv[0], [&]() { initNix(); + initGC(); Strings files, searchPath; From 57aeef0b6a3d3c9506e35f57f5b6db33019967e5 Mon Sep 17 00:00:00 2001 From: Susan Potter Date: Mon, 6 Jul 2015 08:26:17 -0500 Subject: [PATCH 42/70] Fix nix-repl does not support '--help' According to popular practice and convention `nix-repl` now supports `--help` like a good POSIX citizen[1]. [1] https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html --- nix-repl.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 8cfbfeff9..43e8c4a6c 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -59,7 +59,8 @@ struct NixRepl void printHelp() { - std::cout << "Usage: nix-repl\n"; + std::cout << "Usage: nix-repl [--help|--version]"; + std::cout << std::endl; } @@ -601,6 +602,11 @@ int main(int argc, char * * argv) parseCmdLine(argc, argv, [&](Strings::iterator & arg, const Strings::iterator & end) { if (*arg == "--version") printVersion("nix-repl"); + else if (*arg == "--help") { + printHelp(); + // exit with 0 since user asked for help + _exit(0); + } else if (parseSearchPathArg(arg, end, searchPath)) ; else if (*arg != "" && arg->at(0) == '-') From 8a2f5f0607540ffe56b56d52db544373e1efb980 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 7 Sep 2015 13:05:58 +0200 Subject: [PATCH 43/70] Fix building against Nix 1.10 Fixes #12. --- nix-repl.cc | 68 ++++++++++++++++++++++++++++------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 43e8c4a6c..474ad4fc9 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -87,8 +87,8 @@ void NixRepl::mainLoop(const Strings & files) { std::cout << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; - foreach (Strings::const_iterator, i, files) - loadedFiles.push_back(*i); + for (auto & i : files) + loadedFiles.push_back(i); reloadFiles(); if (!loadedFiles.empty()) std::cout << std::endl; @@ -210,8 +210,8 @@ void NixRepl::completePrefix(string prefix) e->eval(state, *env, v); state.forceAttrs(v); - foreach (Bindings::iterator, i, *v.attrs) { - string name = i->name; + for (auto & i : *v.attrs) { + string name = i.name; if (string(name, 0, prefix2.size()) != prefix2) continue; completions.insert(expr + "." + name); } @@ -251,11 +251,11 @@ static int runProgram(const string & program, const Strings & args) bool isVarName(const string & s) { // FIXME: not quite correct. - foreach (string::const_iterator, i, s) - if (!((*i >= 'a' && *i <= 'z') || - (*i >= 'A' && *i <= 'Z') || - (*i >= '0' && *i <= '9') || - *i == '_' || *i == '\'')) + for (auto & i : s) + if (!((i >= 'a' && i <= 'z') || + (i >= 'A' && i <= 'Z') || + (i >= '0' && i <= '9') || + i == '_' || i == '\'')) return false; return true; } @@ -329,8 +329,8 @@ bool NixRepl::processLine(string line) if (runProgram("nix-store", Strings{"-r", drvPath}) == 0) { Derivation drv = readDerivation(drvPath); std::cout << std::endl << "this derivation produced the following outputs:" << std::endl; - foreach (DerivationOutputs::iterator, i, drv.outputs) - std::cout << format(" %1% -> %2%") % i->first % i->second.path << std::endl; + for (auto & i : drv.outputs) + std::cout << format(" %1% -> %2%") % i.first % i.second.path << std::endl; } } else runProgram("nix-shell", Strings{drvPath}); @@ -393,8 +393,8 @@ void NixRepl::initEnv() staticEnv.vars.clear(); varNames.clear(); - foreach (StaticEnv::Vars::iterator, i, state.staticBaseEnv.vars) - varNames.insert(i->first); + for (auto & i : state.staticBaseEnv.vars) + varNames.insert(i.first); } @@ -405,10 +405,12 @@ void NixRepl::reloadFiles() Strings old = loadedFiles; loadedFiles.clear(); - foreach (Strings::iterator, i, old) { - if (i != old.begin()) std::cout << std::endl; - std::cout << format("Loading ‘%1%’...") % *i << std::endl; - loadFile(*i); + bool first = true; + for (auto & i : old) { + if (!first) std::cout << std::endl; + first = false; + std::cout << format("Loading ‘%1%’...") % i << std::endl; + loadFile(i); } } @@ -416,8 +418,8 @@ void NixRepl::reloadFiles() void NixRepl::addAttrsToScope(Value & attrs) { state.forceAttrs(attrs); - foreach (Bindings::iterator, i, *attrs.attrs) - addVarToScope(i->name, *i->value); + for (auto & i : *attrs.attrs) + addVarToScope(i.name, *i.value); std::cout << format("Added %1% variables.") % attrs.attrs->size() << std::endl; } @@ -509,8 +511,8 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m typedef std::map Sorted; Sorted sorted; - foreach (Bindings::iterator, i, *v.attrs) - sorted[i->name] = i->value; + for (auto & i : *v.attrs) + sorted[i.name] = i.value; /* If this is a derivation, then don't show the self-references ("all", "out", etc.). */ @@ -522,20 +524,20 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m hidden.insert("out"); else { state.forceList(*i->value); - for (unsigned int j = 0; j < i->value->list.length; ++j) - hidden.insert(state.forceStringNoCtx(*i->value->list.elems[j])); + for (unsigned int j = 0; j < i->value->listSize(); ++j) + hidden.insert(state.forceStringNoCtx(*i->value->listElems()[j])); } } - foreach (Sorted::iterator, i, sorted) { - str << i->first << " = "; - if (hidden.find(i->first) != hidden.end()) + for (auto & i : sorted) { + str << i.first << " = "; + if (hidden.find(i.first) != hidden.end()) str << "«...»"; - else if (seen.find(i->second) != seen.end()) + else if (seen.find(i.second) != seen.end()) str << "«repeated»"; else try { - printValue(str, *i->second, maxDepth - 1, seen); + printValue(str, *i.second, maxDepth - 1, seen); } catch (AssertionError & e) { str << "«error: " << e.msg() << "»"; } @@ -549,17 +551,19 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; } - case tList: + case tList1: + case tList2: + case tListN: seen.insert(&v); str << "[ "; if (maxDepth > 0) - for (unsigned int n = 0; n < v.list.length; ++n) { - if (seen.find(v.list.elems[n]) != seen.end()) + for (unsigned int n = 0; n < v.listSize(); ++n) { + if (seen.find(v.listElems()[n]) != seen.end()) str << "«repeated»"; else try { - printValue(str, *v.list.elems[n], maxDepth - 1, seen); + printValue(str, *v.listElems()[n], maxDepth - 1, seen); } catch (AssertionError & e) { str << "«error: " << e.msg() << "»"; } From f7980b471273d695aa0b28f2f73e6ee443dfe9eb Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Sun, 14 Feb 2016 01:16:30 -0600 Subject: [PATCH 44/70] Parse `foo-bar = expr` as an assignment. --- nix-repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 474ad4fc9..25f84a308 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -255,7 +255,7 @@ bool isVarName(const string & s) if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || (i >= '0' && i <= '9') || - i == '_' || i == '\'')) + i == '_' || i == '-' || i == '\'')) return false; return true; } From 2111098a3a26d11edf4452f021245b55287c45b8 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Sun, 14 Feb 2016 01:29:48 -0600 Subject: [PATCH 45/70] Don't consider strings starting with - or ' as variable names. --- nix-repl.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 25f84a308..5c319f068 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -250,7 +250,8 @@ static int runProgram(const string & program, const Strings & args) bool isVarName(const string & s) { - // FIXME: not quite correct. + if (s.size() > 0 && (s[0] == '-' || s[0] == '\'')) + return false; for (auto & i : s) if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || From f30fd9c47b1ae7a48f4854c86b3ad5e038845aa3 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Sun, 14 Feb 2016 01:50:47 -0600 Subject: [PATCH 46/70] Don't consider empty strings or strings beginning with numbers as variable names. --- nix-repl.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 5c319f068..1077f5d8f 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -250,8 +250,9 @@ static int runProgram(const string & program, const Strings & args) bool isVarName(const string & s) { - if (s.size() > 0 && (s[0] == '-' || s[0] == '\'')) - return false; + if (s.size() == 0) return false; + char c = s[0]; + if ((c >= '0' && c <= '9') || c == '-' || c == '\'') return false; for (auto & i : s) if (!((i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z') || From 3cfb8d15846238d79b36de7e52a90a4d3afa4268 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Mon, 15 Feb 2016 19:16:24 -0600 Subject: [PATCH 47/70] Remove unused global variable. --- nix-repl.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 1077f5d8f..8569b5eb6 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -19,9 +19,6 @@ using namespace std; using namespace nix; -string programId = "nix-repl"; - - struct NixRepl { string curDir; From 30a7bfbebe8582ab02f2a9b659403a5b3e1c097b Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Mon, 15 Feb 2016 23:11:26 -0600 Subject: [PATCH 48/70] Fix grammar. --- nix-repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 8569b5eb6..e753c637a 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -316,7 +316,7 @@ bool NixRepl::processLine(string line) evalString(arg, v); DrvInfo drvInfo(state); if (!getDerivation(state, v, drvInfo, false)) - throw Error("expression does not evaluation to a derivation, so I can't build it"); + throw Error("expression does not evaluate to a derivation, so I can't build it"); Path drvPath = drvInfo.queryDrvPath(); if (drvPath == "" || !store->isValidPath(drvPath)) throw Error("expression did not evaluate to a valid derivation"); From 82aca33899a0348736604e6b6a601f9c7b4e0633 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Tue, 16 Feb 2016 00:24:50 -0600 Subject: [PATCH 49/70] Add :i command to install a package to the current profile. It works by running `nix-env -i `. Fixes #15. --- nix-repl.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index e753c637a..ca221b033 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -281,6 +281,7 @@ bool NixRepl::processLine(string line) << " = Bind expression to variable\n" << " :a Add attributes from resulting set to scope\n" << " :b Build derivation\n" + << " :i Build derivation, then install result into current profile\n" << " :l Load Nix expression and add it to scope\n" << " :p Evaluate and print expression recursively\n" << " :q Exit nix-repl\n" @@ -311,7 +312,7 @@ bool NixRepl::processLine(string line) std::cout << showType(v) << std::endl; } - else if (command == ":b" || command == ":s") { + else if (command == ":b" || command == ":i" || command == ":s") { Value v; evalString(arg, v); DrvInfo drvInfo(state); @@ -331,8 +332,11 @@ bool NixRepl::processLine(string line) for (auto & i : drv.outputs) std::cout << format(" %1% -> %2%") % i.first % i.second.path << std::endl; } - } else + } else if (command == ":i") { + runProgram("nix-env", Strings{"-i", drvPath}); + } else { runProgram("nix-shell", Strings{drvPath}); + } } else if (command == ":p" || command == ":print") { From cfc874ee52008f523a86b5079243deabaecb62e4 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Tue, 16 Feb 2016 18:40:45 -0600 Subject: [PATCH 50/70] Open the store before constructing EvalState. EvalState requires the `store` global to be initialized before it is constructed in some cases, e.g. when it needs to download a tarball for something in NIX_PATH. Hence, this fixes #13. --- nix-repl.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 1077f5d8f..cdf6a79e9 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -78,8 +78,6 @@ NixRepl::NixRepl(const Strings & searchPath) , staticEnv(false, &state.staticBaseEnv) { curDir = absPath("."); - - store = openStore(); } @@ -622,6 +620,7 @@ int main(int argc, char * * argv) return true; }); + store = openStore(); NixRepl repl(searchPath); repl.mainLoop(files); }); From 287dfee35edc6c324ee8829f37a8ed6b07c35ffa Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Thu, 18 Feb 2016 04:05:11 -0600 Subject: [PATCH 51/70] Expand the help message printed from --help. Fixes #10. I consider this a temporary measure, however, until nix-repl has a manpage (see #14). Then it can just open its manpage on --help like the other nix tools do. Much of the text in this commit was copied from nix-build's manpage. --- nix-repl.cc | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 1077f5d8f..1b098405f 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -59,8 +59,35 @@ struct NixRepl void printHelp() { - std::cout << "Usage: nix-repl [--help|--version]"; - std::cout << std::endl; + cout << "Usage: nix-repl [--help] [--version] [-I path] paths...\n" + << "\n" + << "nix-repl is a simple read-eval-print loop (REPL) for the Nix package manager.\n" + << "\n" + << "Options:\n" + << " --help\n" + << " Prints out a summary of the command syntax and exits.\n" + << "\n" + << " --version\n" + << " Prints out the Nix version number on standard output and exits.\n" + << "\n" + << " -I path\n" + << " Add a path to the Nix expression search path. This option may be given\n" + << " multiple times. See the NIX_PATH environment variable for information on\n" + << " the semantics of the Nix search path. Paths added through -I take\n" + << " precedence over NIX_PATH.\n" + << "\n" + << " paths...\n" + << " A list of paths to files containing Nix expressions which nix-repl will\n" + << " load and add to its scope.\n" + << "\n" + << " A path surrounded in < and > will be looked up in the Nix expression search\n" + << " path, as in the Nix language itself.\n" + << "\n" + << " If an element of paths starts with http:// or https://, it is interpreted\n" + << " as the URL of a tarball that will be downloaded and unpacked to a temporary\n" + << " location. The tarball must include a single top-level directory containing\n" + << " at least a file named default.nix.\n" + << flush; } From 2d729e4f6f45c079ddf149610357e648e805f42c Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Thu, 18 Feb 2016 06:27:39 -0600 Subject: [PATCH 52/70] Support multiline input by detecting "unfinished" parse errors. Fixes #4, --- nix-repl.cc | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 1077f5d8f..9dddb2603 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -41,7 +41,7 @@ struct NixRepl NixRepl(const Strings & searchPath); void mainLoop(const Strings & files); void completePrefix(string prefix); - bool getLine(string & line); + bool getLine(string & line, const char * prompt); bool processLine(string line); void loadFile(const Path & path); void initEnv(); @@ -96,21 +96,39 @@ void NixRepl::mainLoop(const Strings & files) using_history(); read_history(0); + string input; + while (true) { + // When continuing input from a previous, don't print a prompt, just align to the same + // number of chars as the prompt. + const char * prompt = input.empty() ? "nix-repl> " : " "; string line; - if (!getLine(line)) { + if (!getLine(line, prompt)) { std::cout << std::endl; break; } + input.append(removeWhitespace(line)); + input.push_back('\n'); + try { - if (!processLine(removeWhitespace(line))) return; + if (!processLine(input)) return; + } catch (ParseError & e) { + if (e.msg().find("unexpected $end") != std::string::npos) { + // For parse errors on incomplete input, we continue waiting for the next line of + // input without clearing the input so far. + continue; + } else { + printMsg(lvlError, "error: " + e.msg()); + } } catch (Error & e) { printMsg(lvlError, "error: " + e.msg()); } catch (Interrupted & e) { printMsg(lvlError, "error: " + e.msg()); } + // We handled the current input fully, so we should clear it and read brand new input. + input.clear(); std::cout << std::endl; } } @@ -149,7 +167,7 @@ char * completerThunk(const char * s, int state) } -bool NixRepl::getLine(string & line) +bool NixRepl::getLine(string & line, const char * prompt) { struct sigaction act, old; act.sa_handler = sigintHandler; @@ -164,7 +182,7 @@ bool NixRepl::getLine(string & line) curRepl = this; rl_completion_entry_function = completerThunk; - char * s = readline("nix-repl> "); + char * s = readline(prompt); if (!s) return false; line = chomp(string(s)); free(s); From 64080d26fe9364bc0ea0893f357386ed3121878f Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Thu, 18 Feb 2016 06:50:52 -0600 Subject: [PATCH 53/70] Cancel multiline input on Ctrl-C. --- nix-repl.cc | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 9dddb2603..8d2fbd919 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -41,7 +41,7 @@ struct NixRepl NixRepl(const Strings & searchPath); void mainLoop(const Strings & files); void completePrefix(string prefix); - bool getLine(string & line, const char * prompt); + bool getLine(string & input, const char * prompt); bool processLine(string line); void loadFile(const Path & path); void initEnv(); @@ -102,15 +102,11 @@ void NixRepl::mainLoop(const Strings & files) // When continuing input from a previous, don't print a prompt, just align to the same // number of chars as the prompt. const char * prompt = input.empty() ? "nix-repl> " : " "; - string line; - if (!getLine(line, prompt)) { + if (!getLine(input, prompt)) { std::cout << std::endl; break; } - input.append(removeWhitespace(line)); - input.push_back('\n'); - try { if (!processLine(input)) return; } catch (ParseError & e) { @@ -167,7 +163,7 @@ char * completerThunk(const char * s, int state) } -bool NixRepl::getLine(string & line, const char * prompt) +bool NixRepl::getLine(string & input, const char * prompt) { struct sigaction act, old; act.sa_handler = sigintHandler; @@ -176,15 +172,17 @@ bool NixRepl::getLine(string & line, const char * prompt) if (sigaction(SIGINT, &act, &old)) throw SysError("installing handler for SIGINT"); - if (sigsetjmp(sigintJmpBuf, 1)) - line = ""; - else { + if (sigsetjmp(sigintJmpBuf, 1)) { + input.clear(); + } else { curRepl = this; rl_completion_entry_function = completerThunk; char * s = readline(prompt); if (!s) return false; - line = chomp(string(s)); + string line = chomp(string(s)); + input.append(removeWhitespace(line)); + input.push_back('\n'); free(s); if (line != "") { add_history(line.c_str()); From 60ba98242f7c976e4e14113d28bced03b32db4f5 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Thu, 18 Feb 2016 06:59:51 -0600 Subject: [PATCH 54/70] Fix recognition of REPL commands. --- nix-repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 8d2fbd919..e52c3b257 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -286,7 +286,7 @@ bool NixRepl::processLine(string line) string command, arg; if (line[0] == ':') { - size_t p = line.find(' '); + size_t p = line.find_first_of(" \n\r\t"); command = string(line, 0, p); if (p != string::npos) arg = removeWhitespace(string(line, p)); } else { From 56c7f0e8c581c66a968fdae681e9c417817e28d0 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Thu, 18 Feb 2016 07:04:55 -0600 Subject: [PATCH 55/70] Fix typo in comment. --- nix-repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index e52c3b257..3834e572a 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -99,7 +99,7 @@ void NixRepl::mainLoop(const Strings & files) string input; while (true) { - // When continuing input from a previous, don't print a prompt, just align to the same + // When continuing input from previous lines, don't print a prompt, just align to the same // number of chars as the prompt. const char * prompt = input.empty() ? "nix-repl> " : " "; if (!getLine(input, prompt)) { From 97da6d62f2a1580dfdae9575c92418d5f45a29af Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Sat, 20 Feb 2016 01:10:06 -0600 Subject: [PATCH 56/70] Print syntactially invalid attribute names as strings. --- nix-repl.cc | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index f4850271d..577efa8e2 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -472,6 +472,19 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } +std::ostream & printStringValue(std::ostream & str, const char * string) { + str << "\""; + for (const char * i = string; *i; i++) + if (*i == '\"' || *i == '\\') str << "\\" << *i; + else if (*i == '\n') str << "\\n"; + else if (*i == '\r') str << "\\r"; + else if (*i == '\t') str << "\\t"; + else str << *i; + str << "\""; + return str; +} + + // FIXME: lot of cut&paste from Nix's eval.cc. std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int maxDepth, ValuesSeen & seen) { @@ -491,14 +504,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; case tString: - str << "\""; - for (const char * i = v.string.s; *i; i++) - if (*i == '\"' || *i == '\\') str << "\\" << *i; - else if (*i == '\n') str << "\\n"; - else if (*i == '\r') str << "\\r"; - else if (*i == '\t') str << "\\t"; - else str << *i; - str << "\""; + printStringValue(str, v.string.s); break; case tPath: @@ -546,7 +552,11 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m } for (auto & i : sorted) { - str << i.first << " = "; + if (isVarName(i.first)) + str << i.first; + else + printStringValue(str, i.first.c_str()); + str << " = "; if (hidden.find(i.first) != hidden.end()) str << "«...»"; else if (seen.find(i.second) != seen.end()) From 103c46abc273266afcd5dbffa40151114234a02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20J=C3=B8rgen=20Br=C3=B8nner?= Date: Tue, 23 Feb 2016 23:19:49 +0100 Subject: [PATCH 57/70] Preserve readline history across sessions. Add rl_readline_name. --- README.md | 4 ++++ nix-repl.cc | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c5964fd5e..acdcd367f 100644 --- a/README.md +++ b/README.md @@ -102,3 +102,7 @@ example: nix-repl> config.networking.use config.networking.useDHCP config.networking.usePredictableInterfaceNames + +Input history is preserved by readline in ~/.nix-repl-history +The readline "application name" is nix-repl. This allows for nix-repl specific +settings in ~/.inputrc diff --git a/nix-repl.cc b/nix-repl.cc index 577efa8e2..1c878cd0e 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -20,6 +20,7 @@ using namespace nix; string programId = "nix-repl"; +const string historyFile = string(getenv("HOME")) + "/.nix-repl-history"; struct NixRepl @@ -91,8 +92,10 @@ void NixRepl::mainLoop(const Strings & files) reloadFiles(); if (!loadedFiles.empty()) std::cout << std::endl; + // Allow nix-repl specific settings in .inputrc + rl_readline_name = "nix-repl"; using_history(); - read_history(0); + read_history(historyFile.c_str()); string input; @@ -649,5 +652,7 @@ int main(int argc, char * * argv) store = openStore(); NixRepl repl(searchPath); repl.mainLoop(files); + + write_history(historyFile.c_str()); }); } From 87e6649fc30a37adabf384a68f588de946bc3468 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Tue, 23 Feb 2016 18:29:56 -0600 Subject: [PATCH 58/70] Fix handling of whitespace. Whitespace will no longer be removed from input lines, which fixes pasting multiline strings containing end-of-line or beginning-of-line whitespace. --- nix-repl.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 577efa8e2..1cdff20fd 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -178,14 +178,13 @@ bool NixRepl::getLine(string & input, const char * prompt) char * s = readline(prompt); if (!s) return false; - string line = chomp(string(s)); - input.append(removeWhitespace(line)); + input.append(s); input.push_back('\n'); - free(s); - if (line != "") { - add_history(line.c_str()); + if (!removeWhitespace(s).empty()) { + add_history(s); append_history(1, 0); } + free(s); } _isInterrupted = 0; From 38816759fc7f70605ecfd73304b9d442db388b78 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Tue, 23 Feb 2016 18:30:21 -0600 Subject: [PATCH 59/70] Ignore blank inputs. Previously, nix-repl would consider this an incomplete parse and wait for the next line as if it was a multiline input. Blank lines in the middle of a multiline input will continue to work. --- nix-repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 1cdff20fd..6f4287a2b 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -106,7 +106,7 @@ void NixRepl::mainLoop(const Strings & files) } try { - if (!processLine(input)) return; + if (!removeWhitespace(input).empty() && !processLine(input)) return; } catch (ParseError & e) { if (e.msg().find("unexpected $end") != std::string::npos) { // For parse errors on incomplete input, we continue waiting for the next line of From ff8d0698c76914f30d5311e1ceb0ab7d18a543b6 Mon Sep 17 00:00:00 2001 From: Fabian Schmitthenner Date: Sun, 28 Feb 2016 22:41:16 +0000 Subject: [PATCH 60/70] fix nix-repl after we don't have a global store variable anymore (cf nix@c10c61449f954702ae6d8092120321744acd82ff) --- nix-repl.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 6f4287a2b..89c35c311 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -38,7 +38,7 @@ struct NixRepl StringSet completions; StringSet::iterator curCompletion; - NixRepl(const Strings & searchPath); + NixRepl(const Strings & searchPath, nix::ref store); void mainLoop(const Strings & files); void completePrefix(string prefix); bool getLine(string & input, const char * prompt); @@ -73,8 +73,8 @@ string removeWhitespace(string s) } -NixRepl::NixRepl(const Strings & searchPath) - : state(searchPath) +NixRepl::NixRepl(const Strings & searchPath, nix::ref store) + : state(searchPath, store) , staticEnv(false, &state.staticBaseEnv) { curDir = absPath("."); @@ -334,7 +334,7 @@ bool NixRepl::processLine(string line) if (!getDerivation(state, v, drvInfo, false)) throw Error("expression does not evaluation to a derivation, so I can't build it"); Path drvPath = drvInfo.queryDrvPath(); - if (drvPath == "" || !store->isValidPath(drvPath)) + if (drvPath == "" || !state.store->isValidPath(drvPath)) throw Error("expression did not evaluate to a valid derivation"); if (command == ":b") { @@ -645,8 +645,7 @@ int main(int argc, char * * argv) return true; }); - store = openStore(); - NixRepl repl(searchPath); + NixRepl repl(searchPath, openStore()); repl.mainLoop(files); }); } From 86e93b9f61cf53cfd766e1724e65507aca952f55 Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Wed, 17 Feb 2016 20:31:30 -0600 Subject: [PATCH 61/70] Add :x command which works like `nix-shell -p`. --- nix-repl.cc | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index 8c4f40174..adf418697 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -39,6 +39,7 @@ struct NixRepl void mainLoop(const Strings & files); void completePrefix(string prefix); bool getLine(string & input, const char * prompt); + Path getDerivationPath(Value & v); bool processLine(string line); void loadFile(const Path & path); void initEnv(); @@ -300,6 +301,17 @@ bool isVarName(const string & s) } +Path NixRepl::getDerivationPath(Value & v) { + DrvInfo drvInfo(state); + if (!getDerivation(state, v, drvInfo, false)) + throw Error("expression does not evaluate to a derivation, so I can't build it"); + Path drvPath = drvInfo.queryDrvPath(); + if (drvPath == "" || !state.store->isValidPath(drvPath)) + throw Error("expression did not evaluate to a valid derivation"); + return drvPath; +} + + bool NixRepl::processLine(string line) { if (line == "") return true; @@ -327,7 +339,8 @@ bool NixRepl::processLine(string line) << " :q Exit nix-repl\n" << " :r Reload all files\n" << " :s Build dependencies of derivation, then start nix-shell\n" - << " :t Describe result of evaluation\n"; + << " :t Describe result of evaluation\n" + << " :x Build derivation, then start nix-shell\n"; } else if (command == ":a" || command == ":add") { @@ -350,17 +363,21 @@ bool NixRepl::processLine(string line) Value v; evalString(arg, v); std::cout << showType(v) << std::endl; + + } else if (command == ":x") { + Value v, f, result; + evalString(arg, v); + evalString("drv: (import {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f); + state.callFunction(f, v, result, Pos()); + + Path drvPath = getDerivationPath(result); + runProgram("nix-shell", Strings{drvPath}); } else if (command == ":b" || command == ":i" || command == ":s") { Value v; evalString(arg, v); - DrvInfo drvInfo(state); - if (!getDerivation(state, v, drvInfo, false)) - throw Error("expression does not evaluate to a derivation, so I can't build it"); - Path drvPath = drvInfo.queryDrvPath(); - if (drvPath == "" || !state.store->isValidPath(drvPath)) - throw Error("expression did not evaluate to a valid derivation"); + Path drvPath = getDerivationPath(v); if (command == ":b") { /* We could do the build in this process using buildPaths(), From e2ff27da07f30c598c88e8e7552be0d126e2b4da Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Fri, 19 Feb 2016 04:00:36 -0600 Subject: [PATCH 62/70] Rename :x to :u, for 'use'. --- nix-repl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index adf418697..a9a21ae76 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -340,7 +340,7 @@ bool NixRepl::processLine(string line) << " :r Reload all files\n" << " :s Build dependencies of derivation, then start nix-shell\n" << " :t Describe result of evaluation\n" - << " :x Build derivation, then start nix-shell\n"; + << " :u Build derivation, then start nix-shell\n"; } else if (command == ":a" || command == ":add") { @@ -364,7 +364,7 @@ bool NixRepl::processLine(string line) evalString(arg, v); std::cout << showType(v) << std::endl; - } else if (command == ":x") { + } else if (command == ":u") { Value v, f, result; evalString(arg, v); evalString("drv: (import {}).runCommand \"shell\" { buildInputs = [ drv ]; } \"\"", f); From 8bec2c07a1e25e3471ee5f1b7aedb30a5d5b03cd Mon Sep 17 00:00:00 2001 From: Fabian Schmitthenner Date: Sat, 5 Mar 2016 16:47:17 +0000 Subject: [PATCH 63/70] When showing a lambda, also show the position of the definition --- nix-repl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix-repl.cc b/nix-repl.cc index 8c4f40174..e17f73ae0 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -628,7 +628,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; case tLambda: - str << "«lambda»"; + str << "«lambda defined at " << v.lambda.fun->pos << "»"; break; case tPrimOp: From 828cf7b0582220ce568b69e9cc51af794bdd2416 Mon Sep 17 00:00:00 2001 From: Fabian Schmitthenner Date: Sat, 19 Mar 2016 13:52:39 +0000 Subject: [PATCH 64/70] show trace of errors when using --show-trace --- nix-repl.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index a9a21ae76..d1c67276c 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -14,6 +14,7 @@ #include "get-drvs.hh" #include "derivations.hh" #include "affinity.hh" +#include "globals.hh" using namespace std; using namespace nix; @@ -108,6 +109,7 @@ NixRepl::NixRepl(const Strings & searchPath, nix::ref store) void NixRepl::mainLoop(const Strings & files) { + string error = ANSI_RED "error:" ANSI_NORMAL " "; std::cout << "Welcome to Nix version " << NIX_VERSION << ". Type :? for help." << std::endl << std::endl; for (auto & i : files) @@ -138,12 +140,12 @@ void NixRepl::mainLoop(const Strings & files) // input without clearing the input so far. continue; } else { - printMsg(lvlError, "error: " + e.msg()); + printMsg(lvlError, format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg()); } } catch (Error & e) { - printMsg(lvlError, "error: " + e.msg()); + printMsg(lvlError, format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg()); } catch (Interrupted & e) { - printMsg(lvlError, "error: " + e.msg()); + printMsg(lvlError, format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg()); } // We handled the current input fully, so we should clear it and read brand new input. From eaabcba1c39a22c588b8c9336ec7ba98aefce86e Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sat, 25 Jun 2016 13:25:31 +0200 Subject: [PATCH 65/70] Colorize Berlin NixOS meetup --- nix-repl.cc | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index a9a21ae76..e28c54303 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -18,6 +18,13 @@ using namespace std; using namespace nix; +#define ESC_RED "\033[31m" +#define ESC_GRE "\033[32m" +#define ESC_YEL "\033[33m" +#define ESC_BLU "\033[34m" +#define ESC_MAG "\033[35m" +#define ESC_CYA "\033[36m" +#define ESC_END "\033[0m" struct NixRepl { @@ -540,23 +547,25 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m switch (v.type) { case tInt: - str << v.integer; + str << ESC_CYA << v.integer << ESC_END; break; case tBool: - str << (v.boolean ? "true" : "false"); + str << ESC_CYA << (v.boolean ? "true" : "false") << ESC_END; break; case tString: + str << ESC_YEL; printStringValue(str, v.string.s); + str << ESC_END; break; case tPath: - str << v.path; // !!! escaping? + str << ESC_GRE << v.path << ESC_END; // !!! escaping? break; case tNull: - str << "null"; + str << ESC_CYA "null" ESC_END; break; case tAttrs: { @@ -609,7 +618,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m try { printValue(str, *i.second, maxDepth - 1, seen); } catch (AssertionError & e) { - str << "«error: " << e.msg() << "»"; + str << ESC_RED "«error: " << e.msg() << "»" ESC_END; } str << "; "; } @@ -635,7 +644,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m try { printValue(str, *v.listElems()[n], maxDepth - 1, seen); } catch (AssertionError & e) { - str << "«error: " << e.msg() << "»"; + str << ESC_RED "«error: " << e.msg() << "»" ESC_END; } str << " "; } @@ -645,19 +654,19 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; case tLambda: - str << "«lambda»"; + str << ESC_BLU "«lambda»" ESC_END; break; case tPrimOp: - str << "«primop»"; + str << ESC_MAG "«primop»" ESC_END; break; case tPrimOpApp: - str << "«primop-app»"; + str << ESC_BLU "«primop-app»" ESC_END; break; default: - str << "«unknown»"; + str << "ESC_RED «unknown»" ESC_END; break; } From 34ec98176e4644c8c6ec45e4e932b83cbddc6cce Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sat, 25 Jun 2016 13:40:50 +0200 Subject: [PATCH 66/70] fixup "Colorize" Do not quote escape sequence macro --- nix-repl.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index e28c54303..fc0c37913 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -551,7 +551,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; case tBool: - str << ESC_CYA << (v.boolean ? "true" : "false") << ESC_END; + str << ESC_CYA << (v.boolean ? "true" : "false") << ESC_END; break; case tString: @@ -666,7 +666,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; default: - str << "ESC_RED «unknown»" ESC_END; + str << ESC_RED "«unknown»" ESC_END; break; } From 8b6052923167f19c1f4728c46e8cfc97b9f029fb Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 21 Jul 2016 11:21:59 +0200 Subject: [PATCH 67/70] Strip ANSI escapes from file names Also, use bright blue for lambdas, otherwise my eyes hurt. --- nix-repl.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/nix-repl.cc b/nix-repl.cc index ab943f7ba..0e8c67cf7 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -22,7 +22,7 @@ using namespace nix; #define ESC_RED "\033[31m" #define ESC_GRE "\033[32m" #define ESC_YEL "\033[33m" -#define ESC_BLU "\033[34m" +#define ESC_BLU "\033[34;1m" #define ESC_MAG "\033[35m" #define ESC_CYA "\033[36m" #define ESC_END "\033[0m" @@ -655,9 +655,12 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m str << "]"; break; - case tLambda: - str << ESC_BLU "«lambda defined at " << v.lambda.fun->pos << "»" ESC_END; + case tLambda: { + std::ostringstream s; + s << v.lambda.fun->pos; + str << ESC_BLU "«lambda @ " << filterANSIEscapes(s.str()) << "»" ESC_END; break; + } case tPrimOp: str << ESC_MAG "«primop»" ESC_END; From 5476e987d5d605e8fc8e50d76912e342c722bbdb Mon Sep 17 00:00:00 2001 From: Kjetil Orbekk Date: Sun, 1 Jan 2017 16:13:11 -0500 Subject: [PATCH 68/70] Update path in documentation. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c5964fd5e..57613cc19 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Here is a typical `nix-repl` session: nix-repl> map (x: x * x) xs [ 1 4 9 16 25 ] - nix-repl> :l + nix-repl> :l Added 7 variables. nix-repl> config.services.dhcpd @@ -86,7 +86,7 @@ Here is a typical `nix-repl` session: Tab completion works on variables in scope and on attribute sets. For example: - $ nix-repl '' '' + $ nix-repl '' '' Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. nix-repl> thunder => thunderbird From 2dff9556a4131af8a50647f23fe03bfc3c295e12 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 25 Apr 2017 16:55:03 +0200 Subject: [PATCH 69/70] Fix build --- default.nix | 8 ++++---- nix-repl.cc | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/default.nix b/default.nix index 8690325e5..919082981 100644 --- a/default.nix +++ b/default.nix @@ -4,13 +4,13 @@ with import nixpkgs { inherit system; }; let nix = nixUnstable; in -runCommand "nix-repl" - { buildInputs = [ readline nix boehmgc ]; } +runCommandCC "nix-repl" + { buildInputs = [ pkgconfig readline nix boehmgc ]; } '' mkdir -p $out/bin - g++ -O3 -Wall -std=c++0x \ + g++ -O3 -Wall -std=c++14 \ -o $out/bin/nix-repl ${./nix-repl.cc} \ - -I${nix}/include/nix \ + $(pkg-config --cflags nix-main) \ -lnixformat -lnixutil -lnixstore -lnixexpr -lnixmain -lreadline -lgc \ -DNIX_VERSION=\"${(builtins.parseDrvName nix.name).version}\" '' diff --git a/nix-repl.cc b/nix-repl.cc index 0e8c67cf7..0c50f4683 100644 --- a/nix-repl.cc +++ b/nix-repl.cc @@ -1,3 +1,5 @@ +#include + #include #include @@ -291,7 +293,7 @@ static int runProgram(const string & program, const Strings & args) _exit(1); } - return pid.wait(true); + return pid.wait(); } From 40daf0d800d6a248a57bae0fff8c3989d4814840 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 25 Apr 2017 18:13:23 +0200 Subject: [PATCH 70/70] Cleanup in preparation of merging nix-repl repo into nix repo --- COPYING | 674 --------------------------------- README.md | 108 ------ default.nix | 16 - nix-repl.cc => src/nix/repl.cc | 0 4 files changed, 798 deletions(-) delete mode 100644 COPYING delete mode 100644 README.md delete mode 100644 default.nix rename nix-repl.cc => src/nix/repl.cc (100%) diff --git a/COPYING b/COPYING deleted file mode 100644 index 94a9ed024..000000000 --- a/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/README.md b/README.md deleted file mode 100644 index ac5ad98cf..000000000 --- a/README.md +++ /dev/null @@ -1,108 +0,0 @@ -nix-repl -======== - -`nix-repl` is a simple read–eval–print loop (REPL) for the Nix package -manager. - -Installation ------------- - -Assuming you have Nix installed, just do - - $ git clone https://github.com/edolstra/nix-repl.git - $ cd nix-repl - $ nix-env -f . -i nix-repl - -Example -------- - -Here is a typical `nix-repl` session: - - $ nix-repl - Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. - - nix-repl> 3 * 4 - 12 - - nix-repl> :l - Added 3337 variables. - - nix-repl> lib.range 1 5 - [ 1 2 3 4 5 ] - - nix-repl> :a lib - Added 299 variables. - - nix-repl> range 1 5 - [ 1 2 3 4 5 ] - - nix-repl> xs = range 1 5 - - nix-repl> map (x: x * x) xs - [ 1 4 9 16 25 ] - - nix-repl> :l - Added 7 variables. - - nix-repl> config.services.dhcpd - { configFile = null; enable = false; extraConfig = ""; interfaces = [ ... ]; machines = [ ... ]; } - - nix-repl> :p config.services.dhcpd - { configFile = null; enable = false; extraConfig = ""; interfaces = [ "eth0" ]; machines = [ ]; } - - nix-repl> config.fileSystems - { "/" = { ... }; "/boot" = { ... }; } - - nix-repl> mapAttrsToList (n: v: v.device) config.fileSystems - [ "/dev/disk/by-label/nixos" "/dev/disk/by-label/boot" ] - - nix-repl> :b libjson - these derivations will be built: - /nix/store/h910xqb36pysxcxkayb1zkr1zcvvk1zy-libjson_7.6.1.zip.drv - /nix/store/iv0rdx08di0fg704zyxklkvdz6i96lm8-libjson-7.6.1.drv - ... - this derivation produced the following outputs: - out -> /nix/store/ys6bvgfia81rjwqxjlgkwnx6jhsml8h9-libjson-7.6.1 - - nix-repl> :t makeFontsConf - a function - - nix-repl> :b makeFontsConf { fontDirectories = [ "${freefont_ttf}/share/fonts/truetype" ]; } - ... - this derivation produced the following outputs: - out -> /nix/store/jkw848xj0gkbhmvxi0hwpnhzn2716v3c-fonts.conf - - nix-repl> :s pan - # Builds dependencies of the ‘pan’ derivation, then starts a shell - # in which the environment variables of the derivation are set - - [nix-shell:/tmp/nix-repl]$ echo $src - /nix/store/0ibx15r02nnkwiclmfbpzrzjm2y204fh-pan-0.139.tar.bz2 - - [nix-shell:/tmp/nix-repl]$ exit - - nix-repl> - -Tab completion works on variables in scope and on attribute sets. For -example: - - $ nix-repl '' '' - Welcome to Nix version 1.6pre3215_2c1ecf8. Type :? for help. - - nix-repl> thunder => thunderbird - - nix-repl> - Display all 3634 possibilities? (y or n) - - nix-repl> lib - Display all 291 possibilities? (y or n) - - nix-repl> xorg.libX - xorg.libXdamage xorg.libXdmcp - - nix-repl> config.networking.use - config.networking.useDHCP config.networking.usePredictableInterfaceNames - -Input history is preserved by readline in ~/.nix-repl-history -The readline "application name" is nix-repl. This allows for nix-repl specific -settings in ~/.inputrc diff --git a/default.nix b/default.nix deleted file mode 100644 index 919082981..000000000 --- a/default.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ nixpkgs ? , system ? builtins.currentSystem }: - -with import nixpkgs { inherit system; }; - -let nix = nixUnstable; in - -runCommandCC "nix-repl" - { buildInputs = [ pkgconfig readline nix boehmgc ]; } - '' - mkdir -p $out/bin - g++ -O3 -Wall -std=c++14 \ - -o $out/bin/nix-repl ${./nix-repl.cc} \ - $(pkg-config --cflags nix-main) \ - -lnixformat -lnixutil -lnixstore -lnixexpr -lnixmain -lreadline -lgc \ - -DNIX_VERSION=\"${(builtins.parseDrvName nix.name).version}\" - '' diff --git a/nix-repl.cc b/src/nix/repl.cc similarity index 100% rename from nix-repl.cc rename to src/nix/repl.cc