Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Commit

Permalink
Merge branch 'display_logs' of github.com:ConsenSys/truffle-security …
Browse files Browse the repository at this point in the history
…into display_logs
  • Loading branch information
rocky committed Mar 5, 2019
2 parents 52d312f + eefbdb0 commit ab25a4e
Show file tree
Hide file tree
Showing 32 changed files with 2,095 additions and 88 deletions.
File renamed without changes.
File renamed without changes.
16 changes: 16 additions & 0 deletions compat/truffle-compile/compileerror.js
@@ -0,0 +1,16 @@
var colors = require("colors");
var TruffleError = require("truffle-error");
var inherits = require("util").inherits;

inherits(CompileError, TruffleError);

function CompileError(message) {
// Note we trim() because solc likes to add extra whitespace.
var fancy_message = message.trim() + "\n" + colors.red("Compilation failed. See above.");
var normal_message = message.trim();

CompileError.super_.call(this, normal_message);
this.message = fancy_message;
};

module.exports = CompileError;
96 changes: 96 additions & 0 deletions compat/truffle-compile/compilerSupplier/index.js
@@ -0,0 +1,96 @@
const path = require("path");
const fs = require("fs");
const semver = require("semver");

const {
Bundled,
Docker,
Local,
Native,
VersionRange
} = require("./loadingStrategies");

class CompilerSupplier {
constructor(_config) {
_config = _config || {};
const defaultConfig = { version: null };
this.config = Object.assign({}, defaultConfig, _config);
this.strategyOptions = { version: this.config.version };
}

badInputError(userSpecification) {
const message =
`Could not find a compiler version matching ${userSpecification}. ` +
`compilers.solc.version option must be a string specifying:\n` +
` - a path to a locally installed solcjs\n` +
` - a solc version or range (ex: '0.4.22' or '^0.5.0')\n` +
` - a docker image name (ex: 'stable')\n` +
` - 'native' to use natively installed solc\n`;
return new Error(message);
}

load() {
const userSpecification = this.config.version;

return new Promise(async (resolve, reject) => {
let strategy;
const useDocker = this.config.docker;
const useNative = userSpecification === "native";
const useBundledSolc = !userSpecification;
const useSpecifiedLocal =
userSpecification && this.fileExists(userSpecification);
const isValidVersionRange = semver.validRange(userSpecification);

if (useDocker) {
strategy = new Docker(this.strategyOptions);
} else if (useNative) {
strategy = new Native(this.strategyOptions);
} else if (useBundledSolc) {
strategy = new Bundled(this.strategyOptions);
} else if (useSpecifiedLocal) {
strategy = new Local(this.strategyOptions);
} else if (isValidVersionRange) {
strategy = new VersionRange(this.strategyOptions);
}

if (strategy) {
try {
const solc = await strategy.load(userSpecification);
resolve(solc);
} catch (error) {
reject(error);
}
} else {
reject(this.badInputError(userSpecification));
}
});
}

fileExists(localPath) {
return fs.existsSync(localPath) || path.isAbsolute(localPath);
}

getDockerTags() {
return new Docker(this.strategyOptions).getDockerTags();
}

getReleases() {
return new VersionRange(this.strategyOptions)
.getSolcVersions()
.then(list => {
const prereleases = list.builds
.filter(build => build["prerelease"])
.map(build => build["longVersion"]);

const releases = Object.keys(list.releases);

return {
prereleases: prereleases,
releases: releases,
latestRelease: list.latestRelease
};
});
}
}

module.exports = CompilerSupplier;
@@ -0,0 +1,14 @@
const LoadingStrategy = require("./LoadingStrategy");

class Bundled extends LoadingStrategy {
load() {
return this.getBundledSolc();
}

getBundledSolc() {
this.removeListener();
return require("solc");
}
}

module.exports = Bundled;
101 changes: 101 additions & 0 deletions compat/truffle-compile/compilerSupplier/loadingStrategies/Docker.js
@@ -0,0 +1,101 @@
const request = require("request-promise");
const fs = require("fs");
const { execSync } = require("child_process");
const ora = require("ora");
const semver = require("semver");
const LoadingStrategy = require("./LoadingStrategy");
const VersionRange = require("./VersionRange");

class Docker extends LoadingStrategy {
async load() {
const versionString = await this.validateAndGetSolcVersion();
const command =
"docker run -i ethereum/solc:" + this.config.version + " --standard-json";

const versionRange = new VersionRange();
const commit = versionRange.getCommitFromVersion(versionString);

return versionRange
.getSolcByCommit(commit)
.then(solcjs => {
return {
compile: options => String(execSync(command, { input: options })),
version: () => versionString,
importsParser: solcjs
};
})
.catch(error => {
if (error.message === "No matching version found") {
throw this.errors("noVersion", versionString);
}
throw new Error(error);
});
}

getDockerTags() {
return request(this.config.dockerTagsUrl)
.then(list => JSON.parse(list).results.map(item => item.name))
.catch(error => {
throw this.errors("noRequest", this.config.dockerTagsUrl, error);
});
}

downloadDockerImage(image) {
if (!semver.valid(image)) {
const message =
`The image version you have provided is not valid.\n` +
`Please ensure that ${image} is a valid docker image name.`;
throw new Error(message);
}
const spinner = ora({
text: "Downloading Docker image",
color: "red"
}).start();
try {
execSync(`docker pull ethereum/solc:${image}`);
spinner.stop();
} catch (error) {
spinner.stop();
throw new Error(error);
}
}

async validateAndGetSolcVersion() {
const image = this.config.version;
const fileName = image + ".version";

// Skip validation if they've validated for this image before.
if (this.fileIsCached(fileName)) {
const cachePath = this.resolveCache(fileName);
return fs.readFileSync(cachePath, "utf-8");
}
// Image specified
if (!image) throw this.errors("noString", image);

// Docker exists locally
try {
execSync("docker -v");
} catch (error) {
throw this.errors("noDocker");
}

// Image exists locally
try {
execSync("docker inspect --type=image ethereum/solc:" + image);
} catch (error) {
console.log(`${image} does not exist locally.\n`);
console.log("Attempting to download the Docker image.");
this.downloadDockerImage(image);
}

// Get version & cache.
const version = execSync(
"docker run ethereum/solc:" + image + " --version"
);
const normalized = new VersionRange().normalizeSolcVersion(version);
this.addFileToCache(normalized, fileName);
return normalized;
}
}

