Merge remote-tracking branch 'upstream/master' into ca-floating-upstream
This commit is contained in:
commit
c5ccebae00
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -107,7 +107,7 @@ perl/Makefile.config
|
|||
|
||||
/src/resolve-system-dependencies/resolve-system-dependencies
|
||||
|
||||
inst/
|
||||
outputs/
|
||||
|
||||
*.a
|
||||
*.o
|
||||
|
@ -126,4 +126,10 @@ GRTAGS
|
|||
GSYMS
|
||||
GTAGS
|
||||
|
||||
# ccls
|
||||
/.ccls-cache
|
||||
|
||||
# auto-generated compilation database
|
||||
compile_commands.json
|
||||
|
||||
nix-rust/target
|
||||
|
|
|
@ -20,7 +20,7 @@ Information on additional installation methods is available on the [Nix download
|
|||
|
||||
## Building And Developing
|
||||
|
||||
See our [Hacking guide](https://hydra.nixos.org/job/nix/master/build.x86_64-linux/latest/download-by-type/doc/manual#chap-hacking) in our manual for instruction on how to
|
||||
See our [Hacking guide](https://hydra.nixos.org/job/nix/master/build.x86_64-linux/latest/download-by-type/doc/manual/hacking.html) in our manual for instruction on how to
|
||||
build nix from source with nix-build or how to get a development environment.
|
||||
|
||||
## Additional Resources
|
||||
|
|
|
@ -39,7 +39,7 @@ To build Nix itself in this shell:
|
|||
|
||||
```console
|
||||
[nix-shell]$ ./bootstrap.sh
|
||||
[nix-shell]$ ./configure $configureFlags
|
||||
[nix-shell]$ ./configure $configureFlags --prefix=$(pwd)/inst
|
||||
[nix-shell]$ make -j $NIX_BUILD_CORES
|
||||
```
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ features:
|
|||
- The binary tarball installer has been improved. You can now install
|
||||
Nix by running:
|
||||
|
||||
$ bash <(curl https://nixos.org/nix/install)
|
||||
$ bash <(curl -L https://nixos.org/nix/install)
|
||||
|
||||
- More evaluation errors include position information. For instance,
|
||||
selecting a missing attribute will print something like
|
||||
|
|
|
@ -10,7 +10,7 @@ in certain situations. In addition, it has the following new features:
|
|||
- The Nix installer now supports performing a Multi-User
|
||||
installation for Linux computers which are running systemd. You
|
||||
can select a Multi-User installation by passing the `--daemon`
|
||||
flag to the installer: `sh <(curl https://nixos.org/nix/install)
|
||||
flag to the installer: `sh <(curl -L https://nixos.org/nix/install)
|
||||
--daemon`.
|
||||
|
||||
The multi-user installer cannot handle systems with SELinux. If
|
||||
|
|
|
@ -87,6 +87,7 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
|
|||
else if (*i == '\n') str << "\\n";
|
||||
else if (*i == '\r') str << "\\r";
|
||||
else if (*i == '\t') str << "\\t";
|
||||
else if (*i == '$' && *(i+1) == '{') str << "\\" << *i;
|
||||
else str << *i;
|
||||
str << "\"";
|
||||
break;
|
||||
|
@ -1348,7 +1349,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res)
|
|||
}
|
||||
|
||||
Value * actualArgs = allocValue();
|
||||
mkAttrs(*actualArgs, fun.lambda.fun->formals->formals.size());
|
||||
mkAttrs(*actualArgs, std::max(static_cast<uint32_t>(fun.lambda.fun->formals->formals.size()), args.size()));
|
||||
|
||||
if (fun.lambda.fun->formals->ellipsis) {
|
||||
// If the formals have an ellipsis (eg the function accepts extra args) pass
|
||||
|
|
|
@ -40,7 +40,7 @@ DrvInfo::DrvInfo(EvalState & state, ref<Store> store, const std::string & drvPat
|
|||
throw Error("derivation '%s' does not have output '%s'", store->printStorePath(drvPath), outputName);
|
||||
auto & [outputName, output] = *i;
|
||||
|
||||
auto optStorePath = output.pathOpt(*store, drv.name, outputName);
|
||||
auto optStorePath = output.path(*store, drv.name, outputName);
|
||||
if (optStorePath)
|
||||
outPath = store->printStorePath(*optStorePath);
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ static void mkOutputString(EvalState & state, Value & v,
|
|||
const StorePath & drvPath, const BasicDerivation & drv,
|
||||
std::pair<string, DerivationOutput> o)
|
||||
{
|
||||
auto optOutputPath = o.second.pathOpt(*state.store, drv.name, o.first);
|
||||
auto optOutputPath = o.second.path(*state.store, drv.name, o.first);
|
||||
mkString(
|
||||
*state.allocAttr(v, state.symbols.create(o.first)),
|
||||
optOutputPath
|
||||
|
|
|
@ -718,16 +718,25 @@ typedef enum {rpAccept, rpDecline, rpPostpone} HookReply;
|
|||
|
||||
class SubstitutionGoal;
|
||||
|
||||
/* Unless we are repairing, we don't both to test validity and just assume it,
|
||||
so the choices are `Absent` or `Valid`. */
|
||||
enum struct PathStatus {
|
||||
Corrupt,
|
||||
Absent,
|
||||
Valid,
|
||||
};
|
||||
|
||||
struct InitialOutputStatus {
|
||||
StorePath path;
|
||||
/* The output optional indicates whether it's already valid; i.e. exists
|
||||
and is registered. If we're repairing, inner bool indicates whether the
|
||||
valid path is in fact not corrupt. Otherwise, the inner bool is always
|
||||
true (assumed no corruption). */
|
||||
std::optional<bool> valid;
|
||||
PathStatus status;
|
||||
/* Valid in the store, and additionally non-corrupt if we are repairing */
|
||||
bool isValid() const {
|
||||
return valid && *valid;
|
||||
return status == PathStatus::Valid;
|
||||
}
|
||||
/* Merely present, allowed to be corrupt */
|
||||
bool isPresent() const {
|
||||
return status == PathStatus::Corrupt
|
||||
|| status == PathStatus::Valid;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2186,10 +2195,10 @@ void DerivationGoal::startBuilder()
|
|||
: !needsHashRewrite()
|
||||
/* Can always use original path in sandbox */
|
||||
? status.known->path
|
||||
: !status.known->valid
|
||||
: !status.known->isPresent()
|
||||
/* If path doesn't yet exist can just use it */
|
||||
? status.known->path
|
||||
: buildMode != bmRepair && !*status.known->valid
|
||||
: buildMode != bmRepair && !status.known->isValid()
|
||||
/* If we aren't repairing we'll delete a corrupted path, so we
|
||||
can use original path */
|
||||
? status.known->path
|
||||
|
@ -2199,7 +2208,7 @@ void DerivationGoal::startBuilder()
|
|||
scratchOutputs.insert_or_assign(outputName, scratchPath);
|
||||
|
||||
/* A non-removed corrupted path needs to be stored here, too */
|
||||
if (buildMode == bmRepair && !*status.known->valid)
|
||||
if (buildMode == bmRepair && !status.known->isValid())
|
||||
redirectedBadOutputs.insert(status.known->path);
|
||||
|
||||
/* Substitute output placeholders with the scratch output paths.
|
||||
|
@ -4110,7 +4119,7 @@ void DerivationGoal::registerOutputs()
|
|||
floating CA derivations and hash-mismatching fixed-output
|
||||
derivations. */
|
||||
PathLocks dynamicOutputLock;
|
||||
auto optFixedPath = output.pathOpt(worker.store, drv->name, outputName);
|
||||
auto optFixedPath = output.path(worker.store, drv->name, outputName);
|
||||
if (!optFixedPath ||
|
||||
worker.store.printStorePath(*optFixedPath) != finalDestPath)
|
||||
{
|
||||
|
@ -4289,26 +4298,32 @@ void DerivationGoal::registerOutputs()
|
|||
/* Register each output path as valid, and register the sets of
|
||||
paths referenced by each of them. If there are cycles in the
|
||||
outputs, this will fail. */
|
||||
{
|
||||
ValidPathInfos infos2;
|
||||
for (auto & [outputName, newInfo] : infos) {
|
||||
if (useDerivation)
|
||||
worker.store.linkDeriverToPath(drvPath, outputName, newInfo.path);
|
||||
else {
|
||||
/* Once a floating CA derivations reaches this point, it must
|
||||
already be resolved, drvPath the basic derivation path, and
|
||||
a file existsing at that path for sake of the DB's foreign key. */
|
||||
assert(drv->type() != DerivationType::CAFloating);
|
||||
}
|
||||
infos2.push_back(newInfo);
|
||||
}
|
||||
worker.store.registerValidPaths(infos2);
|
||||
ValidPathInfos infos2;
|
||||
for (auto & [outputName, newInfo] : infos) {
|
||||
infos2.push_back(newInfo);
|
||||
}
|
||||
worker.store.registerValidPaths(infos2);
|
||||
|
||||
/* In case of a fixed-output derivation hash mismatch, throw an
|
||||
exception now that we have registered the output as valid. */
|
||||
if (delayedException)
|
||||
std::rethrow_exception(delayedException);
|
||||
|
||||
/* If we made it this far, we are sure the output matches the derivation
|
||||
(since the delayedException would be a fixed output CA mismatch). That
|
||||
means it's safe to link the derivation to the output hash. We must do
|
||||
that for floating CA derivations, which otherwise couldn't be cached,
|
||||
but it's fine to do in all cases. */
|
||||
for (auto & [outputName, newInfo] : infos) {
|
||||
if (useDerivation)
|
||||
worker.store.linkDeriverToPath(drvPath, outputName, newInfo.path);
|
||||
else {
|
||||
/* Once a floating CA derivations reaches this point, it must
|
||||
already be resolved, drvPath the basic derivation path, and
|
||||
a file existsing at that path for sake of the DB's foreign key. */
|
||||
assert(drv->type() != DerivationType::CAFloating);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -4601,7 +4616,7 @@ std::map<std::string, std::optional<StorePath>> DerivationGoal::queryPartialDeri
|
|||
if (drv->type() != DerivationType::CAFloating) {
|
||||
std::map<std::string, std::optional<StorePath>> res;
|
||||
for (auto & [name, output] : drv->outputs)
|
||||
res.insert_or_assign(name, output.pathOpt(worker.store, drv->name, name));
|
||||
res.insert_or_assign(name, output.path(worker.store, drv->name, name));
|
||||
return res;
|
||||
} else {
|
||||
return worker.store.queryPartialDerivationOutputMap(drvPath);
|
||||
|
@ -4632,9 +4647,11 @@ void DerivationGoal::checkPathValidity()
|
|||
auto outputPath = *i.second;
|
||||
info.known = {
|
||||
.path = outputPath,
|
||||
.valid = !worker.store.isValidPath(outputPath)
|
||||
? std::optional<bool> {}
|
||||
: !checkHash || worker.pathContentsGood(outputPath),
|
||||
.status = !worker.store.isValidPath(outputPath)
|
||||
? PathStatus::Absent
|
||||
: !checkHash || worker.pathContentsGood(outputPath)
|
||||
? PathStatus::Valid
|
||||
: PathStatus::Corrupt,
|
||||
};
|
||||
}
|
||||
initialOutputs.insert_or_assign(i.first, info);
|
||||
|
|
|
@ -232,7 +232,7 @@ struct ClientSettings
|
|||
else if (setSubstituters(settings.extraSubstituters))
|
||||
;
|
||||
else
|
||||
warn("ignoring the user-specified setting '%s', because it is a restricted setting and you are not a trusted user", name);
|
||||
debug("ignoring the client-specified setting '%s', because it is a restricted setting and you are not a trusted user", name);
|
||||
} catch (UsageError & e) {
|
||||
warn(e.what());
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
std::optional<StorePath> DerivationOutput::pathOpt(const Store & store, std::string_view drvName, std::string_view outputName) const
|
||||
std::optional<StorePath> DerivationOutput::path(const Store & store, std::string_view drvName, std::string_view outputName) const
|
||||
{
|
||||
return std::visit(overloaded {
|
||||
[](DerivationOutputInputAddressed doi) -> std::optional<StorePath> {
|
||||
|
@ -557,7 +557,7 @@ DerivationOutputsAndOptPaths BasicDerivation::outputsAndOptPaths(const Store & s
|
|||
for (auto output : outputs)
|
||||
outsAndOptPaths.insert(std::make_pair(
|
||||
output.first,
|
||||
std::make_pair(output.second, output.second.pathOpt(store, name, output.first))
|
||||
std::make_pair(output.second, output.second.path(store, name, output.first))
|
||||
)
|
||||
);
|
||||
return outsAndOptPaths;
|
||||
|
|
|
@ -52,7 +52,7 @@ struct DerivationOutput
|
|||
/* Note, when you use this function you should make sure that you're passing
|
||||
the right derivation name. When in doubt, you should use the safer
|
||||
interface provided by BasicDerivation::outputsAndOptPaths */
|
||||
std::optional<StorePath> pathOpt(const Store & store, std::string_view drvName, std::string_view outputName) const;
|
||||
std::optional<StorePath> path(const Store & store, std::string_view drvName, std::string_view outputName) const;
|
||||
};
|
||||
|
||||
typedef std::map<string, DerivationOutput> DerivationOutputs;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "serialise.hh"
|
||||
#include "util.hh"
|
||||
#include "remote-fs-accessor.hh"
|
||||
#include "remote-store.hh"
|
||||
#include "worker-protocol.hh"
|
||||
#include "archive.hh"
|
||||
|
@ -43,8 +44,11 @@ StorePathCAMap readStorePathCAMap(const Store & store, Source & from)
|
|||
{
|
||||
StorePathCAMap paths;
|
||||
auto count = readNum<size_t>(from);
|
||||
while (count--)
|
||||
paths.insert_or_assign(store.parseStorePath(readString(from)), parseContentAddressOpt(readString(from)));
|
||||
while (count--) {
|
||||
auto path = store.parseStorePath(readString(from));
|
||||
auto ca = parseContentAddressOpt(readString(from));
|
||||
paths.insert_or_assign(path, ca);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
|
@ -476,10 +480,26 @@ StorePathSet RemoteStore::queryDerivationOutputs(const StorePath & path)
|
|||
|
||||
std::map<std::string, std::optional<StorePath>> RemoteStore::queryPartialDerivationOutputMap(const StorePath & path)
|
||||
{
|
||||
auto conn(getConnection());
|
||||
conn->to << wopQueryDerivationOutputMap << printStorePath(path);
|
||||
conn.processStderr();
|
||||
return worker_proto::read(*this, conn->from, Phantom<std::map<std::string, std::optional<StorePath>>> {});
|
||||
if (GET_PROTOCOL_MINOR(getProtocol()) >= 0x16) {
|
||||
auto conn(getConnection());
|
||||
conn->to << wopQueryDerivationOutputMap << printStorePath(path);
|
||||
conn.processStderr();
|
||||
return worker_proto::read(*this, conn->from, Phantom<std::map<std::string, std::optional<StorePath>>> {});
|
||||
} else {
|
||||
// Fallback for old daemon versions.
|
||||
// For floating-CA derivations (and their co-dependencies) this is an
|
||||
// under-approximation as it only returns the paths that can be inferred
|
||||
// from the derivation itself (and not the ones that are known because
|
||||
// the have been built), but as old stores don't handle floating-CA
|
||||
// derivations this shouldn't matter
|
||||
auto derivation = readDerivation(path);
|
||||
auto outputsWithOptPaths = derivation.outputsAndOptPaths(*this);
|
||||
std::map<std::string, std::optional<StorePath>> ret;
|
||||
for (auto & [outputName, outputAndPath] : outputsWithOptPaths) {
|
||||
ret.emplace(outputName, outputAndPath.second);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -868,6 +888,18 @@ RemoteStore::Connection::~Connection()
|
|||
}
|
||||
}
|
||||
|
||||
void RemoteStore::narFromPath(const StorePath & path, Sink & sink)
|
||||
{
|
||||
auto conn(connections->get());
|
||||
conn->to << wopNarFromPath << printStorePath(path);
|
||||
conn->processStderr();
|
||||
copyNAR(conn->from, sink);
|
||||
}
|
||||
|
||||
ref<FSAccessor> RemoteStore::getFSAccessor()
|
||||
{
|
||||
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()));
|
||||
}
|
||||
|
||||
static Logger::Fields readFields(Source & from)
|
||||
{
|
||||
|
|
|
@ -131,6 +131,10 @@ protected:
|
|||
|
||||
friend struct ConnectionHandle;
|
||||
|
||||
virtual ref<FSAccessor> getFSAccessor() override;
|
||||
|
||||
virtual void narFromPath(const StorePath & path, Sink & sink) override;
|
||||
|
||||
private:
|
||||
|
||||
std::atomic_bool failed{false};
|
||||
|
@ -149,6 +153,12 @@ public:
|
|||
bool sameMachine() override
|
||||
{ return true; }
|
||||
|
||||
ref<FSAccessor> getFSAccessor() override
|
||||
{ return LocalFSStore::getFSAccessor(); }
|
||||
|
||||
void narFromPath(const StorePath & path, Sink & sink) override
|
||||
{ LocalFSStore::narFromPath(path, sink); }
|
||||
|
||||
private:
|
||||
|
||||
ref<RemoteStore::Connection> openConnection() override;
|
||||
|
|
|
@ -40,10 +40,6 @@ public:
|
|||
bool sameMachine() override
|
||||
{ return false; }
|
||||
|
||||
void narFromPath(const StorePath & path, Sink & sink) override;
|
||||
|
||||
ref<FSAccessor> getFSAccessor() override;
|
||||
|
||||
private:
|
||||
|
||||
struct Connection : RemoteStore::Connection
|
||||
|
@ -68,19 +64,6 @@ private:
|
|||
};
|
||||
};
|
||||
|
||||
void SSHStore::narFromPath(const StorePath & path, Sink & sink)
|
||||
{
|
||||
auto conn(connections->get());
|
||||
conn->to << wopNarFromPath << printStorePath(path);
|
||||
conn->processStderr();
|
||||
copyNAR(conn->from, sink);
|
||||
}
|
||||
|
||||
ref<FSAccessor> SSHStore::getFSAccessor()
|
||||
{
|
||||
return make_ref<RemoteFSAccessor>(ref<Store>(shared_from_this()));
|
||||
}
|
||||
|
||||
ref<RemoteStore::Connection> SSHStore::openConnection()
|
||||
{
|
||||
auto conn = make_ref<Connection>();
|
||||
|
|
|
@ -98,8 +98,8 @@ static void _main(int argc, char * * argv)
|
|||
|
||||
// List of environment variables kept for --pure
|
||||
std::set<string> keepVars{
|
||||
"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM",
|
||||
"IN_NIX_SHELL", "TZ", "PAGER", "NIX_BUILD_SHELL", "SHLVL",
|
||||
"HOME", "USER", "LOGNAME", "DISPLAY", "PATH", "TERM", "IN_NIX_SHELL",
|
||||
"NIX_SHELL_PRESERVE_PROMPT", "TZ", "PAGER", "NIX_BUILD_SHELL", "SHLVL",
|
||||
"http_proxy", "https_proxy", "ftp_proxy", "all_proxy", "no_proxy"
|
||||
};
|
||||
|
||||
|
@ -446,7 +446,7 @@ static void _main(int argc, char * * argv)
|
|||
"PATH=%4%:\"$PATH\"; "
|
||||
"SHELL=%5%; "
|
||||
"set +e; "
|
||||
R"s([ -n "$PS1" ] && PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] '; )s"
|
||||
R"s([ -n "$PS1" -a -z "$NIX_SHELL_PRESERVE_PROMPT" ] && PS1='\n\[\033[1;32m\][nix-shell:\w]\$\[\033[0m\] '; )s"
|
||||
"if [ \"$(type -t runHook)\" = function ]; then runHook shellHook; fi; "
|
||||
"unset NIX_ENFORCE_PURITY; "
|
||||
"shopt -u nullglob; "
|
||||
|
|
|
@ -53,7 +53,7 @@ trap finish EXIT
|
|||
|
||||
# First setup Nix
|
||||
cleanup
|
||||
curl -o install https://nixos.org/nix/install
|
||||
curl -L -o install https://nixos.org/nix/install
|
||||
yes | bash ./install
|
||||
verify
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
"This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', ${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: ${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\ncut -d $'\\t' -f 1\nending dollar $$\n"
|
||||
"This is an indented multi-line string\nliteral. An amount of whitespace at\nthe start of each line matching the minimum\nindentation of all lines in the string\nliteral together will be removed. Thus,\nin this case four spaces will be\nstripped from each line, even though\n THIS LINE is indented six spaces.\n\nAlso, empty lines don't count in the\ndetermination of the indentation level (the\nprevious empty line has indentation 0, but\nit doesn't matter).\nIf the string starts with whitespace\n followed by a newline, it's stripped, but\n that's not the case here. Two spaces are\n stripped because of the \" \" at the start. \nThis line is indented\na bit further.\nAnti-quotations, like so, are\nalso allowed.\n The \\ is not special here.\n' can be followed by any character except another ', e.g. 'x'.\nLikewise for $, e.g. $$ or $varName.\nBut ' followed by ' is special, as is $ followed by {.\nIf you want them, use anti-quotations: '', \${.\n Tabs are not interpreted as whitespace (since we can't guess\n what tab settings are intended), so don't use them.\n\tThis line starts with a space and a tab, so only one\n space will be stripped from each line.\nAlso note that if the last line (just before the closing ' ')\nconsists only of whitespace, it's ignored. But here there is\nsome non-whitespace stuff, so the line isn't removed. \nThis shows a hacky way to preserve an empty line after the start.\nBut there's no reason to do so: you could just repeat the empty\nline.\n Similarly you can force an indentation level,\n in this case to 2 spaces. This works because the anti-quote\n is significant (not whitespace).\nstart on network-interfaces\n\nstart script\n\n rm -f /var/run/opengl-driver\n ln -sf 123 /var/run/opengl-driver\n\n rm -f /var/log/slim.log\n \nend script\n\nenv SLIM_CFGFILE=abc\nenv SLIM_THEMESDIR=def\nenv FONTCONFIG_FILE=/etc/fonts/fonts.conf \t\t\t\t# !!! cleanup\nenv XKB_BINDIR=foo/bin \t\t\t\t# Needed for the Xkb extension.\nenv LD_LIBRARY_PATH=libX11/lib:libXext/lib:/usr/lib/ # related to xorg-sys-opengl - needed to load libglx for (AI)GLX support (for compiz)\n\nenv XORG_DRI_DRIVER_PATH=nvidiaDrivers/X11R6/lib/modules/drivers/ \n\nexec slim/bin/slim\nEscaping of ' followed by ': ''\nEscaping of $ followed by {: \${\nAnd finally to interpret \\n etc. as in a string: \n, \r, \t.\nfoo\n'bla'\nbar\ncut -d $'\\t' -f 1\nending dollar $$\n"
|
||||
|
|
|
@ -13,7 +13,7 @@ let
|
|||
builder = ./user-envs.builder.sh;
|
||||
} // {
|
||||
meta = {
|
||||
description = "A silly test package";
|
||||
description = "A silly test package with some \${escaped anti-quotation} in it";
|
||||
};
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue