* Get `nix-push' working again. It now uses Nix/Fix to create Nix
archives (using the package in corepkgs/nar). * queryPathByHash -> expandHash, and it takes an argument specifying the target path (which may be empty). * Install the core Fix packages in $prefix/share/fix. TODO: bootstrap Nix and install Nix as a Fix package.
This commit is contained in:
parent
5d4b90b689
commit
d072485d28
16 changed files with 154 additions and 54 deletions
|
@ -1 +1 @@
|
||||||
SUBDIRS = src scripts
|
SUBDIRS = src scripts corepkgs
|
||||||
|
|
|
@ -13,9 +13,10 @@ AC_PROG_RANLIB
|
||||||
|
|
||||||
# Unix shell scripting should die a slow and painful death.
|
# Unix shell scripting should die a slow and painful death.
|
||||||
AC_DEFINE_UNQUOTED(NIX_STORE_DIR, "$(eval echo $prefix/store)", Nix store directory.)
|
AC_DEFINE_UNQUOTED(NIX_STORE_DIR, "$(eval echo $prefix/store)", Nix store directory.)
|
||||||
|
AC_DEFINE_UNQUOTED(NIX_DATA_DIR, "$(eval echo $datadir)", Nix data directory.)
|
||||||
AC_DEFINE_UNQUOTED(NIX_STATE_DIR, "$(eval echo $localstatedir/nix)", Nix state directory.)
|
AC_DEFINE_UNQUOTED(NIX_STATE_DIR, "$(eval echo $localstatedir/nix)", Nix state directory.)
|
||||||
AC_DEFINE_UNQUOTED(NIX_LOG_DIR, "$(eval echo $localstatedir/log/nix)", Nix log file directory.)
|
AC_DEFINE_UNQUOTED(NIX_LOG_DIR, "$(eval echo $localstatedir/log/nix)", Nix log file directory.)
|
||||||
|
|
||||||
AM_CONFIG_HEADER([config.h])
|
AM_CONFIG_HEADER([config.h])
|
||||||
AC_CONFIG_FILES([Makefile src/Makefile scripts/Makefile])
|
AC_CONFIG_FILES([Makefile src/Makefile scripts/Makefile corepkgs/Makefile])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
8
corepkgs/Makefile.am
Normal file
8
corepkgs/Makefile.am
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
install-data-local:
|
||||||
|
$(INSTALL) -d $(datadir)/fix
|
||||||
|
$(INSTALL) -d $(datadir)/fix/fetchurl
|
||||||
|
$(INSTALL_DATA) fetchurl/fetchurl.fix $(datadir)/fix/fetchurl
|
||||||
|
$(INSTALL_DATA) fetchurl/fetchurl.sh $(datadir)/fix/fetchurl
|
||||||
|
$(INSTALL) -d $(datadir)/fix/nar
|
||||||
|
$(INSTALL_DATA) nar/nar.fix $(datadir)/fix/nar
|
||||||
|
$(INSTALL_DATA) nar/nar.sh $(datadir)/fix/nar
|
8
corepkgs/nar/nar.fix
Normal file
8
corepkgs/nar/nar.fix
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
Function(["path", "name"],
|
||||||
|
Package(
|
||||||
|
[ ("name", Var("name"))
|
||||||
|
, ("build", Relative("nar/nar.sh"))
|
||||||
|
, ("path", Var("path"))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
3
corepkgs/nar/nar.sh
Normal file
3
corepkgs/nar/nar.sh
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
/tmp/nix/bin/nix --dump --file "$path" > $out || exit 1
|
|
@ -1,5 +1,5 @@
|
||||||
bin_SCRIPTS = nix-switch nix-collect-garbage \
|
bin_SCRIPTS = nix-switch nix-collect-garbage \
|
||||||
nix-pull-prebuilts nix-push-prebuilts
|
nix-pull nix-push
|
||||||
|
|
||||||
install-exec-local:
|
install-exec-local:
|
||||||
$(INSTALL) -d $(sysconfdir)/profile.d
|
$(INSTALL) -d $(sysconfdir)/profile.d
|
||||||
|
|
2
scripts/nix-pull
Normal file
2
scripts/nix-pull
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#! /usr/bin/perl -w
|
||||||
|
|
60
scripts/nix-push
Normal file
60
scripts/nix-push
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#! /usr/bin/perl -w
|
||||||
|
|
||||||
|
my @pushlist;
|
||||||
|
|
||||||
|
foreach my $hash (@ARGV) {
|
||||||
|
|
||||||
|
die unless $hash =~ /^([0-9a-z]{32})$/;
|
||||||
|
|
||||||
|
# Get all paths referenced by the normalisation of the given
|
||||||
|
# fstate expression.
|
||||||
|
my @paths;
|
||||||
|
open PATHS, "nix -qrh $hash 2> /dev/null |" or die "nix -qrh";
|
||||||
|
while (<PATHS>) {
|
||||||
|
chomp;
|
||||||
|
next unless /^\//;
|
||||||
|
push @paths, $_;
|
||||||
|
}
|
||||||
|
close PATHS;
|
||||||
|
|
||||||
|
# For each path, create a Fix expression that turns the path into
|
||||||
|
# a Nix archive.
|
||||||
|
foreach my $path (@paths) {
|
||||||
|
|
||||||
|
# Hash the path.
|
||||||
|
my $phash = `nix-hash $path`;
|
||||||
|
$? and die "nix-hash";
|
||||||
|
chomp $phash;
|
||||||
|
die unless $phash =~ /^([0-9a-z]{32})$/;
|
||||||
|
|
||||||
|
# Construct a Fix expression that creates a Nar archive.
|
||||||
|
my $fixexpr =
|
||||||
|
"App(IncludeFix(\"nar/nar.fix\"), " .
|
||||||
|
"[ (\"path\", Path(\"$path\", Hash(\"$phash\"), [Include(\"$hash\")]))" .
|
||||||
|
", (\"name\", \"$phash.nar\")" .
|
||||||
|
"])";
|
||||||
|
|
||||||
|
my $fixfile = "/tmp/nix-push-tmp.fix";
|
||||||
|
open FIX, ">$fixfile";
|
||||||
|
print FIX $fixexpr;
|
||||||
|
close FIX;
|
||||||
|
|
||||||
|
# Instantiate a Nix expression from the Fix expression.
|
||||||
|
my $nhash = `fix $fixfile`;
|
||||||
|
$? and die "instantiating Nix archive expression";
|
||||||
|
chomp $nhash;
|
||||||
|
die unless $nhash =~ /^([0-9a-z]{32})$/;
|
||||||
|
|
||||||
|
# Realise the Nix expression.
|
||||||
|
my $npath = `nix -qph $nhash 2> /dev/null`;
|
||||||
|
$? and die "creating Nix archive";
|
||||||
|
chomp $npath;
|
||||||
|
|
||||||
|
push @pushlist, $npath;
|
||||||
|
|
||||||
|
print "$path -> $npath\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Push the prebuilts to the server. !!! FIXME
|
||||||
|
system "rsync -av -e ssh @pushlist eelco\@losser.st-lab.cs.uu.nl:/home/eelco/public_html/nix-dist/";
|
|
@ -15,6 +15,8 @@ static Strings searchDirs;
|
||||||
|
|
||||||
static string searchPath(string relPath)
|
static string searchPath(string relPath)
|
||||||
{
|
{
|
||||||
|
if (string(relPath, 0, 1) == "/") return relPath;
|
||||||
|
|
||||||
for (Strings::iterator i = searchDirs.begin();
|
for (Strings::iterator i = searchDirs.begin();
|
||||||
i != searchDirs.end(); i++)
|
i != searchDirs.end(); i++)
|
||||||
{
|
{
|
||||||
|
@ -218,7 +220,10 @@ static Expr evalExpr(Expr e)
|
||||||
|
|
||||||
static Expr evalFile(string relPath)
|
static Expr evalFile(string relPath)
|
||||||
{
|
{
|
||||||
Expr e = ATreadFromNamedFile(searchPath(relPath).c_str());
|
string path = searchPath(relPath);
|
||||||
|
Expr e = ATreadFromNamedFile(path.c_str());
|
||||||
|
if (!e)
|
||||||
|
throw Error(format("unable to read a term from `%1%'") % path);
|
||||||
return evalExpr(e);
|
return evalExpr(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +233,7 @@ void run(Strings args)
|
||||||
Strings files;
|
Strings files;
|
||||||
|
|
||||||
searchDirs.push_back(".");
|
searchDirs.push_back(".");
|
||||||
|
searchDirs.push_back(nixDataDir + "/fix");
|
||||||
|
|
||||||
for (Strings::iterator it = args.begin();
|
for (Strings::iterator it = args.begin();
|
||||||
it != args.end(); )
|
it != args.end(); )
|
||||||
|
|
|
@ -149,7 +149,7 @@ Hash hashTerm(ATerm t)
|
||||||
|
|
||||||
ATerm termFromHash(const Hash & hash, string * p)
|
ATerm termFromHash(const Hash & hash, string * p)
|
||||||
{
|
{
|
||||||
string path = queryPathByHash(hash);
|
string path = expandHash(hash);
|
||||||
if (p) *p = path;
|
if (p) *p = path;
|
||||||
ATerm t = ATreadFromNamedFile(path.c_str());
|
ATerm t = ATreadFromNamedFile(path.c_str());
|
||||||
if (!t) throw Error(format("cannot read aterm %1%") % path);
|
if (!t) throw Error(format("cannot read aterm %1%") % path);
|
||||||
|
@ -253,26 +253,6 @@ static FState realise(FState fs, StringSet & paths)
|
||||||
/* Expand the hash into the target path. */
|
/* Expand the hash into the target path. */
|
||||||
expandHash(hash, path);
|
expandHash(hash, path);
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Perhaps the path already exists and has the right hash? */
|
|
||||||
if (pathExists(path)) {
|
|
||||||
|
|
||||||
if (hash != hashPath(path))
|
|
||||||
throw Error(format("path %1% exists, but does not have hash %2%")
|
|
||||||
% path % (string) hash);
|
|
||||||
|
|
||||||
debug(format("path %1% already has hash %2%")
|
|
||||||
% path % (string) hash);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* Do we know a path with that hash? If so, copy it. */
|
|
||||||
string path2 = queryPathByHash(hash);
|
|
||||||
copyPath(path2, path);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return nf;
|
return nf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
|
|
||||||
string dbHash2Paths = "hash2paths";
|
string dbHash2Paths = "hash2paths";
|
||||||
string dbSuccessors = "successors";
|
string dbSuccessors = "successors";
|
||||||
|
string dbSubstitutes = "substitutes";
|
||||||
|
|
||||||
|
|
||||||
string nixStore = "/UNINIT";
|
string nixStore = "/UNINIT";
|
||||||
|
string nixDataDir = "/UNINIT";
|
||||||
string nixLogDir = "/UNINIT";
|
string nixLogDir = "/UNINIT";
|
||||||
string nixDB = "/UNINIT";
|
string nixDB = "/UNINIT";
|
||||||
|
|
||||||
|
@ -14,4 +17,5 @@ void initDB()
|
||||||
{
|
{
|
||||||
createDB(nixDB, dbHash2Paths);
|
createDB(nixDB, dbHash2Paths);
|
||||||
createDB(nixDB, dbSuccessors);
|
createDB(nixDB, dbSuccessors);
|
||||||
|
createDB(nixDB, dbSubstitutes);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,8 @@ extern string dbSubstitutes;
|
||||||
derived files. */
|
derived files. */
|
||||||
extern string nixStore;
|
extern string nixStore;
|
||||||
|
|
||||||
|
extern string nixDataDir; /* !!! fix */
|
||||||
|
|
||||||
/* nixLogDir is the directory where we log various operations. */
|
/* nixLogDir is the directory where we log various operations. */
|
||||||
extern string nixLogDir;
|
extern string nixLogDir;
|
||||||
|
|
||||||
|
|
24
src/nix.cc
24
src/nix.cc
|
@ -37,7 +37,7 @@ static ArgType argType = atpUnknown;
|
||||||
|
|
||||||
Source selection for --install, --dump:
|
Source selection for --install, --dump:
|
||||||
|
|
||||||
--file / -f: by file name
|
--file / -f: by file name !!! -> path
|
||||||
--hash / -h: by hash
|
--hash / -h: by hash
|
||||||
|
|
||||||
Query flags:
|
Query flags:
|
||||||
|
@ -87,6 +87,12 @@ static Hash argToHash(const string & arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static FState hash2fstate(Hash hash)
|
||||||
|
{
|
||||||
|
return ATmake("Include(<str>)", ((string) hash).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Realise (or install) paths from the given Nix fstate
|
/* Realise (or install) paths from the given Nix fstate
|
||||||
expressions. */
|
expressions. */
|
||||||
static void opInstall(Strings opFlags, Strings opArgs)
|
static void opInstall(Strings opFlags, Strings opArgs)
|
||||||
|
@ -98,7 +104,7 @@ static void opInstall(Strings opFlags, Strings opArgs)
|
||||||
it != opArgs.end(); it++)
|
it != opArgs.end(); it++)
|
||||||
{
|
{
|
||||||
StringSet paths;
|
StringSet paths;
|
||||||
realiseFState(termFromHash(argToHash(*it)), paths);
|
realiseFState(hash2fstate(argToHash(*it)), paths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,14 +163,16 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
|
|
||||||
switch (query) {
|
switch (query) {
|
||||||
|
|
||||||
case qPath:
|
case qPath: {
|
||||||
|
StringSet refs;
|
||||||
cout << format("%s\n") %
|
cout << format("%s\n") %
|
||||||
(string) fstatePath(termFromHash(hash));
|
(string) fstatePath(realiseFState(termFromHash(hash), refs));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case qRefs: {
|
case qRefs: {
|
||||||
StringSet refs;
|
StringSet refs;
|
||||||
FState fs = ATmake("Include(<str>)", ((string) hash).c_str());
|
FState fs = hash2fstate(hash);
|
||||||
fstateRefs(realiseFState(fs, refs), refs);
|
fstateRefs(realiseFState(fs, refs), refs);
|
||||||
for (StringSet::iterator j = refs.begin();
|
for (StringSet::iterator j = refs.begin();
|
||||||
j != refs.end(); j++)
|
j != refs.end(); j++)
|
||||||
|
@ -203,10 +211,8 @@ static void opDump(Strings opFlags, Strings opArgs)
|
||||||
string arg = *opArgs.begin();
|
string arg = *opArgs.begin();
|
||||||
string path;
|
string path;
|
||||||
|
|
||||||
if (argType == atpHash)
|
if (argType == atpHash) path = expandHash(parseHash(arg));
|
||||||
path = queryPathByHash(parseHash(arg));
|
else if (argType == atpPath) path = arg;
|
||||||
else if (argType == atpPath)
|
|
||||||
path = arg;
|
|
||||||
|
|
||||||
dumpPath(path, sink);
|
dumpPath(path, sink);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ static void initAndRun(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
/* Setup Nix paths. */
|
/* Setup Nix paths. */
|
||||||
nixStore = NIX_STORE_DIR;
|
nixStore = NIX_STORE_DIR;
|
||||||
|
nixDataDir = NIX_DATA_DIR;
|
||||||
nixLogDir = NIX_LOG_DIR;
|
nixLogDir = NIX_LOG_DIR;
|
||||||
nixDB = (string) NIX_STATE_DIR + "/nixstate.db";
|
nixDB = (string) NIX_STATE_DIR + "/nixstate.db";
|
||||||
|
|
||||||
|
|
51
src/store.cc
51
src/store.cc
|
@ -131,25 +131,53 @@ bool isInPrefix(const string & path, const string & _prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static string queryPathByHashPrefix(Hash hash, const string & prefix)
|
string expandHash(const Hash & hash, const string & target,
|
||||||
|
const string & prefix)
|
||||||
{
|
{
|
||||||
Strings paths;
|
Strings paths;
|
||||||
|
|
||||||
|
if (!target.empty() && !isInPrefix(target, prefix))
|
||||||
|
abort();
|
||||||
|
|
||||||
if (!queryListDB(nixDB, dbHash2Paths, hash, paths))
|
if (!queryListDB(nixDB, dbHash2Paths, hash, paths))
|
||||||
throw Error(format("no paths known with hash `%1%'") % (string) hash);
|
throw Error(format("no paths known with hash `%1%'") % (string) hash);
|
||||||
|
|
||||||
/* Arbitrarily pick the first one that exists and still hash the
|
/* !!! we shouldn't check for staleness by default --- too slow */
|
||||||
right hash. */
|
|
||||||
|
|
||||||
|
/* Pick one equal to `target'. */
|
||||||
|
if (!target.empty()) {
|
||||||
|
|
||||||
|
for (Strings::iterator i = paths.begin();
|
||||||
|
i != paths.end(); i++)
|
||||||
|
{
|
||||||
|
string path = *i;
|
||||||
|
try {
|
||||||
|
if (path == target && hashPath(path) == hash)
|
||||||
|
return path;
|
||||||
|
} catch (Error & e) {
|
||||||
|
debug(format("stale path: %1%") % e.msg());
|
||||||
|
/* try next one */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Arbitrarily pick the first one that exists and isn't stale. */
|
||||||
for (Strings::iterator it = paths.begin();
|
for (Strings::iterator it = paths.begin();
|
||||||
it != paths.end(); it++)
|
it != paths.end(); it++)
|
||||||
{
|
{
|
||||||
string path = *it;
|
string path = *it;
|
||||||
try {
|
try {
|
||||||
if (isInPrefix(path, prefix) && hashPath(path) == hash)
|
if (isInPrefix(path, prefix) && hashPath(path) == hash) {
|
||||||
return path;
|
if (target.empty())
|
||||||
|
return path;
|
||||||
|
else {
|
||||||
|
copyPath(path, target);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
debug(format("checking hash: %1%") % e.msg());
|
debug(format("stale path: %1%") % e.msg());
|
||||||
/* try next one */
|
/* try next one */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,16 +185,7 @@ static string queryPathByHashPrefix(Hash hash, const string & prefix)
|
||||||
throw Error(format("all paths with hash `%1%' are stale") % (string) hash);
|
throw Error(format("all paths with hash `%1%' are stale") % (string) hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string expandHash(const Hash & hash, const string & outPath = "")
|
|
||||||
{
|
|
||||||
|
|
||||||
string queryPathByHash(Hash hash)
|
|
||||||
{
|
|
||||||
return queryPathByHashPrefix(hash, "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void addToStore(string srcPath, string & dstPath, Hash & hash)
|
void addToStore(string srcPath, string & dstPath, Hash & hash)
|
||||||
{
|
{
|
||||||
srcPath = absPath(srcPath);
|
srcPath = absPath(srcPath);
|
||||||
|
@ -174,7 +193,7 @@ void addToStore(string srcPath, string & dstPath, Hash & hash)
|
||||||
hash = hashPath(srcPath);
|
hash = hashPath(srcPath);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
dstPath = queryPathByHashPrefix(hash, nixStore);
|
dstPath = expandHash(hash, "", nixStore);
|
||||||
return;
|
return;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,15 +13,15 @@ void copyPath(string src, string dst);
|
||||||
/* Register a path keyed on its hash. */
|
/* Register a path keyed on its hash. */
|
||||||
Hash registerPath(const string & path, Hash hash = Hash());
|
Hash registerPath(const string & path, Hash hash = Hash());
|
||||||
|
|
||||||
/* Return a path whose contents have the given hash. If outPath is
|
/* Return a path whose contents have the given hash. If target is
|
||||||
not empty, ensure that such a path is realised in outPath (if
|
not empty, ensure that such a path is realised in target (if
|
||||||
necessary by copying from another location). If prefix is not
|
necessary by copying from another location). If prefix is not
|
||||||
empty, only return a path that is an descendent of prefix.
|
empty, only return a path that is an descendent of prefix.
|
||||||
|
|
||||||
If no path with the given hash is known to exist in the file
|
If no path with the given hash is known to exist in the file
|
||||||
system, ...
|
system,
|
||||||
*/
|
*/
|
||||||
string expandHash(const Hash & hash, const string & outPath = "",
|
string expandHash(const Hash & hash, const string & target = "",
|
||||||
const string & prefix = "/");
|
const string & prefix = "/");
|
||||||
|
|
||||||
/* Copy a file to the nixStore directory and register it in dbRefs.
|
/* Copy a file to the nixStore directory and register it in dbRefs.
|
||||||
|
|
Loading…
Reference in a new issue