| @@ -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 | ||
| } |
| @@ -0,0 +1,146 @@ | ||
| 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 | ||
| } |
| @@ -0,0 +1,275 @@ | ||
| var path = require("path") | ||
| , assert = require("assert") | ||
| , fs = require("graceful-fs") | ||
| , http = require("http") | ||
| , log = require("npmlog") | ||
| , semver = require("semver") | ||
| , readJson = require("read-package-json") | ||
| , url = require("url") | ||
| , npm = require("../npm.js") | ||
| , registry = npm.registry | ||
| , deprCheck = require("../utils/depr-check.js") | ||
| , inflight = require("inflight") | ||
| , locker = require("../utils/locker.js") | ||
| , lock = locker.lock | ||
| , unlock = locker.unlock | ||
| , maybeGithub = require("./maybe-github.js") | ||
| , addRemoteTarball = require("./add-remote-tarball.js") | ||
|
|
||
|
|
||
| module.exports = addNamed | ||
|
|
||
| var NAME_PREFIX = "addName:" | ||
| function addNamed (name, version, data, cb_) { | ||
| assert(typeof name === "string", "must have module name") | ||
| assert(typeof cb_ === "function", "must have callback") | ||
|
|
||
| log.verbose("addNamed", [name, version]) | ||
|
|
||
| var key = name + "@" + version | ||
| function cb (er, data) { | ||
| if (data && !data._fromGithub) data._from = key | ||
| unlock(key, function () { cb_(er, data) }) | ||
| } | ||
|
|
||
| cb_ = inflight(NAME_PREFIX + key, cb_) | ||
|
|
||
| if (!cb_) return | ||
|
|
||
| log.verbose("addNamed", [semver.valid(version), semver.validRange(version)]) | ||
| lock(key, function (er) { | ||
| if (er) return cb(er) | ||
|
|
||
| var fn = ( semver.valid(version, true) ? addNameVersion | ||
| : semver.validRange(version, true) ? addNameRange | ||
| : addNameTag | ||
| ) | ||
| fn(name, version, data, cb) | ||
| }) | ||
| } | ||
|
|
||
| function addNameTag (name, tag, data, cb_) { | ||
| log.info("addNameTag", [name, tag]) | ||
| var explicit = true | ||
| if (!tag) { | ||
| explicit = false | ||
| tag = npm.config.get("tag") | ||
| } | ||
|
|
||
| function cb(er, data) { | ||
| // might be username/project | ||
| // in that case, try it as a github url. | ||
| if (er && tag.split("/").length === 2) { | ||
| return maybeGithub(tag, er, cb_) | ||
| } | ||
| return cb_(er, data) | ||
| } | ||
|
|
||
| registry.get(name, function (er, data, json, resp) { | ||
| if (!er) { | ||
| er = errorResponse(name, resp) | ||
| } | ||
| if (er) return cb(er) | ||
| engineFilter(data) | ||
| if (data["dist-tags"] && data["dist-tags"][tag] | ||
| && data.versions[data["dist-tags"][tag]]) { | ||
| var ver = data["dist-tags"][tag] | ||
| return addNamed(name, ver, data.versions[ver], cb) | ||
| } | ||
| if (!explicit && Object.keys(data.versions).length) { | ||
| return addNamed(name, "*", data, cb) | ||
| } | ||
|
|
||
| er = installTargetsError(tag, data) | ||
| return cb(er) | ||
| }) | ||
| } | ||
|
|
||
| function engineFilter (data) { | ||
| var npmv = npm.version | ||
| , nodev = npm.config.get("node-version") | ||
| , strict = npm.config.get("engine-strict") | ||
|
|
||
| if (!nodev || npm.config.get("force")) return data | ||
|
|
||
| Object.keys(data.versions || {}).forEach(function (v) { | ||
| var eng = data.versions[v].engines | ||
| if (!eng) return | ||
| if (!strict && !data.versions[v].engineStrict) return | ||
| if (eng.node && !semver.satisfies(nodev, eng.node, true) | ||
| || eng.npm && !semver.satisfies(npmv, eng.npm, true)) { | ||
| delete data.versions[v] | ||
| } | ||
| }) | ||
| } | ||
|
|
||
| function addNameVersion (name, v, data, cb) { | ||
| var ver = semver.valid(v, true) | ||
| if (!ver) return cb(new Error("Invalid version: "+v)) | ||
|
|
||
| var response | ||
|
|
||
| if (data) { | ||
| response = null | ||
| return next() | ||
| } | ||
| registry.get(name, function (er, d, json, resp) { | ||
| if (!er) { | ||
| er = errorResponse(name, resp) | ||
| } | ||
| if (er) return cb(er) | ||
| data = d && d.versions[ver] | ||
| if (!data) { | ||
| er = new Error('version not found: ' + name + '@' + ver) | ||
| er.package = name | ||
| er.statusCode = 404 | ||
| return cb(er) | ||
| } | ||
| response = resp | ||
| next() | ||
| }) | ||
|
|
||
| function next () { | ||
| deprCheck(data) | ||
| var dist = data.dist | ||
|
|
||
| if (!dist) return cb(new Error("No dist in "+data._id+" package")) | ||
|
|
||
| if (!dist.tarball) return cb(new Error( | ||
| "No dist.tarball in " + data._id + " package")) | ||
|
|
||
| if ((response && response.statusCode !== 304) || npm.config.get("force")) { | ||
| return fetchit() | ||
| } | ||
|
|
||
| // we got cached data, so let's see if we have a tarball. | ||
| var pkgroot = path.join(npm.cache, name, ver) | ||
| var pkgtgz = path.join(pkgroot, "package.tgz") | ||
| var pkgjson = path.join(pkgroot, "package", "package.json") | ||
| fs.stat(pkgtgz, function (er) { | ||
| if (!er) { | ||
| readJson(pkgjson, function (er, data) { | ||
| er = needName(er, data) | ||
| er = needVersion(er, data) | ||
| if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") | ||
| return cb(er) | ||
| if (er) return fetchit() | ||
| return cb(null, data) | ||
| }) | ||
| } else return fetchit() | ||
| }) | ||
|
|
||
| function fetchit () { | ||
| if (!npm.config.get("registry")) { | ||
| return cb(new Error("Cannot fetch: "+dist.tarball)) | ||
| } | ||
|
|
||
| // use the same protocol as the registry. | ||
| // https registry --> https tarballs, but | ||
| // only if they're the same hostname, or else | ||
| // detached tarballs may not work. | ||
| var tb = url.parse(dist.tarball) | ||
| var rp = url.parse(npm.config.get("registry")) | ||
| if (tb.hostname === rp.hostname | ||
| && tb.protocol !== rp.protocol) { | ||
| tb.protocol = url.parse(npm.config.get("registry")).protocol | ||
| delete tb.href | ||
| } | ||
| tb = url.format(tb) | ||
|
|
||
| // only add non-shasum'ed packages if --forced. | ||
| // only ancient things would lack this for good reasons nowadays. | ||
| if (!dist.shasum && !npm.config.get("force")) { | ||
| return cb(new Error("package lacks shasum: " + data._id)) | ||
| } | ||
| return addRemoteTarball(tb, data, dist.shasum, cb) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| function addNameRange (name, range, data, cb) { | ||
| range = semver.validRange(range, true) | ||
| if (range === null) return cb(new Error( | ||
| "Invalid version range: "+range)) | ||
|
|
||
| log.silly("addNameRange", {name:name, range:range, hasData:!!data}) | ||
|
|
||
| if (data) return next() | ||
| registry.get(name, function (er, d, json, resp) { | ||
| if (!er) { | ||
| er = errorResponse(name, resp) | ||
| } | ||
| if (er) return cb(er) | ||
| data = d | ||
| next() | ||
| }) | ||
|
|
||
| function next () { | ||
| log.silly( "addNameRange", "number 2" | ||
| , {name:name, range:range, hasData:!!data}) | ||
| engineFilter(data) | ||
|
|
||
| log.silly("addNameRange", "versions" | ||
| , [data.name, Object.keys(data.versions || {})]) | ||
|
|
||
| // if the tagged version satisfies, then use that. | ||
| var tagged = data["dist-tags"][npm.config.get("tag")] | ||
| if (tagged | ||
| && data.versions[tagged] | ||
| && semver.satisfies(tagged, range, true)) { | ||
| return addNamed(name, tagged, data.versions[tagged], cb) | ||
| } | ||
|
|
||
| // find the max satisfying version. | ||
| var versions = Object.keys(data.versions || {}) | ||
| var ms = semver.maxSatisfying(versions, range, true) | ||
| if (!ms) { | ||
| return cb(installTargetsError(range, data)) | ||
| } | ||
|
|
||
| // if we don't have a registry connection, try to see if | ||
| // there's a cached copy that will be ok. | ||
| addNamed(name, ms, data.versions[ms], cb) | ||
| } | ||
| } | ||
|
|
||
| function installTargetsError (requested, data) { | ||
| var targets = Object.keys(data["dist-tags"]).filter(function (f) { | ||
| return (data.versions || {}).hasOwnProperty(f) | ||
| }).concat(Object.keys(data.versions || {})) | ||
|
|
||
| requested = data.name + (requested ? "@'" + requested + "'" : "") | ||
|
|
||
| targets = targets.length | ||
| ? "Valid install targets:\n" + JSON.stringify(targets) + "\n" | ||
| : "No valid targets found.\n" | ||
| + "Perhaps not compatible with your version of node?" | ||
|
|
||
| var er = new Error( "No compatible version found: " | ||
| + requested + "\n" + targets) | ||
| er.code = "ETARGET" | ||
| return er | ||
| } | ||
|
|
||
| function errorResponse (name, response) { | ||
| var er | ||
| if (response.statusCode >= 400) { | ||
| er = new Error(http.STATUS_CODES[response.statusCode]) | ||
| er.statusCode = response.statusCode | ||
| er.code = "E" + er.statusCode | ||
| er.pkgid = name | ||
| } | ||
| return er | ||
| } | ||
|
|
||
| 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 | ||
| } |
| @@ -0,0 +1,285 @@ | ||
| var mkdir = require("mkdirp") | ||
| , assert = require("assert") | ||
| , spawn = require("child_process").spawn | ||
| , exec = require("child_process").execFile | ||
| , once = require("once") | ||
| , fs = require("graceful-fs") | ||
| , log = require("npmlog") | ||
| , path = require("path") | ||
| , url = require("url") | ||
| , chownr = require("chownr") | ||
| , zlib = require("zlib") | ||
| , which = require("which") | ||
| , crypto = require("crypto") | ||
| , chmodr = require("chmodr") | ||
| , npm = require("../npm.js") | ||
| , rm = require("../utils/gently-rm.js") | ||
| , inflight = require("inflight") | ||
| , locker = require("../utils/locker.js") | ||
| , lock = locker.lock | ||
| , unlock = locker.unlock | ||
| , getCacheStat = require("./get-stat.js") | ||
| , addLocalTarball = require("./add-local-tarball.js") | ||
|
|
||
|
|
||
| // 1. cacheDir = path.join(cache,'_git-remotes',sha1(u)) | ||
| // 2. checkGitDir(cacheDir) ? 4. : 3. (rm cacheDir if necessary) | ||
| // 3. git clone --mirror u cacheDir | ||
| // 4. cd cacheDir && git fetch -a origin | ||
| // 5. git archive /tmp/random.tgz | ||
| // 6. addLocalTarball(/tmp/random.tgz) <gitref> --format=tar --prefix=package/ | ||
| // silent flag is used if this should error quietly | ||
| module.exports = function addRemoteGit (u, parsed, silent, cb_) { | ||
| assert(typeof u === "string", "must have git URL") | ||
| assert(typeof parsed === "object", "must have parsed query") | ||
| assert(typeof cb_ === "function", "must have callback") | ||
|
|
||
| function cb (er, data) { | ||
| unlock(u, function () { cb_(er, data) }) | ||
| } | ||
|
|
||
| cb_ = inflight(u, cb_) | ||
|
|
||
| if (!cb_) return | ||
|
|
||
| // git is so tricky! | ||
| // if the path is like ssh://foo:22/some/path then it works, but | ||
| // it needs the ssh:// | ||
| // If the path is like ssh://foo:some/path then it works, but | ||
| // only if you remove the ssh:// | ||
| var origUrl = u | ||
| u = u.replace(/^git\+/, "") | ||
| .replace(/#.*$/, "") | ||
|
|
||
| // ssh paths that are scp-style urls don't need the ssh:// | ||
| if (parsed.pathname.match(/^\/?:/)) { | ||
| u = u.replace(/^ssh:\/\//, "") | ||
| } | ||
|
|
||
| lock(u, function (er) { | ||
| if (er) return cb(er) | ||
|
|
||
| // figure out what we should check out. | ||
| var co = parsed.hash && parsed.hash.substr(1) || "master" | ||
|
|
||
| var v = crypto.createHash("sha1").update(u).digest("hex").slice(0, 8) | ||
| v = u.replace(/[^a-zA-Z0-9]+/g, '-') + '-' + v | ||
|
|
||
| log.verbose("addRemoteGit", [u, co]) | ||
|
|
||
| var p = path.join(npm.config.get("cache"), "_git-remotes", v) | ||
|
|
||
| checkGitDir(p, u, co, origUrl, silent, function(er, data) { | ||
| chmodr(p, npm.modes.file, function(erChmod) { | ||
| if (er) return cb(er, data) | ||
| return cb(erChmod, data) | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| function checkGitDir (p, u, co, origUrl, silent, cb) { | ||
| fs.stat(p, function (er, s) { | ||
| if (er) return cloneGitRemote(p, u, co, origUrl, silent, cb) | ||
| if (!s.isDirectory()) return rm(p, function (er){ | ||
| if (er) return cb(er) | ||
| cloneGitRemote(p, u, co, origUrl, silent, cb) | ||
| }) | ||
|
|
||
| var git = npm.config.get("git") | ||
| var args = [ "config", "--get", "remote.origin.url" ] | ||
| var env = gitEnv() | ||
|
|
||
| // check for git | ||
| which(git, function (err) { | ||
| if (err) { | ||
| err.code = "ENOGIT" | ||
| return cb(err) | ||
| } | ||
| exec(git, args, {cwd: p, env: env}, function (er, stdout, stderr) { | ||
| var stdoutTrimmed = (stdout + "\n" + stderr).trim() | ||
| if (er || u !== stdout.trim()) { | ||
| log.warn( "`git config --get remote.origin.url` returned " | ||
| + "wrong result ("+u+")", stdoutTrimmed ) | ||
| return rm(p, function (er){ | ||
| if (er) return cb(er) | ||
| cloneGitRemote(p, u, co, origUrl, silent, cb) | ||
| }) | ||
| } | ||
| log.verbose("git remote.origin.url", stdoutTrimmed) | ||
| archiveGitRemote(p, u, co, origUrl, cb) | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| function checkGitDir (p, u, co, origUrl, silent, cb) { | ||
| fs.stat(p, function (er, s) { | ||
| if (er) return cloneGitRemote(p, u, co, origUrl, silent, cb) | ||
| if (!s.isDirectory()) return rm(p, function (er){ | ||
| if (er) return cb(er) | ||
| cloneGitRemote(p, u, co, origUrl, silent, cb) | ||
| }) | ||
|
|
||
| var git = npm.config.get("git") | ||
| var args = [ "config", "--get", "remote.origin.url" ] | ||
| var env = gitEnv() | ||
|
|
||
| // check for git | ||
| which(git, function (err) { | ||
| if (err) { | ||
| err.code = "ENOGIT" | ||
| return cb(err) | ||
| } | ||
| exec(git, args, {cwd: p, env: env}, function (er, stdout, stderr) { | ||
| var stdoutTrimmed = (stdout + "\n" + stderr).trim() | ||
| if (er || u !== stdout.trim()) { | ||
| log.warn( "`git config --get remote.origin.url` returned " | ||
| + "wrong result ("+u+")", stdoutTrimmed ) | ||
| return rm(p, function (er){ | ||
| if (er) return cb(er) | ||
| cloneGitRemote(p, u, co, origUrl, silent, cb) | ||
| }) | ||
| } | ||
| log.verbose("git remote.origin.url", stdoutTrimmed) | ||
| archiveGitRemote(p, u, co, origUrl, cb) | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| function cloneGitRemote (p, u, co, origUrl, silent, cb) { | ||
| mkdir(p, function (er) { | ||
| if (er) return cb(er) | ||
|
|
||
| var git = npm.config.get("git") | ||
| var args = [ "clone", "--mirror", u, p ] | ||
| var env = gitEnv() | ||
|
|
||
| // check for git | ||
| which(git, function (err) { | ||
| if (err) { | ||
| err.code = "ENOGIT" | ||
| return cb(err) | ||
| } | ||
| exec(git, args, {cwd: p, env: env}, function (er, stdout, stderr) { | ||
| stdout = (stdout + "\n" + stderr).trim() | ||
| if (er) { | ||
| if (silent) { | ||
| log.verbose("git clone " + u, stdout) | ||
| } else { | ||
| log.error("git clone " + u, stdout) | ||
| } | ||
| return cb(er) | ||
| } | ||
| log.verbose("git clone " + u, stdout) | ||
| archiveGitRemote(p, u, co, origUrl, cb) | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| function archiveGitRemote (p, u, co, origUrl, cb) { | ||
| var git = npm.config.get("git") | ||
| var archive = [ "fetch", "-a", "origin" ] | ||
| var resolve = [ "rev-list", "-n1", co ] | ||
| var env = gitEnv() | ||
|
|
||
| var resolved = null | ||
| var tmp | ||
|
|
||
| exec(git, archive, {cwd: p, env: env}, function (er, stdout, stderr) { | ||
| stdout = (stdout + "\n" + stderr).trim() | ||
| if (er) { | ||
| log.error("git fetch -a origin ("+u+")", stdout) | ||
| return cb(er) | ||
| } | ||
| log.verbose("git fetch -a origin ("+u+")", stdout) | ||
| tmp = path.join(npm.tmp, Date.now()+"-"+Math.random(), "tmp.tgz") | ||
| verifyOwnership() | ||
| }) | ||
|
|
||
| function verifyOwnership() { | ||
| if (process.platform === "win32") { | ||
| log.silly("verifyOwnership", "skipping for windows") | ||
| resolveHead() | ||
| } else { | ||
| getCacheStat(function(er, cs) { | ||
| if (er) { | ||
| log.error("Could not get cache stat") | ||
| return cb(er) | ||
| } | ||
| chownr(p, cs.uid, cs.gid, function(er) { | ||
| if (er) { | ||
| log.error("Failed to change folder ownership under npm cache for %s", p) | ||
| return cb(er) | ||
| } | ||
| resolveHead() | ||
| }) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| function resolveHead () { | ||
| exec(git, resolve, {cwd: p, env: env}, function (er, stdout, stderr) { | ||
| stdout = (stdout + "\n" + stderr).trim() | ||
| if (er) { | ||
| log.error("Failed resolving git HEAD (" + u + ")", stderr) | ||
| return cb(er) | ||
| } | ||
| log.verbose("git rev-list -n1 " + co, stdout) | ||
| var parsed = url.parse(origUrl) | ||
| parsed.hash = stdout | ||
| resolved = url.format(parsed) | ||
|
|
||
| // https://github.com/npm/npm/issues/3224 | ||
| // node incorrectly sticks a / at the start of the path | ||
| // We know that the host won't change, so split and detect this | ||
| var spo = origUrl.split(parsed.host) | ||
| var spr = resolved.split(parsed.host) | ||
| if (spo[1].charAt(0) === ':' && spr[1].charAt(0) === '/') | ||
| spr[1] = spr[1].slice(1) | ||
| resolved = spr.join(parsed.host) | ||
|
|
||
| log.verbose('resolved git url', resolved) | ||
| next() | ||
| }) | ||
| } | ||
|
|
||
| function next () { | ||
| mkdir(path.dirname(tmp), function (er) { | ||
| if (er) return cb(er) | ||
| var gzip = zlib.createGzip({ level: 9 }) | ||
| var git = npm.config.get("git") | ||
| var args = ["archive", co, "--format=tar", "--prefix=package/"] | ||
| var out = fs.createWriteStream(tmp) | ||
| var env = gitEnv() | ||
| cb = once(cb) | ||
| var cp = spawn(git, args, { env: env, cwd: p }) | ||
| cp.on("error", cb) | ||
| cp.stderr.on("data", function(chunk) { | ||
| log.silly(chunk.toString(), "git archive") | ||
| }) | ||
|
|
||
| cp.stdout.pipe(gzip).pipe(out).on("close", function() { | ||
| addLocalTarball(tmp, null, null, function(er, data) { | ||
| if (data) data._resolved = resolved | ||
| cb(er, data) | ||
| }) | ||
| }) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| var gitEnv_ | ||
| function gitEnv () { | ||
| // git responds to env vars in some weird ways in post-receive hooks | ||
| // so don't carry those along. | ||
| if (gitEnv_) return gitEnv_ | ||
| gitEnv_ = {} | ||
| for (var k in process.env) { | ||
| if (!~['GIT_PROXY_COMMAND','GIT_SSH','GIT_SSL_NO_VERIFY'].indexOf(k) && k.match(/^GIT/)) continue | ||
| gitEnv_[k] = process.env[k] | ||
| } | ||
| return gitEnv_ | ||
| } |
| @@ -0,0 +1,106 @@ | ||
| var mkdir = require("mkdirp") | ||
| , assert = require("assert") | ||
| , log = require("npmlog") | ||
| , path = require("path") | ||
| , sha = require("sha") | ||
| , retry = require("retry") | ||
| , npm = require("../npm.js") | ||
| , fetch = require("../utils/fetch.js") | ||
| , inflight = require("inflight") | ||
| , locker = require("../utils/locker.js") | ||
| , lock = locker.lock | ||
| , unlock = locker.unlock | ||
| , addLocalTarball = require("./add-local-tarball.js") | ||
| , cacheFile = require("npm-cache-filename") | ||
|
|
||
| module.exports = addRemoteTarball | ||
|
|
||
| function addRemoteTarball (u, pkgData, shasum, cb_) { | ||
| assert(typeof u === "string", "must have module URL") | ||
| assert(typeof cb_ === "function", "must have callback") | ||
|
|
||
| function cb (er, data) { | ||
| if (data) { | ||
| data._from = u | ||
| data._shasum = data._shasum || shasum | ||
| data._resolved = u | ||
| } | ||
| unlock(u, function () { | ||
| cb_(er, data) | ||
| }) | ||
| } | ||
|
|
||
| cb_ = inflight(u, cb_) | ||
|
|
||
| if (!cb_) return | ||
|
|
||
| // XXX Fetch direct to cache location, store tarballs under | ||
| // ${cache}/registry.npmjs.org/pkg/-/pkg-1.2.3.tgz | ||
| var tmp = cacheFile(npm.tmp, u) | ||
|
|
||
| function next (er, resp, shasum) { | ||
| if (er) return cb(er) | ||
| addLocalTarball(tmp, pkgData, shasum, cb) | ||
| } | ||
|
|
||
| lock(u, function (er) { | ||
| if (er) return cb(er) | ||
|
|
||
| log.verbose("addRemoteTarball", [u, shasum]) | ||
| mkdir(path.dirname(tmp), function (er) { | ||
| if (er) return cb(er) | ||
| addRemoteTarball_(u, tmp, shasum, next) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| function addRemoteTarball_(u, tmp, shasum, cb) { | ||
| // Tuned to spread 3 attempts over about a minute. | ||
| // See formula at <https://github.com/tim-kos/node-retry>. | ||
| var operation = retry.operation | ||
| ( { retries: npm.config.get("fetch-retries") | ||
| , factor: npm.config.get("fetch-retry-factor") | ||
| , minTimeout: npm.config.get("fetch-retry-mintimeout") | ||
| , maxTimeout: npm.config.get("fetch-retry-maxtimeout") }) | ||
|
|
||
| operation.attempt(function (currentAttempt) { | ||
| log.info("retry", "fetch attempt " + currentAttempt | ||
| + " at " + (new Date()).toLocaleTimeString()) | ||
| fetchAndShaCheck(u, tmp, shasum, function (er, response, shasum) { | ||
| // Only retry on 408, 5xx or no `response`. | ||
| var sc = response && response.statusCode | ||
| var statusRetry = !sc || (sc === 408 || sc >= 500) | ||
| if (er && statusRetry && operation.retry(er)) { | ||
| log.info("retry", "will retry, error on last attempt: " + er) | ||
| return | ||
| } | ||
| cb(er, response, shasum) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| function fetchAndShaCheck (u, tmp, shasum, cb) { | ||
| fetch(u, tmp, function (er, response) { | ||
| if (er) { | ||
| log.error("fetch failed", u) | ||
| return cb(er, response) | ||
| } | ||
|
|
||
| if (!shasum) { | ||
| // Well, we weren't given a shasum, so at least sha what we have | ||
| // in case we want to compare it to something else later | ||
| return sha.get(tmp, function (er, shasum) { | ||
| cb(er, response, shasum) | ||
| }) | ||
| } | ||
|
|
||
| // validate that the url we just downloaded matches the expected shasum. | ||
| sha.check(tmp, shasum, function (er) { | ||
| if (er && er.message) { | ||
| // add original filename for better debuggability | ||
| er.message = er.message + '\n' + 'From: ' + u | ||
| } | ||
| return cb(er, response, shasum) | ||
| }) | ||
| }) | ||
| } |
| @@ -0,0 +1,63 @@ | ||
| var mkdir = require("mkdirp") | ||
| , fs = require("graceful-fs") | ||
| , log = require("npmlog") | ||
| , chownr = require("chownr") | ||
| , npm = require("../npm.js") | ||
| , inflight = require("inflight") | ||
|
|
||
| // to maintain the cache dir's permissions consistently. | ||
| var cacheStat = null | ||
| module.exports = function getCacheStat (cb) { | ||
| if (cacheStat) return cb(null, cacheStat) | ||
|
|
||
| cb = inflight("getCacheStat", cb) | ||
| if (!cb) return | ||
|
|
||
| fs.stat(npm.cache, function (er, st) { | ||
| if (er) return makeCacheDir(cb) | ||
| if (!st.isDirectory()) { | ||
| log.error("getCacheStat", "invalid cache dir %j", npm.cache) | ||
| return cb(er) | ||
| } | ||
| return cb(null, cacheStat = st) | ||
| }) | ||
| } | ||
|
|
||
| function makeCacheDir (cb) { | ||
| if (!process.getuid) return mkdir(npm.cache, cb) | ||
|
|
||
| var uid = +process.getuid() | ||
| , gid = +process.getgid() | ||
|
|
||
| if (uid === 0) { | ||
| if (process.env.SUDO_UID) uid = +process.env.SUDO_UID | ||
| if (process.env.SUDO_GID) gid = +process.env.SUDO_GID | ||
| } | ||
| if (uid !== 0 || !process.env.HOME) { | ||
| cacheStat = {uid: uid, gid: gid} | ||
| return mkdir(npm.cache, afterMkdir) | ||
| } | ||
|
|
||
| fs.stat(process.env.HOME, function (er, st) { | ||
| if (er) { | ||
| log.error("makeCacheDir", "homeless?") | ||
| return cb(er) | ||
| } | ||
| cacheStat = st | ||
| log.silly("makeCacheDir", "cache dir uid, gid", [st.uid, st.gid]) | ||
| return mkdir(npm.cache, afterMkdir) | ||
| }) | ||
|
|
||
| function afterMkdir (er, made) { | ||
| if (er || !cacheStat || isNaN(cacheStat.uid) || isNaN(cacheStat.gid)) { | ||
| return cb(er, cacheStat) | ||
| } | ||
|
|
||
| if (!made) return cb(er, cacheStat) | ||
|
|
||
| // ensure that the ownership is correct. | ||
| chownr(made, cacheStat.uid, cacheStat.gid, function (er) { | ||
| return cb(er, cacheStat) | ||
| }) | ||
| } | ||
| } |
| @@ -0,0 +1,35 @@ | ||
| var url = require("url") | ||
| , assert = require("assert") | ||
| , log = require("npmlog") | ||
| , addRemoteGit = require("./add-remote-git.js") | ||
|
|
||
| module.exports = function maybeGithub (p, er, cb) { | ||
| assert(typeof p === "string", "must pass package name") | ||
| assert(er instanceof Error, "must include error") | ||
| assert(typeof cb === "function", "must pass callback") | ||
|
|
||
| var u = "git://github.com/" + p | ||
| , up = url.parse(u) | ||
| log.info("maybeGithub", "Attempting %s from %s", p, u) | ||
|
|
||
| return addRemoteGit(u, up, true, function (er2, data) { | ||
| if (er2) { | ||
| var upriv = "git+ssh://git@github.com:" + p | ||
| , uppriv = url.parse(upriv) | ||
|
|
||
| log.info("maybeGithub", "Attempting %s from %s", p, upriv) | ||
|
|
||
| return addRemoteGit(upriv, uppriv, false, function (er3, data) { | ||
| if (er3) return cb(er) | ||
| success(upriv, data) | ||
| }) | ||
| } | ||
| success(u, data) | ||
| }) | ||
|
|
||
| function success (u, data) { | ||
| data._from = u | ||
| data._fromGithub = true | ||
| return cb(null, data) | ||
| } | ||
| } |
| @@ -15,6 +15,7 @@ var fs = require("graceful-fs") | ||
| , glob = require("glob") | ||
|
|
||
| function help (args, cb) { | ||
| npm.spinner.stop() | ||
| var argv = npm.config.get("argv").cooked | ||
|
|
||
| var argnum = 0 | ||
| @@ -0,0 +1,13 @@ | ||
| var log = require("npmlog") | ||
|
|
||
| var deprecated = {} | ||
| , deprWarned = {} | ||
| module.exports = function deprCheck (data) { | ||
| if (deprecated[data._id]) data.deprecated = deprecated[data._id] | ||
| if (data.deprecated) deprecated[data._id] = data.deprecated | ||
| else return | ||
| if (!deprWarned[data._id]) { | ||
| deprWarned[data._id] = true | ||
| log.warn("deprecated", "%s: %s", data._id, data.deprecated) | ||
| } | ||
| } |
| @@ -0,0 +1,52 @@ | ||
| var crypto = require("crypto") | ||
| var path = require("path") | ||
|
|
||
| var npm = require("../npm.js") | ||
| var lockFile = require("lockfile") | ||
| var log = require("npmlog") | ||
| var getCacheStat = require("../cache/get-stat.js") | ||
|
|
||
| function lockFileName (u) { | ||
| var c = u.replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "") | ||
| , h = crypto.createHash("sha1").update(u).digest("hex") | ||
| h = h.substr(0, 8) | ||
| c = c.substr(-32) | ||
| log.silly("lockFile", h + "-" + c, u) | ||
| return path.resolve(npm.config.get("cache"), h + "-" + c + ".lock") | ||
| } | ||
|
|
||
| var myLocks = {} | ||
| function lock (u, cb) { | ||
| // the cache dir needs to exist already for this. | ||
| getCacheStat(function (er, cs) { | ||
| if (er) return cb(er) | ||
| var opts = { stale: npm.config.get("cache-lock-stale") | ||
| , retries: npm.config.get("cache-lock-retries") | ||
| , wait: npm.config.get("cache-lock-wait") } | ||
| var lf = lockFileName(u) | ||
| log.verbose("lock", u, lf) | ||
| lockFile.lock(lf, opts, function(er) { | ||
| if (!er) myLocks[lf] = true | ||
| cb(er) | ||
| }) | ||
| }) | ||
| } | ||
|
|
||
| function unlock (u, cb) { | ||
| var lf = lockFileName(u) | ||
| , locked = myLocks[lf] | ||
| if (locked === false) { | ||
| return process.nextTick(cb) | ||
| } else if (locked === true) { | ||
| myLocks[lf] = false | ||
| lockFile.unlock(lockFileName(u), cb) | ||
| } else { | ||
| throw new Error("Attempt to unlock " + u + ", which hasn't been locked") | ||
| } | ||
| } | ||
|
|
||
| module.exports = { | ||
| lock: lock, | ||
| unlock: unlock, | ||
| _lockFileName: lockFileName | ||
| } |
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-ADDUSER" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-adduser\fR \-\- Add a registry user account | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-BIN" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-bin\fR \-\- Display npm bin folder | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-BUILD" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-build\fR \-\- Build a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-BUNDLE" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-bundle\fR \-\- REMOVED | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-COMPLETION" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-completion\fR \-\- Tab Completion for npm | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-CONFIG" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-config\fR \-\- Manage the npm configuration files | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-DEDUPE" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-dedupe\fR \-\- Reduce duplication | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-EDIT" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-edit\fR \-\- Edit an installed package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-EXPLORE" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-explore\fR \-\- Browse an installed package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-HELP" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-help\fR \-\- Get help on npm | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-INSTALL" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-install\fR \-\- Install a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-LINK" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-link\fR \-\- Symlink a package folder | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-OUTDATED" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-outdated\fR \-\- Check for outdated packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-OWNER" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-owner\fR \-\- Manage package owners | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PACK" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-pack\fR \-\- Create a tarball from a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PREFIX" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-prefix\fR \-\- Display prefix | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PRUNE" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-prune\fR \-\- Remove extraneous packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PUBLISH" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-publish\fR \-\- Publish a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-REBUILD" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-rebuild\fR \-\- Rebuild a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-RESTART" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-restart\fR \-\- Start a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-RM" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-rm\fR \-\- Remove a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-ROOT" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-root\fR \-\- Display npm root | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-SEARCH" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-search\fR \-\- Search for packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-STAR" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-star\fR \-\- Mark your favorite packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-STARS" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-stars\fR \-\- View packages marked as favorites | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-START" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-start\fR \-\- Start a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-STOP" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-stop\fR \-\- Stop a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-TAG" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-tag\fR \-\- Tag a published version | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-TEST" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-test\fR \-\- Test a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-RM" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-rm\fR \-\- Remove a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-UPDATE" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-update\fR \-\- Update a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-VERSION" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-version\fR \-\- Bump a package version | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-VIEW" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-view\fR \-\- View registry info | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-WHOAMI" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-whoami\fR \-\- Display npm username | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-BIN" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-bin\fR \-\- Display npm bin folder | ||
| @@ -0,0 +1,40 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-CACHE" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-cache\fR \-\- manage the npm cache programmatically | ||
| . | ||
| .SH "SYNOPSIS" | ||
| . | ||
| .nf | ||
| npm\.commands\.cache([args], callback) | ||
| // helpers | ||
| npm\.commands\.cache\.clean([args], callback) | ||
| npm\.commands\.cache\.add([args], callback) | ||
| npm\.commands\.cache\.read(name, version, forceBypass, callback) | ||
| . | ||
| .fi | ||
| . | ||
| .SH "DESCRIPTION" | ||
| npm help This acts much the same ways as the npm\-cache command line | ||
| functionality\. | ||
| . | ||
| .P | ||
| The callback is called with the package\.json data of the thing that is | ||
| eventually added to or read from the cache\. | ||
| . | ||
| .P | ||
| The top level \fBnpm\.commands\.cache(\.\.\.)\fR functionality is a public | ||
| interface, and like all commands on the \fBnpm\.commands\fR object, it will | ||
| match the command line behavior exactly\. | ||
| . | ||
| .P | ||
| However, the cache folder structure and the cache helper functions are | ||
| considered \fBinternal\fR API surface, and as such, may change in future | ||
| releases of npm, potentially without warning or significant version | ||
| incrementation\. | ||
| . | ||
| .P | ||
| Use at your own risk\. |
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-COMMANDS" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-commands\fR \-\- npm commands | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-CONFIG" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-config\fR \-\- Manage the npm configuration files | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-EDIT" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-edit\fR \-\- Edit an installed package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-EXPLORE" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-explore\fR \-\- Browse an installed package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-HELP\-SEARCH" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-help-search\fR \-\- Search the help pages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "INIT" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBinit\fR \-\- Interactively create a package\.json file | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-INSTALL" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-install\fR \-\- install a package programmatically | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-LINK" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-link\fR \-\- Symlink a package folder | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-LOAD" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-load\fR \-\- Load config settings | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-LS" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-ls\fR \-\- List installed packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-OUTDATED" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-outdated\fR \-\- Check for outdated packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-OWNER" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-owner\fR \-\- Manage package owners | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PACK" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-pack\fR \-\- Create a tarball from a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PREFIX" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-prefix\fR \-\- Display prefix | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PRUNE" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-prune\fR \-\- Remove extraneous packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-PUBLISH" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-publish\fR \-\- Publish a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-REBUILD" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-rebuild\fR \-\- Rebuild a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-RESTART" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-restart\fR \-\- Start a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-ROOT" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-root\fR \-\- Display npm root | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-SEARCH" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-search\fR \-\- Search for packages | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-START" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-start\fR \-\- Start a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-STOP" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-stop\fR \-\- Stop a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-TAG" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-tag\fR \-\- Tag a published version | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-TEST" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-test\fR \-\- Test a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-UPDATE" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-update\fR \-\- Update a package | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-VERSION" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-version\fR \-\- Bump a package version | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-VIEW" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-view\fR \-\- View registry info | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-WHOAMI" "3" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-whoami\fR \-\- Display npm username | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-FOLDERS" "5" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-folders\fR \-\- Folder Structures Used by npm | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-FOLDERS" "5" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-folders\fR \-\- Folder Structures Used by npm | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-DEVELOPERS" "7" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-developers\fR \-\- Developer Guide | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-DISPUTES" "7" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-disputes\fR \-\- Handling Module Name Disputes | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-REGISTRY" "7" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-registry\fR \-\- The JavaScript Package Registry | ||
| @@ -1,7 +1,7 @@ | ||
| .\" Generated with Ronnjs 0.3.8 | ||
| .\" http://github.com/kapouer/ronnjs/ | ||
| . | ||
| .TH "NPM\-REMOVAL" "1" "June 2014" "" "" | ||
| . | ||
| .SH "NAME" | ||
| \fBnpm-removal\fR \-\- Cleaning the Slate | ||