mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
fs interface refactoring
This commit is contained in:
parent
d519e8e763
commit
68d3cc7295
4 changed files with 92 additions and 108 deletions
|
@ -47,7 +47,7 @@ function Config(config) {
|
|||
for (var i in this.users) {
|
||||
assert(this.users[i].password, 'CONFIG: no password for user: ' + i)
|
||||
assert(
|
||||
typeof(this.users[i].password) === 'string' &&
|
||||
typeof(this.users[i].password) === 'string' &&
|
||||
this.users[i].password.match(/^[a-f0-9]{40}$/)
|
||||
, 'CONFIG: wrong password format for user: ' + i + ', sha1 expected')
|
||||
}
|
||||
|
@ -113,15 +113,10 @@ function Config(config) {
|
|||
}
|
||||
|
||||
function allow_action(package, who, action) {
|
||||
for (var i in this.packages) {
|
||||
if (minimatch.makeRe(i).exec(package)) {
|
||||
return this.packages[i][action].reduce(function(prev, curr) {
|
||||
if (curr === String(who) || curr === 'all') return true
|
||||
return prev
|
||||
}, false)
|
||||
}
|
||||
}
|
||||
return false
|
||||
return (this.get_package_setting(package, action) || []).reduce(function(prev, curr) {
|
||||
if (curr === String(who) || curr === 'all') return true
|
||||
return prev
|
||||
}, false)
|
||||
}
|
||||
|
||||
Config.prototype.allow_access = function(package, user) {
|
||||
|
@ -140,6 +135,15 @@ Config.prototype.proxy_publish = function(package, uplink) {
|
|||
return allow_action.call(this, package, uplink, 'proxy_publish')
|
||||
}
|
||||
|
||||
Config.prototype.get_package_setting = function(package, setting) {
|
||||
for (var i in this.packages) {
|
||||
if (minimatch.makeRe(i).exec(package)) {
|
||||
return this.packages[i][setting]
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
Config.prototype.authenticate = function(user, password) {
|
||||
if (this.users[user] == null) return false
|
||||
return crypto.createHash('sha1').update(password).digest('hex') === this.users[user].password
|
||||
|
|
100
lib/local-fs.js
100
lib/local-fs.js
|
@ -1,24 +1,10 @@
|
|||
var fs = require('fs')
|
||||
, fsExt = require('fs-ext')
|
||||
, Path = require('path')
|
||||
, mkdirp = require('mkdirp')
|
||||
, mystreams = require('./streams')
|
||||
, Logger = require('./logger')
|
||||
, FSError = require('./error').FSError
|
||||
|
||||
function make_directories(dest, cb) {
|
||||
var dir = Path.dirname(dest)
|
||||
if (dir === '.' || dir === '..') return cb()
|
||||
fs.mkdir(dir, function(err) {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
make_directories(dir, function() {
|
||||
fs.mkdir(dir, cb)
|
||||
})
|
||||
} else {
|
||||
cb()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function write(dest, data, cb) {
|
||||
var safe_write = function(cb) {
|
||||
var tmpname = dest + '.tmp' + String(Math.random()).substr(2)
|
||||
|
@ -30,7 +16,8 @@ function write(dest, data, cb) {
|
|||
|
||||
safe_write(function(err) {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
make_directories(dest, function() {
|
||||
mkdirp(Path.dirname(dest), function(err) {
|
||||
if (err) return cb(err)
|
||||
safe_write(cb)
|
||||
})
|
||||
} else {
|
||||
|
@ -137,7 +124,7 @@ function open_flock(name, opmod, flmod, tries, backoff, cb) {
|
|||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// this function neither unlocks file nor closes it
|
||||
// it'll have to be done manually later
|
||||
|
@ -158,23 +145,10 @@ function lock_and_read(name, callback) {
|
|||
})
|
||||
}
|
||||
|
||||
function Storage(path) {
|
||||
this.path = path
|
||||
this.logger = Logger.logger.child({sub: 'fs'})
|
||||
try {
|
||||
fs.mkdirSync(path)
|
||||
this.logger.warn({path: path}, 'created new packages directory: @{path}')
|
||||
} catch(err) {
|
||||
if (err.code !== 'EEXIST') throw new Error(err)
|
||||
}
|
||||
}
|
||||
module.exports.read = read
|
||||
|
||||
Storage.prototype.read = function(name, cb) {
|
||||
read(this.path + '/' + name, cb)
|
||||
}
|
||||
|
||||
Storage.prototype.read_json = function(name, cb) {
|
||||
read(this.path + '/' + name, function(err, res) {
|
||||
module.exports.read_json = function(name, cb) {
|
||||
read(name, function(err, res) {
|
||||
if (err) return cb(err)
|
||||
|
||||
var args = []
|
||||
|
@ -187,12 +161,10 @@ Storage.prototype.read_json = function(name, cb) {
|
|||
})
|
||||
}
|
||||
|
||||
Storage.prototype.lock_and_read = function(name, cb) {
|
||||
lock_and_read(this.path + '/' + name, cb)
|
||||
}
|
||||
module.exports.lock_and_read = lock_and_read
|
||||
|
||||
Storage.prototype.lock_and_read_json = function(name, cb) {
|
||||
lock_and_read(this.path + '/' + name, function(err, fd, res) {
|
||||
module.exports.lock_and_read_json = function(name, cb) {
|
||||
lock_and_read(name, function(err, fd, res) {
|
||||
if (err) return cb(err, fd)
|
||||
|
||||
var args = []
|
||||
|
@ -205,49 +177,29 @@ Storage.prototype.lock_and_read_json = function(name, cb) {
|
|||
})
|
||||
}
|
||||
|
||||
Storage.prototype.path_to = function(file) {
|
||||
return this.path + '/' + file
|
||||
module.exports.create = create
|
||||
|
||||
module.exports.create_json = function(name, value, cb) {
|
||||
create(name, JSON.stringify(value, null, '\t'), cb)
|
||||
}
|
||||
|
||||
Storage.prototype.create = function(name, value, cb) {
|
||||
create(this.path + '/' + name, value, cb)
|
||||
module.exports.update = update
|
||||
|
||||
module.exports.update_json = function(name, value, cb) {
|
||||
update(name, JSON.stringify(value, null, '\t'), cb)
|
||||
}
|
||||
|
||||
Storage.prototype.create_json = function(name, value, cb) {
|
||||
create(this.path + '/' + name, JSON.stringify(value, null, '\t'), cb)
|
||||
module.exports.write = write
|
||||
|
||||
module.exports.write_json = function(name, value, cb) {
|
||||
write(name, JSON.stringify(value, null, '\t'), cb)
|
||||
}
|
||||
|
||||
Storage.prototype.update = function(name, value, cb) {
|
||||
update(this.path + '/' + name, value, cb)
|
||||
}
|
||||
module.exports.write_stream = write_stream
|
||||
|
||||
Storage.prototype.update_json = function(name, value, cb) {
|
||||
update(this.path + '/' + name, JSON.stringify(value, null, '\t'), cb)
|
||||
}
|
||||
module.exports.read_stream = read_stream
|
||||
|
||||
Storage.prototype.write = function(name, value, cb) {
|
||||
write(this.path + '/' + name, value, cb)
|
||||
}
|
||||
module.exports.unlink = fs.unlink
|
||||
|
||||
Storage.prototype.write_json = function(name, value, cb) {
|
||||
write(this.path + '/' + name, JSON.stringify(value, null, '\t'), cb)
|
||||
}
|
||||
|
||||
Storage.prototype.write_stream = function(name, value, cb) {
|
||||
return write_stream(this.path + '/' + name, value, cb)
|
||||
}
|
||||
|
||||
Storage.prototype.read_stream = function(name, cb) {
|
||||
return read_stream(this.path + '/' + name, cb)
|
||||
}
|
||||
|
||||
Storage.prototype.unlink = function(name, cb) {
|
||||
fs.unlink(this.path + '/' + name, cb)
|
||||
}
|
||||
|
||||
Storage.prototype.rmdir = function(name, cb) {
|
||||
fs.rmdir(this.path + '/' + name, cb)
|
||||
}
|
||||
|
||||
module.exports = Storage
|
||||
module.exports.rmdir = fs.rmdir
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ var fs = require('fs')
|
|||
, Path = require('path')
|
||||
, crypto = require('crypto')
|
||||
, assert = require('assert')
|
||||
, FS_Storage = require('./local-fs')
|
||||
, fs_storage = require('./local-fs')
|
||||
, UError = require('./error').UserError
|
||||
, utils = require('./utils')
|
||||
, mystreams = require('./streams')
|
||||
|
@ -16,8 +16,6 @@ var fs = require('fs')
|
|||
function Storage(config) {
|
||||
if (!(this instanceof Storage)) return new Storage(config)
|
||||
this.config = config
|
||||
var path = Path.resolve(Path.dirname(this.config.self_path), this.config.storage)
|
||||
this.storage = new FS_Storage(path)
|
||||
this.logger = Logger.logger.child({sub: 'fs'})
|
||||
return this
|
||||
}
|
||||
|
@ -38,7 +36,7 @@ function get_boilerplate(name) {
|
|||
}
|
||||
|
||||
Storage.prototype._internal_error = function(err, file, msg) {
|
||||
this.logger.error( {err: err, file: this.storage.path_to(file)}
|
||||
this.logger.error( {err: err, file: file}
|
||||
, msg + ' @{file}: @{!err.message}'
|
||||
)
|
||||
return new UError({
|
||||
|
@ -48,7 +46,7 @@ Storage.prototype._internal_error = function(err, file, msg) {
|
|||
}
|
||||
|
||||
Storage.prototype.add_package = function(name, metadata, callback) {
|
||||
this.storage.create_json(name + '/' + info_file, get_boilerplate(name), function(err) {
|
||||
this.storage(name).create_json(info_file, get_boilerplate(name), function(err) {
|
||||
if (err && err.code === 'EEXISTS') {
|
||||
return callback(new UError({
|
||||
status: 409,
|
||||
|
@ -62,7 +60,7 @@ Storage.prototype.add_package = function(name, metadata, callback) {
|
|||
Storage.prototype.remove_package = function(name, callback) {
|
||||
var self = this
|
||||
self.logger.info({name: name}, 'unpublishing @{name} (all)')
|
||||
self.storage.read_json(name + '/' + info_file, function(err, data) {
|
||||
self.storage(name).read_json(info_file, function(err, data) {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return callback(new UError({
|
||||
|
@ -75,7 +73,7 @@ Storage.prototype.remove_package = function(name, callback) {
|
|||
}
|
||||
self._normalize_package(data)
|
||||
|
||||
self.storage.unlink(name + '/' + info_file, function(err) {
|
||||
self.storage(name).unlink(info_file, function(err) {
|
||||
if (err) return callback(err)
|
||||
|
||||
var files = Object.keys(data._attachments)
|
||||
|
@ -84,14 +82,14 @@ Storage.prototype.remove_package = function(name, callback) {
|
|||
if (files.length === 0) return cb()
|
||||
|
||||
var file = files.shift()
|
||||
self.storage.unlink(name + '/' + file, function() {
|
||||
self.storage(name).unlink(file, function() {
|
||||
unlinkNext(cb)
|
||||
})
|
||||
}
|
||||
|
||||
unlinkNext(function() {
|
||||
// try to unlink the directory, but ignore errors because it can fail
|
||||
self.storage.rmdir(name, function(err) {
|
||||
self.storage(name).rmdir('.', function(err) {
|
||||
callback()
|
||||
})
|
||||
})
|
||||
|
@ -101,15 +99,14 @@ Storage.prototype.remove_package = function(name, callback) {
|
|||
|
||||
Storage.prototype._read_create_package = function(name, callback) {
|
||||
var self = this
|
||||
, file = name + '/' + info_file
|
||||
self.storage.read_json(file, function(err, data) {
|
||||
self.storage(name).read_json(info_file, function(err, data) {
|
||||
// TODO: race condition
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
// if package doesn't exist, we create it here
|
||||
data = get_boilerplate(name)
|
||||
} else {
|
||||
return callback(self._internal_error(err, file, 'error reading'))
|
||||
return callback(self._internal_error(err, info_file, 'error reading'))
|
||||
}
|
||||
}
|
||||
self._normalize_package(data)
|
||||
|
@ -294,7 +291,7 @@ Storage.prototype.remove_tarball = function(name, filename, revision, callback)
|
|||
}
|
||||
}, function(err) {
|
||||
if (err) return callback(err)
|
||||
self.storage.unlink(name + '/' + filename, callback)
|
||||
self.storage(name).unlink(filename, callback)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -320,7 +317,7 @@ Storage.prototype.add_tarball = function(name, filename) {
|
|||
}))
|
||||
}
|
||||
|
||||
var wstream = this.storage.write_stream(name + '/' + filename)
|
||||
var wstream = this.storage(name).write_stream(filename)
|
||||
|
||||
wstream.on('error', function(err) {
|
||||
if (err.code === 'EEXISTS') {
|
||||
|
@ -387,7 +384,7 @@ Storage.prototype.get_tarball = function(name, filename, callback) {
|
|||
rstream.close()
|
||||
}
|
||||
|
||||
var rstream = this.storage.read_stream(name + '/' + filename)
|
||||
var rstream = this.storage(name).read_stream(filename)
|
||||
rstream.on('error', function(err) {
|
||||
if (err && err.code === 'ENOENT') {
|
||||
stream.emit('error', new UError({
|
||||
|
@ -410,9 +407,8 @@ Storage.prototype.get_package = function(name, options, callback) {
|
|||
if (typeof(options) === 'function') callback = options, options = {}
|
||||
|
||||
var self = this
|
||||
, file = name + '/' + info_file
|
||||
|
||||
self.storage.read_json(file, function(err, result) {
|
||||
self.storage(name).read_json(info_file, function(err, result) {
|
||||
if (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return callback(new UError({
|
||||
|
@ -420,7 +416,7 @@ Storage.prototype.get_package = function(name, options, callback) {
|
|||
msg: 'no such package available'
|
||||
}))
|
||||
} else {
|
||||
return callback(self._internal_error(err, file, 'error reading'))
|
||||
return callback(self._internal_error(err, info_file, 'error reading'))
|
||||
}
|
||||
}
|
||||
self._normalize_package(result)
|
||||
|
@ -446,12 +442,8 @@ Storage.prototype.get_package = function(name, options, callback) {
|
|||
//
|
||||
Storage.prototype.update_package = function(name, updateFn, _callback) {
|
||||
var self = this
|
||||
, file = name + '/' + info_file
|
||||
self.storage.lock_and_read_json(file, function(err, fd, json) {
|
||||
self.logger.debug({file: file}, 'locking @{file}')
|
||||
|
||||
self.storage(name).lock_and_read_json(info_file, function(err, fd, json) {
|
||||
function callback() {
|
||||
self.logger.debug({file: file}, 'unlocking @{file}')
|
||||
var _args = arguments
|
||||
if (fd) {
|
||||
fs.close(fd, function(err) {
|
||||
|
@ -502,8 +494,43 @@ Storage.prototype._write_package = function(name, json, callback) {
|
|||
var rev = json._rev.split('-')
|
||||
json._rev = ((+rev[0] || 0) + 1) + '-' + crypto.pseudoRandomBytes(8).toString('hex')
|
||||
|
||||
this.storage.write_json(name + '/' + info_file, json, callback)
|
||||
this.storage(name).write_json(info_file, json, callback)
|
||||
}
|
||||
|
||||
Storage.prototype.storage = function(package) {
|
||||
return new Path_Wrapper(
|
||||
Path.join(
|
||||
Path.resolve(
|
||||
Path.dirname(this.config.self_path),
|
||||
this.config.storage
|
||||
),
|
||||
package
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
var Path_Wrapper = (function() {
|
||||
// a wrapper adding paths to fs_storage methods
|
||||
function Wrapper(path) {
|
||||
this.path = path
|
||||
}
|
||||
|
||||
for (var i in fs_storage) {
|
||||
if (fs_storage.hasOwnProperty(i)) {
|
||||
Wrapper.prototype[i] = wrapper(i)
|
||||
}
|
||||
}
|
||||
|
||||
function wrapper(method) {
|
||||
return function(/*...*/) {
|
||||
var args = Array.prototype.slice.apply(arguments)
|
||||
args[0] = Path.join(this.path, args[0] || '')
|
||||
return fs_storage[method].apply(null, args)
|
||||
}
|
||||
}
|
||||
|
||||
return Wrapper
|
||||
})()
|
||||
|
||||
module.exports = Storage
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ dependencies:
|
|||
minimatch: '*'
|
||||
bunyan: '>= 0.16.4'
|
||||
fs-ext: '*'
|
||||
mkdirp: '*'
|
||||
|
||||
devDependencies:
|
||||
rimraf: '*'
|
||||
|
|
Loading…
Reference in a new issue