diff --git a/DEPS b/DEPS index 83e003210ea..2f9d10e789e 100644 --- a/DEPS +++ b/DEPS @@ -176,6 +176,11 @@ hooks = [ "condition": 'checkout_mac and host_os != "mac" and checkout_dmg_tool', 'action': ['build/mac/cross-compile/build-libdmg-hfsplus.py', 'third_party/libdmg-hfsplus'] }, + { + 'name': 'download_rust_toolchain_aux', + 'pattern': '.', + 'action': ['python3', 'build/rust/download_rust_toolchain_aux.py'] + }, ] include_rules = [ diff --git a/build/commands/lib/config.js b/build/commands/lib/config.js index cc0b6130e64..50b7e4bf10c 100644 --- a/build/commands/lib/config.js +++ b/build/commands/lib/config.js @@ -254,6 +254,7 @@ const Config = function () { this.service_key_aichat = getEnvConfig(['service_key_aichat']) || '' this.braveIOSDeveloperOptionsCode = getEnvConfig(['brave_ios_developer_options_code']) || '' this.service_key_stt = getEnvConfig(['service_key_stt']) || '' + this.skip_download_rust_toolchain_aux = getEnvConfig(['skip_download_rust_toolchain_aux']) || false } Config.prototype.isReleaseBuild = function () { @@ -1137,6 +1138,10 @@ Object.defineProperty(Config.prototype, 'defaultOptions', { env.VSCMD_SKIP_SENDTELEMETRY = '1' } + if (this.isCI && this.skip_download_rust_toolchain_aux) { + env.SKIP_DOWNLOAD_RUST_TOOLCHAIN_AUX = '1' + } + // TeamCity displays only stderr on the "Build Problems" page when an error // occurs. By redirecting stdout to stderr, we ensure that all outputs from // external processes are visible in case of a failure. diff --git a/build/rust/build_rust_toolchain_aux.py b/build/rust/build_rust_toolchain_aux.py index ecdce7a053c..29d5cfba8da 100755 --- a/build/rust/build_rust_toolchain_aux.py +++ b/build/rust/build_rust_toolchain_aux.py @@ -18,6 +18,8 @@ import brave_chromium_utils CONFIG_TOML_TEMPLATE = 'config.toml.template' TOOLS_RUST = '//tools/rust' +RUST_LLD = 'rust-lld' + ('.exe' if sys.platform == 'win32' else '') +WASM32_UNKNOWN_UNKNOWN = 'wasm32-unknown-unknown' def restore_config_toml_template(): args = [ @@ -100,18 +102,13 @@ def create_archive(): stage1_output_path = os.path.join(build_rust.RUST_BUILD_DIR, target_triple, 'stage1', 'lib', 'rustlib') - rust_toolchain = os.path.relpath(build_rust.RUST_TOOLCHAIN_OUT_DIR, - brave_chromium_utils.get_src_dir()) - exe_postfix = '.exe' if sys.platform == 'win32' else '' with tarfile.open(package_name(), 'w:xz') as tar: tar.add(os.path.join(stage1_output_path, target_triple, 'bin', - f'rust-lld{exe_postfix}'), - arcname=os.path.join(rust_toolchain, 'bin', - f'rust-lld{exe_postfix}')) - tar.add(os.path.join(stage1_output_path, 'wasm32-unknown-unknown'), - arcname=os.path.join(rust_toolchain, 'lib', 'rustlib', - 'wasm32-unknown-unknown')) + RUST_LLD), + arcname=RUST_LLD) + tar.add(os.path.join(stage1_output_path, WASM32_UNKNOWN_UNKNOWN), + arcname=WASM32_UNKNOWN_UNKNOWN) def main(): diff --git a/build/rust/download_rust_toolchain_aux.py b/build/rust/download_rust_toolchain_aux.py new file mode 100755 index 00000000000..69ee7770b3d --- /dev/null +++ b/build/rust/download_rust_toolchain_aux.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# Copyright (c) 2025 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. + +from urllib.error import HTTPError +import os +from pathlib import Path +import shutil +import tempfile + +import brave_chromium_utils +import build_rust_toolchain_aux +import deps +import deps_config + +with brave_chromium_utils.sys_path(build_rust_toolchain_aux.TOOLS_RUST): + import build_rust + RUST_TOOLCHAIN = build_rust.RUST_TOOLCHAIN_OUT_DIR + +BRAVE_RUST_TOOLCHAIN_AUX = os.path.join(RUST_TOOLCHAIN, + '.brave_rust_toolchain_aux') + + +def is_download_needed(): + if os.getenv('SKIP_DOWNLOAD_RUST_TOOLCHAIN_AUX', '0') == '1': + return False + + package_name = '' + try: + with open(BRAVE_RUST_TOOLCHAIN_AUX) as file: + package_name = file.readline().rstrip() + except Exception: + pass + return package_name != build_rust_toolchain_aux.package_name() + + +def install_package(src_dir): + rust_lld_path = os.path.join(RUST_TOOLCHAIN, 'bin', + build_rust_toolchain_aux.RUST_LLD) + wasm32_unknown_unknown_path = os.path.join( + RUST_TOOLCHAIN, 'lib', 'rustlib', + build_rust_toolchain_aux.WASM32_UNKNOWN_UNKNOWN) + + # delete existing artifacts + Path(rust_lld_path).unlink(missing_ok=True) + shutil.rmtree(wasm32_unknown_unknown_path, ignore_errors=True) + + # move new artifacts into their final places + shutil.move(os.path.join(src_dir, build_rust_toolchain_aux.RUST_LLD), + rust_lld_path) + shutil.move( + os.path.join(src_dir, build_rust_toolchain_aux.WASM32_UNKNOWN_UNKNOWN), + wasm32_unknown_unknown_path) + + +def save_package_name(): + with open(BRAVE_RUST_TOOLCHAIN_AUX, 'w+') as file: + file.write(f'{build_rust_toolchain_aux.package_name()}\n') + + +def main(): + if not is_download_needed(): + print(f'Skipping {Path(__file__).stem}') + return + + with tempfile.TemporaryDirectory(dir=RUST_TOOLCHAIN) as temp_dir: + try: + deps.DownloadAndUnpack( + f'{deps_config.DEPS_PACKAGES_URL}/rust-toolchain-aux/{build_rust_toolchain_aux.package_name()}', + temp_dir) + install_package(temp_dir) + save_package_name() + except HTTPError as error: + if error.code == 403: + print("If you see this error message, " + "it means you're likely on the rebase team " + "and doing a Chromium bump - please visit " + "https://ci.brave.com/view/rust and use your branch " + "to build the required Rust auxiliary package.") + raise + + +if __name__ == '__main__': + main() diff --git a/script/deps.py b/script/deps.py index 2de3deb769e..fddad999aa0 100755 --- a/script/deps.py +++ b/script/deps.py @@ -1,7 +1,8 @@ #!/usr/bin/env python -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. +# Copyright (c) 2025 The Brave Authors. All rights reserved. +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this file, +# You can obtain one at https://mozilla.org/MPL/2.0/. """This script is used to download deps.""" @@ -87,13 +88,13 @@ def DownloadAndUnpack(url, output_dir, path_prefix=None): assert path_prefix is None extract_zip(tmp_file.name, output_dir) else: - t = tarfile.open(tmp_file.name, mode='r:gz') - members = None - if path_prefix is not None: - members = [ - m for m in t.getmembers() - if m.name.startswith(path_prefix) - ] - t.extractall(path=output_dir, members=members) + with tarfile.open(tmp_file.name, mode='r:*') as t: + members = None + if path_prefix is not None: + members = [ + m for m in t.getmembers() + if m.name.startswith(path_prefix) + ] + t.extractall(path=output_dir, members=members) finally: os.unlink(tmp_file.name)