summaryrefslogtreecommitdiff
path: root/deps/npm/lib/cache/add-local-tarball.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/lib/cache/add-local-tarball.js')
-rw-r--r--deps/npm/lib/cache/add-local-tarball.js223
1 files changed, 223 insertions, 0 deletions
diff --git a/deps/npm/lib/cache/add-local-tarball.js b/deps/npm/lib/cache/add-local-tarball.js
new file mode 100644
index 0000000000..bcb938fa97
--- /dev/null
+++ b/deps/npm/lib/cache/add-local-tarball.js
@@ -0,0 +1,223 @@
+var mkdir = require("mkdirp")
+ , assert = require("assert")
+ , fs = require("graceful-fs")
+ , readJson = require("read-package-json")
+ , log = require("npmlog")
+ , path = require("path")
+ , sha = require("sha")
+ , npm = require("../npm.js")
+ , tar = require("../utils/tar.js")
+ , pathIsInside = require("path-is-inside")
+ , locker = require("../utils/locker.js")
+ , lock = locker.lock
+ , unlock = locker.unlock
+ , getCacheStat = require("./get-stat.js")
+ , chownr = require("chownr")
+ , inflight = require("inflight")
+ , once = require("once")
+
+module.exports = addLocalTarball
+
+function addLocalTarball (p, pkgData, shasum, cb_) {
+ assert(typeof p === "string", "must have path")
+ assert(typeof cb_ === "function", "must have callback")
+
+ if (!pkgData) pkgData = {}
+ var name = pkgData.name || ""
+
+ // If we don't have a shasum yet, then get the shasum now.
+ if (!shasum) {
+ return sha.get(p, function (er, shasum) {
+ if (er) return cb_(er)
+ addLocalTarball(p, pkgData, shasum, cb_)
+ })
+ }
+
+ // if it's a tar, and not in place,
+ // then unzip to .tmp, add the tmp folder, and clean up tmp
+ if (pathIsInside(p, npm.tmp))
+ return addTmpTarball(p, pkgData, shasum, cb_)
+
+ if (pathIsInside(p, npm.cache)) {
+ if (path.basename(p) !== "package.tgz") return cb_(new Error(
+ "Not a valid cache tarball name: "+p))
+ return addPlacedTarball(p, pkgData, shasum, cb_)
+ }
+
+ function cb (er, data) {
+ if (data) {
+ data._resolved = p
+ data._shasum = data._shasum || shasum
+ }
+ return cb_(er, data)
+ }
+
+ // just copy it over and then add the temp tarball file.
+ var tmp = path.join(npm.tmp, name + Date.now()
+ + "-" + Math.random(), "tmp.tgz")
+ mkdir(path.dirname(tmp), function (er) {
+ if (er) return cb(er)
+ var from = fs.createReadStream(p)
+ , to = fs.createWriteStream(tmp)
+ , errState = null
+ function errHandler (er) {
+ if (errState) return
+ return cb(errState = er)
+ }
+ from.on("error", errHandler)
+ to.on("error", errHandler)
+ to.on("close", function () {
+ if (errState) return
+ log.verbose("chmod", tmp, npm.modes.file.toString(8))
+ fs.chmod(tmp, npm.modes.file, function (er) {
+ if (er) return cb(er)
+ addTmpTarball(tmp, pkgData, shasum, cb)
+ })
+ })
+ from.pipe(to)
+ })
+}
+
+function addPlacedTarball (p, pkgData, shasum, cb) {
+ assert(pkgData, "should have package data by now")
+ assert(typeof cb === "function", "cb function required")
+
+ getCacheStat(function (er, cs) {
+ if (er) return cb(er)
+ return addPlacedTarball_(p, pkgData, cs.uid, cs.gid, shasum, cb)
+ })
+}
+
+function addPlacedTarball_ (p, pkgData, uid, gid, resolvedSum, cb) {
+ // now we know it's in place already as .cache/name/ver/package.tgz
+ var name = pkgData.name
+ , version = pkgData.version
+ , folder = path.join(npm.cache, name, version, "package")
+
+ // First, make sure we have the shasum, if we don't already.
+ if (!resolvedSum) {
+ sha.get(p, function (er, shasum) {
+ if (er) return cb(er)
+ addPlacedTarball_(p, pkgData, uid, gid, shasum, cb)
+ })
+ return
+ }
+
+ lock(folder, function (er) {
+ if (er) return cb(er)
+
+ // async try/finally
+ var originalCb = cb
+ cb = function (er, data) {
+ unlock(folder, function (er2) {
+ return originalCb(er || er2, data)
+ })
+ }
+
+ mkdir(folder, function (er) {
+ if (er) return cb(er)
+ var pj = path.join(folder, "package.json")
+ var json = JSON.stringify(pkgData, null, 2)
+ fs.writeFile(pj, json, "utf8", function (er) {
+ cb(er, pkgData)
+ })
+ })
+ })
+}
+
+function addTmpTarball (tgz, pkgData, shasum, cb) {
+ assert(typeof cb === "function", "must have callback function")
+ assert(shasum, "should have shasum by now")
+
+ cb = inflight("addTmpTarball:" + tgz, cb)
+ if (!cb) return
+
+ // we already have the package info, so just move into place
+ if (pkgData && pkgData.name && pkgData.version) {
+ return addTmpTarball_(tgz, pkgData, shasum, cb)
+ }
+
+ // This is a tarball we probably downloaded from the internet.
+ // The shasum's already been checked, but we haven't ever had
+ // a peek inside, so we unpack it here just to make sure it is
+ // what it says it is.
+ // Note: we might not have any clue what we think it is, for
+ // example if the user just did `npm install ./foo.tgz`
+
+ var target = tgz + "-unpack"
+ getCacheStat(function (er, cs) {
+ tar.unpack(tgz, target, null, null, cs.uid, cs.gid, next)
+ })
+
+ function next (er) {
+ if (er) return cb(er)
+ var pj = path.join(target, "package.json")
+ readJson(pj, function (er, data) {
+ // XXX dry with similar stanza in add-local.js
+ 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)
+
+ addTmpTarball_(tgz, data, shasum, cb)
+ })
+ }
+}
+
+function addTmpTarball_ (tgz, data, shasum, cb) {
+ assert(typeof cb === "function", "must have callback function")
+ cb = once(cb)
+
+ var name = data.name
+ var version = data.version
+ assert(name, "should have package name by now")
+ assert(version, "should have package version by now")
+
+ var root = path.resolve(npm.cache, name, version)
+ var pkg = path.resolve(root, "package")
+ var target = path.resolve(root, "package.tgz")
+ getCacheStat(function (er, cs) {
+ if (er) return cb(er)
+ mkdir(pkg, function (er) {
+ if (er) return cb(er)
+ var read = fs.createReadStream(tgz)
+ var write = fs.createWriteStream(target)
+ var fin = cs.uid && cs.gid ? chown : done
+ read.on("error", cb).pipe(write).on("error", cb).on("close", fin)
+ })
+
+ function chown () {
+ chownr(root, cs.uid, cs.gid, done)
+ }
+ })
+
+ function done() {
+ data._shasum = data._shasum || shasum
+ cb(null, data)
+ }
+}
+
+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
+}