1
0
mirror of https://github.com/verdaccio/verdaccio.git synced 2025-02-21 07:29:37 +01:00

Refactor, reduce eslint warnings, add doc

This commit is contained in:
Juan Picado 2017-05-20 08:56:06 +02:00
parent 93bea50176
commit 01dc7dc1d8
No known key found for this signature in database
GPG Key ID: 18AC54485952D158
4 changed files with 177 additions and 119 deletions

@ -1,6 +1,7 @@
#!/usr/bin/env node
/* eslint no-sync:0*/
/* eslint no-sync:0 */
/* eslint no-empty:0 */
'use strict';
if (process.getuid && process.getuid() === 0) {
@ -13,24 +14,24 @@ try {
// for debugging memory leaks
// totally optional
require('heapdump');
} catch(err) {}
} catch(err) { }
let logger = require('./logger');
const logger = require('./logger');
logger.setup(); // default setup
let commander = require('commander');
let constants = require('constants');
let fs = require('fs');
let http = require('http');
let https = require('https');
let YAML = require('js-yaml');
let Path = require('path');
let URL = require('url');
let server = require('./index');
let Utils = require('./utils');
let pkginfo = require('pkginfo')(module); // eslint-disable-line no-unused-vars
let pkgVersion = module.exports.version;
let pkgName = module.exports.name;
const commander = require('commander');
const constants = require('constants');
const fs = require('fs');
const http = require('http');
const https = require('https');
const YAML = require('js-yaml');
const Path = require('path');
const URL = require('url');
const server = require('./index');
const Utils = require('./utils');
const pkginfo = require('pkginfo')(module); // eslint-disable-line no-unused-vars
const pkgVersion = module.exports.version;
const pkgName = module.exports.name;
commander
.option('-l, --listen <[host:]port>', 'host:port number to listen on (default: localhost:4873)')
@ -71,6 +72,7 @@ afterConfigLoad();
* listen:
- localhost:5555
- localhost:5557
@return {Array}
*/
function get_listen_addresses() {
// command line || config file || default
@ -113,7 +115,6 @@ function afterConfigLoad() {
const app = server(config);
get_listen_addresses().forEach(function(addr) {
let webServer;
if (addr.proto === 'https') { // https
if (!config.https || !config.https.key || !config.https.cert || !config.https.ca) {
let conf_path = function(file) {
@ -128,7 +129,8 @@ function afterConfigLoad() {
'To quickly create self-signed certificate, use:',
' $ openssl genrsa -out ' + conf_path('verdaccio-key.pem') + ' 2048',
' $ openssl req -new -sha256 -key ' + conf_path('verdaccio-key.pem') + ' -out ' + conf_path('verdaccio-csr.pem'),
' $ openssl x509 -req -in ' + conf_path('verdaccio-csr.pem') + ' -signkey ' + conf_path('verdaccio-key.pem') + ' -out ' + conf_path('verdaccio-cert.pem'),
' $ openssl x509 -req -in ' + conf_path('verdaccio-csr.pem') +
' -signkey ' + conf_path('verdaccio-key.pem') + ' -out ' + conf_path('verdaccio-cert.pem'),
'',
'And then add to config file (' + conf_path() + '):',
' https:',
@ -186,7 +188,7 @@ function afterConfigLoad() {
}
process.on('uncaughtException', function(err) {
logger.logger.fatal( {err: err},
logger.logger.fatal( {err: err},
'uncaught exception, please report this\n@{err.stack}' );
process.exit(255);
});

@ -1,13 +1,15 @@
'use strict';
let fs = require('fs');
let Path = require('path');
let logger = require('./logger');
module.exports = find_config_file;
const fs = require('fs');
const Path = require('path');
const logger = require('./logger');
/**
*
* @return {String} the config file path
*/
function find_config_file() {
let paths = get_paths();
const paths = get_paths();
for (let i=0; i<paths.length; i++) {
if (file_exists(paths[i].path)) return paths[i].path;
@ -89,3 +91,4 @@ function file_exists(path) {
return stat.isFile();
}
module.exports = find_config_file;

@ -1,3 +1,5 @@
/* eslint prefer-rest-params: "off" */
/* eslint prefer-spread: "off" */
'use strict';
const assert = require('assert');
@ -16,7 +18,7 @@ const Utils = require('./utils');
const info_file = 'package.json';
// returns the minimal package file
function get_boilerplate(name) {
const get_boilerplate = function(name) {
return {
// standard things
'name': name,
@ -28,35 +30,40 @@ function get_boilerplate(name) {
'_attachments': {},
'_uplinks': {},
};
}
};
//
// Implements Storage interface
// (same for storage.js, local-storage.js, up-storage.js)
//
/**
* Implements Storage interface (same for storage.js, local-storage.js, up-storage.js).
*/
class Storage {
/**
* Constructor
* @param {Object} config config list of properties
*/
constructor(config) {
this.config = config;
this.logger = Logger.logger.child({sub: 'fs'});
}
/**
*
* Handle internal error
* @param {*} err
* @param {*} file
* @param {*} message
* @return {Object} Error instance
*/
_internal_error(err, file, message) {
this.logger.error( {err: err, file: file}
, message + ' @{file}: @{!err.message}' );
this.logger.error( {err: err, file: file},
message + ' @{file}: @{!err.message}' );
return Error[500]();
}
/**
*
* Add a package.
* @param {*} name
* @param {*} info
* @param {*} callback
* @return {Function}
*/
add_package(name, info, callback) {
let storage = this.storage(name);
@ -76,16 +83,19 @@ class Storage {
}
/**
*
* Remove package.
* @param {*} name
* @param {*} callback
* @return {Function}
*/
remove_package(name, callback) {
this.logger.info( {name: name}
, 'unpublishing @{name} (all)');
let storage = this.storage(name);
if (!storage) return callback( Error[404]('no such package available') );
if (!storage) {
return callback( Error[404]('no such package available') );
}
storage.read_json(info_file, (err, data) => {
if (err) {
@ -98,18 +108,22 @@ class Storage {
this._normalize_package(data);
storage.unlink(info_file, function(err) {
if (err) return callback(err);
if (err) {
return callback(err);
}
let files = Object.keys(data._attachments);
const files = Object.keys(data._attachments);
function unlinkNext(cb) {
if (files.length === 0) return cb();
const unlinkNext = function(cb) {
if (files.length === 0) {
return cb();
}
let file = files.shift();
storage.unlink(file, function() {
unlinkNext(cb);
});
}
};
unlinkNext(function() {
// try to unlink the directory, but ignore errors because it can fail
@ -125,12 +139,13 @@ class Storage {
}
/**
*
* Retrieve either a previous created local package or a boilerplate.
* @param {*} name
* @param {*} callback
* @return {Function}
*/
_read_create_package(name, callback) {
let storage = this.storage(name);
const storage = this.storage(name);
if (!storage) {
let data = get_boilerplate(name);
this._normalize_package(data);
@ -159,7 +174,9 @@ class Storage {
*/
update_versions(name, newdata, callback) {
this._read_create_package(name, (err, data) => {
if (err) return callback(err);
if (err) {
return callback(err);
}
let change = false;
for (let ver in newdata.versions) {
@ -206,13 +223,15 @@ class Storage {
}
}
for (let up in newdata._uplinks) {
let need_change = !Utils.is_object(data._uplinks[up])
|| newdata._uplinks[up].etag !== data._uplinks[up].etag
|| newdata._uplinks[up].fetched !== data._uplinks[up].fetched;
if (Object.prototype.hasOwnProperty.call(newdata._uplinks, up)) {
const need_change = !Utils.is_object(data._uplinks[up])
|| newdata._uplinks[up].etag !== data._uplinks[up].etag
|| newdata._uplinks[up].fetched !== data._uplinks[up].fetched;
if (need_change) {
change = true;
data._uplinks[up] = newdata._uplinks[up];
if (need_change) {
change = true;
data._uplinks[up] = newdata._uplinks[up];
}
}
}
if (newdata.readme !== data.readme) {
@ -232,7 +251,7 @@ class Storage {
}
/**
*
* Add a new version to a previous local package.
* @param {*} name
* @param {*} version
* @param {*} metadata
@ -272,7 +291,7 @@ class Storage {
}
/**
*
* Merge a new list of tags for a local packages with the existing one.
* @param {*} name
* @param {*} tags
* @param {*} callback
@ -284,7 +303,7 @@ class Storage {
delete data['dist-tags'][t];
continue;
}
// be careful here with == (cast)
if (data.versions[tags[t]] == null) {
return cb( Error[404]('this version doesn\'t exist') );
}
@ -295,8 +314,8 @@ class Storage {
}, callback);
}
/**
*
/**
* Replace the complete list of tags for a local package.
* @param {*} name
* @param {*} tags
* @param {*} callback
@ -322,11 +341,13 @@ class Storage {
}
/**
* Currently supports unpublishing only
* Update the package metadata, tags and attachments (tarballs).
* Note: Currently supports unpublishing only.
* @param {*} name
* @param {*} metadata
* @param {*} revision
* @param {*} callback
* @return {Function}
*/
change_package(name, metadata, revision, callback) {
if (!Utils.is_object(metadata.versions) || !Utils.is_object(metadata['dist-tags'])) {
@ -336,10 +357,9 @@ class Storage {
this.update_package(name, (data, cb) => {
for (let ver in data.versions) {
if (metadata.versions[ver] == null) {
this.logger.info( {name: name, version: ver}
, 'unpublishing @{name}@@{version}');
this.logger.info( {name: name, version: ver},
'unpublishing @{name}@@{version}');
delete data.versions[ver];
for (let file in data._attachments) {
if (data._attachments[file].version === ver) {
delete data._attachments[file].version;
@ -350,13 +370,15 @@ class Storage {
data['dist-tags'] = metadata['dist-tags'];
cb();
}, function(err) {
if (err) return callback(err);
if (err) {
return callback(err);
}
callback();
});
}
/**
*
* Remove a tarball.
* @param {*} name
* @param {*} filename
* @param {*} revision
@ -384,9 +406,10 @@ class Storage {
}
/**
*
* @param {*} name
* @param {*} filename
* Add a tarball.
* @param {String} name
* @param {String} filename
* @return {Function}
*/
add_tarball(name, filename) {
assert(Utils.validate_name(filename));
@ -473,28 +496,29 @@ class Storage {
}
/**
*
* Get a tarball.
* @param {*} name
* @param {*} filename
* @param {*} callback
* @return {Function}
*/
get_tarball(name, filename, callback) {
assert(Utils.validate_name(filename));
let self = this;
let stream = MyStreams.readTarballStream();
const stream = MyStreams.readTarballStream();
stream.abort = function() {
if (rstream) rstream.abort();
if (rstream) {
rstream.abort();
}
};
let storage = self.storage(name);
let storage = this.storage(name);
if (!storage) {
process.nextTick(function() {
stream.emit('error', Error[404]('no such file available'));
});
return stream;
}
/* eslint no-var: "off" */
var rstream = storage.read_stream(filename);
rstream.on('error', function(err) {
if (err && err.code === 'ENOENT') {
@ -515,10 +539,11 @@ class Storage {
}
/**
*
* Retrieve a package by name.
* @param {*} name
* @param {*} options
* @param {*} callback
* @return {Function}
*/
get_package(name, options, callback) {
if (typeof(options) === 'function') {
@ -526,7 +551,9 @@ class Storage {
}
let storage = this.storage(name);
if (!storage) return callback( Error[404]('no such package available') );
if (!storage) {
return callback( Error[404]('no such package available') );
}
storage.read_json(info_file, (err, result) => {
if (err) {
@ -542,7 +569,7 @@ class Storage {
}
/**
* Walks through each package and calls `on_package` on them
* Walks through each package and calls `on_package` on them.
* @param {*} on_package
* @param {*} on_end
*/
@ -550,7 +577,6 @@ class Storage {
let storages = {};
storages[this.config.storage] = true;
if (this.config.packages) {
Object.keys(this.packages || {}).map( (pkg) => {
if (this.config.packages[pkg].storage) {
@ -562,13 +588,17 @@ class Storage {
async.eachSeries(Object.keys(storages), function(storage, cb) {
fs.readdir(Path.resolve(base, storage), function(err, files) {
if (err) return cb(err);
if (err) {
return cb(err);
}
async.eachSeries(files, function(file, cb) {
if (file.match(/^@/)) {
// scoped
fs.readdir(Path.resolve(base, storage, file), function(err, files) {
if (err) return cb(err);
if (err) {
return cb(err);
}
async.eachSeries(files, function(file2, cb) {
if (Utils.validate_name(file2)) {
@ -606,16 +636,18 @@ class Storage {
* @param {*} name package name
* @param {*} updateFn function(package, cb) - update function
* @param {*} _callback callback that gets invoked after it's all updated
* @return {Function}
*/
update_package(name, updateFn, _callback) {
let self = this;
let storage = self.storage(name);
if (!storage) return _callback( Error[404]('no such package available') );
storage.lock_and_read_json(info_file, function(err, json) {
const storage = this.storage(name);
if (!storage) {
return _callback( Error[404]('no such package available') );
}
storage.lock_and_read_json(info_file, (err, json) => {
let locked = false;
// callback that cleans up lock first
function callback(err) {
const callback = function(err) {
let _args = arguments;
if (locked) {
storage.unlock_file(info_file, function() {
@ -625,7 +657,7 @@ class Storage {
} else {
_callback.apply(null, _args);
}
}
};
if (!err) {
locked = true;
@ -641,19 +673,21 @@ class Storage {
}
}
self._normalize_package(json);
updateFn(json, function(err) {
if (err) return callback(err);
self._write_package(name, json, callback);
this._normalize_package(json);
updateFn(json, (err) => {
if (err) {
return callback(err);
}
this._write_package(name, json, callback);
});
});
}
/**
*
* Search a local package.
* @param {*} startkey
* @param {*} options
* @return {Function}
*/
search(startkey, options) {
const stream = new Stream.PassThrough({objectMode: true});
@ -709,12 +743,14 @@ class Storage {
}
/**
*
* @param {*} pkg
* Normalise package properties, tags, revision id.
* @param {Object} pkg package reference.
*/
_normalize_package(pkg) {
['versions', 'dist-tags', '_distfiles', '_attachments', '_uplinks'].forEach(function(key) {
if (!Utils.is_object(pkg[key])) pkg[key] = {};
if (!Utils.is_object(pkg[key])) {
pkg[key] = {};
}
});
if (typeof(pkg._rev) !== 'string') {
pkg._rev = '0-0000000000000000';
@ -724,10 +760,11 @@ class Storage {
}
/**
*
* Update the revision (_rev) string for a package.
* @param {*} name
* @param {*} json
* @param {*} callback
* @return {Function}
*/
_write_package(name, json, callback) {
// calculate revision a la couchdb
@ -738,13 +775,16 @@ class Storage {
json._rev = ((+rev[0] || 0) + 1) + '-' + Crypto.pseudoRandomBytes(8).toString('hex');
let storage = this.storage(name);
if (!storage) return callback();
if (!storage) {
return callback();
}
storage.write_json(info_file, json, callback);
}
/**
*
* @param {*} pkg
* Retrieve a wrapper that provide access to the package location.
* @param {*} pkg package name.
* @return {Object}
*/
storage(pkg) {
let path = this.config.get_package_spec(pkg).storage;
@ -756,7 +796,7 @@ class Storage {
, 'this package has no storage defined: @{name}' );
return null;
}
return Path_Wrapper(
return new PathWrapper(
Path.join(
Path.resolve(Path.dirname(this.config.self_path || ''), path),
pkg
@ -765,26 +805,33 @@ class Storage {
}
}
var Path_Wrapper = (function() {
// a wrapper adding paths to fs_storage methods
function Wrapper(path) {
let self = Object.create(Wrapper.prototype);
self.path = path;
return self;
}
const PathWrapper = (function() {
/**
* A wrapper adding paths to fs_storage methods.
*/
class Wrapper {
for (let i in fs_storage) {
if (fs_storage.hasOwnProperty(i)) {
Wrapper.prototype[i] = wrapper(i);
/**
* @param {*} path
*/
constructor(path) {
this.path = path;
}
}
function wrapper(method) {
return function(/* ...*/) {
const wrapLocalStorageMethods = function(method) {
return function() {
let args = Array.prototype.slice.apply(arguments);
/* eslint no-invalid-this: off */
args[0] = Path.join(this.path, args[0] || '');
return fs_storage[method].apply(null, args);
};
};
for (let i in fs_storage) {
if (fs_storage.hasOwnProperty(i)) {
Wrapper.prototype[i] = wrapLocalStorageMethods(i);
}
}
return Wrapper;

@ -1,9 +1,11 @@
/* eslint prefer-rest-params: "off" */
'use strict';
let crypto = require('crypto');
let Error = require('http-errors');
let utils = require('./utils');
let Logger = require('./logger');
const crypto = require('crypto');
const Error = require('http-errors');
const utils = require('./utils');
const Logger = require('./logger');
module.exports.match = function match(regexp) {
return function(req, res, next, value, name) {
@ -71,9 +73,13 @@ module.exports.anti_loop = function(config) {
};
};
// express doesn't do etags with requests <= 1024b
// we use md5 here, it works well on 1k+ bytes, but sucks with fewer data
// could improve performance using crc32 after benchmarks
/**
* Express doesn't do etags with requests <= 1024b
* we use md5 here, it works well on 1k+ bytes, but sucks with fewer data
* could improve performance using crc32 after benchmarks.
* @param {Object} data
* @return {String}
*/
function md5sum(data) {
return crypto.createHash('md5').update(data).digest('hex');
}
@ -168,7 +174,7 @@ module.exports.log = function(req, res, next) {
_write.apply(res, arguments);
};
function log() {
const log = function() {
let message = '@{status}, user: @{user}, req: \'@{request.method} @{request.url}\'';
if (res._verdaccio_error) {
message += ', error: @{!error}';
@ -189,7 +195,7 @@ module.exports.log = function(req, res, next) {
},
}, message);
req.originalUrl = req.url;
}
};
req.on('close', function() {
log(true);