mirror of
https://github.com/privatevoid-net/nix-super.git
synced 2024-11-27 00:06:16 +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 {
|
||||
|
||||
/**
|
||||
* An InstallableCommand where the single positional argument must be an
|
||||
* InstallableValue in particular.
|
||||
*/
|
||||
struct InstallableValueCommand : InstallableCommand
|
||||
{
|
||||
/**
|
||||
* Entry point to this command
|
||||
*/
|
||||
virtual void run(ref<Store> store, ref<InstallableValue> installable) = 0;
|
||||
|
||||
void run(ref<Store> store, ref<Installable> installable) override;
|
||||
|
|
|
@ -87,39 +87,56 @@ struct FileTransfer
|
|||
{
|
||||
virtual ~FileTransfer() { }
|
||||
|
||||
/* Enqueue a data transfer request, returning a future to the result of
|
||||
the download. The future may throw a FileTransferError
|
||||
exception. */
|
||||
/**
|
||||
* Enqueue a data transfer request, returning a future to the result of
|
||||
* the download. The future may throw a FileTransferError
|
||||
* exception.
|
||||
*/
|
||||
virtual void enqueueFileTransfer(const FileTransferRequest & request,
|
||||
Callback<FileTransferResult> callback) = 0;
|
||||
|
||||
std::future<FileTransferResult> enqueueFileTransfer(const FileTransferRequest & request);
|
||||
|
||||
/* Synchronously download a file. */
|
||||
/**
|
||||
* Synchronously download a file.
|
||||
*/
|
||||
FileTransferResult download(const FileTransferRequest & request);
|
||||
|
||||
/* Synchronously upload a file. */
|
||||
/**
|
||||
* Synchronously upload a file.
|
||||
*/
|
||||
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);
|
||||
|
||||
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();
|
||||
|
||||
/* Return a new FileTransfer object. */
|
||||
/**
|
||||
* @return a new FileTransfer object
|
||||
*
|
||||
* Prefer getFileTransfer() to this; see its docs for why.
|
||||
*/
|
||||
ref<FileTransfer> makeFileTransfer();
|
||||
|
||||
class FileTransferError : public Error
|
||||
{
|
||||
public:
|
||||
FileTransfer::Error error;
|
||||
std::optional<std::string> response; // intentionally optional
|
||||
/// intentionally optional
|
||||
std::optional<std::string> response;
|
||||
|
||||
template<typename... Args>
|
||||
FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args);
|
||||
|
|
|
@ -4,6 +4,13 @@
|
|||
|
||||
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>
|
||||
T & require(Store & store)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,10 @@ namespace nix {
|
|||
#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 {
|
||||
wopIsValidPath = 1,
|
||||
wopHasSubstitutes = 3,
|
||||
|
@ -74,7 +78,12 @@ typedef enum {
|
|||
class Store;
|
||||
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>
|
||||
struct Phantom {};
|
||||
|
||||
|
@ -103,18 +112,19 @@ MAKE_WORKER_PROTO(X_, Y_);
|
|||
#undef X_
|
||||
#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.
|
||||
|
||||
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
|
||||
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
|
||||
worker protocol harder to implement in other languages where such
|
||||
specializations may not be allowed.
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* 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<ContentAddress>);
|
||||
|
|
|
@ -7,54 +7,71 @@
|
|||
namespace nix {
|
||||
|
||||
|
||||
/* dumpPath creates a Nix archive of the specified path. The format
|
||||
is as follows:
|
||||
|
||||
IF path points to a REGULAR FILE:
|
||||
dump(path) = attrs(
|
||||
[ ("type", "regular")
|
||||
, ("contents", contents(path))
|
||||
])
|
||||
|
||||
IF path points to a DIRECTORY:
|
||||
dump(path) = attrs(
|
||||
[ ("type", "directory")
|
||||
, ("entries", concat(map(f, sort(entries(path)))))
|
||||
])
|
||||
where f(fn) = attrs(
|
||||
[ ("name", fn)
|
||||
, ("file", dump(path + "/" + fn))
|
||||
])
|
||||
|
||||
where:
|
||||
|
||||
attrs(as) = concat(map(attr, as)) + encN(0)
|
||||
attrs((a, b)) = encS(a) + encS(b)
|
||||
|
||||
encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)
|
||||
|
||||
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. */
|
||||
|
||||
|
||||
/**
|
||||
* dumpPath creates a Nix archive of the specified path.
|
||||
*
|
||||
* @param path the file system data to dump. Dumping is recursive so if
|
||||
* this is a directory we dump it and all its children.
|
||||
*
|
||||
* @param [out] sink The serialised archive is fed into this sink.
|
||||
*
|
||||
* @param filter Can be used to skip certain files.
|
||||
*
|
||||
* The format is as follows:
|
||||
*
|
||||
* IF path points to a REGULAR FILE:
|
||||
* dump(path) = attrs(
|
||||
* [ ("type", "regular")
|
||||
* , ("contents", contents(path))
|
||||
* ])
|
||||
*
|
||||
* IF path points to a DIRECTORY:
|
||||
* dump(path) = attrs(
|
||||
* [ ("type", "directory")
|
||||
* , ("entries", concat(map(f, sort(entries(path)))))
|
||||
* ])
|
||||
* where f(fn) = attrs(
|
||||
* [ ("name", fn)
|
||||
* , ("file", dump(path + "/" + fn))
|
||||
* ])
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* attrs(as) = concat(map(attr, as)) + encN(0)
|
||||
* attrs((a, b)) = encS(a) + encS(b)
|
||||
*
|
||||
* encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)
|
||||
*
|
||||
* 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,
|
||||
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,
|
||||
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);
|
||||
|
||||
/* FIXME: fix this API, it sucks. */
|
||||
/**
|
||||
* \todo Fix this API, it sucks.
|
||||
*/
|
||||
struct ParseSink
|
||||
{
|
||||
virtual void createDirectory(const Path & path) { };
|
||||
|
@ -68,8 +85,10 @@ struct ParseSink
|
|||
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
|
||||
{
|
||||
bool regular = true;
|
||||
|
@ -97,7 +116,9 @@ void parseDump(ParseSink & sink, 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 copyPath(const Path & from, const Path & to);
|
||||
|
|
|
@ -18,16 +18,22 @@ class Args
|
|||
{
|
||||
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);
|
||||
|
||||
/* Return a short one-line description of the command. */
|
||||
/**
|
||||
* 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. */
|
||||
/**
|
||||
* Return documentation about this command, in Markdown format.
|
||||
*/
|
||||
virtual std::string doc() { return ""; }
|
||||
|
||||
protected:
|
||||
|
@ -146,13 +152,17 @@ protected:
|
|||
|
||||
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() {}
|
||||
|
||||
/* 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. */
|
||||
/**
|
||||
* 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:
|
||||
|
@ -166,7 +176,9 @@ public:
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
expectArgs({
|
||||
|
@ -202,14 +216,19 @@ private:
|
|||
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
|
||||
{
|
||||
friend class MultiCommand;
|
||||
|
||||
virtual ~Command() { }
|
||||
|
||||
/**
|
||||
* Entry point to the command
|
||||
*/
|
||||
virtual void run() = 0;
|
||||
|
||||
typedef int Category;
|
||||
|
@ -221,8 +240,10 @@ struct Command : virtual public Args
|
|||
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -230,7 +251,9 @@ public:
|
|||
|
||||
std::map<Command::Category, std::string> categories;
|
||||
|
||||
// Selected command, if any.
|
||||
/**
|
||||
* Selected command, if any.
|
||||
*/
|
||||
std::optional<std::pair<std::string, ref<Command>>> command;
|
||||
|
||||
MultiCommand(const Commands & commands);
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
|
||||
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
|
||||
exception.) */
|
||||
/**
|
||||
* 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
|
||||
* exception.)
|
||||
*/
|
||||
template<typename T>
|
||||
class Callback
|
||||
{
|
||||
|
|
|
@ -8,28 +8,31 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
/* A canonical representation of a path. It ensures the following:
|
||||
|
||||
- It always starts with a slash.
|
||||
|
||||
- It never ends with a slash, except if the path is "/".
|
||||
|
||||
- A slash is never followed by a slash (i.e. no empty components).
|
||||
|
||||
- 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
|
||||
resolved.
|
||||
*/
|
||||
/**
|
||||
* A canonical representation of a path. It ensures the following:
|
||||
*
|
||||
* - It always starts with a slash.
|
||||
*
|
||||
* - It never ends with a slash, except if the path is "/".
|
||||
*
|
||||
* - A slash is never followed by a slash (i.e. no empty components).
|
||||
*
|
||||
* - 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
|
||||
* resolved.
|
||||
*/
|
||||
class CanonPath
|
||||
{
|
||||
std::string path;
|
||||
|
||||
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);
|
||||
|
||||
explicit CanonPath(const char * raw)
|
||||
|
@ -44,9 +47,11 @@ public:
|
|||
|
||||
static CanonPath root;
|
||||
|
||||
/* If `raw` starts with a slash, return
|
||||
`CanonPath(raw)`. Otherwise return a `CanonPath` representing
|
||||
`root + "/" + raw`. */
|
||||
/**
|
||||
* If `raw` starts with a slash, return
|
||||
* `CanonPath(raw)`. Otherwise return a `CanonPath` representing
|
||||
* `root + "/" + raw`.
|
||||
*/
|
||||
CanonPath(std::string_view raw, const CanonPath & root);
|
||||
|
||||
bool isRoot() const
|
||||
|
@ -58,8 +63,10 @@ public:
|
|||
const std::string & abs() const
|
||||
{ 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 static std::string epsilon;
|
||||
|
@ -107,7 +114,9 @@ public:
|
|||
|
||||
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();
|
||||
|
||||
std::optional<std::string_view> dirOf() const
|
||||
|
@ -128,10 +137,12 @@ public:
|
|||
bool operator != (const CanonPath & x) const
|
||||
{ return path != x.path; }
|
||||
|
||||
/* Compare paths lexicographically except that path separators
|
||||
are sorted before any other character. That is, in the sorted order
|
||||
a directory is always followed directly by its children. For
|
||||
instance, 'foo' < 'foo/bar' < 'foo!'. */
|
||||
/**
|
||||
* Compare paths lexicographically except that path separators
|
||||
* are sorted before any other character. That is, in the sorted order
|
||||
* a directory is always followed directly by its children. For
|
||||
* instance, 'foo' < 'foo/bar' < 'foo!'.
|
||||
*/
|
||||
bool operator < (const CanonPath & x) const
|
||||
{
|
||||
auto i = path.begin();
|
||||
|
@ -147,27 +158,37 @@ public:
|
|||
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;
|
||||
|
||||
CanonPath removePrefix(const CanonPath & prefix) const;
|
||||
|
||||
/* Append another path to this one. */
|
||||
/**
|
||||
* Append another path to this one.
|
||||
*/
|
||||
void extend(const CanonPath & x);
|
||||
|
||||
/* Concatenate two paths. */
|
||||
/**
|
||||
* Concatenate two paths.
|
||||
*/
|
||||
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);
|
||||
|
||||
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
|
||||
the `allowed` paths are within `this`. (The latter condition
|
||||
ensures access to the parents of allowed paths.) */
|
||||
/**
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
/* Return a representation `x` of `path` relative to `this`, i.e.
|
||||
|
|
|
@ -18,10 +18,12 @@ struct CgroupStats
|
|||
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
|
||||
been killed. Also return statistics from the cgroup just before
|
||||
destruction. */
|
||||
/**
|
||||
* Destroy the cgroup denoted by 'path'. The postcondition is that
|
||||
* 'path' does not exist, and thus any processes in the cgroup have
|
||||
* been killed. Also return statistics from the cgroup just before
|
||||
* destruction.
|
||||
*/
|
||||
CgroupStats destroyCgroup(const Path & cgroup);
|
||||
|
||||
}
|
||||
|
|
|
@ -7,20 +7,24 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
/* Provides an indexable container like vector<> with memory overhead
|
||||
guarantees like list<> by allocating storage in chunks of ChunkSize
|
||||
elements instead of using a contiguous memory allocation like vector<>
|
||||
does. Not using a single vector that is resized reduces memory overhead
|
||||
on large data sets by on average (growth factor)/2, mostly
|
||||
eliminates copies within the vector during resizing, and provides stable
|
||||
references to its elements. */
|
||||
/**
|
||||
* Provides an indexable container like vector<> with memory overhead
|
||||
* guarantees like list<> by allocating storage in chunks of ChunkSize
|
||||
* elements instead of using a contiguous memory allocation like vector<>
|
||||
* does. Not using a single vector that is resized reduces memory overhead
|
||||
* on large data sets by on average (growth factor)/2, mostly
|
||||
* eliminates copies within the vector during resizing, and provides stable
|
||||
* references to its elements.
|
||||
*/
|
||||
template<typename T, size_t ChunkSize>
|
||||
class ChunkedVector {
|
||||
private:
|
||||
uint32_t size_ = 0;
|
||||
std::vector<std::vector<T>> chunks;
|
||||
|
||||
/* keep this out of the ::add hot path */
|
||||
/**
|
||||
* Keep this out of the ::add hot path
|
||||
*/
|
||||
[[gnu::noinline]]
|
||||
auto & addChunk()
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#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.
|
||||
*
|
||||
* ```
|
||||
|
|
|
@ -124,21 +124,21 @@ public:
|
|||
void reapplyUnknownSettings();
|
||||
};
|
||||
|
||||
/* A class to simplify providing configuration settings. The typical
|
||||
use is to inherit Config and add Setting<T> members:
|
||||
|
||||
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"};
|
||||
|
||||
MyClass() : Config(readConfigFile("/etc/my-app.conf"))
|
||||
{
|
||||
std::cout << foo << "\n"; // will print 123 unless overridden
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
/**
|
||||
* A class to simplify providing configuration settings. The typical
|
||||
* use is to inherit Config and add Setting<T> members:
|
||||
*
|
||||
* 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"};
|
||||
*
|
||||
* MyClass() : Config(readConfigFile("/etc/my-app.conf"))
|
||||
* {
|
||||
* std::cout << foo << "\n"; // will print 123 unless overridden
|
||||
* }
|
||||
* };
|
||||
*/
|
||||
class Config : public AbstractConfig
|
||||
{
|
||||
friend class AbstractSetting;
|
||||
|
@ -228,7 +228,9 @@ protected:
|
|||
bool isOverridden() const { return overridden; }
|
||||
};
|
||||
|
||||
/* A setting of type T. */
|
||||
/**
|
||||
* A setting of type T.
|
||||
*/
|
||||
template<typename T>
|
||||
class BaseSetting : public AbstractSetting
|
||||
{
|
||||
|
@ -311,8 +313,10 @@ public:
|
|||
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>
|
||||
{
|
||||
bool allowEmpty;
|
||||
|
|
|
@ -54,20 +54,26 @@ typedef enum {
|
|||
lvlVomit
|
||||
} Verbosity;
|
||||
|
||||
// the lines of code surrounding an error.
|
||||
/**
|
||||
* The lines of code surrounding an error.
|
||||
*/
|
||||
struct LinesOfCode {
|
||||
std::optional<std::string> prevLineOfCode;
|
||||
std::optional<std::string> errLineOfCode;
|
||||
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
|
||||
{
|
||||
uint32_t line = 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
|
||||
{ return std::nullopt; };
|
||||
|
||||
|
@ -104,8 +110,10 @@ struct ErrorInfo {
|
|||
|
||||
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
|
||||
{
|
||||
protected:
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace nix {
|
|||
*
|
||||
* If you update this, don’t forget to also change the map defining their
|
||||
* string representation in the corresponding `.cc` file.
|
||||
**/
|
||||
*/
|
||||
enum struct ExperimentalFeature
|
||||
{
|
||||
CaDerivations,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#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>
|
||||
class Finally
|
||||
{
|
||||
|
|
|
@ -8,20 +8,25 @@
|
|||
namespace nix {
|
||||
|
||||
|
||||
/* Inherit some names from other namespaces for convenience. */
|
||||
/**
|
||||
* Inherit some names from other namespaces for convenience.
|
||||
*/
|
||||
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...) {} };
|
||||
|
||||
|
||||
/* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
|
||||
equivalent to ‘boost::format(format) % a_0 % ... %
|
||||
... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
|
||||
takes place). */
|
||||
|
||||
/**
|
||||
* A helper for formatting strings. ‘fmt(format, a_0, ..., a_n)’ is
|
||||
* equivalent to ‘boost::format(format) % a_0 % ... %
|
||||
* ... a_n’. However, ‘fmt(s)’ is equivalent to ‘s’ (so no %-expansion
|
||||
* takes place).
|
||||
*/
|
||||
template<class F>
|
||||
inline void formatHelper(F & f)
|
||||
{
|
||||
|
|
|
@ -8,21 +8,23 @@ namespace nix {
|
|||
|
||||
namespace git {
|
||||
|
||||
// A line from the output of `git ls-remote --symref`.
|
||||
//
|
||||
// These can be of two kinds:
|
||||
//
|
||||
// - Symbolic references of the form
|
||||
//
|
||||
// ref: {target} {reference}
|
||||
//
|
||||
// where {target} is itself a reference and {reference} is optional
|
||||
//
|
||||
// - Object references of the form
|
||||
//
|
||||
// {target} {reference}
|
||||
//
|
||||
// where {target} is a commit id and {reference} is mandatory
|
||||
/**
|
||||
* A line from the output of `git ls-remote --symref`.
|
||||
*
|
||||
* These can be of two kinds:
|
||||
*
|
||||
* - Symbolic references of the form
|
||||
*
|
||||
* ref: {target} {reference}
|
||||
*
|
||||
* where {target} is itself a reference and {reference} is optional
|
||||
*
|
||||
* - Object references of the form
|
||||
*
|
||||
* {target} {reference}
|
||||
*
|
||||
* where {target} is a commit id and {reference} is mandatory
|
||||
*/
|
||||
struct LsRemoteRefLine {
|
||||
enum struct Kind {
|
||||
Symbolic,
|
||||
|
|
|
@ -33,62 +33,86 @@ struct Hash
|
|||
|
||||
HashType type;
|
||||
|
||||
/* Create a zero-filled hash object. */
|
||||
/**
|
||||
* Create a zero-filled hash object.
|
||||
*/
|
||||
Hash(HashType type);
|
||||
|
||||
/* Parse the hash from a string representation in the format
|
||||
"[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a
|
||||
Subresource Integrity hash expression). If the 'type' argument
|
||||
is not present, then the hash type must be specified in the
|
||||
string. */
|
||||
/**
|
||||
* Parse the hash from a string representation in the format
|
||||
* "[<type>:]<base16|base32|base64>" or "<type>-<base64>" (a
|
||||
* Subresource Integrity hash expression). If the 'type' argument
|
||||
* is not present, then the hash type must be specified in the
|
||||
* string.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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 parseSRI(std::string_view original);
|
||||
|
||||
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);
|
||||
|
||||
public:
|
||||
/* Check whether two hash are equal. */
|
||||
/**
|
||||
* Check whether two hash are equal.
|
||||
*/
|
||||
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;
|
||||
|
||||
/* For sorting. */
|
||||
/**
|
||||
* For sorting.
|
||||
*/
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
(e.g. "sha256:"). */
|
||||
/**
|
||||
* Return a string representation of the hash, in base-16, base-32
|
||||
* 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 gitRev() const
|
||||
|
@ -104,35 +128,53 @@ public:
|
|||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Compute the hash of the given string. */
|
||||
/**
|
||||
* Compute the hash of the given string.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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;
|
||||
HashResult hashPath(HashType ht, const Path & path,
|
||||
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);
|
||||
|
||||
/* Parse a string representing a hash type. */
|
||||
/**
|
||||
* Parse a string representing a hash type.
|
||||
*/
|
||||
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);
|
||||
|
||||
/* And the reverse. */
|
||||
/**
|
||||
* And the reverse.
|
||||
*/
|
||||
std::string_view printHashType(HashType ht);
|
||||
|
||||
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
/* 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. */
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
std::string hiliteMatches(
|
||||
std::string_view s,
|
||||
std::vector<std::smatch> matches,
|
||||
|
|
|
@ -217,7 +217,9 @@ extern Verbosity verbosity; /* suppress msgs > this */
|
|||
#define debug(args...) printMsg(lvlDebug, 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>
|
||||
inline void warn(const std::string & fs, const Args & ... args)
|
||||
{
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
|
||||
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>
|
||||
class LRUCache
|
||||
{
|
||||
|
@ -31,7 +33,9 @@ public:
|
|||
|
||||
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)
|
||||
{
|
||||
if (capacity == 0) return;
|
||||
|
@ -39,7 +43,9 @@ public:
|
|||
erase(key);
|
||||
|
||||
if (data.size() >= capacity) {
|
||||
/* Retire the oldest item. */
|
||||
/**
|
||||
* Retire the oldest item.
|
||||
*/
|
||||
auto oldest = lru.begin();
|
||||
data.erase(*oldest);
|
||||
lru.erase(oldest);
|
||||
|
@ -63,14 +69,18 @@ public:
|
|||
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)
|
||||
{
|
||||
auto i = data.find(key);
|
||||
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);
|
||||
auto j = lru.insert(lru.end(), i);
|
||||
i->second.first.it = j;
|
||||
|
|
|
@ -11,33 +11,37 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
/* This template class implements a simple pool manager of resources
|
||||
of some type R, such as database connections. It is used as
|
||||
follows:
|
||||
|
||||
class Connection { ... };
|
||||
|
||||
Pool<Connection> pool;
|
||||
|
||||
{
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This template class implements a simple pool manager of resources
|
||||
* of some type R, such as database connections. It is used as
|
||||
* follows:
|
||||
*
|
||||
* class Connection { ... };
|
||||
*
|
||||
* Pool<Connection> pool;
|
||||
*
|
||||
* {
|
||||
* 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.
|
||||
*/
|
||||
template <class R>
|
||||
class Pool
|
||||
{
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
private:
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
|
||||
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>
|
||||
class ref
|
||||
{
|
||||
|
|
|
@ -10,7 +10,9 @@ namespace boost::context { struct stack_context; }
|
|||
namespace nix {
|
||||
|
||||
|
||||
/* Abstract destination of binary data. */
|
||||
/**
|
||||
* Abstract destination of binary data.
|
||||
*/
|
||||
struct Sink
|
||||
{
|
||||
virtual ~Sink() { }
|
||||
|
@ -18,7 +20,9 @@ struct Sink
|
|||
virtual bool good() { return true; }
|
||||
};
|
||||
|
||||
/* Just throws away data. */
|
||||
/**
|
||||
* Just throws away data.
|
||||
*/
|
||||
struct NullSink : Sink
|
||||
{
|
||||
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
|
||||
{
|
||||
size_t bufSize, bufPos;
|
||||
|
@ -50,19 +56,25 @@ struct BufferedSink : virtual Sink
|
|||
};
|
||||
|
||||
|
||||
/* Abstract source of binary data. */
|
||||
/**
|
||||
* Abstract source of binary data.
|
||||
*/
|
||||
struct 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
|
||||
an error if it is not going to be available. */
|
||||
/**
|
||||
* Store exactly ‘len’ bytes in the buffer pointed to by ‘data’.
|
||||
* 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);
|
||||
|
||||
/* Store up to ‘len’ in the buffer pointed to by ‘data’, and
|
||||
return the number of bytes stored. It blocks until at least
|
||||
one byte is available. */
|
||||
/**
|
||||
* Store up to ‘len’ in the buffer pointed to by ‘data’, and
|
||||
* 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 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
|
||||
{
|
||||
size_t bufSize, bufPosIn, bufPosOut;
|
||||
|
@ -88,12 +102,16 @@ struct BufferedSource : Source
|
|||
bool hasData();
|
||||
|
||||
protected:
|
||||
/* Underlying read call, to be overridden. */
|
||||
/**
|
||||
* Underlying read call, to be overridden.
|
||||
*/
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
Source & orig;
|
||||
|
@ -219,7 +249,9 @@ struct SizedSource : Source
|
|||
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()
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
Source & source1, & source2;
|
||||
|
@ -289,8 +329,10 @@ struct ChainSource : Source
|
|||
|
||||
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::function<void(Sink &)> fun,
|
||||
std::function<void()> eof = []() {
|
||||
|
@ -376,7 +418,9 @@ Source & operator >> (Source & in, bool & b)
|
|||
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
|
||||
{
|
||||
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,
|
||||
even in the event of errors.
|
||||
|
||||
Use with FramedSink, which also allows the logical stream to be terminated
|
||||
in the event of an exception.
|
||||
*/
|
||||
/**
|
||||
* 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,
|
||||
* even in the event of errors.
|
||||
*
|
||||
* Use with FramedSink, which also allows the logical stream to be terminated
|
||||
* in the event of an exception.
|
||||
*/
|
||||
struct FramedSource : Source
|
||||
{
|
||||
Source & from;
|
||||
|
@ -450,11 +495,12 @@ struct FramedSource : Source
|
|||
}
|
||||
};
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
struct FramedSink : nix::BufferedSink
|
||||
{
|
||||
BufferedSink & to;
|
||||
|
@ -487,17 +533,20 @@ struct FramedSink : nix::BufferedSink
|
|||
};
|
||||
};
|
||||
|
||||
/* 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.
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
struct StackAllocator {
|
||||
virtual boost::context::stack_context allocate() = 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;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
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
|
||||
// separator. Otherwise, we return `std::nullopt`, and we leave the argument
|
||||
// string alone.
|
||||
/**
|
||||
* 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
|
||||
* 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) {
|
||||
auto sepInstance = string.find(separator);
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ int levenshteinDistance(std::string_view first, std::string_view second);
|
|||
*/
|
||||
class Suggestion {
|
||||
public:
|
||||
int distance; // The smaller the better
|
||||
/// The smaller the better
|
||||
int distance;
|
||||
std::string suggestion;
|
||||
|
||||
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 Suggestions &);
|
||||
|
||||
// Either a value of type `T`, or some suggestions
|
||||
/**
|
||||
* Either a value of type `T`, or some suggestions
|
||||
*/
|
||||
template<typename T>
|
||||
class OrSuggestions {
|
||||
public:
|
||||
|
|
|
@ -7,22 +7,22 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
/* This template class ensures synchronized access to a value of type
|
||||
T. It is used as follows:
|
||||
|
||||
struct Data { int x; ... };
|
||||
|
||||
Sync<Data> data;
|
||||
|
||||
{
|
||||
auto data_(data.lock());
|
||||
data_->x = 123;
|
||||
}
|
||||
|
||||
Here, "data" is automatically unlocked when "data_" goes out of
|
||||
scope.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This template class ensures synchronized access to a value of type
|
||||
* T. It is used as follows:
|
||||
*
|
||||
* struct Data { int x; ... };
|
||||
*
|
||||
* Sync<Data> data;
|
||||
*
|
||||
* {
|
||||
* auto data_(data.lock());
|
||||
* data_->x = 123;
|
||||
* }
|
||||
*
|
||||
* Here, "data" is automatically unlocked when "data_" goes out of
|
||||
* scope.
|
||||
*/
|
||||
template<class T, class M = std::mutex>
|
||||
class Sync
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@ struct TarArchive {
|
|||
|
||||
TarArchive(const Path & path);
|
||||
|
||||
// disable copy constructor
|
||||
/// disable copy constructor
|
||||
TarArchive(const TarArchive &) = delete;
|
||||
|
||||
void close();
|
||||
|
|
|
@ -13,8 +13,10 @@ namespace nix {
|
|||
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -23,19 +25,30 @@ public:
|
|||
|
||||
~ThreadPool();
|
||||
|
||||
// FIXME: use std::packaged_task?
|
||||
/**
|
||||
* An individual work item.
|
||||
*
|
||||
* \todo use std::packaged_task?
|
||||
*/
|
||||
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);
|
||||
|
||||
/* Execute work items until the queue is empty. Note that work
|
||||
items are allowed to add new items to the queue; this is
|
||||
handled correctly. 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. */
|
||||
/**
|
||||
* Execute work items until the queue is empty.
|
||||
*
|
||||
* \note Note that work items are allowed to add new items to the
|
||||
* queue; this is handled correctly.
|
||||
*
|
||||
* 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();
|
||||
|
||||
private:
|
||||
|
@ -62,9 +75,11 @@ private:
|
|||
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
|
||||
its dependencies have been processed. */
|
||||
/**
|
||||
* 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
|
||||
* its dependencies have been processed.
|
||||
*/
|
||||
template<typename T>
|
||||
void processGraph(
|
||||
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> StringPairs;
|
||||
|
||||
/* Paths are just strings. */
|
||||
/**
|
||||
* Paths are just strings.
|
||||
*/
|
||||
typedef std::string Path;
|
||||
typedef std::string_view PathView;
|
||||
typedef std::list<Path> Paths;
|
||||
|
@ -25,15 +27,19 @@ typedef std::set<Path> PathSet;
|
|||
|
||||
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>
|
||||
struct OnStartup
|
||||
{
|
||||
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>
|
||||
struct Explicit {
|
||||
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
|
||||
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
|
||||
into copying behaviour we want to avoid. */
|
||||
/**
|
||||
* This wants to be a little bit like rust's Cow type.
|
||||
* Some parts of the evaluator benefit greatly from being able to reuse
|
||||
* 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
|
||||
* into copying behaviour we want to avoid.
|
||||
*/
|
||||
class BackedStringView {
|
||||
private:
|
||||
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
|
||||
even when we already own a string. */
|
||||
/**
|
||||
* Needed to introduce a temporary since operator-> must return
|
||||
* a pointer. Without this we'd need to store the view object
|
||||
* even when we already own a string.
|
||||
*/
|
||||
class Ptr {
|
||||
private:
|
||||
std::string_view view;
|
||||
|
@ -77,8 +87,10 @@ public:
|
|||
BackedStringView(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 & operator=(BackedStringView && other) = default;
|
||||
|
||||
|
|
|
@ -22,21 +22,22 @@ const static std::string segmentRegex = "(?:" + pcharRegex + "*)";
|
|||
const static std::string absPathRegex = "(?:(?:/" + segmentRegex + ")*/?)";
|
||||
const static std::string pathRegex = "(?:" + segmentRegex + "(?:/" + segmentRegex + ")*/?)";
|
||||
|
||||
// A Git ref (i.e. branch or tag name).
|
||||
const static std::string refRegexS = "[a-zA-Z0-9@][a-zA-Z0-9_.\\/@-]*"; // FIXME: check
|
||||
/// A Git ref (i.e. branch or tag name).
|
||||
/// \todo check that this is correct.
|
||||
const static std::string refRegexS = "[a-zA-Z0-9@][a-zA-Z0-9_.\\/@-]*";
|
||||
extern std::regex refRegex;
|
||||
|
||||
// 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
|
||||
// See tests/fetchGitRefs.sh for the full definition
|
||||
/// 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
|
||||
/// See tests/fetchGitRefs.sh for the full definition
|
||||
const static std::string badGitRefRegexS = "//|^[./]|/\\.|\\.\\.|[[:cntrl:][:space:]:?^~\[]|\\\\|\\*|\\.lock$|\\.lock/|@\\{|[/.]$|^@$|^$";
|
||||
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}";
|
||||
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 flakeIdRegexS = "[a-zA-Z][a-zA-Z0-9_-]*";
|
||||
|
|
|
@ -7,7 +7,8 @@ namespace nix {
|
|||
struct ParsedURL
|
||||
{
|
||||
std::string url;
|
||||
std::string base; // URL without query/fragment
|
||||
/// URL without query/fragment
|
||||
std::string base;
|
||||
std::string scheme;
|
||||
std::optional<std::string> authority;
|
||||
std::string path;
|
||||
|
@ -28,7 +29,7 @@ std::map<std::string, std::string> decodeQuery(const std::string & query);
|
|||
|
||||
ParsedURL parseURL(const std::string & url);
|
||||
|
||||
/*
|
||||
/**
|
||||
* 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”
|
||||
* scheme, and x is the “application layer” scheme.
|
||||
|
|
Loading…
Reference in a new issue