diff options
author | Forrest L Norvell <forrest@npmjs.com> | 2014-06-18 11:19:39 +0400 |
---|---|---|
committer | Forrest L Norvell <forrest@npmjs.com> | 2014-07-02 05:43:16 +0400 |
commit | 0689ba249b92b4c6279a26804c96af6f92b3a501 (patch) | |
tree | c1d56154d44ee0f25eefbd0bdc5c8c4413007721 /lib | |
parent | 4441ea1ca17c584a12c266beacf4f9a77d763dfc (diff) |
use --scope to map scope to registry
Diffstat (limited to 'lib')
-rw-r--r-- | lib/adduser.js | 40 | ||||
-rw-r--r-- | lib/bugs.js | 21 | ||||
-rw-r--r-- | lib/cache.js | 32 | ||||
-rw-r--r-- | lib/cache/add-named.js | 98 | ||||
-rw-r--r-- | lib/dedupe.js | 16 | ||||
-rw-r--r-- | lib/deprecate.js | 34 | ||||
-rw-r--r-- | lib/docs.js | 24 | ||||
-rw-r--r-- | lib/install.js | 70 | ||||
-rw-r--r-- | lib/outdated.js | 13 | ||||
-rw-r--r-- | lib/owner.js | 150 | ||||
-rw-r--r-- | lib/publish.js | 71 | ||||
-rw-r--r-- | lib/repo.js | 27 | ||||
-rw-r--r-- | lib/search.js | 13 | ||||
-rw-r--r-- | lib/star.js | 30 | ||||
-rw-r--r-- | lib/stars.js | 11 | ||||
-rw-r--r-- | lib/tag.js | 11 | ||||
-rw-r--r-- | lib/unpublish.js | 60 | ||||
-rw-r--r-- | lib/utils/is-organized.js | 5 | ||||
-rw-r--r-- | lib/utils/is-scoped.js | 16 | ||||
-rw-r--r-- | lib/utils/map-name-to-registry.js | 28 | ||||
-rw-r--r-- | lib/utils/map-to-registry.js | 51 | ||||
-rw-r--r-- | lib/view.js | 108 |
22 files changed, 554 insertions, 375 deletions
diff --git a/lib/adduser.js b/lib/adduser.js index 8315809c5..23c073ae7 100644 --- a/lib/adduser.js +++ b/lib/adduser.js @@ -95,7 +95,7 @@ function readPassword (c, u, cb) { return readPassword(c, u, cb) } - c.changed = c.changed || c.p != pw + c.changed = c.changed || c.p !== pw u.p = pw cb(er) }) @@ -133,24 +133,48 @@ function save (c, u, cb) { registry.password = u.p } npm.spinner.start() + // save existing configs, but yank off for this PUT - var uri = npm.config.get("registry") + var uri = npm.config.get("registry") + var scope = npm.config.get("scope") + + // there may be a saved scope and no --registry (for login) + if (scope) { + if (scope.charAt(0) !== "@") scope = "@" + scope + + var scopedRegistry = npm.config.get(scope + ":registry") + if (scopedRegistry) uri = scopedRegistry + } + registry.adduser(uri, u.u, u.p, u.e, function (er, doc) { npm.spinner.stop() if (er) return cb(er) + registry.username = u.u registry.password = u.p registry.email = u.e + // don't want this polluting the configuration npm.config.del("_token", "user") - npm.config.set("username", u.u, "user") - npm.config.set("_password", u.p, "user") + + if (scope) { + npm.config.set(scope + ":registry", uri, "user") + } + + var munged = url.parse(uri) + delete munged.protocol + // 'nerf dart' courtesy jennmoneydollaz + var nerfDart = url.format(munged) + if (doc && doc.token) { - var munged = url.parse(uri) - delete munged.protocol - npm.config.set(url.format(munged) + ":_authToken", doc.token, "user") + npm.config.set(nerfDart + ":_authToken", doc.token, "user") } - npm.config.set("email", u.e, "user") + + var auth = u.u + ":" + u.p + var quasiSecret = new Buffer(auth, "utf8").toString("base64") + npm.config.set(nerfDart + ":_auth", quasiSecret, "user") + npm.config.set(nerfDart + ":email", u.e, "user") + log.info("adduser", "Authorized user %s", u.u) npm.config.save("user", cb) }) diff --git a/lib/bugs.js b/lib/bugs.js index b3022bf2a..41f1386b0 100644 --- a/lib/bugs.js +++ b/lib/bugs.js @@ -10,13 +10,16 @@ var npm = require("./npm.js") , path = require("path") , readJson = require("read-package-json") , fs = require("fs") - , url = require("url") + , mapToRegistry = require("./utils/map-to-registry.js") bugs.completion = function (opts, cb) { if (opts.conf.argv.remain.length > 2) return cb() - var uri = url.resolve(npm.config.get("registry"), "-/short") - registry.get(uri, { timeout : 60000 }, function (er, list) { - return cb(null, list || []) + mapToRegistry("-/short", npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, { timeout : 60000 }, function (er, list) { + return cb(null, list || []) + }) }) } @@ -56,9 +59,13 @@ function getUrlAndOpen (d, cb) { } function callRegistry (n, cb) { - var uri = url.resolve(npm.config.get("registry"), n + "/latest") - registry.get(uri, { timeout : 3600 }, function (er, d) { + mapToRegistry(n, npm.config, function (er, uri) { if (er) return cb(er) - getUrlAndOpen (d, cb) + + registry.get(uri + "/latest", { timeout : 3600 }, function (er, d) { + if (er) return cb(er) + + getUrlAndOpen (d, cb) + }) }) } diff --git a/lib/cache.js b/lib/cache.js index 01b7d4cba..063cbe38b 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -343,22 +343,30 @@ function maybeFile (spec, cb) { fs.stat(spec, function (er) { if (!er) { // definitely a local thing + log.verbose("maybeFile", "statted local spec", spec) return addLocal(spec, {}, cb) } - maybeAt(spec, cb) - }) -} + var pivot + // scoped modules might have @ as first character + if (spec.charAt(0) === "@") { + pivot = spec.slice(1).indexOf("@") + 1 + } + else { + pivot = spec.indexOf("@") + } -function maybeAt (spec, cb) { - // scoped modules might have @ as first character - var pivot = spec.lastIndexOf("@") - if (pivot > 0) { - add([spec.slice(0, pivot), spec.slice(pivot + 1)], cb) - } else { - // already know it's not a url, so must be local - addLocal(spec, {}, cb) - } + if (pivot > 0) { + var name = spec.slice(0, pivot) + spec = spec.slice(pivot + 1) + log.verbose("maybeFile", "name=%s, spec=%s", name, spec) + add([name, spec], cb) + } else { + // already know it's not a url, so must be local + log.verbose("maybeFile", "found local spec", spec) + addLocal(spec, {}, cb) + } + }) } function needName(er, data) { diff --git a/lib/cache/add-named.js b/lib/cache/add-named.js index f8c09aa03..e595db228 100644 --- a/lib/cache/add-named.js +++ b/lib/cache/add-named.js @@ -15,7 +15,7 @@ var path = require("path") , unlock = locker.unlock , maybeGithub = require("./maybe-github.js") , addRemoteTarball = require("./add-remote-tarball.js") - , mapNameToRegistry = require("../utils/map-name-to-registry.js") + , mapToRegistry = require("../utils/map-to-registry.js") module.exports = addNamed @@ -57,6 +57,12 @@ function addNameTag (name, tag, data, cb_) { tag = npm.config.get("tag") } + mapToRegistry(name, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, next) + }) + function cb(er, data) { // might be username/project // in that case, try it as a github url. @@ -66,28 +72,24 @@ function addNameTag (name, tag, data, cb_) { return cb_(er, data) } - mapNameToRegistry(name, npm.config, function (er, uri) { + function next (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) + } - registry.get(uri, null, 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) - }) - }) + er = installTargetsError(tag, data) + return cb(er) + } } function engineFilter (data) { @@ -119,26 +121,28 @@ function addNameVersion (name, v, data, cb) { return next() } - mapNameToRegistry(name, npm.config, function (er, uri) { + mapToRegistry(name, npm.config, function (er, uri) { if (er) return cb(er) - registry.get(uri, null, 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() - }) + registry.get(uri, null, setData) }) + function setData (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 @@ -205,19 +209,21 @@ function addNameRange (name, range, data, cb) { if (data) return next() - mapNameToRegistry(name, npm.config, function (er, uri) { + mapToRegistry(name, npm.config, function (er, uri) { if (er) return cb(er) - registry.get(uri, null, function (er, d, json, resp) { - if (!er) { - er = errorResponse(name, resp) - } - if (er) return cb(er) - data = d - next() - }) + registry.get(uri, null, setData) }) + function setData (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}) diff --git a/lib/dedupe.js b/lib/dedupe.js index e6762e15b..70a63a3ab 100644 --- a/lib/dedupe.js +++ b/lib/dedupe.js @@ -7,7 +7,6 @@ // much better "put pkg X at folder Y" abstraction. Oh well, // whatever. Perfect enemy of the good, and all that. -var url = require("url") var fs = require("fs") var asyncMap = require("slide").asyncMap var path = require("path") @@ -16,6 +15,7 @@ var semver = require("semver") var rm = require("./utils/gently-rm.js") var log = require("npmlog") var npm = require("./npm.js") +var mapToRegistry = require("./utils/map-to-registry.js") module.exports = dedupe @@ -240,13 +240,19 @@ function findVersions (npm, summary, cb) { var versions = data.versions var ranges = data.ranges - var uri = url.resolve(npm.config.get("registry"), name) - npm.registry.get(uri, null, function (er, data) { + mapToRegistry(name, npm.config, function (er, uri) { + if (er) return cb(er) + + npm.registry.get(uri, null, next) + }) + + function next (er, data) { var regVersions = er ? [] : Object.keys(data.versions) var locMatch = bestMatch(versions, ranges) - var regMatch; var tag = npm.config.get("tag") var distTag = data["dist-tags"] && data["dist-tags"][tag] + + var regMatch if (distTag && data.versions[distTag] && matches(distTag, ranges)) { regMatch = distTag } else { @@ -254,7 +260,7 @@ function findVersions (npm, summary, cb) { } cb(null, [[name, has, loc, locMatch, regMatch, locs]]) - }) + } }, cb) } diff --git a/lib/deprecate.js b/lib/deprecate.js index 175b69ceb..17c029f92 100644 --- a/lib/deprecate.js +++ b/lib/deprecate.js @@ -1,5 +1,5 @@ -var url = require("url") - , npm = require("./npm.js") +var npm = require("./npm.js") + , mapToRegistry = require("./utils/map-to-registry.js") module.exports = deprecate @@ -13,11 +13,14 @@ deprecate.completion = function (opts, cb) { if (opts.conf.argv.remain.length > 2) return cb() // get the list of packages by user var path = "/-/by-user/"+encodeURIComponent(un) - , uri = url.resolve(npm.config.get("registry"), path) - npm.registry.get(uri, { timeout : 60000 }, function (er, list) { - if (er) return cb() - console.error(list) - return cb(null, list[un]) + mapToRegistry(path, npm.config, function (er, uri) { + if (er) return cb(er) + + npm.registry.get(uri, { timeout : 60000 }, function (er, list) { + if (er) return cb() + console.error(list) + return cb(null, list[un]) + }) }) } @@ -25,11 +28,18 @@ function deprecate (args, cb) { var pkg = args[0] , msg = args[1] if (msg === undefined) return cb("Usage: " + deprecate.usage) + // fetch the data and make sure it exists. - pkg = pkg.split(/@/) - var name = pkg.shift() - , ver = pkg.join("@") - , uri = url.resolve(npm.config.get("registry"), name) + var pivot = pkg.lastIndexOf("@") + if (pivot === 0) pivot = pkg.length + var name = pkg.substr(0, pivot) + , ver = pkg.substr(pivot + 1) + + mapToRegistry(name, npm.config, next) + + function next (er, uri) { + if (er) return cb(er) - npm.registry.deprecate(uri, ver, msg, cb) + npm.registry.deprecate(uri, ver, msg, cb) + } } diff --git a/lib/docs.js b/lib/docs.js index 77073fbb9..2c59b2672 100644 --- a/lib/docs.js +++ b/lib/docs.js @@ -5,18 +5,21 @@ docs.usage += "\n" docs.usage += "npm docs ." docs.completion = function (opts, cb) { - var uri = url_.resolve(npm.config.get("registry"), "/-/short") - registry.get(uri, { timeout : 60000 }, function (er, list) { - return cb(null, list || []) + mapToRegistry("/-/short", npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, { timeout : 60000 }, function (er, list) { + return cb(null, list || []) + }) }) } -var url_ = require("url") - , npm = require("./npm.js") +var npm = require("./npm.js") , registry = npm.registry , opener = require("opener") , path = require("path") , log = require("npmlog") + , mapToRegistry = require("./utils/map-to-registry.js") function url (json) { return json.homepage ? json.homepage : "https://npmjs.org/package/" + json.name @@ -54,8 +57,13 @@ function getDoc (project, cb) { return opener(url(json), { command: npm.config.get("browser") }, cb) } - var uri = url_.resolve(npm.config.get("registry"), project + "/latest") - registry.get(uri, { timeout : 3600 }, function (er, json) { + mapToRegistry(project, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri + "/latest", { timeout : 3600 }, next) + }) + + function next (er, json) { var github = "https://github.com/" + project + "#readme" if (er) { @@ -64,5 +72,5 @@ function getDoc (project, cb) { } return opener(url(json), { command: npm.config.get("browser") }, cb) - }) + } } diff --git a/lib/install.js b/lib/install.js index 8f20bc839..6d07a8294 100644 --- a/lib/install.js +++ b/lib/install.js @@ -34,28 +34,34 @@ install.completion = function (opts, cb) { // if it starts with https?://, then just give up, because it's a url // for now, not yet implemented. var registry = npm.registry - , uri = url.resolve(npm.config.get("registry"), "-/short") - registry.get(uri, null, function (er, pkgs) { - if (er) return cb() - if (!opts.partialWord) return cb(null, pkgs) + mapToRegistry("-/short", npm.config, function (er, uri) { + if (er) return cb(er) - var name = opts.partialWord.split("@").shift() - pkgs = pkgs.filter(function (p) { - return p.indexOf(name) === 0 - }) + registry.get(uri, null, function (er, pkgs) { + if (er) return cb() + if (!opts.partialWord) return cb(null, pkgs) - if (pkgs.length !== 1 && opts.partialWord === name) { - return cb(null, pkgs) - } + var name = opts.partialWord.split("@").shift() + pkgs = pkgs.filter(function (p) { + return p.indexOf(name) === 0 + }) - uri = url.resolve(npm.config.get("registry"), pkgs[0]) - registry.get(uri, null, function (er, d) { - if (er) return cb() - return cb(null, Object.keys(d["dist-tags"] || {}) - .concat(Object.keys(d.versions || {})) - .map(function (t) { - return pkgs[0] + "@" + t - })) + if (pkgs.length !== 1 && opts.partialWord === name) { + return cb(null, pkgs) + } + + mapToRegistry(pkgs[0], npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, function (er, d) { + if (er) return cb() + return cb(null, Object.keys(d["dist-tags"] || {}) + .concat(Object.keys(d.versions || {})) + .map(function (t) { + return pkgs[0] + "@" + t + })) + }) + }) }) }) } @@ -77,6 +83,7 @@ var npm = require("./npm.js") , isGitUrl = require("./utils/is-git-url.js") , npmInstallChecks = require("npm-install-checks") , sortedObject = require("sorted-object") + , mapToRegistry = require("./utils/map-to-registry.js") function install (args, cb_) { var hasArguments = !!args.length @@ -412,12 +419,12 @@ function save (where, installed, tree, pretty, hasArguments, cb) { // that the submodules are not immediately require()able. // TODO: Show the complete tree, ls-style, but only if --long is provided function prettify (tree, installed) { - if (npm.config.get("json")) { - function red (set, kv) { - set[kv[0]] = kv[1] - return set - } + function red (set, kv) { + set[kv[0]] = kv[1] + return set + } + if (npm.config.get("json")) { tree = Object.keys(tree).map(function (p) { if (!tree[p]) return null var what = tree[p].what.split("@") @@ -771,6 +778,13 @@ function localLink (target, where, context, cb) { , parent = context.parent readJson(jsonFile, log.warn, function (er, data) { + function thenLink () { + npm.commands.link([target.name], function (er, d) { + log.silly("localLink", "back from link", [er, d]) + cb(er, [resultList(target, where, parent && parent._id)]) + }) + } + if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er) if (er || data._id === target._id) { if (er) { @@ -781,14 +795,6 @@ function localLink (target, where, context, cb) { thenLink() }) } else thenLink() - - function thenLink () { - npm.commands.link([target.name], function (er, d) { - log.silly("localLink", "back from link", [er, d]) - cb(er, [resultList(target, where, parent && parent._id)]) - }) - } - } else { log.verbose("localLink", "install locally (no link)", target._id) installOne_(target, where, context, cb) diff --git a/lib/outdated.js b/lib/outdated.js index b29ea9fe6..bfed369ba 100644 --- a/lib/outdated.js +++ b/lib/outdated.js @@ -34,6 +34,7 @@ var path = require("path") , table = require("text-table") , semver = require("semver") , os = require("os") + , mapToRegistry = require("./utils/map-to-registry.js") function outdated (args, silent, cb) { if (typeof cb !== "function") cb = silent, silent = false @@ -268,8 +269,13 @@ function shouldUpdate (args, dir, dep, has, req, depth, cb) { return doIt("git", "git") // search for the latest package - var uri = url.resolve(npm.config.get("registry"), dep) - npm.registry.get(uri, null, function (er, d) { + mapToRegistry(dep, npm.config, function (er, uri) { + if (er) return cb(er) + + npm.registry.get(uri, null, updateDeps) + }) + + function updateDeps (er, d) { if (er) return cb() if (!d || !d['dist-tags'] || !d.versions) return cb() var l = d.versions[d['dist-tags'].latest] @@ -315,6 +321,5 @@ function shouldUpdate (args, dir, dep, has, req, depth, cb) { else skip() } - - }) + } } diff --git a/lib/owner.js b/lib/owner.js index 34dbbc247..1f9d79b25 100644 --- a/lib/owner.js +++ b/lib/owner.js @@ -15,51 +15,65 @@ owner.completion = function (opts, cb) { return cb(null, subs) } var un = encodeURIComponent(npm.config.get("username")) - var theUser, uri + var byUser, theUser switch (argv[2]) { case "ls": if (argv.length > 3) return cb() - uri = url.resolve(npm.config.get("registry"), "-/short") - return registry.get(uri, null, cb) + return mapToRegistry("-/short", npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, cb) + }) case "rm": if (argv.length > 3) { theUser = encodeURIComponent(argv[3]) - uri = url.resolve(npm.config.get("registry"), "-/by-user/"+theUser+"|"+un) - console.error(uri) - return registry.get(uri, null, function (er, d) { + byUser = "-/by-user/" + theUser + "|" + un + return mapToRegistry(byUser, npm.config, function (er, uri) { if (er) return cb(er) - // return the intersection - return cb(null, d[theUser].filter(function (p) { - // kludge for server adminery. - return un === "isaacs" || d[un].indexOf(p) === -1 - })) + + console.error(uri) + registry.get(uri, null, function (er, d) { + if (er) return cb(er) + // return the intersection + return cb(null, d[theUser].filter(function (p) { + // kludge for server adminery. + return un === "isaacs" || d[un].indexOf(p) === -1 + })) + }) }) } // else fallthrough case "add": if (argv.length > 3) { theUser = encodeURIComponent(argv[3]) - uri = url.resolve(npm.config.get("registry"), "-/by-user/"+theUser+"|"+un) - console.error(uri) - return registry.get(uri, null, function (er, d) { - console.error(uri, er || d) - // return mine that they're not already on. + byUser = "-/by-user/"+theUser+"|"+un + return mapToRegistry(byUser, npm.config, function (er, uri) { if (er) return cb(er) - var mine = d[un] || [] - , theirs = d[theUser] || [] - return cb(null, mine.filter(function (p) { - return theirs.indexOf(p) === -1 - })) + + console.error(uri) + registry.get(uri, null, function (er, d) { + console.error(uri, er || d) + // return mine that they're not already on. + if (er) return cb(er) + var mine = d[un] || [] + , theirs = d[theUser] || [] + return cb(null, mine.filter(function (p) { + return theirs.indexOf(p) === -1 + })) + }) }) } // just list all users who aren't me. - uri = url.resolve(npm.config.get("registry"), "-/users") - return registry.get(uri, null, function (er, list) { - if (er) return cb() - return cb(null, Object.keys(list).filter(function (n) { - return n !== un - })) + return mapToRegistry("-/users", npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, function (er, list) { + if (er) return cb() + return cb(null, Object.keys(list).filter(function (n) { + return n !== un + })) + }) }) default: @@ -71,7 +85,7 @@ var npm = require("./npm.js") , registry = npm.registry , log = require("npmlog") , readJson = require("read-package-json") - , url = require("url") + , mapToRegistry = require("./utils/map-to-registry.js") function owner (args, cb) { var action = args.shift() @@ -90,18 +104,21 @@ function ls (pkg, cb) { ls(pkg, cb) }) - var uri = url.resolve(npm.config.get("registry"), pkg) - registry.get(uri, null, function (er, data) { - var msg = "" - if (er) { - log.error("owner ls", "Couldn't get owner data", pkg) - return cb(er) - } - var owners = data.maintainers - if (!owners || !owners.length) msg = "admin party!" - else msg = owners.map(function (o) { return o.name +" <"+o.email+">" }).join("\n") - console.log(msg) - cb(er, owners) + mapToRegistry(pkg, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, function (er, data) { + var msg = "" + if (er) { + log.error("owner ls", "Couldn't get owner data", pkg) + return cb(er) + } + var owners = data.maintainers + if (!owners || !owners.length) msg = "admin party!" + else msg = owners.map(function (o) { return o.name +" <"+o.email+">" }).join("\n") + console.log(msg) + cb(er, owners) + }) }) } @@ -156,8 +173,12 @@ function rm (user, pkg, cb) { function mutate (pkg, user, mutation, cb) { if (user) { - var uri = url.resolve(npm.config.get("registry"), "-/user/org.couchdb.user:"+user) - registry.get(uri, null, mutate_) + var byUser = "-/user/org.couchdb.user:" + user + mapToRegistry(byUser, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, mutate_) + }) } else { mutate_(null, null) } @@ -172,27 +193,34 @@ function mutate (pkg, user, mutation, cb) { } if (u) u = { "name" : u.name, "email" : u.email } - var uri = url.resolve(npm.config.get("registry"), pkg) - registry.get(uri, null, function (er, data) { - if (er) { - log.error("owner mutate", "Error getting package data for %s", pkg) - return cb(er) - } - var m = mutation(u, data.maintainers) - if (!m) return cb() // handled - if (m instanceof Error) return cb(m) // error - data = { _id : data._id - , _rev : data._rev - , maintainers : m - } - var uri = url.resolve(npm.config.get("registry"), pkg+"/-rev/"+data._rev) - registry.request("PUT", uri, { body : data }, function (er, data) { - if (!er && data.error) er = new Error( - "Failed to update package metadata: "+JSON.stringify(data)) + mapToRegistry(pkg, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, function (er, data) { if (er) { - log.error("owner mutate", "Failed to update package metadata") + log.error("owner mutate", "Error getting package data for %s", pkg) + return cb(er) } - cb(er, data) + var m = mutation(u, data.maintainers) + if (!m) return cb() // handled + if (m instanceof Error) return cb(m) // error + data = { _id : data._id + , _rev : data._rev + , maintainers : m + } + var dataPath = pkg + "/-rev/" + data._rev + mapToRegistry(dataPath, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.request("PUT", uri, { body : data }, function (er, data) { + if (!er && data.error) er = new Error( + "Failed to update package metadata: "+JSON.stringify(data)) + if (er) { + log.error("owner mutate", "Failed to update package metadata") + } + cb(er, data) + }) + }) }) }) } diff --git a/lib/publish.js b/lib/publish.js index 32b09f8e0..349ac00a7 100644 --- a/lib/publish.js +++ b/lib/publish.js @@ -1,7 +1,8 @@ module.exports = publish -var npm = require("./npm.js") +var url = require("url") + , npm = require("./npm.js") , log = require("npmlog") , path = require("path") , readJson = require("read-package-json") @@ -9,7 +10,7 @@ var npm = require("./npm.js") , chain = require("slide").chain , Conf = require("npmconf").Conf , RegClient = require("npm-registry-client") - , isOrganized = require("./utils/is-organized.js") + , mapToRegistry = require("./utils/map-to-registry.js") publish.usage = "npm publish <tarball>" + "\nnpm publish <folder>" @@ -84,47 +85,43 @@ function publish_ (arg, data, isRetry, cachedir, cb) { registry = new RegClient(config) } - var registryURI - if (isOrganized(data.name)) { - var org = data.name.match(/^(@[^@\/]+)\//)[1] - if (!org) return cb(new Error("No organization found in scoped package name")) - log.silly("publish", "scope", org) - - var base = config.get(org + ":registry") - if (!base) { - return cb(new Error("no registry URL found for scope " + org)) - } - registryURI = base - } - else { - registryURI = config.get("registry") - } - data._npmVersion = npm.version data._npmUser = { name: npm.config.get("username") , email: npm.config.get("email") } delete data.modules - if (data.private) return cb(new Error - ("This package has been marked as private\n" - +"Remove the 'private' field from the package.json to publish it.")) - - var tarball = cachedir + ".tgz" - registry.publish(registryURI, data, tarball, function (er) { - if (er && er.code === "EPUBLISHCONFLICT" - && npm.config.get("force") && !isRetry) { - log.warn("publish", "Forced publish over "+data._id) - return npm.commands.unpublish([data._id], function (er) { - // ignore errors. Use the force. Reach out with your feelings. - // but if it fails again, then report the first error. - publish([arg], er || true, cb) - }) - } - // report the unpublish error if this was a retry and unpublish failed - if (er && isRetry && isRetry !== true) return cb(isRetry) + if (data.private) return cb( + new Error( + "This package has been marked as private\n" + + "Remove the 'private' field from the package.json to publish it." + ) + ) + + mapToRegistry(data.name, config, function (er, registryURI) { if (er) return cb(er) - console.log("+ " + data._id) - cb() + + var tarball = cachedir + ".tgz" + + // we just want the base registry URL in this case + var registryBase = url.resolve(registryURI, ".") + log.verbose("publish", "registryBase", registryBase) + + registry.publish(registryBase, data, tarball, function (er) { + if (er && er.code === "EPUBLISHCONFLICT" + && npm.config.get("force") && !isRetry) { + log.warn("publish", "Forced publish over " + data._id) + return npm.commands.unpublish([data._id], function (er) { + // ignore errors. Use the force. Reach out with your feelings. + // but if it fails again, then report the first error. + publish([arg], er || true, cb) + }) + } + // report the unpublish error if this was a retry and unpublish failed + if (er && isRetry && isRetry !== true) return cb(isRetry) + if (er) return cb(er) + console.log("+ " + data._id) + cb() + }) }) } diff --git a/lib/repo.js b/lib/repo.js index d209c3ca8..1fe81f293 100644 --- a/lib/repo.js +++ b/lib/repo.js @@ -5,9 +5,12 @@ repo.usage = "npm repo <pkgname>" repo.completion = function (opts, cb) { if (opts.conf.argv.remain.length > 2) return cb() - var uri = url_.resolve(npm.config.get("registry"), "/-/short") - registry.get(uri, { timeout : 60000 }, function (er, list) { - return cb(null, list || []) + mapToRegistry("/-/short", npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, { timeout : 60000 }, function (er, list) { + return cb(null, list || []) + }) }) } @@ -19,10 +22,11 @@ var npm = require("./npm.js") , path = require("path") , readJson = require("read-package-json") , fs = require("fs") - , url_ = require('url') + , url_ = require("url") + , mapToRegistry = require("./utils/map-to-registry.js") function repo (args, cb) { - var n = args.length && args[0].split("@").shift() || '.' + var n = args.length && args[0].split("@").shift() || "." fs.stat(n, function (er, s) { if (er && er.code === "ENOENT") return callRegistry(n, cb) else if (er) return cb(er) @@ -35,8 +39,8 @@ function repo (args, cb) { } function getUrlAndOpen (d, cb) { - var r = d.repository; - if (!r) return cb(new Error('no repository')); + var r = d.repository + if (!r) return cb(new Error('no repository')) // XXX remove this when npm@v1.3.10 from node 0.10 is deprecated // from https://github.com/npm/npm-www/issues/418 if (githubUserRepo(r.url)) @@ -52,10 +56,13 @@ function getUrlAndOpen (d, cb) { } function callRegistry (n, cb) { - var uri = url_.resolve(npm.config.get("registry"), n + "/latest") - registry.get(uri, { timeout : 3600 }, function (er, d) { + mapToRegistry(n, npm.config, function (er, uri) { if (er) return cb(er) - getUrlAndOpen(d, cb) + + registry.get(uri + "/latest", { timeout : 3600 }, function (er, d) { + if (er) return cb(er) + getUrlAndOpen(d, cb) + }) }) } diff --git a/lib/search.js b/lib/search.js index e7892350c..3be8b0d27 100644 --- a/lib/search.js +++ b/lib/search.js @@ -1,10 +1,10 @@ module.exports = exports = search -var url = require("url") - , npm = require("./npm.js") +var npm = require("./npm.js") , registry = npm.registry , columnify = require('columnify') + , mapToRegistry = require("./utils/map-to-registry.js") search.usage = "npm search [some search terms ...]" @@ -63,10 +63,13 @@ function getFilteredData (staleness, args, notArgs, cb) { follow : true, staleOk : true } - var uri = url.resolve(npm.config.get("registry"), "-/all") - registry.get(uri, opts, function (er, data) { + mapToRegistry("-/all", npm.config, function (er, uri) { if (er) return cb(er) - return cb(null, filter(data, args, notArgs)) + + registry.get(uri, opts, function (er, data) { + if (er) return cb(er) + return cb(null, filter(data, args, notArgs)) + }) }) } diff --git a/lib/star.js b/lib/star.js index 9c0b4ea9e..123c4ebbb 100644 --- a/lib/star.js +++ b/lib/star.js @@ -1,19 +1,22 @@ module.exports = star -var url = require("url") - , npm = require("./npm.js") +var npm = require("./npm.js") , registry = npm.registry , log = require("npmlog") , asyncMap = require("slide").asyncMap + , mapToRegistry = require("./utils/map-to-registry.js") star.usage = "npm star <package> [pkg, pkg, ...]\n" + "npm unstar <package> [pkg, pkg, ...]" star.completion = function (opts, cb) { - var uri = url.resolve(npm.config.get("registry"), "-/short") - registry.get(uri, { timeout : 60000 }, function (er, list) { - return cb(null, list || []) + mapToRegistry("-/short", npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, { timeout : 60000 }, function (er, list) { + return cb(null, list || []) + }) }) } @@ -24,13 +27,16 @@ function star (args, cb) { , using = !(npm.command.match(/^un/)) if (!using) s = u asyncMap(args, function (pkg, cb) { - var uri = url.resolve(npm.config.get("registry"), pkg) - registry.star(uri, using, function (er, data, raw, req) { - if (!er) { - console.log(s + " "+pkg) - log.verbose("star", data) - } - cb(er, data, raw, req) + mapToRegistry(pkg, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.star(uri, using, function (er, data, raw, req) { + if (!er) { + console.log(s + " "+pkg) + log.verbose("star", data) + } + cb(er, data, raw, req) + }) }) }, cb) } diff --git a/lib/stars.js b/lib/stars.js index f0d2ef73a..a482a4b4a 100644 --- a/lib/stars.js +++ b/lib/stars.js @@ -2,15 +2,18 @@ module.exports = stars stars.usage = "npm stars [username]" -var url = require("url") - , npm = require("./npm.js") +var npm = require("./npm.js") , registry = npm.registry , log = require("npmlog") + , mapToRegistry = require("./utils/map-to-registry.js") function stars (args, cb) { var name = args.length === 1 ? args[0] : npm.config.get("username") - , uri = url.resolve(npm.config.get("registry"), name) - registry.stars(uri, showstars) + mapToRegistry(name, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.stars(uri, showstars) + }) function showstars (er, data) { if (er) { diff --git a/lib/tag.js b/lib/tag.js index 1d04ad1f7..cf7752a69 100644 --- a/lib/tag.js +++ b/lib/tag.js @@ -5,9 +5,9 @@ tag.usage = "npm tag <project>@<version> [<tag>]" tag.completion = require("./unpublish.js").completion -var url = require("url") - , npm = require("./npm.js") +var npm = require("./npm.js") , registry = npm.registry + , mapToRegistry = require("./utils/map-to-registry.js") function tag (args, cb) { var thing = (args.shift() || "").split("@") @@ -15,6 +15,9 @@ function tag (args, cb) { , version = thing.join("@") , t = args.shift() || npm.config.get("tag") if (!project || !version || !t) return cb("Usage:\n"+tag.usage) - var uri = url.resolve(npm.config.get("registry"), project) - registry.tag(uri, version, t, cb) + mapToRegistry(project, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.tag(uri, version, t, cb) + }) } diff --git a/lib/unpublish.js b/lib/unpublish.js index 225c1c3c4..cd4f18deb 100644 --- a/lib/unpublish.js +++ b/lib/unpublish.js @@ -1,12 +1,12 @@ module.exports = unpublish -var url = require("url") - , log = require("npmlog") +var log = require("npmlog") , npm = require("./npm.js") , registry = npm.registry , readJson = require("read-package-json") , path = require("path") + , mapToRegistry = require("./utils/map-to-registry.js") unpublish.usage = "npm unpublish <project>[@<version>]" @@ -14,27 +14,34 @@ unpublish.completion = function (opts, cb) { if (opts.conf.argv.remain.length >= 3) return cb() var un = encodeURIComponent(npm.config.get("username")) if (!un) return cb() - var uri = url.resolve(npm.config.get("registry"), "-/by-user/"+un) - registry.get(uri, null, function (er, pkgs) { - // do a bit of filtering at this point, so that we don't need - // to fetch versions for more than one thing, but also don't - // accidentally a whole project. - pkgs = pkgs[un] - if (!pkgs || !pkgs.length) return cb() - var partial = opts.partialWord.split("@") - , pp = partial.shift() - pkgs = pkgs.filter(function (p) { - return p.indexOf(pp) === 0 - }) - if (pkgs.length > 1) return cb(null, pkgs) - var uri = url.resolve(npm.config.get("registry"), pkgs[0]) - registry.get(uri, null, function (er, d) { - if (er) return cb(er) - var vers = Object.keys(d.versions) - if (!vers.length) return cb(null, pkgs) - return cb(null, vers.map(function (v) { - return pkgs[0]+"@"+v - })) + var byUser = "-/by-user/" + un + mapToRegistry(byUser, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, function (er, pkgs) { + // do a bit of filtering at this point, so that we don't need + // to fetch versions for more than one thing, but also don't + // accidentally a whole project. + pkgs = pkgs[un] + if (!pkgs || !pkgs.length) return cb() + var partial = opts.partialWord.split("@") + , pp = partial.shift() + pkgs = pkgs.filter(function (p) { + return p.indexOf(pp) === 0 + }) + if (pkgs.length > 1) return cb(null, pkgs) + mapToRegistry(pkgs[0], npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, function (er, d) { + if (er) return cb(er) + var vers = Object.keys(d.versions) + if (!vers.length) return cb(null, pkgs) + return cb(null, vers.map(function (v) { + return pkgs[0]+"@"+v + })) + }) + }) }) }) } @@ -79,7 +86,10 @@ function gotProject (project, version, cb_) { return cb(er) } - var uri = url.resolve(npm.config.get("registry"), project) - registry.unpublish(uri, version, cb) + mapToRegistry(project, npm.config, function (er, uri) { + if (er) return cb(er) + + registry.unpublish(uri, version, cb) + }) }) } diff --git a/lib/utils/is-organized.js b/lib/utils/is-organized.js deleted file mode 100644 index 61b45508f..000000000 --- a/lib/utils/is-organized.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = isOrganized - -function isOrganized(spec) { - return !!/^@[^@\/]+\//.test(spec) -} diff --git a/lib/utils/is-scoped.js b/lib/utils/is-scoped.js new file mode 100644 index 000000000..fb34f558e --- /dev/null +++ b/lib/utils/is-scoped.js @@ -0,0 +1,16 @@ +module.exports = isScoped + +function isScoped(spec) { + if (spec.charAt(0) !== "@") return null + + var rest = spec.slice(1).split("/") + if (rest.length !== 2) return null + + if (!(rest[0] && rest[1] && + rest[0] === encodeURIComponent(rest[0]) && + rest[1] === encodeURIComponent(rest[1]))) { + return null + } + + return {scope : rest[0], name : rest[1]} +} diff --git a/lib/utils/map-name-to-registry.js b/lib/utils/map-name-to-registry.js deleted file mode 100644 index 2b2e2a062..000000000 --- a/lib/utils/map-name-to-registry.js +++ /dev/null @@ -1,28 +0,0 @@ -var url = require("url") - -var isOrganized = require("./is-organized.js") - , log = require("npmlog") - -module.exports = mapNameToRegistry - -function mapNameToRegistry(name, config, cb) { - var uri - - if (isOrganized(name)) { - var org = name.match(/^(@[^@\/]+)\//)[1] - if (!org) return cb(new Error("No organization found in scoped package name")) - log.silly("mapNameToRegistry", "org", org) - - var escaped = name.replace("/", "%2f") - var orgRegistry = config.get(org + ":registry") - if (!orgRegistry) return cb(new Error("no registry URL found for scope " + org)) - - uri = url.resolve(orgRegistry, escaped) - } - else { - uri = url.resolve(config.get("registry"), name) - } - - log.verbose("mapNameToRegistry", "uri", uri) - cb(null, uri) -} diff --git a/lib/utils/map-to-registry.js b/lib/utils/map-to-registry.js new file mode 100644 index 000000000..169167f76 --- /dev/null +++ b/lib/utils/map-to-registry.js @@ -0,0 +1,51 @@ +var url = require("url") + +var isScoped = require("./is-scoped.js") + , log = require("npmlog") + +module.exports = mapToRegistry + +function mapToRegistry(name, config, cb) { + var uri + var scopedRegistry + + // the name itself takes precedence + var data = isScoped(name) + if (data) { + var packageScope = "@" + data.scope + if (!packageScope) return cb(new Error("No scope found in scoped package named " + name)) + log.silly("mapToRegistry", "packageScope", packageScope) + + var escaped = name.replace("/", "%2f") + scopedRegistry = config.get(packageScope + ":registry") + if (scopedRegistry) { + uri = url.resolve(scopedRegistry, escaped) + } + else { + log.verbose("mapToRegistry", "no registry URL found for scope", packageScope) + } + } + + // ...then --scope=@scope or --scope=scope + var scope = config.get("scope") + if (!uri && scope) { + // I'm an enabler, sorry + if (scope.charAt(0) !== "@") scope = "@" + scope + + scopedRegistry = config.get(scope + ":registry") + if (scopedRegistry) { + uri = url.resolve(scopedRegistry, name) + } + else { + log.verbose("mapToRegistry", "no registry URL found for scope", scope) + } + } + + // ...and finally use the default registry + if (!uri) { + uri = url.resolve(config.get("registry"), name) + } + + log.verbose("mapToRegistry", "uri", uri) + cb(null, uri) +} diff --git a/lib/view.js b/lib/view.js index 33bf550dd..8e0c97cf8 100644 --- a/lib/view.js +++ b/lib/view.js @@ -4,21 +4,26 @@ module.exports = view view.usage = "npm view pkg[@version] [<field>[.subfield]...]" view.completion = function (opts, cb) { - var uri if (opts.conf.argv.remain.length <= 2) { - uri = url.resolve(npm.config.get("registry"), "-/short") - return registry.get(uri, null, cb) + return mapToRegistry("-/short", npm.config, function (er, uri) { + if (er) return cb(er) + + registry.get(uri, null, cb) + }) } // have the package, get the fields. var tag = npm.config.get("tag") - uri = url.resolve(npm.config.get("registry"), opts.conf.argv.remain[2]) - registry.get(uri, null, function (er, d) { + mapToRegistry(opts.conf.argv.remain[2], npm.config, function (er, uri) { if (er) return cb(er) - var dv = d.versions[d["dist-tags"][tag]] - , fields = [] - d.versions = Object.keys(d.versions).sort(semver.compareLoose) - fields = getFields(d).concat(getFields(dv)) - cb(null, fields) + + registry.get(uri, null, function (er, d) { + if (er) return cb(er) + var dv = d.versions[d["dist-tags"][tag]] + , fields = [] + d.versions = Object.keys(d.versions).sort(semver.compareLoose) + fields = getFields(d).concat(getFields(dv)) + cb(null, fields) + }) }) function getFields (d, f, pref) { @@ -42,12 +47,12 @@ view.completion = function (opts, cb) { } } -var url = require("url") - , npm = require("./npm.js") +var npm = require("./npm.js") , registry = npm.registry , log = require("npmlog") , util = require("util") , semver = require("semver") + , mapToRegistry = require("./utils/map-to-registry.js") function view (args, silent, cb) { if (typeof cb !== "function") cb = silent, silent = false @@ -60,53 +65,56 @@ function view (args, silent, cb) { if (name === ".") return cb(view.usage) // get the data about this package - var uri = url.resolve(npm.config.get("registry"), name) - registry.get(uri, null, function (er, data) { + mapToRegistry(name, npm.config, function (er, uri) { if (er) return cb(er) - if (data["dist-tags"] && data["dist-tags"].hasOwnProperty(version)) { - version = data["dist-tags"][version] - } - if (data.time && data.time.unpublished) { - var u = data.time.unpublished - er = new Error("Unpublished by " + u.name + " on " + u.time) - er.statusCode = 404 - er.code = "E404" - er.pkgid = data._id - return cb(er, data) - } + registry.get(uri, null, function (er, data) { + if (er) return cb(er) + if (data["dist-tags"] && data["dist-tags"].hasOwnProperty(version)) { + version = data["dist-tags"][version] + } + if (data.time && data.time.unpublished) { + var u = data.time.unpublished + er = new Error("Unpublished by " + u.name + " on " + u.time) + er.statusCode = 404 + er.code = "E404" + er.pkgid = data._id + return cb(er, data) + } - var results = [] - , error = null - , versions = data.versions || {} - data.versions = Object.keys(versions).sort(semver.compareLoose) - if (!args.length) args = [""] - // remove readme unless we asked for it - if (-1 === args.indexOf("readme")) { - delete data.readme - } + var results = [] + , error = null + , versions = data.versions || {} + data.versions = Object.keys(versions).sort(semver.compareLoose) + if (!args.length) args = [""] + + // remove readme unless we asked for it + if (-1 === args.indexOf("readme")) { + delete data.readme + } - Object.keys(versions).forEach(function (v) { - if (semver.satisfies(v, version, true)) args.forEach(function (args) { - // remove readme unless we asked for it - if (-1 === args.indexOf("readme")) { - delete versions[v].readme - } - results.push(showFields(data, versions[v], args)) + Object.keys(versions).forEach(function (v) { + if (semver.satisfies(v, version, true)) args.forEach(function (args) { + // remove readme unless we asked for it + if (-1 === args.indexOf("readme")) { + delete versions[v].readme + } + results.push(showFields(data, versions[v], args)) + }) }) - }) - results = results.reduce(reducer, {}) - var retval = results + results = results.reduce(reducer, {}) + var retval = results - if (args.length === 1 && args[0] === "") { - retval = cleanBlanks(retval) - log.silly("cleanup", retval) - } + if (args.length === 1 && args[0] === "") { + retval = cleanBlanks(retval) + log.silly("cleanup", retval) + } - if (error || silent) cb(error, retval) - else printData(results, data._id, cb.bind(null, error, retval)) + if (error || silent) cb(error, retval) + else printData(results, data._id, cb.bind(null, error, retval)) + }) }) } |