1
0
mirror of https://github.com/verdaccio/verdaccio.git synced 2024-11-13 03:35:52 +01:00
verdaccio/lib/local-fs.js

252 lines
5.6 KiB
JavaScript
Raw Normal View History

var fs = require('fs')
, fsExt = require('fs-ext')
, Path = require('path')
, mystreams = require('./streams')
, FSError = require('./error').FSError
2013-06-01 00:57:28 +02:00
function make_directories(dest, cb) {
2013-10-26 14:18:36 +02:00
var dir = Path.dirname(dest)
if (dir === '.' || dir === '..') return cb()
2013-06-01 00:57:28 +02:00
fs.mkdir(dir, function(err) {
if (err && err.code === 'ENOENT') {
make_directories(dir, function() {
2013-10-26 14:18:36 +02:00
fs.mkdir(dir, cb)
2013-06-01 00:57:28 +02:00
})
} else {
2013-10-26 14:18:36 +02:00
cb()
2013-06-01 00:57:28 +02:00
}
2013-10-26 14:18:36 +02:00
})
2013-06-01 00:57:28 +02:00
}
2013-06-18 20:14:55 +02:00
function write(dest, data, cb) {
2013-06-01 00:57:28 +02:00
var safe_write = function(cb) {
2013-10-26 14:18:36 +02:00
var tmpname = dest + '.tmp' + String(Math.random()).substr(2)
2013-06-22 02:19:46 +02:00
fs.writeFile(tmpname, data, function(err) {
2013-10-26 14:18:36 +02:00
if (err) return cb(err)
return fs.rename(tmpname, dest, cb)
})
2013-06-01 00:57:28 +02:00
}
safe_write(function(err) {
if (err && err.code === 'ENOENT') {
make_directories(dest, function() {
2013-10-26 14:18:36 +02:00
safe_write(cb)
2013-06-01 00:57:28 +02:00
})
} else {
2013-10-26 14:18:36 +02:00
cb(err)
2013-06-01 00:57:28 +02:00
}
2013-10-26 14:18:36 +02:00
})
2013-06-01 00:57:28 +02:00
}
2013-06-20 15:07:34 +02:00
function write_stream(name) {
2013-10-26 14:18:36 +02:00
var stream = new mystreams.UploadTarballStream()
2013-06-20 15:07:34 +02:00
2013-10-26 14:18:36 +02:00
var _ended = 0
2013-09-28 14:19:40 +02:00
stream.on('end', function() {
2013-10-26 14:18:36 +02:00
_ended = 1
})
2013-09-28 14:19:40 +02:00
2013-06-20 15:07:34 +02:00
fs.exists(name, function(exists) {
2013-10-26 14:18:36 +02:00
if (exists) return stream.emit('error', new FSError('EEXISTS'))
2013-06-20 15:07:34 +02:00
2013-10-26 14:18:36 +02:00
var tmpname = name + '.tmp-'+String(Math.random()).replace(/^0\./, '')
, file = fs.createWriteStream(tmpname)
, opened = false
stream.pipe(file)
2013-09-28 14:19:40 +02:00
stream.done = function() {
2013-09-28 14:19:40 +02:00
function onend() {
2013-09-27 13:31:28 +02:00
file.on('close', function() {
fs.rename(tmpname, name, function(err) {
2013-10-26 14:18:36 +02:00
if (err) stream.emit('error', err)
stream.emit('success')
})
})
file.destroySoon()
2013-09-28 14:19:40 +02:00
}
if (_ended) {
2013-10-26 14:18:36 +02:00
onend()
2013-09-28 14:19:40 +02:00
} else {
2013-10-26 14:18:36 +02:00
stream.on('end', onend)
2013-09-28 14:19:40 +02:00
}
2013-10-26 14:18:36 +02:00
}
stream.abort = function() {
2013-10-11 11:50:41 +02:00
if (opened) {
2013-10-26 14:18:36 +02:00
opened = false
2013-10-11 11:50:41 +02:00
file.on('close', function() {
2013-10-26 14:18:36 +02:00
fs.unlink(tmpname, function(){})
})
2013-10-11 11:50:41 +02:00
}
2013-10-26 14:18:36 +02:00
file.destroySoon()
}
file.on('open', function() {
2013-10-26 14:18:36 +02:00
opened = true
// re-emitting open because it's handled in storage.js
2013-10-26 14:18:36 +02:00
stream.emit('open')
})
2013-09-28 14:19:40 +02:00
file.on('error', function(err) {
2013-10-26 14:18:36 +02:00
stream.emit('error', err)
})
})
return stream
2013-06-20 15:07:34 +02:00
}
function read_stream(name, stream, callback) {
2013-10-26 14:18:36 +02:00
return fs.createReadStream(name)
2013-06-20 15:07:34 +02:00
}
2013-06-01 00:57:28 +02:00
function create(name, contents, callback) {
fs.exists(name, function(exists) {
2013-10-26 14:18:36 +02:00
if (exists) return callback(new FSError('EEXISTS'))
write(name, contents, callback)
})
2013-06-01 00:57:28 +02:00
}
function update(name, contents, callback) {
fs.exists(name, function(exists) {
2013-10-26 14:18:36 +02:00
if (!exists) return callback(new FSError('ENOENT'))
write(name, contents, callback)
})
2013-06-01 00:57:28 +02:00
}
function read(name, callback) {
fs.readFile(name, callback)
}
// open and flock with exponential backoff
function open_flock(name, opmod, flmod, tries, backoff, cb) {
fs.open(name, opmod, function(err, fd) {
if (err) return cb(err, fd)
fsExt.flock(fd, flmod, function(err) {
if (err) {
if (!tries) {
fs.close(fd, function() {
cb(err)
})
} else {
fs.close(fd, function() {
setTimeout(function() {
open_flock(name, opmod, flmod, tries-1, backoff*2, cb)
}, backoff)
})
}
} else {
cb(null, fd)
}
})
})
}
// this function neither unlocks file nor closes it
// it'll have to be done manually later
function lock_and_read(name, callback) {
open_flock(name, 'r', 'exnb', 4, 10, function(err, fd) {
if (err) return callback(err, fd)
fs.fstat(fd, function(err, st) {
if (err) return callback(err, fd)
var buffer = new Buffer(st.size)
fs.read(fd, buffer, 0, st.size, null, function(err, bytesRead, buffer) {
if (bytesRead != st.size) return callback(new Error('st.size != bytesRead'), fd)
callback(null, fd, buffer)
})
})
})
2013-06-01 00:57:28 +02:00
}
2013-06-14 10:34:29 +02:00
function Storage(path) {
2013-10-26 14:18:36 +02:00
this.path = path
2013-06-14 10:34:29 +02:00
try {
2013-10-26 14:18:36 +02:00
fs.mkdirSync(path)
console.log('created new packages directory: ', path)
2013-06-14 10:34:29 +02:00
} catch(err) {
2013-10-26 14:18:36 +02:00
if (err.code !== 'EEXIST') throw new Error(err)
2013-06-14 10:34:29 +02:00
}
}
Storage.prototype.read = function(name, cb) {
read(this.path + '/' + name, cb)
2013-06-14 10:34:29 +02:00
}
Storage.prototype.read_json = function(name, cb) {
read(this.path + '/' + name, function(err, res) {
2013-10-26 14:18:36 +02:00
if (err) return cb(err)
2013-10-18 22:46:13 +02:00
var args = []
try {
args = [null, JSON.parse(res.toString('utf8'))]
} catch(err) {
args = [err]
}
cb.apply(null, args)
})
2013-06-14 10:34:29 +02:00
}
Storage.prototype.lock_and_read = function(name, cb) {
lock_and_read(this.path + '/' + name, cb)
}
Storage.prototype.lock_and_read_json = function(name, cb) {
lock_and_read(this.path + '/' + name, function(err, fd, res) {
if (err) return cb(err, fd)
var args = []
try {
args = [null, fd, JSON.parse(res.toString('utf8'))]
} catch(err) {
args = [err, fd]
}
cb.apply(null, args)
})
}
2013-10-18 23:17:53 +02:00
Storage.prototype.path_to = function(file) {
return this.path + '/' + file
}
2013-06-14 10:34:29 +02:00
Storage.prototype.create = function(name, value, cb) {
create(this.path + '/' + name, value, cb)
2013-06-14 10:34:29 +02:00
}
Storage.prototype.create_json = function(name, value, cb) {
create(this.path + '/' + name, JSON.stringify(value, null, '\t'), cb)
2013-06-14 10:34:29 +02:00
}
Storage.prototype.update = function(name, value, cb) {
update(this.path + '/' + name, value, cb)
2013-06-14 10:34:29 +02:00
}
Storage.prototype.update_json = function(name, value, cb) {
update(this.path + '/' + name, JSON.stringify(value, null, '\t'), cb)
2013-06-14 10:34:29 +02:00
}
2013-06-18 20:14:55 +02:00
Storage.prototype.write = function(name, value, cb) {
write(this.path + '/' + name, value, cb)
2013-06-18 20:14:55 +02:00
}
Storage.prototype.write_json = function(name, value, cb) {
write(this.path + '/' + name, JSON.stringify(value, null, '\t'), cb)
2013-06-18 20:14:55 +02:00
}
2013-06-20 15:07:34 +02:00
Storage.prototype.write_stream = function(name, value, cb) {
return write_stream(this.path + '/' + name, value, cb)
2013-06-20 15:07:34 +02:00
}
Storage.prototype.read_stream = function(name, cb) {
return read_stream(this.path + '/' + name, cb)
2013-06-20 15:07:34 +02:00
}
Storage.prototype.unlink = function(name, cb) {
fs.unlink(this.path + '/' + name, cb)
}
Storage.prototype.rmdir = function(name, cb) {
fs.rmdir(this.path + '/' + name, cb)
}
2013-10-26 14:18:36 +02:00
module.exports = Storage
2013-06-01 00:57:28 +02:00