-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Build FXIOS-13790 [AS] Add script to automate building and comsuming a local AS build #29868
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
issammani
wants to merge
1
commit into
main
Choose a base branch
from
build/add-script-for-local-as-builds
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+281
−0
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,281 @@ | ||
#!/usr/bin/env zsh | ||
# macOS helper to build local Application Services artifacts for Firefox iOS. | ||
# Run this script from within the firefox-ios repo root. | ||
# The script should take care of installing all the necessary dependencies, with the exception of Xcode itself. | ||
# Usage: `./use_local_as.sh` | ||
# | ||
# NOTE1: We explicitly use zsh here since that's the default shell on macOS nowadays. Also handling bash/zsh differences is a pain. | ||
# | ||
# NOTE2: Expected directory structure: | ||
# parent/ | ||
# ├─ application-services/ | ||
# └─ firefox-ios/ (this script runs here) | ||
|
||
set -euo pipefail | ||
|
||
############################################################################### | ||
# Pretty logging | ||
# This helps with understanding what the script is doing. Also useful when stuff breaks to trace back what happened. | ||
############################################################################### | ||
log() { printf "\033[1;34m[info]\033[0m %s\n" "$*"; } | ||
warn() { printf "\033[1;33m[warn]\033[0m %s\n" "$*"; } | ||
err() { printf "\033[1;31m[err]\033[0m %s\n" "$*" >&2; } | ||
have_cmd() { command -v "$1" >/dev/null 2>&1; } | ||
|
||
|
||
############################################################################### | ||
# Repo roots (we run FROM firefox-ios; AS is a sibling) | ||
############################################################################### | ||
IOS_DIR="$(pwd)" | ||
AS_DIR="$(cd "$IOS_DIR/../application-services" 2>/dev/null && pwd || true)" | ||
|
||
|
||
if [[ -z "$AS_DIR" || ! -d "$AS_DIR" ]]; then | ||
expected_path="$(cd "$PWD/.." && pwd)/application-services" | ||
err "Could not find sibling application-services/ next to firefox-ios/." | ||
err "Make sure application-services is at: $expected_path" | ||
exit 1 | ||
fi | ||
|
||
log "Found firefox-ios dir: $IOS_DIR" | ||
log "Found application-services dir: $AS_DIR" | ||
|
||
|
||
############################################################################### | ||
# Xcode Command Line Tools / Full Xcode check | ||
############################################################################### | ||
log "Checking Xcode installation..." | ||
|
||
# Get the currently selected developer path | ||
DEVELOPER_DIR="$(xcode-select -p 2>/dev/null || true)" | ||
|
||
if [[ -z "$DEVELOPER_DIR" ]]; then | ||
warn "No Xcode developer directory found." | ||
warn "Please install Xcode from the App Store or from Apple's developer site." | ||
warn "After installing, run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" | ||
exit 1 | ||
fi | ||
|
||
# Check if the path looks like Command Line Tools instead of full Xcode | ||
if [[ "$DEVELOPER_DIR" == *"CommandLineTools"* ]]; then | ||
warn "xcode-select is currently pointing to CommandLineTools:" | ||
warn " $DEVELOPER_DIR" | ||
warn "For building iOS apps, you need full Xcode." | ||
warn "If Xcode is already installed, set it like this:" | ||
warn " sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" | ||
warn "Otherwise, install it from the App Store first." | ||
exit 1 | ||
fi | ||
|
||
log "Xcode is correctly configured at: $DEVELOPER_DIR" | ||
|
||
|
||
############################################################################### | ||
# Homebrew + dependencies | ||
# Install needed dependencies via Homebrew if not already installed. | ||
############################################################################### | ||
log "Ensuring Homebrew..." | ||
if ! have_cmd brew; then | ||
warn "Homebrew not found; installing." | ||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | ||
if [[ -d /opt/homebrew/bin ]]; then | ||
export PATH="/opt/homebrew/bin:$PATH" | ||
elif [[ -d /usr/local/bin ]]; then | ||
export PATH="/usr/local/bin:$PATH" | ||
fi | ||
fi | ||
|
||
deps=(ninja python3 wget git rsync) | ||
log "Updating Homebrew and installing dependencies if missing $(printf '%s, ' "${deps[@]}")..." | ||
|
||
missing=() | ||
for dep in "${deps[@]}"; do | ||
if have_cmd "$dep"; then | ||
log "$dep already installed" | ||
else | ||
missing+=("$dep") | ||
fi | ||
done | ||
|
||
# Only update/install if something’s missing | ||
if ((${#missing[@]} > 0)); then | ||
log "Updating Homebrew..." | ||
brew update | ||
log "Installing missing dependencies: ${missing[*]}" | ||
brew install "${missing[@]}" | ||
else | ||
log "All dependencies already satisfied." | ||
fi | ||
|
||
############################################################################### | ||
# xcpretty (nice Xcode log formatter) | ||
############################################################################### | ||
if have_cmd xcpretty; then | ||
log "xcpretty available in PATH" | ||
else | ||
RUBY_USER_BIN="$(ruby -e 'puts Gem.user_dir')/bin" | ||
XCPRETTY_BIN="$RUBY_USER_BIN/xcpretty" | ||
if [[ ! -x "$XCPRETTY_BIN" ]]; then | ||
log "Installing xcpretty via RubyGems (user install)..." | ||
gem install --user-install xcpretty || true | ||
fi | ||
export PATH="$RUBY_USER_BIN:$PATH" | ||
log "Added $RUBY_USER_BIN to PATH for this session" | ||
fi | ||
|
||
############################################################################### | ||
# Python venv (isolated environment). Will be cleaned up later. | ||
# This is better than polluting the system Python or using pipx. We risk breaking stuff otherwise. | ||
############################################################################### | ||
VENV_DIR="$IOS_DIR/.venv-as" | ||
VENV_PY="$VENV_DIR/bin/python" | ||
VENV_PIP="$VENV_DIR/bin/pip" | ||
|
||
if [[ ! -d "$VENV_DIR" ]]; then | ||
log "Creating Python venv at $VENV_DIR..." | ||
python3 -m venv "$VENV_DIR" | ||
fi | ||
|
||
log "Activating Python venv..." | ||
source "$VENV_DIR/bin/activate" | ||
|
||
log "Upgrading pip and installing essentials..." | ||
"$VENV_PIP" install --upgrade pip setuptools wheel six | ||
|
||
############################################################################### | ||
# gyp (needed for building some native dependencies) | ||
# We clone it locally instead of using pipx or system-wide install to avoid breaking other stuff | ||
############################################################################### | ||
GYP_DIR="$HOME/tools/gyp" | ||
if [[ -d "$GYP_DIR" ]]; then | ||
log "gyp already present at $GYP_DIR" | ||
else | ||
log "Cloning gyp into $GYP_DIR..." | ||
mkdir -p "${GYP_DIR%/*}" | ||
git clone https://chromium.googlesource.com/external/gyp.git "$GYP_DIR" | ||
fi | ||
|
||
log "Installing gyp into venv..." | ||
"$VENV_PIP" install --upgrade "$GYP_DIR" | ||
"$VENV_PIP" install --upgrade six | ||
export PATH="$GYP_DIR:$VENV_DIR/bin:$HOME/.local/bin:$PATH" | ||
|
||
############################################################################### | ||
# Rust (rustup + stable toolchain) | ||
############################################################################### | ||
log "Ensuring rustup and stable toolchain..." | ||
if ! have_cmd rustup; then | ||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | ||
fi | ||
|
||
if [[ -f "$HOME/.cargo/env" ]]; then | ||
source "$HOME/.cargo/env" | ||
fi | ||
|
||
if ! rustup toolchain list | grep -q '^stable'; then | ||
log "Installing Rust stable toolchain..." | ||
rustup toolchain install stable --profile default | ||
else | ||
log "Rust stable toolchain already installed" | ||
fi | ||
|
||
|
||
############################################################################### | ||
# NSS platform setup | ||
# This is needed to point AS to the right NSS build for the current platform. | ||
############################################################################### | ||
if [[ "$(uname -s)" == "Darwin" ]]; then | ||
if [[ "$(uname -m)" == "arm64" ]]; then | ||
export NSS_DIR="$AS_DIR/libs/desktop/darwin-aarch64" | ||
else | ||
export NSS_DIR="$AS_DIR/libs/desktop/darwin-x86-64" | ||
fi | ||
else | ||
export NSS_DIR="$AS_DIR/libs/desktop/linux-x86-64" | ||
fi | ||
export NSS_STATIC=1 | ||
log "Using NSS_DIR=$NSS_DIR" | ||
log "Using NSS_STATIC=$NSS_STATIC" | ||
|
||
############################################################################### | ||
# Verify and build Application Services for iOS | ||
############################################################################### | ||
|
||
# Switch to AS dir because some scripts expect to be run from there | ||
log "Switching to application-services dir: $AS_DIR" | ||
cd "$AS_DIR" | ||
|
||
VERIFY_SCRIPT="$AS_DIR/libs/verify-ios-environment.sh" | ||
BUILD_SCRIPT="$AS_DIR/megazords/ios-rust/build-xcframework.sh" | ||
|
||
if [[ ! -x "$VERIFY_SCRIPT" ]]; then | ||
err "Missing verify script at $VERIFY_SCRIPT" | ||
exit 1 | ||
fi | ||
if [[ ! -x "$BUILD_SCRIPT" ]]; then | ||
err "Missing build script at $BUILD_SCRIPT" | ||
exit 1 | ||
fi | ||
|
||
log "Verifying Application Services iOS build environment..." | ||
"$VERIFY_SCRIPT" | ||
|
||
log "Building Application Services iOS artifacts..." | ||
"$BUILD_SCRIPT" --generate-swift-sources | ||
|
||
# Delete and deactivate python venv | ||
log "Deactivating Python venv..." | ||
deactivate || true | ||
log "Deleting Python venv at $VENV_DIR..." | ||
rm -rf "$VENV_DIR" | ||
|
||
# Switch to back to firefox-ios dir | ||
log "Switching back to firefox-ios dir: $IOS_DIR" | ||
cd "$IOS_DIR" | ||
|
||
|
||
############################################################################### | ||
# Copy built artifacts into firefox-ios | ||
############################################################################### | ||
MEGAZORDS_DIR="$AS_DIR/megazords/ios-rust" | ||
XCFRAMEWORK_ZIP="$MEGAZORDS_DIR/MozillaRustComponents.xcframework.zip" | ||
GENERATED_SRC="$MEGAZORDS_DIR/Sources/MozillaRustComponentsWrapper/Generated/" | ||
GENERATED_DST="$IOS_DIR/MozillaRustComponents/Sources/MozillaRustComponentsWrapper/Generated/" | ||
PKG_FILE="$IOS_DIR/MozillaRustComponents/Package.swift" | ||
|
||
if [[ ! -f "$XCFRAMEWORK_ZIP" ]]; then | ||
err "Expected xcframework zip not found: $XCFRAMEWORK_ZIP" | ||
exit 1 | ||
fi | ||
|
||
log "Unzipping xcframework into firefox-ios/MozillaRustComponents/..." | ||
unzip -oq "$XCFRAMEWORK_ZIP" -d "$IOS_DIR/MozillaRustComponents/" | ||
|
||
log "Copying generated Swift wrappers into project..." | ||
rsync -avm --include='*/' --include='*.swift' --exclude='*' "$GENERATED_SRC/" "$GENERATED_DST/" | ||
|
||
############################################################################### | ||
# Switch SPM binaryTarget to use the local xcframework instead of remote URL | ||
############################################################################### | ||
if [[ ! -f "$PKG_FILE" ]]; then | ||
err "Package.swift not found at $PKG_FILE" | ||
exit 1 | ||
fi | ||
|
||
log "Rewriting Package.swift to point MozillaRustComponents to local path..." | ||
perl -pi -e ' | ||
if (/\.binaryTarget\(/ .. /\),/) { | ||
$inblock .= $_; | ||
if (/name:\s*"MozillaRustComponents"/) { $flag=1 } | ||
if (/\),/) { | ||
if ($flag) { | ||
$inblock =~ s|^(\s*)url:|\1//url:|mg; | ||
$inblock =~ s|^(\s*)checksum:|\1//checksum:|mg; | ||
$inblock =~ s|^(\s*)//path:|\1path:|mg; | ||
} | ||
$_=$inblock; $inblock=""; $flag=0; | ||
} else { $_=""; } | ||
} | ||
' "$PKG_FILE" | ||
|
||
log "All done! Open Xcode and build Firefox iOS 🎉" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is fantastic! However I wonder if we should potentially split the scripts here. I think for most people regularly doing dev on a-s -> iOS, most of the above script is not necessarily needed. Starting from here is really the (awesome) driver that most devs would be interested in. Should we split the above to go in some kinda "appservices_bootstrap" and the below is actual use_local_as.sh? That might make it easier to maintain in the future.
Also I do worry a little about when appservices moves to monorepo the above might change in some form. I'm half wondering if there should be something like "go to X to see the set-up for appservices" or something like that. However that can be tweaked in the future as we try to get the flow more stable!