You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

146 lines
4.4 KiB

var fs = require("graceful-fs")
, assert = require("assert")
, path = require("path")
, mkdir = require("mkdirp")
, chownr = require("chownr")
, pathIsInside = require("path-is-inside")
, readJson = require("read-package-json")
, log = require("npmlog")
, npm = require("../npm.js")
, tar = require("../utils/tar.js")
, deprCheck = require("../utils/depr-check.js")
, locker = require("../utils/locker.js")
, lock = locker.lock
, unlock = locker.unlock
, getCacheStat = require("./get-stat.js")
, addNamed = require("./add-named.js")
, addLocalTarball = require("./add-local-tarball.js")
, maybeGithub = require("./maybe-github.js")
, sha = require("sha")
module.exports = addLocal
function addLocal (p, pkgData, cb_) {
assert(typeof p === "string", "must have path")
assert(typeof cb === "function", "must have callback")
pkgData = pkgData || {}
function cb (er, data) {
unlock(p, function () {
if (er) {
// if it doesn't have a / in it, it might be a
// remote thing.
if (p.indexOf("/") === -1 && p.charAt(0) !== "."
&& (process.platform !== "win32" || p.indexOf("\\") === -1)) {
return addNamed(p, "", null, cb_)
}
log.error("addLocal", "Could not install %s", p)
return cb_(er)
}
if (data && !data._fromGithub) data._from = p
return cb_(er, data)
})
}
lock(p, function (er) {
if (er) return cb(er)
// figure out if this is a folder or file.
fs.stat(p, function (er, s) {
if (er) {
// might be username/project
// in that case, try it as a github url.
if (p.split("/").length === 2) {
return maybeGithub(p, er, cb)
}
return cb(er)
}
if (s.isDirectory()) addLocalDirectory(p, pkgData, null, cb)
else addLocalTarball(p, pkgData, null, cb)
})
})
}
// At this point, if shasum is set, it's something that we've already
// read and checked. Just stashing it in the data at this point.
function addLocalDirectory (p, pkgData, shasum, cb) {
assert(pkgData, "must pass package data")
assert(typeof cb === "function", "must have callback")
// if it's a folder, then read the package.json,
// tar it to the proper place, and add the cache tar
if (pathIsInside(p, npm.cache)) return cb(new Error(
"Adding a cache directory to the cache will make the world implode."))
readJson(path.join(p, "package.json"), false, function (er, data) {
er = needName(er, data)
er = needVersion(er, data)
// check that this is what we expected.
if (!er && pkgData.name && pkgData.name !== data.name) {
er = new Error( "Invalid Package: expected "
+ pkgData.name + " but found "
+ data.name )
}
if (!er && pkgData.version && pkgData.version !== data.version) {
er = new Error( "Invalid Package: expected "
+ pkgData.name + "@" + pkgData.version
+ " but found "
+ data.name + "@" + data.version )
}
if (er) return cb(er)
deprCheck(data)
// pack to {cache}/name/ver/package.tgz
var croot = path.resolve(npm.cache, data.name, data.version)
var tgz = path.resolve(croot, "package.tgz")
var pj = path.resolve(croot, "package/package.json")
getCacheStat(function (er, cs) {
mkdir(path.dirname(pj), function (er, made) {
if (er) return cb(er)
var fancy = !pathIsInside(p, npm.tmp)
tar.pack(tgz, p, data, fancy, function (er) {
if (er) {
log.error( "addLocalDirectory", "Could not pack %j to %j"
, p, tgz )
return cb(er)
}
if (!cs || isNaN(cs.uid) || isNaN(cs.gid)) next()
chownr(made || tgz, cs.uid, cs.gid, next)
})
})
})
function next (er) {
if (er) return cb(er)
// if we have the shasum already, just add it
if (shasum) {
return addLocalTarball(tgz, data, shasum, cb)
} else {
sha.get(tgz, function (er, shasum) {
if (er) {
return cb(er)
}
data._shasum = shasum
return addLocalTarball(tgz, data, shasum, cb)
})
}
}
})
}
function needName(er, data) {
return er ? er
: (data && !data.name) ? new Error("No name provided")
: null
}
function needVersion(er, data) {
return er ? er
: (data && !data.version) ? new Error("No version provided")
: null
}