mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#!/usr/bin/env python3
 | 
						|
 | 
						|
# ------------------------------------------------------------------------------
 | 
						|
# This file is part of solidity.
 | 
						|
#
 | 
						|
# solidity is free software: you can redistribute it and/or modify
 | 
						|
# it under the terms of the GNU General Public License as published by
 | 
						|
# the Free Software Foundation, either version 3 of the License, or
 | 
						|
# (at your option) any later version.
 | 
						|
#
 | 
						|
# solidity is distributed in the hope that it will be useful,
 | 
						|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
# GNU General Public License for more details.
 | 
						|
#
 | 
						|
# You should have received a copy of the GNU General Public License
 | 
						|
# along with solidity.  If not, see <http://www.gnu.org/licenses/>
 | 
						|
#
 | 
						|
# (c) 2023 solidity contributors.
 | 
						|
# ------------------------------------------------------------------------------
 | 
						|
 | 
						|
import os
 | 
						|
import re
 | 
						|
import subprocess
 | 
						|
import sys
 | 
						|
from argparse import ArgumentParser
 | 
						|
from enum import Enum
 | 
						|
from pathlib import Path
 | 
						|
from typing import List
 | 
						|
from typing import Set
 | 
						|
 | 
						|
# Our scripts/ is not a proper Python package so we need to modify PYTHONPATH to import from it
 | 
						|
# pragma pylint: disable=import-error,wrong-import-position
 | 
						|
PROJECT_ROOT = Path(__file__).parents[2]
 | 
						|
sys.path.insert(0, f"{PROJECT_ROOT}/scripts/common")
 | 
						|
 | 
						|
from git_helpers import git_commit_hash
 | 
						|
 | 
						|
SOLC_FULL_VERSION_REGEX = re.compile(r"^[a-zA-Z: ]*(.*)$")
 | 
						|
SOLC_SHORT_VERSION_REGEX = re.compile(r"^([0-9.]+).*\+|\-$")
 | 
						|
 | 
						|
 | 
						|
class SettingsPreset(Enum):
 | 
						|
    LEGACY_NO_OPTIMIZE = 'legacy-no-optimize'
 | 
						|
    IR_NO_OPTIMIZE = 'ir-no-optimize'
 | 
						|
    LEGACY_OPTIMIZE_EVM_ONLY = 'legacy-optimize-evm-only'
 | 
						|
    IR_OPTIMIZE_EVM_ONLY = 'ir-optimize-evm-only'
 | 
						|
    LEGACY_OPTIMIZE_EVM_YUL = 'legacy-optimize-evm+yul'
 | 
						|
    IR_OPTIMIZE_EVM_YUL = 'ir-optimize-evm+yul'
 | 
						|
 | 
						|
 | 
						|
def compiler_settings(evm_version: str, via_ir: bool = False, optimizer: bool = False, yul: bool = False) -> dict:
 | 
						|
    return {
 | 
						|
        "optimizer": {"enabled": optimizer, "details": {"yul": yul}},
 | 
						|
        "evmVersion": evm_version,
 | 
						|
        "viaIR": via_ir,
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
def settings_from_preset(preset: SettingsPreset, evm_version: str) -> dict:
 | 
						|
    return {
 | 
						|
        SettingsPreset.LEGACY_NO_OPTIMIZE:       compiler_settings(evm_version),
 | 
						|
        SettingsPreset.IR_NO_OPTIMIZE:           compiler_settings(evm_version, via_ir=True),
 | 
						|
        SettingsPreset.LEGACY_OPTIMIZE_EVM_ONLY: compiler_settings(evm_version, optimizer=True),
 | 
						|
        SettingsPreset.IR_OPTIMIZE_EVM_ONLY:     compiler_settings(evm_version, via_ir=True, optimizer=True),
 | 
						|
        SettingsPreset.LEGACY_OPTIMIZE_EVM_YUL:  compiler_settings(evm_version, optimizer=True, yul=True),
 | 
						|
        SettingsPreset.IR_OPTIMIZE_EVM_YUL:      compiler_settings(evm_version, via_ir=True, optimizer=True, yul=True),
 | 
						|
    }[preset]
 | 
						|
 | 
						|
 | 
						|
def parse_custom_presets(presets: List[str]) -> Set[SettingsPreset]:
 | 
						|
    return {SettingsPreset(p) for p in presets}
 | 
						|
 | 
						|
def parse_command_line(description: str, args: List[str]):
 | 
						|
    arg_parser = ArgumentParser(description)
 | 
						|
    arg_parser.add_argument(
 | 
						|
        "solc_binary_type",
 | 
						|
        metavar="solc-binary-type",
 | 
						|
        type=str,
 | 
						|
        default="native",
 | 
						|
        choices=["native", "solcjs"],
 | 
						|
        help="""Solidity compiler binary type""",
 | 
						|
    )
 | 
						|
    arg_parser.add_argument(
 | 
						|
        "solc_binary_path",
 | 
						|
        metavar="solc-binary-path",
 | 
						|
        type=Path,
 | 
						|
        help="""Path to solc binary""",
 | 
						|
    )
 | 
						|
    arg_parser.add_argument(
 | 
						|
        "selected_presets",
 | 
						|
        metavar="selected-presets",
 | 
						|
        help="""List of compiler settings presets""",
 | 
						|
        nargs='*',
 | 
						|
    )
 | 
						|
    return arg_parser.parse_args(args)
 | 
						|
 | 
						|
 | 
						|
def download_project(test_dir: Path, repo_url: str, ref_type: str = "branch", ref: str = "master"):
 | 
						|
    assert ref_type in ("commit", "branch", "tag")
 | 
						|
 | 
						|
    print(f"Cloning {ref_type} {ref} of {repo_url}...")
 | 
						|
    if ref_type == "commit":
 | 
						|
        os.mkdir(test_dir)
 | 
						|
        os.chdir(test_dir)
 | 
						|
        subprocess.run(["git", "init"], check=True)
 | 
						|
        subprocess.run(["git", "remote", "add", "origin", repo_url], check=True)
 | 
						|
        subprocess.run(["git", "fetch", "--depth", "1", "origin", ref], check=True)
 | 
						|
        subprocess.run(["git", "reset", "--hard", "FETCH_HEAD"], check=True)
 | 
						|
    else:
 | 
						|
        os.chdir(test_dir.parent)
 | 
						|
        subprocess.run(["git", "clone", "--no-progress", "--depth", "1", repo_url, "-b", ref, test_dir.resolve()], check=True)
 | 
						|
        if not test_dir.exists():
 | 
						|
            raise RuntimeError("Failed to clone the project.")
 | 
						|
        os.chdir(test_dir)
 | 
						|
 | 
						|
    if (test_dir / ".gitmodules").exists():
 | 
						|
        subprocess.run(["git", "submodule", "update", "--init"], check=True)
 | 
						|
 | 
						|
    print(f"Current commit hash: {git_commit_hash()}")
 | 
						|
 | 
						|
 | 
						|
def parse_solc_version(solc_version_string: str) -> str:
 | 
						|
    solc_version_match = re.search(SOLC_FULL_VERSION_REGEX, solc_version_string)
 | 
						|
    if solc_version_match is None:
 | 
						|
        raise RuntimeError(f"Solc version could not be found in: {solc_version_string}.")
 | 
						|
    return solc_version_match.group(1)
 | 
						|
 | 
						|
 | 
						|
def get_solc_short_version(solc_full_version: str) -> str:
 | 
						|
    solc_short_version_match = re.search(SOLC_SHORT_VERSION_REGEX, solc_full_version)
 | 
						|
    if solc_short_version_match is None:
 | 
						|
        raise RuntimeError(f"Error extracting short version string from: {solc_full_version}.")
 | 
						|
    return solc_short_version_match.group(1)
 | 
						|
 | 
						|
 | 
						|
def store_benchmark_report(self):
 | 
						|
    raise NotImplementedError()
 | 
						|
 | 
						|
 | 
						|
def replace_version_pragmas(test_dir: Path):
 | 
						|
    """
 | 
						|
    Replace fixed-version pragmas (part of Consensys best practice).
 | 
						|
    Include all directories to also cover node dependencies.
 | 
						|
    """
 | 
						|
    print("Replacing fixed-version pragmas...")
 | 
						|
    for source in test_dir.glob("**/*.sol"):
 | 
						|
        content = source.read_text(encoding="utf-8")
 | 
						|
        content = re.sub(r"pragma solidity [^;]+;", r"pragma solidity >=0.0;", content)
 | 
						|
        with open(source, "w", encoding="utf-8") as f:
 | 
						|
            f.write(content)
 |