From 985d705ad22251af9500a260571d2e8b217e46af Mon Sep 17 00:00:00 2001 From: Alex Kocharin Date: Fri, 27 Dec 2013 17:06:30 +0400 Subject: [PATCH] working on tags / incomplete --- lib/index.js | 13 +++++++++ lib/local-storage.js | 21 ++++++++++++++ lib/storage.js | 64 ++++++++++++++++++++++--------------------- lib/up-storage.js | 17 ++++++++++++ lib/utils.js | 33 ++++++++++++++++++++++ test/unit/st_merge.js | 2 +- 6 files changed, 118 insertions(+), 32 deletions(-) diff --git a/lib/index.js b/lib/index.js index 00b867224..f89bc0700 100644 --- a/lib/index.js +++ b/lib/index.js @@ -198,6 +198,19 @@ module.exports = function(config_hash) { }) }) + // tagging a package + app.put('/:package/:tag', can('publish'), media('application/json'), function(req, res, next) { + if (typeof(req.body) !== 'string') return next('route') + + storage.add_tag(req.params.name, req.body, req.params.tag, function(err) { + if (err) return next(err) + res.status(201) + return res.send({ + ok: 'package tagged' + }) + }) + }) + // publishing a package app.put('/:package/:_rev?/:revision?', can('publish'), media('application/json'), expect_json, function(req, res, next) { if (req.params._rev != null && req.params._rev != '-rev') return next('route') diff --git a/lib/local-storage.js b/lib/local-storage.js index b922802b0..03d4bd43f 100644 --- a/lib/local-storage.js +++ b/lib/local-storage.js @@ -225,6 +225,27 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback) }, callback) } +Storage.prototype.add_tag = function(name, version, tag, callback) { + var self = this + self.update_package(name, function updater(data, cb) { + if (data.versions[version] == null) { + return cb(new UError({ + status: 404, + msg: "this version doesn't exist" + })) + } + + data.versions[version] = metadata + utils.add_tag(data, version, tag) + cb() + }, callback) +} + +// change package info to tag a specific version +function _add_tag(data, version, tag) { + data['dist-tags'][tag] = version +} + // currently supports unpublishing only Storage.prototype.change_package = function(name, metadata, revision, callback) { var self = this diff --git a/lib/storage.js b/lib/storage.js index 8f376ffed..f33256f94 100644 --- a/lib/storage.js +++ b/lib/storage.js @@ -1,5 +1,4 @@ var async = require('async') - , semver = require('semver') , assert = require('assert') , UError = require('./error').UserError , Local = require('./local-storage') @@ -187,6 +186,34 @@ Storage.prototype.add_version = function(name, version, metadata, tag, callback) }) } +// Tags a package version with a provided tag +// +// Function is basically the same as add_version +// +// Used storages: local (write) && uplinks (proxy_publish, write) +// +Storage.prototype.add_tag = function(name, version, tag, callback) { + var self = this + + var uplinks = [] + for (var i in self.uplinks) { + if (self.config.proxy_publish(name, i)) { + uplinks.push(self.uplinks[i]) + } + } + async.map(uplinks, function(up, cb) { + up.add_tag(name, version, tag, cb) + }, function(err, results) { + if (err) { + return callback(new UError({ + status: 503, + msg: 'can\'t tag on one of the uplinks, refuse to proceed' + })) + } + self.local.add_tag(name, version, tag, callback) + }) +} + // // Change an existing package (i.e. unpublish one version) // @@ -436,7 +463,7 @@ Storage.prototype.get_package = function(name, options, callback) { if (whitelist.indexOf(i) === -1) delete result[i] } - result['dist-tags'].latest = Storage._semver_sort(Object.keys(result.versions)) + result['dist-tags'].latest = utils.semver_sort(Object.keys(result.versions)) for (var i in result['dist-tags']) { if (Array.isArray(result['dist-tags'][i])) { result['dist-tags'][i] = result['dist-tags'][i][result['dist-tags'][i].length-1] @@ -444,6 +471,9 @@ Storage.prototype.get_package = function(name, options, callback) { } } + // npm can throw if this field doesn't exist + result._attachments = {} + callback(null, result, uplink_errors) }) }) @@ -542,37 +572,9 @@ Storage._merge_versions = function(local, up) { // refresh dist-tags for (var i in up['dist-tags']) { - if (i === 'latest') continue - switch(typeof(local['dist-tags'][i])) { - case 'string': - local['dist-tags'][i] = [local['dist-tags'][i]] - break - case 'object': // array - break - default: - local['dist-tags'][i] = [] - } - if (local['dist-tags'][i].indexOf(up['dist-tags'][i]) === -1) { - local['dist-tags'][i].push(up['dist-tags'][i]) - local['dist-tags'][i] = Storage._semver_sort(local['dist-tags'][i]) - } + utils.tag_version(local, i, up['dist-tags'][i]) } } -// function filters out bad semver versions and sorts the array -// exported for unit tests only -Storage._semver_sort = function semver_sort(array) { - return array - .filter(function(x) { - if (!semver.parse(x, true)) { - Logger.logger.warn({ver: x, sub: 'out'}, 'ignoring bad version @{ver}') - return false - } - return true - }) - .sort(semver.compareLoose) - .map(String) -} - module.exports = Storage diff --git a/lib/up-storage.js b/lib/up-storage.js index 69e09721f..cd171cf2c 100644 --- a/lib/up-storage.js +++ b/lib/up-storage.js @@ -237,6 +237,22 @@ Storage.prototype.add_version = function(name, version, metadata, tag, options, }) } +Storage.prototype.add_tag = function(name, version, tag, options, callback) { + if (typeof(options) === 'function') callback = options, options = {} + + this.request({ + uri: '/' + encode(name) + '/' + encode(tag), + method: 'PUT', + json: JSON.stringify(version), + }, function(err, res, body) { + if (err) return callback(err) + if (!(res.statusCode >= 200 && res.statusCode < 300)) { + return callback(new Error('bad status code: ' + res.statusCode)) + } + callback(null, body) + }) +} + Storage.prototype.add_tarball = function(name, filename, options) { if (!options) options = {} @@ -285,6 +301,7 @@ Storage.prototype.get_package = function(name, options, callback) { var headers = {} if (options.etag) { headers['If-None-Match'] = options.etag + headers['Accept'] = 'application/octet-stream' } this._add_proxy_headers(options.req, headers) diff --git a/lib/utils.js b/lib/utils.js index f3e4d52d9..719484d62 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,4 +1,6 @@ var assert = require('assert') + , semver = require('semver') + , Logger = require('./logger') , URL = require('url') // from normalize-package-data/lib/fixer.js @@ -88,3 +90,34 @@ module.exports.filter_tarball_urls = function(pkg, req, config) { return pkg } +module.exports.tag_version = function(data, tag, version) { + if (tag === 'latest') return + switch(typeof(data['dist-tags'][tag])) { + case 'string': + data['dist-tags'][tag] = [data['dist-tags'][tag]] + break + case 'object': // array + break + default: + data['dist-tags'][tag] = [] + } + if (data['dist-tags'][tag].indexOf(version) === -1) { + data['dist-tags'][tag].push(version) + data['dist-tags'][tag] = module.exports.semver_sort(data['dist-tags'][tag]) + } +} + +// function filters out bad semver versions and sorts the array +module.exports.semver_sort = function semver_sort(array) { + return array + .filter(function(x) { + if (!semver.parse(x, true)) { + Logger.logger.warn({ver: x}, 'ignoring bad version @{ver}') + return false + } + return true + }) + .sort(semver.compareLoose) + .map(String) +} + diff --git a/test/unit/st_merge.js b/test/unit/st_merge.js index d565796ca..9e4d424ab 100644 --- a/test/unit/st_merge.js +++ b/test/unit/st_merge.js @@ -1,5 +1,5 @@ var assert = require('assert') - , semver_sort = require('../../lib/storage')._semver_sort + , semver_sort = require('../../lib/utils').semver_sort , merge = require('../../lib/storage')._merge_versions require('../../lib/logger').setup([])