aboutsummaryrefslogtreecommitdiff
path: root/src/libutil
diff options
context:
space:
mode:
authorThéophane Hufschmitt <7226587+thufschmitt@users.noreply.github.com>2022-07-20 10:05:34 +0200
committerGitHub <noreply@github.com>2022-07-20 10:05:34 +0200
commit7ed91d6c6ab86199e7c9703f2852f47d36976d6b (patch)
tree64a829bc84eb0a16d0ed5943dbaf3b2bd3d96610 /src/libutil
parent56f6f3725f4fbeeb7900ae95bd71d559695b3dc5 (diff)
parentfbd0a6c6e2e87f6679fe5cabaddaa877cf3e5a90 (diff)
Merge branch 'master' into parallel-nix-copy
Diffstat (limited to 'src/libutil')
-rw-r--r--src/libutil/args.cc10
-rw-r--r--src/libutil/args.hh9
-rw-r--r--src/libutil/experimental-features.cc1
-rw-r--r--src/libutil/experimental-features.hh1
-rw-r--r--src/libutil/hilite.cc4
-rw-r--r--src/libutil/util.cc36
-rw-r--r--src/libutil/util.hh6
7 files changed, 63 insertions, 4 deletions
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index 4b8c55686..44b63f0f6 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -124,7 +124,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
bool anyCompleted = false;
for (size_t n = 0 ; n < flag.handler.arity; ++n) {
if (pos == end) {
- if (flag.handler.arity == ArityAny) break;
+ if (flag.handler.arity == ArityAny || anyCompleted) break;
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
}
if (auto prefix = needsCompletion(*pos)) {
@@ -362,6 +362,14 @@ bool MultiCommand::processArgs(const Strings & args, bool finish)
return Args::processArgs(args, finish);
}
+void MultiCommand::completionHook()
+{
+ if (command)
+ return command->second->completionHook();
+ else
+ return Args::completionHook();
+}
+
nlohmann::json MultiCommand::toJSON()
{
auto cmds = nlohmann::json::object();
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index fdd036f9a..84866f12b 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -25,6 +25,8 @@ public:
/* Return a short one-line description of the command. */
virtual std::string description() { return ""; }
+ virtual bool forceImpureByDefault() { return false; }
+
/* Return documentation about this command, in Markdown format. */
virtual std::string doc() { return ""; }
@@ -146,6 +148,11 @@ protected:
argument (if any) have been processed. */
virtual void initialFlagsProcessed() {}
+ /* Called after the command line has been processed if we need to generate
+ completions. Useful for commands that need to know the whole command line
+ in order to know what completions to generate. */
+ virtual void completionHook() { }
+
public:
void addFlag(Flag && flag);
@@ -221,6 +228,8 @@ public:
bool processArgs(const Strings & args, bool finish) override;
+ void completionHook() override;
+
nlohmann::json toJSON() override;
};
diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc
index 315de64a4..fa79cca6b 100644
--- a/src/libutil/experimental-features.cc
+++ b/src/libutil/experimental-features.cc
@@ -13,6 +13,7 @@ std::map<ExperimentalFeature, std::string> stringifiedXpFeatures = {
{ Xp::RecursiveNix, "recursive-nix" },
{ Xp::NoUrlLiterals, "no-url-literals" },
{ Xp::FetchClosure, "fetch-closure" },
+ { Xp::ReplFlake, "repl-flake" },
};
const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name)
diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh
index 57512830c..d09ab025c 100644
--- a/src/libutil/experimental-features.hh
+++ b/src/libutil/experimental-features.hh
@@ -22,6 +22,7 @@ enum struct ExperimentalFeature
RecursiveNix,
NoUrlLiterals,
FetchClosure,
+ ReplFlake,
};
/**
diff --git a/src/libutil/hilite.cc b/src/libutil/hilite.cc
index a5991ca39..e5088230d 100644
--- a/src/libutil/hilite.cc
+++ b/src/libutil/hilite.cc
@@ -8,9 +8,9 @@ std::string hiliteMatches(
std::string_view prefix,
std::string_view postfix)
{
- // Avoid copy on zero matches
+ // Avoid extra work on zero matches
if (matches.size() == 0)
- return (std::string) s;
+ return std::string(s);
std::sort(matches.begin(), matches.end(), [](const auto & a, const auto & b) {
return a.position() < b.position();
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 1c19938a8..28df30fef 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -29,6 +29,7 @@
#ifdef __APPLE__
#include <sys/syscall.h>
+#include <mach-o/dyld.h>
#endif
#ifdef __linux__
@@ -574,6 +575,20 @@ Path getHome()
static Path homeDir = []()
{
auto homeDir = getEnv("HOME");
+ if (homeDir) {
+ // Only use $HOME if doesn't exist or is owned by the current user.
+ struct stat st;
+ int result = stat(homeDir->c_str(), &st);
+ if (result != 0) {
+ if (errno != ENOENT) {
+ warn("couldn't stat $HOME ('%s') for reason other than not existing ('%d'), falling back to the one defined in the 'passwd' file", *homeDir, errno);
+ homeDir.reset();
+ }
+ } else if (st.st_uid != geteuid()) {
+ warn("$HOME ('%s') is not owned by you, falling back to the one defined in the 'passwd' file", *homeDir);
+ homeDir.reset();
+ }
+ }
if (!homeDir) {
std::vector<char> buf(16384);
struct passwd pwbuf;
@@ -619,6 +634,27 @@ Path getDataDir()
}
+std::optional<Path> getSelfExe()
+{
+ static auto cached = []() -> std::optional<Path>
+ {
+ #if __linux__
+ return readLink("/proc/self/exe");
+ #elif __APPLE__
+ char buf[1024];
+ uint32_t size = sizeof(buf);
+ if (_NSGetExecutablePath(buf, &size) == 0)
+ return buf;
+ else
+ return std::nullopt;
+ #else
+ return std::nullopt;
+ #endif
+ }();
+ return cached;
+}
+
+
Paths createDirs(const Path & path)
{
Paths created;
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index 90418b04d..d3ed15b0b 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -149,10 +149,14 @@ std::vector<Path> getConfigDirs();
/* Return $XDG_DATA_HOME or $HOME/.local/share. */
Path getDataDir();
+/* Return the path of the current executable. */
+std::optional<Path> getSelfExe();
+
/* Create a directory and all its parents, if necessary. Returns the
list of created directories, in order of creation. */
Paths createDirs(const Path & path);
-inline Paths createDirs(PathView path) {
+inline Paths createDirs(PathView path)
+{
return createDirs(Path(path));
}