--- /dev/null
+var 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")
+ , getCacheStat = require("./get-stat.js")
+ , cachedPackageRoot = require("./cached-package-root.js")
+ , addLocalTarball = require("./add-local-tarball.js")
+ , sha = require("sha")
+ , inflight = require("inflight")
+
+module.exports = addLocal
+
+function addLocal (p, pkgData, cb_) {
+ assert(typeof p === "object", "must have spec info")
+ assert(typeof cb_ === "function", "must have callback")
+
+ pkgData = pkgData || {}
+
+ function cb (er, data) {
+ if (er) {
+ log.error("addLocal", "Could not install %s", p.spec)
+ return cb_(er)
+ }
+ if (data && !data._fromGithub) {
+ data._from = path.relative(npm.prefix, p.spec) || "."
+ var resolved = path.relative(npm.prefix, p.spec)
+ if (resolved) data._resolved = "file:"+resolved
+ }
+ return cb_(er, data)
+ }
+
+ if (p.type === "directory") {
+ addLocalDirectory(p.spec, pkgData, null, cb)
+ }
+ else {
+ addLocalTarball(p.spec, 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) {
+ if (er) return cb(er)
+
+ if (!data.name) {
+ return cb(new Error("No name provided in package.json"))
+ }
+ else if (pkgData.name && pkgData.name !== data.name) {
+ return cb(new Error(
+ "Invalid package: expected " + pkgData.name + " but found " + data.name
+ ))
+ }
+
+ if (!data.version) {
+ return cb(new Error("No version provided in package.json"))
+ }
+ else if (pkgData.version && pkgData.version !== data.version) {
+ return cb(new Error(
+ "Invalid package: expected " + pkgData.name + "@" + pkgData.version +
+ " but found " + data.name + "@" + data.version
+ ))
+ }
+
+ deprCheck(data)
+
+ // pack to {cache}/name/ver/package.tgz
+ var root = cachedPackageRoot(data)
+ var tgz = path.resolve(root, "package.tgz")
+ var pj = path.resolve(root, "package/package.json")
+
+ var wrapped = inflight(tgz, next)
+ if (!wrapped) return log.verbose("addLocalDirectory", tgz, "already in flight; waiting")
+ log.verbose("addLocalDirectory", tgz, "not in flight; packing")
+
+ getCacheStat(function (er, cs) {
+ mkdir(path.dirname(pj), function (er, made) {
+ if (er) return wrapped(er)
+ var fancy = !pathIsInside(p, npm.tmp)
+ tar.pack(tgz, p, data, fancy, function (er) {
+ if (er) {
+ log.error("addLocalDirectory", "Could not pack", p, "to", tgz)
+ return wrapped(er)
+ }
+
+ if (!cs || isNaN(cs.uid) || isNaN(cs.gid)) return wrapped()
+
+ chownr(made || tgz, cs.uid, cs.gid, function (er) {
+ if (er && er.code === 'ENOENT') return wrapped()
+ wrapped(er)
+ })
+ })
+ })
+ })
+
+ 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)
+ })
+ }
+ }
+ })
+}