* Various updates.
This commit is contained in:
parent
b3594e9eaf
commit
f7a98e081d
1 changed files with 152 additions and 78 deletions
230
src/nix.cc
230
src/nix.cc
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue