diff --git a/Dockerfile b/Dockerfile index d1a0df3..9680bd1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,21 +5,20 @@ ARG VERSION_RUST="nightly-2022-08-23" ARG VERSION_BINARYEN="105-1" ARG VERSION_WABT="1.0.27-1" -RUN apt-get update && apt-get install wget -y -RUN apt-get update && apt-get install python3.10 python-is-python3 -y -RUN apt-get update && apt-get install build-essential -y +# Install dependencies (including binaryen and wabt) +RUN apt-get update && apt-get install -y \ + wget \ + build-essential \ + python3.10 python-is-python3 \ + binaryen=${VERSION_BINARYEN} \ + wabt=${VERSION_WABT} # Install rust RUN wget -O rustup.sh https://sh.rustup.rs && \ chmod +x rustup.sh && \ CARGO_HOME=/rust RUSTUP_HOME=/rust ./rustup.sh --verbose --default-toolchain ${VERSION_RUST} --profile minimal --target wasm32-unknown-unknown -y && \ - rm rustup.sh - -# Install wasm-opt -RUN apt-get update && apt-get install binaryen=${VERSION_BINARYEN} - -# Install wabt -RUN apt-get update && apt-get install wabt=${VERSION_WABT} + rm rustup.sh && \ + chmod -R 777 /rust COPY "./build_within_docker.py" "/build.py" @@ -28,13 +27,11 @@ ENV CARGO_HOME="/rust" ENV RUSTUP_HOME="/rust" # Additional arguments (must be provided at "docker run"): -# --output-owner-id -# --output-group-id # --no-wasm-opt (optional) ENTRYPOINT ["python", "./build.py", \ "--project", "/project", \ "--output", "/output", \ - "--cargo-target-dir", "/cargo-target-dir"] + "--cargo-target-dir", "/rust/cargo-target-dir"] LABEL frozen="yes" LABEL rust=${VERSION_RUST} diff --git a/README.md b/README.md index ec9ac49..f27dcf9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # elrond-sdk-images-build-contract-rust -Docker image (and wrappers) for reproducible contract builds (Rust). +Docker image (and wrappers) for reproducible contract builds (Rust). See [docs.elrond.com](https://docs.elrond.com/developers/reproducible-contract-builds/). ## Build the Docker image @@ -35,8 +35,6 @@ This is useful for useful for testing, debugging and reviewing the script. export PROJECT=${HOME}/contracts/reproducible-contract-build-example export OUTPUT=${HOME}/contracts/output export CARGO_TARGET_DIR=${HOME}/cargo-target-dir -export OWNER_ID=$(id -u) -export GROUP_ID=$(id -g) export PATH=${HOME}/elrondsdk/vendor-rust/bin:${HOME}/elrondsdk/wabt/latest/bin:${PATH} export RUSTUP_HOME=${HOME}/elrondsdk/vendor-rust export CARGO_HOME=${HOME}/elrondsdk/vendor-rust @@ -46,7 +44,5 @@ Build a project: ``` python3 ./build_within_docker.py --project=${PROJECT} --output=${OUTPUT} \ - --cargo-target-dir=${CARGO_TARGET_DIR} \ - --output-owner-id=${OWNER_ID} \ - --output-group-id=${GROUP_ID} + --cargo-target-dir=${CARGO_TARGET_DIR} ``` diff --git a/build_with_docker.py b/build_with_docker.py index 7e7d9cc..05f517a 100644 --- a/build_with_docker.py +++ b/build_with_docker.py @@ -42,12 +42,12 @@ def main(cli_args: List[str]): def run_docker(image: str, docker_interactive: bool, docker_tty: bool, project_path: Path, output_path: Path, cargo_target_dir: Union[Path, None], no_wasm_opt: bool): docker_mount_args = [ - "--mount", f"type=bind,source={project_path},destination=/project", - "--mount", f"type=bind,source={output_path},destination=/output" + "--volume", f"{project_path}:/project", + "--volume", f"{output_path}:/output" ] if cargo_target_dir: - docker_mount_args += ["--mount", f"type=bind,source={cargo_target_dir},destination=/cargo-target-dir"] + docker_mount_args += ["--volume", f"{cargo_target_dir}:/cargo-target-dir"] docker_args = ["docker", "run"] @@ -57,12 +57,10 @@ def run_docker(image: str, docker_interactive: bool, docker_tty: bool, project_p docker_args += ["--tty"] docker_args += docker_mount_args + docker_args += ["--user", f"{str(os.getuid())}:{str(os.getgid())}"] docker_args += ["--rm", image] - entrypoint_args = [ - "--output-owner-id", str(os.getuid()), - "--output-group-id", str(os.getgid()) - ] + entrypoint_args: List[str] = [] if no_wasm_opt: entrypoint_args.append("--no-wasm-opt") diff --git a/build_within_docker.py b/build_within_docker.py index 3459f20..7d2010e 100644 --- a/build_within_docker.py +++ b/build_within_docker.py @@ -4,6 +4,7 @@ import shutil import subprocess import sys +import time from argparse import ArgumentParser from hashlib import blake2b from pathlib import Path @@ -55,6 +56,8 @@ def dump_to_file(self, file: Path): def main(cli_args: List[str]): logging.basicConfig(level=logging.DEBUG) + start_time = time.time() + artifacts_accumulator = BuildArtifactsAccumulator() parser = ArgumentParser() @@ -62,14 +65,10 @@ def main(cli_args: List[str]): parser.add_argument("--output", type=str, required=True) parser.add_argument("--no-wasm-opt", action="store_true", default=False, help="do not optimize wasm files after the build (default: %(default)s)") parser.add_argument("--cargo-target-dir", type=str, required=True, help="Cargo's target-dir") - parser.add_argument("--output-owner-id", type=int, required=True, help="set owner of output folder") - parser.add_argument("--output-group-id", type=int, required=True, help="set group of output folder") parsed_args = parser.parse_args(cli_args) project_path = Path(parsed_args.project).expanduser() parent_output_directory = Path(parsed_args.output) - owner_id = parsed_args.output_owner_id - group_id = parsed_args.output_group_id contracts_directories = get_contracts_directories(project_path) @@ -96,7 +95,7 @@ def main(cli_args: List[str]): # The archive will also include the "output" folder (useful for debugging) clean(build_directory, clean_output=False) - promote_cargo_lock_to_contract_directory(build_directory, contract_directory, owner_id, group_id) + promote_cargo_lock_to_contract_directory(build_directory, contract_directory) # The archive is created after build, so that Cargo.lock files are included, as well (useful for debugging) archive_source_code(contract_name, contract_version, build_directory, output_subdirectory) @@ -104,7 +103,10 @@ def main(cli_args: List[str]): artifacts_accumulator.gather_artifacts(contract_name, output_subdirectory) artifacts_accumulator.dump_to_file(parent_output_directory / "artifacts.json") - adjust_output_ownership(parent_output_directory, owner_id, group_id) + + end_time = time.time() + time_elapsed = end_time - start_time + logger.info(f"Built in {time_elapsed} seconds, as user = {os.getuid()}, group = {os.getgid()}") def get_contracts_directories(project_path: Path) -> List[Path]: @@ -168,11 +170,10 @@ def build(context: BuildContext): shutil.copytree(cargo_output_directory, context.output_directory, dirs_exist_ok=True) -def promote_cargo_lock_to_contract_directory(build_directory: Path, contract_directory: Path, owner_id: int, group_id: int): +def promote_cargo_lock_to_contract_directory(build_directory: Path, contract_directory: Path): from_path = build_directory / "wasm" / "Cargo.lock" to_path = contract_directory / "wasm" / "Cargo.lock" shutil.copy(from_path, to_path) - os.chown(to_path, owner_id, group_id) def generate_wabt_artifacts(wasm_file: Path): @@ -233,15 +234,5 @@ def archive_source_code(contract_name: str, contract_version: str, input_directo logger.info(f"Created archive: {archive_file}") -def adjust_output_ownership(output_directory: Path, owner_id: int, group_id: int): - logger.info(f"Adjust ownership of output directory: directory = {output_directory}, owner = {owner_id}, group = {group_id}") - - for root, dirs, files in os.walk(output_directory): - for item in dirs: - os.chown(Path(root) / item, owner_id, group_id) - for item in files: - os.chown(Path(root) / item, owner_id, group_id) - - if __name__ == "__main__": main(sys.argv[1:])