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

216 lines
4.8 KiB
JavaScript

'use strict';
const fs = require('fs');
const Error = require('http-errors');
const mkdirp = require('mkdirp');
const Path = require('path');
const MyStreams = require('./streams');
function FSError(code) {
let err = Error(code);
err.code = code;
return err;
}
let locker = require('./file-locking');
function tempFile(str) {
return str + '.tmp' + String(Math.random()).substr(2);
}
function renameTmp(src, dst, _cb) {
function cb(err) {
if (err) fs.unlink(src, function() {});
_cb(err);
}
if (process.platform !== 'win32') {
return fs.rename(src, dst, cb);
}
// windows can't remove opened file,
// but it seem to be able to rename it
let tmp = tempFile(dst);
fs.rename(dst, tmp, function(err) {
fs.rename(src, dst, cb);
if (!err) fs.unlink(tmp, () => {});
});
}
function write(dest, data, cb) {
let safe_write = function(cb) {
let tmpname = tempFile(dest);
fs.writeFile(tmpname, data, function(err) {
if (err) return cb(err);
renameTmp(tmpname, dest, cb);
});
};
safe_write(function(err) {
if (err && err.code === 'ENOENT') {
mkdirp(Path.dirname(dest), function(err) {
if (err) return cb(err);
safe_write(cb);
});
} else {
cb(err);
}
});
}
function write_stream(name) {
let stream = MyStreams.uploadTarballStream();
let _ended = 0;
stream.on('end', function() {
_ended = 1;
});
fs.exists(name, function(exists) {
if (exists) return stream.emit('error', FSError('EEXISTS'));
let tmpname = name + '.tmp-'+String(Math.random()).replace(/^0\./, '');
let file = fs.createWriteStream(tmpname);
let opened = false;
stream.pipe(file);
stream.done = function() {
function onend() {
file.on('close', function() {
renameTmp(tmpname, name, function(err) {
if (err) {
stream.emit('error', err);
} else {
stream.emit('success');
}
});
});
file.destroySoon();
}
if (_ended) {
onend();
} else {
stream.on('end', onend);
}
};
stream.abort = function() {
if (opened) {
opened = false;
file.on('close', function() {
fs.unlink(tmpname, function() {});
});
}
file.destroySoon();
};
file.on('open', function() {
opened = true;
// re-emitting open because it's handled in storage.js
stream.emit('open');
});
file.on('error', function(err) {
stream.emit('error', err);
});
});
return stream;
}
function read_stream(name, stream, callback) {
let rstream = fs.createReadStream(name);
rstream.on('error', function(err) {
stream.emit('error', err);
});
rstream.on('open', function(fd) {
fs.fstat(fd, function(err, stats) {
if (err) return stream.emit('error', err);
stream.emit('content-length', stats.size);
stream.emit('open');
rstream.pipe(stream);
});
});
stream = MyStreams.readTarballStream();
stream.abort = function() {
rstream.close();
};
return stream;
}
function create(name, contents, callback) {
fs.exists(name, function(exists) {
if (exists) return callback( FSError('EEXISTS') );
write(name, contents, callback);
});
}
function update(name, contents, callback) {
fs.exists(name, function(exists) {
if (!exists) return callback( FSError('ENOENT') );
write(name, contents, callback);
});
}
function read(name, callback) {
fs.readFile(name, callback);
}
module.exports.read = read;
module.exports.read_json = function(name, cb) {
read(name, function(err, res) {
if (err) return cb(err);
let args = [];
try {
args = [null, JSON.parse(res.toString('utf8'))];
} catch(err) {
args = [err];
}
cb.apply(null, args);
});
};
module.exports.lock_and_read = function(name, cb) {
locker.readFile(name, {lock: true}, function(err, res) {
if (err) return cb(err);
return cb(null, res);
});
};
module.exports.lock_and_read_json = function(name, cb) {
locker.readFile(name, {lock: true, parse: true}, function(err, res) {
if (err) return cb(err);
return cb(null, res);
});
};
module.exports.unlock_file = function(name, cb) {
locker.unlockFile(name, cb);
};
module.exports.create = create;
module.exports.create_json = function(name, value, cb) {
create(name, JSON.stringify(value, null, '\t'), cb);
};
module.exports.update = update;
module.exports.update_json = function(name, value, cb) {
update(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);
};
module.exports.write_stream = write_stream;
module.exports.read_stream = read_stream;
module.exports.unlink = fs.unlink;
module.exports.rmdir = fs.rmdir;