UNPKG

4.6 kBJavaScriptView Raw
1
2module.exports = publish
3
4var url = require("url")
5 , npm = require("./npm.js")
6 , log = require("npmlog")
7 , path = require("path")
8 , readJson = require("read-package-json")
9 , lifecycle = require("./utils/lifecycle.js")
10 , chain = require("slide").chain
11 , Conf = require("./config/core.js").Conf
12 , RegClient = require("npm-registry-client")
13 , mapToRegistry = require("./utils/map-to-registry.js")
14 , cachedPackageRoot = require("./cache/cached-package-root.js")
15
16publish.usage = "npm publish <tarball>"
17 + "\nnpm publish <folder>"
18 + "\n\nPublishes '.' if no argument supplied"
19
20publish.completion = function (opts, cb) {
21 // publish can complete to a folder with a package.json
22 // or a tarball, or a tarball url.
23 // for now, not yet implemented.
24 return cb()
25}
26
27function publish (args, isRetry, cb) {
28 if (typeof cb !== "function") {
29 cb = isRetry
30 isRetry = false
31 }
32 if (args.length === 0) args = ["."]
33 if (args.length !== 1) return cb(publish.usage)
34
35 log.verbose("publish", args)
36 var arg = args[0]
37 // if it's a local folder, then run the prepublish there, first.
38 readJson(path.resolve(arg, "package.json"), function (er, data) {
39 if (er && er.code !== "ENOENT" && er.code !== "ENOTDIR") return cb(er)
40
41 if (data) {
42 if (!data.name) return cb(new Error("No name provided"))
43 if (!data.version) return cb(new Error("No version provided"))
44 }
45
46 // Error is OK. Could be publishing a URL or tarball, however, that means
47 // that we will not have automatically run the prepublish script, since
48 // that gets run when adding a folder to the cache.
49 if (er) return cacheAddPublish(arg, false, isRetry, cb)
50 else cacheAddPublish(arg, true, isRetry, cb)
51 })
52}
53
54// didPre in this case means that we already ran the prepublish script,
55// and that the "dir" is an actual directory, and not something silly
56// like a tarball or name@version thing.
57// That means that we can run publish/postpublish in the dir, rather than
58// in the cache dir.
59function cacheAddPublish (dir, didPre, isRetry, cb) {
60 npm.commands.cache.add(dir, null, null, false, function (er, data) {
61 if (er) return cb(er)
62 log.silly("publish", data)
63 var cachedir = path.resolve(cachedPackageRoot(data), "package")
64 chain([ !didPre &&
65 [lifecycle, data, "prepublish", cachedir]
66 , [publish_, dir, data, isRetry, cachedir]
67 , [lifecycle, data, "publish", didPre ? dir : cachedir]
68 , [lifecycle, data, "postpublish", didPre ? dir : cachedir] ]
69 , cb )
70 })
71}
72
73function publish_ (arg, data, isRetry, cachedir, cb) {
74 if (!data) return cb(new Error("no package.json file found"))
75
76 var registry = npm.registry
77 var config = npm.config
78
79 // check for publishConfig hash
80 if (data.publishConfig) {
81 config = new Conf(npm.config)
82 config.save = npm.config.save.bind(npm.config)
83
84 // don't modify the actual publishConfig object, in case we have
85 // to set a login token or some other data.
86 config.unshift(Object.keys(data.publishConfig).reduce(function (s, k) {
87 s[k] = data.publishConfig[k]
88 return s
89 }, {}))
90 registry = new RegClient(config)
91 }
92
93 data._npmVersion = npm.version
94 data._nodeVersion = process.versions.node
95
96 delete data.modules
97 if (data.private) return cb(
98 new Error(
99 "This package has been marked as private\n" +
100 "Remove the 'private' field from the package.json to publish it."
101 )
102 )
103
104 mapToRegistry(data.name, config, function (er, registryURI) {
105 if (er) return cb(er)
106
107 var tarball = cachedir + ".tgz"
108
109 // we just want the base registry URL in this case
110 var registryBase = url.resolve(registryURI, ".")
111 log.verbose("publish", "registryBase", registryBase)
112
113 var c = config.getCredentialsByURI(registryBase)
114 data._npmUser = {name: c.username, email: c.email}
115
116 registry.publish(registryBase, data, tarball, function (er) {
117 if (er && er.code === "EPUBLISHCONFLICT"
118 && npm.config.get("force") && !isRetry) {
119 log.warn("publish", "Forced publish over " + data._id)
120 return npm.commands.unpublish([data._id], function (er) {
121 // ignore errors. Use the force. Reach out with your feelings.
122 // but if it fails again, then report the first error.
123 publish([arg], er || true, cb)
124 })
125 }
126 // report the unpublish error if this was a retry and unpublish failed
127 if (er && isRetry && isRetry !== true) return cb(isRetry)
128 if (er) return cb(er)
129 console.log("+ " + data._id)
130 cb()
131 })
132 })
133}