1
1
Fork 0
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:
John Ericson 2023-04-02 16:21:38 -04:00
commit b2c9315bf2
209 changed files with 4006 additions and 2527 deletions

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include <nlohmann/json.hpp>
#include "config.hh"

View file

@ -1,4 +1,5 @@
#pragma once
///@file
namespace nix {

View file

@ -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);

View file

@ -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);

View file

@ -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
{

View file

@ -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;
}
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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()
{

View file

@ -1,3 +1,6 @@
#pragma once
///@file
#include <set>
#include <future>
#include "sync.hh"

View file

@ -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.
*
* ```

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include "ref.hh"
#include "types.hh"

View file

@ -1,3 +1,6 @@
#pragma once
///@file
#include "types.hh"
namespace nix {

View file

@ -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;

View file

@ -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:

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include "comparator.hh"
#include "error.hh"
@ -12,7 +13,7 @@ namespace nix {
*
* If you update this, dont forget to also change the map defining their string
* representation and documentation in the corresponding `.cc` file as well.
**/
*/
enum struct ExperimentalFeature
{
CaDerivations,

View file

@ -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
{

View file

@ -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)
{

View file

@ -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,

View file

@ -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";

View file

@ -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;

View file

@ -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,

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include "nlohmann/json_fwd.hpp"

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include <nlohmann/json.hpp>

View file

@ -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)
{

View file

@ -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;

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include <thread>
#include <atomic>

View file

@ -1,4 +1,5 @@
#pragma once
///@file
namespace nix {

View file

@ -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:

View file

@ -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
{

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include <string_view>

View file

@ -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;
};

View file

@ -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);

View file

@ -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:

View file

@ -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
{

View file

@ -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();

View file

@ -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");
}
}

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include <rapidcheck/gen/Arbitrary.h>

View file

@ -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,

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include "error.hh"

View file

@ -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;

View file

@ -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_-]*";

View file

@ -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 thats 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.

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include "types.hh"
#include "error.hh"

View file

@ -1,4 +1,5 @@
#pragma once
///@file
#include <iostream>
#include <string>