Files
IronFox/builder/src/cli.py
Akash Yadav 8be05ef441 fix(builder): program hang on startup
Signed-off-by: Akash Yadav <itsaky01@gmail.com>
2025-10-25 20:17:02 +05:30

207 lines
5.0 KiB
Python

"""The CLI interface for IronFox builder."""
from __future__ import annotations
import os
import click
import multiprocessing
from click.core import Context
from pathlib import Path
from commands.base import DEFAULT_APP_CONFIG, AppConfig, BaseConfig
from commands.build import BuildCommand
from commands.prepare import PrepareCommand
from commands.setup import SetupCommand
from common.utils import find_prog
@click.group("Python scripts to build IronFox")
@click.option(
"--root-dir",
help="Path to root of the IronFox source tree.",
default=Path.cwd(),
type=click.Path(exists=True),
)
@click.option(
"--android-home",
help="Path to the Android SDK directory.",
type=click.Path(exists=False),
default=os.getenv("ANDROID_HOME", ""),
)
@click.option(
"--java-home",
help="Path to the JDK installation directory.",
type=click.Path(exists=True),
default=os.getenv("JAVA_HOME", ""),
)
@click.option(
"--cargo-home",
help="Path to the Cargo installation directory.",
type=click.Path(exists=True),
default=os.getenv("CARGO_HOME", ""),
)
@click.option(
"--gradle-exec",
help="Path to the Gradle executable file",
type=click.Path(exists=True, dir_okay=False, executable=True),
default=None,
)
@click.option(
"--jobs",
help="Number of parallel jobs to run.",
type=int,
default=multiprocessing.cpu_count(),
)
@click.option(
"--dry-run",
help="Disable task execution.",
is_flag=True,
default=False,
)
@click.option(
"--verbose",
help="Enable verbose logging.",
is_flag=True,
default=False,
)
@click.pass_context
def cli(
ctx: Context,
root_dir: str,
android_home: str,
java_home: str,
cargo_home: str,
gradle_exec: str | None,
jobs: int,
dry_run: bool,
verbose: bool,
):
if not gradle_exec or len(gradle_exec.strip()) == 0:
raise RuntimeError(f"Invalid gradle executable path: {gradle_exec}")
ctx.obj = BaseConfig(
root_dir=Path(root_dir),
android_home=Path(android_home),
java_home=Path(java_home),
cargo_home=Path(cargo_home),
gradle_exec=Path(gradle_exec),
jobs=jobs,
dry_run=dry_run,
verbose=verbose,
)
pass_base_config = click.make_pass_decorator(BaseConfig)
@cli.command(help="Setup the build environment.")
@click.option(
"--clone-depth",
help="The clone depth for cloning repositories. Defaults to 1 (shallow-clone).",
type=int,
default=1,
)
@pass_base_config
def setup(base_config: BaseConfig, clone_depth: int):
cmd = SetupCommand(base_config, clone_depth)
return cmd.run()
@cli.command(help="Prepare source files for the build.")
@click.option(
"--sb-gapi-file",
help="Path to a file containing the Google Safe Browsing API key",
type=click.Path(exists=False, dir_okay=False),
default=os.getenv("SB_GAPI_KEY_FILE", ""),
)
@click.option(
"--app-name",
help="Name of the application (as shown in launchers). Defaults to 'IronFox'.",
type=str,
default=DEFAULT_APP_CONFIG.app_name,
)
@click.option(
"--app-vendor",
help="Name of the vendor. Defaults to 'IronFox OSS'.",
type=str,
default=DEFAULT_APP_CONFIG.vendor,
)
@click.option(
"--app-id-base",
help="Base package ID (organization-level). Defaults to 'org.ironfoxoss'.",
type=str,
default=DEFAULT_APP_CONFIG.app_id_base,
)
@click.option(
"--app-id",
help="Application identifier (may include variant, e.g. 'ironfox.nightly'). Defaults to 'ironfox'.",
type=str,
default=DEFAULT_APP_CONFIG.app_id,
)
@click.option(
"--browser-name",
help="Name of the browser (as shown in-app). Defaults to 'IronFox'.",
type=str,
default=DEFAULT_APP_CONFIG.app_name,
)
@click.option(
"--nightly",
help="Whether to build a nightly build. Defaults to false.",
is_flag=True,
default=DEFAULT_APP_CONFIG.nightly,
)
@click.argument(
"build_variant",
type=click.Choice(["arm64", "arm", "x86_64", "bundle"]),
)
@click.option(
"--ubo-assets",
help="URL to the uBlock Origin assets file.",
type=str,
default="",
)
@pass_base_config
def prepare(
base_config: BaseConfig,
sb_gapi_file: Path,
build_variant: str,
ubo_assets: str,
app_name: str,
app_vendor: str,
app_id_base: str,
app_id: str,
browser_name: str,
nightly: bool,
):
app_config = AppConfig(
app_name=app_name,
vendor=app_vendor,
app_id_base=app_id_base,
app_id=app_id,
browser_name=browser_name,
nightly=nightly,
)
cmd = PrepareCommand(
base_config=base_config,
app_config=app_config,
sb_gapi_file=Path(sb_gapi_file),
build_variant=build_variant,
ubo_assets=ubo_assets,
)
return cmd.run()
@cli.command(help="Start the build.")
@click.argument("build_type", type=click.Choice(["apk", "bundle"]))
@pass_base_config
def build(base_config: BaseConfig, build_type: str):
cmd = BuildCommand(base_config, build_type)
return cmd.run()
if __name__ == "__main__":
cli()