diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libexpr/attr-path.cc | 32 | ||||
-rw-r--r-- | src/libexpr/attr-path.hh | 3 | ||||
-rw-r--r-- | src/libutil/args.cc | 13 | ||||
-rw-r--r-- | src/libutil/args.hh | 4 | ||||
-rw-r--r-- | src/libutil/util.cc | 6 | ||||
-rw-r--r-- | src/nix/doctor.cc | 67 | ||||
-rw-r--r-- | src/nix/edit.cc | 40 | ||||
-rw-r--r-- | src/nix/repl.cc | 30 |
8 files changed, 134 insertions, 61 deletions
diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 832235cfd..843585631 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -93,4 +93,36 @@ Value * findAlongAttrPath(EvalState & state, const string & attrPath, } +Pos findDerivationFilename(EvalState & state, Value & v, std::string what) +{ + Value * v2; + try { + auto dummyArgs = state.allocBindings(0); + v2 = findAlongAttrPath(state, "meta.position", *dummyArgs, v); + } catch (Error &) { + throw Error("package '%s' has no source location information", what); + } + + // FIXME: is it possible to extract the Pos object instead of doing this + // toString + parsing? + auto pos = state.forceString(*v2); + + auto colon = pos.rfind(':'); + if (colon == std::string::npos) + throw Error("cannot parse meta.position attribute '%s'", pos); + + std::string filename(pos, 0, colon); + unsigned int lineno; + try { + lineno = std::stoi(std::string(pos, colon + 1)); + } catch (std::invalid_argument & e) { + throw Error("cannot parse line number '%s'", pos); + } + + Symbol file = state.symbols.create(filename); + + return { file, lineno, 0 }; +} + + } diff --git a/src/libexpr/attr-path.hh b/src/libexpr/attr-path.hh index 1eae64625..fcccc39c8 100644 --- a/src/libexpr/attr-path.hh +++ b/src/libexpr/attr-path.hh @@ -12,4 +12,7 @@ MakeError(AttrPathNotFound, Error); Value * findAlongAttrPath(EvalState & state, const string & attrPath, Bindings & autoArgs, Value & vIn); +/* Heuristic to find the filename and lineno or a nix value. */ +Pos findDerivationFilename(EvalState & state, Value & v, std::string what); + } diff --git a/src/libutil/args.cc b/src/libutil/args.cc index ba15ea571..ad7a268fc 100644 --- a/src/libutil/args.cc +++ b/src/libutil/args.cc @@ -178,6 +178,19 @@ Strings argvToStrings(int argc, char * * argv) return args; } +Strings editorFor(Pos pos) +{ + auto editor = getEnv("EDITOR", "cat"); + auto args = tokenizeString<Strings>(editor); + if (pos.line > 0 && ( + editor.find("emacs") != std::string::npos || + editor.find("nano") != std::string::npos || + editor.find("vim") != std::string::npos)) + args.push_back(fmt("+%d", pos.line)); + args.push_back(pos.file); + return args; +} + std::string renderLabels(const Strings & labels) { std::string res; diff --git a/src/libutil/args.hh b/src/libutil/args.hh index b960a55a8..59d427ee6 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -5,6 +5,7 @@ #include <memory> #include "util.hh" +#include "nixexpr.hh" namespace nix { @@ -241,6 +242,9 @@ public: Strings argvToStrings(int argc, char * * argv); +/* Helper function to generate args that invoke $EDITOR on filename:lineno */ +Strings editorFor(Pos pos); + /* Helper function for rendering argument labels. */ std::string renderLabels(const Strings & labels); diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 747b31cff..0902c3783 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1572,7 +1572,11 @@ std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) { - AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + AutoCloseFD fdSocket = socket(PF_UNIX, SOCK_STREAM + #ifdef SOCK_CLOEXEC + | SOCK_CLOEXEC + #endif + , 0); if (!fdSocket) throw SysError("cannot create Unix domain socket"); diff --git a/src/nix/doctor.cc b/src/nix/doctor.cc index 98260127b..5f76d0019 100644 --- a/src/nix/doctor.cc +++ b/src/nix/doctor.cc @@ -1,11 +1,17 @@ +#include <sstream> + #include "command.hh" +#include "logging.hh" #include "serve-protocol.hh" #include "shared.hh" #include "store-api.hh" +#include "util.hh" #include "worker-protocol.hh" using namespace nix; +namespace { + std::string formatProtocol(unsigned int proto) { if (proto) { @@ -16,19 +22,30 @@ std::string formatProtocol(unsigned int proto) return "unknown"; } +bool checkPass(const std::string & msg) { + logger->log(ANSI_GREEN "[PASS] " ANSI_NORMAL + msg); + return true; +} + +bool checkFail(const std::string & msg) { + logger->log(ANSI_RED "[FAIL] " ANSI_NORMAL + msg); + return false; +} + +} + struct CmdDoctor : StoreCommand { bool success = true; std::string description() override { - return "check your system for potential problems"; + return "check your system for potential problems and print a PASS or FAIL for each check."; } void run(ref<Store> store) override { - std::cout << "Store uri: " << store->getUri() << std::endl; - std::cout << std::endl; + logger->log("Running checks against store uri: " + store->getUri()); auto type = getStoreType(); @@ -51,15 +68,14 @@ struct CmdDoctor : StoreCommand dirs.insert(dirOf(canonPath(dir + "/nix-env", true))); if (dirs.size() != 1) { - std::cout << "Warning: multiple versions of nix found in PATH." << std::endl; - std::cout << std::endl; + std::stringstream ss; + ss << "Multiple versions of nix found in PATH:\n"; for (auto & dir : dirs) - std::cout << " " << dir << std::endl; - std::cout << std::endl; - return false; + ss << " " << dir << "\n"; + return checkFail(ss.str()); } - return true; + return checkPass("PATH contains only one nix version."); } bool checkProfileRoots(ref<Store> store) @@ -82,17 +98,17 @@ struct CmdDoctor : StoreCommand } if (!dirs.empty()) { - std::cout << "Warning: found profiles outside of " << settings.nixStateDir << "/profiles." << std::endl; - std::cout << "The generation this profile points to might not have a gcroot and could be" << std::endl; - std::cout << "garbage collected, resulting in broken symlinks." << std::endl; - std::cout << std::endl; + std::stringstream ss; + ss << "Found profiles outside of " << settings.nixStateDir << "/profiles.\n" + << "The generation this profile points to might not have a gcroot and could be\n" + << "garbage collected, resulting in broken symlinks.\n\n"; for (auto & dir : dirs) - std::cout << " " << dir << std::endl; - std::cout << std::endl; - return false; + ss << " " << dir << "\n"; + ss << "\n"; + return checkFail(ss.str()); } - return true; + return checkPass("All profiles are gcroots."); } bool checkStoreProtocol(unsigned int storeProto) @@ -102,17 +118,16 @@ struct CmdDoctor : StoreCommand : PROTOCOL_VERSION; if (clientProto != storeProto) { - std::cout << "Warning: protocol version of this client does not match the store." << std::endl; - std::cout << "While this is not necessarily a problem it's recommended to keep the client in" << std::endl; - std::cout << "sync with the daemon." << std::endl; - std::cout << std::endl; - std::cout << "Client protocol: " << formatProtocol(clientProto) << std::endl; - std::cout << "Store protocol: " << formatProtocol(storeProto) << std::endl; - std::cout << std::endl; - return false; + std::stringstream ss; + ss << "Warning: protocol version of this client does not match the store.\n" + << "While this is not necessarily a problem it's recommended to keep the client in\n" + << "sync with the daemon.\n\n" + << "Client protocol: " << formatProtocol(clientProto) << "\n" + << "Store protocol: " << formatProtocol(storeProto) << "\n\n"; + return checkFail(ss.str()); } - return true; + return checkPass("Client protocol matches store protocol."); } }; diff --git a/src/nix/edit.cc b/src/nix/edit.cc index 632a99d11..ca410cd1f 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -31,45 +31,17 @@ struct CmdEdit : InstallableCommand auto v = installable->toValue(*state); - Value * v2; - try { - auto dummyArgs = state->allocBindings(0); - v2 = findAlongAttrPath(*state, "meta.position", *dummyArgs, *v); - } catch (Error &) { - throw Error("package '%s' has no source location information", installable->what()); - } - - auto pos = state->forceString(*v2); - debug("position is %s", pos); - - auto colon = pos.rfind(':'); - if (colon == std::string::npos) - throw Error("cannot parse meta.position attribute '%s'", pos); - - std::string filename(pos, 0, colon); - int lineno; - try { - lineno = std::stoi(std::string(pos, colon + 1)); - } catch (std::invalid_argument & e) { - throw Error("cannot parse line number '%s'", pos); - } - - auto editor = getEnv("EDITOR", "cat"); - - auto args = tokenizeString<Strings>(editor); - - if (editor.find("emacs") != std::string::npos || - editor.find("nano") != std::string::npos || - editor.find("vim") != std::string::npos) - args.push_back(fmt("+%d", lineno)); - - args.push_back(filename); + Pos pos = findDerivationFilename(*state, *v, installable->what()); stopProgressBar(); + auto args = editorFor(pos); + execvp(args.front().c_str(), stringsToCharPtrs(args).data()); - throw SysError("cannot run editor '%s'", editor); + std::string command; + for (const auto &arg : args) command += " '" + arg + "'"; + throw SysError("cannot run command%s", command); } }; diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 0fa1594cc..2b4d1a2c4 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -22,6 +22,7 @@ extern "C" { #include "shared.hh" #include "eval.hh" #include "eval-inline.hh" +#include "attr-path.hh" #include "store-api.hh" #include "common-eval-args.hh" #include "get-drvs.hh" @@ -440,6 +441,7 @@ bool NixRepl::processLine(string line) << " <x> = <expr> Bind expression to variable\n" << " :a <expr> Add attributes from resulting set to scope\n" << " :b <expr> Build derivation\n" + << " :e <expr> Open the derivation in $EDITOR\n" << " :i <expr> Build derivation, then install result into current profile\n" << " :l <path> Load Nix expression and add it to scope\n" << " :p <expr> Evaluate and print expression recursively\n" @@ -466,6 +468,34 @@ bool NixRepl::processLine(string line) reloadFiles(); } + else if (command == ":e" || command == ":edit") { + Value v; + evalString(arg, v); + + Pos pos; + + if (v.type == tPath || v.type == tString) { + PathSet context; + auto filename = state.coerceToString(noPos, v, context); + pos.file = state.symbols.create(filename); + } else if (v.type == tLambda) { + pos = v.lambda.fun->pos; + } else { + // assume it's a derivation + pos = findDerivationFilename(state, v, arg); + } + + // Open in EDITOR + auto args = editorFor(pos); + auto editor = args.front(); + args.pop_front(); + runProgram(editor, args); + + // Reload right after exiting the editor + state.resetFileCache(); + reloadFiles(); + } + else if (command == ":t") { Value v; evalString(arg, v); |