Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change rules for selecting filename for generated files #220

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ jobs:

echo "contract C {}" > C.sol
dist/solc.js C.sol --bin
[[ -f C_sol_C.bin ]]
[[ -f C.bin ]]
- run:
name: "CLI smoke test (package)"
command: |
Expand All @@ -362,7 +362,7 @@ jobs:

echo "contract C {}" > C.sol
npx solcjs C.sol --bin
[[ -f C_sol_C.bin ]]
[[ -f C.bin ]]

solidity-solcjs-ext-test:
docker:
Expand Down
30 changes: 19 additions & 11 deletions solc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ program
'When using a package manager to install libraries, use this option to specify directories where packages are installed. ' +
'Can be used multiple times to provide multiple locations.'
)
.option('--overwrite', 'If artifacts already exist on disk, overwrite them.', false)
.option('-o, --output-dir <output-directory>', 'Output directory for the contracts.')
.option('-p, --pretty-json', 'Pretty-print all JSON output.', false)
.option('-v, --verbose', 'More detailed console output.', false);
Expand Down Expand Up @@ -224,26 +225,33 @@ if (!output) {

fs.mkdirSync(destination, { recursive: true });

function writeFile (file, content) {
file = path.join(destination, file);
function writeFile (file, extension, content) {
file = path.join(destination, `${file}.${extension}`);

if (fs.existsSync(file) && !options.overwrite) {
throw new Error(`Refusing to overwrite existing file ${file} (use --overwrite to force).`);
}

fs.writeFile(file, content, function (err) {
if (err) {
console.error('Failed to write ' + file + ': ' + err);
throw new Error(`Failed to write ${file}: ${err}`);
}
});
}

for (const fileName in output.contracts) {
for (const contractName in output.contracts[fileName]) {
let contractFileName = fileName + ':' + contractName;
contractFileName = contractFileName.replace(/[:./\\]/g, '_');

if (options.bin) {
writeFile(contractFileName + '.bin', output.contracts[fileName][contractName].evm.bytecode.object);
}
try {
if (options.bin) {
writeFile(contractName, 'bin', output.contracts[fileName][contractName].evm.bytecode.object);
}

if (options.abi) {
writeFile(contractFileName + '.abi', toFormattedJson(output.contracts[fileName][contractName].abi));
if (options.abi) {
writeFile(contractName, 'abi', toFormattedJson(output.contracts[fileName][contractName].abi));
}
} catch (err) {
console.error(err.message);
hasError = true;
}
}
}
Expand Down
137 changes: 89 additions & 48 deletions test/cli.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,109 @@
import tape from 'tape';
import spawn from 'tape-spawn';
import rimraf from 'rimraf';
import tmp from 'tmp';
import fs from 'fs';
import * as path from 'path';
import solc from '../';

const dist = path.resolve(__dirname, '..');
const solcjs = path.join(dist, 'solc.js');

function cleanupArtifacts () {
rimraf.sync(`${dist}/*{.bin,.abi}`);
}

tape('CLI', function (t) {
t.test('--version', function (st) {
const spt = spawn(st, './solc.js --version');
const spt = spawn(st, `node ${solcjs} --version`);
spt.stdout.match(solc.version() + '\n');
spt.stdout.match(/^\s*[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?\+commit\.[0-9a-f]+([a-zA-Z0-9.-]+)?\s*$/);
spt.stderr.empty();
spt.end();
});

t.test('no parameters', function (st) {
const spt = spawn(st, './solc.js');
const spt = spawn(st, `node ${solcjs}`);
spt.stderr.match(/^Must provide a file/);
spt.end();
});

t.test('no mode specified', function (st) {
const spt = spawn(st, './solc.js test/resources/fixtureSmoke.sol');
const spt = spawn(st, `node ${solcjs} test/resources/fixtureSmoke.sol`);
spt.stderr.match(/^Invalid option selected/);
spt.end();
});

t.test('--bin', function (st) {
const spt = spawn(st, './solc.js --bin test/resources/fixtureSmoke.sol');
const spt = spawn(st, `node ${solcjs} --bin test/resources/fixtureSmoke.sol`);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('--bin --optimize', function (st) {
const spt = spawn(st, './solc.js --bin --optimize test/resources/fixtureSmoke.sol');
const spt = spawn(st, `node ${solcjs} --bin --optimize test/resources/fixtureSmoke.sol`);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('--bin --optimize-runs 666', function (st) {
const spt = spawn(st, './solc.js --bin --optimize-runs 666 test/resources/fixtureSmoke.sol');
const spt = spawn(st, `node ${solcjs} --bin --optimize-runs 666 test/resources/fixtureSmoke.sol`);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('--bin --optimize-runs not-a-number', function (st) {
const spt = spawn(st, './solc.js --bin --optimize-runs not-a-number test/resources/fixtureSmoke.sol');
const spt = spawn(st, `node ${solcjs} --bin --optimize-runs not-a-number test/resources/fixtureSmoke.sol`);
spt.stderr.match(/^error: option '--optimize-runs <optimize-runs>' argument 'not-a-number' is invalid/);
spt.end();
});

t.test('invalid file specified', function (st) {
const spt = spawn(st, './solc.js --bin test/fileNotFound.sol');
const spt = spawn(st, `node ${solcjs} --bin test/fileNotFound.sol`);
spt.stderr.match(/^Error reading /);
spt.end();
});

t.test('incorrect source source', function (st) {
const spt = spawn(st, './solc.js --bin test/resources/fixtureIncorrectSource.sol');
const spt = spawn(st, `node ${solcjs} --bin test/resources/fixtureIncorrectSource.sol`);
spt.stderr.match(/SyntaxError: Invalid pragma "contract"/);
spt.end();
});

t.test('--abi', function (st) {
const spt = spawn(st, './solc.js --abi test/resources/fixtureSmoke.sol');
const spt = spawn(st, `node ${solcjs} --abi test/resources/fixtureSmoke.sol`);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('--bin --abi', function (st) {
const spt = spawn(st, './solc.js --bin --abi test/resources/fixtureSmoke.sol');
const spt = spawn(st, `node ${solcjs} --bin --abi test/resources/fixtureSmoke.sol`);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('no base path', function (st) {
const spt = spawn(
st,
'./solc.js --bin ' +
'test/resources/importA.sol ' +
'./test/resources//importA.sol ' +
path.resolve('test/resources/importA.sol')
`node ${solcjs} --bin \
test/resources/importA.sol \
./test/resources//importA.sol \
${path.resolve('test/resources/importA.sol')}`
);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('relative base path', function (st) {
Expand All @@ -96,65 +112,69 @@ tape('CLI', function (t) {
// by the import callback when it appends the base path back.
const spt = spawn(
st,
'./solc.js --bin --base-path test/resources ' +
'test/resources/importA.sol ' +
'./test/resources//importA.sol ' +
path.resolve('test/resources/importA.sol')
`node ${solcjs} --bin --base-path test/resources \
test/resources/importA.sol \
./test/resources//importA.sol \
${path.resolve('test/resources/importA.sol')}`
);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('relative non canonical base path', function (st) {
const spt = spawn(
st,
'./solc.js --bin --base-path ./test/resources ' +
'test/resources/importA.sol ' +
'./test/resources//importA.sol ' +
path.resolve('test/resources/importA.sol')
`node ${solcjs} --bin --base-path ./test/resources \
test/resources/importA.sol \
./test/resources//importA.sol \
${path.resolve('test/resources/importA.sol')}`
);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('absolute base path', function (st) {
const spt = spawn(
st,
'./solc.js --bin --base-path ' + path.resolve('test/resources') + ' ' +
'test/resources/importA.sol ' +
'./test/resources//importA.sol ' +
path.resolve('test/resources/importA.sol')
`node ${solcjs} --bin --base-path ${path.resolve('test/resources')} \
test/resources/importA.sol \
./test/resources//importA.sol \
${path.resolve('test/resources/importA.sol')}`
);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('include paths', function (st) {
const spt = spawn(
st,
'./solc.js --bin ' +
'test/resources/importCallback/base/contractB.sol ' +
'test/resources/importCallback/includeA/libY.sol ' +
'./test/resources/importCallback/includeA//libY.sol ' +
path.resolve('test/resources/importCallback/includeA/libY.sol') + ' ' +
'--base-path test/resources/importCallback/base ' +
'--include-path test/resources/importCallback/includeA ' +
'--include-path ' + path.resolve('test/resources/importCallback/includeB/')
`node ${solcjs} --bin \
test/resources/importCallback/base/contractB.sol \
test/resources/importCallback/includeA/libY.sol \
./test/resources/importCallback/includeA//libY.sol \
${path.resolve('test/resources/importCallback/includeA/libY.sol')} \
--base-path test/resources/importCallback/base \
--include-path test/resources/importCallback/includeA \
--include-path ${path.resolve('test/resources/importCallback/includeB/')}`
);
spt.stderr.empty();
spt.succeeds();
spt.end();
st.teardown(cleanupArtifacts);
});

t.test('include paths without base path', function (st) {
const spt = spawn(
st,
'./solc.js --bin ' +
'test/resources/importCallback/contractC.sol ' +
'--include-path test/resources/importCallback/includeA'
`node ${solcjs} --bin \
test/resources/importCallback/contractC.sol \
--include-path test/resources/importCallback/includeA`
);
spt.stderr.match(/--include-path option requires a non-empty base path\./);
spt.fails();
Expand All @@ -164,10 +184,10 @@ tape('CLI', function (t) {
t.test('empty include paths', function (st) {
const spt = spawn(
st,
'./solc.js --bin ' +
'test/resources/importCallback/contractC.sol ' +
'--base-path test/resources/importCallback/base ' +
'--include-path='
`node ${solcjs} --bin \
test/resources/importCallback/contractC.sol \
--base-path test/resources/importCallback/base \
--include-path=`
);
spt.stderr.match(/Empty values are not allowed in --include-path\./);
spt.fails();
Expand All @@ -190,7 +210,7 @@ tape('CLI', function (t) {
}
}
};
const spt = spawn(st, './solc.js --standard-json');
const spt = spawn(st, `node ${solcjs} --standard-json`);
spt.stdin.setEncoding('utf-8');
spt.stdin.write(JSON.stringify(input));
spt.stdin.end();
Expand Down Expand Up @@ -219,7 +239,7 @@ tape('CLI', function (t) {
}
}
};
const spt = spawn(st, './solc.js --standard-json --base-path test/resources');
const spt = spawn(st, `node ${solcjs} --standard-json --base-path test/resources`);
spt.stdin.setEncoding('utf-8');
spt.stdin.write(JSON.stringify(input));
spt.stdin.end();
Expand All @@ -245,10 +265,10 @@ tape('CLI', function (t) {
};
const spt = spawn(
st,
'./solc.js --standard-json ' +
'--base-path test/resources/importCallback/base ' +
'--include-path test/resources/importCallback/includeA ' +
'--include-path ' + path.resolve('test/resources/importCallback/includeB/')
`node ${solcjs} --standard-json \
--base-path test/resources/importCallback/base \
--include-path test/resources/importCallback/includeA \
--include-path ${path.resolve('test/resources/importCallback/includeB/')}`
);
spt.stdin.setEncoding('utf-8');
spt.stdin.write(JSON.stringify(input));
Expand All @@ -260,4 +280,25 @@ tape('CLI', function (t) {
spt.end();
});
});

t.test('attempt to overwrite without --overwrite flag', function (st) {
const cwd = tmp.dirSync({ unsafeCleanup: true }).name;
// create a fake C.bin to cause name collision
fs.openSync(`${cwd}/C.bin`, 'w');

const spt = spawn(st, `node ${solcjs} --bin ${dist}/test/resources/fixtureSmoke.sol`, { cwd });
spt.stderr.match(/^Refusing to overwrite existing file C\.bin \(use --overwrite to force\)\./);
spt.end();
});

t.test('--overwrite', function (st) {
const cwd = tmp.dirSync({ unsafeCleanup: true }).name;
// create a fake C.bin to cause name collision
fs.openSync(`${cwd}/C.bin`, 'w');

const spt = spawn(st, `node ${solcjs} --bin ${dist}/test/resources/fixtureSmoke.sol --overwrite`, { cwd });
spt.stderr.empty();
spt.succeeds();
spt.end();
});
});