* `Fix' is a high-level descriptor instantiator for Nix. It replaces
nix-instantiate.
This commit is contained in:
parent
814b256da4
commit
0d2b24cdd1
8 changed files with 405 additions and 217 deletions
|
@ -11,5 +11,4 @@ AC_PROG_CC
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
|
|
||||||
AC_CONFIG_FILES([Makefile src/Makefile])
|
AC_CONFIG_FILES([Makefile src/Makefile])
|
||||||
AC_CONFIG_FILES([src/nix-instantiate], [chmod +x src/nix-instantiate])
|
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
|
@ -1,9 +1,13 @@
|
||||||
bin_PROGRAMS = nix
|
bin_PROGRAMS = nix fix
|
||||||
|
|
||||||
nix_SOURCES = nix.cc md5.c
|
nix_SOURCES = nix.cc md5.c
|
||||||
nix_CXXFLAGS = -DSYSTEM=\"@host@\"
|
nix_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall
|
||||||
nix_LDADD = -ldb_cxx-4 -lATerm
|
nix_LDADD = -ldb_cxx-4 -lATerm
|
||||||
|
|
||||||
|
fix_SOURCES = fix.cc md5.c
|
||||||
|
fix_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall
|
||||||
|
fix_LDADD = -lATerm
|
||||||
|
|
||||||
install-data-local:
|
install-data-local:
|
||||||
$(INSTALL) -d $(localstatedir)/nix
|
$(INSTALL) -d $(localstatedir)/nix
|
||||||
$(INSTALL) -d $(localstatedir)/nix/descriptors
|
$(INSTALL) -d $(localstatedir)/nix/descriptors
|
||||||
|
|
295
src/fix.cc
Normal file
295
src/fix.cc
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <aterm2.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "util.hh"
|
||||||
|
|
||||||
|
|
||||||
|
static string nixDescriptorDir;
|
||||||
|
static string nixSourcesDir;
|
||||||
|
|
||||||
|
|
||||||
|
typedef map<string, string> DescriptorMap;
|
||||||
|
|
||||||
|
|
||||||
|
void registerFile(string filename)
|
||||||
|
{
|
||||||
|
int res = system(("nix regfile " + filename).c_str());
|
||||||
|
if (WEXITSTATUS(res) != 0)
|
||||||
|
throw Error("cannot register " + filename + " with Nix");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Download object referenced by the given URL into the sources
|
||||||
|
directory. Return the file name it was downloaded to. */
|
||||||
|
string fetchURL(string url)
|
||||||
|
{
|
||||||
|
unsigned int pos = url.rfind('/');
|
||||||
|
if (pos == string::npos) throw Error("invalid url");
|
||||||
|
string filename(url, pos + 1);
|
||||||
|
string fullname = nixSourcesDir + "/" + filename;
|
||||||
|
/* !!! quoting */
|
||||||
|
string shellCmd =
|
||||||
|
"cd " + nixSourcesDir + " && wget --quiet -N \"" + url + "\"";
|
||||||
|
int res = system(shellCmd.c_str());
|
||||||
|
if (WEXITSTATUS(res) != 0)
|
||||||
|
throw Error("cannot fetch " + url);
|
||||||
|
return fullname;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the directory part of the given path, i.e., everything
|
||||||
|
before the final `/'. */
|
||||||
|
string dirOf(string s)
|
||||||
|
{
|
||||||
|
unsigned int pos = s.rfind('/');
|
||||||
|
if (pos == string::npos) throw Error("invalid file name");
|
||||||
|
return string(s, 0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Term evaluation functions. */
|
||||||
|
|
||||||
|
string evaluateStr(ATerm e)
|
||||||
|
{
|
||||||
|
char * s;
|
||||||
|
if (ATmatch(e, "<str>", &s))
|
||||||
|
return s;
|
||||||
|
else throw Error("invalid string expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ATerm evaluateBool(ATerm e)
|
||||||
|
{
|
||||||
|
if (ATmatch(e, "True") || ATmatch(e, "False"))
|
||||||
|
return e;
|
||||||
|
else throw Error("invalid boolean expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string evaluateFile(ATerm e, string dir)
|
||||||
|
{
|
||||||
|
char * s;
|
||||||
|
ATerm t;
|
||||||
|
if (ATmatch(e, "<str>", &s)) {
|
||||||
|
checkHash(s);
|
||||||
|
return s;
|
||||||
|
} else if (ATmatch(e, "Url(<term>)", &t)) {
|
||||||
|
string url = evaluateStr(t);
|
||||||
|
string filename = fetchURL(url);
|
||||||
|
registerFile(filename);
|
||||||
|
return hashFile(filename);
|
||||||
|
} else if (ATmatch(e, "Local(<term>)", &t)) {
|
||||||
|
string filename = absPath(evaluateStr(t), dir); /* !!! */
|
||||||
|
string cmd = "cp -p " + filename + " " + nixSourcesDir;
|
||||||
|
int res = system(cmd.c_str());
|
||||||
|
if (WEXITSTATUS(res) != 0)
|
||||||
|
throw Error("cannot copy " + filename);
|
||||||
|
return hashFile(filename);
|
||||||
|
} else throw Error("invalid hash expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ATerm evaluatePkg(ATerm e, DescriptorMap & done)
|
||||||
|
{
|
||||||
|
char * s;
|
||||||
|
if (ATmatch(e, "<str>", &s)) {
|
||||||
|
checkHash(s);
|
||||||
|
return s;
|
||||||
|
} else throw Error("invalid hash expression");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ATerm evaluate(ATerm e, string dir, DescriptorMap & done)
|
||||||
|
{
|
||||||
|
ATerm t;
|
||||||
|
if (ATmatch(e, "Str(<term>)", &t))
|
||||||
|
return ATmake("Str(<str>)", evaluateStr(t).c_str());
|
||||||
|
else if (ATmatch(e, "Bool(<term>)", &t))
|
||||||
|
return ATmake("Bool(<term>)", evaluateBool(t));
|
||||||
|
else if (ATmatch(e, "File(<term>)", &t))
|
||||||
|
return ATmake("File(<str>)", evaluateFile(t, dir).c_str());
|
||||||
|
else if (ATmatch(e, "Pkg(<term>)", &t))
|
||||||
|
return ATmake("Pkg(<term>)", evaluatePkg(t, done));
|
||||||
|
else throw Error("invalid expression type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef map<string, ATerm> BindingsMap;
|
||||||
|
|
||||||
|
|
||||||
|
string getStringFromMap(BindingsMap & bindingsMap,
|
||||||
|
const string & name)
|
||||||
|
{
|
||||||
|
ATerm e = bindingsMap[name];
|
||||||
|
if (!e) throw Error("binding " + name + " is not set");
|
||||||
|
char * s;
|
||||||
|
if (ATmatch(e, "Str(<str>)", &s))
|
||||||
|
return s;
|
||||||
|
else
|
||||||
|
throw Error("binding " + name + " is not a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Instantiate a Fix descriptors into a Nix descriptor, recursively
|
||||||
|
instantiating referenced descriptors as well. */
|
||||||
|
string instantiateDescriptor(string filename,
|
||||||
|
DescriptorMap & done)
|
||||||
|
{
|
||||||
|
/* Already done? */
|
||||||
|
DescriptorMap::iterator isInMap = done.find(filename);
|
||||||
|
if (isInMap != done.end()) return isInMap->second;
|
||||||
|
|
||||||
|
/* No. */
|
||||||
|
string dir = dirOf(filename);
|
||||||
|
|
||||||
|
/* Read the Fix descriptor as an ATerm. */
|
||||||
|
ATerm inTerm = ATreadFromNamedFile(filename.c_str());
|
||||||
|
if (!inTerm) throw Error("cannot read aterm " + filename);
|
||||||
|
|
||||||
|
ATerm bindings;
|
||||||
|
if (!ATmatch(inTerm, "Descr(<term>)", &bindings))
|
||||||
|
throw Error("invalid term in " + filename);
|
||||||
|
|
||||||
|
/* Iterate over the bindings and evaluate them to normal form. */
|
||||||
|
BindingsMap bindingsMap; /* the normal forms */
|
||||||
|
|
||||||
|
char * cname;
|
||||||
|
ATerm value;
|
||||||
|
while (ATmatch(bindings, "[Bind(<str>, <term>), <list>]",
|
||||||
|
&cname, &value, &bindings))
|
||||||
|
{
|
||||||
|
string name(cname);
|
||||||
|
ATerm e = evaluate(value, dir, done);
|
||||||
|
bindingsMap[name] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Construct a descriptor identifier by concatenating the package
|
||||||
|
and release ids. */
|
||||||
|
string pkgId = getStringFromMap(bindingsMap, "pkgId");
|
||||||
|
string releaseId = getStringFromMap(bindingsMap, "releaseId");
|
||||||
|
string id = pkgId + "-" + releaseId;
|
||||||
|
bindingsMap["id"] = ATmake("Str(<str>)", id.c_str());
|
||||||
|
|
||||||
|
/* Add a system name. */
|
||||||
|
bindingsMap["system"] = ATmake("Str(<str>)", thisSystem.c_str());
|
||||||
|
|
||||||
|
/* Construct the resulting ATerm. Note that iterating over the
|
||||||
|
map yields the bindings in sorted order, which is exactly the
|
||||||
|
canonical form for Nix descriptors. */
|
||||||
|
ATermList bindingsList = ATempty;
|
||||||
|
for (BindingsMap::iterator it = bindingsMap.begin();
|
||||||
|
it != bindingsMap.end(); it++)
|
||||||
|
/* !!! O(n^2) */
|
||||||
|
bindingsList = ATappend(bindingsList,
|
||||||
|
ATmake("Bind(<str>, <term>)", it->first.c_str(), it->second));
|
||||||
|
ATerm outTerm = ATmake("Descr(<term>)", bindingsList);
|
||||||
|
|
||||||
|
/* Write out the resulting ATerm. */
|
||||||
|
string tmpFilename = nixDescriptorDir + "/tmp";
|
||||||
|
if (!ATwriteToNamedTextFile(outTerm, tmpFilename.c_str()))
|
||||||
|
throw Error("cannot write aterm to " + tmpFilename);
|
||||||
|
|
||||||
|
string outHash = hashFile(tmpFilename);
|
||||||
|
string outFilename = nixDescriptorDir + "/" + id + "-" + outHash + ".nix";
|
||||||
|
if (rename(tmpFilename.c_str(), outFilename.c_str()))
|
||||||
|
throw Error("cannot rename " + tmpFilename + " to " + outFilename);
|
||||||
|
|
||||||
|
cout << outFilename << endl;
|
||||||
|
|
||||||
|
/* Register it with Nix. */
|
||||||
|
registerFile(outFilename);
|
||||||
|
|
||||||
|
done[filename] = outFilename;
|
||||||
|
return outFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Instantiate a set of Fix descriptors into Nix descriptors. */
|
||||||
|
void instantiateDescriptors(Strings filenames)
|
||||||
|
{
|
||||||
|
DescriptorMap done;
|
||||||
|
|
||||||
|
for (Strings::iterator it = filenames.begin();
|
||||||
|
it != filenames.end(); it++)
|
||||||
|
{
|
||||||
|
string filename = absPath(*it);
|
||||||
|
instantiateDescriptor(filename, done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Print help. */
|
||||||
|
void printUsage()
|
||||||
|
{
|
||||||
|
cerr <<
|
||||||
|
"Usage: fix ...
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse the command-line arguments, call the right operation. */
|
||||||
|
void run(Strings::iterator argCur, Strings::iterator argEnd)
|
||||||
|
{
|
||||||
|
Strings extraArgs;
|
||||||
|
enum { cmdUnknown, cmdInstantiate } command = cmdUnknown;
|
||||||
|
|
||||||
|
char * homeDir = getenv(nixHomeDirEnvVar.c_str());
|
||||||
|
if (homeDir) nixHomeDir = homeDir;
|
||||||
|
|
||||||
|
nixDescriptorDir = nixHomeDir + "/var/nix/descriptors";
|
||||||
|
nixSourcesDir = nixHomeDir + "/var/nix/sources";
|
||||||
|
|
||||||
|
for ( ; argCur != argEnd; argCur++) {
|
||||||
|
string arg(*argCur);
|
||||||
|
if (arg == "-h" || arg == "--help") {
|
||||||
|
printUsage();
|
||||||
|
return;
|
||||||
|
} if (arg == "--instantiate" || arg == "-i") {
|
||||||
|
command = cmdInstantiate;
|
||||||
|
} else if (arg[0] == '-')
|
||||||
|
throw UsageError("invalid option `" + arg + "'");
|
||||||
|
else
|
||||||
|
extraArgs.push_back(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
|
||||||
|
case cmdInstantiate:
|
||||||
|
instantiateDescriptors(extraArgs);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw UsageError("no operation specified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
ATerm bottomOfStack;
|
||||||
|
ATinit(argc, argv, &bottomOfStack);
|
||||||
|
|
||||||
|
/* Put the arguments in a vector. */
|
||||||
|
Strings args;
|
||||||
|
while (argc--) args.push_back(*argv++);
|
||||||
|
Strings::iterator argCur = args.begin(), argEnd = args.end();
|
||||||
|
|
||||||
|
argCur++;
|
||||||
|
|
||||||
|
try {
|
||||||
|
run(argCur, argEnd);
|
||||||
|
} catch (UsageError & e) {
|
||||||
|
cerr << "error: " << e.what() << endl
|
||||||
|
<< "Try `fix -h' for more information.\n";
|
||||||
|
return 1;
|
||||||
|
} catch (exception & e) {
|
||||||
|
cerr << "error: " << e.what() << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,121 +0,0 @@
|
||||||
#! /usr/bin/perl -w
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use FileHandle;
|
|
||||||
use File::Spec;
|
|
||||||
use Digest::MD5;
|
|
||||||
|
|
||||||
my $system = "@host@";
|
|
||||||
|
|
||||||
my $outdir = File::Spec->rel2abs($ARGV[0]);
|
|
||||||
my $netdir = File::Spec->rel2abs($ARGV[1]);
|
|
||||||
|
|
||||||
my %donetmpls = ();
|
|
||||||
|
|
||||||
sub fetchFile {
|
|
||||||
my $loc = shift;
|
|
||||||
|
|
||||||
if ($loc =~ /^([+\w\d\.\/-]+)$/) {
|
|
||||||
return $1;
|
|
||||||
} elsif ($loc =~ /^url\((.*)\)$/) {
|
|
||||||
my $url = $1;
|
|
||||||
$url =~ /\/([^\/]+)$/ || die "invalid url $url";
|
|
||||||
my $fn = "$netdir/$1";
|
|
||||||
if (! -f $fn) {
|
|
||||||
print "fetching $url...\n";
|
|
||||||
system "cd $netdir; wget --quiet -N $url";
|
|
||||||
if ($? != 0) {
|
|
||||||
unlink($fn);
|
|
||||||
die;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $fn;
|
|
||||||
} else {
|
|
||||||
die "invalid file specified $loc";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub hashFile {
|
|
||||||
my $file = shift;
|
|
||||||
open FILE, "< $file" or die "cannot open $file";
|
|
||||||
# !!! error checking
|
|
||||||
my $hash = Digest::MD5->new->addfile(*FILE)->hexdigest;
|
|
||||||
close FILE;
|
|
||||||
return $hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub convert {
|
|
||||||
my $descr = shift;
|
|
||||||
|
|
||||||
if (defined $donetmpls{$descr}) {
|
|
||||||
return $donetmpls{$descr};
|
|
||||||
}
|
|
||||||
|
|
||||||
my ($x, $dir, $fn) = File::Spec->splitpath($descr);
|
|
||||||
|
|
||||||
print "$descr\n";
|
|
||||||
|
|
||||||
my $IN = new FileHandle;
|
|
||||||
my $OUT = new FileHandle;
|
|
||||||
my $tmpfile = "$outdir/$fn-tmp";
|
|
||||||
open $IN, "< $descr" or die "cannot open $descr";
|
|
||||||
|
|
||||||
# Descr([Bind("x", Str("y")), Bind("x", File("1234")), Bind("x", Pkg("1234"))])
|
|
||||||
# bindings alphabetisch gesorteerd
|
|
||||||
|
|
||||||
my %bindings;
|
|
||||||
|
|
||||||
while (<$IN>) {
|
|
||||||
chomp;
|
|
||||||
s/\s*#.*$//;
|
|
||||||
next if (/^$/);
|
|
||||||
|
|
||||||
if (/^(\w+)\s*=\s*([^\#\s]*)\s*(\#.*)?$/) {
|
|
||||||
my ($name, $loc) = ($1, $2);
|
|
||||||
my $file = fetchFile($loc);
|
|
||||||
$file = File::Spec->rel2abs($file, $dir);
|
|
||||||
my $hash = hashFile($file);
|
|
||||||
$bindings{$name} = "File(\"$hash\")";
|
|
||||||
} elsif (/^(\w+)\s*<-\s*([+\w\d\.\/-]+)\s*(\#.*)?$/) {
|
|
||||||
my $name = $1;
|
|
||||||
my $file = $2;
|
|
||||||
$file = File::Spec->rel2abs($file, $dir);
|
|
||||||
$file = convert($file);
|
|
||||||
my $hash = hashFile($file);
|
|
||||||
$bindings{$name} = "Pkg(\"$hash\")";
|
|
||||||
} elsif (/^(\w+)\s*:\s*([+\w\d\.\/-]+)\s*(\#.*)?$/) {
|
|
||||||
my $name = $1;
|
|
||||||
my $value = $2;
|
|
||||||
$bindings{$name} = "Str(\"$value\")";
|
|
||||||
} else {
|
|
||||||
die "syntax error: $_";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
close $IN;
|
|
||||||
|
|
||||||
$bindings{"system"} = "Str(\"$system\")";
|
|
||||||
|
|
||||||
open $OUT, "| baffle -wt > $tmpfile" or die "cannot create $tmpfile";
|
|
||||||
print $OUT "Descr([";
|
|
||||||
my $first = 1;
|
|
||||||
foreach my $name (sort (keys %bindings)) {
|
|
||||||
if (!$first) { print $OUT ","; };
|
|
||||||
print $OUT "Bind(\"$name\",$bindings{$name})";
|
|
||||||
$first = 0;
|
|
||||||
}
|
|
||||||
print $OUT "])";
|
|
||||||
close $OUT;
|
|
||||||
|
|
||||||
my $hash = hashFile($tmpfile);
|
|
||||||
|
|
||||||
my $outfile = "$outdir/$fn-$hash";
|
|
||||||
rename($tmpfile, $outfile) or die "cannot rename $tmpfile to $outfile";
|
|
||||||
|
|
||||||
$donetmpls{$descr} = $outfile;
|
|
||||||
return $outfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (my $i = 2; $i < scalar @ARGV; $i++) {
|
|
||||||
convert(File::Spec->rel2abs($ARGV[$i]));
|
|
||||||
}
|
|
86
src/nix.cc
86
src/nix.cc
|
@ -1,15 +1,11 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
@ -20,10 +16,6 @@ extern "C" {
|
||||||
#include <aterm1.h>
|
#include <aterm1.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "md5.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -35,16 +27,6 @@ static string dbInstPkgs = "pkginst";
|
||||||
static string dbPrebuilts = "prebuilts";
|
static string dbPrebuilts = "prebuilts";
|
||||||
|
|
||||||
|
|
||||||
/* The canonical system name, as returned by config.guess. */
|
|
||||||
static string thisSystem = SYSTEM;
|
|
||||||
|
|
||||||
|
|
||||||
/* The prefix of the Nix installation, and the environment variable
|
|
||||||
that can be used to override the default. */
|
|
||||||
static string nixHomeDir = "/nix";
|
|
||||||
static string nixHomeDirEnvVar = "NIX";
|
|
||||||
|
|
||||||
|
|
||||||
/* Wrapper classes that ensures that the database is closed upon
|
/* Wrapper classes that ensures that the database is closed upon
|
||||||
object destruction. */
|
object destruction. */
|
||||||
class Db2 : public Db
|
class Db2 : public Db
|
||||||
|
@ -132,47 +114,6 @@ void enumDB(const string & dbname, DBPairs & contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string printHash(unsigned char * buf)
|
|
||||||
{
|
|
||||||
ostringstream str;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
str.fill('0');
|
|
||||||
str.width(2);
|
|
||||||
str << hex << (int) buf[i];
|
|
||||||
}
|
|
||||||
return str.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Verify that a reference is valid (that is, is a MD5 hash code). */
|
|
||||||
void checkHash(const string & s)
|
|
||||||
{
|
|
||||||
string err = "invalid reference: " + s;
|
|
||||||
if (s.length() != 32)
|
|
||||||
throw BadRefError(err);
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
char c = s[i];
|
|
||||||
if (!((c >= '0' && c <= '9') ||
|
|
||||||
(c >= 'a' && c <= 'f')))
|
|
||||||
throw BadRefError(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Compute the MD5 hash of a file. */
|
|
||||||
string hashFile(string filename)
|
|
||||||
{
|
|
||||||
unsigned char hash[16];
|
|
||||||
FILE * file = fopen(filename.c_str(), "rb");
|
|
||||||
if (!file)
|
|
||||||
throw BadRefError("file `" + filename + "' does not exist");
|
|
||||||
int err = md5_stream(file, hash);
|
|
||||||
fclose(file);
|
|
||||||
if (err) throw BadRefError("cannot hash file");
|
|
||||||
return printHash(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
typedef map<string, string> Params;
|
typedef map<string, string> Params;
|
||||||
|
|
||||||
|
|
||||||
|
@ -212,7 +153,14 @@ void readPkgDescr(const string & hash,
|
||||||
fileImports[name] = arg;
|
fileImports[name] = arg;
|
||||||
} else if (ATmatch(value, "Str(<str>)", &arg))
|
} else if (ATmatch(value, "Str(<str>)", &arg))
|
||||||
arguments[name] = arg;
|
arguments[name] = arg;
|
||||||
else throw Error("invalid binding in " + pkgfile);
|
else if (ATmatch(value, "Bool(True)"))
|
||||||
|
arguments[name] = "1";
|
||||||
|
else if (ATmatch(value, "Bool(False)"))
|
||||||
|
arguments[name] = "";
|
||||||
|
else {
|
||||||
|
ATprintf("%t\n", value);
|
||||||
|
throw Error("invalid binding in " + pkgfile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,12 +421,15 @@ void exportPkgs(string outDir,
|
||||||
Strings::iterator firstHash,
|
Strings::iterator firstHash,
|
||||||
Strings::iterator lastHash)
|
Strings::iterator lastHash)
|
||||||
{
|
{
|
||||||
|
outDir = absPath(outDir);
|
||||||
|
|
||||||
for (Strings::iterator it = firstHash; it != lastHash; it++) {
|
for (Strings::iterator it = firstHash; it != lastHash; it++) {
|
||||||
string hash = *it;
|
string hash = *it;
|
||||||
string pkgDir = getPkg(hash);
|
string pkgDir = getPkg(hash);
|
||||||
string tmpFile = outDir + "/export_tmp";
|
string tmpFile = outDir + "/export_tmp";
|
||||||
|
|
||||||
int res = system(("cd " + pkgDir + " && tar cvfj " + tmpFile + " .").c_str()); // !!! escaping
|
string cmd = "cd " + pkgDir + " && tar cvfj " + tmpFile + " .";
|
||||||
|
int res = system(cmd.c_str()); // !!! escaping
|
||||||
if (WEXITSTATUS(res) != 0)
|
if (WEXITSTATUS(res) != 0)
|
||||||
throw Error("cannot tar " + pkgDir);
|
throw Error("cannot tar " + pkgDir);
|
||||||
|
|
||||||
|
@ -500,19 +451,6 @@ void regPrebuilt(string pkgHash, string prebuiltHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string absPath(string filename)
|
|
||||||
{
|
|
||||||
if (filename[0] != '/') {
|
|
||||||
char buf[PATH_MAX];
|
|
||||||
if (!getcwd(buf, sizeof(buf)))
|
|
||||||
throw Error("cannot get cwd");
|
|
||||||
filename = string(buf) + "/" + filename;
|
|
||||||
/* !!! canonicalise */
|
|
||||||
}
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void registerFile(string filename)
|
void registerFile(string filename)
|
||||||
{
|
{
|
||||||
filename = absPath(filename);
|
filename = absPath(filename);
|
||||||
|
|
82
src/util.hh
82
src/util.hh
|
@ -1,7 +1,15 @@
|
||||||
#ifndef __UTIL_H
|
#ifndef __UTIL_H
|
||||||
#define __UTIL_H
|
#define __UTIL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "md5.h"
|
||||||
|
}
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -31,4 +39,78 @@ public:
|
||||||
typedef vector<string> Strings;
|
typedef vector<string> Strings;
|
||||||
|
|
||||||
|
|
||||||
|
/* !!! the following shouldn't be here; abuse of the preprocessor */
|
||||||
|
|
||||||
|
|
||||||
|
/* The canonical system name, as returned by config.guess. */
|
||||||
|
static string thisSystem = SYSTEM;
|
||||||
|
|
||||||
|
|
||||||
|
/* The prefix of the Nix installation, and the environment variable
|
||||||
|
that can be used to override the default. */
|
||||||
|
static string nixHomeDir = "/nix";
|
||||||
|
static string nixHomeDirEnvVar = "NIX";
|
||||||
|
|
||||||
|
|
||||||
|
string absPath(string filename, string dir = "")
|
||||||
|
{
|
||||||
|
if (filename[0] != '/') {
|
||||||
|
if (dir == "") {
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
if (!getcwd(buf, sizeof(buf)))
|
||||||
|
throw Error("cannot get cwd");
|
||||||
|
dir = buf;
|
||||||
|
}
|
||||||
|
filename = dir + "/" + filename;
|
||||||
|
/* !!! canonicalise */
|
||||||
|
char resolved[PATH_MAX];
|
||||||
|
if (!realpath(filename.c_str(), resolved))
|
||||||
|
throw Error("cannot canonicalise path " + filename);
|
||||||
|
filename = resolved;
|
||||||
|
}
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string printHash(unsigned char * buf)
|
||||||
|
{
|
||||||
|
ostringstream str;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
str.fill('0');
|
||||||
|
str.width(2);
|
||||||
|
str << hex << (int) buf[i];
|
||||||
|
}
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Verify that a reference is valid (that is, is a MD5 hash code). */
|
||||||
|
void checkHash(const string & s)
|
||||||
|
{
|
||||||
|
string err = "invalid reference: " + s;
|
||||||
|
if (s.length() != 32)
|
||||||
|
throw BadRefError(err);
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
char c = s[i];
|
||||||
|
if (!((c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'a' && c <= 'f')))
|
||||||
|
throw BadRefError(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compute the MD5 hash of a file. */
|
||||||
|
string hashFile(string filename)
|
||||||
|
{
|
||||||
|
unsigned char hash[16];
|
||||||
|
FILE * file = fopen(filename.c_str(), "rb");
|
||||||
|
if (!file)
|
||||||
|
throw BadRefError("file `" + filename + "' does not exist");
|
||||||
|
int err = md5_stream(file, hash);
|
||||||
|
fclose(file);
|
||||||
|
if (err) throw BadRefError("cannot hash file");
|
||||||
|
return printHash(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !__UTIL_H */
|
#endif /* !__UTIL_H */
|
||||||
|
|
10
test/fixdescriptors/aterm-2.0.fix
Normal file
10
test/fixdescriptors/aterm-2.0.fix
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
Descr(
|
||||||
|
[ Bind("pkgId", Str("aterm-2.0"))
|
||||||
|
, Bind("releaseId", Str("1"))
|
||||||
|
|
||||||
|
, Bind("createGCC", Bool(True))
|
||||||
|
|
||||||
|
, Bind("src", File(Url("http://www.cwi.nl/projects/MetaEnv/aterm/aterm-2.0.tar.gz")))
|
||||||
|
, Bind("build", File(Local("../build/aterm-build.sh")))
|
||||||
|
]
|
||||||
|
)
|
|
@ -1,19 +0,0 @@
|
||||||
#! /bin/sh
|
|
||||||
|
|
||||||
if test -z "$NIX"; then NIX=/nix; fi
|
|
||||||
|
|
||||||
echo target $NIX
|
|
||||||
|
|
||||||
if ! nix-instantiate $NIX/var/nix/descriptors $NIX/var/nix/sources tmpl/*.nix; then
|
|
||||||
exit 1;
|
|
||||||
fi
|
|
||||||
|
|
||||||
rm -f build/*~
|
|
||||||
cp -p build/* $NIX/var/nix/sources
|
|
||||||
|
|
||||||
for i in $NIX/var/nix/sources/*; do nix regfile $i; done
|
|
||||||
|
|
||||||
for i in $NIX/var/nix/descriptors/*; do
|
|
||||||
md5sum $i
|
|
||||||
nix regfile $i
|
|
||||||
done
|
|
Loading…
Reference in a new issue