| 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 cb(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 cb(er) |
| } |
| |
| if (!cs || isNaN(cs.uid) || isNaN(cs.gid)) wrapped() |
| |
| chownr(made || tgz, cs.uid, cs.gid, wrapped) |
| }) |
| }) |
| }) |
| |
| 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) |
| }) |
| } |
| } |
| }) |
| } |