mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-07-07 13:53:06 +02:00
Use relative linking (#6011)
* Use relative linking * Add copyFile method and tests Closes #5988 * Fix relative linking on Windows Hard links and junctions don't work with relative paths * Fix tests * Revert ghange to gitignore
This commit is contained in:
committed by
Barış Soner Uşaklı
parent
18f4f27fe0
commit
adc47fd053
91
src/file.js
91
src/file.js
@@ -12,35 +12,76 @@ var utils = require('./utils');
|
||||
|
||||
var file = module.exports;
|
||||
|
||||
/**
|
||||
* Asynchronously copies `src` to `dest`
|
||||
* @param {string} src - source filename to copy
|
||||
* @param {string} dest - destination filename of the copy operation
|
||||
* @param {function(Error): void} callback
|
||||
*/
|
||||
function copyFile(src, dest, callback) {
|
||||
var calledBack = false;
|
||||
|
||||
var read;
|
||||
var write;
|
||||
|
||||
function done(err) {
|
||||
if (calledBack) {
|
||||
return;
|
||||
}
|
||||
calledBack = true;
|
||||
|
||||
if (err) {
|
||||
if (read) {
|
||||
read.destroy();
|
||||
}
|
||||
if (write) {
|
||||
write.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
callback(err);
|
||||
}
|
||||
|
||||
read = fs.createReadStream(src);
|
||||
read.on('error', done);
|
||||
|
||||
write = fs.createWriteStream(dest);
|
||||
write.on('error', done);
|
||||
write.on('close', function () {
|
||||
done();
|
||||
});
|
||||
|
||||
read.pipe(write);
|
||||
}
|
||||
|
||||
file.copyFile = (typeof fs.copyFile === 'function') ? fs.copyFile : copyFile;
|
||||
|
||||
file.saveFileToLocal = function (filename, folder, tempPath, callback) {
|
||||
/*
|
||||
* remarkable doesn't allow spaces in hyperlinks, once that's fixed, remove this.
|
||||
*/
|
||||
filename = filename.split('.');
|
||||
filename.forEach(function (name, idx) {
|
||||
filename[idx] = utils.slugify(name);
|
||||
});
|
||||
filename = filename.join('.');
|
||||
filename = filename.split('.').map(function (name) {
|
||||
return utils.slugify(name);
|
||||
}).join('.');
|
||||
|
||||
var uploadPath = path.join(nconf.get('upload_path'), folder, filename);
|
||||
|
||||
winston.verbose('Saving file ' + filename + ' to : ' + uploadPath);
|
||||
mkdirp(path.dirname(uploadPath), function (err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var is = fs.createReadStream(tempPath);
|
||||
var os = fs.createWriteStream(uploadPath);
|
||||
is.on('end', function () {
|
||||
file.copyFile(tempPath, uploadPath, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
url: '/assets/uploads/' + folder + '/' + filename,
|
||||
path: uploadPath,
|
||||
});
|
||||
});
|
||||
|
||||
os.on('error', callback);
|
||||
is.pipe(os);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -125,15 +166,33 @@ file.delete = function (path) {
|
||||
}
|
||||
};
|
||||
|
||||
file.link = function link(filePath, destPath, cb) {
|
||||
file.link = function link(filePath, destPath, relative, callback) {
|
||||
if (!callback) {
|
||||
callback = relative;
|
||||
relative = false;
|
||||
}
|
||||
|
||||
if (relative && process.platform !== 'win32') {
|
||||
filePath = path.relative(path.dirname(destPath), filePath);
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
fs.link(filePath, destPath, cb);
|
||||
fs.link(filePath, destPath, callback);
|
||||
} else {
|
||||
fs.symlink(filePath, destPath, 'file', cb);
|
||||
fs.symlink(filePath, destPath, 'file', callback);
|
||||
}
|
||||
};
|
||||
|
||||
file.linkDirs = function linkDirs(sourceDir, destDir, callback) {
|
||||
file.linkDirs = function linkDirs(sourceDir, destDir, relative, callback) {
|
||||
if (!callback) {
|
||||
callback = relative;
|
||||
relative = false;
|
||||
}
|
||||
|
||||
if (relative && process.platform !== 'win32') {
|
||||
sourceDir = path.relative(path.dirname(destDir), sourceDir);
|
||||
}
|
||||
|
||||
var type = (process.platform === 'win32') ? 'junction' : 'dir';
|
||||
fs.symlink(sourceDir, destDir, type, callback);
|
||||
};
|
||||
|
||||
@@ -88,6 +88,14 @@ JS.scripts = {
|
||||
},
|
||||
};
|
||||
|
||||
function linkIfLinux(srcPath, destPath, next) {
|
||||
if (process.platform === 'win32') {
|
||||
file.copyFile(srcPath, destPath, next);
|
||||
} else {
|
||||
file.link(srcPath, destPath, true, next);
|
||||
}
|
||||
}
|
||||
|
||||
var basePath = path.resolve(__dirname, '../..');
|
||||
|
||||
function minifyModules(modules, fork, callback) {
|
||||
@@ -120,7 +128,7 @@ function minifyModules(modules, fork, callback) {
|
||||
},
|
||||
function (cb) {
|
||||
async.eachLimit(filtered.skip, 500, function (mod, next) {
|
||||
file.link(mod.srcPath, mod.destPath, next);
|
||||
linkIfLinux(mod.srcPath, mod.destPath, next);
|
||||
}, cb);
|
||||
},
|
||||
], callback);
|
||||
@@ -148,20 +156,10 @@ function linkModules(callback) {
|
||||
return next(err);
|
||||
}
|
||||
if (res.stats.isDirectory()) {
|
||||
return file.linkDirs(srcPath, destPath, next);
|
||||
return file.linkDirs(srcPath, destPath, true, next);
|
||||
}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
fs.readFile(srcPath, function (err, file) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
fs.writeFile(destPath, file, next);
|
||||
});
|
||||
} else {
|
||||
file.link(srcPath, destPath, next);
|
||||
}
|
||||
linkIfLinux(srcPath, destPath, next);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
@@ -267,7 +265,7 @@ JS.linkStatics = function (callback) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
file.linkDirs(sourceDir, destDir, next);
|
||||
file.linkDirs(sourceDir, destDir, true, next);
|
||||
});
|
||||
}, callback);
|
||||
});
|
||||
|
||||
100
test/file.js
Normal file
100
test/file.js
Normal file
@@ -0,0 +1,100 @@
|
||||
'use strict';
|
||||
|
||||
var assert = require('assert');
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var nconf = require('nconf');
|
||||
|
||||
var utils = require('../src/utils');
|
||||
var file = require('../src/file');
|
||||
|
||||
describe('file', function () {
|
||||
var filename = utils.generateUUID() + '.png';
|
||||
var folder = 'files';
|
||||
var uploadPath = path.join(nconf.get('upload_path'), folder, filename);
|
||||
var tempPath = path.join(__dirname, './files/test.png');
|
||||
|
||||
afterEach(function (done) {
|
||||
fs.unlink(uploadPath, function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('copyFile', function () {
|
||||
it('should copy a file', function (done) {
|
||||
file.copyFile(tempPath, uploadPath, function (err) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert(file.existsSync(uploadPath));
|
||||
|
||||
var srcContent = fs.readFileSync(tempPath, 'utf8');
|
||||
var destContent = fs.readFileSync(uploadPath, 'utf8');
|
||||
|
||||
assert.strictEqual(srcContent, destContent);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should override an existing file', function (done) {
|
||||
fs.writeFileSync(uploadPath, 'hsdkjhgkjsfhkgj');
|
||||
|
||||
file.copyFile(tempPath, uploadPath, function (err) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert(file.existsSync(uploadPath));
|
||||
|
||||
var srcContent = fs.readFileSync(tempPath, 'utf8');
|
||||
var destContent = fs.readFileSync(uploadPath, 'utf8');
|
||||
|
||||
assert.strictEqual(srcContent, destContent);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error if source file does not exist', function (done) {
|
||||
file.copyFile(tempPath + '0000000000', uploadPath, function (err) {
|
||||
assert(err);
|
||||
assert.strictEqual(err.code, 'ENOENT');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error if existing file is read only', function (done) {
|
||||
fs.writeFileSync(uploadPath, 'hsdkjhgkjsfhkgj');
|
||||
fs.chmodSync(uploadPath, '444');
|
||||
|
||||
file.copyFile(tempPath, uploadPath, function (err) {
|
||||
assert(err);
|
||||
assert(err.code === 'EPERM' || err.code === 'EACCES');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('saveFileToLocal', function () {
|
||||
it('should work', function (done) {
|
||||
file.saveFileToLocal(filename, folder, tempPath, function (err) {
|
||||
assert.ifError(err);
|
||||
|
||||
assert(file.existsSync(uploadPath));
|
||||
|
||||
var oldFile = fs.readFileSync(tempPath, 'utf8');
|
||||
var newFile = fs.readFileSync(uploadPath, 'utf8');
|
||||
assert.strictEqual(oldFile, newFile);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error if source does not exist', function (done) {
|
||||
file.saveFileToLocal(filename, folder, tempPath + '000000000', function (err) {
|
||||
assert(err);
|
||||
assert.strictEqual(err.code, 'ENOENT');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user