brizental pushed to branch tor-browser-145.0a1-16.0-1 at The Tor Project / Applications / Tor Browser Commits: 0693577b by Beatriz Rizental at 2025-11-27T12:48:48+01:00 fixup! [android] Modify build system - - - - - fc0668a4 by Beatriz Rizental at 2025-11-27T12:48:48+01:00 fixup! TB 41878: [android] Add standalone Tor Bootstrap - - - - - 52aa72a6 by Beatriz Rizental at 2025-11-27T12:48:48+01:00 fixup! BB 43564: Modify ./mach bootstrap for Base Browser - - - - - 2bd95ead by Beatriz Rizental at 2025-11-27T12:48:48+01:00 fixup! BB 43564: Modify ./mach bootstrap for Tor Browser - - - - - 8e60c9e7 by Dan Ballard at 2025-11-27T12:48:48+01:00 fixup! [android] Modify build system add checks for empty env vars to not override mozconfig defaults in base-browser-android - - - - - 8 changed files: - browser/config/mozconfigs/base-browser-android - build/moz.configure/basebrowser-resources.configure - build/moz.configure/torbrowser-resources.configure - mobile/android/fenix/app/build.gradle - mobile/android/fenix/tools/tba-fetch-deps.sh - python/mozbuild/mozbuild/backend/base.py - python/mozbuild/mozbuild/tbbutils.py - python/mozbuild/mozbuild/test/test_tbbutils.py Changes: ===================================== browser/config/mozconfigs/base-browser-android ===================================== @@ -11,11 +11,22 @@ ac_add_options --enable-application=mobile/android CC="clang" CXX="clang++" ac_add_options --enable-linker=lld -ac_add_options --with-java-bin-path=$JAVA_HOME/bin -ac_add_options --with-android-sdk=$ANDROID_HOME -ac_add_options --with-android-ndk=$ANDROID_NDK_HOME + +if test -n "$ANDROID_HOME"; then + ac_add_options --with-android-sdk=$ANDROID_HOME +fi + +if test -n "$ANDROID_NDK_HOME"; then + ac_add_options --with-android-ndk=$ANDROID_NDK_HOME +fi + ac_add_options --with-android-min-sdk=21 -ac_add_options --with-gradle=$GRADLE_HOME/bin/gradle + +if test -n "$GRADLE_HOME"; then + ac_add_options --with-gradle=$GRADLE_HOME/bin/gradle +fi +# Otherwise (as per /mobile/android/gradle.config) a version will be downloaded by the gradle wrapper when needed +# so don't use this override, and let it do it's thing ac_add_options --enable-strip ac_add_options --enable-install-strip ===================================== build/moz.configure/basebrowser-resources.configure ===================================== @@ -55,6 +55,7 @@ option( nargs=1, default=None, help="Path to location of fonts directory.", + when=is_desktop_build, ) @@ -63,8 +64,11 @@ option( mozbuild_state_path, bootstrap_path( "fonts", - when=depends("--with-tor-browser-fonts")(lambda x: not x) & is_desktop_build, + when=depends("--with-tor-browser-fonts", when=is_desktop_build)( + lambda x: not x + ), ), + when=is_desktop_build, ) @checking("for tor-browser fonts directory") @imports(_from="pathlib", _import="Path") ===================================== build/moz.configure/torbrowser-resources.configure ===================================== @@ -4,6 +4,7 @@ option( nargs=1, default=None, help="Path to location of tor-expert-bundle directory.", + when=is_desktop_build, ) @@ -12,8 +13,11 @@ option( mozbuild_state_path, bootstrap_path( "tor-expert-bundle", - when=depends("--with-tor-expert-bundle")(lambda x: not x) & is_desktop_build, + when=depends("--with-tor-expert-bundle", when=is_desktop_build)( + lambda x: not x + ), ), + when=is_desktop_build, ) @checking("for tor-expert-bundle") @imports(_from="pathlib", _import="Path") @@ -34,4 +38,155 @@ def tor_expert_bundle(value, mozbuild_state_path, _bootstrapped): return None -set_config("TOR_EXPERT_BUNDLE", tor_expert_bundle) +set_config("TOR_EXPERT_BUNDLE", tor_expert_bundle, when=is_desktop_build) + + +# Android +# ------------------------------------------------- + + +@depends(build_project) +def is_android_build(build_project): + return build_project == "mobile/android" + + +@imports(_from="pathlib", _import="Path") +def maven_local_default(): + return str(Path.home() / ".m2/repository") + + +option( + "--with-maven-local", + nargs=1, + default=maven_local_default(), + help="Path the maven local directory. Defaults to $HOME/.m2/repository", +) + + +@depends("--with-maven-local") +def maven_local(value): + if value: + return value[0] + + +option( + "--with-tor-expert-bundle-aar", + env="TOR_EXPERT_BUNDLE_AAR", + nargs=1, + default=None, + help="Path to location of tor-expert-bundle.aar archive.", + when=is_android_build, +) + + +@depends( + "--with-tor-expert-bundle-aar", + mozbuild_state_path, + bootstrap_path( + "tor-expert-bundle-aar", + no_unpack=True, + when=depends("--with-tor-expert-bundle-aar", when=is_android_build)( + lambda x: not x + ), + ), + when=is_android_build, +) +@checking("for tor-expert-bundle.aar") +@imports(_from="pathlib", _import="Path") +def tor_expert_bundle_aar(value, mozbuild_state_path, _bootstrapped): + if value: + path = Path(value[0]) + if path.suffix.lower() == ".aar": + return value[0] + else: + die("--with-tor-expert-bundle-aar must point to a AAR archive.") + + bootstrapped_location = Path(mozbuild_state_path) / "tor-expert-bundle.aar" + if bootstrapped_location.is_file(): + return str(bootstrapped_location) + + die( + "tor-expert-bundle-aar not found. Either enable bootstrap, or provide a path with --with-tor-expert-bundle-aar." + ) + + +set_config("TOR_EXPERT_BUNDLE_AAR", tor_expert_bundle_aar) + + +option( + "--with-application-services", + env="APPLICATION_SERVICES", + nargs=1, + default=None, + help="Path to location of application-services gradle lib.", + when=is_android_build, +) + + +@depends( + maven_local, + "--with-application-services", + mozbuild_state_path, + bootstrap_path( + "application-services", + when=depends("--with-application-services", when=is_android_build)( + lambda x: not x + ), + ), + when=is_android_build, +) +@checking("for application-services") +@imports(_from="pathlib", _import="Path") +@imports("mozbuild.tbbutils") +def application_services(maven_local, value, mozbuild_state_path, _bootstrapped): + as_location = None + + if value: + path = Path(value[0]) + if path.is_dir(): + as_location = path + else: + die("--with-application-services must point to a directory.") + else: + bootstrapped_location = Path(mozbuild_state_path) / "application-services/maven" + if bootstrapped_location.is_dir(): + as_location = bootstrapped_location + + if not as_location: + # application-services is not required for building. + die( + "application-services not found. Either enable bootstrap, or provide a path with --with-application-services." + ) + + # Symlink a-s in the maven local repository. + # Note that this _overwrites_ whatever is already in there. + mozbuild.tbbutils.symlink_tree(as_location, maven_local) + return as_location + + +option( + "--with-nimbus-fml", + env="NIMBUS_FML", + nargs=1, + default=None, + help="Path to location of nimbus-fml executable.", + when=is_android_build, +) + + +@depends("--with-nimbus-fml", when=is_android_build) +@checking("for nimbus-fml") +@imports(_from="pathlib", _import="Path") +def nimbus_fml(value): + if value: + path = Path(value[0]) + if path.is_file(): + return value[0] + else: + die("--with-nimbus-fml must point to an existing file.") + + # a-s nimbus-gradle-plugin will download nimbus-fml itself if not provided. + return None + + +set_config("NIMBUS_FML", nimbus_fml) ===================================== mobile/android/fenix/app/build.gradle ===================================== @@ -327,13 +327,10 @@ android.applicationVariants.configureEach { variant -> def isDebugOrDCD = isDebug || isDataCollectionDisabled def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false - // env var NIMBUS_FML always overrides this in the tbb built patched application services - // https://gitlab.torproject.org/tpo/applications/tor-browser-build/-/blob/main... - // so safe to have always set so local builds and supply their expected location as fetched by - // fenix/tools/tba-fetch-deps.sh - // We normalize the path because it is valid to open/build from both tb and fenix roots - def normalizedTBPath = rootProject.projectDir.absolutePath.minus("mobile/android/fenix") - System.setProperty("nimbusFml", normalizedTBPath + "/mobile/android/fenix/tools/nimbus-fml") + // When this is set, a-s doesn't attempt to download NIMBUS_FML. + if (gradle.mozconfig.substs.NIMBUS_FML) { + System.setProperty("nimbusFml", gradle.mozconfig.substs.NIMBUS_FML) + } def disableTor = false if (project.hasProperty("disableTor")) { @@ -774,7 +771,7 @@ dependencies { lintChecks project(':components:tooling-lint') // Tor Expert Bundle - implementation files('tor-expert-bundle.aar') + implementation files(gradle.mozconfig.substs.TOR_EXPERT_BUNDLE_AAR) } protobuf { ===================================== mobile/android/fenix/tools/tba-fetch-deps.sh ===================================== @@ -1,124 +1,7 @@ #!/bin/bash -if [ $# -eq 0 ]; then - echo "Usage: ./tba-fetch-deps.sh --\$MODE" - echo " modes:" - echo " --nightly Downloads the needed assets from the nightlies build server. Use when local version matches nightly build server version." - echo " --tbb PATH Harvest most recently built assets from PATH assuming it points to a tor-browser-build dir. Use when local version does NOT match nightly build server version." - exit -1 -fi +echo -e "\033[1;33mThis file is deprecated.\033[0m" +echo "Run ./mach bootstrap and/or define options in your mozconfig from now on." +echo "See documentation at: https://gitlab.torproject.org/tpo/applications/wiki/-/wikis/Development-Info..." -TBB_BUILD_06="https://tb-build-06.torproject.org/~tb-builder/tor-browser-build/out" - -if [[ $1 == "--tbb" && -z $2 ]]; then - echo "--tbb needs path to tor-browser-build dir" - exit -1 -fi -TBB_PATH=$2 - -cd "$(dirname $(realpath "$0"))/.." - -if [ -z "$TOR_BROWSER_BUILD" ]; then - TOR_BROWSER_BUILD=../../../../tor-browser-build -fi - -echo "Fetching tor-expert-bundle.aar..." - -if [[ $1 == "--tbb" ]]; then - tor_expert_bundle_aar="$(ls -1td "$TOR_BROWSER_BUILD/out/tor-expert-bundle-aar/"tor-expert-bundle-aar-* | head -1)" - cp "$tor_expert_bundle_aar"/* app/ -else - tor_expert_bundle_aar_dirname="$(curl -s $TBB_BUILD_06/tor-expert-bundle-aar/ | sed -nE 's/.*href=\"(tor-expert-bundle-aar-[0-9a-z\.\-]*).*/\1/p' | head -n 1)" - curl -o app/tor-expert-bundle.aar $TBB_BUILD_06/tor-expert-bundle-aar/$tor_expert_bundle_aar_dirname/tor-expert-bundle.aar -fi - -if [ -z app/tor_expert_bundle.aar ]; then - echo "Cannot find Tor Expert Bundle arr artifacts!" - exit 2 -fi -echo "" - -echo "Fetching noscript..." - -mkdir -p "app/src/main/assets/extensions" - -if [[ $1 == "--tbb" ]]; then - noscript="$(find "$TOR_BROWSER_BUILD/out/browser" -name 'noscript*.xpi' -print | sort | tail -1)" - cp "$noscript" "app/src/main/assets/extensions/{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi" -else - noscript_fname="$(curl -s $TBB_BUILD_06/browser/ | sed -nE 's/.*href=\"(noscript-[0-9a-z\.\-]*).*/\1/p')" - curl -o "app/src/main/assets/extensions/{73a6fe31-595d-460b-a920-fcc0f8843232}.xpi" $TBB_BUILD_06/browser/$noscript_fname -fi -echo "" - -if [ -z "$GRADLE_MAVEN_REPOSITORIES" ]; then - GRADLE_MAVEN_REPOSITORIES="$HOME/.m2/repository" -fi - -os="$(uname -s)" -case "${os}" in - Linux*) os=unknown-linux;; - Darwin*) os=apple-darwin;; - # This is not quite correct, however the only option for the nimbus-fml - # build are these three... so if it's not Linux or Darwin it's very likely - # we are building from Windows. I apologize in advance to all the BSD users. - *) os="pc-windows";; -esac - -arch="$(uname -m)" -case "${arch}" in - # Also no quite correct, but again these are the only options for nimbus-fml. - aarch64) arch=aarch64;; - arm64) arch=aarch64;; - *) arch="x86_64";; -esac - -if [ "$os" = "unsupported" ] || [ "$arch" = "unsupported" ]; then - echo "Android builds from $os-$arch are not supported." - exit 2 -fi - -echo "Fetching application-services..." - -if [[ $1 == "--tbb" ]]; then - app_services="$(ls -1t "$TOR_BROWSER_BUILD/out/application-services/"application-services*.tar.zst | head -1)" - tar -C /tmp -xf "$app_services" -else - app_services_fname="$(curl -s $TBB_BUILD_06/application-services/ | sed -nE 's/.*href=\"(application-services-[0-9a-z\.\-]*).*/\1/p')" - app_services=/tmp/$app_services_fname - curl -o $app_services $TBB_BUILD_06/application-services/$app_services_fname - tar -C /tmp -xf "$app_services" - rm "$app_services" -fi -mkdir -p "$GRADLE_MAVEN_REPOSITORIES/org/mozilla" -if [ -d /tmp/application-services ]; then - cp -r /tmp/application-services/maven/org/mozilla/* "$GRADLE_MAVEN_REPOSITORIES/org/mozilla" - - # Over on tor-browser-build all build tools are built for x86_64-linux. - # If we are not building from that platform, we need to fetch the correct - # nimbus-fml binary. - # - # Even though we do modify nimbus-fml in tbb, all the changes are made to - # support reproducibility and are not necessary for development builds. - if [ "$os" != "unknown-linux" ] || [ "$arch" != "x86_64" ]; then - echo "Downloading nimbus-fml binary for $arch-$os" - app_services_version=$(echo "$app_services" | grep -oE 'application-services-[0-9]+\.[0-9]+(\.[0-9]{1,2})?' | grep -oE '[0-9]+\.[0-9]+(\.[0-9]{1,2})?') - - curl -L -o /tmp/nimbus-fml.zip "https://archive.mozilla.org/pub/app-services/releases/$app_services_version/..." - unzip -d /tmp/nimbus-fml /tmp/nimbus-fml.zip - nimbus_fml="$(find "/tmp/nimbus-fml/" -name 'nimbus-fml*' | grep "$arch-$os")" - echo "Using nimbus-fml binary: $nimbus_fml" - cp $nimbus_fml tools/ - - rm -rf /tmp/nimbus-fml - rm /tmp/nimbus-fml.zip - else - cp /tmp/application-services/nimbus-fml tools/ - fi - chmod +x tools/nimbus-fml - - rm -rf /tmp/application-services -else - echo "Cannot find application-services artifacts!" - exit 2 -fi +exit 1 ===================================== python/mozbuild/mozbuild/backend/base.py ===================================== @@ -258,8 +258,35 @@ class BuildBackend(LoggingMixin): os.remove(dst) os.symlink(src, dst) else: + self.log( + logging.ERROR, + "_setup_tor_browser_environment", + {}, + "Error creating symlink.", + ) return + if app == "mobile/android": + # Set up NoScript extension + # We put it in the srcdir... It will be moved to the APK in the gradle build. + if noscript_location: + noscript_target = ( + Path(config.topsrcdir) + / "mobile/android/fenix/app/src/main/assets/extensions" + / noscript_target_filename + ) + self.log( + logging.INFO, + "_setup_tor_browser_environment", + { + "noscript_location": noscript_location, + "noscript_target": str(noscript_target), + }, + "Creating symlink for NoScript from {noscript_location} to {noscript_target}", + ) + + _infallible_symlink(noscript_location, noscript_target) + if app == "browser": tbdir = Path(config.topobjdir) / "dist" / "bin" ===================================== python/mozbuild/mozbuild/tbbutils.py ===================================== @@ -1,7 +1,37 @@ +import os import re +from pathlib import Path from urllib.request import Request, urlopen +def symlink_tree(src_dir, target_dir): + """ + Recursively mirror the directory tree from `src_dir` into `target_dir` + using symbolic links. + + Equivalent to: `cp -rs src_dir/* target_dir` + + Notes: + - If a file or symlink already exists in the destination, it overwritten. + - The symlinks created here use absolute paths i.e. not relocatable. + """ + src = Path(src_dir) + target = Path(target_dir) + + target.mkdir(parents=True, exist_ok=True) + + for root, _, files in os.walk(src): + target_path = target / Path(root).relative_to(src) + target_path.mkdir(parents=True, exist_ok=True) + + for file in files: + src_file = Path(root) / file + target_file = target_path / file + if target_file.exists() or target_file.is_symlink(): + target_file.unlink() + os.symlink(src_file, target_file) + + def list_files_http(url): try: req = Request(url, method="GET") @@ -17,7 +47,9 @@ def list_files_http(url): if href == "../": continue - if "tor-expert-bundle" in href: + if "tor-expert-bundle-aar" in href: + href = f"{href.rstrip('/')}/tor-expert-bundle.aar" + elif "tor-expert-bundle" in href: href = f"{href.rstrip('/')}/tor-expert-bundle.tar.gz" links.append(href) @@ -30,6 +62,8 @@ TOR_BROWSER_BUILD_ARTIFACTS = [ "noscript", "fonts", "tor-expert-bundle", + "tor-expert-bundle-aar", + "application-services", ] # Mapping of artifacts from taskcluster to tor-browser-build. ===================================== python/mozbuild/mozbuild/test/test_tbbutils.py ===================================== @@ -1,10 +1,98 @@ +import os +import shutil +import tempfile import unittest +from pathlib import Path from types import SimpleNamespace from unittest.mock import MagicMock, patch import mozunit -from mozbuild.tbbutils import get_artifact_index, get_artifact_path, list_files_http +from mozbuild.tbbutils import ( + get_artifact_index, + get_artifact_path, + list_files_http, + symlink_tree, +) + + +class TestSymlinkTree(unittest.TestCase): + def _create_sample_tree(self, base: Path): + (base / "subdir").mkdir() + (base / "file1.txt").write_text("content1") + (base / "subdir" / "file2.txt").write_text("content2") + + def setUp(self): + self.tmpdir = tempfile.mkdtemp() + self.src = Path(self.tmpdir) / "src" + self.dst = Path(self.tmpdir) / "dst" + self.src.mkdir() + self.dst.mkdir() + + def tearDown(self): + shutil.rmtree(self.tmpdir) + + def test_symlinks_created_correctly(self): + self._create_sample_tree(self.src) + + symlink_tree(self.src, self.dst) + + self.assertTrue((self.dst / "file1.txt").is_symlink()) + self.assertTrue((self.dst / "subdir" / "file2.txt").is_symlink()) + + self.assertEqual( + os.readlink(self.dst / "file1.txt"), + str(self.src / "file1.txt"), + ) + self.assertEqual( + os.readlink(self.dst / "subdir" / "file2.txt"), + str(self.src / "subdir" / "file2.txt"), + ) + + def test_overwrites_existing_files(self): + self._create_sample_tree(self.src) + + # Create a conflicting file in destination + (self.dst / "file1.txt").write_text("old") + + symlink_tree(self.src, self.dst) + + self.assertTrue((self.dst / "file1.txt").is_symlink()) + self.assertEqual( + os.readlink(self.dst / "file1.txt"), + str(self.src / "file1.txt"), + ) + + def test_nested_directories_are_mirrored(self): + (self.src / "a" / "b" / "c").mkdir(parents=True) + (self.src / "a" / "b" / "c" / "deep.txt").write_text("deep content") + + symlink_tree(self.src, self.dst) + + deep_link = self.dst / "a" / "b" / "c" / "deep.txt" + self.assertTrue(deep_link.is_symlink()) + self.assertEqual( + os.readlink(deep_link), + str(self.src / "a" / "b" / "c" / "deep.txt"), + ) + + def test_idempotence(self): + self._create_sample_tree(self.src) + + symlink_tree(self.src, self.dst) + symlink_tree(self.src, self.dst) # Run again + + self.assertTrue((self.dst / "file1.txt").is_symlink()) + self.assertTrue((self.dst / "subdir" / "file2.txt").is_symlink()) + + def test_symlinks_use_absolute_paths(self): + (self.src / "file.txt").write_text("absolute") + + symlink_tree(self.src, self.dst) + + link_target = os.readlink(self.dst / "file.txt") + self.assertTrue(Path(link_target).is_absolute()) + self.assertEqual(Path(link_target), self.src / "file.txt") class TestGetArtifactName(unittest.TestCase): @@ -152,6 +240,7 @@ class TestListFilesHttp(unittest.TestCase): def test_tor_expert_bundle_rewrites(self, mock_urlopen): html = """ <a href="tor-expert-bundle">bundle</a> + <a href="tor-expert-bundle-aar">bundle</a> """ mock_resp = MagicMock() mock_resp.status = 200 @@ -163,6 +252,7 @@ class TestListFilesHttp(unittest.TestCase): result, [ "tor-expert-bundle/tor-expert-bundle.tar.gz", + "tor-expert-bundle-aar/tor-expert-bundle.aar", ], ) View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/529b5c8... -- View it on GitLab: https://gitlab.torproject.org/tpo/applications/tor-browser/-/compare/529b5c8... You're receiving this email because of your account on gitlab.torproject.org.
participants (1)
-
brizental (@brizental)