diff --git a/.github/workflows/sync-upstream.yml b/.github/workflows/sync-upstream.yml index 44241aa7f..efc4c79f5 100644 --- a/.github/workflows/sync-upstream.yml +++ b/.github/workflows/sync-upstream.yml @@ -73,15 +73,13 @@ jobs: npm run sync fi - - name: Run formatter - if: steps.check-upstream-branch.outputs.branch_exists == 'false' - run: | - sudo apt install python3-autopep8 - npm run pretty + - name: Install autopep8 + run: sudo apt install python3-autopep8 - name: Check if any files changed id: git-check run: | + npm run pretty if [ -n "$(git status --porcelain)" ]; then echo "files_changed=true" >> $GITHUB_OUTPUT else @@ -111,6 +109,15 @@ jobs: if: steps.git-check.outputs.files_changed == 'true' run: python3 scripts/import_external_tests.py || true + - name: Import external patches + if: steps.git-check.outputs.files_changed == 'true' + run: python3 scripts/import_external_patches.py || true + + - name: Run formatter + if: steps.check-upstream-branch.outputs.branch_exists == 'false' + run: | + npm run pretty + - name: Create pull request uses: peter-evans/create-pull-request@v7 if: steps.git-check.outputs.files_changed == 'true' diff --git a/scripts/download_phab_patch.py b/scripts/download_phab_patch.py deleted file mode 100644 index 66d87935a..000000000 --- a/scripts/download_phab_patch.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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 http://mozilla.org/MPL/2.0/. - -import os -import sys -import requests - -BASE_URI = "https://phabricator.services.mozilla.com" -OUTPUT_DIR = os.path.join(os.getcwd(), "src", "firefox-patches") - - -def download_phab_patch(phab_id, output_file): - """Download a Phabricator patch by its ID and save it to output_file.""" - patch_url = f"{BASE_URI}/{phab_id}?download=true" - try: - print(f"Downloading patch from {patch_url}") - response = requests.get(patch_url) - response.raise_for_status() # Raise an error for bad responses - with open(output_file, 'wb') as f: - f.write(response.content) - print(f"Patch saved to {output_file}") - except requests.RequestException as e: - print(f"Error downloading patch: {e}") - sys.exit(1) - - -def main(): - if len(sys.argv) < 2: - print("Usage: python download_phab_patch.py [output_file]", file=sys.stderr) - sys.exit(1) - - phab_id = sys.argv[1] - output_file = sys.argv[2] if len(sys.argv) > 2 else f"phab_{phab_id}" - output_file = os.path.join(OUTPUT_DIR, output_file + ".patch") - - download_phab_patch(phab_id, output_file) - - -if __name__ == "__main__": - main() diff --git a/scripts/update_external_patches.py b/scripts/update_external_patches.py new file mode 100644 index 000000000..cf2c1c0ef --- /dev/null +++ b/scripts/update_external_patches.py @@ -0,0 +1,99 @@ +# 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 http://mozilla.org/MPL/2.0/. + +import os +import sys +import json +import requests +from json_with_comments import JSONWithCommentsDecoder + +BASE_URI = "https://phabricator.services.mozilla.com" +OUTPUT_DIR = os.path.join(os.getcwd(), "src", "external-patches") + + +def die(message): + print(f"Error: {message}") + sys.exit(1) + + +def download_phab_patch(phab_id, output_file): + """Download a Phabricator patch by its ID and save it to output_file.""" + patch_url = f"{BASE_URI}/{phab_id}?download=true" + try: + print(f"Downloading patch from {patch_url}") + response = requests.get(patch_url) + response.raise_for_status() # Raise an error for bad responses + with open(output_file, 'wb') as f: + f.write(response.content) + print(f"Patch saved to {output_file}") + except requests.RequestException as e: + die(f"Failed to download patch {phab_id}: {e}") + + +def download_patch_from_url(url, output_file): + """Download a patch from a given URL and save it to output_file.""" + try: + print(f"Downloading patch from {url}") + response = requests.get(url) + response.raise_for_status() # Raise an error for bad responses + with open(output_file, 'wb') as f: + f.write(response.content) + print(f"Patch saved to {output_file}") + except requests.RequestException as e: + die(f"Failed to download patch from {url}: {e}") + + +def main(): + with open(os.path.join(OUTPUT_DIR, "manifest.json"), 'r') as f: + manifest = json.load(f, cls=JSONWithCommentsDecoder) + + expected_files = set() + for patch in manifest: + if patch.get("type") == "phabricator": + phab_id = patch.get("id") + name = patch.get("name") + if not phab_id or not name: + die(f"Patch entry missing 'id' or 'name': {patch}") + name = name.replace(" ", "_").lower() + output_file = os.path.join(OUTPUT_DIR, "firefox", f"{name}.patch") + print(f"Processing Phabricator patch: {phab_id} -> {output_file}") + download_phab_patch(phab_id, output_file) + expected_files.add(output_file) + elif patch.get("type") == "local": + print(f"Local patch: {patch.get('path')}") + expected_files.add(os.path.join(OUTPUT_DIR, patch.get("path"))) + elif patch.get("type") == "patch": + url = patch.get("url") + dest = patch.get("dest") + if not url or not dest: + die(f"Patch entry missing 'url' or 'dest': {patch}") + filename = url.split("/")[-1] + output_file = os.path.join(OUTPUT_DIR, dest, filename) + download_patch_from_url(url, output_file) + replaces = patch.get("replaces", {}) + for replace in replaces.keys(): + value = replaces[replace] + with open(output_file, 'r') as f: + content = f.read() + if replace not in content: + die(f"Replace string '{replace}' not found in {replace}") + with open(output_file, 'w') as f: + f.write(content.replace(replace, value)) + expected_files.add(output_file) + else: + die(f"Unknown patch type: {patch.get('type')}") + + # Check for unexpected files in the output directory + # and remove them if they are not in the expected_files set. + for root, dirs, files in os.walk(OUTPUT_DIR): + for file in files: + if file.endswith(".patch"): + file_path = os.path.join(root, file) + if file_path not in expected_files: + print(f"Removing unexpected patch file: {file_path}") + os.remove(file_path) + + +if __name__ == "__main__": + main() diff --git a/src/firefox-patches/.gitkeep b/src/external-patches/firefox/.gitkeep similarity index 100% rename from src/firefox-patches/.gitkeep rename to src/external-patches/firefox/.gitkeep diff --git a/src/firefox-patches/README.md b/src/external-patches/firefox/README.md similarity index 100% rename from src/firefox-patches/README.md rename to src/external-patches/firefox/README.md diff --git a/src/firefox-patches/phab_D279007_fix_macos_builds.patch b/src/external-patches/firefox/fix_macos_crash_on_shutdown_firefox_149.patch similarity index 100% rename from src/firefox-patches/phab_D279007_fix_macos_builds.patch rename to src/external-patches/firefox/fix_macos_crash_on_shutdown_firefox_149.patch diff --git a/src/firefox-patches/no_liquid_glass_icon.patch b/src/external-patches/firefox/no_liquid_glass_icon.patch similarity index 100% rename from src/firefox-patches/no_liquid_glass_icon.patch rename to src/external-patches/firefox/no_liquid_glass_icon.patch diff --git a/src/external-patches/librewolf/README.md b/src/external-patches/librewolf/README.md new file mode 100644 index 000000000..a11780e56 --- /dev/null +++ b/src/external-patches/librewolf/README.md @@ -0,0 +1,3 @@ +# Patches imported from LibreWolf + +Firefox sometimes makes changes without considering the impact on forks. This is the case of the patches that are imported from LibreWolf, which are already present in LibreWolf but not yet (or never) present in Firefox. Thanks to LibreWolf for making these patches available and for their work in maintaining them. We will keep these patches as long as they are needed, and we will remove them once they are no longer necessary (for example, when they are merged into Firefox or when the issue they solve is no longer present). diff --git a/src/external-patches/librewolf/firefox-in-ua.patch b/src/external-patches/librewolf/firefox-in-ua.patch new file mode 100644 index 000000000..e4e23c284 --- /dev/null +++ b/src/external-patches/librewolf/firefox-in-ua.patch @@ -0,0 +1,12 @@ +diff --git a/toolkit/moz.configure b/toolkit/moz.configure +--- a/toolkit/moz.configure ++++ b/toolkit/moz.configure +@@ -28,7 +28,7 @@ project_flag( + + project_flag( + env="MOZ_APP_UA_NAME", +- default="", ++ default="Firefox", + nargs=1, + help="Application name in the User Agent string", + ) diff --git a/src/external-patches/librewolf/xdg-dir.patch b/src/external-patches/librewolf/xdg-dir.patch new file mode 100644 index 000000000..cb05e7c45 --- /dev/null +++ b/src/external-patches/librewolf/xdg-dir.patch @@ -0,0 +1,65 @@ +diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp +index 3cf7073..b1c782a 100644 +--- a/toolkit/xre/nsXREDirProvider.cpp ++++ b/toolkit/xre/nsXREDirProvider.cpp +@@ -1283,9 +1283,11 @@ nsresult nsXREDirProvider::AppendFromAppData(nsIFile* aFile, bool aIsDotted) { + // Similar to nsXREDirProvider::AppendProfilePath. + // TODO: Bug 1990407 - Evaluate if refactoring might be required there in the + // future? +- if (gAppData->profile) { ++ // Use aIsDotted for a different purpose here, will probably break in the future ++ if (gAppData->profile && aIsDotted) { + nsAutoCString profile; + profile = gAppData->profile; ++ profile = "."_ns + nsDependentCString(gAppData->profile); + MOZ_TRY(aFile->AppendRelativeNativePath(profile)); + } else { + nsAutoCString vendor; +@@ -1295,8 +1297,8 @@ nsresult nsXREDirProvider::AppendFromAppData(nsIFile* aFile, bool aIsDotted) { + ToLowerCase(vendor); + ToLowerCase(appName); + +- MOZ_TRY(aFile->AppendRelativeNativePath(aIsDotted ? ("."_ns + vendor) +- : vendor)); ++ //MOZ_TRY(aFile->AppendRelativeNativePath(aIsDotted ? ("."_ns + vendor) ++ // : vendor)); + MOZ_TRY(aFile->AppendRelativeNativePath(appName)); + } + +@@ -1435,28 +1437,22 @@ nsresult nsXREDirProvider::GetLegacyOrXDGHomePath(const char* aHomeDir, + return NS_OK; + } + +- // If the build was made against a specific profile name, MOZ_APP_PROFILE= +- // then make sure we respect this and dont move to XDG directory +- if (gAppData->profile) { +- MOZ_TRY(NS_NewNativeLocalFile(nsDependentCString(aHomeDir), +- getter_AddRefs(localDir))); +- } else { +- MOZ_TRY(GetLegacyOrXDGConfigHome(aHomeDir, getter_AddRefs(localDir))); +- MOZ_TRY(localDir->Clone(getter_AddRefs(parentDir))); +- } ++ // Since we set gAppData->profile and don't want to force legacy behaviour ++ MOZ_TRY(GetLegacyOrXDGConfigHome(aHomeDir, getter_AddRefs(localDir))); ++ MOZ_TRY(localDir->Clone(getter_AddRefs(parentDir))); + + MOZ_TRY(AppendFromAppData(localDir, false)); + } + ++ // The profile root directory needs to exists at that point. ++ MOZ_TRY(EnsureDirectoryExists(localDir)); ++ + // If required return the parent directory that matches the profile root + // directory. + if (aFile) { +- parentDir.forget(aFile); ++ localDir.forget(aFile); + } + +- // The profile root directory needs to exists at that point. +- MOZ_TRY(EnsureDirectoryExists(localDir)); +- + return NS_OK; + } + #endif // defined(MOZ_WIDGET_GTK) + diff --git a/src/external-patches/manifest.json b/src/external-patches/manifest.json new file mode 100644 index 000000000..256ca76ea --- /dev/null +++ b/src/external-patches/manifest.json @@ -0,0 +1,29 @@ +// 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 http://mozilla.org/MPL/2.0/. +[ + { + "type": "phabricator", + "id": "D279007", + "name": "Fix MacOS Crash on Shutdown Firefox 149" + }, + { + "type": "local", + "path": "firefox/no_liquid_glass_icon.patch" + }, + { + "type": "patch", + "url": "https://codeberg.org/librewolf/source/raw/branch/main/patches/firefox-in-ua.patch", + "dest": "librewolf", + "replaces": { + // They don't correctly export this patch, so we need to replace + // the parameter's help description with the correct one. + "application": "Application" + } + }, + { + "type": "patch", + "url": "https://codeberg.org/librewolf/source/raw/branch/main/patches/xdg-dir.patch", + "dest": "librewolf" + } +] diff --git a/src/netwerk/protocol/http/moz-build.patch b/src/netwerk/protocol/http/moz-build.patch deleted file mode 100644 index 19b407ac1..000000000 --- a/src/netwerk/protocol/http/moz-build.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build -index d2330003caf35c43d6831fb0d356ece513906f78..76c2faf822ddaf645eb03d93380c58b4e3b510c0 100644 ---- a/netwerk/protocol/http/moz.build -+++ b/netwerk/protocol/http/moz.build -@@ -227,7 +227,7 @@ LOCAL_INCLUDES += [ - "/netwerk/url-classifier", - ] - --DEFINES["MOZ_APP_UA_NAME"] = f'"{CONFIG["MOZ_APP_UA_NAME"]}"' -+DEFINES["MOZ_APP_UA_NAME"] = f'"Firefox"' - - if CONFIG["MOZ_AUTH_EXTENSION"]: - LOCAL_INCLUDES += [ diff --git a/src/toolkit/components/extensions/parent/ext-runtime-js.patch b/src/toolkit/components/extensions/parent/ext-runtime-js.patch index 3e3a78344..99f21302f 100644 --- a/src/toolkit/components/extensions/parent/ext-runtime-js.patch +++ b/src/toolkit/components/extensions/parent/ext-runtime-js.patch @@ -7,7 +7,7 @@ index 0d7a3e505b6bd30548c6dda1504dd343a517b083..54400def5e02e886765fab68c3854a6b getBrowserInfo: function () { const { name, vendor, version, appBuildID } = Services.appinfo; - const info = { name, vendor, version, buildID: appBuildID }; -+ const info = { name: 'firefox', vendor, version: AppConstants.ZEN_FIREFOX_VERSION, buildID: appBuildID }; ++ const info = { name: 'Firefox', vendor, version: AppConstants.ZEN_FIREFOX_VERSION, buildID: appBuildID }; return Promise.resolve(info); },