* Various updates.

This commit is contained in:
Eelco Dolstra 2003-03-20 16:53:00 +00:00
parent b3594e9eaf
commit f7a98e081d

View file

@ -16,8 +16,11 @@
using namespace std; using namespace std;
#define PKGINFO_ENVVAR "NIX_DB"
#define PKGINFO_PATH "/pkg/sys/var/pkginfo" #define PKGINFO_PATH "/pkg/sys/var/pkginfo"
#define PKGHOME_ENVVAR "NIX_PKGHOME"
static string dbRefs = "refs"; static string dbRefs = "refs";
static string dbInstPkgs = "pkginst"; static string dbInstPkgs = "pkginst";
@ -27,6 +30,25 @@ static string prog;
static string dbfile = PKGINFO_PATH; static string dbfile = PKGINFO_PATH;
static string pkgHome = "/pkg";
class Error : public exception
{
string err;
public:
Error(string _err) { err = _err; }
~Error() throw () { };
const char * what() const throw () { return err.c_str(); }
};
class UsageError : public Error
{
public:
UsageError(string _err) : Error(_err) { };
};
/* Wrapper class that ensures that the database is closed upon /* Wrapper class that ensures that the database is closed upon
object destruction. */ object destruction. */
class Db2 : public Db class Db2 : public Db
@ -96,12 +118,12 @@ void checkRef(const string & s)
{ {
string err = "invalid reference: " + s; string err = "invalid reference: " + s;
if (s.length() != 32) if (s.length() != 32)
throw err; throw Error(err);
for (int i = 0; i < 32; i++) { for (int i = 0; i < 32; i++) {
char c = s[i]; char c = s[i];
if (!((c >= '0' && c <= '9') || if (!((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f'))) (c >= 'a' && c <= 'f')))
throw err; throw Error(err);
} }
} }
@ -112,10 +134,10 @@ string makeRef(string filename)
char hash[33]; char hash[33];
FILE * pipe = popen(("md5sum " + filename).c_str(), "r"); FILE * pipe = popen(("md5sum " + filename).c_str(), "r");
if (!pipe) throw string("cannot execute md5sum"); if (!pipe) throw Error("cannot execute md5sum");
if (fread(hash, 32, 1, pipe) != 1) if (fread(hash, 32, 1, pipe) != 1)
throw string("cannot read hash from md5sum"); throw Error("cannot read hash from md5sum");
hash[32] = 0; hash[32] = 0;
pclose(pipe); pclose(pipe);
@ -166,7 +188,7 @@ void readPkgDescr(const string & pkgfile,
pkgImports.push_back(Dep(name, ref)); pkgImports.push_back(Dep(name, ref));
else if (op == "=") else if (op == "=")
fileImports.push_back(Dep(name, ref)); fileImports.push_back(Dep(name, ref));
else throw string("invalid operator " + op); else throw Error("invalid operator " + op);
} }
} }
@ -187,13 +209,13 @@ void installPkg(string pkgref)
string builder; string builder;
if (!queryDB("refs", pkgref, pkgfile)) if (!queryDB("refs", pkgref, pkgfile))
throw string("unknown package " + pkgref); throw Error("unknown package " + pkgref);
cerr << "installing package " + pkgref + " from " + pkgfile + "\n"; cerr << "installing package " + pkgref + " from " + pkgfile + "\n";
/* Verify that the file hasn't changed. !!! race */ /* Verify that the file hasn't changed. !!! race */
if (makeRef(pkgfile) != pkgref) if (makeRef(pkgfile) != pkgref)
throw string("file " + pkgfile + " is stale"); throw Error("file " + pkgfile + " is stale");
/* Read the package description file. */ /* Read the package description file. */
DepList pkgImports, fileImports; DepList pkgImports, fileImports;
@ -222,10 +244,10 @@ void installPkg(string pkgref)
string file; string file;
if (!queryDB("refs", it->ref, file)) if (!queryDB("refs", it->ref, file))
throw string("unknown file " + it->ref); throw Error("unknown file " + it->ref);
if (makeRef(file) != it->ref) if (makeRef(file) != it->ref)
throw string("file " + file + " is stale"); throw Error("file " + file + " is stale");
if (it->name == "build") if (it->name == "build")
builder = file; builder = file;
@ -234,57 +256,66 @@ void installPkg(string pkgref)
} }
if (builder == "") if (builder == "")
throw string("no builder specified"); throw Error("no builder specified");
/* Construct a path for the installed package. */ /* Construct a path for the installed package. */
path = "/pkg/" + pkgref; path = pkgHome + "/" + pkgref;
/* Create the path. */ /* Create the path. */
if (mkdir(path.c_str(), 0777)) if (mkdir(path.c_str(), 0777))
throw string("unable to create directory " + path); throw Error("unable to create directory " + path);
/* Fork a child to build the package. */ try {
pid_t pid;
switch (pid = fork()) {
case -1: /* Fork a child to build the package. */
throw string("unable to fork"); pid_t pid;
switch (pid = fork()) {
case -1:
throw Error("unable to fork");
case 0: /* child */ case 0: { /* child */
/* Go to the build directory. */ /* Go to the build directory. */
if (chdir(path.c_str())) { if (chdir(path.c_str())) {
cout << "unable to chdir to package directory\n"; cout << "unable to chdir to package directory\n";
_exit(1);
}
/* Fill in the environment. We don't bother freeing the
strings, since we'll exec or die soon anyway. */
const char * env2[env.size() + 1];
int i = 0;
for (Environment::iterator it = env.begin();
it != env.end(); it++, i++)
env2[i] = (new string(it->first + "=" + it->second))->c_str();
env2[i] = 0;
/* Execute the builder. This should not return. */
execle(builder.c_str(), builder.c_str(), 0, env2);
cout << strerror(errno) << endl;
cout << "unable to execute builder\n";
_exit(1); _exit(1);
} }
/* Fill in the environment. We don't bother freeing the }
strings, since we'll exec or die soon anyway. */
const char * env2[env.size() + 1];
int i = 0;
for (Environment::iterator it = env.begin();
it != env.end(); it++, i++)
env2[i] = (new string(it->first + "=" + it->second))->c_str();
env2[i] = 0;
/* Execute the builder. This should not return. */ /* parent */
execle(builder.c_str(), builder.c_str(), 0, env2);
cout << strerror(errno) << endl; /* Wait for the child to finish. */
int status;
cout << "unable to execute builder\n"; if (waitpid(pid, &status, 0) != pid)
_exit(1); throw Error("unable to wait for child");
}
/* parent */
/* Wait for the child to finish. */
int status;
if (waitpid(pid, &status, 0) != pid)
throw string("unable to wait for child");
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
throw string("unable to build package"); throw Error("unable to build package");
} catch (exception &) {
system(("rm -rf " + path).c_str());
throw;
}
setDB(dbInstPkgs, pkgref, path); setDB(dbInstPkgs, pkgref, path);
} }
@ -305,7 +336,7 @@ string absPath(string filename)
if (filename[0] != '/') { if (filename[0] != '/') {
char buf[PATH_MAX]; char buf[PATH_MAX];
if (!getcwd(buf, sizeof(buf))) if (!getcwd(buf, sizeof(buf)))
throw string("cannot get cwd"); throw Error("cannot get cwd");
filename = string(buf) + "/" + filename; filename = string(buf) + "/" + filename;
/* !!! canonicalise */ /* !!! canonicalise */
} }
@ -343,69 +374,112 @@ void run(int argc, char * * argv)
string cmd; string cmd;
if (argc < 1) if (argc < 1)
throw string("command not specified"); throw UsageError("no command specified");
cmd = argv[0]; cmd = argv[0];
argc--, argv++; argc--, argv++;
if (cmd == "init") { if (cmd == "init") {
if (argc != 0) if (argc != 0)
throw string("init doesn't have arguments"); throw UsageError("wrong number of arguments");
initDB(); initDB();
} else if (cmd == "getpkg") { } else if (cmd == "getpkg") {
if (argc != 1) if (argc != 1)
throw string("arguments missing in getpkg"); throw UsageError("wrong number of arguments");
string path = getPkg(argv[0]); string path = getPkg(argv[0]);
cout << path << endl; cout << path << endl;
} else if (cmd == "reg") { } else if (cmd == "regfile") {
if (argc != 1) if (argc != 1)
throw string("arguments missing in reg"); throw UsageError("wrong number of arguments");
registerFile(argv[0]); registerFile(argv[0]);
} else if (cmd == "regpkg") { } else if (cmd == "reginst") {
if (argc != 2) if (argc != 2)
throw string("arguments missing in regpkg"); throw UsageError("wrong number of arguments");
registerInstalledPkg(argv[0], argv[1]); registerInstalledPkg(argv[0], argv[1]);
} else } else
throw string("unknown command: " + string(cmd)); throw UsageError("unknown command: " + string(cmd));
} }
int main(int argc, char * * argv) void printUsage()
{
cerr <<
"Usage: nix SUBCOMMAND OPTIONS...
Subcommands:
init
Initialize the database.
regfile FILENAME
Register FILENAME keyed by its hash.
reginst HASH PATH
Register an installed package.
getpkg HASH
Ensure that the package referenced by HASH is installed. Prints
out the path of the package on stdout.
";
}
void main2(int argc, char * * argv)
{ {
int c; int c;
prog = argv[0];
umask(0022); umask(0022);
try { if (getenv(PKGINFO_ENVVAR))
dbfile = getenv(PKGINFO_ENVVAR);
while ((c = getopt(argc, argv, "d:")) != EOF) { if (getenv(PKGHOME_ENVVAR))
pkgHome = getenv(PKGHOME_ENVVAR);
opterr = 0;
while ((c = getopt(argc, argv, "hd:")) != EOF) {
switch (c) { switch (c) {
case 'd': case 'h':
dbfile = optarg; printUsage();
break; return;
default: case 'd':
throw string("unknown option"); dbfile = optarg;
break; break;
} default:
throw UsageError("invalid option `" + string(1, optopt) + "'");
break;
} }
}
argc -= optind, argv += optind; argc -= optind, argv += optind;
run(argc, argv); run(argc, argv);
}
} catch (DbException e) {
cerr << "db exception: " << e.what() << endl; int main(int argc, char * * argv)
{
prog = argv[0];
try {
try {
main2(argc, argv);
} catch (DbException e) {
throw Error(e.what());
}
} catch (UsageError & e) {
cerr << "error: " << e.what() << endl
<< "Try `nix -h' for more information.\n";
return 1; return 1;
} catch (exception e) { } catch (exception & e) {
cerr << e.what() << endl; cerr << "error: " << e.what() << endl;
return 1;
} catch (string s) {
cerr << s << endl;
return 1; return 1;
} }