mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-30 09:36:15 +02:00
Extend internal API docs, part 2
Picking up from #8111. Co-authored-by: Eelco Dolstra <edolstra@gmail.com>
This commit is contained in:
parent
8ae9d66940
commit
abd5e7dec0
32 changed files with 640 additions and 359 deletions
|
@ -3,8 +3,15 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An InstallableCommand where the single positional argument must be an
|
||||||
|
* InstallableValue in particular.
|
||||||
|
*/
|
||||||
struct InstallableValueCommand : InstallableCommand
|
struct InstallableValueCommand : InstallableCommand
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Entry point to this command
|
||||||
|
*/
|
||||||
virtual void run(ref<Store> store, ref<InstallableValue> installable) = 0;
|
virtual void run(ref<Store> store, ref<InstallableValue> installable) = 0;
|
||||||
|
|
||||||
void run(ref<Store> store, ref<Installable> installable) override;
|
void run(ref<Store> store, ref<Installable> installable) override;
|
||||||
|
|
|
@ -87,39 +87,56 @@ struct FileTransfer
|
||||||
{
|
{
|
||||||
virtual ~FileTransfer() { }
|
virtual ~FileTransfer() { }
|
||||||
|
|
||||||
/* Enqueue a data transfer request, returning a future to the result of
|
/**
|
||||||
the download. The future may throw a FileTransferError
|
* Enqueue a data transfer request, returning a future to the result of
|
||||||
exception. */
|
* the download. The future may throw a FileTransferError
|
||||||
|
* exception.
|
||||||
|
*/
|
||||||
virtual void enqueueFileTransfer(const FileTransferRequest & request,
|
virtual void enqueueFileTransfer(const FileTransferRequest & request,
|
||||||
Callback<FileTransferResult> callback) = 0;
|
Callback<FileTransferResult> callback) = 0;
|
||||||
|
|
||||||
std::future<FileTransferResult> enqueueFileTransfer(const FileTransferRequest & request);
|
std::future<FileTransferResult> enqueueFileTransfer(const FileTransferRequest & request);
|
||||||
|
|
||||||
/* Synchronously download a file. */
|
/**
|
||||||
|
* Synchronously download a file.
|
||||||
|
*/
|
||||||
FileTransferResult download(const FileTransferRequest & request);
|
FileTransferResult download(const FileTransferRequest & request);
|
||||||
|
|
||||||
/* Synchronously upload a file. */
|
/**
|
||||||
|
* Synchronously upload a file.
|
||||||
|
*/
|
||||||
FileTransferResult upload(const FileTransferRequest & request);
|
FileTransferResult upload(const FileTransferRequest & request);
|
||||||
|
|
||||||
/* Download a file, writing its data to a sink. The sink will be
|
/**
|
||||||
invoked on the thread of the caller. */
|
* Download a file, writing its data to a sink. The sink will be
|
||||||
|
* invoked on the thread of the caller.
|
||||||
|
*/
|
||||||
void download(FileTransferRequest && request, Sink & sink);
|
void download(FileTransferRequest && request, Sink & sink);
|
||||||
|
|
||||||
enum Error { NotFound, Forbidden, Misc, Transient, Interrupted };
|
enum Error { NotFound, Forbidden, Misc, Transient, Interrupted };
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Return a shared FileTransfer object. Using this object is preferred
|
/**
|
||||||
because it enables connection reuse and HTTP/2 multiplexing. */
|
* @return a shared FileTransfer object.
|
||||||
|
*
|
||||||
|
* Using this object is preferred because it enables connection reuse
|
||||||
|
* and HTTP/2 multiplexing.
|
||||||
|
*/
|
||||||
ref<FileTransfer> getFileTransfer();
|
ref<FileTransfer> getFileTransfer();
|
||||||
|
|
||||||
/* Return a new FileTransfer object. */
|
/**
|
||||||
|
* @return a new FileTransfer object
|
||||||
|
*
|
||||||
|
* Prefer getFileTransfer() to this; see its docs for why.
|
||||||
|
*/
|
||||||
ref<FileTransfer> makeFileTransfer();
|
ref<FileTransfer> makeFileTransfer();
|
||||||
|
|
||||||
class FileTransferError : public Error
|
class FileTransferError : public Error
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileTransfer::Error error;
|
FileTransfer::Error error;
|
||||||
std::optional<std::string> response; // intentionally optional
|
/// intentionally optional
|
||||||
|
std::optional<std::string> response;
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args);
|
FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args);
|
||||||
|
|
|
@ -4,6 +4,13 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to try downcasting a Store with a nice method if it fails.
|
||||||
|
*
|
||||||
|
* This is basically an alternative to the user-facing part of
|
||||||
|
* Store::unsupported that allows us to still have a nice message but
|
||||||
|
* better interface design.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T & require(Store & store)
|
T & require(Store & store)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,6 +14,10 @@ namespace nix {
|
||||||
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
#define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration of all the request types for the "worker protocol", used
|
||||||
|
* by unix:// and ssh-ng:// stores.
|
||||||
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
wopIsValidPath = 1,
|
wopIsValidPath = 1,
|
||||||
wopHasSubstitutes = 3,
|
wopHasSubstitutes = 3,
|
||||||
|
@ -74,7 +78,12 @@ typedef enum {
|
||||||
class Store;
|
class Store;
|
||||||
struct Source;
|
struct Source;
|
||||||
|
|
||||||
/* To guide overloading */
|
/**
|
||||||
|
* Used to guide overloading
|
||||||
|
*
|
||||||
|
* See https://en.cppreference.com/w/cpp/language/adl for the broader
|
||||||
|
* concept of what is going on here.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Phantom {};
|
struct Phantom {};
|
||||||
|
|
||||||
|
@ -103,18 +112,19 @@ MAKE_WORKER_PROTO(X_, Y_);
|
||||||
#undef X_
|
#undef X_
|
||||||
#undef Y_
|
#undef Y_
|
||||||
|
|
||||||
/* These use the empty string for the null case, relying on the fact
|
/**
|
||||||
that the underlying types never serialize to the empty string.
|
* These use the empty string for the null case, relying on the fact
|
||||||
|
* that the underlying types never serialize to the empty string.
|
||||||
We do this instead of a generic std::optional<T> instance because
|
*
|
||||||
ordinal tags (0 or 1, here) are a bit of a compatability hazard. For
|
* We do this instead of a generic std::optional<T> instance because
|
||||||
the same reason, we don't have a std::variant<T..> instances (ordinal
|
* ordinal tags (0 or 1, here) are a bit of a compatability hazard. For
|
||||||
tags 0...n).
|
* the same reason, we don't have a std::variant<T..> instances (ordinal
|
||||||
|
* tags 0...n).
|
||||||
We could the generic instances and then these as specializations for
|
*
|
||||||
compatability, but that's proven a bit finnicky, and also makes the
|
* We could the generic instances and then these as specializations for
|
||||||
worker protocol harder to implement in other languages where such
|
* compatability, but that's proven a bit finnicky, and also makes the
|
||||||
specializations may not be allowed.
|
* worker protocol harder to implement in other languages where such
|
||||||
|
* specializations may not be allowed.
|
||||||
*/
|
*/
|
||||||
MAKE_WORKER_PROTO(, std::optional<StorePath>);
|
MAKE_WORKER_PROTO(, std::optional<StorePath>);
|
||||||
MAKE_WORKER_PROTO(, std::optional<ContentAddress>);
|
MAKE_WORKER_PROTO(, std::optional<ContentAddress>);
|
||||||
|
|
|
@ -7,54 +7,71 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
/* dumpPath creates a Nix archive of the specified path. The format
|
/**
|
||||||
is as follows:
|
* dumpPath creates a Nix archive of the specified path.
|
||||||
|
*
|
||||||
IF path points to a REGULAR FILE:
|
* @param path the file system data to dump. Dumping is recursive so if
|
||||||
dump(path) = attrs(
|
* this is a directory we dump it and all its children.
|
||||||
[ ("type", "regular")
|
*
|
||||||
, ("contents", contents(path))
|
* @param [out] sink The serialised archive is fed into this sink.
|
||||||
])
|
*
|
||||||
|
* @param filter Can be used to skip certain files.
|
||||||
IF path points to a DIRECTORY:
|
*
|
||||||
dump(path) = attrs(
|
* The format is as follows:
|
||||||
[ ("type", "directory")
|
*
|
||||||
, ("entries", concat(map(f, sort(entries(path)))))
|
* IF path points to a REGULAR FILE:
|
||||||
])
|
* dump(path) = attrs(
|
||||||
where f(fn) = attrs(
|
* [ ("type", "regular")
|
||||||
[ ("name", fn)
|
* , ("contents", contents(path))
|
||||||
, ("file", dump(path + "/" + fn))
|
* ])
|
||||||
])
|
*
|
||||||
|
* IF path points to a DIRECTORY:
|
||||||
where:
|
* dump(path) = attrs(
|
||||||
|
* [ ("type", "directory")
|
||||||
attrs(as) = concat(map(attr, as)) + encN(0)
|
* , ("entries", concat(map(f, sort(entries(path)))))
|
||||||
attrs((a, b)) = encS(a) + encS(b)
|
* ])
|
||||||
|
* where f(fn) = attrs(
|
||||||
encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)
|
* [ ("name", fn)
|
||||||
|
* , ("file", dump(path + "/" + fn))
|
||||||
encN(n) = 64-bit little-endian encoding of n.
|
* ])
|
||||||
|
*
|
||||||
contents(path) = the contents of a regular file.
|
* where:
|
||||||
|
*
|
||||||
sort(strings) = lexicographic sort by 8-bit value (strcmp).
|
* attrs(as) = concat(map(attr, as)) + encN(0)
|
||||||
|
* attrs((a, b)) = encS(a) + encS(b)
|
||||||
entries(path) = the entries of a directory, without `.' and
|
*
|
||||||
`..'.
|
* encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)
|
||||||
|
*
|
||||||
`+' denotes string concatenation. */
|
* encN(n) = 64-bit little-endian encoding of n.
|
||||||
|
*
|
||||||
|
* contents(path) = the contents of a regular file.
|
||||||
|
*
|
||||||
|
* sort(strings) = lexicographic sort by 8-bit value (strcmp).
|
||||||
|
*
|
||||||
|
* entries(path) = the entries of a directory, without `.' and
|
||||||
|
* `..'.
|
||||||
|
*
|
||||||
|
* `+' denotes string concatenation.
|
||||||
|
*/
|
||||||
void dumpPath(const Path & path, Sink & sink,
|
void dumpPath(const Path & path, Sink & sink,
|
||||||
PathFilter & filter = defaultPathFilter);
|
PathFilter & filter = defaultPathFilter);
|
||||||
|
|
||||||
/* Same as `void dumpPath()`, but returns the last modified date of the path */
|
/**
|
||||||
|
* Same as dumpPath(), but returns the last modified date of the path.
|
||||||
|
*/
|
||||||
time_t dumpPathAndGetMtime(const Path & path, Sink & sink,
|
time_t dumpPathAndGetMtime(const Path & path, Sink & sink,
|
||||||
PathFilter & filter = defaultPathFilter);
|
PathFilter & filter = defaultPathFilter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump an archive with a single file with these contents.
|
||||||
|
*
|
||||||
|
* @param s Contents of the file.
|
||||||
|
*/
|
||||||
void dumpString(std::string_view s, Sink & sink);
|
void dumpString(std::string_view s, Sink & sink);
|
||||||
|
|
||||||
/* FIXME: fix this API, it sucks. */
|
/**
|
||||||
|
* \todo Fix this API, it sucks.
|
||||||
|
*/
|
||||||
struct ParseSink
|
struct ParseSink
|
||||||
{
|
{
|
||||||
virtual void createDirectory(const Path & path) { };
|
virtual void createDirectory(const Path & path) { };
|
||||||
|
@ -68,8 +85,10 @@ struct ParseSink
|
||||||
virtual void createSymlink(const Path & path, const std::string & target) { };
|
virtual void createSymlink(const Path & path, const std::string & target) { };
|
||||||
};
|
};
|
||||||
|
|
||||||
/* If the NAR archive contains a single file at top-level, then save
|
/**
|
||||||
the contents of the file to `s'. Otherwise barf. */
|
* If the NAR archive contains a single file at top-level, then save
|
||||||
|
* the contents of the file to `s'. Otherwise barf.
|
||||||
|
*/
|
||||||
struct RetrieveRegularNARSink : ParseSink
|
struct RetrieveRegularNARSink : ParseSink
|
||||||
{
|
{
|
||||||
bool regular = true;
|
bool regular = true;
|
||||||
|
@ -97,7 +116,9 @@ void parseDump(ParseSink & sink, Source & source);
|
||||||
|
|
||||||
void restorePath(const Path & path, Source & source);
|
void restorePath(const Path & path, Source & source);
|
||||||
|
|
||||||
/* Read a NAR from 'source' and write it to 'sink'. */
|
/**
|
||||||
|
* Read a NAR from 'source' and write it to 'sink'.
|
||||||
|
*/
|
||||||
void copyNAR(Source & source, Sink & sink);
|
void copyNAR(Source & source, Sink & sink);
|
||||||
|
|
||||||
void copyPath(const Path & from, const Path & to);
|
void copyPath(const Path & from, const Path & to);
|
||||||
|
|
|
@ -18,16 +18,22 @@ class Args
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Parse the command line, throwing a UsageError if something goes
|
/**
|
||||||
wrong. */
|
* Parse the command line, throwing a UsageError if something goes
|
||||||
|
* wrong.
|
||||||
|
*/
|
||||||
void parseCmdline(const Strings & cmdline);
|
void parseCmdline(const Strings & cmdline);
|
||||||
|
|
||||||
/* Return a short one-line description of the command. */
|
/**
|
||||||
|
* Return a short one-line description of the command.
|
||||||
|
*/
|
||||||
virtual std::string description() { return ""; }
|
virtual std::string description() { return ""; }
|
||||||
|
|
||||||
virtual bool forceImpureByDefault() { return false; }
|
virtual bool forceImpureByDefault() { return false; }
|
||||||
|
|
||||||
/* Return documentation about this command, in Markdown format. */
|
/**
|
||||||
|
* Return documentation about this command, in Markdown format.
|
||||||
|
*/
|
||||||
virtual std::string doc() { return ""; }
|
virtual std::string doc() { return ""; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -146,13 +152,17 @@ protected:
|
||||||
|
|
||||||
std::set<std::string> hiddenCategories;
|
std::set<std::string> hiddenCategories;
|
||||||
|
|
||||||
/* Called after all command line flags before the first non-flag
|
/**
|
||||||
argument (if any) have been processed. */
|
* Called after all command line flags before the first non-flag
|
||||||
|
* argument (if any) have been processed.
|
||||||
|
*/
|
||||||
virtual void initialFlagsProcessed() {}
|
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
|
* Called after the command line has been processed if we need to generate
|
||||||
in order to know what completions 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() { }
|
virtual void completionHook() { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -166,7 +176,9 @@ public:
|
||||||
expectedArgs.emplace_back(std::move(arg));
|
expectedArgs.emplace_back(std::move(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expect a string argument. */
|
/**
|
||||||
|
* Expect a string argument.
|
||||||
|
*/
|
||||||
void expectArg(const std::string & label, std::string * dest, bool optional = false)
|
void expectArg(const std::string & label, std::string * dest, bool optional = false)
|
||||||
{
|
{
|
||||||
expectArgs({
|
expectArgs({
|
||||||
|
@ -176,7 +188,9 @@ public:
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expect 0 or more arguments. */
|
/**
|
||||||
|
* Expect 0 or more arguments.
|
||||||
|
*/
|
||||||
void expectArgs(const std::string & label, std::vector<std::string> * dest)
|
void expectArgs(const std::string & label, std::vector<std::string> * dest)
|
||||||
{
|
{
|
||||||
expectArgs({
|
expectArgs({
|
||||||
|
@ -202,14 +216,19 @@ private:
|
||||||
std::set<ExperimentalFeature> flagExperimentalFeatures;
|
std::set<ExperimentalFeature> flagExperimentalFeatures;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A command is an argument parser that can be executed by calling its
|
/**
|
||||||
run() method. */
|
* A command is an argument parser that can be executed by calling its
|
||||||
|
* run() method.
|
||||||
|
*/
|
||||||
struct Command : virtual public Args
|
struct Command : virtual public Args
|
||||||
{
|
{
|
||||||
friend class MultiCommand;
|
friend class MultiCommand;
|
||||||
|
|
||||||
virtual ~Command() { }
|
virtual ~Command() { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point to the command
|
||||||
|
*/
|
||||||
virtual void run() = 0;
|
virtual void run() = 0;
|
||||||
|
|
||||||
typedef int Category;
|
typedef int Category;
|
||||||
|
@ -221,8 +240,10 @@ struct Command : virtual public Args
|
||||||
|
|
||||||
typedef std::map<std::string, std::function<ref<Command>()>> Commands;
|
typedef std::map<std::string, std::function<ref<Command>()>> Commands;
|
||||||
|
|
||||||
/* An argument parser that supports multiple subcommands,
|
/**
|
||||||
i.e. ‘<command> <subcommand>’. */
|
* An argument parser that supports multiple subcommands,
|
||||||
|
* i.e. ‘<command> <subcommand>’.
|
||||||
|
*/
|
||||||
class MultiCommand : virtual public Args
|
class MultiCommand : virtual public Args
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -230,7 +251,9 @@ public:
|
||||||
|
|
||||||
std::map<Command::Category, std::string> categories;
|
std::map<Command::Category, std::string> categories;
|
||||||
|
|
||||||
// Selected command, if any.
|
/**
|
||||||
|
* Selected command, if any.
|
||||||
|
*/
|
||||||
std::optional<std::pair<std::string, ref<Command>>> command;
|
std::optional<std::pair<std::string, ref<Command>>> command;
|
||||||
|
|
||||||
MultiCommand(const Commands & commands);
|
MultiCommand(const Commands & commands);
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* A callback is a wrapper around a lambda that accepts a valid of
|
/**
|
||||||
type T or an exception. (We abuse std::future<T> to pass the value or
|
* A callback is a wrapper around a lambda that accepts a valid of
|
||||||
exception.) */
|
* type T or an exception. (We abuse std::future<T> to pass the value or
|
||||||
|
* exception.)
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Callback
|
class Callback
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,28 +8,31 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* A canonical representation of a path. It ensures the following:
|
/**
|
||||||
|
* A canonical representation of a path. It ensures the following:
|
||||||
- It always starts with a slash.
|
*
|
||||||
|
* - It always starts with a slash.
|
||||||
- It never ends with a slash, except if the path is "/".
|
*
|
||||||
|
* - It never ends with a slash, except if the path is "/".
|
||||||
- A slash is never followed by a slash (i.e. no empty components).
|
*
|
||||||
|
* - A slash is never followed by a slash (i.e. no empty components).
|
||||||
- There are no components equal to '.' or '..'.
|
*
|
||||||
|
* - There are no components equal to '.' or '..'.
|
||||||
Note that the path does not need to correspond to an actually
|
*
|
||||||
existing path, and there is no guarantee that symlinks are
|
* Note that the path does not need to correspond to an actually
|
||||||
resolved.
|
* existing path, and there is no guarantee that symlinks are
|
||||||
*/
|
* resolved.
|
||||||
|
*/
|
||||||
class CanonPath
|
class CanonPath
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* Construct a canon path from a non-canonical path. Any '.', '..'
|
/**
|
||||||
or empty components are removed. */
|
* Construct a canon path from a non-canonical path. Any '.', '..'
|
||||||
|
* or empty components are removed.
|
||||||
|
*/
|
||||||
CanonPath(std::string_view raw);
|
CanonPath(std::string_view raw);
|
||||||
|
|
||||||
explicit CanonPath(const char * raw)
|
explicit CanonPath(const char * raw)
|
||||||
|
@ -44,9 +47,11 @@ public:
|
||||||
|
|
||||||
static CanonPath root;
|
static CanonPath root;
|
||||||
|
|
||||||
/* If `raw` starts with a slash, return
|
/**
|
||||||
`CanonPath(raw)`. Otherwise return a `CanonPath` representing
|
* If `raw` starts with a slash, return
|
||||||
`root + "/" + raw`. */
|
* `CanonPath(raw)`. Otherwise return a `CanonPath` representing
|
||||||
|
* `root + "/" + raw`.
|
||||||
|
*/
|
||||||
CanonPath(std::string_view raw, const CanonPath & root);
|
CanonPath(std::string_view raw, const CanonPath & root);
|
||||||
|
|
||||||
bool isRoot() const
|
bool isRoot() const
|
||||||
|
@ -58,8 +63,10 @@ public:
|
||||||
const std::string & abs() const
|
const std::string & abs() const
|
||||||
{ return path; }
|
{ return path; }
|
||||||
|
|
||||||
/* Like abs(), but return an empty string if this path is
|
/**
|
||||||
'/'. Thus the returned string never ends in a slash. */
|
* Like abs(), but return an empty string if this path is
|
||||||
|
* '/'. Thus the returned string never ends in a slash.
|
||||||
|
*/
|
||||||
const std::string & absOrEmpty() const
|
const std::string & absOrEmpty() const
|
||||||
{
|
{
|
||||||
const static std::string epsilon;
|
const static std::string epsilon;
|
||||||
|
@ -107,7 +114,9 @@ public:
|
||||||
|
|
||||||
std::optional<CanonPath> parent() const;
|
std::optional<CanonPath> parent() const;
|
||||||
|
|
||||||
/* Remove the last component. Panics if this path is the root. */
|
/**
|
||||||
|
* Remove the last component. Panics if this path is the root.
|
||||||
|
*/
|
||||||
void pop();
|
void pop();
|
||||||
|
|
||||||
std::optional<std::string_view> dirOf() const
|
std::optional<std::string_view> dirOf() const
|
||||||
|
@ -128,10 +137,12 @@ public:
|
||||||
bool operator != (const CanonPath & x) const
|
bool operator != (const CanonPath & x) const
|
||||||
{ return path != x.path; }
|
{ return path != x.path; }
|
||||||
|
|
||||||
/* Compare paths lexicographically except that path separators
|
/**
|
||||||
are sorted before any other character. That is, in the sorted order
|
* Compare paths lexicographically except that path separators
|
||||||
a directory is always followed directly by its children. For
|
* are sorted before any other character. That is, in the sorted order
|
||||||
instance, 'foo' < 'foo/bar' < 'foo!'. */
|
* a directory is always followed directly by its children. For
|
||||||
|
* instance, 'foo' < 'foo/bar' < 'foo!'.
|
||||||
|
*/
|
||||||
bool operator < (const CanonPath & x) const
|
bool operator < (const CanonPath & x) const
|
||||||
{
|
{
|
||||||
auto i = path.begin();
|
auto i = path.begin();
|
||||||
|
@ -147,27 +158,37 @@ public:
|
||||||
return i == path.end() && j != x.path.end();
|
return i == path.end() && j != x.path.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return true if `this` is equal to `parent` or a child of
|
/**
|
||||||
`parent`. */
|
* Return true if `this` is equal to `parent` or a child of
|
||||||
|
* `parent`.
|
||||||
|
*/
|
||||||
bool isWithin(const CanonPath & parent) const;
|
bool isWithin(const CanonPath & parent) const;
|
||||||
|
|
||||||
CanonPath removePrefix(const CanonPath & prefix) const;
|
CanonPath removePrefix(const CanonPath & prefix) const;
|
||||||
|
|
||||||
/* Append another path to this one. */
|
/**
|
||||||
|
* Append another path to this one.
|
||||||
|
*/
|
||||||
void extend(const CanonPath & x);
|
void extend(const CanonPath & x);
|
||||||
|
|
||||||
/* Concatenate two paths. */
|
/**
|
||||||
|
* Concatenate two paths.
|
||||||
|
*/
|
||||||
CanonPath operator + (const CanonPath & x) const;
|
CanonPath operator + (const CanonPath & x) const;
|
||||||
|
|
||||||
/* Add a path component to this one. It must not contain any slashes. */
|
/**
|
||||||
|
* Add a path component to this one. It must not contain any slashes.
|
||||||
|
*/
|
||||||
void push(std::string_view c);
|
void push(std::string_view c);
|
||||||
|
|
||||||
CanonPath operator + (std::string_view c) const;
|
CanonPath operator + (std::string_view c) const;
|
||||||
|
|
||||||
/* Check whether access to this path is allowed, which is the case
|
/**
|
||||||
if 1) `this` is within any of the `allowed` paths; or 2) any of
|
* Check whether access to this path is allowed, which is the case
|
||||||
the `allowed` paths are within `this`. (The latter condition
|
* if 1) `this` is within any of the `allowed` paths; or 2) any of
|
||||||
ensures access to the parents of allowed paths.) */
|
* the `allowed` paths are within `this`. (The latter condition
|
||||||
|
* ensures access to the parents of allowed paths.)
|
||||||
|
*/
|
||||||
bool isAllowed(const std::set<CanonPath> & allowed) const;
|
bool isAllowed(const std::set<CanonPath> & allowed) const;
|
||||||
|
|
||||||
/* Return a representation `x` of `path` relative to `this`, i.e.
|
/* Return a representation `x` of `path` relative to `this`, i.e.
|
||||||
|
|
|
@ -18,10 +18,12 @@ struct CgroupStats
|
||||||
std::optional<std::chrono::microseconds> cpuUser, cpuSystem;
|
std::optional<std::chrono::microseconds> cpuUser, cpuSystem;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Destroy the cgroup denoted by 'path'. The postcondition is that
|
/**
|
||||||
'path' does not exist, and thus any processes in the cgroup have
|
* Destroy the cgroup denoted by 'path'. The postcondition is that
|
||||||
been killed. Also return statistics from the cgroup just before
|
* 'path' does not exist, and thus any processes in the cgroup have
|
||||||
destruction. */
|
* been killed. Also return statistics from the cgroup just before
|
||||||
|
* destruction.
|
||||||
|
*/
|
||||||
CgroupStats destroyCgroup(const Path & cgroup);
|
CgroupStats destroyCgroup(const Path & cgroup);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,24 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* Provides an indexable container like vector<> with memory overhead
|
/**
|
||||||
guarantees like list<> by allocating storage in chunks of ChunkSize
|
* Provides an indexable container like vector<> with memory overhead
|
||||||
elements instead of using a contiguous memory allocation like vector<>
|
* guarantees like list<> by allocating storage in chunks of ChunkSize
|
||||||
does. Not using a single vector that is resized reduces memory overhead
|
* elements instead of using a contiguous memory allocation like vector<>
|
||||||
on large data sets by on average (growth factor)/2, mostly
|
* does. Not using a single vector that is resized reduces memory overhead
|
||||||
eliminates copies within the vector during resizing, and provides stable
|
* on large data sets by on average (growth factor)/2, mostly
|
||||||
references to its elements. */
|
* eliminates copies within the vector during resizing, and provides stable
|
||||||
|
* references to its elements.
|
||||||
|
*/
|
||||||
template<typename T, size_t ChunkSize>
|
template<typename T, size_t ChunkSize>
|
||||||
class ChunkedVector {
|
class ChunkedVector {
|
||||||
private:
|
private:
|
||||||
uint32_t size_ = 0;
|
uint32_t size_ = 0;
|
||||||
std::vector<std::vector<T>> chunks;
|
std::vector<std::vector<T>> chunks;
|
||||||
|
|
||||||
/* keep this out of the ::add hot path */
|
/**
|
||||||
|
* Keep this out of the ::add hot path
|
||||||
|
*/
|
||||||
[[gnu::noinline]]
|
[[gnu::noinline]]
|
||||||
auto & addChunk()
|
auto & addChunk()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/* Awfull hacky generation of the comparison operators by doing a lexicographic
|
/**
|
||||||
|
* Awful hacky generation of the comparison operators by doing a lexicographic
|
||||||
* comparison between the choosen fields.
|
* comparison between the choosen fields.
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
|
|
|
@ -124,21 +124,21 @@ public:
|
||||||
void reapplyUnknownSettings();
|
void reapplyUnknownSettings();
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A class to simplify providing configuration settings. The typical
|
/**
|
||||||
use is to inherit Config and add Setting<T> members:
|
* A class to simplify providing configuration settings. The typical
|
||||||
|
* use is to inherit Config and add Setting<T> members:
|
||||||
class MyClass : private Config
|
*
|
||||||
{
|
* class MyClass : private Config
|
||||||
Setting<int> foo{this, 123, "foo", "the number of foos to use"};
|
* {
|
||||||
Setting<std::string> bar{this, "blabla", "bar", "the name of the bar"};
|
* Setting<int> foo{this, 123, "foo", "the number of foos to use"};
|
||||||
|
* Setting<std::string> bar{this, "blabla", "bar", "the name of the bar"};
|
||||||
MyClass() : Config(readConfigFile("/etc/my-app.conf"))
|
*
|
||||||
{
|
* MyClass() : Config(readConfigFile("/etc/my-app.conf"))
|
||||||
std::cout << foo << "\n"; // will print 123 unless overridden
|
* {
|
||||||
}
|
* std::cout << foo << "\n"; // will print 123 unless overridden
|
||||||
};
|
* }
|
||||||
*/
|
* };
|
||||||
|
*/
|
||||||
class Config : public AbstractConfig
|
class Config : public AbstractConfig
|
||||||
{
|
{
|
||||||
friend class AbstractSetting;
|
friend class AbstractSetting;
|
||||||
|
@ -228,7 +228,9 @@ protected:
|
||||||
bool isOverridden() const { return overridden; }
|
bool isOverridden() const { return overridden; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A setting of type T. */
|
/**
|
||||||
|
* A setting of type T.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class BaseSetting : public AbstractSetting
|
class BaseSetting : public AbstractSetting
|
||||||
{
|
{
|
||||||
|
@ -311,8 +313,10 @@ public:
|
||||||
void operator =(const T & v) { this->assign(v); }
|
void operator =(const T & v) { this->assign(v); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A special setting for Paths. These are automatically canonicalised
|
/**
|
||||||
(e.g. "/foo//bar/" becomes "/foo/bar"). */
|
* A special setting for Paths. These are automatically canonicalised
|
||||||
|
* (e.g. "/foo//bar/" becomes "/foo/bar").
|
||||||
|
*/
|
||||||
class PathSetting : public BaseSetting<Path>
|
class PathSetting : public BaseSetting<Path>
|
||||||
{
|
{
|
||||||
bool allowEmpty;
|
bool allowEmpty;
|
||||||
|
|
|
@ -54,20 +54,26 @@ typedef enum {
|
||||||
lvlVomit
|
lvlVomit
|
||||||
} Verbosity;
|
} Verbosity;
|
||||||
|
|
||||||
// the lines of code surrounding an error.
|
/**
|
||||||
|
* The lines of code surrounding an error.
|
||||||
|
*/
|
||||||
struct LinesOfCode {
|
struct LinesOfCode {
|
||||||
std::optional<std::string> prevLineOfCode;
|
std::optional<std::string> prevLineOfCode;
|
||||||
std::optional<std::string> errLineOfCode;
|
std::optional<std::string> errLineOfCode;
|
||||||
std::optional<std::string> nextLineOfCode;
|
std::optional<std::string> nextLineOfCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* An abstract type that represents a location in a source file. */
|
/**
|
||||||
|
* An abstract type that represents a location in a source file.
|
||||||
|
*/
|
||||||
struct AbstractPos
|
struct AbstractPos
|
||||||
{
|
{
|
||||||
uint32_t line = 0;
|
uint32_t line = 0;
|
||||||
uint32_t column = 0;
|
uint32_t column = 0;
|
||||||
|
|
||||||
/* Return the contents of the source file. */
|
/**
|
||||||
|
* Return the contents of the source file.
|
||||||
|
*/
|
||||||
virtual std::optional<std::string> getSource() const
|
virtual std::optional<std::string> getSource() const
|
||||||
{ return std::nullopt; };
|
{ return std::nullopt; };
|
||||||
|
|
||||||
|
@ -104,8 +110,10 @@ struct ErrorInfo {
|
||||||
|
|
||||||
std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace);
|
std::ostream & showErrorInfo(std::ostream & out, const ErrorInfo & einfo, bool showTrace);
|
||||||
|
|
||||||
/* BaseError should generally not be caught, as it has Interrupted as
|
/**
|
||||||
a subclass. Catch Error instead. */
|
* BaseError should generally not be caught, as it has Interrupted as
|
||||||
|
* a subclass. Catch Error instead.
|
||||||
|
*/
|
||||||
class BaseError : public std::exception
|
class BaseError : public std::exception
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace nix {
|
||||||
*
|
*
|
||||||
* If you update this, don’t forget to also change the map defining their
|
* If you update this, don’t forget to also change the map defining their
|
||||||
* string representation in the corresponding `.cc` file.
|
* string representation in the corresponding `.cc` file.
|
||||||
**/
|
*/
|
||||||
enum struct ExperimentalFeature
|
enum struct ExperimentalFeature
|
||||||
{
|
{
|
||||||
CaDerivations,
|
CaDerivations,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/* A trivial class to run a function at the end of a scope. */
|
/**
|
||||||
|
* A trivial class to run a function at the end of a scope.
|
||||||
|
*/
|
||||||
template<typename Fn>
|
template<typename Fn>
|
||||||
class Finally
|
class Finally
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,20 +8,25 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
/* Inherit some names from other namespaces for convenience. */
|
/**
|
||||||
|
* Inherit some names from other namespaces for convenience.
|
||||||
|
*/
|
||||||
using boost::format;
|
using boost::format;
|
||||||
|
|
||||||
|
|
||||||
/* A variadic template that does nothing. Useful to call a function
|
/**
|
||||||
for all variadic arguments but ignoring the result. */
|
* A variadic template that does nothing. Useful to call a function
|
||||||
|
* for all variadic arguments but ignoring the result.
|
||||||
|
*/
|
||||||
struct nop { template<typename... T> nop(T...) {} };
|
struct nop { template<typename... T> nop(T...) {} };
|
||||||
|
|
||||||
|
|
||||||
/* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
|
/**
|
||||||
equivalent to ‘boost::format(format) % a_0 % ... %
|
* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
|
||||||
... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
|
* equivalent to ‘boost::format(format) % a_0 % ... %
|
||||||
takes place). */
|
* ... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
|
||||||
|
* takes place).
|
||||||
|
*/
|
||||||
template<class F>
|
template<class F>
|
||||||
inline void formatHelper(F & f)
|
inline void formatHelper(F & f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,21 +8,23 @@ namespace nix {
|
||||||
|
|
||||||
namespace git {
|
namespace git {
|
||||||
|
|
||||||
// A line from the output of `git ls-remote --symref`.
|
/**
|
||||||
//
|
* A line from the output of `git ls-remote --symref`.
|
||||||
// These can be of two kinds:
|
*
|
||||||
//
|
* These can be of two kinds:
|
||||||
// - Symbolic references of the form
|
*
|
||||||
//
|
* - Symbolic references of the form
|
||||||
// ref: {target} {reference}
|
*
|
||||||
//
|
* ref: {target} {reference}
|
||||||
// where {target} is itself a reference and {reference} is optional
|
*
|
||||||
//
|
* where {target} is itself a reference and {reference} is optional
|
||||||
// - Object references of the form
|
*
|
||||||
//
|
* - Object references of the form
|
||||||
// {target} {reference}
|
*
|
||||||
//
|
* {target} {reference}
|
||||||
// where {target} is a commit id and {reference} is mandatory
|
*
|
||||||
|
* where {target} is a commit id and {reference} is mandatory
|
||||||
|
*/
|
||||||
struct LsRemoteRefLine {
|
struct LsRemoteRefLine {
|
||||||
enum struct Kind {
|
enum struct Kind {
|
||||||
Symbolic,
|
Symbolic,
|
||||||
|
|
|
@ -33,62 +33,86 @@ struct Hash
|
||||||
|
|
||||||
HashType type;
|
HashType type;
|
||||||
|
|
||||||
/* Create a zero-filled hash object. */
|
/**
|
||||||
|
* Create a zero-filled hash object.
|
||||||
|
*/
|
||||||
Hash(HashType type);
|
Hash(HashType type);
|
||||||
|
|
||||||
/* Parse the hash from a string representation in the format
|
/**
|
||||||
"[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a
|
* Parse the hash from a string representation in the format
|
||||||
Subresource Integrity hash expression). If the 'type' argument
|
* "[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a
|
||||||
is not present, then the hash type must be specified in the
|
* Subresource Integrity hash expression). If the 'type' argument
|
||||||
string. */
|
* is not present, then the hash type must be specified in the
|
||||||
|
* string.
|
||||||
|
*/
|
||||||
static Hash parseAny(std::string_view s, std::optional<HashType> type);
|
static Hash parseAny(std::string_view s, std::optional<HashType> type);
|
||||||
|
|
||||||
/* Parse a hash from a string representation like the above, except the
|
/**
|
||||||
type prefix is mandatory is there is no separate arguement. */
|
* Parse a hash from a string representation like the above, except the
|
||||||
|
* type prefix is mandatory is there is no separate arguement.
|
||||||
|
*/
|
||||||
static Hash parseAnyPrefixed(std::string_view s);
|
static Hash parseAnyPrefixed(std::string_view s);
|
||||||
|
|
||||||
/* Parse a plain hash that musst not have any prefix indicating the type.
|
/**
|
||||||
The type is passed in to disambiguate. */
|
* Parse a plain hash that musst not have any prefix indicating the type.
|
||||||
|
* The type is passed in to disambiguate.
|
||||||
|
*/
|
||||||
static Hash parseNonSRIUnprefixed(std::string_view s, HashType type);
|
static Hash parseNonSRIUnprefixed(std::string_view s, HashType type);
|
||||||
|
|
||||||
static Hash parseSRI(std::string_view original);
|
static Hash parseSRI(std::string_view original);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* The type must be provided, the string view must not include <type>
|
/**
|
||||||
prefix. `isSRI` helps disambigate the various base-* encodings. */
|
* The type must be provided, the string view must not include <type>
|
||||||
|
* prefix. `isSRI` helps disambigate the various base-* encodings.
|
||||||
|
*/
|
||||||
Hash(std::string_view s, HashType type, bool isSRI);
|
Hash(std::string_view s, HashType type, bool isSRI);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/* Check whether two hash are equal. */
|
/**
|
||||||
|
* Check whether two hash are equal.
|
||||||
|
*/
|
||||||
bool operator == (const Hash & h2) const;
|
bool operator == (const Hash & h2) const;
|
||||||
|
|
||||||
/* Check whether two hash are not equal. */
|
/**
|
||||||
|
* Check whether two hash are not equal.
|
||||||
|
*/
|
||||||
bool operator != (const Hash & h2) const;
|
bool operator != (const Hash & h2) const;
|
||||||
|
|
||||||
/* For sorting. */
|
/**
|
||||||
|
* For sorting.
|
||||||
|
*/
|
||||||
bool operator < (const Hash & h) const;
|
bool operator < (const Hash & h) const;
|
||||||
|
|
||||||
/* Returns the length of a base-16 representation of this hash. */
|
/**
|
||||||
|
* Returns the length of a base-16 representation of this hash.
|
||||||
|
*/
|
||||||
size_t base16Len() const
|
size_t base16Len() const
|
||||||
{
|
{
|
||||||
return hashSize * 2;
|
return hashSize * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the length of a base-32 representation of this hash. */
|
/**
|
||||||
|
* Returns the length of a base-32 representation of this hash.
|
||||||
|
*/
|
||||||
size_t base32Len() const
|
size_t base32Len() const
|
||||||
{
|
{
|
||||||
return (hashSize * 8 - 1) / 5 + 1;
|
return (hashSize * 8 - 1) / 5 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the length of a base-64 representation of this hash. */
|
/**
|
||||||
|
* Returns the length of a base-64 representation of this hash.
|
||||||
|
*/
|
||||||
size_t base64Len() const
|
size_t base64Len() const
|
||||||
{
|
{
|
||||||
return ((4 * hashSize / 3) + 3) & ~3;
|
return ((4 * hashSize / 3) + 3) & ~3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a string representation of the hash, in base-16, base-32
|
/**
|
||||||
or base-64. By default, this is prefixed by the hash type
|
* Return a string representation of the hash, in base-16, base-32
|
||||||
(e.g. "sha256:"). */
|
* or base-64. By default, this is prefixed by the hash type
|
||||||
|
* (e.g. "sha256:").
|
||||||
|
*/
|
||||||
std::string to_string(Base base, bool includeType) const;
|
std::string to_string(Base base, bool includeType) const;
|
||||||
|
|
||||||
std::string gitRev() const
|
std::string gitRev() const
|
||||||
|
@ -104,35 +128,53 @@ public:
|
||||||
static Hash dummy;
|
static Hash dummy;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Helper that defaults empty hashes to the 0 hash. */
|
/**
|
||||||
|
* Helper that defaults empty hashes to the 0 hash.
|
||||||
|
*/
|
||||||
Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht);
|
Hash newHashAllowEmpty(std::string_view hashStr, std::optional<HashType> ht);
|
||||||
|
|
||||||
/* Print a hash in base-16 if it's MD5, or base-32 otherwise. */
|
/**
|
||||||
|
* Print a hash in base-16 if it's MD5, or base-32 otherwise.
|
||||||
|
*/
|
||||||
std::string printHash16or32(const Hash & hash);
|
std::string printHash16or32(const Hash & hash);
|
||||||
|
|
||||||
/* Compute the hash of the given string. */
|
/**
|
||||||
|
* Compute the hash of the given string.
|
||||||
|
*/
|
||||||
Hash hashString(HashType ht, std::string_view s);
|
Hash hashString(HashType ht, std::string_view s);
|
||||||
|
|
||||||
/* Compute the hash of the given file. */
|
/**
|
||||||
|
* Compute the hash of the given file.
|
||||||
|
*/
|
||||||
Hash hashFile(HashType ht, const Path & path);
|
Hash hashFile(HashType ht, const Path & path);
|
||||||
|
|
||||||
/* Compute the hash of the given path. The hash is defined as
|
/**
|
||||||
(essentially) hashString(ht, dumpPath(path)). */
|
* Compute the hash of the given path. The hash is defined as
|
||||||
|
* (essentially) hashString(ht, dumpPath(path)).
|
||||||
|
*/
|
||||||
typedef std::pair<Hash, uint64_t> HashResult;
|
typedef std::pair<Hash, uint64_t> HashResult;
|
||||||
HashResult hashPath(HashType ht, const Path & path,
|
HashResult hashPath(HashType ht, const Path & path,
|
||||||
PathFilter & filter = defaultPathFilter);
|
PathFilter & filter = defaultPathFilter);
|
||||||
|
|
||||||
/* Compress a hash to the specified number of bytes by cyclically
|
/**
|
||||||
XORing bytes together. */
|
* Compress a hash to the specified number of bytes by cyclically
|
||||||
|
* XORing bytes together.
|
||||||
|
*/
|
||||||
Hash compressHash(const Hash & hash, unsigned int newSize);
|
Hash compressHash(const Hash & hash, unsigned int newSize);
|
||||||
|
|
||||||
/* Parse a string representing a hash type. */
|
/**
|
||||||
|
* Parse a string representing a hash type.
|
||||||
|
*/
|
||||||
HashType parseHashType(std::string_view s);
|
HashType parseHashType(std::string_view s);
|
||||||
|
|
||||||
/* Will return nothing on parse error */
|
/**
|
||||||
|
* Will return nothing on parse error
|
||||||
|
*/
|
||||||
std::optional<HashType> parseHashTypeOpt(std::string_view s);
|
std::optional<HashType> parseHashTypeOpt(std::string_view s);
|
||||||
|
|
||||||
/* And the reverse. */
|
/**
|
||||||
|
* And the reverse.
|
||||||
|
*/
|
||||||
std::string_view printHashType(HashType ht);
|
std::string_view printHashType(HashType ht);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,13 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* Highlight all the given matches in the given string `s` by wrapping
|
/**
|
||||||
them between `prefix` and `postfix`.
|
* Highlight all the given matches in the given string `s` by wrapping
|
||||||
|
* them between `prefix` and `postfix`.
|
||||||
If some matches overlap, then their union will be wrapped rather
|
*
|
||||||
than the individual matches. */
|
* If some matches overlap, then their union will be wrapped rather
|
||||||
|
* than the individual matches.
|
||||||
|
*/
|
||||||
std::string hiliteMatches(
|
std::string hiliteMatches(
|
||||||
std::string_view s,
|
std::string_view s,
|
||||||
std::vector<std::smatch> matches,
|
std::vector<std::smatch> matches,
|
||||||
|
|
|
@ -217,7 +217,9 @@ extern Verbosity verbosity; /* suppress msgs > this */
|
||||||
#define debug(args...) printMsg(lvlDebug, args)
|
#define debug(args...) printMsg(lvlDebug, args)
|
||||||
#define vomit(args...) printMsg(lvlVomit, args)
|
#define vomit(args...) printMsg(lvlVomit, args)
|
||||||
|
|
||||||
/* if verbosity >= lvlWarn, print a message with a yellow 'warning:' prefix. */
|
/**
|
||||||
|
* if verbosity >= lvlWarn, print a message with a yellow 'warning:' prefix.
|
||||||
|
*/
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void warn(const std::string & fs, const Args & ... args)
|
inline void warn(const std::string & fs, const Args & ... args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* A simple least-recently used cache. Not thread-safe. */
|
/**
|
||||||
|
* A simple least-recently used cache. Not thread-safe.
|
||||||
|
*/
|
||||||
template<typename Key, typename Value>
|
template<typename Key, typename Value>
|
||||||
class LRUCache
|
class LRUCache
|
||||||
{
|
{
|
||||||
|
@ -31,7 +33,9 @@ public:
|
||||||
|
|
||||||
LRUCache(size_t capacity) : capacity(capacity) { }
|
LRUCache(size_t capacity) : capacity(capacity) { }
|
||||||
|
|
||||||
/* Insert or upsert an item in the cache. */
|
/**
|
||||||
|
* Insert or upsert an item in the cache.
|
||||||
|
*/
|
||||||
void upsert(const Key & key, const Value & value)
|
void upsert(const Key & key, const Value & value)
|
||||||
{
|
{
|
||||||
if (capacity == 0) return;
|
if (capacity == 0) return;
|
||||||
|
@ -39,7 +43,9 @@ public:
|
||||||
erase(key);
|
erase(key);
|
||||||
|
|
||||||
if (data.size() >= capacity) {
|
if (data.size() >= capacity) {
|
||||||
/* Retire the oldest item. */
|
/**
|
||||||
|
* Retire the oldest item.
|
||||||
|
*/
|
||||||
auto oldest = lru.begin();
|
auto oldest = lru.begin();
|
||||||
data.erase(*oldest);
|
data.erase(*oldest);
|
||||||
lru.erase(oldest);
|
lru.erase(oldest);
|
||||||
|
@ -63,14 +69,18 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look up an item in the cache. If it exists, it becomes the most
|
/**
|
||||||
recently used item. */
|
* Look up an item in the cache. If it exists, it becomes the most
|
||||||
|
* recently used item.
|
||||||
|
* */
|
||||||
std::optional<Value> get(const Key & key)
|
std::optional<Value> get(const Key & key)
|
||||||
{
|
{
|
||||||
auto i = data.find(key);
|
auto i = data.find(key);
|
||||||
if (i == data.end()) return {};
|
if (i == data.end()) return {};
|
||||||
|
|
||||||
/* Move this item to the back of the LRU list. */
|
/**
|
||||||
|
* Move this item to the back of the LRU list.
|
||||||
|
*/
|
||||||
lru.erase(i->second.first.it);
|
lru.erase(i->second.first.it);
|
||||||
auto j = lru.insert(lru.end(), i);
|
auto j = lru.insert(lru.end(), i);
|
||||||
i->second.first.it = j;
|
i->second.first.it = j;
|
||||||
|
|
|
@ -11,33 +11,37 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* This template class implements a simple pool manager of resources
|
/**
|
||||||
of some type R, such as database connections. It is used as
|
* This template class implements a simple pool manager of resources
|
||||||
follows:
|
* of some type R, such as database connections. It is used as
|
||||||
|
* follows:
|
||||||
class Connection { ... };
|
*
|
||||||
|
* class Connection { ... };
|
||||||
Pool<Connection> pool;
|
*
|
||||||
|
* Pool<Connection> pool;
|
||||||
{
|
*
|
||||||
auto conn(pool.get());
|
* {
|
||||||
conn->exec("select ...");
|
* auto conn(pool.get());
|
||||||
}
|
* conn->exec("select ...");
|
||||||
|
* }
|
||||||
Here, the Connection object referenced by ‘conn’ is automatically
|
*
|
||||||
returned to the pool when ‘conn’ goes out of scope.
|
* Here, the Connection object referenced by ‘conn’ is automatically
|
||||||
*/
|
* returned to the pool when ‘conn’ goes out of scope.
|
||||||
|
*/
|
||||||
template <class R>
|
template <class R>
|
||||||
class Pool
|
class Pool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* A function that produces new instances of R on demand. */
|
/**
|
||||||
|
* A function that produces new instances of R on demand.
|
||||||
|
*/
|
||||||
typedef std::function<ref<R>()> Factory;
|
typedef std::function<ref<R>()> Factory;
|
||||||
|
|
||||||
/* A function that checks whether an instance of R is still
|
/**
|
||||||
usable. Unusable instances are removed from the pool. */
|
* A function that checks whether an instance of R is still
|
||||||
|
* usable. Unusable instances are removed from the pool.
|
||||||
|
*/
|
||||||
typedef std::function<bool(const ref<R> &)> Validator;
|
typedef std::function<bool(const ref<R> &)> Validator;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* A simple non-nullable reference-counted pointer. Actually a wrapper
|
/**
|
||||||
around std::shared_ptr that prevents null constructions. */
|
* A simple non-nullable reference-counted pointer. Actually a wrapper
|
||||||
|
* around std::shared_ptr that prevents null constructions.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class ref
|
class ref
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,9 @@ namespace boost::context { struct stack_context; }
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
/* Abstract destination of binary data. */
|
/**
|
||||||
|
* Abstract destination of binary data.
|
||||||
|
*/
|
||||||
struct Sink
|
struct Sink
|
||||||
{
|
{
|
||||||
virtual ~Sink() { }
|
virtual ~Sink() { }
|
||||||
|
@ -18,7 +20,9 @@ struct Sink
|
||||||
virtual bool good() { return true; }
|
virtual bool good() { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Just throws away data. */
|
/**
|
||||||
|
* Just throws away data.
|
||||||
|
*/
|
||||||
struct NullSink : Sink
|
struct NullSink : Sink
|
||||||
{
|
{
|
||||||
void operator () (std::string_view data) override
|
void operator () (std::string_view data) override
|
||||||
|
@ -32,8 +36,10 @@ struct FinishSink : virtual Sink
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A buffered abstract sink. Warning: a BufferedSink should not be
|
/**
|
||||||
used from multiple threads concurrently. */
|
* A buffered abstract sink. Warning: a BufferedSink should not be
|
||||||
|
* used from multiple threads concurrently.
|
||||||
|
*/
|
||||||
struct BufferedSink : virtual Sink
|
struct BufferedSink : virtual Sink
|
||||||
{
|
{
|
||||||
size_t bufSize, bufPos;
|
size_t bufSize, bufPos;
|
||||||
|
@ -50,19 +56,25 @@ struct BufferedSink : virtual Sink
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Abstract source of binary data. */
|
/**
|
||||||
|
* Abstract source of binary data.
|
||||||
|
*/
|
||||||
struct Source
|
struct Source
|
||||||
{
|
{
|
||||||
virtual ~Source() { }
|
virtual ~Source() { }
|
||||||
|
|
||||||
/* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
|
/**
|
||||||
It blocks until all the requested data is available, or throws
|
* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
|
||||||
an error if it is not going to be available. */
|
* It blocks until all the requested data is available, or throws
|
||||||
|
* an error if it is not going to be available.
|
||||||
|
*/
|
||||||
void operator () (char * data, size_t len);
|
void operator () (char * data, size_t len);
|
||||||
|
|
||||||
/* Store up to ‘len’ in the buffer pointed to by ‘data’, and
|
/**
|
||||||
return the number of bytes stored. It blocks until at least
|
* Store up to ‘len’ in the buffer pointed to by ‘data’, and
|
||||||
one byte is available. */
|
* return the number of bytes stored. It blocks until at least
|
||||||
|
* one byte is available.
|
||||||
|
*/
|
||||||
virtual size_t read(char * data, size_t len) = 0;
|
virtual size_t read(char * data, size_t len) = 0;
|
||||||
|
|
||||||
virtual bool good() { return true; }
|
virtual bool good() { return true; }
|
||||||
|
@ -73,8 +85,10 @@ struct Source
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A buffered abstract source. Warning: a BufferedSource should not be
|
/**
|
||||||
used from multiple threads concurrently. */
|
* A buffered abstract source. Warning: a BufferedSource should not be
|
||||||
|
* used from multiple threads concurrently.
|
||||||
|
*/
|
||||||
struct BufferedSource : Source
|
struct BufferedSource : Source
|
||||||
{
|
{
|
||||||
size_t bufSize, bufPosIn, bufPosOut;
|
size_t bufSize, bufPosIn, bufPosOut;
|
||||||
|
@ -88,12 +102,16 @@ struct BufferedSource : Source
|
||||||
bool hasData();
|
bool hasData();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* Underlying read call, to be overridden. */
|
/**
|
||||||
|
* Underlying read call, to be overridden.
|
||||||
|
*/
|
||||||
virtual size_t readUnbuffered(char * data, size_t len) = 0;
|
virtual size_t readUnbuffered(char * data, size_t len) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A sink that writes data to a file descriptor. */
|
/**
|
||||||
|
* A sink that writes data to a file descriptor.
|
||||||
|
*/
|
||||||
struct FdSink : BufferedSink
|
struct FdSink : BufferedSink
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -123,7 +141,9 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A source that reads data from a file descriptor. */
|
/**
|
||||||
|
* A source that reads data from a file descriptor.
|
||||||
|
*/
|
||||||
struct FdSource : BufferedSource
|
struct FdSource : BufferedSource
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -149,7 +169,9 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A sink that writes data to a string. */
|
/**
|
||||||
|
* A sink that writes data to a string.
|
||||||
|
*/
|
||||||
struct StringSink : Sink
|
struct StringSink : Sink
|
||||||
{
|
{
|
||||||
std::string s;
|
std::string s;
|
||||||
|
@ -163,7 +185,9 @@ struct StringSink : Sink
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A source that reads data from a string. */
|
/**
|
||||||
|
* A source that reads data from a string.
|
||||||
|
*/
|
||||||
struct StringSource : Source
|
struct StringSource : Source
|
||||||
{
|
{
|
||||||
std::string_view s;
|
std::string_view s;
|
||||||
|
@ -173,7 +197,9 @@ struct StringSource : Source
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A sink that writes all incoming data to two other sinks. */
|
/**
|
||||||
|
* A sink that writes all incoming data to two other sinks.
|
||||||
|
*/
|
||||||
struct TeeSink : Sink
|
struct TeeSink : Sink
|
||||||
{
|
{
|
||||||
Sink & sink1, & sink2;
|
Sink & sink1, & sink2;
|
||||||
|
@ -186,7 +212,9 @@ struct TeeSink : Sink
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Adapter class of a Source that saves all data read to a sink. */
|
/**
|
||||||
|
* Adapter class of a Source that saves all data read to a sink.
|
||||||
|
*/
|
||||||
struct TeeSource : Source
|
struct TeeSource : Source
|
||||||
{
|
{
|
||||||
Source & orig;
|
Source & orig;
|
||||||
|
@ -201,7 +229,9 @@ struct TeeSource : Source
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A reader that consumes the original Source until 'size'. */
|
/**
|
||||||
|
* A reader that consumes the original Source until 'size'.
|
||||||
|
*/
|
||||||
struct SizedSource : Source
|
struct SizedSource : Source
|
||||||
{
|
{
|
||||||
Source & orig;
|
Source & orig;
|
||||||
|
@ -219,7 +249,9 @@ struct SizedSource : Source
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Consume the original source until no remain data is left to consume. */
|
/**
|
||||||
|
* Consume the original source until no remain data is left to consume.
|
||||||
|
*/
|
||||||
size_t drainAll()
|
size_t drainAll()
|
||||||
{
|
{
|
||||||
std::vector<char> buf(8192);
|
std::vector<char> buf(8192);
|
||||||
|
@ -232,7 +264,9 @@ struct SizedSource : Source
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* A sink that that just counts the number of bytes given to it */
|
/**
|
||||||
|
* A sink that that just counts the number of bytes given to it
|
||||||
|
*/
|
||||||
struct LengthSink : Sink
|
struct LengthSink : Sink
|
||||||
{
|
{
|
||||||
uint64_t length = 0;
|
uint64_t length = 0;
|
||||||
|
@ -243,7 +277,9 @@ struct LengthSink : Sink
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Convert a function into a sink. */
|
/**
|
||||||
|
* Convert a function into a sink.
|
||||||
|
*/
|
||||||
struct LambdaSink : Sink
|
struct LambdaSink : Sink
|
||||||
{
|
{
|
||||||
typedef std::function<void(std::string_view data)> lambda_t;
|
typedef std::function<void(std::string_view data)> lambda_t;
|
||||||
|
@ -259,7 +295,9 @@ struct LambdaSink : Sink
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Convert a function into a source. */
|
/**
|
||||||
|
* Convert a function into a source.
|
||||||
|
*/
|
||||||
struct LambdaSource : Source
|
struct LambdaSource : Source
|
||||||
{
|
{
|
||||||
typedef std::function<size_t(char *, size_t)> lambda_t;
|
typedef std::function<size_t(char *, size_t)> lambda_t;
|
||||||
|
@ -274,8 +312,10 @@ struct LambdaSource : Source
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Chain two sources together so after the first is exhausted, the second is
|
/**
|
||||||
used */
|
* Chain two sources together so after the first is exhausted, the second is
|
||||||
|
* used
|
||||||
|
*/
|
||||||
struct ChainSource : Source
|
struct ChainSource : Source
|
||||||
{
|
{
|
||||||
Source & source1, & source2;
|
Source & source1, & source2;
|
||||||
|
@ -289,8 +329,10 @@ struct ChainSource : Source
|
||||||
|
|
||||||
std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun);
|
std::unique_ptr<FinishSink> sourceToSink(std::function<void(Source &)> fun);
|
||||||
|
|
||||||
/* Convert a function that feeds data into a Sink into a Source. The
|
/**
|
||||||
Source executes the function as a coroutine. */
|
* Convert a function that feeds data into a Sink into a Source. The
|
||||||
|
* Source executes the function as a coroutine.
|
||||||
|
*/
|
||||||
std::unique_ptr<Source> sinkToSource(
|
std::unique_ptr<Source> sinkToSource(
|
||||||
std::function<void(Sink &)> fun,
|
std::function<void(Sink &)> fun,
|
||||||
std::function<void()> eof = []() {
|
std::function<void()> eof = []() {
|
||||||
|
@ -376,7 +418,9 @@ Source & operator >> (Source & in, bool & b)
|
||||||
Error readError(Source & source);
|
Error readError(Source & source);
|
||||||
|
|
||||||
|
|
||||||
/* An adapter that converts a std::basic_istream into a source. */
|
/**
|
||||||
|
* An adapter that converts a std::basic_istream into a source.
|
||||||
|
*/
|
||||||
struct StreamToSourceAdapter : Source
|
struct StreamToSourceAdapter : Source
|
||||||
{
|
{
|
||||||
std::shared_ptr<std::basic_istream<char>> istream;
|
std::shared_ptr<std::basic_istream<char>> istream;
|
||||||
|
@ -399,13 +443,14 @@ struct StreamToSourceAdapter : Source
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* A source that reads a distinct format of concatenated chunks back into its
|
/**
|
||||||
logical form, in order to guarantee a known state to the original stream,
|
* A source that reads a distinct format of concatenated chunks back into its
|
||||||
even in the event of errors.
|
* logical form, in order to guarantee a known state to the original stream,
|
||||||
|
* even in the event of errors.
|
||||||
Use with FramedSink, which also allows the logical stream to be terminated
|
*
|
||||||
in the event of an exception.
|
* Use with FramedSink, which also allows the logical stream to be terminated
|
||||||
*/
|
* in the event of an exception.
|
||||||
|
*/
|
||||||
struct FramedSource : Source
|
struct FramedSource : Source
|
||||||
{
|
{
|
||||||
Source & from;
|
Source & from;
|
||||||
|
@ -450,11 +495,12 @@ struct FramedSource : Source
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Write as chunks in the format expected by FramedSource.
|
/**
|
||||||
|
* Write as chunks in the format expected by FramedSource.
|
||||||
The exception_ptr reference can be used to terminate the stream when you
|
*
|
||||||
detect that an error has occurred on the remote end.
|
* The exception_ptr reference can be used to terminate the stream when you
|
||||||
*/
|
* detect that an error has occurred on the remote end.
|
||||||
|
*/
|
||||||
struct FramedSink : nix::BufferedSink
|
struct FramedSink : nix::BufferedSink
|
||||||
{
|
{
|
||||||
BufferedSink & to;
|
BufferedSink & to;
|
||||||
|
@ -487,17 +533,20 @@ struct FramedSink : nix::BufferedSink
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Stack allocation strategy for sinkToSource.
|
/**
|
||||||
Mutable to avoid a boehm gc dependency in libutil.
|
* Stack allocation strategy for sinkToSource.
|
||||||
|
* Mutable to avoid a boehm gc dependency in libutil.
|
||||||
boost::context doesn't provide a virtual class, so we define our own.
|
*
|
||||||
|
* boost::context doesn't provide a virtual class, so we define our own.
|
||||||
*/
|
*/
|
||||||
struct StackAllocator {
|
struct StackAllocator {
|
||||||
virtual boost::context::stack_context allocate() = 0;
|
virtual boost::context::stack_context allocate() = 0;
|
||||||
virtual void deallocate(boost::context::stack_context sctx) = 0;
|
virtual void deallocate(boost::context::stack_context sctx) = 0;
|
||||||
|
|
||||||
/* The stack allocator to use in sinkToSource and potentially elsewhere.
|
/**
|
||||||
It is reassigned by the initGC() method in libexpr. */
|
* The stack allocator to use in sinkToSource and potentially elsewhere.
|
||||||
|
* It is reassigned by the initGC() method in libexpr.
|
||||||
|
*/
|
||||||
static StackAllocator *defaultAllocator;
|
static StackAllocator *defaultAllocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,12 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
// If `separator` is found, we return the portion of the string before the
|
/**
|
||||||
// separator, and modify the string argument to contain only the part after the
|
* If `separator` is found, we return the portion of the string before the
|
||||||
// separator. Otherwise, we return `std::nullopt`, and we leave the argument
|
* separator, and modify the string argument to contain only the part after the
|
||||||
// string alone.
|
* separator. Otherwise, we return `std::nullopt`, and we leave the argument
|
||||||
|
* string alone.
|
||||||
|
*/
|
||||||
static inline std::optional<std::string_view> splitPrefixTo(std::string_view & string, char separator) {
|
static inline std::optional<std::string_view> splitPrefixTo(std::string_view & string, char separator) {
|
||||||
auto sepInstance = string.find(separator);
|
auto sepInstance = string.find(separator);
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@ int levenshteinDistance(std::string_view first, std::string_view second);
|
||||||
*/
|
*/
|
||||||
class Suggestion {
|
class Suggestion {
|
||||||
public:
|
public:
|
||||||
int distance; // The smaller the better
|
/// The smaller the better
|
||||||
|
int distance;
|
||||||
std::string suggestion;
|
std::string suggestion;
|
||||||
|
|
||||||
std::string to_string() const;
|
std::string to_string() const;
|
||||||
|
@ -43,7 +44,9 @@ public:
|
||||||
std::ostream & operator<<(std::ostream & str, const Suggestion &);
|
std::ostream & operator<<(std::ostream & str, const Suggestion &);
|
||||||
std::ostream & operator<<(std::ostream & str, const Suggestions &);
|
std::ostream & operator<<(std::ostream & str, const Suggestions &);
|
||||||
|
|
||||||
// Either a value of type `T`, or some suggestions
|
/**
|
||||||
|
* Either a value of type `T`, or some suggestions
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class OrSuggestions {
|
class OrSuggestions {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -7,22 +7,22 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
/* This template class ensures synchronized access to a value of type
|
/**
|
||||||
T. It is used as follows:
|
* This template class ensures synchronized access to a value of type
|
||||||
|
* T. It is used as follows:
|
||||||
struct Data { int x; ... };
|
*
|
||||||
|
* struct Data { int x; ... };
|
||||||
Sync<Data> data;
|
*
|
||||||
|
* Sync<Data> data;
|
||||||
{
|
*
|
||||||
auto data_(data.lock());
|
* {
|
||||||
data_->x = 123;
|
* auto data_(data.lock());
|
||||||
}
|
* data_->x = 123;
|
||||||
|
* }
|
||||||
Here, "data" is automatically unlocked when "data_" goes out of
|
*
|
||||||
scope.
|
* Here, "data" is automatically unlocked when "data_" goes out of
|
||||||
*/
|
* scope.
|
||||||
|
*/
|
||||||
template<class T, class M = std::mutex>
|
template<class T, class M = std::mutex>
|
||||||
class Sync
|
class Sync
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,7 @@ struct TarArchive {
|
||||||
|
|
||||||
TarArchive(const Path & path);
|
TarArchive(const Path & path);
|
||||||
|
|
||||||
// disable copy constructor
|
/// disable copy constructor
|
||||||
TarArchive(const TarArchive &) = delete;
|
TarArchive(const TarArchive &) = delete;
|
||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
|
@ -13,8 +13,10 @@ namespace nix {
|
||||||
|
|
||||||
MakeError(ThreadPoolShutDown, Error);
|
MakeError(ThreadPoolShutDown, Error);
|
||||||
|
|
||||||
/* A simple thread pool that executes a queue of work items
|
/**
|
||||||
(lambdas). */
|
* A simple thread pool that executes a queue of work items
|
||||||
|
* (lambdas).
|
||||||
|
*/
|
||||||
class ThreadPool
|
class ThreadPool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -23,19 +25,30 @@ public:
|
||||||
|
|
||||||
~ThreadPool();
|
~ThreadPool();
|
||||||
|
|
||||||
// FIXME: use std::packaged_task?
|
/**
|
||||||
|
* An individual work item.
|
||||||
|
*
|
||||||
|
* \todo use std::packaged_task?
|
||||||
|
*/
|
||||||
typedef std::function<void()> work_t;
|
typedef std::function<void()> work_t;
|
||||||
|
|
||||||
/* Enqueue a function to be executed by the thread pool. */
|
/**
|
||||||
|
* Enqueue a function to be executed by the thread pool.
|
||||||
|
*/
|
||||||
void enqueue(const work_t & t);
|
void enqueue(const work_t & t);
|
||||||
|
|
||||||
/* Execute work items until the queue is empty. Note that work
|
/**
|
||||||
items are allowed to add new items to the queue; this is
|
* Execute work items until the queue is empty.
|
||||||
handled correctly. Queue processing stops prematurely if any
|
*
|
||||||
work item throws an exception. This exception is propagated to
|
* \note Note that work items are allowed to add new items to the
|
||||||
the calling thread. If multiple work items throw an exception
|
* queue; this is handled correctly.
|
||||||
concurrently, only one item is propagated; the others are
|
*
|
||||||
printed on stderr and otherwise ignored. */
|
* Queue processing stops prematurely if any work item throws an
|
||||||
|
* exception. This exception is propagated to the calling thread. If
|
||||||
|
* multiple work items throw an exception concurrently, only one
|
||||||
|
* item is propagated; the others are printed on stderr and
|
||||||
|
* otherwise ignored.
|
||||||
|
*/
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -62,9 +75,11 @@ private:
|
||||||
void shutdown();
|
void shutdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Process in parallel a set of items of type T that have a partial
|
/**
|
||||||
ordering between them. Thus, any item is only processed after all
|
* Process in parallel a set of items of type T that have a partial
|
||||||
its dependencies have been processed. */
|
* ordering between them. Thus, any item is only processed after all
|
||||||
|
* its dependencies have been processed.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void processGraph(
|
void processGraph(
|
||||||
ThreadPool & pool,
|
ThreadPool & pool,
|
||||||
|
|
|
@ -17,7 +17,9 @@ typedef std::set<std::string> StringSet;
|
||||||
typedef std::map<std::string, std::string> StringMap;
|
typedef std::map<std::string, std::string> StringMap;
|
||||||
typedef std::map<std::string, std::string> StringPairs;
|
typedef std::map<std::string, std::string> StringPairs;
|
||||||
|
|
||||||
/* Paths are just strings. */
|
/**
|
||||||
|
* Paths are just strings.
|
||||||
|
*/
|
||||||
typedef std::string Path;
|
typedef std::string Path;
|
||||||
typedef std::string_view PathView;
|
typedef std::string_view PathView;
|
||||||
typedef std::list<Path> Paths;
|
typedef std::list<Path> Paths;
|
||||||
|
@ -25,15 +27,19 @@ typedef std::set<Path> PathSet;
|
||||||
|
|
||||||
typedef std::vector<std::pair<std::string, std::string>> Headers;
|
typedef std::vector<std::pair<std::string, std::string>> Headers;
|
||||||
|
|
||||||
/* Helper class to run code at startup. */
|
/**
|
||||||
|
* Helper class to run code at startup.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct OnStartup
|
struct OnStartup
|
||||||
{
|
{
|
||||||
OnStartup(T && t) { t(); }
|
OnStartup(T && t) { t(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Wrap bools to prevent string literals (i.e. 'char *') from being
|
/**
|
||||||
cast to a bool in Attr. */
|
* Wrap bools to prevent string literals (i.e. 'char *') from being
|
||||||
|
* cast to a bool in Attr.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Explicit {
|
struct Explicit {
|
||||||
T t;
|
T t;
|
||||||
|
@ -45,21 +51,25 @@ struct Explicit {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* This wants to be a little bit like rust's Cow type.
|
/**
|
||||||
Some parts of the evaluator benefit greatly from being able to reuse
|
* This wants to be a little bit like rust's Cow type.
|
||||||
existing allocations for strings, but have to be able to also use
|
* Some parts of the evaluator benefit greatly from being able to reuse
|
||||||
newly allocated storage for values.
|
* existing allocations for strings, but have to be able to also use
|
||||||
|
* newly allocated storage for values.
|
||||||
We do not define implicit conversions, even with ref qualifiers,
|
*
|
||||||
since those can easily become ambiguous to the reader and can degrade
|
* We do not define implicit conversions, even with ref qualifiers,
|
||||||
into copying behaviour we want to avoid. */
|
* since those can easily become ambiguous to the reader and can degrade
|
||||||
|
* into copying behaviour we want to avoid.
|
||||||
|
*/
|
||||||
class BackedStringView {
|
class BackedStringView {
|
||||||
private:
|
private:
|
||||||
std::variant<std::string, std::string_view> data;
|
std::variant<std::string, std::string_view> data;
|
||||||
|
|
||||||
/* Needed to introduce a temporary since operator-> must return
|
/**
|
||||||
a pointer. Without this we'd need to store the view object
|
* Needed to introduce a temporary since operator-> must return
|
||||||
even when we already own a string. */
|
* a pointer. Without this we'd need to store the view object
|
||||||
|
* even when we already own a string.
|
||||||
|
*/
|
||||||
class Ptr {
|
class Ptr {
|
||||||
private:
|
private:
|
||||||
std::string_view view;
|
std::string_view view;
|
||||||
|
@ -77,8 +87,10 @@ public:
|
||||||
BackedStringView(const BackedStringView &) = delete;
|
BackedStringView(const BackedStringView &) = delete;
|
||||||
BackedStringView & operator=(const BackedStringView &) = delete;
|
BackedStringView & operator=(const BackedStringView &) = delete;
|
||||||
|
|
||||||
/* We only want move operations defined since the sole purpose of
|
/**
|
||||||
this type is to avoid copies. */
|
* We only want move operations defined since the sole purpose of
|
||||||
|
* this type is to avoid copies.
|
||||||
|
*/
|
||||||
BackedStringView(BackedStringView && other) = default;
|
BackedStringView(BackedStringView && other) = default;
|
||||||
BackedStringView & operator=(BackedStringView && other) = default;
|
BackedStringView & operator=(BackedStringView && other) = default;
|
||||||
|
|
||||||
|
|
|
@ -22,21 +22,22 @@ const static std::string segmentRegex = "(?:" + pcharRegex + "*)";
|
||||||
const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
|
const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
|
||||||
const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
|
const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
|
||||||
|
|
||||||
// A Git ref (i.e. branch or tag name).
|
/// A Git ref (i.e. branch or tag name).
|
||||||
const static std::string refRegexS = "[a-zA-Z0-9@][a-zA-Z0-9_.\\/@-]*"; // FIXME: check
|
/// \todo check that this is correct.
|
||||||
|
const static std::string refRegexS = "[a-zA-Z0-9@][a-zA-Z0-9_.\\/@-]*";
|
||||||
extern std::regex refRegex;
|
extern std::regex refRegex;
|
||||||
|
|
||||||
// Instead of defining what a good Git Ref is, we define what a bad Git Ref is
|
/// Instead of defining what a good Git Ref is, we define what a bad Git Ref is
|
||||||
// This is because of the definition of a ref in refs.c in https://github.com/git/git
|
/// This is because of the definition of a ref in refs.c in https://github.com/git/git
|
||||||
// See tests/fetchGitRefs.sh for the full definition
|
/// See tests/fetchGitRefs.sh for the full definition
|
||||||
const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
|
const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
|
||||||
extern std::regex badGitRefRegex;
|
extern std::regex badGitRefRegex;
|
||||||
|
|
||||||
// A Git revision (a SHA-1 commit hash).
|
/// A Git revision (a SHA-1 commit hash).
|
||||||
const static std::string revRegexS = "[0-9a-fA-F]{40}";
|
const static std::string revRegexS = "[0-9a-fA-F]{40}";
|
||||||
extern std::regex revRegex;
|
extern std::regex revRegex;
|
||||||
|
|
||||||
// A ref or revision, or a ref followed by a revision.
|
/// A ref or revision, or a ref followed by a revision.
|
||||||
const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegexS + ")(?:/(" + revRegexS + "))?))";
|
const static std::string refAndOrRevRegex = "(?:(" + revRegexS + ")|(?:(" + refRegexS + ")(?:/(" + revRegexS + "))?))";
|
||||||
|
|
||||||
const static std::string flakeIdRegexS = "[a-zA-Z][a-zA-Z0-9_-]*";
|
const static std::string flakeIdRegexS = "[a-zA-Z][a-zA-Z0-9_-]*";
|
||||||
|
|
|
@ -7,7 +7,8 @@ namespace nix {
|
||||||
struct ParsedURL
|
struct ParsedURL
|
||||||
{
|
{
|
||||||
std::string url;
|
std::string url;
|
||||||
std::string base; // URL without query/fragment
|
/// URL without query/fragment
|
||||||
|
std::string base;
|
||||||
std::string scheme;
|
std::string scheme;
|
||||||
std::optional<std::string> authority;
|
std::optional<std::string> authority;
|
||||||
std::string path;
|
std::string path;
|
||||||
|
@ -28,7 +29,7 @@ std::map<std::string, std::string> decodeQuery(const std::string & query);
|
||||||
|
|
||||||
ParsedURL parseURL(const std::string & url);
|
ParsedURL parseURL(const std::string & url);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Although that’s not really standardized anywhere, an number of tools
|
* Although that’s not really standardized anywhere, an number of tools
|
||||||
* use a scheme of the form 'x+y' in urls, where y is the “transport layer”
|
* use a scheme of the form 'x+y' in urls, where y is the “transport layer”
|
||||||
* scheme, and x is the “application layer” scheme.
|
* scheme, and x is the “application layer” scheme.
|
||||||
|
|
Loading…
Reference in a new issue