Commit 21e1291a authored by Michael Amadi's avatar Michael Amadi Committed by GitHub

make custom process bash function (#12704)

* make custom process bash function

* rm Executables.sol, fix failing test

* fixes

* fixes...
parent fd1e0622
......@@ -67,11 +67,7 @@ abstract contract Artifacts {
/// as well as the JSON files that contain addresses in the `superchain-registry`
/// repo. The JSON key is the name of the contract and the value is an address.
function _loadAddresses(string memory _path) internal {
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("jq -cr < ", _path);
string memory json = string(Process.run(commands));
string memory json = Process.bash(string.concat("jq -cr < ", _path));
string[] memory keys = vm.parseJsonKeys(json, "");
for (uint256 i; i < keys.length; i++) {
string memory key = keys[i];
......
......@@ -642,11 +642,7 @@ contract L2Genesis is Deployer {
/// @notice Sorts the allocs by address
function sortJsonByKeys(string memory _path) internal {
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("cat <<< $(jq -S '.' ", _path, ") > ", _path);
Process.run(commands);
Process.bash(string.concat("cat <<< $(jq -S '.' ", _path, ") > ", _path));
}
/// @notice Funds the default dev accounts with ether
......
......@@ -9,11 +9,8 @@ import { Process } from "scripts/libraries/Process.sol";
contract SemverLock is Script {
function run() public {
// First, find all contracts with a Semver inheritance.
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = "grep -rl '@custom:semver' src | jq -Rs 'split(\"\\n\") | map(select(length > 0))'";
string memory rawFiles = string(Process.run(commands));
string memory rawFiles =
Process.bash("grep -rl '@custom:semver' src | jq -Rs 'split(\"\\n\") | map(select(length > 0))'");
string[] memory files = vm.parseJsonStringArray(rawFiles, "");
writeSemverLock(files);
......@@ -30,22 +27,21 @@ contract SemverLock is Script {
string memory fileContents = string(Process.run(commands));
// Grab the contract name
commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("echo \"", _files[i], "\"| sed -E \'s|src/.*/(.+)\\.sol|\\1|\'");
string memory contractName = string(Process.run(commands));
string memory contractName =
Process.bash(string.concat("echo \"", _files[i], "\"| sed -E 's|src/.*/(.+)\\.sol|\\1|'"));
commands[2] = "forge config --json | jq -r .out";
string memory artifactsDir = string(Process.run(commands));
string memory artifactsDir = Process.bash("forge config --json | jq -r .out");
// Handle the case where there are multiple artifacts for a contract. This happens
// when the same contract is compiled with multiple compiler versions.
string memory contractArtifactDir = string.concat(artifactsDir, "/", contractName, ".sol");
commands[2] = string.concat(
"ls -1 --color=never ", contractArtifactDir, " | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'"
string memory artifactFiles = Process.bash(
string.concat(
"ls -1 --color=never ",
contractArtifactDir,
" | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'"
)
);
string memory artifactFiles = string(Process.run(commands));
string[] memory files = stdJson.readStringArray(artifactFiles, "");
require(files.length > 0, string.concat("SemverLock: no artifacts found for ", contractName));
......
......@@ -995,17 +995,13 @@ contract Deploy is Deployer {
function _loadDevnetStMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) {
// Fetch the absolute prestate dump
string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof.json");
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("[[ -f ", filePath, " ]] && echo \"present\"");
if (Process.run(commands).length == 0) {
if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) {
revert(
"Deploy: cannon prestate dump not found, generate it with `make cannon-prestate` in the monorepo root"
);
}
commands[2] = string.concat("cat ", filePath, " | jq -r .pre");
mipsAbsolutePrestate_ = Claim.wrap(abi.decode(Process.run(commands), (bytes32)));
mipsAbsolutePrestate_ =
Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32)));
console.log(
"[Cannon Dispute Game] Using devnet MIPS Absolute prestate: %s",
vm.toString(Claim.unwrap(mipsAbsolutePrestate_))
......@@ -1017,17 +1013,13 @@ contract Deploy is Deployer {
function _loadDevnetMtMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) {
// Fetch the absolute prestate dump
string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof-mt.json");
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("[[ -f ", filePath, " ]] && echo \"present\"");
if (Process.run(commands).length == 0) {
if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) {
revert(
"Deploy: MT-Cannon prestate dump not found, generate it with `make cannon-prestate-mt` in the monorepo root"
);
}
commands[2] = string.concat("cat ", filePath, " | jq -r .pre");
mipsAbsolutePrestate_ = Claim.wrap(abi.decode(Process.run(commands), (bytes32)));
mipsAbsolutePrestate_ =
Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32)));
console.log(
"[MT-Cannon Dispute Game] Using devnet MIPS2 Absolute prestate: %s",
vm.toString(Claim.unwrap(mipsAbsolutePrestate_))
......
......@@ -4,7 +4,6 @@ pragma solidity 0.8.15;
import { Script } from "forge-std/Script.sol";
import { console2 as console } from "forge-std/console2.sol";
import { stdJson } from "forge-std/StdJson.sol";
import { Executables } from "scripts/libraries/Executables.sol";
import { Process } from "scripts/libraries/Process.sol";
import { Config, Fork, ForkUtils } from "scripts/libraries/Config.sol";
......@@ -211,12 +210,9 @@ contract DeployConfig is Script {
function l2OutputOracleStartingTimestamp() public returns (uint256) {
if (_l2OutputOracleStartingTimestamp < 0) {
bytes32 tag = l1StartingBlockTag();
string[] memory cmd = new string[](3);
cmd[0] = Executables.bash;
cmd[1] = "-c";
cmd[2] = string.concat("cast block ", vm.toString(tag), " --json | ", Executables.jq, " .timestamp");
bytes memory res = Process.run(cmd);
return stdJson.readUint(string(res), "");
string memory cmd = string.concat("cast block ", vm.toString(tag), " --json | jq .timestamp");
string memory res = Process.bash(cmd);
return stdJson.readUint(res, "");
}
return uint256(_l2OutputOracleStartingTimestamp);
}
......@@ -263,11 +259,8 @@ contract DeployConfig is Script {
}
function _getBlockByTag(string memory _tag) internal returns (bytes32) {
string[] memory cmd = new string[](3);
cmd[0] = Executables.bash;
cmd[1] = "-c";
cmd[2] = string.concat("cast block ", _tag, " --json | ", Executables.jq, " -r .hash");
bytes memory res = Process.run(cmd);
string memory cmd = string.concat("cast block ", _tag, " --json | jq -r .hash");
bytes memory res = bytes(Process.bash(cmd));
return abi.decode(res, (bytes32));
}
......
......@@ -5,8 +5,8 @@ import { Script } from "forge-std/Script.sol";
import { Artifacts } from "scripts/Artifacts.s.sol";
import { Config } from "scripts/libraries/Config.sol";
import { DeployConfig } from "scripts/deploy/DeployConfig.s.sol";
import { Executables } from "scripts/libraries/Executables.sol";
import { console } from "forge-std/console.sol";
import { Process } from "scripts/libraries/Process.sol";
/// @title Deployer
/// @author tynes
......@@ -19,11 +19,20 @@ abstract contract Deployer is Script, Artifacts {
function setUp() public virtual override {
Artifacts.setUp();
console.log("Commit hash: %s", Executables.gitCommitHash());
console.log("Commit hash: %s", gitCommitHash());
vm.etch(address(cfg), vm.getDeployedCode("DeployConfig.s.sol:DeployConfig"));
vm.label(address(cfg), "DeployConfig");
vm.allowCheatcodes(address(cfg));
cfg.read(Config.deployConfigPath());
}
/// @notice Returns the commit hash of HEAD. If no git repository is
/// found, it will return the contents of the .gitcommit file. Otherwise,
/// it will return an error. The .gitcommit file is used to store the
/// git commit of the contracts when they are packaged into docker images
/// in order to avoid the need to have a git repository in the image.
function gitCommitHash() internal returns (string memory) {
return Process.bash("cast abi-encode 'f(string)' $(git rev-parse HEAD || cat .gitcommit)");
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Vm } from "forge-std/Vm.sol";
import { Process } from "scripts/libraries/Process.sol";
/// @notice The executables used in ffi commands. These are set here
/// to have a single source of truth in case absolute paths
/// need to be used.
library Executables {
/// @notice Foundry cheatcode VM.
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
string internal constant bash = "bash";
string internal constant jq = "jq";
string internal constant forge = "forge";
string internal constant echo = "echo";
string internal constant sed = "sed";
string internal constant find = "find";
string internal constant ls = "ls";
string internal constant git = "git";
/// @notice Returns the commit hash of HEAD. If no git repository is
/// found, it will return the contents of the .gitcommit file. Otherwise,
/// it will return an error. The .gitcommit file is used to store the
/// git commit of the contracts when they are packaged into docker images
/// in order to avoid the need to have a git repository in the image.
function gitCommitHash() internal returns (string memory) {
string[] memory commands = new string[](3);
commands[0] = bash;
commands[1] = "-c";
commands[2] = "cast abi-encode 'f(string)' $(git rev-parse HEAD || cat .gitcommit)";
return abi.decode(Process.run(commands), (string));
}
}
......@@ -10,6 +10,25 @@ library Process {
/// @notice Foundry cheatcode VM.
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
/// @notice Executes a bash command in a subprocess and returns its output as a string. Will revert if the command
/// returns no output.
/// @param _command The bash command to execute
function bash(string memory _command) internal returns (string memory stdout_) {
stdout_ = bash({ _command: _command, _allowEmpty: false });
}
/// @notice Executes a bash command in a subprocess and returns its output as a string. Will 'optionally' revert if
/// the command returns no output.
/// @param _command The bash command to execute
/// @param _allowEmpty Allow empty output.
function bash(string memory _command, bool _allowEmpty) internal returns (string memory stdout_) {
string[] memory command = new string[](3);
command[0] = "bash";
command[1] = "-c";
command[2] = _command;
stdout_ = string(run({ _command: command, _allowEmpty: _allowEmpty }));
}
/// @notice Run a command in a subprocess. Fails if no output is returned.
/// @param _command Command to run.
function run(string[] memory _command) internal returns (bytes memory stdout_) {
......
......@@ -22,32 +22,21 @@ contract L2GenesisTest is Test {
/// @notice Creates a temp file and returns the path to it.
function tmpfile() internal returns (string memory) {
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = "mktemp";
bytes memory result = Process.run(commands);
return string(result);
return Process.bash("mktemp");
}
/// @notice Deletes a file at a given filesystem path. Does not force delete
/// and does not recursively delete.
function deleteFile(string memory path) internal {
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("rm ", path);
Process.run({ _command: commands, _allowEmpty: true });
Process.bash(string.concat("rm ", path), true);
}
/// @notice Returns the number of top level keys in a JSON object at a given
/// file path.
function getJSONKeyCount(string memory path) internal returns (uint256) {
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("jq 'keys | length' < ", path, " | xargs cast abi-encode 'f(uint256)'");
return abi.decode(Process.run(commands), (uint256));
bytes memory result =
bytes(Process.bash(string.concat("jq 'keys | length' < ", path, " | xargs cast abi-encode 'f(uint256)'")));
return abi.decode(result, (uint256));
}
/// @notice Helper function to run a function with a temporary dump file.
......@@ -59,43 +48,44 @@ contract L2GenesisTest is Test {
/// @notice Helper function for reading the number of storage keys for a given account.
function getStorageKeysCount(string memory _path, address _addr) internal returns (uint256) {
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] =
string.concat("jq -r '.[\"", vm.toLowercase(vm.toString(_addr)), "\"].storage | length' < ", _path);
return vm.parseUint(string(Process.run(commands)));
return vm.parseUint(
Process.bash(
string.concat("jq -r '.[\"", vm.toLowercase(vm.toString(_addr)), "\"].storage | length' < ", _path)
)
);
}
/// @notice Returns the number of accounts that contain particular code at a given path to a genesis file.
function getCodeCount(string memory path, string memory name) internal returns (uint256) {
bytes memory code = vm.getDeployedCode(name);
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat(
"jq -r 'map_values(select(.code == \"",
vm.toString(code),
"\")) | length' < ",
path,
" | xargs cast abi-encode 'f(uint256)'"
bytes memory result = bytes(
Process.bash(
string.concat(
"jq -r 'map_values(select(.code == \"",
vm.toString(code),
"\")) | length' < ",
path,
" | xargs cast abi-encode 'f(uint256)'"
)
)
);
return abi.decode(Process.run(commands), (uint256));
return abi.decode(result, (uint256));
}
/// @notice Returns the number of accounts that have a particular slot set.
function getPredeployCountWithSlotSet(string memory path, bytes32 slot) internal returns (uint256) {
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat(
"jq 'map_values(.storage | select(has(\"",
vm.toString(slot),
"\"))) | keys | length' < ",
path,
" | xargs cast abi-encode 'f(uint256)'"
bytes memory result = bytes(
Process.bash(
string.concat(
"jq 'map_values(.storage | select(has(\"",
vm.toString(slot),
"\"))) | keys | length' < ",
path,
" | xargs cast abi-encode 'f(uint256)'"
)
)
);
return abi.decode(Process.run(commands), (uint256));
return abi.decode(result, (uint256));
}
/// @notice Returns the number of accounts that have a particular slot set to a particular value.
......@@ -107,19 +97,20 @@ contract L2GenesisTest is Test {
internal
returns (uint256)
{
string[] memory commands = new string[](3);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat(
"jq 'map_values(.storage | select(.\"",
vm.toString(slot),
"\" == \"",
vm.toString(value),
"\")) | length' < ",
path,
" | xargs cast abi-encode 'f(uint256)'"
bytes memory result = bytes(
Process.bash(
string.concat(
"jq 'map_values(.storage | select(.\"",
vm.toString(slot),
"\" == \"",
vm.toString(value),
"\")) | length' < ",
path,
" | xargs cast abi-encode 'f(uint256)'"
)
)
);
return abi.decode(Process.run(commands), (uint256));
return abi.decode(result, (uint256));
}
/// @notice Tests the genesis predeploys setup using a temp file for the case where useInterop is false.
......
......@@ -5,7 +5,6 @@ pragma solidity 0.8.15;
import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol";
// Scripts
import { Executables } from "scripts/libraries/Executables.sol";
import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol";
import { Process } from "scripts/libraries/Process.sol";
......@@ -432,21 +431,14 @@ contract Initializer_Test is Bridge_Initializer {
}
// Construct the query for the initialize function in the contract's ABI.
string[] memory command = new string[](3);
command[0] = Executables.bash;
command[1] = "-c";
command[2] = string.concat(
Executables.echo,
" '",
string memory cmd = string.concat(
"echo '",
ForgeArtifacts.getAbi(contractName),
"'",
" | ",
Executables.jq,
" '.[] | select(.name == \"initialize\" and .type == \"function\")'"
"' | jq '.[] | select(.name == \"initialize\" and .type == \"function\")'"
);
// If the contract does not have an `initialize()` function, skip it.
if (Process.run(command).length == 0) {
if (bytes(Process.bash(cmd)).length == 0) {
continue;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment