adding new patches

This commit is contained in:
Nikhil Sonti
2025-07-17 17:57:18 -07:00
parent f48e140d5b
commit d5a0e62d0c
9 changed files with 2902 additions and 47 deletions

View File

@@ -79,6 +79,7 @@ def build_main(
chromium_src_dir: Optional[Path] = None,
slack_notifications: bool = False,
patch_interactive: bool = False,
patch_commit: bool = False,
upload_gcs: bool = True, # Default to uploading to GCS
):
"""Main build orchestration"""
@@ -244,11 +245,11 @@ def build_main(
log_info("Skipping Sparkle setup (macOS only)")
# Apply patches
apply_patches(ctx, interactive=patch_interactive)
apply_patches(ctx, interactive=patch_interactive, commit_each=patch_commit)
# Copy resources
copy_resources(ctx)
copy_resources(ctx, commit_each=patch_commit)
if slack_notifications:
@@ -470,6 +471,12 @@ def build_main(
default=False,
help="Ask for confirmation before applying each patch",
)
@click.option(
"--patch-commit",
is_flag=True,
default=False,
help="Create a git commit after applying each patch",
)
@click.option(
"--no-gcs-upload",
is_flag=True,
@@ -492,6 +499,7 @@ def main(
add_replace,
string_replace,
patch_interactive,
patch_commit,
no_gcs_upload,
):
"""Simple build system for Nxtscape Browser"""
@@ -583,6 +591,7 @@ def main(
chromium_src_dir=chromium_src,
slack_notifications=slack_notifications,
patch_interactive=patch_interactive,
patch_commit=patch_commit,
upload_gcs=not no_gcs_upload, # Invert the flag
)

View File

@@ -178,6 +178,13 @@ class BuildContext:
def get_app_path(self) -> Path:
"""Get built app path"""
# For debug builds, check if the app has a different name
if self.build_type == "debug" and IS_MACOS:
# Check for debug-branded app name
debug_app_name = f"{self.NXTSCAPE_APP_BASE_NAME} Dev.app"
debug_app_path = join_paths(self.chromium_src, self.out_dir, debug_app_name)
if debug_app_path.exists():
return debug_app_path
return join_paths(self.chromium_src, self.out_dir, self.NXTSCAPE_APP_NAME)
def get_chromium_app_path(self) -> Path:

View File

@@ -12,7 +12,7 @@ from context import BuildContext
from utils import log_info, log_error, log_success, log_warning, IS_WINDOWS
def apply_patches(ctx: BuildContext, interactive: bool = False) -> bool:
def apply_patches(ctx: BuildContext, interactive: bool = False, commit_each: bool = False) -> bool:
"""Apply Nxtscape patches"""
if not ctx.apply_patches:
log_info("\n⏭️ Skipping patches")
@@ -46,6 +46,9 @@ def apply_patches(ctx: BuildContext, interactive: bool = False) -> bool:
if interactive:
log_info("🔍 Interactive mode enabled - will ask for confirmation before each patch")
if commit_each:
log_info("📝 Git commit mode enabled - will create a commit after each patch")
# Apply each patch
for i, patch_path in enumerate(patches, 1):
if not patch_path.exists():
@@ -62,7 +65,7 @@ def apply_patches(ctx: BuildContext, interactive: bool = False) -> bool:
choice = input("\nOptions:\n 1) Apply this patch\n 2) Skip this patch\n 3) Stop patching here\nEnter your choice (1-3): ").strip()
if choice == "1":
apply_single_patch(patch_path, ctx.chromium_src, i, len(patches))
apply_single_patch(patch_path, ctx.chromium_src, i, len(patches), commit_each)
break
elif choice == "2":
log_warning(f"⏭️ Skipping patch {patch_path.name}")
@@ -73,7 +76,7 @@ def apply_patches(ctx: BuildContext, interactive: bool = False) -> bool:
else:
log_error("Invalid choice. Please enter 1, 2, or 3.")
else:
apply_single_patch(patch_path, ctx.chromium_src, i, len(patches))
apply_single_patch(patch_path, ctx.chromium_src, i, len(patches), commit_each)
log_success("Patches applied")
return True
@@ -103,7 +106,7 @@ def parse_series_file(patches_dir: Path) -> Iterator[Path]:
return patches
def apply_single_patch(patch_path: Path, tree_path: Path, current_num: int, total: int) -> bool:
def apply_single_patch(patch_path: Path, tree_path: Path, current_num: int, total: int, commit_each: bool = False) -> bool:
"""Apply a single patch using git apply"""
# Use git apply which is cross-platform and handles patch format better
cmd = [
@@ -120,6 +123,8 @@ def apply_single_patch(patch_path: Path, tree_path: Path, current_num: int, tota
result = subprocess.run(cmd, text=True, capture_output=True, cwd=tree_path)
if result.returncode == 0:
if commit_each:
commit_patch(patch_path, tree_path)
return True
# Patch failed - try with --3way for better conflict resolution
@@ -129,6 +134,8 @@ def apply_single_patch(patch_path: Path, tree_path: Path, current_num: int, tota
if result.returncode == 0:
log_info(f"✓ Applied {patch_path.name} with 3-way merge")
if commit_each:
commit_patch(patch_path, tree_path)
return True
# Patch still failed
@@ -152,7 +159,7 @@ def apply_single_patch(patch_path: Path, tree_path: Path, current_num: int, tota
log_warning(f"⏭️ Skipping patch {patch_path.name}")
return True # Continue with next patch
elif choice == "2":
return apply_single_patch(patch_path, tree_path, current_num, total)
return apply_single_patch(patch_path, tree_path, current_num, total, commit_each)
elif choice == "3":
log_error("Aborting patch process")
raise RuntimeError("Patch process aborted by user")
@@ -160,4 +167,38 @@ def apply_single_patch(patch_path: Path, tree_path: Path, current_num: int, tota
log_info("\nPlease fix the issue manually, then press Enter to continue...")
input("Press Enter when ready: ")
# Retry after manual fix
return apply_single_patch(patch_path, tree_path, current_num, total)
return apply_single_patch(patch_path, tree_path, current_num, total, commit_each)
def commit_patch(patch_path: Path, tree_path: Path) -> bool:
"""Create a git commit for the applied patch"""
try:
# Stage all changes
cmd_add = ['git', 'add', '-A']
result = subprocess.run(cmd_add, capture_output=True, text=True, cwd=tree_path)
if result.returncode != 0:
log_warning(f"Failed to stage changes for patch {patch_path.name}")
if result.stderr:
log_warning(f"Error: {result.stderr}")
return False
# Create commit message
patch_name = patch_path.stem # Remove .patch extension
commit_message = f"patch: {patch_name}"
# Create the commit
cmd_commit = ['git', 'commit', '-m', commit_message]
result = subprocess.run(cmd_commit, capture_output=True, text=True, cwd=tree_path)
if result.returncode == 0:
log_success(f"📝 Created commit for patch: {patch_name}")
return True
else:
log_warning(f"Failed to commit patch {patch_path.name}")
if result.stderr:
log_warning(f"Error: {result.stderr}")
return False
except Exception as e:
log_warning(f"Error creating commit for patch {patch_path.name}: {e}")
return False

View File

@@ -7,12 +7,13 @@ import sys
import glob
import shutil
import yaml
import subprocess
from pathlib import Path
from context import BuildContext
from utils import log_info, log_success, log_error, log_warning
def copy_resources(ctx: BuildContext) -> bool:
def copy_resources(ctx: BuildContext, commit_each: bool = False) -> bool:
"""Copy AI extensions and icons based on YAML configuration"""
log_info("\n📦 Copying resources...")
@@ -29,6 +30,9 @@ def copy_resources(ctx: BuildContext) -> bool:
log_info("⚠️ No copy_operations defined in configuration")
return True
if commit_each:
log_info("📝 Git commit mode enabled - will create a commit after each resource copy")
# Process each copy operation
for operation in config["copy_operations"]:
name = operation.get("name", "Unnamed operation")
@@ -58,6 +62,8 @@ def copy_resources(ctx: BuildContext) -> bool:
dst_path.mkdir(parents=True, exist_ok=True)
shutil.copytree(src_path, dst_path, dirs_exist_ok=True)
log_info(f" ✓ Copied directory: {source}{destination}")
if commit_each:
commit_resource_copy(name, source, destination, ctx.chromium_src)
else:
log_warning(f" Source directory not found: {source}")
@@ -71,6 +77,8 @@ def copy_resources(ctx: BuildContext) -> bool:
if file_path.is_file():
shutil.copy2(file_path, dst_base)
log_info(f" ✓ Copied {len(files)} files: {source}{destination}")
if commit_each:
commit_resource_copy(name, source, destination, ctx.chromium_src)
else:
log_warning(f" No files found matching: {source}")
@@ -80,6 +88,8 @@ def copy_resources(ctx: BuildContext) -> bool:
dst_base.parent.mkdir(parents=True, exist_ok=True)
shutil.copy2(src_path, dst_base)
log_info(f" ✓ Copied file: {source}{destination}")
if commit_each:
commit_resource_copy(name, source, destination, ctx.chromium_src)
else:
log_warning(f" Source file not found: {source}")
@@ -87,4 +97,38 @@ def copy_resources(ctx: BuildContext) -> bool:
log_error(f" Error: {e}")
log_success("Resources copied")
return True
def commit_resource_copy(name: str, source: str, destination: str, chromium_src: Path) -> bool:
"""Create a git commit for the copied resource"""
try:
# Stage all changes
cmd_add = ['git', 'add', '-A']
result = subprocess.run(cmd_add, capture_output=True, text=True, cwd=chromium_src)
if result.returncode != 0:
log_warning(f"Failed to stage changes for resource copy: {name}")
if result.stderr:
log_warning(f"Error: {result.stderr}")
return False
# Create commit message
commit_message = f"resource: {name.to_lower()}"
# Create the commit
cmd_commit = ['git', 'commit', '-m', commit_message]
result = subprocess.run(cmd_commit, capture_output=True, text=True, cwd=chromium_src)
if result.returncode == 0:
log_success(f"📝 Created commit for resource: {name}")
return True
else:
log_warning(f"Failed to commit resource copy: {name}")
if result.stderr:
log_warning(f"Error: {result.stderr}")
return False
except Exception as e:
log_warning(f"Error creating commit for resource {name}: {e}")
return False

View File

@@ -19,6 +19,7 @@ from utils import (
log_success,
log_warning,
IS_MACOS,
join_paths,
)
@@ -115,27 +116,27 @@ def find_components_to_sign(
"apps": [],
}
framework_path = app_path / "Contents" / "Frameworks"
framework_path = join_paths(app_path, "Contents", "Frameworks")
# Check both versioned and non-versioned paths for BrowserOS Framework
nxtscape_framework_paths = [framework_path / "BrowserOS Framework.framework"]
# Handle both release and debug framework names
framework_names = ["BrowserOS Framework.framework", "BrowserOS Dev Framework.framework"]
nxtscape_framework_paths = []
for fw_name in framework_names:
fw_path = join_paths(framework_path, fw_name)
if fw_path.exists():
nxtscape_framework_paths.append(fw_path)
# Add versioned path if context is available
if ctx and ctx.nxtscape_chromium_version:
versioned_path = (
framework_path
/ "BrowserOS Framework.framework"
/ "Versions"
/ ctx.nxtscape_chromium_version
)
versioned_path = join_paths(fw_path, "Versions", ctx.nxtscape_chromium_version)
if versioned_path.exists():
nxtscape_framework_paths.insert(
0, versioned_path
) # Prioritize versioned path
nxtscape_framework_paths.insert(0, versioned_path) # Prioritize versioned path
# Find all helper apps
for nxtscape_fw_path in nxtscape_framework_paths:
helpers_dir = nxtscape_fw_path / "Helpers"
helpers_dir = join_paths(nxtscape_fw_path, "Helpers")
if helpers_dir.exists():
# Find all .app helpers
components["helpers"].extend(helpers_dir.glob("*.app"))
@@ -156,16 +157,16 @@ def find_components_to_sign(
# Special handling for Sparkle framework versioned structure
if "Sparkle.framework" in str(fw_path):
# Look for Sparkle's versioned executables at Versions/B/
sparkle_version_b = fw_path / "Versions" / "B"
sparkle_version_b = join_paths(fw_path, "Versions", "B")
if sparkle_version_b.exists():
# Add Autoupdate executable if it exists
autoupdate = sparkle_version_b / "Autoupdate"
autoupdate = join_paths(sparkle_version_b, "Autoupdate")
if autoupdate.exists() and autoupdate.is_file():
components["executables"].append(autoupdate)
# Find all dylibs (check versioned path for BrowserOS Framework libraries)
for nxtscape_fw_path in nxtscape_framework_paths:
libraries_dir = nxtscape_fw_path / "Libraries"
libraries_dir = join_paths(nxtscape_fw_path, "Libraries")
if libraries_dir.exists():
components["dylibs"].extend(libraries_dir.glob("*.dylib"))
@@ -216,7 +217,7 @@ def get_identifier_for_component(
# For frameworks
if component_path.suffix == ".framework":
if name == "BrowserOS Framework":
if name == "BrowserOS Framework" or name == "BrowserOS Dev Framework":
return f"{base_identifier}.framework"
else:
return f"{base_identifier}.{name.replace(' ', '_').lower()}"
@@ -355,7 +356,7 @@ def sign_all_components(
if entitlements_name:
for ent_dir in entitlements_dirs:
ent_path = ent_dir / entitlements_name
ent_path = join_paths(ent_dir, entitlements_name)
if ent_path.exists():
entitlements = ent_path
break
@@ -379,7 +380,19 @@ def sign_all_components(
# 7. Sign main executable
log_info("\n🔏 Signing main executable...")
main_exe = app_path / "Contents" / "MacOS" / "BrowserOS"
# Handle both release and debug executable names
main_exe_names = ["BrowserOS", "BrowserOS Dev"]
main_exe = None
for exe_name in main_exe_names:
exe_path = join_paths(app_path, "Contents", "MacOS", exe_name)
if exe_path.exists():
main_exe = exe_path
break
if not main_exe:
log_error(f"Main executable not found in {join_paths(app_path, 'Contents', 'MacOS')}")
return False
if not sign_component(main_exe, certificate_name, "com.browseros.BrowserOS"):
return False
@@ -398,19 +411,19 @@ def sign_all_components(
if ctx:
entitlements_dirs.append(ctx.get_entitlements_dir())
else:
entitlements_dirs.append(root_dir / "resources" / "entitlements")
entitlements_dirs.append(join_paths(root_dir, "resources", "entitlements"))
# Add fallback locations
entitlements_dirs.extend(
[
root_dir / "entitlements", # Legacy location
root_dir / "build" / "src" / "chrome" / "app",
app_path.parent.parent.parent / "chrome" / "app", # Chromium source
join_paths(root_dir, "entitlements"), # Legacy location
join_paths(root_dir, "build", "src", "chrome", "app"),
join_paths(app_path.parent.parent.parent, "chrome", "app"), # Chromium source
]
)
for ent_name in entitlements_names:
for ent_dir in entitlements_dirs:
ent_path = ent_dir / ent_name
ent_path = join_paths(ent_dir, ent_name)
if ent_path.exists():
entitlements = ent_path
log_info(f" Using entitlements: {entitlements}")
@@ -474,7 +487,7 @@ def notarize_app(
log_info("\n📤 Preparing for notarization...")
# Create zip for notarization
notarize_zip = ctx.get_notarization_zip() if ctx else root_dir / "notarize.zip"
notarize_zip = ctx.get_notarization_zip() if ctx else join_paths(root_dir, "notarize.zip")
if notarize_zip.exists():
notarize_zip.unlink()
@@ -600,7 +613,7 @@ def sign_app(ctx: BuildContext, create_dmg: bool = True) -> bool:
if create_dmg:
dmg_dir = ctx.get_dist_dir()
dmg_name = ctx.get_dmg_name(True)
dmg_path = dmg_dir / dmg_name
dmg_path = join_paths(dmg_dir, dmg_name)
# Verify app exists
if not app_path.exists():
@@ -696,8 +709,8 @@ def sign_universal(contexts: List[BuildContext]) -> bool:
log_info(f"✓ Found {ctx.architecture} build: {app_path}")
# Create universal output directory
universal_dir = contexts[0].chromium_src / "out/Default_universal"
universal_app_path = universal_dir / contexts[0].NXTSCAPE_APP_NAME
universal_dir = join_paths(contexts[0].chromium_src, "out", "Default_universal")
universal_app_path = join_paths(universal_dir, contexts[0].NXTSCAPE_APP_NAME)
if universal_dir.exists():
log_info("Removing existing universal directory...")
@@ -706,7 +719,7 @@ def sign_universal(contexts: List[BuildContext]) -> bool:
universal_dir.mkdir(parents=True, exist_ok=True)
# Use universalizer script to merge architectures
universalizer_script = contexts[0].root_dir / "build" / "universalizer_patched.py"
universalizer_script = join_paths(contexts[0].root_dir, "build", "universalizer_patched.py")
if not universalizer_script.exists():
log_error(f"Universalizer script not found: {universalizer_script}")

File diff suppressed because it is too large Load Diff

View File

@@ -63,6 +63,7 @@ index 0000000000000..3c2a0cbaffed5
+
+class UFRDataSource : public content::URLDataSource {
+ public:
+ UFRDataSource() {}
+ UFRDataSource(const UFRDataSource&) = delete;
+ UFRDataSource& operator=(const UFRDataSource&) = delete;
+

View File

@@ -210,7 +210,7 @@ index 0000000000000..c0b84c7873a18
\ No newline at end of file
diff --git a/chrome/browser/mac/sparkle_glue.mm b/chrome/browser/mac/sparkle_glue.mm
new file mode 100644
index 0000000000000..06a2e9d8a5b8e
index 0000000000000..cf39a1f49a55a
--- /dev/null
+++ b/chrome/browser/mac/sparkle_glue.mm
@@ -0,0 +1,580 @@
@@ -959,7 +959,7 @@ index 0000000000000..bdb3d62440d0d
\ No newline at end of file
diff --git a/chrome/browser/ui/webui/help/sparkle_version_updater_mac.mm b/chrome/browser/ui/webui/help/sparkle_version_updater_mac.mm
new file mode 100644
index 0000000000000..79bb8e37c2e8e
index 0000000000000..889b72abb254a
--- /dev/null
+++ b/chrome/browser/ui/webui/help/sparkle_version_updater_mac.mm
@@ -0,0 +1,109 @@
@@ -998,9 +998,6 @@ index 0000000000000..79bb8e37c2e8e
+ [sparkle setVersionUpdater:GetWeakPtr()];
+
+ [sparkle checkForUpdates];
+
+ SparkleVersionUpdater* Updater = this;
+ updater->PromoteUpdater();
+}
+
+void SparkleVersionUpdater::PromoteUpdater() {

View File

@@ -14,6 +14,8 @@ nxtscape/disable-chrome-labs-pinning.patch
nxtscape/ai-chat-extension.patch
nxtscape/bug-reporter-extension.patch
nxtscape/pin-nxtscape-ai-chat.patch
nxtscape/browserOS-API.patch
nxtscape/new-snapshot-API.patch
# updater
nxtscape/nxtscape-updater-sparkle.patch