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:
parent
2ae80dd15e
commit
4f5443d857
4 changed files with 43 additions and 84 deletions
|
@ -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 && \
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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
BIN
yarn.lock
Binary file not shown.
Loading…
Reference in a new issue