Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

Commit

Permalink
Do the dependency dance.
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacs committed Feb 27, 2010
1 parent b81e220 commit 1ab6b7b
Showing 1 changed file with 97 additions and 9 deletions.
106 changes: 97 additions & 9 deletions lib/install.js
Expand Up @@ -11,7 +11,8 @@ var npm = require("../npm"),
fetch = require("./utils/fetch"),
sys = require("sys"),
fs = require("fs"),
path = require("path");
path = require("path"),
semver = require("./utils/semver");

module.exports = install;

Expand Down Expand Up @@ -45,7 +46,7 @@ function install (tarball, cb) {
// at this point, presumably the filesystem knows how to open it.
chain(
[fs, "stat", tarball],
[ensureDir, unpackTargetDir, 0755],
[ensureDir, unpackTargetDir],
[unpackTar, tarball, unpackTargetDir],
// clean up
[function (cb) { log("unpacked, deleting"); cb() }],
Expand All @@ -62,7 +63,16 @@ function install (tarball, cb) {
}],

// move to ROOT/.npm/{name}/{version}/package
[function (cb) { log("about to move into place"); cb() }],
[moveIntoPlace, unpackTargetDir, pkg],

[function (cb) { log("about to resolve deps"); cb() }],
// link deps into ROOT/.npm/{name}/{version}/dependencies
// this is then added to require.paths, but ONLY for this package's main module.
// of course, they could do require(".npm/foo/1.0.3/dependencies/bar") to import
// whichever version of bar is currently satisfying foo-1.0.3's need.
// For now, all dependencies must already be installed, or the install fails.
[resolveDependencies, pkg],

// generate ROOT/.npm/{name}/{version}/main.js
[createMain, pkg],
Expand All @@ -86,6 +96,79 @@ function install (tarball, cb) {
);
};

// make sure that all the dependencies have been installed.
// todo: if they're not, then install them, and come back here.
function resolveDependencies (pkg, topCb) {
log("Resolving dependencies");
pkg = pkg && pkg.data;
if (!pkg) return cb(new Error("Package not found to resolve dependencies"));
// link foo-1.0.3 to ROOT/.npm/{pkg}/{ver}/dependencies/foo

var found = [];
chain(
[ensureDir, path.join(npm.dir, pkg.name, pkg.version, "dependencies")],
[function (cb) {
if (!pkg.dependencies) return topCb();
// don't create anything until they're all verified.
var reqs = [];
for (var i in pkg.dependencies) reqs.push({name:i, ver:pkg.dependencies[i]});
if (!reqs.length) return topCb();

(function R (req) {
if (!req) return cb();
log(req.name+" "+req.ver, "required");
// see if we have this thing installed.
fs.readdir(path.join(npm.dir, req.name), function (er, versions) {
if (er) return cb(new Error(
"Required package: "+req.name+"("+req.ver+") not found."));
// TODO: Get the "stable" version if there is one.
// Look that up from the registry.
versions.sort(semver.compare);
var i = versions.length;
while (i--) {
if (semver.satisfies(versions[i], req.ver)) {
found.push({name:req.name, ver:versions[i]});
return R(reqs.pop());
}
}
return cb(new Error(
"Required package: "+req.name+"("+req.ver+") not found. "+
"(Found: "+JSON.stringify(versions)+")"));
});
})(reqs.pop());
}],
[function (cb) {
// link in all the found reqs.
(function L (req) {
if (!req) return cb();

log(req.name+ "-" +req.ver, "found");

// link ROOT/.npm/{pkg}/{ver}/dependencies/{req.name} to
// ROOT/{req.name}-{req.version}
// both the JS and the folder, if they're there
// then try again with the next req.
var to = path.join(npm.dir, pkg.name, pkg.version, "dependencies", req.name),
from = path.join(npm.root, req.name + "-" + req.ver);
function link (cb) {
fs.stat(from, function (er, stat) {
if (er) return cb();
processCb("ln", ["-s", from, to], cb);
});
};

// todo: link to pkg.linkdeps[ req.name ], too
chain([link], [function (cb) {
from += ".js";
to += ".js";
cb();
}], [link], function (er) { if (er) return topCb(er); L(found.pop()) });
})(found.pop());
}],
topCb
);
}

// move to ROOT/.npm/{name}/{version}/package
function moveIntoPlace (dir, pkg, cb) {
pkg = pkg.data;
Expand All @@ -97,13 +180,13 @@ function moveIntoPlace (dir, pkg, cb) {
chain(
[function (cb) {
path.exists(target, function (e) {
log(target + " " + (e?"exists, removing it":"doesn't exist, creating it"));
log(target + " ", (e?"remove":"creating"));
if (e) rm(target, function (er, ok) {
if (er) {
log("couldn't remove "+target);
log(target, "could not remove!");
cb(new Error(target+" exists, and can't be removed"));
} else {
log(target+" successfully unlinked");
log(target,"unlinked");
cb();
};
});
Expand All @@ -120,7 +203,7 @@ function moveIntoPlace (dir, pkg, cb) {

function fetchAndInstall (tarball, cb) {
log("fetchAndInstall: "+tarball);
ensureDir(npm.tmp, 0755, function (er, ok) {
ensureDir(npm.tmp, function (er, ok) {
if (er) return cb(er, ok);
var target = path.join(npm.tmp, tarball.replace(/[^a-zA-Z0-9]/g, "-")+"-"+
Date.now()+"-"+Math.random()+".tgz");
Expand All @@ -141,7 +224,7 @@ function ensureDir (ensure, chmod, cb) {
cb = chmod;
chmod = 0755;
}
log("Ensuring: "+ensure);
log(ensure, "mkdir");
walker.push(dirs.shift()); // gobble the "/" first
(function S (d) {
if (d === undefined) return cb();
Expand Down Expand Up @@ -200,9 +283,14 @@ function createMain (pkg,cb) {

var code =
"// generated by npm, please don't touch!\n"+
"module.exports=require("+
"require.paths.unshift("+
JSON.stringify(path.join(npm.dir, pkg.name, pkg.version, "dependencies"))+
");"+
"module.exports = require("+
JSON.stringify(path.join(npm.dir, pkg.name, pkg.version, "package", pkg.main)) +
");\n",
");"+
"require.paths.shift();"+
"\n",
proxyFile = path.join(npm.dir, pkg.name, pkg.version, "main.js");

fs.writeFile(proxyFile, code, "ascii", cb);
Expand Down

0 comments on commit 1ab6b7b

Please sign in to comment.