Add sol-compiler watch mode
This commit is contained in:
parent
8ddf925a8f
commit
657b698e1e
@ -1,4 +1,17 @@
|
||||
[
|
||||
{
|
||||
"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": [
|
||||
|
@ -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",
|
||||
|
@ -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);
|
||||
|
@ -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}`);
|
||||
}
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user