mirror of
https://github.com/NixOS/nix.git
synced 2025-11-11 13:06:01 +01:00
Merge remote-tracking branch 'upstream/master' into list-experimental-features
This commit is contained in:
commit
b2c9315bf2
209 changed files with 4006 additions and 2527 deletions
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "config.hh"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "serialise.hh"
|
||||
|
|
@ -7,54 +8,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 +86,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 +117,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);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
|
@ -18,16 +19,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 +153,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 +177,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 +189,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 +217,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 +241,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 +252,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);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <future>
|
||||
#include <functional>
|
||||
|
||||
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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -100,4 +100,30 @@ std::ostream & operator << (std::ostream & stream, const CanonPath & path)
|
|||
return stream;
|
||||
}
|
||||
|
||||
std::string CanonPath::makeRelative(const CanonPath & path) const
|
||||
{
|
||||
auto p1 = begin();
|
||||
auto p2 = path.begin();
|
||||
|
||||
for (; p1 != end() && p2 != path.end() && *p1 == *p2; ++p1, ++p2) ;
|
||||
|
||||
if (p1 == end() && p2 == path.end())
|
||||
return ".";
|
||||
else if (p1 == end())
|
||||
return std::string(p2.remaining);
|
||||
else {
|
||||
std::string res;
|
||||
while (p1 != end()) {
|
||||
++p1;
|
||||
if (!res.empty()) res += '/';
|
||||
res += "..";
|
||||
}
|
||||
if (p2 != path.end()) {
|
||||
if (!res.empty()) res += '/';
|
||||
res += p2.remaining;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
|
@ -8,28 +9,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 +48,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 +64,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;
|
||||
|
|
@ -85,6 +93,9 @@ public:
|
|||
bool operator != (const Iterator & x) const
|
||||
{ return remaining.data() != x.remaining.data(); }
|
||||
|
||||
bool operator == (const Iterator & x) const
|
||||
{ return !(*this != x); }
|
||||
|
||||
const std::string_view operator * () const
|
||||
{ return remaining.substr(0, slash); }
|
||||
|
||||
|
|
@ -104,7 +115,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
|
||||
|
|
@ -125,10 +138,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();
|
||||
|
|
@ -144,28 +159,42 @@ 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.
|
||||
`CanonPath(this.makeRelative(x), this) == path`. */
|
||||
std::string makeRelative(const CanonPath & path) const;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream & stream, const CanonPath & path);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#if __linux__
|
||||
|
||||
|
|
@ -18,10 +19,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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
|
@ -7,20 +8,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,3 +1,6 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <set>
|
||||
#include <future>
|
||||
#include "sync.hh"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
/* 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.
|
||||
*
|
||||
* ```
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "ref.hh"
|
||||
#include "types.hh"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
|
||||
namespace nix {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
|
@ -124,21 +125,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 +229,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 +314,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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "suggestions.hh"
|
||||
#include "ref.hh"
|
||||
|
|
@ -54,20 +55,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 +111,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:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "comparator.hh"
|
||||
#include "error.hh"
|
||||
|
|
@ -12,7 +13,7 @@ namespace nix {
|
|||
*
|
||||
* If you update this, don’t forget to also change the map defining their string
|
||||
* representation and documentation in the corresponding `.cc` file as well.
|
||||
**/
|
||||
*/
|
||||
enum struct ExperimentalFeature
|
||||
{
|
||||
CaDerivations,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
/* 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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <string>
|
||||
|
|
@ -8,20 +9,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
|
@ -8,21 +9,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,
|
||||
|
|
|
|||
|
|
@ -71,12 +71,13 @@ const std::string base16Chars = "0123456789abcdef";
|
|||
|
||||
static std::string printHash16(const Hash & hash)
|
||||
{
|
||||
char buf[hash.hashSize * 2];
|
||||
std::string buf;
|
||||
buf.reserve(hash.hashSize * 2);
|
||||
for (unsigned int i = 0; i < hash.hashSize; i++) {
|
||||
buf[i * 2] = base16Chars[hash.hash[i] >> 4];
|
||||
buf[i * 2 + 1] = base16Chars[hash.hash[i] & 0x0f];
|
||||
buf.push_back(base16Chars[hash.hash[i] >> 4]);
|
||||
buf.push_back(base16Chars[hash.hash[i] & 0x0f]);
|
||||
}
|
||||
return std::string(buf, hash.hashSize * 2);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -130,7 +131,7 @@ std::string Hash::to_string(Base base, bool includeType) const
|
|||
break;
|
||||
case Base64:
|
||||
case SRI:
|
||||
s += base64Encode(std::string((const char *) hash, hashSize));
|
||||
s += base64Encode(std::string_view((const char *) hash, hashSize));
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
|
|
@ -403,7 +404,7 @@ HashType parseHashType(std::string_view s)
|
|||
throw UsageError("unknown hash algorithm '%1%'", s);
|
||||
}
|
||||
|
||||
std::string printHashType(HashType ht)
|
||||
std::string_view printHashType(HashType ht)
|
||||
{
|
||||
switch (ht) {
|
||||
case htMD5: return "md5";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "serialise.hh"
|
||||
|
|
@ -33,62 +34,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,36 +129,54 @@ 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. */
|
||||
std::string printHashType(HashType ht);
|
||||
/**
|
||||
* And the reverse.
|
||||
*/
|
||||
std::string_view printHashType(HashType ht);
|
||||
|
||||
|
||||
union Ctx;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
|
@ -6,11 +7,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,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "error.hh"
|
||||
|
|
@ -72,6 +73,9 @@ public:
|
|||
|
||||
virtual void stop() { };
|
||||
|
||||
virtual void pause() { };
|
||||
virtual void resume() { };
|
||||
|
||||
// Whether the logger prints the whole build log
|
||||
virtual bool isVerbose() { return false; }
|
||||
|
||||
|
|
@ -214,7 +218,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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
|
|
@ -7,7 +8,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 +34,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 +44,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 +70,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;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
|
@ -11,33 +12,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:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
|
|
@ -6,8 +7,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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <string_view>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -10,7 +11,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 +21,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 +37,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 +57,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 +86,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 +103,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 +142,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 +170,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 +186,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 +198,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 +213,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 +230,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 +250,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 +265,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 +278,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 +296,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 +313,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 +330,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 +419,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 +444,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 +496,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 +534,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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
|
|
@ -7,10 +8,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "comparator.hh"
|
||||
#include "types.hh"
|
||||
|
|
@ -13,7 +14,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 +45,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:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <cstdlib>
|
||||
#include <mutex>
|
||||
|
|
@ -7,22 +8,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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "serialise.hh"
|
||||
#include <archive.h>
|
||||
|
||||
|
|
@ -14,7 +17,7 @@ struct TarArchive {
|
|||
|
||||
TarArchive(const Path & path);
|
||||
|
||||
// disable copy constructor
|
||||
/// disable copy constructor
|
||||
TarArchive(const TarArchive &) = delete;
|
||||
|
||||
void close();
|
||||
|
|
|
|||
|
|
@ -107,15 +107,13 @@ namespace nix {
|
|||
}
|
||||
|
||||
TEST(CanonPath, within) {
|
||||
{
|
||||
ASSERT_TRUE(CanonPath("foo").isWithin(CanonPath("foo")));
|
||||
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("bar")));
|
||||
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("fo")));
|
||||
ASSERT_TRUE(CanonPath("foo/bar").isWithin(CanonPath("foo")));
|
||||
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("foo/bar")));
|
||||
ASSERT_TRUE(CanonPath("/foo/bar/default.nix").isWithin(CanonPath("/")));
|
||||
ASSERT_TRUE(CanonPath("/").isWithin(CanonPath("/")));
|
||||
}
|
||||
ASSERT_TRUE(CanonPath("foo").isWithin(CanonPath("foo")));
|
||||
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("bar")));
|
||||
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("fo")));
|
||||
ASSERT_TRUE(CanonPath("foo/bar").isWithin(CanonPath("foo")));
|
||||
ASSERT_FALSE(CanonPath("foo").isWithin(CanonPath("foo/bar")));
|
||||
ASSERT_TRUE(CanonPath("/foo/bar/default.nix").isWithin(CanonPath("/")));
|
||||
ASSERT_TRUE(CanonPath("/").isWithin(CanonPath("/")));
|
||||
}
|
||||
|
||||
TEST(CanonPath, sort) {
|
||||
|
|
@ -127,29 +125,38 @@ namespace nix {
|
|||
}
|
||||
|
||||
TEST(CanonPath, allowed) {
|
||||
{
|
||||
std::set<CanonPath> allowed {
|
||||
CanonPath("foo/bar"),
|
||||
CanonPath("foo!"),
|
||||
CanonPath("xyzzy"),
|
||||
CanonPath("a/b/c"),
|
||||
};
|
||||
std::set<CanonPath> allowed {
|
||||
CanonPath("foo/bar"),
|
||||
CanonPath("foo!"),
|
||||
CanonPath("xyzzy"),
|
||||
CanonPath("a/b/c"),
|
||||
};
|
||||
|
||||
ASSERT_TRUE (CanonPath("foo/bar").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("foo/bar/bla").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("foo").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("bar").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("bar/a").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b/c").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b/c/d").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b/c/d/e").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("a/b/a").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("a/b/d").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("aaa").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("zzz").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("/").isAllowed(allowed));
|
||||
}
|
||||
ASSERT_TRUE (CanonPath("foo/bar").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("foo/bar/bla").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("foo").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("bar").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("bar/a").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b/c").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b/c/d").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("a/b/c/d/e").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("a/b/a").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("a/b/d").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("aaa").isAllowed(allowed));
|
||||
ASSERT_FALSE(CanonPath("zzz").isAllowed(allowed));
|
||||
ASSERT_TRUE (CanonPath("/").isAllowed(allowed));
|
||||
}
|
||||
|
||||
TEST(CanonPath, makeRelative) {
|
||||
CanonPath d("/foo/bar");
|
||||
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar")), ".");
|
||||
ASSERT_EQ(d.makeRelative(CanonPath("/foo")), "..");
|
||||
ASSERT_EQ(d.makeRelative(CanonPath("/")), "../..");
|
||||
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy")), "xyzzy");
|
||||
ASSERT_EQ(d.makeRelative(CanonPath("/foo/bar/xyzzy/bla")), "xyzzy/bla");
|
||||
ASSERT_EQ(d.makeRelative(CanonPath("/foo/xyzzy/bla")), "../xyzzy/bla");
|
||||
ASSERT_EQ(d.makeRelative(CanonPath("/xyzzy/bla")), "../../xyzzy/bla");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <rapidcheck/gen/Arbitrary.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "sync.hh"
|
||||
#include "util.hh"
|
||||
|
|
@ -13,8 +14,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 +26,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 +76,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,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "error.hh"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "ref.hh"
|
||||
|
||||
|
|
@ -17,7 +18,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 +28,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 +52,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 +88,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
|
|
@ -22,21 +23,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_-]*";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "error.hh"
|
||||
|
||||
|
|
@ -7,7 +8,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 +30,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.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "types.hh"
|
||||
#include "error.hh"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue