aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeonid Logvinov <logvinov.leon@gmail.com>2018-12-19 21:11:08 +0800
committerLeonid Logvinov <logvinov.leon@gmail.com>2018-12-19 22:41:48 +0800
commit657b698e1eba7fde2322bb81547eba26491c0af4 (patch)
tree89572e6217df07336f584d56ac0c49e6385e5601
parent8ddf925a8feb41e240871fe0d57e0f40b9bb4896 (diff)
downloaddexon-sol-tools-657b698e1eba7fde2322bb81547eba26491c0af4.tar.gz
dexon-sol-tools-657b698e1eba7fde2322bb81547eba26491c0af4.tar.zst
dexon-sol-tools-657b698e1eba7fde2322bb81547eba26491c0af4.zip
Add sol-compiler watch mode
-rw-r--r--packages/sol-compiler/CHANGELOG.json13
-rw-r--r--packages/sol-compiler/package.json4
-rw-r--r--packages/sol-compiler/src/cli.ts10
-rw-r--r--packages/sol-compiler/src/compiler.ts46
-rw-r--r--packages/sol-compiler/src/utils/compiler.ts7
-rw-r--r--packages/sol-compiler/src/utils/types.ts9
-rw-r--r--packages/sol-compiler/test/compiler_utils_test.ts6
7 files changed, 88 insertions, 7 deletions
diff --git a/packages/sol-compiler/CHANGELOG.json b/packages/sol-compiler/CHANGELOG.json
index 0a757f519..17b3f9edd 100644
--- a/packages/sol-compiler/CHANGELOG.json
+++ b/packages/sol-compiler/CHANGELOG.json
@@ -1,5 +1,18 @@
[
{
+ "version": "2.0.0",
+ "changes": [
+ {
+ "note": "Add sol-compiler watch mode with -w flag",
+ "pr": "TODO"
+ },
+ {
+ "note": "Make error and warning colouring more visually pleasant and consistent with other compilers",
+ "pr": "TODO"
+ }
+ ]
+ },
+ {
"version": "1.1.16",
"changes": [
{
diff --git a/packages/sol-compiler/package.json b/packages/sol-compiler/package.json
index 0ad620b1f..86167a603 100644
--- a/packages/sol-compiler/package.json
+++ b/packages/sol-compiler/package.json
@@ -44,7 +44,9 @@
"devDependencies": {
"@0x/dev-utils": "^1.0.21",
"@0x/tslint-config": "^2.0.0",
+ "@types/chokidar": "^1.7.5",
"@types/mkdirp": "^0.5.2",
+ "@types/pluralize": "^0.0.29",
"@types/require-from-string": "^1.2.0",
"@types/semver": "^5.5.0",
"chai": "^4.0.1",
@@ -74,10 +76,12 @@
"@0x/web3-wrapper": "^3.2.1",
"@types/yargs": "^11.0.0",
"chalk": "^2.3.0",
+ "chokidar": "^2.0.4",
"ethereum-types": "^1.1.4",
"ethereumjs-util": "^5.1.1",
"lodash": "^4.17.5",
"mkdirp": "^0.5.1",
+ "pluralize": "^7.0.0",
"require-from-string": "^2.0.1",
"semver": "5.5.0",
"solc": "^0.4.23",
diff --git a/packages/sol-compiler/src/cli.ts b/packages/sol-compiler/src/cli.ts
index 0a9db6e05..18cc68aaf 100644
--- a/packages/sol-compiler/src/cli.ts
+++ b/packages/sol-compiler/src/cli.ts
@@ -25,6 +25,10 @@ const SEPARATOR = ',';
type: 'string',
description: 'comma separated list of contracts to compile',
})
+ .option('watch', {
+ alias: 'w',
+ default: false,
+ })
.help().argv;
const contracts = _.isUndefined(argv.contracts)
? undefined
@@ -37,7 +41,11 @@ const SEPARATOR = ',';
contracts,
};
const compiler = new Compiler(opts);
- await compiler.compileAsync();
+ if (argv.watch) {
+ await compiler.watchAsync();
+ } else {
+ await compiler.compileAsync();
+ }
})().catch(err => {
logUtils.log(err);
process.exit(1);
diff --git a/packages/sol-compiler/src/compiler.ts b/packages/sol-compiler/src/compiler.ts
index 45cbf527b..17a1ce563 100644
--- a/packages/sol-compiler/src/compiler.ts
+++ b/packages/sol-compiler/src/compiler.ts
@@ -6,13 +6,17 @@ import {
NPMResolver,
RelativeFSResolver,
Resolver,
+ SpyResolver,
URLResolver,
} from '@0x/sol-resolver';
import { logUtils } from '@0x/utils';
+import chalk from 'chalk';
+import * as chokidar from 'chokidar';
import { CompilerOptions, ContractArtifact, ContractVersionData, StandardOutput } from 'ethereum-types';
import * as fs from 'fs';
import * as _ from 'lodash';
import * as path from 'path';
+import * as pluralize from 'pluralize';
import * as semver from 'semver';
import solc = require('solc');
@@ -30,6 +34,7 @@ import {
} from './utils/compiler';
import { constants } from './utils/constants';
import { fsWrapper } from './utils/fs_wrapper';
+import { CompilationError } from './utils/types';
import { utils } from './utils/utils';
type TYPE_ALL_FILES_IDENTIFIER = '*';
@@ -129,6 +134,43 @@ export class Compiler {
const promisedOutputs = this._compileContractsAsync(this._getContractNamesToCompile(), false);
return promisedOutputs;
}
+ public async watchAsync(): Promise<void> {
+ console.clear(); // tslint:disable-line:no-console
+ logWithTime('Starting compilation in watch mode...');
+ const watcher = chokidar.watch('^$', { ignored: /(^|[\/\\])\../ });
+ const onFileChangedAsync = async () => {
+ watcher.unwatch('*'); // Stop watching
+ try {
+ await this.compileAsync();
+ logWithTime('Found 0 errors. Watching for file changes.');
+ } catch (err) {
+ if (err.typeName === 'CompilationError') {
+ logWithTime(`Found ${err.errorsCount} ${pluralize('error', err.errorsCount)}. Watching for file changes.`);
+ } else {
+ logWithTime('Found errors. Watching for file changes.');
+ }
+ }
+
+ const pathsToWatch = this._getPathsToWatch();
+ watcher.add(pathsToWatch);
+ };
+ await onFileChangedAsync();
+ watcher.on('change', (changedFilePath: string) => {
+ console.clear(); // tslint:disable-line:no-console
+ logWithTime('File change detected. Starting incremental compilation...');
+ onFileChangedAsync();
+ });
+ }
+ private _getPathsToWatch(): string[] {
+ const contractNames = this._getContractNamesToCompile();
+ const spyResolver = new SpyResolver(this._resolver);
+ for (const contractName of contractNames) {
+ const contractSource = spyResolver.resolve(contractName);
+ getSourceTreeHash(spyResolver, contractSource.path);
+ }
+ const pathsToWatch = _.uniq(spyResolver.resolvedContractSources.map(cs => cs.absolutePath));
+ return pathsToWatch;
+ }
private _getContractNamesToCompile(): string[] {
let contractNamesToCompile;
if (this._specifiedContracts === ALL_CONTRACTS_IDENTIFIER) {
@@ -298,3 +340,7 @@ export class Compiler {
logUtils.warn(`${contractName} artifact saved!`);
}
}
+
+function logWithTime(arg: string): void {
+ logUtils.log(`[${chalk.gray(new Date().toLocaleTimeString())}] ${arg}`);
+}
diff --git a/packages/sol-compiler/src/utils/compiler.ts b/packages/sol-compiler/src/utils/compiler.ts
index 034f72f8d..486d8bedd 100644
--- a/packages/sol-compiler/src/utils/compiler.ts
+++ b/packages/sol-compiler/src/utils/compiler.ts
@@ -12,6 +12,7 @@ import { binPaths } from '../solc/bin_paths';
import { constants } from './constants';
import { fsWrapper } from './fs_wrapper';
+import { CompilationError } from './types';
/**
* Gets contract data on network or returns if an artifact does not exist.
@@ -147,13 +148,13 @@ function printCompilationErrorsAndWarnings(solcErrors: solc.SolcError[]): void {
if (!_.isEmpty(errors)) {
errors.forEach(error => {
const normalizedErrMsg = getNormalizedErrMsg(error.formattedMessage || error.message);
- logUtils.warn(chalk.red(normalizedErrMsg));
+ logUtils.log(chalk.red('error'), normalizedErrMsg);
});
- throw new Error('Compilation errors encountered');
+ throw new CompilationError(errors.length);
} else {
warnings.forEach(warning => {
const normalizedWarningMsg = getNormalizedErrMsg(warning.formattedMessage || warning.message);
- logUtils.warn(chalk.yellow(normalizedWarningMsg));
+ logUtils.log(chalk.yellow('warning'), normalizedWarningMsg);
});
}
}
diff --git a/packages/sol-compiler/src/utils/types.ts b/packages/sol-compiler/src/utils/types.ts
index b211cfcbc..64328899d 100644
--- a/packages/sol-compiler/src/utils/types.ts
+++ b/packages/sol-compiler/src/utils/types.ts
@@ -29,3 +29,12 @@ export interface Token {
}
export type DoneCallback = (err?: Error) => void;
+
+export class CompilationError extends Error {
+ public errorsCount: number;
+ public typeName = 'CompilationError';
+ constructor(errorsCount: number) {
+ super('Compilation errors encountered');
+ this.errorsCount = errorsCount;
+ }
+}
diff --git a/packages/sol-compiler/test/compiler_utils_test.ts b/packages/sol-compiler/test/compiler_utils_test.ts
index 4fe7b994e..b8c18110c 100644
--- a/packages/sol-compiler/test/compiler_utils_test.ts
+++ b/packages/sol-compiler/test/compiler_utils_test.ts
@@ -52,7 +52,7 @@ describe('Compiler utils', () => {
const source = await fsWrapper.readFileAsync(path, {
encoding: 'utf8',
});
- const dependencies = parseDependencies({ source, path });
+ const dependencies = parseDependencies({ source, path, absolutePath: path });
const expectedDependencies = [
'zeppelin-solidity/contracts/token/ERC20/ERC20.sol',
'packages/sol-compiler/lib/test/fixtures/contracts/TokenTransferProxy.sol',
@@ -68,7 +68,7 @@ describe('Compiler utils', () => {
const source = await fsWrapper.readFileAsync(path, {
encoding: 'utf8',
});
- expect(parseDependencies({ source, path })).to.be.deep.equal([
+ expect(parseDependencies({ source, path, absolutePath: path })).to.be.deep.equal([
'zeppelin-solidity/contracts/ownership/Ownable.sol',
'zeppelin-solidity/contracts/token/ERC20/ERC20.sol',
]);
@@ -77,7 +77,7 @@ describe('Compiler utils', () => {
it.skip('correctly parses commented out dependencies', async () => {
const path = '';
const source = `// import "./TokenTransferProxy.sol";`;
- expect(parseDependencies({ path, source })).to.be.deep.equal([]);
+ expect(parseDependencies({ path, source, absolutePath: path })).to.be.deep.equal([]);
});
});
});