backport localfs changes from v4

pull/495/head
nightwing 2018-03-25 18:53:38 +04:00
rodzic 086d4293e7
commit 7e90154196
6 zmienionych plików z 214 dodań i 57 usunięć

Wyświetl plik

@ -114,8 +114,9 @@ define(function(require, exports, module) {
});
});
}
onload && onload();
setTimeout(function() {
onload && onload();
});
});
if (app) {
app.on("service", function(name, plugin) {

154
plugins/node_modules/vfs-local/localfs.js wygenerowano vendored
Wyświetl plik

@ -14,9 +14,9 @@ var getMime = (function(simpleMime) {
return function(path) {
var mime = simpleMime(path);
if (typeof mime != "string")
return "application/octet-stream"
return "application/octet-stream";
return mime;
}
};
})(require("simple-mime")());
var vm = require("vm");
var exists = fs.exists || require("path").exists;
@ -69,9 +69,16 @@ function logToFile(message){
});
}
var auditLog = function(description, data) {
}
////////////////////////////////////////////////////////////////////////////////
module.exports = function setup(fsOptions) {
var debug = fsOptions.debug || false;
auditLog = fsOptions.auditLog || auditLog;
var pty;
if (fsOptions.nodePath) {
process.env.NODE_PATH = fsOptions.nodePath;
@ -80,7 +87,7 @@ module.exports = function setup(fsOptions) {
if (!fsOptions.nopty) {
// on darwin trying to load binary for a wrong version crashes the process
[(fsOptions.nodePath || process.env.HOME + "/.c9/node_modules") + "/pty.js",
"pty.js", "pty.nw.js"].some(function(p) {
"pty.js"].some(function(p) {
try {
pty = require(p);
return true;
@ -510,19 +517,27 @@ module.exports = function setup(fsOptions) {
});
}
function getMetadata(path, options, callback){
function resolveMetaPath(path, options, callback) {
if (path.charAt(0) == "~")
path = join(process.env.HOME, path.substr(1));
var metaPath = join(WSMETAPATH, path);
resolvePath(metaPath, options, function (err, path) {
if (err) return callback(err);
callback(null, path);
});
}
function getMetadata(path, options, callback){
resolveMetaPath(path, options, function (err, path) {
if (err) return callback(err);
fs.readFile(path, callback);
});
}
function readfile(path, options, callback) {
auditLog("readfile", path);
var meta = {};
var originalPath = path;
@ -535,20 +550,83 @@ module.exports = function setup(fsOptions) {
return callback(err);
}
var metadata = options.metadata && originalPath.indexOf(WSMETAPATH) == -1;
// Basic file info
meta.mime = getMime(path);
meta.size = stat.size;
meta.etag = calcEtag(stat);
calcEtagConsideringMetadata(metadata, function(err, etag) {
if (err) return callback(err);
meta.etag = etag;
// ETag support
if ((TESTING || stat.mtime % 1000) && options.etag === meta.etag) {
meta.notModified = true;
fs.close(fd);
return callback(null, meta);
}
supportRange(meta, function(_, stop) {
if (stop) {
fs.close(fd);
return callback(null, meta);
}
if (metadata) {
addMetadata(meta);
return;
}
done();
});
});
// ETag support
if ((TESTING || stat.mtime % 1000) && options.etag === meta.etag) {
meta.notModified = true;
fs.close(fd);
return callback(null, meta);
function calcEtagConsideringMetadata(metadata, callback) {
if (!metadata) {
return callback(null, calcEtag(stat));
}
resolveMetaPath(originalPath, options, function (err, path) {
if (err) return callback(null, calcEtag(stat));
fs.stat(path, function (err, metaStat) {
if (err) return callback(null, calcEtag(stat));
var previousMtime = stat.mtime;
var previousSize = stat.size;
var mtime = stat.mtime < metaStat.mtime ? metaStat.mtime : stat.mtime;
var size = parseInt(stat.size.toString() + metaStat.size.toString());
stat.mtime = mtime;
stat.size = size;
var etag = calcEtag(stat);
stat.mtime = previousMtime;
stat.size = previousSize;
callback(null, etag);
});
});
}
function addMetadata(meta) {
getMetadata(originalPath, options, function (err, data) {
if (err) return done();
try {
meta.metadataSize = data.length;
meta.metadataStringLength = data.toString("utf8").length;
done(data);
} catch (e) {
fs.close(fd);
done();
}
});
}
// Range support
if (options.hasOwnProperty('range') && !(options.range.etag && options.range.etag !== meta.etag)) {
function supportRange(meta, callback) {
if (!(options.hasOwnProperty('range') && !(options.range.etag && options.range.etag !== meta.etag)))
return callback(null, false);
var range = options.range;
var start, end;
if (range.hasOwnProperty("start")) {
@ -562,42 +640,21 @@ module.exports = function setup(fsOptions) {
}
else {
meta.rangeNotSatisfiable = "Invalid Range";
fs.close(fd);
return callback(null, meta);
return callback(null, true);
}
}
if (end < start || start < 0 || end >= stat.size) {
meta.rangeNotSatisfiable = "Range out of bounds";
fs.close(fd);
return callback(null, meta);
return callback(null, true);
}
options.start = start;
options.end = end;
meta.size = end - start + 1;
meta.partialContent = { start: start, end: end, size: stat.size };
}
var metaData;
if (options.hasOwnProperty("metadata") && originalPath.indexOf(WSMETAPATH) == -1) {
getMetadata(originalPath, options, function (err, data) {
if (err)
return done();
try {
meta.metadataSize = data.length;
meta.metadataStringLength = data.toString("utf8").length;
metaData = data;
done(true);
} catch (e) {
fs.close(fd);
done();
}
});
}
else {
done();
callback(null, false);
}
function done(fakeStream){
function done(metadata){
// HEAD request support
if (options.hasOwnProperty("head")) {
fs.close(fd);
@ -613,7 +670,7 @@ module.exports = function setup(fsOptions) {
return callback(err);
}
if (fakeStream) {
if (metadata) {
var readStream = meta.stream;
meta.stream = new Stream();
meta.stream.readable = true;
@ -627,7 +684,7 @@ module.exports = function setup(fsOptions) {
};
readStream.pipe(meta.stream, { end : false });
readStream.on("end", function(){
meta.stream.write(metaData);
meta.stream.write(metadata);
meta.stream.end();
});
meta.stream.destroy = function () {
@ -710,6 +767,7 @@ module.exports = function setup(fsOptions) {
// file and then renames to the final destination.
// It will copy the properties of the existing file is there is one.
function mkfile(path, options, realCallback) {
auditLog("mkfile", path);
var meta = {};
var called;
var callback = function (err) {
@ -1014,10 +1072,12 @@ module.exports = function setup(fsOptions) {
}
function rmfile(path, options, callback) {
auditLog("rmfile", path);
remove(path, fs.unlink, options, callback);
}
function rmdir(path, options, callback) {
auditLog("rmdir", path);
if (options.recursive) {
remove(path, function(path, callback) {
spawn("rm", {args: ["-rf", path], stdio: 'ignore'}, function(err, child) {
@ -1039,6 +1099,7 @@ module.exports = function setup(fsOptions) {
}
function rename(path, options, callback) {
auditLog("rename", path);
var from, to;
if (options.from) {
from = options.from; to = path;
@ -1103,6 +1164,7 @@ module.exports = function setup(fsOptions) {
}
function copy(path, options, callback) {
auditLog("copy", path);
var from, to;
if (options.from) {
from = options.from; to = path;
@ -1191,6 +1253,7 @@ module.exports = function setup(fsOptions) {
}
function symlink(path, options, callback) {
auditLog("symlink", path);
if (!options.target) return callback(new Error("options.target is required"));
var meta = {};
// Get real path to target dir
@ -1523,6 +1586,7 @@ module.exports = function setup(fsOptions) {
}
function chmod(path, options, callback) {
auditLog("chmod", path);
resolvePath(path, options, function(err, path){
if (err) return callback(err);
@ -1540,6 +1604,7 @@ module.exports = function setup(fsOptions) {
}
function spawn(executablePath, options, callback) {
auditLog("spawn", executablePath);
if (waitForEnv)
return waitForEnv.push(spawn.bind(null, executablePath, options, callback));
@ -1559,6 +1624,14 @@ module.exports = function setup(fsOptions) {
} catch (err) {
return callback(err);
}
if (!child.pid) {
err = new Error("spawn " + executablePath+ " ENOENT");
err.code = "ENOENT";
err.errno = "ENOENT";
return callback(err);
}
if (options.resumeStdin) child.stdin.resume();
if (options.hasOwnProperty('stdoutEncoding')) {
child.stdout && child.stdout.setEncoding(options.stdoutEncoding);
@ -1571,7 +1644,7 @@ module.exports = function setup(fsOptions) {
child.on("error", function(err) {
child.emit("exit", 127);
});
callback(null, {
process: child
});
@ -2306,6 +2379,7 @@ module.exports = function setup(fsOptions) {
}
function execFile(executablePath, options, callback) {
auditLog("execFile", executablePath);
if (waitForEnv)
return waitForEnv.push(execFile.bind(null, executablePath, options, callback));

Wyświetl plik

@ -0,0 +1 @@
some meta data

Wyświetl plik

@ -1 +1 @@
This is a simple file!
This is a file with exactly 42 characters!!

Wyświetl plik

@ -0,0 +1 @@
juhu kinners

Wyświetl plik

@ -4,7 +4,8 @@
"use mocha";
require("c9/inline-mocha")(module);
const async = require("async");
const assert = require("assert");
var expect = require('chai').expect;
describe('vfs-local', function () {
@ -17,7 +18,8 @@ describe('vfs-local', function () {
root: root,
testing: true,
defaultEnv: { CUSTOM: 43 },
checkSymlinks: true
checkSymlinks: true,
wsmetapath: ".c9/metadata",
}));
var vfsLoose = require('vfs-lint')(require("vfs-local")({
@ -38,7 +40,6 @@ describe('vfs-local', function () {
});
});
});
it('should prepend root when resolving virtual paths', function (done) {
var vpath = "/dir/stuff.json";
vfs.resolve(vpath, {}, function (err, meta) {
@ -82,7 +83,7 @@ describe('vfs-local', function () {
vfs.stat("/file.txt", {}, function (err, stat) {
if (err) throw err;
expect(stat).property("name").equal("file.txt");
expect(stat).property("size").equal(23);
expect(stat).property("size").equal(44);
expect(stat).property("mime").equal("text/plain");
done();
});
@ -96,11 +97,86 @@ describe('vfs-local', function () {
});
describe('vfs.readfile()', function () {
it("should work if metadata is requested but there is none", function(done) {
vfs.readfile("/file2.txt", { metadata: true }, function(err, meta) {
if (err) throw err;
var stream = meta.stream;
var chunks = [];
var length = 0;
stream.on("data", function (chunk) {
chunks.push(chunk);
length += chunk.length;
});
stream.on("end", function () {
expect(length).equal(12);
done();
});
});
});
it("should work if metadata is requested but there is none, don't check symlinks", function(done) {
vfs.readfile("/file2.txt", { metadata: true, checkSymlinks: false }, function(err, meta) {
if (err) throw err;
var stream = meta.stream;
var chunks = [];
var length = 0;
stream.on("data", function (chunk) {
chunks.push(chunk);
length += chunk.length;
});
stream.on("end", function () {
expect(length).equal(12);
done();
});
});
});
it("should return metadata", function(done) {
vfs.readfile("/file.txt", { metadata: true }, function(err, meta) {
if (err) throw err;
expect(meta).property("metadataSize").equals(14);
var stream = meta.stream;
var chunks = [];
var length = 0;
stream.on("data", function (chunk) {
chunks.push(chunk);
length += chunk.length;
});
stream.on("end", function () {
expect(length).equal(58);
var body = chunks.join("");
expect(body).equal("This is a file with exactly 42 characters!!\nsome meta data");
done();
});
});
});
it("etag determined by latest mtime", function(done) {
async.series({
withMeta: (next) => {
vfs.readfile("/file.txt", { metadata: true }, function(err, meta) {
next(err, meta.etag);
})
},
withoutMeta: (next) => {
vfs.readfile("/file.txt", { }, function(err, meta) {
next(err, meta.etag);
})
}
},
function(err, values) {
if (err) throw err;
assert(values.withMeta !== values.withoutMeta);
done();
});
});
it("should read the text file", function (done) {
vfs.readfile("/file.txt", {}, function (err, meta) {
if (err) throw err;
expect(meta).property("mime").equals("text/plain");
expect(meta).property("size").equals(23);
expect(meta).property("size").equals(44);
expect(meta).property("etag");
expect(meta).property("stream").property("readable");
var stream = meta.stream;
@ -111,9 +187,9 @@ describe('vfs-local', function () {
length += chunk.length;
});
stream.on("end", function () {
expect(length).equal(23);
expect(length).equal(44);
var body = chunks.join("");
expect(body).equal("This is a simple file!\n");
expect(body).equal("This is a file with exactly 42 characters!!\n");
done();
});
});
@ -134,7 +210,7 @@ describe('vfs-local', function () {
vfs.readfile("/file.txt", {head:true}, function (err, meta) {
if (err) throw err;
expect(meta).property("mime").equal("text/plain");
expect(meta).property("size").equal(23);
expect(meta).property("size").equal(44);
expect(meta).property("mime").ok;
expect(meta.stream).not.ok;
done();
@ -148,7 +224,7 @@ describe('vfs-local', function () {
vfs.readfile("/file.txt", {etag:etag}, function (err, meta) {
if (err) throw err;
expect(meta).property("mime").equal("text/plain");
expect(meta).property("size").equal(23);
expect(meta).property("size").equal(44);
expect(meta).property("notModified").ok;
expect(meta.stream).not.ok;
done();
@ -161,7 +237,7 @@ describe('vfs-local', function () {
expect(meta).property("mime").equal("text/plain");
expect(meta).property("size").equal(3);
expect(meta).property("etag").ok;
expect(meta).property("partialContent").deep.equal({ start: 1, end: 3, size: 23 });
expect(meta).property("partialContent").deep.equal({ start: 1, end: 3, size: 44 });
expect(meta).property("stream").ok;
var stream = meta.stream;
var chunks = [];
@ -180,7 +256,7 @@ describe('vfs-local', function () {
if (err) throw err;
expect(meta).property("size").equal(10);
expect(meta).property("etag").ok;
expect(meta).property("partialContent").deep.equal({ start: 13, end: 22, size: 23 });
expect(meta).property("partialContent").deep.equal({ start: 34, end: 43, size: 44 });
done();
});
});
@ -212,7 +288,7 @@ describe('vfs-local', function () {
parts.push(part);
});
stream.on("end", function () {
expect(parts).length(5);
expect(parts).length(7);
done();
});
});
@ -340,8 +416,10 @@ describe('vfs-local', function () {
});
});
it("should create intermediate directories", function(done) {
vfs.execFile("rm", {args: ["-rf", root + "/nested"]}, function() {
vfs.execFile("rm", {args: ["-rf", root + "/nested"]}, function(err) {
assert(!err, err);
vfs.mkfile("/nested/dir/file.txt", { parents: true }, function(err, meta) {
assert(!err, err);
meta.stream.write("juhu");
meta.stream.end();
@ -627,6 +705,7 @@ describe('vfs-local', function () {
var inner = false;
vfs.mkfile(vpath, {}, function(err, meta){
assert(!err, err);
var stream = meta.stream;
stream.write("Change!");
stream.end();
@ -1016,7 +1095,8 @@ describe('vfs-local', function () {
});
var inner = false;
vfs.mkfile(vpath, { sandbox: sandbox }, function(err, meta){
vfs.mkfile(vpath, { sandbox: sandbox }, function(err, meta) {
assert(!err, err);
var stream = meta.stream;
stream.write("Change!");
stream.end();