module.exports = Docker;
@@ -0,0 +1,94 @@
const findCacheDir = require("find-cache-dir");
const fs = require("fs");

class LoadingStrategy {
constructor(options) {
const defaultConfig = {
versionsUrl: "https://solc-bin.ethereum.org/bin/list.json",
compilerUrlRoot: "https://solc-bin.ethereum.org/bin/",
dockerTagsUrl:
"https://registry.hub.docker.com/v2/repositories/ethereum/solc/tags/"
};
this.config = Object.assign({}, defaultConfig, options);
this.cachePath = findCacheDir({
name: "truffle",
cwd: __dirname,
create: true
});
}

addFileToCache(code, fileName) {
const filePath = this.resolveCache(fileName);
fs.writeFileSync(filePath, code);
}

errors(kind, input, error) {
const info = "Run `truffle compile --list` to see available versions.";

const kinds = {
noPath: "Could not find compiler at: " + input,
noVersion:
`Could not find a compiler version matching ${input}. ` +
`Please ensure you are specifying a valid version, constraint or ` +
`build in the truffle config. ${info}`,
noRequest:
"Failed to complete request to: " +
input +
". Are you connected to the internet?\n\n" +
error,
noDocker:
"You are trying to run dockerized solc, but docker is not installed.",
noImage:
"Please pull " +
input +
" from docker before trying to compile with it.",
noNative: "Could not execute local solc binary: " + error,
noString:
"`compilers.solc.version` option must be a string specifying:\n" +
" - a path to a locally installed solcjs\n" +
" - a solc version or range (ex: '0.4.22' or '^0.5.0')\n" +
" - a docker image name (ex: 'stable')\n" +
" - 'native' to use natively installed solc\n" +
"Received: " +
input +
" instead."
};

return new Error(kinds[kind]);
}

fileIsCached(fileName) {
const file = this.resolveCache(fileName);
return fs.existsSync(file);
}

load(_userSpecification) {
throw new Error(
"Abstract method LoadingStrategy.load is not implemented for this strategy."
);
}

/**
* Cleans up error listeners set (by solc?) when requiring it. (This code inherited from
* previous implementation, note to self - ask Tim about this)
*/
removeListener() {
const listeners = process.listeners("uncaughtException");
const execeptionHandler = listeners[listeners.length - 1];

if (execeptionHandler) {
process.removeListener("uncaughtException", execeptionHandler);
}
}

resolveCache(fileName) {
const thunk = findCacheDir({
name: "truffle",
cwd: __dirname,
thunk: true
});
return thunk(fileName);
}
}

module.exports = LoadingStrategy;
26 changes: 26 additions & 0 deletions compat/truffle-compile/compilerSupplier/loadingStrategies/Local.js
@@ -0,0 +1,26 @@
const path = require("path");
const originalRequire = require("original-require");
const LoadingStrategy = require("./LoadingStrategy");

class Local extends LoadingStrategy {
load(localPath) {
return this.getLocalCompiler(localPath);
}

getLocalCompiler(localPath) {
let compiler, compilerPath;
compilerPath = path.isAbsolute(localPath)
? localPath
: path.resolve(process.cwd(), localPath);

try {
compiler = originalRequire(compilerPath);
this.removeListener();
} catch (error) {
throw this.errors("noPath", localPath, error);
}
return compiler;
}
}

module.exports = Local;
@@ -0,0 +1,40 @@
const { execSync } = require("child_process");
const LoadingStrategy = require("./LoadingStrategy");
const VersionRange = require("./VersionRange");

class Native extends LoadingStrategy {
load() {
const versionString = this.validateAndGetSolcVersion();
const command = "solc --standard-json";

const versionRange = new VersionRange();
const commit = versionRange.getCommitFromVersion(versionString);
return versionRange
.getSolcByCommit(commit)
.then(solcjs => {
return {
compile: options => String(execSync(command, { input: options })),
version: () => versionString,
importsParser: solcjs
};
})
.catch(error => {
if (error.message === "No matching version found") {
throw this.errors("noVersion", versionString);
}
throw new Error(error);
});
}

validateAndGetSolcVersion() {
let version;
try {
version = execSync("solc --version");
} catch (error) {
throw this.errors("noNative", null, error);
}
return new VersionRange().normalizeSolcVersion(version);
}
}

module.exports = Native;

0 comments on commit ab25a4e

Please sign in to comment.