This repository has been archived by the owner on Jan 25, 2022. It is now read-only.
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'display_logs' of github.com:ConsenSys/truffle-security …
…into display_logs
- Loading branch information
Showing
32 changed files
with
2,095 additions
and
88 deletions.
There are no files selected for viewing
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
14 changes: 14 additions & 0 deletions
14
compat/truffle-compile/compilerSupplier/loadingStrategies/Bundled.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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
101
compat/truffle-compile/compilerSupplier/loadingStrategies/Docker.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
94 changes: 94 additions & 0 deletions
94
compat/truffle-compile/compilerSupplier/loadingStrategies/LoadingStrategy.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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
26
compat/truffle-compile/compilerSupplier/loadingStrategies/Local.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
40 changes: 40 additions & 0 deletions
40
compat/truffle-compile/compilerSupplier/loadingStrategies/Native.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
Oops, something went wrong.