|
|
|
|
|
|
|
module.exports = publish
|
|
|
|
|
|
|
|
var path = require("path")
|
|
|
|
, url = require("url")
|
|
|
|
|
|
|
|
function publish (data, tarball, cb) {
|
|
|
|
|
|
|
|
var email = this.conf.get('email')
|
|
|
|
var auth = this.conf.get('_auth')
|
|
|
|
var username = this.conf.get('username')
|
|
|
|
|
|
|
|
if (!email || !auth || !username) {
|
|
|
|
var er = new Error("auth and email required for publishing")
|
|
|
|
er.code = 'ENEEDAUTH'
|
|
|
|
return cb(er)
|
|
|
|
}
|
|
|
|
|
|
|
|
// add the dist-url to the data, pointing at the tarball.
|
|
|
|
// if the {name} isn't there, then create it.
|
|
|
|
// if the {version} is already there, then fail.
|
|
|
|
// then:
|
|
|
|
// PUT the data to {config.registry}/{data.name}/{data.version}
|
|
|
|
var registry = this.conf.get('registry')
|
|
|
|
|
|
|
|
var fullData =
|
|
|
|
{ _id : data.name
|
|
|
|
, name : data.name
|
|
|
|
, description : data.description
|
|
|
|
, "dist-tags" : {}
|
|
|
|
, versions : {}
|
|
|
|
, readme: data.readme || ""
|
|
|
|
, maintainers :
|
|
|
|
[ { name : username
|
|
|
|
, email : email
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
var tbName = data.name + "-" + data.version + ".tgz"
|
|
|
|
, tbURI = data.name + "/-/" + tbName
|
|
|
|
|
|
|
|
data._id = data.name+"@"+data.version
|
|
|
|
data.dist = data.dist || {}
|
|
|
|
data.dist.tarball = url.resolve(registry, tbURI)
|
|
|
|
.replace(/^https:\/\//, "http://")
|
|
|
|
|
|
|
|
|
|
|
|
// first try to just PUT the whole fullData, and this will fail if it's
|
|
|
|
// already there, because it'll be lacking a _rev, so couch'll bounce it.
|
|
|
|
this.request("PUT", encodeURIComponent(data.name), fullData,
|
|
|
|
function (er, parsed, json, response) {
|
|
|
|
// get the rev and then upload the attachment
|
|
|
|
// a 409 is expected here, if this is a new version of an existing package.
|
|
|
|
if (er
|
|
|
|
&& !(response && response.statusCode === 409)
|
|
|
|
&& !( parsed
|
|
|
|
&& parsed.reason ===
|
|
|
|
"must supply latest _rev to update existing package" )) {
|
|
|
|
this.log.error("publish", "Failed PUT response "
|
|
|
|
+(response && response.statusCode))
|
|
|
|
return cb(er)
|
|
|
|
}
|
|
|
|
var dataURI = encodeURIComponent(data.name)
|
|
|
|
+ "/" + encodeURIComponent(data.version)
|
|
|
|
|
|
|
|
var tag = data.tag || this.conf.get('tag') || "latest"
|
|
|
|
dataURI += "/-tag/" + tag
|
|
|
|
|
|
|
|
// let's see what versions are already published.
|
|
|
|
// could be that we just need to update the bin dist values.
|
|
|
|
this.request("GET", data.name, function (er, fullData) {
|
|
|
|
if (er) return cb(er)
|
|
|
|
|
|
|
|
function handle(er) {
|
|
|
|
if (er.message.indexOf("conflict Document update conflict.") === 0) {
|
|
|
|
return cb(conflictError.call(this, data._id));
|
|
|
|
}
|
|
|
|
this.log.error("publish", "Error uploading package");
|
|
|
|
return cb(er)
|
|
|
|
}
|
|
|
|
|
|
|
|
var exists = fullData.versions && fullData.versions[data.version]
|
|
|
|
if (exists) return cb(conflictError.call(this, data._id))
|
|
|
|
|
|
|
|
var rev = fullData._rev;
|
|
|
|
attach.call(this, data.name, tarball, tbName, rev, function (er) {
|
|
|
|
if (er) return handle(er)
|
|
|
|
this.log.verbose("publish", "attached", [data.name, tarball, tbName])
|
|
|
|
this.request("PUT", dataURI, data, function (er) {
|
|
|
|
if (er) return handle(er)
|
|
|
|
return cb(er)
|
|
|
|
}.bind(this))
|
|
|
|
}.bind(this))
|
|
|
|
}.bind(this))
|
|
|
|
}.bind(this)) // pining for fat arrows.
|
|
|
|
}
|
|
|
|
|
|
|
|
function conflictError (pkgid) {
|
|
|
|
var e = new Error("publish fail")
|
|
|
|
e.code = "EPUBLISHCONFLICT"
|
|
|
|
e.pkgid = pkgid
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
function attach (doc, file, filename, rev, cb) {
|
|
|
|
doc = encodeURIComponent(doc)
|
|
|
|
var revu = "-rev/"+rev
|
|
|
|
, attURI = doc + "/-/" + encodeURIComponent(filename) + "/" + revu
|
|
|
|
this.log.verbose("uploading", [attURI, file])
|
|
|
|
this.upload(attURI, file, cb)
|
|
|
|
}
|