@authereum/zos
Version:
Command-line interface for the ZeppelinOS smart contract platform
146 lines • 7.88 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const lodash_max_1 = __importDefault(require("lodash.max"));
const lodash_maxby_1 = __importDefault(require("lodash.maxby"));
const lodash_pick_1 = __importDefault(require("lodash.pick"));
const lodash_omitby_1 = __importDefault(require("lodash.omitby"));
const lodash_isundefined_1 = __importDefault(require("lodash.isundefined"));
const fs_extra_1 = require("fs-extra");
const fs_1 = require("fs");
const zos_lib_1 = require("zos-lib");
const SolidityContractsCompiler_1 = require("./SolidityContractsCompiler");
const imports_fs_1 = require("@resolver-engine/imports-fs");
const ResolverEngineGatherer_1 = require("./ResolverEngineGatherer");
const solidity_1 = require("../../../utils/solidity");
const try_1 = require("../../../utils/try");
function compileProject(options = {}) {
return __awaiter(this, void 0, void 0, function* () {
const inputDir = options.inputDir || zos_lib_1.Contracts.getLocalContractsDir();
const outputDir = options.outputDir || zos_lib_1.Contracts.getLocalBuildDir();
const projectCompiler = new SolidityProjectCompiler(inputDir, outputDir, options);
yield projectCompiler.call();
return {
contracts: projectCompiler.contracts,
compilerVersion: projectCompiler.compilerVersion,
};
});
}
exports.compileProject = compileProject;
class SolidityProjectCompiler {
constructor(inputDir, outputDir, options = {}) {
this.inputDir = inputDir;
this.outputDir = outputDir;
this.roots = [];
this.contracts = [];
this.compilerOutput = [];
this.options = options;
}
call() {
return __awaiter(this, void 0, void 0, function* () {
yield this._loadSoliditySourcesFromDir();
yield this._loadDependencies();
if (this.contracts.length === 0) {
zos_lib_1.Loggy.noSpin(__filename, 'call', 'compile-contracts', 'No contracts found to compile.');
return;
}
yield this._resolveCompilerVersion();
if (!this._shouldCompile()) {
zos_lib_1.Loggy.noSpin(__filename, 'call', `compile-contracts`, 'Nothing to compile, all contracts are up to date.');
return;
}
zos_lib_1.Loggy.spin(__filename, 'call', 'compile-contracts', `Compiling contracts with solc ${this.compilerVersion.version} (${this.compilerVersion.build})`);
this.compilerOutput = yield SolidityContractsCompiler_1.compileWith(this.compilerVersion, this.contracts, this.options);
this._writeOutput();
zos_lib_1.Loggy.succeed('compile-contracts', `Compiled contracts with solc ${this.compilerVersion.version} (${this.compilerVersion.build})`);
});
}
_loadSoliditySourcesFromDir(dir = this.inputDir) {
// TODO: Replace by a glob expression
fs_1.readdirSync(dir).forEach(fileName => {
const filePath = path_1.default.resolve(dir, fileName);
if (fs_1.lstatSync(filePath).isDirectory()) {
this._loadSoliditySourcesFromDir(filePath);
}
else if (path_1.default.extname(filePath).toLowerCase() === '.sol') {
this.roots.push(filePath);
}
});
}
_loadDependencies() {
return __awaiter(this, void 0, void 0, function* () {
const importFiles = yield ResolverEngineGatherer_1.gatherSources(this.roots, this.inputDir, imports_fs_1.ImportsFsEngine());
const cwd = process.cwd();
this.contracts = importFiles.map(file => ({
fileName: path_1.default.basename(file.url),
filePath: path_1.default.isAbsolute(file.url)
? path_1.default.relative(cwd, file.url)
: file.url,
source: file.source,
lastModified: try_1.tryFunc(() => fs_1.statSync(file.url).mtimeMs),
}));
});
}
_resolveCompilerVersion() {
return __awaiter(this, void 0, void 0, function* () {
this.compilerVersion = yield SolidityContractsCompiler_1.resolveCompilerVersion(this.contracts, this.options);
});
}
_shouldCompile() {
const artifacts = this._listArtifacts();
const artifactsWithMtimes = artifacts.map(artifact => ({
artifact,
mtime: fs_1.statSync(artifact).mtimeMs,
}));
// We pick a single artifact (the most recent one) to get the version it was compiled with
const latestArtifact = lodash_maxby_1.default(artifactsWithMtimes, 'mtime');
const latestSchema = latestArtifact && fs_extra_1.readJsonSync(latestArtifact.artifact);
const artifactCompiledVersion = latestSchema && latestSchema.compiler.version;
const artifactSettings = latestSchema && lodash_pick_1.default(latestSchema.compiler, 'evmVersion', 'optimizer');
// Build current settings based on defaults
const currentSettings = Object.assign({ optimizer: SolidityContractsCompiler_1.DEFAULT_OPTIMIZER, evmVersion: SolidityContractsCompiler_1.DEFAULT_EVM_VERSION }, lodash_omitby_1.default(this.options, lodash_isundefined_1.default));
// Gather artifacts vs sources modified times
const maxArtifactsMtimes = lodash_max_1.default(artifactsWithMtimes.map(({ mtime }) => mtime));
const maxSourcesMtimes = lodash_max_1.default(this.contracts.map(({ lastModified }) => lastModified));
// Compile if there are no previous artifacts, or no mtimes could be collected for sources,
// or sources were modified after artifacts, or compiler version changed, or compiler settings changed
return (!maxArtifactsMtimes ||
!maxSourcesMtimes ||
maxArtifactsMtimes < maxSourcesMtimes ||
!artifactCompiledVersion ||
!solidity_1.compilerVersionsMatch(artifactCompiledVersion, this.compilerVersion.longVersion) ||
!solidity_1.compilerSettingsMatch(currentSettings, artifactSettings));
}
_writeOutput() {
// Create directory if not exists, or clear it of artifacts if it does
if (!fs_1.existsSync(this.outputDir))
fs_extra_1.ensureDirSync(this.outputDir);
else
this._listArtifacts().forEach(filePath => fs_1.unlinkSync(filePath));
// Write compiler output
this.compilerOutput.forEach(data => {
const buildFileName = `${this.outputDir}/${data.contractName}.json`;
fs_extra_1.writeJsonSync(buildFileName, data);
});
}
_listArtifacts() {
if (!fs_1.existsSync(this.outputDir))
return [];
return fs_1.readdirSync(this.outputDir)
.map(fileName => path_1.default.resolve(this.outputDir, fileName))
.filter(fileName => !fs_1.lstatSync(fileName).isDirectory())
.filter(fileName => path_1.default.extname(fileName) === '.json');
}
}
//# sourceMappingURL=SolidityProjectCompiler.js.map