0
Fork 0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-12-30 22:34:10 -05:00

refactor: remove locking files from local-storage, update to minor versions local-storage and types

This commit is contained in:
Juan Picado @jotadeveloper 2017-12-21 09:44:57 +01:00 committed by juanpicado
parent 2ae80dd15e
commit 4f5443d857
4 changed files with 43 additions and 84 deletions

View file

@ -19,7 +19,7 @@ ADD . $APPDIR
ENV NODE_ENV=production ENV NODE_ENV=production
RUN npm config set registry http://registry.npmjs.org/ && \ RUN npm config set registry http://registry.npmjs.org/ && \
yarn global add -s flow-bin@0.60.0 && \ yarn global add -s flow-bin@0.52.0 && \
yarn install --production=false && \ yarn install --production=false && \
yarn run lint && \ yarn run lint && \
yarn run code:build && \ yarn run code:build && \

View file

@ -16,9 +16,9 @@
}, },
"dependencies": { "dependencies": {
"@verdaccio/file-locking": "^0.0.5", "@verdaccio/file-locking": "^0.0.5",
"@verdaccio/local-storage": "^0.0.14", "@verdaccio/local-storage": "^0.1.0",
"@verdaccio/streams": "^0.0.2", "@verdaccio/streams": "^0.0.2",
"@verdaccio/types": "^0.0.10", "@verdaccio/types": "^0.1.0",
"JSONStream": "^1.1.1", "JSONStream": "^1.1.1",
"apache-md5": "^1.1.2", "apache-md5": "^1.1.2",
"async": "^2.6.0", "async": "^2.6.0",

View file

@ -14,7 +14,7 @@ import async from 'async';
import * as Utils from './utils'; import * as Utils from './utils';
import { import {
generatePackageTemplate, normalizePackage, generateRevision, cleanUpReadme, generatePackageTemplate, normalizePackage, generateRevision, cleanUpReadme,
fileExist, noSuchFile, resourceNotAvailable, DEFAULT_REVISION, pkgFileName, fileExist, noSuchFile, DEFAULT_REVISION, pkgFileName,
} from './storage-utils'; } from './storage-utils';
import LocalDatabase from '@verdaccio/local-storage'; import LocalDatabase from '@verdaccio/local-storage';
@ -30,8 +30,8 @@ import type {
Logger, Logger,
} from '@verdaccio/types'; } from '@verdaccio/types';
import type { import type {
ILocalFS,
ILocalData, ILocalData,
IPackageStorage,
} from '@verdaccio/local-storage'; } from '@verdaccio/local-storage';
/** /**
@ -50,13 +50,13 @@ class LocalStorage implements IStorage {
} }
addPackage(name: string, pkg: Package, callback: Callback) { addPackage(name: string, pkg: Package, callback: Callback) {
const storage: ILocalFS = this._getLocalStorage(name); const storage: IPackageStorage = this._getLocalStorage(name);
if (_.isNil(storage)) { if (_.isNil(storage)) {
return callback( Utils.ErrorCode.get404('this package cannot be added')); return callback( Utils.ErrorCode.get404('this package cannot be added'));
} }
storage.createJSON(pkgFileName, generatePackageTemplate(name), (err) => { storage.createPackage(pkgFileName, generatePackageTemplate(name), (err) => {
if (_.isNull(err) === false && err.code === fileExist) { if (_.isNull(err) === false && err.code === fileExist) {
return callback( Utils.ErrorCode.get409()); return callback( Utils.ErrorCode.get409());
} }
@ -77,13 +77,13 @@ class LocalStorage implements IStorage {
* @return {Function} * @return {Function}
*/ */
removePackage(name: string, callback: Callback) { removePackage(name: string, callback: Callback) {
let storage: ILocalFS = this._getLocalStorage(name); let storage: IPackageStorage = this._getLocalStorage(name);
if (_.isNil(storage)) { if (_.isNil(storage)) {
return callback( Utils.ErrorCode.get404()); return callback( Utils.ErrorCode.get404());
} }
storage.readJSON(pkgFileName, (err, data) => { storage.readPackage(pkgFileName, (err, data) => {
if (_.isNil(err) === false) { if (_.isNil(err) === false) {
if (err.code === noSuchFile) { if (err.code === noSuchFile) {
return callback( Utils.ErrorCode.get404()); return callback( Utils.ErrorCode.get404());
@ -101,7 +101,7 @@ class LocalStorage implements IStorage {
return callback(Utils.ErrorCode.get422(removeFailed.message)); return callback(Utils.ErrorCode.get422(removeFailed.message));
} }
storage.deleteJSON(pkgFileName, (err) => { storage.deletePackage(pkgFileName, (err) => {
if (err) { if (err) {
return callback(err); return callback(err);
} }
@ -367,7 +367,7 @@ class LocalStorage implements IStorage {
const storage = this._getLocalStorage(name); const storage = this._getLocalStorage(name);
if (storage) { if (storage) {
storage.deleteJSON(filename, callback); storage.deletePackage(filename, callback);
} }
}); });
} }
@ -410,7 +410,7 @@ class LocalStorage implements IStorage {
return uploadStream; return uploadStream;
} }
const writeStream = storage.createWriteStream(filename); const writeStream = storage.writeTarball(filename);
writeStream.on('error', (err) => { writeStream.on('error', (err) => {
if (err.code === fileExist) { if (err.code === fileExist) {
@ -476,7 +476,7 @@ class LocalStorage implements IStorage {
getTarball(name: string, filename: string) { getTarball(name: string, filename: string) {
assert(Utils.validate_name(filename)); assert(Utils.validate_name(filename));
const storage: ILocalFS = this._getLocalStorage(name); const storage: IPackageStorage = this._getLocalStorage(name);
if (_.isNil(storage)) { if (_.isNil(storage)) {
return this._createFailureStreamResponse(); return this._createFailureStreamResponse();
@ -506,9 +506,9 @@ class LocalStorage implements IStorage {
* @private * @private
* @return {ReadTarball} * @return {ReadTarball}
*/ */
_streamSuccessReadTarBall(storage: ILocalFS, filename: string) { _streamSuccessReadTarBall(storage: IPackageStorage, filename: string) {
const stream = new ReadTarball(); const stream = new ReadTarball();
const readTarballStream = storage.createReadStream(filename); const readTarballStream = storage.readTarball(filename);
const e404 = Utils.ErrorCode.get404; const e404 = Utils.ErrorCode.get404;
stream.abort = function() { stream.abort = function() {
@ -546,7 +546,7 @@ class LocalStorage implements IStorage {
*/ */
getPackageMetadata(name: string, callback?: Callback = () => {}): void { getPackageMetadata(name: string, callback?: Callback = () => {}): void {
const storage = this._getLocalStorage(name); const storage: IPackageStorage = this._getLocalStorage(name);
if (_.isNil(storage)) { if (_.isNil(storage)) {
return callback( Utils.ErrorCode.get404() ); return callback( Utils.ErrorCode.get404() );
} }
@ -622,12 +622,12 @@ class LocalStorage implements IStorage {
* @param {Object} packageInfo package name. * @param {Object} packageInfo package name.
* @return {Object} * @return {Object}
*/ */
_getLocalStorage(packageInfo: string): any { _getLocalStorage(packageInfo: string): IPackageStorage {
const path = this.__getLocalStoragePath(this.config.getMatchedPackagesSpec(packageInfo).storage); const path: string = this.__getLocalStoragePath(this.config.getMatchedPackagesSpec(packageInfo).storage);
if (_.isNil(path) || path === false) { if (_.isString(path) === false) {
this.logger.debug( {name: packageInfo}, 'this package has no storage defined: @{name}' ); this.logger.debug( {name: packageInfo}, 'this package has no storage defined: @{name}' );
return null; return;
} }
return this.localData.getPackageStorage(packageInfo, path); return this.localData.getPackageStorage(packageInfo, path);
@ -638,8 +638,8 @@ class LocalStorage implements IStorage {
* @param {Object} storage * @param {Object} storage
* @param {Function} callback * @param {Function} callback
*/ */
_readJSON(storage: ILocalFS, callback: Callback) { _readJSON(storage: IPackageStorage, callback: Callback) {
storage.readJSON(pkgFileName, (err, result) => { storage.readPackage(pkgFileName, (err, result) => {
if (err) { if (err) {
if (err.code === noSuchFile) { if (err.code === noSuchFile) {
return callback( Utils.ErrorCode.get404() ); return callback( Utils.ErrorCode.get404() );
@ -669,9 +669,9 @@ class LocalStorage implements IStorage {
/** /**
* Walks through each package and calls `on_package` on them. * Walks through each package and calls `on_package` on them.
* @param {*} onPackage * @param {*} onPackage
* @param {*} on_end * @param {*} onEnd
*/ */
_eachPackage(onPackage: Callback, on_end: Callback) { _eachPackage(onPackage: Callback, onEnd: Callback) {
const storages = {}; const storages = {};
storages[this.config.storage] = true; storages[this.config.storage] = true;
@ -719,7 +719,7 @@ class LocalStorage implements IStorage {
} }
}, cb); }, cb);
}); });
}, on_end); }, onEnd);
} }
/** /**
@ -729,12 +729,12 @@ class LocalStorage implements IStorage {
* @return {Function} * @return {Function}
*/ */
_readCreatePackage(name: string, callback: Callback) { _readCreatePackage(name: string, callback: Callback) {
const storage: ILocalFS = this._getLocalStorage(name); const storage: IPackageStorage = this._getLocalStorage(name);
if (_.isNil(storage)) { if (_.isNil(storage)) {
return this._createNewPackage(name, callback); return this._createNewPackage(name, callback);
} }
storage.readJSON(pkgFileName, (err, data) => { storage.readPackage(pkgFileName, (err, data) => {
// TODO: race condition // TODO: race condition
if (_.isNil(err) === false) { if (_.isNil(err) === false) {
if (err.code === noSuchFile) { if (err.code === noSuchFile) {
@ -766,65 +766,20 @@ class LocalStorage implements IStorage {
} }
/** /**
* This function allows to update the package thread-safely
Algorithm:
1. lock package.json for writing
2. read package.json
3. updateFn(pkg, cb), and wait for cb
4. write package.json.tmp
5. move package.json.tmp package.json
6. callback(err?)
* @param {*} name package name * @param {*} name package name
* @param {*} updateFn function(package, cb) - update function * @param {*} updateHandler function(package, cb) - update function
* @param {*} callback callback that gets invoked after it's all updated * @param {*} callback callback that gets invoked after it's all updated
* @return {Function} * @return {Function}
*/ */
_updatePackage(name: string, updateFn: Callback, callback: Callback) { _updatePackage(name: string, updateHandler: Callback, callback: Callback) {
const storage: ILocalFS = this._getLocalStorage(name); const storage: IPackageStorage = this._getLocalStorage(name);
if (!storage) { if (!storage) {
return callback( Utils.ErrorCode.get404() ); return callback( Utils.ErrorCode.get404() );
} }
storage.lockAndReadJSON(pkgFileName, (err, json) => { storage.updatePackage(name, updateHandler, this._writePackage.bind(this), normalizePackage,
let locked = false; callback);
// callback that cleans up lock first
const lockCallback = function(err: Error) {
let _args = arguments;
if (locked) {
storage.unlockJSON(pkgFileName, function() {
// ignore any error from the unlock
callback.apply(err, _args);
});
} else {
callback(..._args);
}
};
if (!err) {
locked = true;
}
if (err) {
if (err.code === resourceNotAvailable) {
return lockCallback( Utils.ErrorCode.get503() );
} else if (err.code === noSuchFile) {
return lockCallback( Utils.ErrorCode.get404() );
} else {
return lockCallback(err);
}
}
json = normalizePackage(json);
updateFn(json, (err) => {
if (err) {
return lockCallback(err);
}
this._writePackage(name, json, lockCallback);
});
});
} }
/** /**
@ -835,6 +790,14 @@ class LocalStorage implements IStorage {
* @return {Function} * @return {Function}
*/ */
_writePackage(name: string, json: Package, callback: Callback) { _writePackage(name: string, json: Package, callback: Callback) {
const storage: IPackageStorage = this._getLocalStorage(name);
if (_.isNil(storage)) {
return callback();
}
storage.savePackage(pkgFileName, this._setDefaultRevision(json), callback);
}
_setDefaultRevision(json: Package) {
// calculate revision a la couchdb // calculate revision a la couchdb
if (_.isString(json._rev) === false) { if (_.isString(json._rev) === false) {
json._rev = DEFAULT_REVISION; json._rev = DEFAULT_REVISION;
@ -842,21 +805,17 @@ class LocalStorage implements IStorage {
json._rev = generateRevision(json._rev); json._rev = generateRevision(json._rev);
let storage: ILocalFS = this._getLocalStorage(name); return json;
if (_.isNil(storage)) {
return callback();
}
storage.writeJSON(pkgFileName, json, callback);
} }
_deleteAttachments(storage: ILocalFS, attachments: string[], callback: Callback): void { _deleteAttachments(storage: IPackageStorage, attachments: string[], callback: Callback): void {
const unlinkNext = function(cb) { const unlinkNext = function(cb) {
if (_.isEmpty(attachments)) { if (_.isEmpty(attachments)) {
return cb(); return cb();
} }
const attachment = attachments.shift(); const attachment = attachments.shift();
storage.deleteJSON(attachment, function() { storage.deletePackage(attachment, function() {
unlinkNext(cb); unlinkNext(cb);
}); });
}; };

BIN
yarn.lock

Binary file not shown.