embark/lib/core/file.js

153 lines
4.3 KiB
JavaScript
Raw Normal View History

const async = require('async');
const fs = require('./fs.js');
const path = require('path');
const request = require('request');
const utils = require('../utils/utils');
class File {
constructor (options) {
this.filename = options.filename.replace(/\\/g, '/');
this.type = options.type;
this.path = options.path;
2018-02-24 01:36:11 +00:00
this.basedir = options.basedir;
this.resolver = options.resolver;
}
parseFileForImport(content, isHttpContract, callback) {
const self = this;
if (typeof isHttpContract === 'function') {
callback = isHttpContract;
isHttpContract = false;
}
2018-04-19 17:29:25 +00:00
if (self.filename.indexOf('.sol') < 0) {
2018-04-18 20:32:51 +00:00
// Only supported in Solidity
return callback(null, content);
2018-04-18 20:32:51 +00:00
}
2018-09-12 18:08:00 +00:00
const regex = /import ["']([-a-zA-Z0-9@:%_+.~#?&\/=]+)["'];/g;
2018-04-18 20:32:51 +00:00
let matches;
2018-04-19 14:05:11 +00:00
const filesToDownload = [];
2018-04-19 17:29:25 +00:00
const pathWithoutFile = path.dirname(self.path);
2018-09-12 18:08:00 +00:00
let newContent = content;
2018-04-18 20:32:51 +00:00
while ((matches = regex.exec(content))) {
const httpFileObj = utils.getExternalContractUrl(matches[1]);
const fileObj = {
2018-04-19 17:29:25 +00:00
fileRelativePath: path.join(path.dirname(self.filename), matches[1]),
url: `${pathWithoutFile}/${matches[1]}`
};
if (httpFileObj) {
// Replace http import by filePath import in content
2018-09-12 18:08:00 +00:00
newContent = newContent.replace(matches[1], httpFileObj.filePath);
fileObj.fileRelativePath = httpFileObj.filePath;
fileObj.url = httpFileObj.url;
} else if (!isHttpContract) {
// Just a normal import
continue;
}
filesToDownload.push(fileObj);
2018-04-18 20:32:51 +00:00
}
2018-04-19 17:29:25 +00:00
if (self.downloadedImports) {
// We already parsed this file
2018-09-12 18:08:00 +00:00
return callback(null, newContent);
}
self.downloadedImports = true;
2018-04-19 17:29:25 +00:00
async.each(filesToDownload, ((fileObj, eachCb) => {
self.downloadFile(fileObj.fileRelativePath, fileObj.url, (_content) => {
eachCb();
});
}), (err) => {
2018-09-12 18:08:00 +00:00
callback(err, newContent);
});
2018-04-18 20:32:51 +00:00
}
2018-04-19 14:05:11 +00:00
downloadFile (filename, url, callback) {
2018-04-19 17:29:25 +00:00
const self = this;
async.waterfall([
function makeTheDir(next) {
2018-04-19 14:05:11 +00:00
fs.mkdirp(path.dirname(filename), (err) => {
if (err) {
return next(err);
}
next();
});
},
function downloadTheFile(next) {
let alreadyCalledBack = false;
function doCallback(err) {
if (alreadyCalledBack) {
return;
}
alreadyCalledBack = true;
next(err);
}
2018-04-19 14:05:11 +00:00
request(url)
.on('response', function (response) {
if (response.statusCode !== 200) {
doCallback('Getting file returned code ' + response.statusCode);
}
})
.on('error', doCallback)
2018-04-19 14:05:11 +00:00
.pipe(fs.createWriteStream(filename))
.on('finish', () => {
doCallback();
});
},
function readFile(next) {
2018-04-19 14:05:11 +00:00
fs.readFile(filename, next);
2018-04-19 17:29:25 +00:00
},
function parseForImports(content, next) {
self.parseFileForImport(content, true, (err) => {
2018-04-18 20:32:51 +00:00
next(err, content);
});
2018-04-19 17:29:25 +00:00
}
], (err, content) => {
if (err) {
2018-05-08 21:49:46 +00:00
console.error(__('Error while downloading the file'), err);
return callback('');
}
callback(content.toString());
});
}
content (callback) {
let content;
if (this.type === File.types.embark_internal) {
content = fs.readFileSync(fs.embarkPath(this.path)).toString();
} else if (this.type === File.types.dapp_file) {
content = fs.readFileSync(this.path).toString();
} else if (this.type === File.types.custom) {
return this.resolver((theContent) => {
this.parseFileForImport(theContent, (err, newContent) => {
callback(newContent);
});
});
} else if (this.type === File.types.http) {
return this.downloadFile(this.filename, this.path, (content) => {
2018-04-19 14:05:11 +00:00
if (!content) {
return callback(content);
}
this.path = this.filename;
this.type = File.types.dapp_file;
callback(content);
});
} else {
throw new Error("unknown file: " + this.filename);
}
return this.parseFileForImport(content, (err, newContent) => {
callback(newContent);
});
}
}
File.types = {
embark_internal: 'embark_internal',
dapp_file: 'dapp_file',
custom: 'custom',
http: 'http'
};
module.exports = File;