diff --git a/docs/setup/windows_build.rst b/docs/setup/windows_build.rst index af670c65b3e6..4899755bf57b 100644 --- a/docs/setup/windows_build.rst +++ b/docs/setup/windows_build.rst @@ -78,6 +78,13 @@ the interactive setup process. cd mozilla-source wget https://hg.mozilla.org/mozilla-central/raw-file/default/python/mozboot/bin/bootstrap.py python3 bootstrap.py +.. note:: + + When running ``bootstrap.py`` there will be a UAC prompt (for PowerShell) after + selecting the destination directory for the source code clone. This is + necessary to add the Microsoft Defender Antivirus exclusions automatically. You + should select ``Yes`` on the UAC prompt, otherwise you will need + to `follow some manual steps below `_. .. note:: @@ -98,22 +105,25 @@ If you aren't modifying the Firefox backend, then select one of the :ref:`Artifact Mode ` options. If you are building Firefox for Android, you should also see the :ref:`GeckoView Contributor Guide`. -Set antivirus exclusions -~~~~~~~~~~~~~~~~~~~~~~~~ +Ensure antivirus exclusions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Windows Defender and some scanning antivirus products are known to significantly degrade -build times and sometimes even cause failed builds (due to a "missing file"). -This is usually because we have tests for well-known security bugs that have -code samples that antivirus software identifies as a threat, automatically -quarantining/corrupting the files. +Microsoft Defender Antivirus and some third-party antivirus products +are known to significantly degrade build times and sometimes even cause failed +builds (due to a "missing file"). This is usually because we have tests for +well-known security bugs that have code samples that antivirus software identifies +as a threat, automatically quarantining/corrupting the files. -To avoid this, add two folders to your antivirus exclusion list: +To avoid this, add the following folders to your third-party antivirus exclusion list: - The ``C:\mozilla-build`` folder. - The directory where the Firefox code is (probably ``C:\mozilla-source``). +- The ``%USERPROFILE%/.mozbuild`` directory (probably ``C:\Users\\.mozbuild``). -If you haven't installed an antivirus, then you will need to `add the exclusions -to Windows Defender +The ``bootstrap.py`` script attempts to add the above folders to the Microsoft +Defender Antivirus exclusion list automatically. You should check that they were +successfully added, but if they're missing you will need to `add the exclusions to +Microsoft Defender Antivirus manually `_. .. note:: diff --git a/python/mozboot/bin/bootstrap.py b/python/mozboot/bin/bootstrap.py index bd0a28e6fb38..d77e96fa0b1e 100755 --- a/python/mozboot/bin/bootstrap.py +++ b/python/mozboot/bin/bootstrap.py @@ -29,6 +29,7 @@ import stat import subprocess import tempfile import zipfile +import ctypes from pathlib import Path from optparse import OptionParser @@ -254,7 +255,52 @@ def git_clone_firefox(git: Path, dest: Path, watchman: Path): shutil.rmtree(str(tempdir)) -def clone(vcs, no_interactive): +def add_microsoft_defender_antivirus_exclusions(dest, no_system_changes): + if no_system_changes: + return + + powershell_exe = which("powershell") + + if not powershell_exe: + return + + def print_attempt_exclusion(path): + print( + f"Attempting to add exclusion path to Microsoft Defender Antivirus for: {path}" + ) + + powershell_exe = str(powershell_exe) + paths = [] + + # mozilla-unified / clone dest + repo_dir = Path.cwd() / dest + paths.append(repo_dir) + print_attempt_exclusion(repo_dir) + + # MOZILLABUILD + mozillabuild_dir = os.getenv("MOZILLABUILD") + if mozillabuild_dir: + paths.append(mozillabuild_dir) + print_attempt_exclusion(mozillabuild_dir) + + # .mozbuild + mozbuild_dir = Path.home() / ".mozbuild" + paths.append(mozbuild_dir) + print_attempt_exclusion(mozbuild_dir) + + args = ";".join(f"Add-MpPreference -ExclusionPath '{path}'" for path in paths) + command = f'-Command "{args}"' + + # This will attempt to run as administrator by triggering a UAC prompt + # for admin credentials. If "No" is selected, no exclusions are added. + ctypes.windll.shell32.ShellExecuteW(None, "runas", powershell_exe, command, None, 0) + + +def clone(options): + vcs = options.vcs + no_interactive = options.no_interactive + no_system_changes = options.no_system_changes + hg = which("hg") if not hg: print( @@ -289,6 +335,8 @@ def clone(vcs, no_interactive): if not dest: return None + add_microsoft_defender_antivirus_exclusions(dest, no_system_changes) + print(f"Cloning Firefox {VCS_HUMAN_READABLE[vcs]} repository to {dest}") if vcs == "hg": return hg_clone_firefox(binary, dest) @@ -348,7 +396,7 @@ def main(args): options, leftover = parser.parse_args(args) try: - srcdir = clone(options.vcs, options.no_interactive) + srcdir = clone(options) if not srcdir: return 1 print("Clone complete.")