0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-02-17 23:45:29 -05:00

refactor: dist-tags accessor

This commit is contained in:
Juan Picado @jotadeveloper 2018-03-11 07:06:13 +01:00
parent d200bf4507
commit 00865d07db
No known key found for this signature in database
GPG key ID: 18AC54485952D158
8 changed files with 93 additions and 92 deletions

View file

@ -1,6 +1,7 @@
const {media, allow} = require('../../middleware');
const mime = require('mime');
const _ = require('lodash');
import mime from 'mime';
import _ from 'lodash';
import {media, allow} from '../../middleware';
import {DIST_TAGS} from '../../../lib/utils';
export default function(route, auth, storage) {
@ -54,7 +55,7 @@ export default function(route, auth, storage) {
return next(err);
}
next(info['dist-tags']);
next(info[DIST_TAGS]);
},
});
});

View file

@ -2,7 +2,7 @@ const _ = require('lodash');
const createError = require('http-errors');
const {allow} = require('../../middleware');
const Utils = require('../../../lib/utils');
const {DIST_TAGS, filter_tarball_urls, get_version} = require('../../../lib/utils');
export default function(route, auth, storage, config) {
const can = allow(auth);
@ -12,22 +12,22 @@ export default function(route, auth, storage, config) {
if (err) {
return next(err);
}
info = Utils.filter_tarball_urls(info, req, config);
info = filter_tarball_urls(info, req, config);
let queryVersion = req.params.version;
if (_.isNil(queryVersion)) {
return next(info);
}
let t = Utils.get_version(info, queryVersion);
let t = get_version(info, queryVersion);
if (_.isNil(t) === false) {
return next(t);
}
if (_.isNil(info['dist-tags']) === false) {
if (_.isNil(info['dist-tags'][queryVersion]) === false) {
queryVersion = info['dist-tags'][queryVersion];
t = Utils.get_version(info, queryVersion);
if (_.isNil(info[DIST_TAGS]) === false) {
if (_.isNil(info[DIST_TAGS][queryVersion]) === false) {
queryVersion = info[DIST_TAGS][queryVersion];
t = get_version(info, queryVersion);
if (_.isNil(t) === false) {
return next(t);
}

View file

@ -4,7 +4,7 @@ const createError = require('http-errors');
const {media, expect_json, allow} = require('../../middleware');
const Notify = require('../../../lib/notify');
const Utils = require('../../../lib/utils');
const {DIST_TAGS, validate_metadata, isObject} = require('../../../lib/utils');
const mime = require('mime');
const notify = Notify.notify;
@ -80,7 +80,7 @@ export default function(router, auth, storage, config) {
return next(err);
}
add_tags(metadata['dist-tags'], function(err) {
add_tags(metadata[DIST_TAGS], function(err) {
if (err) {
return next(err);
}
@ -92,13 +92,13 @@ export default function(router, auth, storage, config) {
});
};
if (Object.keys(req.body).length === 1 && Utils.isObject(req.body.users)) {
if (Object.keys(req.body).length === 1 && isObject(req.body.users)) {
// 501 status is more meaningful, but npm doesn't show error message for 5xx
return next( createError[404]('npm star|unstar calls are not implemented') );
}
try {
metadata = Utils.validate_metadata(req.body, name);
metadata = validate_metadata(req.body, name);
} catch(err) {
return next( createError[422]('bad incoming package data') );
}

View file

@ -1,5 +1,5 @@
import _ from 'lodash';
import {addScope, addGravatarSupport, deleteProperties, sortByName} from '../../../lib/utils';
import {addScope, addGravatarSupport, deleteProperties, sortByName, DIST_TAGS} from '../../../lib/utils';
import {allow} from '../../middleware';
import async from 'async';
import marked from 'marked';
@ -66,7 +66,7 @@ function addPackageWebApi(route, storage, auth) {
req,
callback: function(err, info) {
if (_.isNil(err)) {
info.latest = info.versions[info['dist-tags'].latest];
info.latest = info.versions[info[DIST_TAGS].latest];
info = deleteProperties(['readme', 'versions'], info);
info = addGravatarSupport(info);
next(info);

View file

@ -1,4 +1,5 @@
import Search from '../../../lib/search';
import {DIST_TAGS} from '../../../lib/utils';
function addSearchWebApi(route, storage, auth) {
// Search package
@ -16,7 +17,7 @@ function addSearchWebApi(route, storage, auth) {
return;
}
packages.push(entry.versions[entry['dist-tags'].latest]);
packages.push(entry.versions[entry[DIST_TAGS].latest]);
});
}

View file

@ -10,7 +10,7 @@ import UrlNode from 'url';
import _ from 'lodash';
// $FlowFixMe
import async from 'async';
import * as Utils from './utils';
import {ErrorCode, isObject, getLatestVersion, tag_version, validate_name, semverSort, DIST_TAGS} from './utils';
import {
generatePackageTemplate, normalizePackage, generateRevision, cleanUpReadme,
fileExist, noSuchFile, DEFAULT_REVISION, pkgFileName,
@ -77,15 +77,15 @@ class LocalStorage implements IStorage {
const storage: any = this._getLocalStorage(name);
if (_.isNil(storage)) {
return callback( Utils.ErrorCode.get404('this package cannot be added'));
return callback( ErrorCode.get404('this package cannot be added'));
}
storage.createPackage(name, generatePackageTemplate(name), (err) => {
if (_.isNull(err) === false && err.code === fileExist) {
return callback( Utils.ErrorCode.get409());
return callback( ErrorCode.get409());
}
const latest = Utils.getLatestVersion(pkg);
const latest = getLatestVersion(pkg);
if (_.isNil(latest) === false && pkg.versions[latest]) {
return callback(null, pkg.versions[latest]);
}
@ -104,13 +104,13 @@ class LocalStorage implements IStorage {
let storage: any = this._getLocalStorage(name);
if (_.isNil(storage)) {
return callback( Utils.ErrorCode.get404());
return callback( ErrorCode.get404());
}
storage.readPackage(name, (err, data) => {
if (_.isNil(err) === false) {
if (err.code === noSuchFile) {
return callback( Utils.ErrorCode.get404());
return callback( ErrorCode.get404());
} else {
return callback(err);
}
@ -122,7 +122,7 @@ class LocalStorage implements IStorage {
if (removeFailed) {
// This will happen when database is locked
return callback(Utils.ErrorCode.get422(removeFailed.message));
return callback(ErrorCode.get422(removeFailed.message));
}
storage.deletePackage(pkgFileName, (err) => {
if (err) {
@ -181,16 +181,16 @@ class LocalStorage implements IStorage {
}
}
for (let tag in packageInfo['dist-tags']) {
if (!packageLocalJson['dist-tags'][tag] || packageLocalJson['dist-tags'][tag] !== packageInfo['dist-tags'][tag]) {
for (let tag in packageInfo[DIST_TAGS]) {
if (!packageLocalJson[DIST_TAGS][tag] || packageLocalJson[DIST_TAGS][tag] !== packageInfo[DIST_TAGS][tag]) {
change = true;
packageLocalJson['dist-tags'][tag] = packageInfo['dist-tags'][tag];
packageLocalJson[DIST_TAGS][tag] = packageInfo[DIST_TAGS][tag];
}
}
for (let up in packageInfo._uplinks) {
if (Object.prototype.hasOwnProperty.call(packageInfo._uplinks, up)) {
const need_change = !Utils.isObject(packageLocalJson._uplinks[up])
const need_change = !isObject(packageLocalJson._uplinks[up])
|| packageInfo._uplinks[up].etag !== packageLocalJson._uplinks[up].etag
|| packageInfo._uplinks[up].fetched !== packageLocalJson._uplinks[up].fetched;
@ -243,19 +243,19 @@ class LocalStorage implements IStorage {
metadata = cleanUpReadme(metadata);
if (data.versions[version] != null) {
return cb( Utils.ErrorCode.get409() );
return cb( ErrorCode.get409() );
}
// if uploaded tarball has a different shasum, it's very likely that we have some kind of error
if (Utils.isObject(metadata.dist) && _.isString(metadata.dist.tarball)) {
if (isObject(metadata.dist) && _.isString(metadata.dist.tarball)) {
let tarball = metadata.dist.tarball.replace(/.*\//, '');
if (Utils.isObject(data._attachments[tarball])) {
if (isObject(data._attachments[tarball])) {
if (_.isNil(data._attachments[tarball].shasum) === false && _.isNil(metadata.dist.shasum) === false) {
if (data._attachments[tarball].shasum != metadata.dist.shasum) {
const errorMessage = `shasum error, ${data._attachments[tarball].shasum} != ${metadata.dist.shasum}`;
return cb( Utils.ErrorCode.get400(errorMessage) );
return cb( ErrorCode.get400(errorMessage) );
}
}
@ -272,11 +272,11 @@ class LocalStorage implements IStorage {
}
data.versions[version] = metadata;
Utils.tag_version(data, version, tag);
tag_version(data, version, tag);
let addFailed = this.localData.add(name);
if (addFailed) {
return cb(Utils.ErrorCode.get422(addFailed.message));
return cb(ErrorCode.get422(addFailed.message));
}
cb();
@ -294,7 +294,7 @@ class LocalStorage implements IStorage {
/* eslint guard-for-in: 0 */
for (let t: string in tags) {
if (_.isNull(tags[t])) {
delete data['dist-tags'][t];
delete data[DIST_TAGS][t];
continue;
}
@ -302,7 +302,7 @@ class LocalStorage implements IStorage {
return cb( this._getVersionNotFound() );
}
const key: string = tags[t];
Utils.tag_version(data, key, t);
tag_version(data, key, t);
}
cb();
}, callback);
@ -314,7 +314,7 @@ class LocalStorage implements IStorage {
* @private
*/
_getVersionNotFound() {
return Utils.ErrorCode.get404('this version doesn\'t exist');
return ErrorCode.get404('this version doesn\'t exist');
}
/**
@ -323,7 +323,7 @@ class LocalStorage implements IStorage {
* @private
*/
_getFileNotAvailable() {
return Utils.ErrorCode.get404('no such file available');
return ErrorCode.get404('no such file available');
}
/**
@ -338,8 +338,8 @@ class LocalStorage implements IStorage {
changePackage(name: string,
pkg: Package,
revision?: string, callback: Callback) {
if (!Utils.isObject(pkg.versions) || !Utils.isObject(pkg['dist-tags'])) {
return callback( Utils.ErrorCode.get422());
if (!isObject(pkg.versions) || !isObject(pkg[DIST_TAGS])) {
return callback( ErrorCode.get422());
}
this._updatePackage(name, (jsonData, cb) => {
@ -359,7 +359,7 @@ class LocalStorage implements IStorage {
}
jsonData['dist-tags'] = pkg['dist-tags'];
jsonData[DIST_TAGS] = pkg[DIST_TAGS];
cb();
}, function(err) {
if (err) {
@ -377,7 +377,7 @@ class LocalStorage implements IStorage {
*/
removeTarball(name: string, filename: string,
revision: string, callback: Callback) {
assert(Utils.validate_name(filename));
assert(validate_name(filename));
this._updatePackage(name, (data, cb) => {
if (data._attachments[filename]) {
@ -405,7 +405,7 @@ class LocalStorage implements IStorage {
* @return {Stream}
*/
addTarball(name: string, filename: string) {
assert(Utils.validate_name(filename));
assert(validate_name(filename));
let length = 0;
const shaOneHash = Crypto.createHash('sha1');
@ -425,7 +425,7 @@ class LocalStorage implements IStorage {
if (name === pkgFileName || name === '__proto__') {
process.nextTick(() => {
uploadStream.emit('error', Utils.ErrorCode.get403());
uploadStream.emit('error', ErrorCode.get403());
});
return uploadStream;
}
@ -441,7 +441,7 @@ class LocalStorage implements IStorage {
writeStream.on('error', (err) => {
if (err.code === fileExist) {
uploadStream.emit('error', Utils.ErrorCode.get409());
uploadStream.emit('error', ErrorCode.get409());
} else if (err.code === noSuchFile) {
// check if package exists to throw an appropriate message
this.getPackageMetadata(name, function(_err, res) {
@ -482,7 +482,7 @@ class LocalStorage implements IStorage {
uploadStream.done = function() {
if (!length) {
uploadStream.emit('error', Utils.ErrorCode.get422('refusing to accept zero-length file'));
uploadStream.emit('error', ErrorCode.get422('refusing to accept zero-length file'));
writeStream.abort();
} else {
writeStream.done();
@ -501,7 +501,7 @@ class LocalStorage implements IStorage {
* @return {ReadTarball}
*/
getTarball(name: string, filename: string): IReadTarball {
assert(Utils.validate_name(filename));
assert(validate_name(filename));
const storage: IPackageStorage = this._getLocalStorage(name);
@ -536,7 +536,7 @@ class LocalStorage implements IStorage {
_streamSuccessReadTarBall(storage: any, filename: string): IReadTarball {
const stream: IReadTarball = new ReadTarball();
const readTarballStream = storage.readTarball(filename);
const e404 = Utils.ErrorCode.get404;
const e404 = ErrorCode.get404;
stream.abort = function() {
if (_.isNil(readTarballStream) === false) {
@ -575,7 +575,7 @@ class LocalStorage implements IStorage {
const storage: IPackageStorage = this._getLocalStorage(name);
if (_.isNil(storage)) {
return callback( Utils.ErrorCode.get404() );
return callback( ErrorCode.get404() );
}
this._readPackage(name, storage, callback);
@ -603,8 +603,8 @@ class LocalStorage implements IStorage {
}
const listVersions: Array<string> = Object.keys(data.versions);
const versions: Array<string> = Utils.semverSort(listVersions);
const latest: string = data['dist-tags'] && data['dist-tags'].latest ? data['dist-tags'].latest : versions.pop();
const versions: Array<string> = semverSort(listVersions);
const latest: string = data[DIST_TAGS] && data[DIST_TAGS].latest ? data[DIST_TAGS].latest : versions.pop();
if (data.versions[latest]) {
const version: Version = data.versions[latest];
@ -663,7 +663,7 @@ class LocalStorage implements IStorage {
storage.readPackage(name, (err, result) => {
if (err) {
if (err.code === noSuchFile) {
return callback( Utils.ErrorCode.get404() );
return callback( ErrorCode.get404() );
} else {
return callback(this._internalError(err, pkgFileName, 'error reading'));
}
@ -706,7 +706,7 @@ class LocalStorage implements IStorage {
}
async.eachSeries(files, (file2, cb) => {
if (Utils.validate_name(file2)) {
if (validate_name(file2)) {
onPackage({
name: `${file}/${file2}`,
path: Path.resolve(base, storage, file, file2),
@ -716,7 +716,7 @@ class LocalStorage implements IStorage {
}
}, cb);
});
} else if (Utils.validate_name(file)) {
} else if (validate_name(file)) {
onPackage({
name: file,
path: Path.resolve(base, storage, file),
@ -769,7 +769,7 @@ class LocalStorage implements IStorage {
_internalError(err: string, file: string, message: string) {
this.logger.error( {err: err, file: file}, `${message} @{file}: @{!err.message}` );
return Utils.ErrorCode.get500();
return ErrorCode.get500();
}
/**
@ -782,7 +782,7 @@ class LocalStorage implements IStorage {
const storage: IPackageStorage = this._getLocalStorage(name);
if (!storage) {
return callback( Utils.ErrorCode.get404() );
return callback( ErrorCode.get404() );
}
storage.updatePackage(name, updateHandler, this._writePackage.bind(this), normalizePackage,

View file

@ -11,7 +11,7 @@ import Search from './search';
import LocalStorage from './local-storage';
import {ReadTarball} from '@verdaccio/streams';
import ProxyStorage from './up-storage';
import * as Utils from './utils';
import {ErrorCode, normalize_dist_tags, validate_metadata, isObject, DIST_TAGS} from './utils';
import type {IStorage, IProxy, IStorageHandler, ProxyList} from '../../types';
import type {
Versions,
@ -26,7 +26,7 @@ import type {
import type {IReadTarball, IUploadTarball} from '@verdaccio/streams';
const LoggerApi = require('../lib/logger');
const WHITELIST = ['_rev', 'name', 'versions', 'dist-tags', 'readme', 'time'];
const WHITELIST = ['_rev', 'name', 'versions', DIST_TAGS, 'readme', 'time'];
const getDefaultMetadata = function(name): Package {
const pkgMetadata: Package = {
name,
@ -85,7 +85,7 @@ class Storage implements IStorageHandler {
return reject(err);
}
if (results) {
return reject(Utils.ErrorCode.get409('this package is already present'));
return reject(ErrorCode.get409('this package is already present'));
}
return resolve();
});
@ -106,7 +106,7 @@ class Storage implements IStorageHandler {
}
// checking package
if (results) {
return reject(Utils.ErrorCode.get409('this package is already present'));
return reject(ErrorCode.get409('this package is already present'));
}
for (let i = 0; i < err_results.length; i++) {
// checking error
@ -421,7 +421,7 @@ class Storage implements IStorageHandler {
}
}
Utils.normalize_dist_tags(result);
normalize_dist_tags(result);
// npm can throw if this field doesn't exist
result._attachments = {};
@ -501,7 +501,7 @@ class Storage implements IStorageHandler {
const getPackage = function(i) {
self.localStorage.getPackageMetadata(locals[i], function(err, info) {
if (_.isNil(err)) {
const latest = info['dist-tags'].latest;
const latest = info[DIST_TAGS].latest;
if (latest && info.versions[latest]) {
packages.push(info.versions[latest]);
@ -550,7 +550,7 @@ class Storage implements IStorageHandler {
const _options = Object.assign({}, options);
let upLinkMeta = packageInfo._uplinks[upLink.upname];
if (Utils.isObject(upLinkMeta)) {
if (isObject(upLinkMeta)) {
const fetched = upLinkMeta.fetched;
@ -572,7 +572,7 @@ class Storage implements IStorageHandler {
}
try {
Utils.validate_metadata(upLinkResponse, name);
validate_metadata(upLinkResponse, name);
} catch(err) {
self.logger.error({
sub: 'out',
@ -612,7 +612,7 @@ class Storage implements IStorageHandler {
}, (err: Error, upLinksErrors: any) => {
assert(!err && Array.isArray(upLinksErrors));
if (!exists) {
return callback( Utils.ErrorCode.get404('no such package available')
return callback( ErrorCode.get404('no such package available')
, null
, upLinksErrors );
}
@ -678,15 +678,12 @@ class Storage implements IStorageHandler {
}
}
// refresh dist-tags
const distTag = 'dist-tags';
for (let i in up[distTag]) {
if (local[distTag][i] !== up[distTag][i]) {
if (!local[distTag][i] || semver.lte(local[distTag][i], up[distTag][i])) {
local[distTag][i] = up[distTag][i];
for (let i in up[DIST_TAGS]) {
if (local[DIST_TAGS][i] !== up[DIST_TAGS][i]) {
if (!local[DIST_TAGS][i] || semver.lte(local[DIST_TAGS][i], up[DIST_TAGS][i])) {
local[DIST_TAGS][i] = up[DIST_TAGS][i];
}
if (i === 'latest' && local[distTag][i] === up[distTag][i]) {
if (i === 'latest' && local[DIST_TAGS][i] === up[DIST_TAGS][i]) {
// if remote has more fresh package, we should borrow its readme
local.readme = up.readme;
}

View file

@ -13,6 +13,8 @@ import type {$Request} from 'express';
const Logger = require('./logger');
export const DIST_TAGS = 'dist-tags';
/**
* Validate a package.
* @return {Boolean} whether the package is valid or not
@ -72,8 +74,8 @@ function validate_metadata(object: Package, name: string) {
assert(isObject(object), 'not a json object');
assert.equal(object.name, name);
if (!isObject(object['dist-tags'])) {
object['dist-tags'] = {};
if (!isObject(object[DIST_TAGS])) {
object[DIST_TAGS] = {};
}
if (!isObject(object['versions'])) {
@ -145,16 +147,16 @@ function filter_tarball_urls(pkg: Package, req: $Request, config: Config) {
*/
function tag_version(data: Package, version: string, tag: string) {
if (_.isEmpty(tag) === false) {
if (data['dist-tags'][tag] !== version) {
if (data[DIST_TAGS][tag] !== version) {
if (semver.parse(version, true)) {
// valid version - store
data['dist-tags'][tag] = version;
data[DIST_TAGS][tag] = version;
return true;
}
}
Logger.logger.warn({ver: version, tag: tag}, 'ignoring bad version @{ver} in @{tag}');
if (tag && data['dist-tags'][tag]) {
delete data['dist-tags'][tag];
if (tag && data[DIST_TAGS][tag]) {
delete data[DIST_TAGS][tag];
}
}
return false;
@ -246,31 +248,31 @@ function semverSort(listVersions: Array<string>) {
*/
function normalize_dist_tags(pkg: Package) {
let sorted;
if (!pkg['dist-tags'].latest) {
if (!pkg[DIST_TAGS].latest) {
// overwrite latest with highest known version based on semver sort
sorted = semverSort(Object.keys(pkg.versions));
if (sorted && sorted.length) {
pkg['dist-tags'].latest = sorted.pop();
pkg[DIST_TAGS].latest = sorted.pop();
}
}
for (let tag in pkg['dist-tags']) {
if (_.isArray(pkg['dist-tags'][tag])) {
if (pkg['dist-tags'][tag].length) {
for (let tag in pkg[DIST_TAGS]) {
if (_.isArray(pkg[DIST_TAGS][tag])) {
if (pkg[DIST_TAGS][tag].length) {
// sort array
// $FlowFixMe
sorted = semverSort(pkg['dist-tags'][tag]);
sorted = semverSort(pkg[DIST_TAGS][tag]);
if (sorted.length) {
// use highest version based on semver sort
pkg['dist-tags'][tag] = sorted.pop();
pkg[DIST_TAGS][tag] = sorted.pop();
}
} else {
delete pkg['dist-tags'][tag];
delete pkg[DIST_TAGS][tag];
}
} else if (_.isString(pkg['dist-tags'][tag] )) {
if (!semver.parse(pkg['dist-tags'][tag], true)) {
} else if (_.isString(pkg[DIST_TAGS][tag] )) {
if (!semver.parse(pkg[DIST_TAGS][tag], true)) {
// if the version is invalid, delete the dist-tag entry
delete pkg['dist-tags'][tag];
delete pkg[DIST_TAGS][tag];
}
}
}
@ -323,7 +325,7 @@ function getWebProtocol(req: $Request) {
}
const getLatestVersion = function(pkgInfo: Package) {
return pkgInfo['dist-tags'].latest;
return pkgInfo[DIST_TAGS].latest;
};
const ErrorCode = {