diff --git a/src/dapp-tests/integration/tests.sh b/src/dapp-tests/integration/tests.sh index 82987bab3..28a3db872 100755 --- a/src/dapp-tests/integration/tests.sh +++ b/src/dapp-tests/integration/tests.sh @@ -60,6 +60,17 @@ dapp_remappings() { dapp_remappings +# tests dapp remappings on a large legacy project with many implicit imports +dapp_remappings_compat() { + REV="bc6d7657f0f5190f65051543199e1b47bf29932b" + TMPDIR=$(mktemp -d) + git clone https://github.com/dapp-org/tinlake-tests "$TMPDIR" + export DAPP_ALLOW_IMPLICIT_IMPORTS=yes + (cd "$TMPDIR" && git checkout "$REV" && dapp update && dapp --use solc:0.7.6 build) +} + +dapp_remappings_compat + test_hevm_symbolic() { solc --bin-runtime -o . --overwrite factor.sol # should find counterexample diff --git a/src/dapp/default.nix b/src/dapp/default.nix index e3b21f8a9..4bdc04493 100644 --- a/src/dapp/default.nix +++ b/src/dapp/default.nix @@ -1,6 +1,7 @@ { lib, stdenv, fetchFromGitHub, makeWrapper, glibcLocales -, coreutils, git, gnused, gnumake, hevm, jshon, jq, nix -, nodejs, perl, python3, seth, shellcheck, solc, tre, dapptoolsSrc }: +, coreutils, findutils, ripgrep, git, gnused, gnumake, hevm +, jshon, jq, nix, nodejs, perl, python3, seth, shellcheck, solc +, tre, dapptoolsSrc }: stdenv.mkDerivation rec { name = "dapp-${version}"; @@ -16,7 +17,7 @@ stdenv.mkDerivation rec { postInstall = let path = lib.makeBinPath [ - coreutils git gnused gnumake hevm jshon jq nix nodejs perl seth solc tre python3 + coreutils findutils git gnused gnumake hevm jshon jq nix nodejs perl seth solc tre python3 ripgrep ]; in '' diff --git a/src/dapp/libexec/dapp/dapp-remappings b/src/dapp/libexec/dapp/dapp-remappings index 38d0df322..30acd026c 100755 --- a/src/dapp/libexec/dapp/dapp-remappings +++ b/src/dapp/libexec/dapp/dapp-remappings @@ -25,10 +25,20 @@ function buildDependencyTree(prefix) { // walk tree and build remappings function buildRemappings(pkg) { - const remappings = pkg.deps.map(dep => { - return `${pkg.path}/:${dep.name}/=${dep.path}/` - }) - return pkg.deps.map(buildRemappings).concat(remappings).flat() + const paths = mapHashes(pkg) + + let implicits = [] + if (process.env.DAPP_ALLOW_IMPLICIT_IMPORTS == "yes") { + const directs = pkg.deps.map(p => p.name) + // get the transitive deps with exactly one version that are not direct deps + const uniques = Object.entries(pkg.deps.reduce(buildVersionMap, {})) + .filter(([name, vs]) => vs.size == 1 && !directs.includes(name)) + // build remappings that allow importing these deps from `pkg` + implicits = uniques.map(([name, v]) => `${pkg.path}/:${name}/=${paths[([...v][0])]}/`) + } + + const remappings = pkg.deps.map(dep => `${pkg.path}/:${dep.name}/=${dep.path}/`) + return pkg.deps.map(buildRemappings).concat(remappings).concat(implicits).flat() } // walk tree and rewrite paths so that all packages with the same hash have the same path @@ -47,6 +57,21 @@ function mapHashes(pkg) { return pkg.deps.reduce(go, { [pkg.hash]: pkg.path }) } +// folds over a dependency tree with map as the accumlator and builds a mapping +// from package name to a set of discovered package verions +function buildVersionMap(map, pkg) { + const update = (map, dep) => { + map[dep.name] == undefined + ? map[dep.name] = new Set([dep.hash]) + : map[dep.name].add(dep.hash) + return map + } + + return pkg.deps.reduce((versions, dep) => { + return update(versions, dep) + }, update(map, pkg)) +} + // strip the leading `.` or `./` from a path function normalize(path) { return path.replace(/^\.\//, "").replace(/^\//, "") @@ -56,9 +81,9 @@ function normalize(path) { // availalbe (because it's faster), or falls back to a sha256sum of the directory contents if needed function hash(dir) { if (ls(dir).includes(".git")) { - return run("git", ["-C", dir, "rev-parse", "HEAD"]) + return run("git", ["-C", dir, "rev-parse", "HEAD"]).trim() } else { - return run("bash", ["-c", `rg --files ${dir} | sort | xargs sha256sum | sha256sum`]) + return run("bash", ["-c", `rg --files ${dir} | sort | xargs sha256sum | sha256sum | cut -d' ' -f1`]).trim() } }