embark/lib/utils/utils.js

569 lines
13 KiB
JavaScript
Raw Normal View History

let http = require('follow-redirects').http;
let https = require('follow-redirects').https;
2018-07-15 17:43:00 +00:00
const {canonicalHost} = require('./host');
2017-12-16 02:53:11 +00:00
2018-07-16 16:48:32 +00:00
const balanceRegex = /([0-9]+) ?([a-zA-Z]*)/;
2017-02-18 19:10:01 +00:00
function joinPath() {
const path = require('path');
2017-02-18 19:10:01 +00:00
return path.join.apply(path.join, arguments);
}
2018-07-06 08:38:09 +00:00
function dirname() {
const path = require('path');
return path.dirname.apply(path.dirname, arguments);
}
2017-02-18 19:45:57 +00:00
function filesMatchingPattern(files) {
const globule = require('globule');
2017-02-19 05:00:01 +00:00
return globule.find(files, {nonull: true});
2017-02-18 19:37:07 +00:00
}
function fileMatchesPattern(patterns, intendedPath) {
const globule = require('globule');
2017-02-19 05:00:01 +00:00
return globule.isMatch(patterns, intendedPath);
2017-02-18 19:37:07 +00:00
}
2017-02-18 19:45:57 +00:00
function recursiveMerge(target, source) {
const merge = require('merge');
2017-02-18 19:45:57 +00:00
return merge.recursive(target, source);
}
2017-02-18 20:27:08 +00:00
function checkIsAvailable(url, callback) {
2017-12-05 23:14:46 +00:00
http.get(url, function (_res) {
callback(true);
2017-12-05 23:14:46 +00:00
}).on('error', function (_res) {
callback(false);
2017-02-18 20:27:08 +00:00
});
}
2017-12-16 03:15:24 +00:00
function httpGetRequest(httpObj, url, callback) {
2018-07-31 14:33:10 +00:00
httpObj.get(url, function (res) {
2017-12-16 03:11:55 +00:00
let body = '';
res.on('data', function (d) {
body += d;
});
res.on('end', function () {
callback(null, body);
});
}).on('error', function (err) {
callback(err);
2017-12-16 03:11:55 +00:00
});
2017-04-02 18:40:10 +00:00
}
2017-12-16 03:15:24 +00:00
function httpGet(url, callback) {
httpGetRequest(http, url, callback);
}
function httpsGet(url, callback) {
2017-12-16 03:15:24 +00:00
httpGetRequest(https, url, callback);
}
2017-12-31 02:44:59 +00:00
function httpGetJson(url, callback) {
2018-07-31 14:33:10 +00:00
httpGetRequest(http, url, function (err, body) {
2017-12-31 02:44:59 +00:00
try {
let parsed = JSON.parse(body);
return callback(err, parsed);
2018-07-31 14:33:10 +00:00
} catch (e) {
2017-12-31 02:44:59 +00:00
return callback(e);
}
});
}
function httpsGetJson(url, callback) {
2018-07-31 14:33:10 +00:00
httpGetRequest(https, url, function (err, body) {
try {
let parsed = JSON.parse(body);
return callback(err, parsed);
2018-07-31 14:33:10 +00:00
} catch (e) {
return callback(e);
}
});
}
2018-07-08 18:24:19 +00:00
function getJson(url, cb) {
if (url.indexOf('https') === 0) {
return httpsGetJson(url, cb);
}
httpGetJson(url, cb);
}
function pingEndpoint(host, port, type, protocol, origin, callback) {
2018-06-19 13:02:19 +00:00
const options = {
protocolVersion: 13,
perMessageDeflate: true,
origin: origin,
host: host,
port: port
};
2018-10-01 08:31:21 +00:00
if (type === 'ws') {
options.headers = {
'Sec-WebSocket-Version': 13,
Connection: 'Upgrade',
Upgrade: 'websocket',
'Sec-WebSocket-Extensions': 'permessage-deflate; client_max_window_bits',
Origin: origin
};
}
2018-06-19 13:02:19 +00:00
let req;
// remove trailing api key from infura, ie rinkeby.infura.io/nmY8WtT4QfEwz2S7wTbl
2018-07-31 14:33:10 +00:00
if (options.host.indexOf('/') > -1) {
2018-06-19 13:02:19 +00:00
options.host = options.host.split('/')[0];
}
if (protocol === 'https') {
2018-06-19 13:02:19 +00:00
req = require('https').get(options);
} else {
req = require('http').get(options);
}
req.on('error', (err) => {
callback(err);
});
req.on('response', (_response) => {
callback();
});
req.on('upgrade', (_res, _socket, _head) => {
callback();
});
}
2018-09-10 08:31:36 +00:00
function runCmd(cmd, options, callback) {
const shelljs = require('shelljs');
2018-09-12 06:20:20 +00:00
options = Object.assign({silent: true, exitOnError: true, async: true}, options || {});
const outputToConsole = !options.silent;
options.silent = true;
let result = shelljs.exec(cmd, options, function (code, stdout) {
2018-09-12 06:20:20 +00:00
if(code !== 0) {
if (options.exitOnError) {
return exit();
}
if(typeof callback === 'function') {
callback(`shell returned code ${code}`);
}
} else {
if(typeof callback === 'function') {
return callback(null, stdout);
}
}
});
result.stdout.on('data', function(data) {
if(outputToConsole) {
console.log(data);
2018-09-10 08:31:36 +00:00
}
});
result.stderr.on('data', function(data) {
if (outputToConsole) {
console.log(data);
2018-09-10 08:31:36 +00:00
}
});
}
function cd(folder) {
const shelljs = require('shelljs');
shelljs.cd(folder);
}
function sed(file, pattern, replace) {
const shelljs = require('shelljs');
shelljs.sed('-i', pattern, replace, file);
}
function exit(code) {
process.exit(code);
}
2017-12-16 02:53:11 +00:00
function downloadFile(url, dest, cb) {
const o_fs = require('fs-extra');
2017-12-16 02:53:11 +00:00
var file = o_fs.createWriteStream(dest);
2018-07-31 14:33:10 +00:00
(url.substring(0, 5) === 'https' ? https : http).get(url, function (response) {
if (response.statusCode !== 200) {
2018-09-11 20:44:37 +00:00
cb(`Download failed, response code ${response.statusCode}`);
2018-09-11 20:22:35 +00:00
return;
}
2017-12-16 02:53:11 +00:00
response.pipe(file);
2018-07-31 14:33:10 +00:00
file.on('finish', function () {
2017-12-16 02:53:11 +00:00
file.close(cb);
});
2018-07-31 14:33:10 +00:00
}).on('error', function (err) {
2017-12-16 02:53:11 +00:00
o_fs.unlink(dest);
2018-09-11 20:44:37 +00:00
cb(err.message);
2017-12-16 02:53:11 +00:00
});
}
2017-12-16 17:23:02 +00:00
function extractTar(filename, packageDirectory, cb) {
const o_fs = require('fs-extra');
const tar = require('tar');
2017-12-16 17:23:02 +00:00
o_fs.createReadStream(filename).pipe(
tar.x({
strip: 1,
C: packageDirectory
2018-07-31 14:33:10 +00:00
}).on('end', function () {
2017-12-16 17:23:02 +00:00
cb();
})
);
}
2018-07-09 13:30:27 +00:00
function extractZip(filename, packageDirectory, opts, cb) {
2018-07-06 08:38:09 +00:00
const decompress = require('decompress');
2018-07-09 13:30:27 +00:00
decompress(filename, packageDirectory, opts).then((_files) => {
2018-07-06 08:38:09 +00:00
cb();
});
}
2017-12-19 19:07:48 +00:00
function proposeAlternative(word, _dictionary, _exceptions) {
const propose = require('propose');
2017-12-19 19:07:48 +00:00
let exceptions = _exceptions || [];
let dictionary = _dictionary.filter((entry) => {
return exceptions.indexOf(entry) < 0;
});
return propose(word, dictionary, {threshold: 0.3});
}
function getExternalContractUrl(file) {
const constants = require('../constants');
let url;
const RAW_URL = 'https://raw.githubusercontent.com/';
const MALFORMED_ERROR = 'Malformed Github URL for ';
if (file.startsWith('https://github')) {
const match = file.match(/https:\/\/github\.[a-z]+\/(.*)/);
if (!match) {
console.error(MALFORMED_ERROR + file);
return null;
}
url = `${RAW_URL}${match[1].replace('blob/', '')}`;
} else if (file.startsWith('git')) {
// Match values
// [0] entire input
// [1] git://
// [2] user
// [3] repository
// [4] path
// [5] branch
const match = file.match(
2018-05-31 14:37:40 +00:00
/(git:\/\/)?github\.[a-z]+\/([-a-zA-Z0-9@:%_+.~#?&=]+)\/([-a-zA-Z0-9@:%_+.~#?&=]+)\/([-a-zA-Z0-9@:%_+.~?\/&=]+)#?([a-zA-Z0-9\/_.-]*)?/
);
if (!match) {
console.error(MALFORMED_ERROR + file);
return null;
}
let branch = match[5];
if (!branch) {
branch = 'master';
}
url = `${RAW_URL}${match[2]}/${match[3]}/${branch}/${match[4]}`;
} else if (file.startsWith('http')) {
url = file;
} else {
return null;
}
const match = url.match(
2018-04-20 16:04:27 +00:00
/\.[a-z]+\/([-a-zA-Z0-9@:%_+.~#?&\/=]+)/
);
return {
url,
filePath: constants.httpContractsDirectory + match[1]
};
}
2018-07-31 14:33:10 +00:00
function hexToNumber(hex) {
const Web3 = require('web3');
return Web3.utils.hexToNumber(hex);
}
2018-07-31 14:33:10 +00:00
function isHex(hex) {
2018-07-30 19:49:58 +00:00
const Web3 = require('web3');
return Web3.utils.isHex(hex);
}
2018-07-31 14:33:10 +00:00
function hashTo32ByteHexString(hash) {
if (isHex(hash)) {
if (!hash.startsWith('0x')) {
hash = '0x' + hash;
}
return hash;
}
const multihash = require('multihashes');
let buf = multihash.fromB58String(hash);
let digest = multihash.decode(buf).digest;
return '0x' + multihash.toHexString(digest);
}
function isValidDomain(domain) {
const isValidDomain = require('is-valid-domain');
return isValidDomain(domain);
}
function isValidEthDomain(ethDomain) {
if (!isValidDomain(ethDomain)) {
return false;
}
2018-08-30 13:53:04 +00:00
return ethDomain.substring(ethDomain.lastIndexOf('.'), ethDomain.length) === '.eth';
2018-07-31 14:33:10 +00:00
}
function decodeParams(typesArray, hexString) {
var Web3EthAbi = require('web3-eth-abi');
2018-06-08 20:34:35 +00:00
return Web3EthAbi.decodeParameters(typesArray, hexString);
}
2018-05-18 20:51:03 +00:00
function toChecksumAddress(address) {
const Web3 = require('web3');
2018-05-18 20:51:03 +00:00
return Web3.utils.toChecksumAddress(address);
}
function sha3(arg) {
const Web3 = require('web3');
2018-05-18 20:51:03 +00:00
return Web3.utils.sha3(arg);
}
2018-07-25 15:05:27 +00:00
function soliditySha3(arg) {
const Web3 = require('web3');
return Web3.utils.soliditySha3(arg);
}
function normalizeInput(input) {
if(typeof input === 'string') return input;
let args = Object.values(input);
if (args.length === 0) {
return "";
}
if (args.length === 1) {
2018-07-31 14:33:10 +00:00
if (Array.isArray(args[0])) {
return args[0].join(',');
}
return args[0] || "";
}
return ('[' + args.map((x) => {
2018-07-31 14:33:10 +00:00
if (x === null) {
return "null";
}
if (x === undefined) {
return "undefined";
}
if (Array.isArray(x)) {
return x.join(',');
}
return x;
}).toString() + ']');
}
/**
* Builds a URL
2018-07-31 14:33:10 +00:00
*
* @param {string} protocol
* The URL protocol, defaults to http.
2018-07-31 14:33:10 +00:00
* @param {string} host
* The URL host, required.
2018-07-31 14:33:10 +00:00
* @param {string} port
* The URL port, default to empty string.
2018-08-23 16:54:43 +00:00
* @param {string} [type]
* Type of connection
* @returns {string} the constructued URL, with defaults
*/
2018-08-23 16:54:43 +00:00
function buildUrl(protocol, host, port, type) {
2018-07-31 14:33:10 +00:00
if (!host) throw new Error('utils.buildUrl: parameter \'host\' is required');
if (port) port = ':' + port;
else port = '';
2018-08-23 16:54:43 +00:00
if (!protocol) {
protocol = type === 'ws' ? 'ws' : 'http';
}
return `${protocol}://${host}${port}`;
}
/**
* Builds a URL
2018-07-31 14:33:10 +00:00
*
* @param {object} configObj Object containing protocol, host, and port to be used to construct the url.
* * protocol {String} (optional) The URL protocol, defaults to http.
* * host {String} (required) The URL host.
* * port {String} (optional) The URL port, default to empty string.
* @returns {string} the constructued URL, with defaults
*/
2018-07-31 14:33:10 +00:00
function buildUrlFromConfig(configObj) {
if (!configObj) throw new Error('[utils.buildUrlFromConfig]: config object must cannot be null');
if (!configObj.host) throw new Error('[utils.buildUrlFromConfig]: object must contain a \'host\' property');
2018-08-23 16:54:43 +00:00
return this.buildUrl(configObj.protocol, canonicalHost(configObj.host), configObj.port, configObj.type);
}
2018-08-22 20:46:39 +00:00
function deconstructUrl(endpoint) {
const matches = endpoint.match(/(ws|https?):\/\/([a-zA-Z0-9_.-]*):?([0-9]*)?/);
return {
protocol: matches[1],
host: matches[2],
port: matches[3],
type: matches[1] === 'ws' ? 'ws' : 'rpc'
};
}
2018-07-16 16:48:32 +00:00
function getWeiBalanceFromString(balanceString, web3){
if(!web3){
throw new Error(__('[utils.getWeiBalanceFromString]: Missing parameter \'web3\''));
}
if (!balanceString) {
return 0;
}
const match = balanceString.match(balanceRegex);
if (!match) {
throw new Error(__('Unrecognized balance string "%s"', balanceString));
}
if (!match[2]) {
return web3.utils.toHex(parseInt(match[1], 10));
}
return web3.utils.toWei(match[1], match[2]);
}
function getHexBalanceFromString(balanceString, web3) {
if(!web3){
throw new Error(__('[utils.getWeiBalanceFromString]: Missing parameter \'web3\''));
}
if (!balanceString) {
return 0xFFFFFFFFFFFFFFFFFF;
}
if (web3.utils.isHexStrict(balanceString)) {
return balanceString;
}
const match = balanceString.match(balanceRegex);
if (!match) {
throw new Error(__('Unrecognized balance string "%s"', balanceString));
}
if (!match[2]) {
return web3.utils.toHex(parseInt(match[1], 10));
}
return web3.utils.toHex(web3.utils.toWei(match[1], match[2]));
}
2018-07-24 12:29:06 +00:00
function compact(array) {
return array.filter(n => n);
}
function groupBy(array, key) {
2018-07-31 14:33:10 +00:00
return array.reduce(function (rv, x) {
2018-07-24 12:29:06 +00:00
(rv[x[key]] = rv[x[key]] || []).push(x);
return rv;
}, {});
}
function sample(array) {
return array[Math.floor(Math.random() * array.length)];
}
function last(array) {
return array[array.length - 1];
}
2018-07-27 21:20:36 +00:00
function interceptLogs(consoleContext, logger) {
let context = {};
context.console = consoleContext;
2018-07-31 14:33:10 +00:00
context.console.log = function () {
2018-07-27 21:20:36 +00:00
logger.info(normalizeInput(arguments));
};
2018-07-31 14:33:10 +00:00
context.console.warn = function () {
2018-07-27 21:20:36 +00:00
logger.warn(normalizeInput(arguments));
};
2018-07-31 14:33:10 +00:00
context.console.info = function () {
2018-07-27 21:20:36 +00:00
logger.info(normalizeInput(arguments));
};
2018-07-31 14:33:10 +00:00
context.console.debug = function () {
2018-07-27 21:20:36 +00:00
// TODO: ue JSON.stringify
logger.debug(normalizeInput(arguments));
};
2018-07-31 14:33:10 +00:00
context.console.trace = function () {
2018-07-27 21:20:36 +00:00
logger.trace(normalizeInput(arguments));
};
2018-07-31 14:33:10 +00:00
context.console.dir = function () {
2018-07-27 21:20:36 +00:00
logger.dir(normalizeInput(arguments));
};
}
2018-08-20 15:36:29 +00:00
function errorMessage(e) {
if (typeof e === 'string') {
return e;
} else if (e && e.message) {
return e.message;
}
2018-08-20 18:57:04 +00:00
return e;
2018-08-20 15:36:29 +00:00
}
function timer(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
2018-09-20 00:47:38 +00:00
}
2018-10-10 04:00:40 +00:00
function isFolder(node) {
return node.children && node.children.length;
}
function isNotFolder(node){
return !isFolder(node);
}
function byName(a, b) {
return a.name.localeCompare(b.name);
}
function fileTreeSort(nodes){
const folders = nodes.filter(isFolder).sort(byName);
const files = nodes.filter(isNotFolder).sort(byName);
return folders.concat(files);
}
2018-10-13 00:46:53 +00:00
function copyToClipboard(text) {
const clipboardy = require('clipboardy');
clipboardy.writeSync(text);
}
2017-02-18 19:10:01 +00:00
module.exports = {
2018-07-06 15:06:55 +00:00
joinPath,
dirname,
filesMatchingPattern,
fileMatchesPattern,
recursiveMerge,
checkIsAvailable,
httpGet,
httpsGet,
httpGetJson,
httpsGetJson,
2018-07-08 18:24:19 +00:00
getJson,
2018-07-06 15:06:55 +00:00
hexToNumber,
2018-07-30 19:49:58 +00:00
isHex,
2018-07-31 14:33:10 +00:00
hashTo32ByteHexString,
isValidDomain,
isValidEthDomain,
2018-06-19 13:02:19 +00:00
pingEndpoint,
2018-07-06 15:06:55 +00:00
decodeParams,
runCmd,
2018-08-15 15:42:28 +00:00
cd,
sed,
exit,
2018-07-06 15:06:55 +00:00
downloadFile,
extractTar,
extractZip,
proposeAlternative,
2018-05-18 20:51:03 +00:00
getExternalContractUrl,
2018-07-06 15:06:55 +00:00
toChecksumAddress,
sha3,
2018-07-25 15:05:27 +00:00
soliditySha3,
normalizeInput,
buildUrl,
2018-07-16 16:48:32 +00:00
buildUrlFromConfig,
2018-08-22 20:46:39 +00:00
deconstructUrl,
2018-07-16 16:48:32 +00:00
getWeiBalanceFromString,
2018-07-24 12:29:06 +00:00
getHexBalanceFromString,
compact,
groupBy,
sample,
2018-07-27 21:20:36 +00:00
last,
2018-08-20 15:36:29 +00:00
interceptLogs,
2018-09-20 00:47:38 +00:00
errorMessage,
2018-10-10 04:00:40 +00:00
timer,
2018-10-13 00:46:53 +00:00
fileTreeSort,
copyToClipboard
2017-02-18 19:10:01 +00:00
};