forked from lix-project/lix
* Refactoring: hash class.
This commit is contained in:
parent
f66055fa1e
commit
21fe717ce2
|
@ -1,13 +1,16 @@
|
||||||
bin_PROGRAMS = nix fix
|
bin_PROGRAMS = nix fix
|
||||||
|
noinst_PROGRAMS = test
|
||||||
|
|
||||||
AM_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall
|
AM_CXXFLAGS = -DSYSTEM=\"@host@\" -Wall
|
||||||
|
|
||||||
nix_SOURCES = nix.cc db.cc util.cc md5.c
|
nix_SOURCES = nix.cc db.cc util.cc hash.cc md5.c
|
||||||
nix_LDADD = -ldb_cxx-4 -lATerm
|
nix_LDADD = -ldb_cxx-4 -lATerm
|
||||||
|
|
||||||
fix_SOURCES = fix.cc util.cc md5.c
|
fix_SOURCES = fix.cc util.cc hash.cc md5.c
|
||||||
fix_LDADD = -lATerm
|
fix_LDADD = -lATerm
|
||||||
|
|
||||||
|
test_SOURCES = test.cc util.cc hash.cc md5.c
|
||||||
|
|
||||||
install-data-local:
|
install-data-local:
|
||||||
$(INSTALL) -d $(localstatedir)/nix
|
$(INSTALL) -d $(localstatedir)/nix
|
||||||
$(INSTALL) -d $(localstatedir)/nix/descriptors
|
$(INSTALL) -d $(localstatedir)/nix/descriptors
|
||||||
|
|
39
src/fix.cc
39
src/fix.cc
|
@ -10,6 +10,7 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "hash.hh"
|
||||||
|
|
||||||
|
|
||||||
static string nixDescriptorDir;
|
static string nixDescriptorDir;
|
||||||
|
@ -20,7 +21,7 @@ static bool verbose = false;
|
||||||
|
|
||||||
/* Mapping of Fix file names to the hashes of the resulting Nix
|
/* Mapping of Fix file names to the hashes of the resulting Nix
|
||||||
descriptors. */
|
descriptors. */
|
||||||
typedef map<string, string> DescriptorMap;
|
typedef map<string, Hash> DescriptorMap;
|
||||||
|
|
||||||
|
|
||||||
void registerFile(string filename)
|
void registerFile(string filename)
|
||||||
|
@ -32,12 +33,13 @@ void registerFile(string filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void registerURL(string hash, string url)
|
void registerURL(Hash hash, string url)
|
||||||
{
|
{
|
||||||
int res = system(("nix regurl " + hash + " " + url).c_str());
|
int res = system(("nix regurl " + (string) hash + " " + url).c_str());
|
||||||
/* !!! escape */
|
/* !!! escape */
|
||||||
if (WEXITSTATUS(res) != 0)
|
if (WEXITSTATUS(res) != 0)
|
||||||
throw Error("cannot register " + hash + " -> " + url + " with Nix");
|
throw Error("cannot register " +
|
||||||
|
(string) hash + " -> " + url + " with Nix");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +63,7 @@ struct EvalContext
|
||||||
|
|
||||||
|
|
||||||
ATerm evaluate(ATerm e, EvalContext ctx);
|
ATerm evaluate(ATerm e, EvalContext ctx);
|
||||||
string instantiateDescriptor(string filename, EvalContext ctx);
|
Hash instantiateDescriptor(string filename, EvalContext ctx);
|
||||||
|
|
||||||
|
|
||||||
string evaluateStr(ATerm e, EvalContext ctx)
|
string evaluateStr(ATerm e, EvalContext ctx)
|
||||||
|
@ -101,7 +103,7 @@ ATerm evaluate(ATerm e, EvalContext ctx)
|
||||||
ATmatch(e, "Pkg(<str>)", &s) ||
|
ATmatch(e, "Pkg(<str>)", &s) ||
|
||||||
ATmatch(e, "File(<str>)", &s))
|
ATmatch(e, "File(<str>)", &s))
|
||||||
{
|
{
|
||||||
checkHash(s);
|
parseHash(s);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +133,7 @@ ATerm evaluate(ATerm e, EvalContext ctx)
|
||||||
else if (ATmatch(e, "Fix(<term>)", &e2)) {
|
else if (ATmatch(e, "Fix(<term>)", &e2)) {
|
||||||
string filename = absPath(evaluateStr(e2, ctx), ctx.dir); /* !!! */
|
string filename = absPath(evaluateStr(e2, ctx), ctx.dir); /* !!! */
|
||||||
return ATmake("Pkg(<str>)",
|
return ATmake("Pkg(<str>)",
|
||||||
instantiateDescriptor(filename, ctx).c_str());
|
((string) instantiateDescriptor(filename, ctx)).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -160,19 +162,18 @@ ATerm evaluate(ATerm e, EvalContext ctx)
|
||||||
hash. */
|
hash. */
|
||||||
else if (ATmatch(e, "Local(<term>)", &e2)) {
|
else if (ATmatch(e, "Local(<term>)", &e2)) {
|
||||||
string filename = absPath(evaluateStr(e2, ctx), ctx.dir); /* !!! */
|
string filename = absPath(evaluateStr(e2, ctx), ctx.dir); /* !!! */
|
||||||
string hash = hashFile(filename);
|
Hash hash = hashFile(filename);
|
||||||
registerFile(filename); /* !!! */
|
registerFile(filename); /* !!! */
|
||||||
return ATmake("File(<str>)", hash.c_str());
|
return ATmake("File(<str>)", ((string) hash).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `Url' registers a mapping from a hash to an url with Nix, and
|
/* `Url' registers a mapping from a hash to an url with Nix, and
|
||||||
returns the hash. */
|
returns the hash. */
|
||||||
else if (ATmatch(e, "Url(<term>, <term>)", &e2, &e3)) {
|
else if (ATmatch(e, "Url(<term>, <term>)", &e2, &e3)) {
|
||||||
string hash = evaluateStr(e2, ctx);
|
Hash hash = parseHash(evaluateStr(e2, ctx));
|
||||||
checkHash(hash);
|
|
||||||
string url = evaluateStr(e3, ctx);
|
string url = evaluateStr(e3, ctx);
|
||||||
registerURL(hash, url);
|
registerURL(hash, url);
|
||||||
return ATmake("File(<str>)", hash.c_str());
|
return ATmake("File(<str>)", ((string) hash).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `If' provides conditional evaluation. */
|
/* `If' provides conditional evaluation. */
|
||||||
|
@ -199,7 +200,7 @@ string getStringFromMap(BindingsMap & bindingsMap,
|
||||||
|
|
||||||
/* Instantiate a Fix descriptors into a Nix descriptor, recursively
|
/* Instantiate a Fix descriptors into a Nix descriptor, recursively
|
||||||
instantiating referenced descriptors as well. */
|
instantiating referenced descriptors as well. */
|
||||||
string instantiateDescriptor(string filename, EvalContext ctx)
|
Hash instantiateDescriptor(string filename, EvalContext ctx)
|
||||||
{
|
{
|
||||||
/* Already done? */
|
/* Already done? */
|
||||||
DescriptorMap::iterator isInMap = ctx.done->find(filename);
|
DescriptorMap::iterator isInMap = ctx.done->find(filename);
|
||||||
|
@ -256,8 +257,9 @@ string instantiateDescriptor(string filename, EvalContext ctx)
|
||||||
if (!ATwriteToNamedTextFile(outTerm, tmpFilename.c_str()))
|
if (!ATwriteToNamedTextFile(outTerm, tmpFilename.c_str()))
|
||||||
throw Error("cannot write aterm to " + tmpFilename);
|
throw Error("cannot write aterm to " + tmpFilename);
|
||||||
|
|
||||||
string outHash = hashFile(tmpFilename);
|
Hash outHash = hashFile(tmpFilename);
|
||||||
string outFilename = nixDescriptorDir + "/" + id + "-" + outHash + ".nix";
|
string outFilename = nixDescriptorDir + "/" +
|
||||||
|
id + "-" + (string) outHash + ".nix";
|
||||||
if (rename(tmpFilename.c_str(), outFilename.c_str()))
|
if (rename(tmpFilename.c_str(), outFilename.c_str()))
|
||||||
throw Error("cannot rename " + tmpFilename + " to " + outFilename);
|
throw Error("cannot rename " + tmpFilename + " to " + outFilename);
|
||||||
|
|
||||||
|
@ -265,7 +267,8 @@ string instantiateDescriptor(string filename, EvalContext ctx)
|
||||||
registerFile(outFilename);
|
registerFile(outFilename);
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
cerr << "instantiated " << outHash << " from " << filename << endl;
|
cerr << "instantiated " << (string) outHash
|
||||||
|
<< " from " << filename << endl;
|
||||||
|
|
||||||
(*ctx.done)[filename] = outHash;
|
(*ctx.done)[filename] = outHash;
|
||||||
return outHash;
|
return outHash;
|
||||||
|
@ -284,7 +287,7 @@ void instantiateDescriptors(Strings filenames)
|
||||||
it != filenames.end(); it++)
|
it != filenames.end(); it++)
|
||||||
{
|
{
|
||||||
string filename = absPath(*it);
|
string filename = absPath(*it);
|
||||||
cout << instantiateDescriptor(filename, ctx) << endl;
|
cout << (string) instantiateDescriptor(filename, ctx) << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +296,7 @@ void instantiateDescriptors(Strings filenames)
|
||||||
void printUsage()
|
void printUsage()
|
||||||
{
|
{
|
||||||
cerr <<
|
cerr <<
|
||||||
"Usage: fix ...
|
"Usage: fix ...\n\
|
||||||
";
|
";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
87
src/hash.cc
Normal file
87
src/hash.cc
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
extern "C" {
|
||||||
|
#include "md5.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "hash.hh"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a zeroed hash object. */
|
||||||
|
Hash::Hash()
|
||||||
|
{
|
||||||
|
memset(hash, 0, sizeof(hash));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check whether two hash are equal. */
|
||||||
|
bool Hash::operator == (Hash & h2)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < hashSize; i++)
|
||||||
|
if (hash[i] != h2.hash[i]) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check whether two hash are not equal. */
|
||||||
|
bool Hash::operator != (Hash & h2)
|
||||||
|
{
|
||||||
|
return !(*this == h2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert a hash code into a hexadecimal representation. */
|
||||||
|
Hash::operator string() const
|
||||||
|
{
|
||||||
|
ostringstream str;
|
||||||
|
for (unsigned int i = 0; i < hashSize; i++) {
|
||||||
|
str.fill('0');
|
||||||
|
str.width(2);
|
||||||
|
str << hex << (int) hash[i];
|
||||||
|
}
|
||||||
|
return str.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse a hexadecimal representation of a hash code. */
|
||||||
|
Hash parseHash(const string & s)
|
||||||
|
{
|
||||||
|
Hash hash;
|
||||||
|
for (unsigned int i = 0; i < Hash::hashSize; i++) {
|
||||||
|
string s2(s, i * 2, 2);
|
||||||
|
if (!isxdigit(s2[0]) || !isxdigit(s2[1]))
|
||||||
|
throw BadRefError("invalid hash: " + s);
|
||||||
|
istringstream str(s2);
|
||||||
|
int n;
|
||||||
|
str >> hex >> n;
|
||||||
|
hash.hash[i] = n;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Verify that a reference is valid (that is, is a MD5 hash code). */
|
||||||
|
bool isHash(const string & s)
|
||||||
|
{
|
||||||
|
if (s.length() != 32) return false;
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
char c = s[i];
|
||||||
|
if (!((c >= '0' && c <= '9') ||
|
||||||
|
(c >= 'a' && c <= 'f')))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Compute the MD5 hash of a file. */
|
||||||
|
Hash hashFile(const string & fileName)
|
||||||
|
{
|
||||||
|
Hash hash;
|
||||||
|
FILE * file = fopen(fileName.c_str(), "rb");
|
||||||
|
if (!file)
|
||||||
|
throw Error("file `" + fileName + "' does not exist");
|
||||||
|
int err = md5_stream(file, hash.hash);
|
||||||
|
fclose(file);
|
||||||
|
if (err) throw Error("cannot hash file");
|
||||||
|
return hash;
|
||||||
|
}
|
34
src/hash.hh
Normal file
34
src/hash.hh
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef __HASH_H
|
||||||
|
#define __HASH_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "util.hh"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
struct Hash
|
||||||
|
{
|
||||||
|
static const unsigned int hashSize = 16;
|
||||||
|
unsigned char hash[hashSize];
|
||||||
|
|
||||||
|
Hash();
|
||||||
|
bool operator == (Hash & h2);
|
||||||
|
bool operator != (Hash & h2);
|
||||||
|
operator string() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BadRefError : public Error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BadRefError(string _err) : Error(_err) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Hash parseHash(const string & s);
|
||||||
|
bool isHash(const string & s);
|
||||||
|
Hash hashFile(const string & fileName);
|
||||||
|
|
||||||
|
#endif /* !__HASH_H */
|
205
src/nix.cc
205
src/nix.cc
|
@ -16,6 +16,7 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
|
#include "hash.hh"
|
||||||
#include "db.hh"
|
#include "db.hh"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -58,7 +59,7 @@ string fetchURL(string url)
|
||||||
database), we use that. Otherwise, we attempt to fetch it from the
|
database), we use that. Otherwise, we attempt to fetch it from the
|
||||||
network (using dbNetSources). We verify that the file has the
|
network (using dbNetSources). We verify that the file has the
|
||||||
right hash. */
|
right hash. */
|
||||||
string getFile(string hash)
|
string getFile(Hash hash)
|
||||||
{
|
{
|
||||||
bool checkedNet = false;
|
bool checkedNet = false;
|
||||||
|
|
||||||
|
@ -77,10 +78,10 @@ string getFile(string hash)
|
||||||
|
|
||||||
if (checkedNet)
|
if (checkedNet)
|
||||||
throw Error("consistency problem: file fetched from " + url +
|
throw Error("consistency problem: file fetched from " + url +
|
||||||
" should have hash " + hash + ", but it doesn't");
|
" should have hash " + (string) hash + ", but it doesn't");
|
||||||
|
|
||||||
if (!queryDB(nixDB, dbNetSources, hash, url))
|
if (!queryDB(nixDB, dbNetSources, hash, url))
|
||||||
throw Error("a file with hash " + hash + " is requested, "
|
throw Error("a file with hash " + (string) hash + " is requested, "
|
||||||
"but it is not known to exist locally or on the network");
|
"but it is not known to exist locally or on the network");
|
||||||
|
|
||||||
checkedNet = true;
|
checkedNet = true;
|
||||||
|
@ -95,7 +96,7 @@ string getFile(string hash)
|
||||||
typedef map<string, string> Params;
|
typedef map<string, string> Params;
|
||||||
|
|
||||||
|
|
||||||
void readPkgDescr(const string & hash,
|
void readPkgDescr(Hash hash,
|
||||||
Params & pkgImports, Params & fileImports, Params & arguments)
|
Params & pkgImports, Params & fileImports, Params & arguments)
|
||||||
{
|
{
|
||||||
string pkgfile;
|
string pkgfile;
|
||||||
|
@ -117,10 +118,10 @@ void readPkgDescr(const string & hash,
|
||||||
string name(cname);
|
string name(cname);
|
||||||
char * arg;
|
char * arg;
|
||||||
if (ATmatch(value, "Pkg(<str>)", &arg)) {
|
if (ATmatch(value, "Pkg(<str>)", &arg)) {
|
||||||
checkHash(arg);
|
parseHash(arg);
|
||||||
pkgImports[name] = arg;
|
pkgImports[name] = arg;
|
||||||
} else if (ATmatch(value, "File(<str>)", &arg)) {
|
} else if (ATmatch(value, "File(<str>)", &arg)) {
|
||||||
checkHash(arg);
|
parseHash(arg);
|
||||||
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;
|
||||||
|
@ -136,13 +137,13 @@ void readPkgDescr(const string & hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string getPkg(string hash);
|
string getPkg(Hash hash);
|
||||||
|
|
||||||
|
|
||||||
typedef map<string, string> Environment;
|
typedef map<string, string> Environment;
|
||||||
|
|
||||||
|
|
||||||
void fetchDeps(string hash, Environment & env)
|
void fetchDeps(Hash hash, Environment & env)
|
||||||
{
|
{
|
||||||
/* Read the package description file. */
|
/* Read the package description file. */
|
||||||
Params pkgImports, fileImports, arguments;
|
Params pkgImports, fileImports, arguments;
|
||||||
|
@ -156,7 +157,7 @@ void fetchDeps(string hash, Environment & env)
|
||||||
cerr << "fetching package dependency "
|
cerr << "fetching package dependency "
|
||||||
<< it->first << " <- " << it->second
|
<< it->first << " <- " << it->second
|
||||||
<< endl;
|
<< endl;
|
||||||
env[it->first] = getPkg(it->second);
|
env[it->first] = getPkg(parseHash(it->second));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Params::iterator it = fileImports.begin();
|
for (Params::iterator it = fileImports.begin();
|
||||||
|
@ -168,7 +169,7 @@ void fetchDeps(string hash, Environment & env)
|
||||||
|
|
||||||
string file;
|
string file;
|
||||||
|
|
||||||
file = getFile(it->second);
|
file = getFile(parseHash(it->second));
|
||||||
|
|
||||||
env[it->first] = file;
|
env[it->first] = file;
|
||||||
}
|
}
|
||||||
|
@ -198,7 +199,7 @@ string getFromEnv(const Environment & env, const string & key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string queryPkgId(const string & hash)
|
string queryPkgId(Hash hash)
|
||||||
{
|
{
|
||||||
Params pkgImports, fileImports, arguments;
|
Params pkgImports, fileImports, arguments;
|
||||||
readPkgDescr(hash, pkgImports, fileImports, arguments);
|
readPkgDescr(hash, pkgImports, fileImports, arguments);
|
||||||
|
@ -206,7 +207,7 @@ string queryPkgId(const string & hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void installPkg(string hash)
|
void installPkg(Hash hash)
|
||||||
{
|
{
|
||||||
string pkgfile;
|
string pkgfile;
|
||||||
string src;
|
string src;
|
||||||
|
@ -223,14 +224,15 @@ void installPkg(string hash)
|
||||||
string id = getFromEnv(env, "id");
|
string id = getFromEnv(env, "id");
|
||||||
|
|
||||||
/* Construct a path for the installed package. */
|
/* Construct a path for the installed package. */
|
||||||
path = nixHomeDir + "/pkg/" + id + "-" + hash;
|
path = nixHomeDir + "/pkg/" + id + "-" + (string) hash;
|
||||||
|
|
||||||
/* Create the path. */
|
/* Create the path. */
|
||||||
if (mkdir(path.c_str(), 0777))
|
if (mkdir(path.c_str(), 0777))
|
||||||
throw Error("unable to create directory " + path);
|
throw Error("unable to create directory " + path);
|
||||||
|
|
||||||
/* Create a log file. */
|
/* Create a log file. */
|
||||||
string logFileName = nixLogDir + "/" + id + "-" + hash + ".log";
|
string logFileName =
|
||||||
|
nixLogDir + "/" + id + "-" + (string) hash + ".log";
|
||||||
/* !!! auto-pclose on exit */
|
/* !!! auto-pclose on exit */
|
||||||
FILE * logFile = popen(("tee " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
|
FILE * logFile = popen(("tee " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
|
||||||
if (!logFile)
|
if (!logFile)
|
||||||
|
@ -256,11 +258,11 @@ void installPkg(string hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to use a prebuilt. */
|
/* Try to use a prebuilt. */
|
||||||
string prebuiltHash, prebuiltFile;
|
string prebuiltHashS, prebuiltFile;
|
||||||
if (queryDB(nixDB, dbPrebuilts, hash, prebuiltHash)) {
|
if (queryDB(nixDB, dbPrebuilts, hash, prebuiltHashS)) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
prebuiltFile = getFile(prebuiltHash);
|
prebuiltFile = getFile(parseHash(prebuiltHashS));
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
cerr << "cannot obtain prebuilt (ignoring): " << e.what() << endl;
|
cerr << "cannot obtain prebuilt (ignoring): " << e.what() << endl;
|
||||||
goto build;
|
goto build;
|
||||||
|
@ -339,17 +341,16 @@ void installPkg(string hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string getPkg(string hash)
|
string getPkg(Hash hash)
|
||||||
{
|
{
|
||||||
string path;
|
string path;
|
||||||
checkHash(hash);
|
|
||||||
while (!queryDB(nixDB, dbInstPkgs, hash, path))
|
while (!queryDB(nixDB, dbInstPkgs, hash, path))
|
||||||
installPkg(hash);
|
installPkg(hash);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void runPkg(string hash,
|
void runPkg(Hash hash,
|
||||||
Strings::iterator firstArg,
|
Strings::iterator firstArg,
|
||||||
Strings::iterator lastArg)
|
Strings::iterator lastArg)
|
||||||
{
|
{
|
||||||
|
@ -389,7 +390,7 @@ void runPkg(string hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ensurePkg(string hash)
|
void ensurePkg(Hash hash)
|
||||||
{
|
{
|
||||||
Params pkgImports, fileImports, arguments;
|
Params pkgImports, fileImports, arguments;
|
||||||
readPkgDescr(hash, pkgImports, fileImports, arguments);
|
readPkgDescr(hash, pkgImports, fileImports, arguments);
|
||||||
|
@ -403,10 +404,9 @@ void ensurePkg(string hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void delPkg(string hash)
|
void delPkg(Hash hash)
|
||||||
{
|
{
|
||||||
string path;
|
string path;
|
||||||
checkHash(hash);
|
|
||||||
if (queryDB(nixDB, dbInstPkgs, hash, path)) {
|
if (queryDB(nixDB, dbInstPkgs, hash, path)) {
|
||||||
int res = system(("chmod -R +w " + path + " && rm -rf " + path).c_str()); // !!! escaping
|
int res = system(("chmod -R +w " + path + " && rm -rf " + path).c_str()); // !!! escaping
|
||||||
delDB(nixDB, dbInstPkgs, hash); // not a bug ???
|
delDB(nixDB, dbInstPkgs, hash); // not a bug ???
|
||||||
|
@ -423,7 +423,7 @@ void exportPkgs(string outDir,
|
||||||
outDir = absPath(outDir);
|
outDir = absPath(outDir);
|
||||||
|
|
||||||
for (Strings::iterator it = firstHash; it != lastHash; it++) {
|
for (Strings::iterator it = firstHash; it != lastHash; it++) {
|
||||||
string hash = *it;
|
Hash hash = parseHash(*it);
|
||||||
string pkgDir = getPkg(hash);
|
string pkgDir = getPkg(hash);
|
||||||
string tmpFile = outDir + "/export_tmp";
|
string tmpFile = outDir + "/export_tmp";
|
||||||
|
|
||||||
|
@ -435,42 +435,38 @@ void exportPkgs(string outDir,
|
||||||
string prebuiltHash = hashFile(tmpFile);
|
string prebuiltHash = hashFile(tmpFile);
|
||||||
string pkgId = queryPkgId(hash);
|
string pkgId = queryPkgId(hash);
|
||||||
string prebuiltFile = outDir + "/" +
|
string prebuiltFile = outDir + "/" +
|
||||||
pkgId + "-" + hash + "-" + prebuiltHash + ".tar.bz2";
|
pkgId + "-" + (string) hash + "-" + prebuiltHash + ".tar.bz2";
|
||||||
|
|
||||||
rename(tmpFile.c_str(), prebuiltFile.c_str());
|
rename(tmpFile.c_str(), prebuiltFile.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void registerPrebuilt(string pkgHash, string prebuiltHash)
|
void registerPrebuilt(Hash pkgHash, Hash prebuiltHash)
|
||||||
{
|
{
|
||||||
checkHash(pkgHash);
|
|
||||||
checkHash(prebuiltHash);
|
|
||||||
setDB(nixDB, dbPrebuilts, pkgHash, prebuiltHash);
|
setDB(nixDB, dbPrebuilts, pkgHash, prebuiltHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string registerFile(string filename)
|
Hash registerFile(string filename)
|
||||||
{
|
{
|
||||||
filename = absPath(filename);
|
filename = absPath(filename);
|
||||||
string hash = hashFile(filename);
|
Hash hash = hashFile(filename);
|
||||||
setDB(nixDB, dbRefs, hash, filename);
|
setDB(nixDB, dbRefs, hash, filename);
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void registerURL(string hash, string url)
|
void registerURL(Hash hash, string url)
|
||||||
{
|
{
|
||||||
checkHash(hash);
|
|
||||||
setDB(nixDB, dbNetSources, hash, url);
|
setDB(nixDB, dbNetSources, hash, url);
|
||||||
/* !!! currently we allow only one network source per hash */
|
/* !!! currently we allow only one network source per hash */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* This is primarily used for bootstrapping. */
|
/* This is primarily used for bootstrapping. */
|
||||||
void registerInstalledPkg(string hash, string path)
|
void registerInstalledPkg(Hash hash, string path)
|
||||||
{
|
{
|
||||||
checkHash(hash);
|
|
||||||
if (path == "")
|
if (path == "")
|
||||||
delDB(nixDB, dbInstPkgs, hash);
|
delDB(nixDB, dbInstPkgs, hash);
|
||||||
else
|
else
|
||||||
|
@ -498,12 +494,13 @@ void verifyDB()
|
||||||
it != fileRefs.end(); it++)
|
it != fileRefs.end(); it++)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (hashFile(it->second) != it->first) {
|
Hash hash = parseHash(it->first);
|
||||||
|
if (hashFile(it->second) != hash) {
|
||||||
cerr << "file " << it->second << " has changed\n";
|
cerr << "file " << it->second << " has changed\n";
|
||||||
delDB(nixDB, dbRefs, it->first);
|
delDB(nixDB, dbRefs, it->first);
|
||||||
}
|
}
|
||||||
} catch (BadRefError e) { /* !!! better error check */
|
} catch (Error e) { /* !!! better error check */
|
||||||
cerr << "file " << it->second << " has disappeared\n";
|
cerr << "error: " << e.what() << endl;
|
||||||
delDB(nixDB, dbRefs, it->first);
|
delDB(nixDB, dbRefs, it->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -544,7 +541,7 @@ void printInfo(Strings::iterator first, Strings::iterator last)
|
||||||
{
|
{
|
||||||
for (Strings::iterator it = first; it != last; it++) {
|
for (Strings::iterator it = first; it != last; it++) {
|
||||||
try {
|
try {
|
||||||
cout << *it << " " << queryPkgId(*it) << endl;
|
cout << *it << " " << queryPkgId(parseHash(*it)) << endl;
|
||||||
} catch (Error & e) { // !!! more specific
|
} catch (Error & e) { // !!! more specific
|
||||||
cout << *it << " (descriptor missing)\n";
|
cout << *it << " (descriptor missing)\n";
|
||||||
}
|
}
|
||||||
|
@ -559,7 +556,7 @@ void computeClosure(Strings::iterator first, Strings::iterator last,
|
||||||
set<string> doneSet;
|
set<string> doneSet;
|
||||||
|
|
||||||
while (!workList.empty()) {
|
while (!workList.empty()) {
|
||||||
string hash = workList.front();
|
Hash hash = parseHash(workList.front());
|
||||||
workList.pop_front();
|
workList.pop_front();
|
||||||
|
|
||||||
if (doneSet.find(hash) == doneSet.end()) {
|
if (doneSet.find(hash) == doneSet.end()) {
|
||||||
|
@ -605,7 +602,7 @@ void printGraph(Strings::iterator first, Strings::iterator last)
|
||||||
it != allHashes.end(); it++)
|
it != allHashes.end(); it++)
|
||||||
{
|
{
|
||||||
Params pkgImports, fileImports, arguments;
|
Params pkgImports, fileImports, arguments;
|
||||||
readPkgDescr(*it, pkgImports, fileImports, arguments);
|
readPkgDescr(parseHash(*it), pkgImports, fileImports, arguments);
|
||||||
|
|
||||||
cout << dotQuote(*it) << "[label = \""
|
cout << dotQuote(*it) << "[label = \""
|
||||||
<< getFromEnv(arguments, "id")
|
<< getFromEnv(arguments, "id")
|
||||||
|
@ -633,8 +630,8 @@ void fetch(string id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register it by hash. */
|
/* Register it by hash. */
|
||||||
string hash = registerFile(fn);
|
Hash hash = registerFile(fn);
|
||||||
cout << hash << endl;
|
cout << (string) hash << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -648,60 +645,60 @@ void fetch(Strings::iterator first, Strings::iterator last)
|
||||||
void printUsage()
|
void printUsage()
|
||||||
{
|
{
|
||||||
cerr <<
|
cerr <<
|
||||||
"Usage: nix SUBCOMMAND OPTIONS...
|
"Usage: nix SUBCOMMAND OPTIONS...\n\
|
||||||
|
\n\
|
||||||
Subcommands:
|
Subcommands:\n\
|
||||||
|
\n\
|
||||||
init
|
init\n\
|
||||||
Initialize the database.
|
Initialize the database.\n\
|
||||||
|
\n\
|
||||||
verify
|
verify\n\
|
||||||
Remove stale entries from the database.
|
Remove stale entries from the database.\n\
|
||||||
|
\n\
|
||||||
regfile FILENAME...
|
regfile FILENAME...\n\
|
||||||
Register each FILENAME keyed by its hash.
|
Register each FILENAME keyed by its hash.\n\
|
||||||
|
\n\
|
||||||
reginst HASH PATH
|
reginst HASH PATH\n\
|
||||||
Register an installed package.
|
Register an installed package.\n\
|
||||||
|
\n\
|
||||||
getpkg HASH...
|
getpkg HASH...\n\
|
||||||
For each HASH, ensure that the package referenced by HASH is
|
For each HASH, ensure that the package referenced by HASH is\n\
|
||||||
installed. Print out the path of the installation on stdout.
|
installed. Print out the path of the installation on stdout.\n\
|
||||||
|
\n\
|
||||||
delpkg HASH...
|
delpkg HASH...\n\
|
||||||
Uninstall the package referenced by each HASH, disregarding any
|
Uninstall the package referenced by each HASH, disregarding any\n\
|
||||||
dependencies that other packages may have on HASH.
|
dependencies that other packages may have on HASH.\n\
|
||||||
|
\n\
|
||||||
listinst
|
listinst\n\
|
||||||
Prints a list of installed packages.
|
Prints a list of installed packages.\n\
|
||||||
|
\n\
|
||||||
run HASH ARGS...
|
run HASH ARGS...\n\
|
||||||
Run the descriptor referenced by HASH with the given arguments.
|
Run the descriptor referenced by HASH with the given arguments.\n\
|
||||||
|
\n\
|
||||||
ensure HASH...
|
ensure HASH...\n\
|
||||||
Like getpkg, but if HASH refers to a run descriptor, fetch only
|
Like getpkg, but if HASH refers to a run descriptor, fetch only\n\
|
||||||
the dependencies.
|
the dependencies.\n\
|
||||||
|
\n\
|
||||||
export DIR HASH...
|
export DIR HASH...\n\
|
||||||
Export installed packages to DIR.
|
Export installed packages to DIR.\n\
|
||||||
|
\n\
|
||||||
regprebuilt HASH1 HASH2
|
regprebuilt HASH1 HASH2\n\
|
||||||
Inform Nix that an export HASH2 can be used to fast-build HASH1.
|
Inform Nix that an export HASH2 can be used to fast-build HASH1.\n\
|
||||||
|
\n\
|
||||||
info HASH...
|
info HASH...\n\
|
||||||
Print information about the specified descriptors.
|
Print information about the specified descriptors.\n\
|
||||||
|
\n\
|
||||||
closure HASH...
|
closure HASH...\n\
|
||||||
Determine the closure of the set of descriptors under the import
|
Determine the closure of the set of descriptors under the import\n\
|
||||||
relation, starting at the given roots.
|
relation, starting at the given roots.\n\
|
||||||
|
\n\
|
||||||
graph HASH...
|
graph HASH...\n\
|
||||||
Like closure, but print a dot graph specification.
|
Like closure, but print a dot graph specification.\n\
|
||||||
|
\n\
|
||||||
fetch ID...
|
fetch ID...\n\
|
||||||
Fetch the objects identified by ID and place them in the Nix
|
Fetch the objects identified by ID and place them in the Nix\n\
|
||||||
sources directory. ID can be a hash or URL. Print out the hash
|
sources directory. ID can be a hash or URL. Print out the hash\n\
|
||||||
of the object.
|
of the object.\n\
|
||||||
";
|
";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,29 +740,31 @@ void run(Strings::iterator argCur, Strings::iterator argEnd)
|
||||||
verifyDB();
|
verifyDB();
|
||||||
} else if (cmd == "getpkg") {
|
} else if (cmd == "getpkg") {
|
||||||
for (Strings::iterator it = argCur; it != argEnd; it++) {
|
for (Strings::iterator it = argCur; it != argEnd; it++) {
|
||||||
string path = getPkg(*it);
|
string path = getPkg(parseHash(*it));
|
||||||
cout << path << endl;
|
cout << path << endl;
|
||||||
}
|
}
|
||||||
} else if (cmd == "delpkg") {
|
} else if (cmd == "delpkg") {
|
||||||
for_each(argCur, argEnd, delPkg);
|
for (Strings::iterator it = argCur; it != argEnd; it++)
|
||||||
|
delPkg(parseHash(*it));
|
||||||
} else if (cmd == "run") {
|
} else if (cmd == "run") {
|
||||||
if (argc < 1) throw argcError;
|
if (argc < 1) throw argcError;
|
||||||
runPkg(*argCur, argCur + 1, argEnd);
|
runPkg(parseHash(*argCur), argCur + 1, argEnd);
|
||||||
} else if (cmd == "ensure") {
|
} else if (cmd == "ensure") {
|
||||||
for_each(argCur, argEnd, ensurePkg);
|
for (Strings::iterator it = argCur; it != argEnd; it++)
|
||||||
|
ensurePkg(parseHash(*it));
|
||||||
} else if (cmd == "export") {
|
} else if (cmd == "export") {
|
||||||
if (argc < 1) throw argcError;
|
if (argc < 1) throw argcError;
|
||||||
exportPkgs(*argCur, argCur + 1, argEnd);
|
exportPkgs(*argCur, argCur + 1, argEnd);
|
||||||
} else if (cmd == "regprebuilt") {
|
} else if (cmd == "regprebuilt") {
|
||||||
if (argc != 2) throw argcError;
|
if (argc != 2) throw argcError;
|
||||||
registerPrebuilt(*argCur, argCur[1]);
|
registerPrebuilt(parseHash(argCur[0]), parseHash(argCur[1]));
|
||||||
} else if (cmd == "regfile") {
|
} else if (cmd == "regfile") {
|
||||||
for_each(argCur, argEnd, registerFile);
|
for_each(argCur, argEnd, registerFile);
|
||||||
} else if (cmd == "regurl") {
|
} else if (cmd == "regurl") {
|
||||||
registerURL(argCur[0], argCur[1]);
|
registerURL(parseHash(argCur[0]), argCur[1]);
|
||||||
} else if (cmd == "reginst") {
|
} else if (cmd == "reginst") {
|
||||||
if (argc != 2) throw argcError;
|
if (argc != 2) throw argcError;
|
||||||
registerInstalledPkg(*argCur, argCur[1]);
|
registerInstalledPkg(parseHash(argCur[0]), argCur[1]);
|
||||||
} else if (cmd == "listinst") {
|
} else if (cmd == "listinst") {
|
||||||
if (argc != 0) throw argcError;
|
if (argc != 0) throw argcError;
|
||||||
listInstalledPkgs();
|
listInstalledPkgs();
|
||||||
|
|
16
src/test.cc
Normal file
16
src/test.cc
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "hash.hh"
|
||||||
|
|
||||||
|
int main(int argc, char * * argv)
|
||||||
|
{
|
||||||
|
Hash h = hashFile("/etc/passwd");
|
||||||
|
|
||||||
|
cout << (string) h << endl;
|
||||||
|
|
||||||
|
h = parseHash("0b0ffd0538622bfe20b92c4aa57254d9");
|
||||||
|
|
||||||
|
cout << (string) h << endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
47
src/util.cc
47
src/util.cc
|
@ -27,53 +27,6 @@ string absPath(string filename, string dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static 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). */
|
|
||||||
bool isHash(const string & s)
|
|
||||||
{
|
|
||||||
if (s.length() != 32) return false;
|
|
||||||
for (int i = 0; i < 32; i++) {
|
|
||||||
char c = s[i];
|
|
||||||
if (!((c >= '0' && c <= '9') ||
|
|
||||||
(c >= 'a' && c <= 'f')))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void checkHash(const string & s)
|
|
||||||
{
|
|
||||||
if (!isHash(s)) throw BadRefError("invalid reference: " + s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the directory part of the given path, i.e., everything
|
/* Return the directory part of the given path, i.e., everything
|
||||||
before the final `/'. */
|
before the final `/'. */
|
||||||
string dirOf(string s)
|
string dirOf(string s)
|
||||||
|
|
13
src/util.hh
13
src/util.hh
|
@ -7,10 +7,6 @@
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include "md5.h"
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,12 +25,6 @@ public:
|
||||||
UsageError(string _err) : Error(_err) { };
|
UsageError(string _err) : Error(_err) { };
|
||||||
};
|
};
|
||||||
|
|
||||||
class BadRefError : public Error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BadRefError(string _err) : Error(_err) { };
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef vector<string> Strings;
|
typedef vector<string> Strings;
|
||||||
|
|
||||||
|
@ -50,9 +40,6 @@ extern string nixHomeDirEnvVar;
|
||||||
|
|
||||||
|
|
||||||
string absPath(string filename, string dir = "");
|
string absPath(string filename, string dir = "");
|
||||||
bool isHash(const string & s);
|
|
||||||
void checkHash(const string & s);
|
|
||||||
string hashFile(string filename);
|
|
||||||
string dirOf(string s);
|
string dirOf(string s);
|
||||||
string baseNameOf(string s);
|
string baseNameOf(string s);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue