Browse Source

build fixes

Frank-Rainer Grahl 5 days ago
parent
commit
15cdcc5132

+ 0 - 0
mozilla-release/patches/1712133-1-90a1.patch → mozilla-release/patches/1712133-01-90a1.patch


+ 0 - 0
mozilla-release/patches/1712133-2-90a1.patch → mozilla-release/patches/1712133-02-90a1.patch


+ 0 - 0
mozilla-release/patches/1712133-3-90a1.patch → mozilla-release/patches/1712133-03-90a1.patch


+ 0 - 0
mozilla-release/patches/1712133-4-90a1.patch → mozilla-release/patches/1712133-04-90a1.patch


+ 56 - 0
mozilla-release/patches/1712133-05-91a1.patch

@@ -0,0 +1,56 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1623768415 0
+# Node ID 4a326b86ad24d57ba0cd5fafaac057f6d0fbf9f2
+# Parent  c4e02cbabd999bc47fa0dd79368249a10d461844
+Bug 1712133: Synchronize virtualenv requirement parsing logic r=ahal
+
+The `mach_bootstrap:search_path()` implementation is out of
+date compared to `virtualenv.py`.
+
+Since `python2:`, `python3:` and `optional:` packages are no
+longer valid virtualenv requirement actions, they can be removed.
+
+Differential Revision: https://phabricator.services.mozilla.com/D117707
+
+diff --git a/build/mach_bootstrap.py b/build/mach_bootstrap.py
+--- a/build/mach_bootstrap.py
++++ b/build/mach_bootstrap.py
+@@ -114,37 +114,23 @@ CATEGORIES = {
+ }
+ 
+ 
+ def search_path(mozilla_dir, packages_txt):
+     with open(os.path.join(mozilla_dir, packages_txt)) as f:
+         packages = [line.rstrip().split(':') for line in f]
+ 
+     def handle_package(package):
+-        if package[0] == 'optional':
+-            try:
+-                for path in handle_package(package[1:]):
+-                    yield path
+-            except Exception:
+-                pass
+-
+         if package[0] in ('windows', '!windows'):
+             for_win = not package[0].startswith('!')
+             is_win = sys.platform == 'win32'
+             if is_win == for_win:
+                 for path in handle_package(package[1:]):
+                     yield path
+ 
+-        if package[0] in ('python2', 'python3'):
+-            for_python3 = package[0].endswith('3')
+-            is_python3 = sys.version_info[0] > 2
+-            if is_python3 == for_python3:
+-                for path in handle_package(package[1:]):
+-                    yield path
+-
+         if package[0] == 'packages.txt':
+             assert len(package) == 2
+             for p in search_path(mozilla_dir, package[1]):
+                 yield os.path.join(mozilla_dir, p)
+ 
+         if package[0].endswith('.pth'):
+             assert len(package) == 2
+             yield os.path.join(mozilla_dir, package[1])

+ 92 - 0
mozilla-release/patches/1712133-06-91a1.patch

@@ -0,0 +1,92 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1623768415 0
+# Node ID a705e6a13d9621d8ae3f7ff615e0ac824eb4b612
+# Parent  7f6dd3ad3508226996102356f612d0ad4dfe9462
+Bug 1712133: Remove "windows" action support from virtualenvs r=ahal
+
+Last year, we stopped vendoring Python packages that have native
+code. Since we have only had pure-python packages since, the
+Windows-specific qualifier (or excluder in the case of `!windows`)
+hasn't been needed.
+
+I don't foresee us needing it again, but if anything we can peel it
+back from `hg` history if this assumption is incorrect.
+
+Differential Revision: https://phabricator.services.mozilla.com/D117468
+
+diff --git a/build/mach_bootstrap.py b/build/mach_bootstrap.py
+--- a/build/mach_bootstrap.py
++++ b/build/mach_bootstrap.py
+@@ -114,23 +114,16 @@ CATEGORIES = {
+ }
+ 
+ 
+ def search_path(mozilla_dir, packages_txt):
+     with open(os.path.join(mozilla_dir, packages_txt)) as f:
+         packages = [line.rstrip().split(':') for line in f]
+ 
+     def handle_package(package):
+-        if package[0] in ('windows', '!windows'):
+-            for_win = not package[0].startswith('!')
+-            is_win = sys.platform == 'win32'
+-            if is_win == for_win:
+-                for path in handle_package(package[1:]):
+-                    yield path
+-
+         if package[0] == 'packages.txt':
+             assert len(package) == 2
+             for p in search_path(mozilla_dir, package[1]):
+                 yield os.path.join(mozilla_dir, p)
+ 
+         if package[0].endswith('.pth'):
+             assert len(package) == 2
+             yield os.path.join(mozilla_dir, package[1])
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -281,22 +281,16 @@ class VirtualenvManager(VirtualenvHelper
+             checkouts. The initial "thunderbird" field is stripped, then the
+             remaining line is processed like normal. e.g.
+             "thunderbird:comms.pth:python/foo"
+ 
+         packages.txt -- Denotes that the specified path is a child manifest. It
+             will be read and processed as if its contents were concatenated
+             into the manifest being read.
+ 
+-        windows -- This denotes that the action should only be taken when run
+-            on Windows.
+-
+-        !windows -- This denotes that the action should only be taken when run
+-            on non-Windows systems.
+-
+         set-variable -- Set the given environment variable; e.g.
+             `set-variable FOO=1`.
+ 
+         Note that the Python interpreter running this function should be the
+         one from the virtualenv. If it is the system Python or if the
+         environment is not configured properly, packages could be installed
+         into the wrong place. This is how virtualenv's work.
+         """
+@@ -331,21 +325,16 @@ class VirtualenvManager(VirtualenvHelper
+                     # This path is relative to the .pth file.  Using a
+                     # relative path allows the srcdir/objdir combination
+                     # to be moved around (as long as the paths relative to
+                     # each other remain the same).
+                     f.write("%s\n" % os.path.relpath(path, python_lib))
+             elif package[0] == "thunderbird":
+                 if is_thunderbird:
+                     handle_package(package[1:])
+-            elif package[0] in ("windows", "!windows"):
+-                for_win = not package[0].startswith('!')
+-                is_win = sys.platform == 'win32'
+-                if is_win == for_win:
+-                    handle_package(package[1:])
+             else:
+                 raise Exception("Unknown action: %s" % package[0])
+ 
+         # We always target the OS X deployment target that Python itself was
+         # built with, regardless of what's in the current environment. If we
+         # don't do # this, we may run into a Python bug. See
+         # http://bugs.python.org/issue9516 and bug 659881.
+         #

+ 184 - 0
mozilla-release/patches/1712133-07-91a1.patch

@@ -0,0 +1,184 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1623941896 0
+# Node ID f439c1345fd71163a5c9d9c62269f37dfd60f50e
+# Parent  417c5f324eca93a9d0de49666e0eaf1229a8adb9
+Bug 1712133: Make virtualenv package parsing more specific r=ahal
+
+This has two benefits:
+1. `handle_package()` becomes more clear - rather than referring to
+   `action` and `package` with array index numbers, we now give
+   them real names. The benefit here is also shown in `up_to_date()`.
+2. This makes the top-level parser for `packages()` less opinionated
+   about sub-formats: if an action has a nested structure, it should
+   have the flexibility to define what it looks like.
+
+Differential Revision: https://phabricator.services.mozilla.com/D117708
+
+diff --git a/build/mach_bootstrap.py b/build/mach_bootstrap.py
+--- a/build/mach_bootstrap.py
++++ b/build/mach_bootstrap.py
+@@ -111,30 +111,28 @@ CATEGORIES = {
+         'run "mach <command>" to see why.',
+         'priority': 0,
+     }
+ }
+ 
+ 
+ def search_path(mozilla_dir, packages_txt):
+     with open(os.path.join(mozilla_dir, packages_txt)) as f:
+-        packages = [line.rstrip().split(':') for line in f]
++        packages = [line.rstrip().split(":", maxsplit=1) for line in f]
+ 
+-    def handle_package(package):
+-        if package[0] == 'packages.txt':
+-            assert len(package) == 2
+-            for p in search_path(mozilla_dir, package[1]):
++    def handle_package(action, package):
++        if action == "packages.txt":
++            for p in search_path(mozilla_dir, package):
+                 yield os.path.join(mozilla_dir, p)
+ 
+-        if package[0].endswith('.pth'):
+-            assert len(package) == 2
+-            yield os.path.join(mozilla_dir, package[1])
++        if action.endswith(".pth"):
++            yield os.path.join(mozilla_dir, package)
+ 
+-    for package in packages:
+-        for path in handle_package(package):
++    for current_action, current_package in packages:
++        for path in handle_package(current_action, current_package):
+             yield path
+ 
+ 
+ def mach_sys_path(mozilla_dir):
+     return [
+         os.path.join(mozilla_dir, path)
+         for path in search_path(mozilla_dir, "build/mach_virtualenv_packages.txt")
+     ]
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -182,18 +182,19 @@ class VirtualenvManager(VirtualenvHelper
+         # virtualenv. If this fails, it is likely system Python has been
+         # upgraded, and our virtualenv would not be usable.
+         orig_version = self.get_exe_info()
+         hexversion = self.python_executable_hexversion(python)
+         if (python != self.python_path) and (hexversion != orig_version):
+             return False
+ 
+         # recursively check sub packages.txt files
+-        submanifests = [i[1] for i in self.packages()
+-                        if i[0] == 'packages.txt']
++        submanifests = [
++            package for action, package in self.packages() if action == "packages.txt"
++        ]
+         for submanifest in submanifests:
+             submanifest = os.path.join(self.topsrcdir, submanifest)
+             submanager = VirtualenvManager(self.topsrcdir,
+                                            self.virtualenv_root,
+                                            self.log_handle,
+                                            submanifest)
+             if not submanager.up_to_date(python):
+                 return False
+@@ -258,19 +259,17 @@ class VirtualenvManager(VirtualenvHelper
+ 
+         self.write_exe_info(python)
+         self._disable_pip_outdated_warning()
+ 
+         return self.virtualenv_root
+ 
+     def packages(self):
+         with open(self.manifest_path, "r") as fh:
+-            packages = [line.rstrip().split(':')
+-                        for line in fh]
+-        return packages
++            return [line.rstrip().split(":", maxsplit=1) for line in fh]
+ 
+     def populate(self):
+         """Populate the virtualenv.
+ 
+         The manifest file consists of colon-delimited fields. The first field
+         specifies the action. The remaining fields are arguments to that
+         action. The following actions are supported:
+ 
+@@ -295,48 +294,43 @@ class VirtualenvManager(VirtualenvHelper
+         into the wrong place. This is how virtualenv's work.
+         """
+         import distutils.sysconfig
+ 
+         thunderbird_dir = os.path.join(self.topsrcdir, "comm")
+         is_thunderbird = os.path.exists(thunderbird_dir) and bool(
+             os.listdir(thunderbird_dir)
+         )
+-        packages = self.packages()
+         python_lib = distutils.sysconfig.get_python_lib()
+ 
+-        def handle_package(package):
+-            if package[0] == 'packages.txt':
+-                assert len(package) == 2
+-
+-                src = os.path.join(self.topsrcdir, package[1])
++        def handle_package(action, package):
++            if action == "packages.txt":
++                src = os.path.join(self.topsrcdir, package)
+                 assert os.path.isfile(src), "'%s' does not exist" % src
+                 submanager = VirtualenvManager(
+                     self.topsrcdir, self.virtualenv_root, self.log_handle, src,
+                     populate_local_paths=self.populate_local_paths)
+                 submanager.populate()
+-            elif package[0].endswith(".pth"):
+-                assert len(package) == 2
+-
++            elif action.endswith(".pth"):
+                 if not self.populate_local_paths:
+                     return
+ 
+-                path = os.path.join(self.topsrcdir, package[1])
++                path = os.path.join(self.topsrcdir, package)
+ 
+-                with open(os.path.join(python_lib, package[0]), 'a') as f:
++                with open(os.path.join(python_lib, action), "a") as f:
+                     # This path is relative to the .pth file.  Using a
+                     # relative path allows the srcdir/objdir combination
+                     # to be moved around (as long as the paths relative to
+                     # each other remain the same).
+                     f.write("%s\n" % os.path.relpath(path, python_lib))
+-            elif package[0] == "thunderbird":
++            elif action == "thunderbird":
+                 if is_thunderbird:
+-                    handle_package(package[1:])
++                    handle_package(*package.split(":", maxsplit=1))
+             else:
+-                raise Exception("Unknown action: %s" % package[0])
++                raise Exception("Unknown action: %s" % action)
+ 
+         # We always target the OS X deployment target that Python itself was
+         # built with, regardless of what's in the current environment. If we
+         # don't do # this, we may run into a Python bug. See
+         # http://bugs.python.org/issue9516 and bug 659881.
+         #
+         # Note that this assumes that nothing compiled in the virtualenv is
+         # shipped as part of a distribution. If we do ship anything, the
+@@ -364,18 +358,18 @@ class VirtualenvManager(VirtualenvHelper
+             old_env_variables = {}
+             for k in IGNORE_ENV_VARIABLES:
+                 if k not in os.environ:
+                     continue
+ 
+                 old_env_variables[k] = os.environ[k]
+                 del os.environ[k]
+ 
+-            for package in packages:
+-                handle_package(package)
++            for current_action, current_package in self.packages():
++                handle_package(current_action, current_package)
+ 
+         finally:
+             os.environ.pop('MACOSX_DEPLOYMENT_TARGET', None)
+ 
+             if old_target is not None:
+                 os.environ['MACOSX_DEPLOYMENT_TARGET'] = old_target
+ 
+             os.environ.update(old_env_variables)

+ 303 - 0
mozilla-release/patches/1712133-08-91a1.patch

@@ -0,0 +1,303 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1623941896 0
+# Node ID 030a489e51f5dc8cd00c6c33c0d1148491ef2c70
+# Parent  32a5c1954a9d659249510cb2b846d24e28cef6dc
+Bug 1712133: Remove "pth" name customization r=ahal
+
+Having separate `<name>.pth` files in the virtual environments
+isn't providing an advantage. We can simplify configuration
+by putting all `pth` adjustments into a single file: `mach.pth`.
+
+Differential Revision: https://phabricator.services.mozilla.com/D117710
+
+diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt
+--- a/build/common_virtualenv_packages.txt
++++ b/build/common_virtualenv_packages.txt
+@@ -1,78 +1,78 @@
+ thunderbird:packages.txt:comm/build/virtualenv_packages.txt
+-mozilla.pth:build
+-mozilla.pth:config
+-mozilla.pth:config/mozunit
+-mozilla.pth:dom/bindings
+-mozilla.pth:dom/bindings/parser
+-mozilla.pth:layout/tools/reftest
+-mozilla.pth:python/mach
+-mozilla.pth:python/mozboot
+-mozilla.pth:python/mozbuild
+-mozilla.pth:python/mozlint
+-mozilla.pth:python/mozperftest
+-mozilla.pth:python/mozrelease
+-mozilla.pth:python/mozterm
+-mozilla.pth:python/mozversioncontrol
+-mozilla.pth:testing
+-mozilla.pth:testing/firefox-ui/harness
+-mozilla.pth:testing/marionette/client
+-mozilla.pth:testing/marionette/harness
+-mozilla.pth:testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py
+-mozilla.pth:testing/marionette/puppeteer/firefox
++pth:build
++pth:config
++pth:config/mozunit
++pth:dom/bindings
++pth:dom/bindings/parser
++pth:layout/tools/reftest
++pth:python/mach
++pth:python/mozboot
++pth:python/mozbuild
++pth:python/mozlint
++pth:python/mozperftest
++pth:python/mozrelease
++pth:python/mozterm
++pth:python/mozversioncontrol
++pth:testing
++pth:testing/firefox-ui/harness
++pth:testing/marionette/client
++pth:testing/marionette/harness
++pth:testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py
++pth:testing/marionette/puppeteer/firefox
+ packages.txt:testing/mozbase/packages.txt
+-mozilla.pth:testing/talos
+-mozilla.pth:testing/web-platform/tests/tools/six
+-mozilla.pth:testing/web-platform/tests/tools/wptrunner
+-mozilla.pth:testing/web-platform/tests/tools/wptserve
+-mozilla.pth:testing/xpcshell
+-mozilla.pth:third_party/python/appdirs
+-mozilla.pth:third_party/python/atomicwrites
+-mozilla.pth:third_party/python/attrs/src
+-mozilla.pth:third_party/python/blessings
+-mozilla.pth:third_party/python/cbor2
+-mozilla.pth:third_party/python/chardet
+-mozilla.pth:third_party/python/Click
+-mozilla.pth:third_party/python/compare-locales
+-mozilla.pth:third_party/python/cookies
+-mozilla.pth:third_party/python/cram
+-mozilla.pth:third_party/python/distro
+-mozilla.pth:third_party/python/dlmanager
+-mozilla.pth:third_party/python/ecdsa/src
+-mozilla.pth:third_party/python/fluent.migrate
+-mozilla.pth:third_party/python/fluent.syntax
+-mozilla.pth:third_party/python/funcsigs
+-mozilla.pth:third_party/python/gyp/pylib
+-mozilla.pth:third_party/python/idna
+-mozilla.pth:third_party/python/importlib_metadata
+-mozilla.pth:third_party/python/jsmin
+-mozilla.pth:third_party/python/json-e
+-mozilla.pth:third_party/python/mock-1.0.0
+-mozilla.pth:third_party/python/more-itertools
+-mozilla.pth:third_party/python/pathspec
+-mozilla.pth:third_party/python/pluggy
+-mozilla.pth:third_party/python/ply
+-mozilla.pth:third_party/python/py
+-mozilla.pth:third_party/python/pyasn1
+-mozilla.pth:third_party/python/pyasn1-modules
+-mozilla.pth:third_party/python/pylru
+-mozilla.pth:third_party/python/pystache
+-mozilla.pth:third_party/python/pytest/src
+-mozilla.pth:third_party/python/python-hglib
+-mozilla.pth:third_party/python/pytoml
+-mozilla.pth:third_party/python/PyYAML/lib3/
+-mozilla.pth:third_party/python/redo
+-mozilla.pth:third_party/python/requests
+-mozilla.pth:third_party/python/requests-unixsocket
+-mozilla.pth:third_party/python/responses
+-mozilla.pth:third_party/python/rsa
+-mozilla.pth:third_party/python/six
+-mozilla.pth:third_party/python/slugid
+-mozilla.pth:third_party/python/typing_extensions/src_py3
+-mozilla.pth:third_party/python/urllib3/src
+-mozilla.pth:third_party/python/voluptuous
+-mozilla.pth:third_party/python/yamllint
+-mozilla.pth:third_party/python/zipp
+-mozilla.pth:tools
+-mozilla.pth:tools/docs
+-mozilla.pth:xpcom/idl-parser
+-mozilla.pth:xpcom/typelib/xpt/tools
++pth:testing/talos
++pth:testing/web-platform/tests/tools/six
++pth:testing/web-platform/tests/tools/wptrunner
++pth:testing/web-platform/tests/tools/wptserve
++pth:testing/xpcshell
++pth:third_party/python/appdirs
++pth:third_party/python/atomicwrites
++pth:third_party/python/attrs/src
++pth:third_party/python/blessings
++pth:third_party/python/cbor2
++pth:third_party/python/chardet
++pth:third_party/python/Click
++pth:third_party/python/compare-locales
++pth:third_party/python/cookies
++pth:third_party/python/cram
++pth:third_party/python/distro
++pth:third_party/python/dlmanager
++pth:third_party/python/ecdsa/src
++pth:third_party/python/fluent.migrate
++pth:third_party/python/fluent.syntax
++pth:third_party/python/funcsigs
++pth:third_party/python/gyp/pylib
++pth:third_party/python/idna
++pth:third_party/python/importlib_metadata
++pth:third_party/python/jsmin
++pth:third_party/python/json-e
++pth:third_party/python/mock-1.0.0
++pth:third_party/python/more-itertools
++pth:third_party/python/pathspec
++pth:third_party/python/pluggy
++pth:third_party/python/ply
++pth:third_party/python/py
++pth:third_party/python/pyasn1
++pth:third_party/python/pyasn1-modules
++pth:third_party/python/pylru
++pth:third_party/python/pystache
++pth:third_party/python/pytest/src
++pth:third_party/python/python-hglib
++pth:third_party/python/pytoml
++pth:third_party/python/PyYAML/lib3/
++pth:third_party/python/redo
++pth:third_party/python/requests
++pth:third_party/python/requests-unixsocket
++pth:third_party/python/responses
++pth:third_party/python/rsa
++pth:third_party/python/six
++pth:third_party/python/slugid
++pth:third_party/python/typing_extensions/src_py3
++pth:third_party/python/urllib3/src
++pth:third_party/python/voluptuous
++pth:third_party/python/yamllint
++pth:third_party/python/zipp
++pth:tools
++pth:tools/docs
++pth:xpcom/idl-parser
++pth:xpcom/typelib/xpt/tools
+diff --git a/build/mach_bootstrap.py b/build/mach_bootstrap.py
+--- a/build/mach_bootstrap.py
++++ b/build/mach_bootstrap.py
+@@ -118,17 +118,17 @@ def search_path(mozilla_dir, packages_tx
+     with open(os.path.join(mozilla_dir, packages_txt)) as f:
+         packages = [line.rstrip().split(":", maxsplit=1) for line in f]
+ 
+     def handle_package(action, package):
+         if action == "packages.txt":
+             for p in search_path(mozilla_dir, package):
+                 yield os.path.join(mozilla_dir, p)
+ 
+-        if action.endswith(".pth"):
++        if action == "pth":
+             yield os.path.join(mozilla_dir, package)
+ 
+     for current_action, current_package in packages:
+         for path in handle_package(current_action, current_package):
+             yield path
+ 
+ 
+ def mach_sys_path(mozilla_dir):
+diff --git a/python/mozbuild/mozbuild/test/test_vendor.py b/python/mozbuild/mozbuild/test/test_vendor.py
+--- a/python/mozbuild/mozbuild/test/test_vendor.py
++++ b/python/mozbuild/mozbuild/test/test_vendor.py
+@@ -24,17 +24,17 @@ def test_up_to_date_vendor():
+         # Create empty virtualenv_packages file
+         with open(
+             os.path.join(work_dir, "build", "build_virtualenv_packages.txt"), "a"
+         ) as file:
+             # Since VendorPython thinks "work_dir" is the topsrcdir,
+             # it will use its associated virtualenv and package configuration.
+             # Since it uses "pip-tools" within, and "pip-tools" needs
+             # the "Click" library, we need to make it available.
+-            file.write("mozilla.pth:third_party/python/Click")
++            file.write("pth:third_party/python/Click")
+ 
+         # Copy existing "third_party/python/" vendored files
+         existing_vendored = os.path.join(topsrcdir, "third_party", "python")
+         work_vendored = os.path.join(work_dir, "third_party", "python")
+         shutil.copytree(existing_vendored, work_vendored)
+ 
+         # Run the vendoring process
+         vendor = VendorPython(
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -274,17 +274,17 @@ class VirtualenvManager(VirtualenvHelper
+         action. The following actions are supported:
+ 
+         filename.pth -- Adds the path given as argument to filename.pth under
+             the virtualenv site packages directory.
+ 
+         thunderbird -- This denotes the action as to only occur for Thunderbird
+             checkouts. The initial "thunderbird" field is stripped, then the
+             remaining line is processed like normal. e.g.
+-            "thunderbird:comms.pth:python/foo"
++            "thunderbird:pth:python/foo"
+ 
+         packages.txt -- Denotes that the specified path is a child manifest. It
+             will be read and processed as if its contents were concatenated
+             into the manifest being read.
+ 
+         set-variable -- Set the given environment variable; e.g.
+             `set-variable FOO=1`.
+ 
+@@ -304,23 +304,23 @@ class VirtualenvManager(VirtualenvHelper
+         def handle_package(action, package):
+             if action == "packages.txt":
+                 src = os.path.join(self.topsrcdir, package)
+                 assert os.path.isfile(src), "'%s' does not exist" % src
+                 submanager = VirtualenvManager(
+                     self.topsrcdir, self.virtualenv_root, self.log_handle, src,
+                     populate_local_paths=self.populate_local_paths)
+                 submanager.populate()
+-            elif action.endswith(".pth"):
++            elif action == "pth":
+                 if not self.populate_local_paths:
+                     return
+ 
+                 path = os.path.join(self.topsrcdir, package)
+ 
+-                with open(os.path.join(python_lib, action), "a") as f:
++                with open(os.path.join(python_lib, "mach.pth"), "a") as f:
+                     # This path is relative to the .pth file.  Using a
+                     # relative path allows the srcdir/objdir combination
+                     # to be moved around (as long as the paths relative to
+                     # each other remain the same).
+                     f.write("%s\n" % os.path.relpath(path, python_lib))
+             elif action == "thunderbird":
+                 if is_thunderbird:
+                     handle_package(*package.split(":", maxsplit=1))
+diff --git a/testing/mozbase/packages.txt b/testing/mozbase/packages.txt
+--- a/testing/mozbase/packages.txt
++++ b/testing/mozbase/packages.txt
+@@ -1,18 +1,18 @@
+-manifestparser.pth:testing/mozbase/manifestparser
+-mozcrash.pth:testing/mozbase/mozcrash
+-mozdebug.pth:testing/mozbase/mozdebug
+-mozdevice.pth:testing/mozbase/mozdevice
+-mozfile.pth:testing/mozbase/mozfile
+-mozhttpd.pth:testing/mozbase/mozhttpd
+-mozinfo.pth:testing/mozbase/mozinfo
+-mozinstall.pth:testing/mozbase/mozinstall
+-mozleak.pth:testing/mozbase/mozleak
+-mozlog.pth:testing/mozbase/mozlog
+-moznetwork.pth:testing/mozbase/moznetwork
+-mozprocess.pth:testing/mozbase/mozprocess
+-mozprofile.pth:testing/mozbase/mozprofile
+-mozrunner.pth:testing/mozbase/mozrunner
+-mozsystemmonitor.pth:testing/mozbase/mozsystemmonitor
+-mozscreenshot.pth:testing/mozbase/mozscreenshot
+-moztest.pth:testing/mozbase/moztest
+-mozversion.pth:testing/mozbase/mozversion
++pth:testing/mozbase/manifestparser
++pth:testing/mozbase/mozcrash
++pth:testing/mozbase/mozdebug
++pth:testing/mozbase/mozdevice
++pth:testing/mozbase/mozfile
++pth:testing/mozbase/mozhttpd
++pth:testing/mozbase/mozinfo
++pth:testing/mozbase/mozinstall
++pth:testing/mozbase/mozleak
++pth:testing/mozbase/mozlog
++pth:testing/mozbase/moznetwork
++pth:testing/mozbase/mozprocess
++pth:testing/mozbase/mozprofile
++pth:testing/mozbase/mozrunner
++pth:testing/mozbase/mozsystemmonitor
++pth:testing/mozbase/mozscreenshot
++pth:testing/mozbase/moztest
++pth:testing/mozbase/mozversion

+ 105 - 0
mozilla-release/patches/1712133-09-91a1.patch

@@ -0,0 +1,105 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1623941897 0
+# Node ID 258461c837947dc1e93bed082868e2165b96f5b8
+# Parent  635ff76e684673d20359d2ca83a47078b6c104b4
+Bug 1712133: Inline `testing/mozbase/packages.txt` contents r=ahal
+
+The `mozbase` modules were being unconditionally added to the
+`sys.path` regardless of the Mach command being run, so there isn't
+much value keeping them in a separate file. Besides, all other
+source module paths are described in `common_virtualenv_packages`,
+why is `mozbase` special?
+
+In the future, we're going to want to make improvements here (such as:
+there's a difference between informing mach of first-party code
+versus defining which third_party vendored packages should be in scope,
+and that workflow difference should be represented in-code).
+It's useful to peel out the existing, less useful abstraction before
+we can build a stronger one.
+
+Differential Revision: https://phabricator.services.mozilla.com/D117711
+
+diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt
+--- a/build/common_virtualenv_packages.txt
++++ b/build/common_virtualenv_packages.txt
+@@ -14,17 +14,34 @@ pth:python/mozrelease
+ pth:python/mozterm
+ pth:python/mozversioncontrol
+ pth:testing
+ pth:testing/firefox-ui/harness
+ pth:testing/marionette/client
+ pth:testing/marionette/harness
+ pth:testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py
+ pth:testing/marionette/puppeteer/firefox
+-packages.txt:testing/mozbase/packages.txt
++pth:testing/mozbase/manifestparser
++pth:testing/mozbase/mozcrash
++pth:testing/mozbase/mozdebug
++pth:testing/mozbase/mozdevice
++pth:testing/mozbase/mozfile
++pth:testing/mozbase/mozhttpd
++pth:testing/mozbase/mozinfo
++pth:testing/mozbase/mozinstall
++pth:testing/mozbase/mozleak
++pth:testing/mozbase/mozlog
++pth:testing/mozbase/moznetwork
++pth:testing/mozbase/mozprocess
++pth:testing/mozbase/mozprofile
++pth:testing/mozbase/mozrunner
++pth:testing/mozbase/mozsystemmonitor
++pth:testing/mozbase/mozscreenshot
++pth:testing/mozbase/moztest
++pth:testing/mozbase/mozversion
+ pth:testing/talos
+ pth:testing/web-platform/tests/tools/six
+ pth:testing/web-platform/tests/tools/wptrunner
+ pth:testing/web-platform/tests/tools/wptserve
+ pth:testing/xpcshell
+ pth:third_party/python/appdirs
+ pth:third_party/python/atomicwrites
+ pth:third_party/python/attrs/src
+diff --git a/moz.configure b/moz.configure
+--- a/moz.configure
++++ b/moz.configure
+@@ -689,17 +689,16 @@ def config_status_deps(build_env, build_
+         os.path.join(topsrcdir, 'nsprpub', 'configure'),
+         os.path.join(topsrcdir, 'config', 'milestone.txt'),
+         os.path.join(topsrcdir, 'browser', 'config', 'version.txt'),
+         os.path.join(topsrcdir, 'browser', 'config', 'version_display.txt'),
+         os.path.join(topsrcdir, 'build', 'build_virtualenv_packages.txt'),
+         os.path.join(topsrcdir, 'build', 'common_virtualenv_packages.txt'),
+         os.path.join(topsrcdir, 'build', 'mach_virtualenv_packages.txt'),
+         os.path.join(topsrcdir, 'python', 'mozbuild', 'mozbuild', 'virtualenv.py'),
+-        os.path.join(topsrcdir, 'testing', 'mozbase', 'packages.txt'),
+         os.path.join(topsrcdir, 'aclocal.m4'),
+         os.path.join(topsrcdir, 'old-configure.in'),
+         os.path.join(topsrcdir, 'js', 'src', 'aclocal.m4'),
+         os.path.join(topsrcdir, 'js', 'src', 'old-configure.in'),
+     ] + glob.glob(os.path.join(topsrcdir, 'build', 'autoconf', '*.m4'))
+ 
+ set_config('CONFIG_STATUS_DEPS', config_status_deps)
+ # Please do not add anything after setting config_dep_paths.
+diff --git a/testing/mozbase/packages.txt b/testing/mozbase/packages.txt
+deleted file mode 100644
+--- a/testing/mozbase/packages.txt
++++ /dev/null
+@@ -1,18 +0,0 @@
+-pth:testing/mozbase/manifestparser
+-pth:testing/mozbase/mozcrash
+-pth:testing/mozbase/mozdebug
+-pth:testing/mozbase/mozdevice
+-pth:testing/mozbase/mozfile
+-pth:testing/mozbase/mozhttpd
+-pth:testing/mozbase/mozinfo
+-pth:testing/mozbase/mozinstall
+-pth:testing/mozbase/mozleak
+-pth:testing/mozbase/mozlog
+-pth:testing/mozbase/moznetwork
+-pth:testing/mozbase/mozprocess
+-pth:testing/mozbase/mozprofile
+-pth:testing/mozbase/mozrunner
+-pth:testing/mozbase/mozsystemmonitor
+-pth:testing/mozbase/mozscreenshot
+-pth:testing/mozbase/moztest
+-pth:testing/mozbase/mozversion

+ 57 - 0
mozilla-release/patches/1712133-10-91a1.patch

@@ -0,0 +1,57 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1623941897 0
+# Node ID 6a5c661cafe7370598c87872930f6cfde182a2a5
+# Parent  c69363cc6067f9acbf3721e12bb079bd9a8b2513
+Bug 1712133: Adds "pypi" action to virtualenv `handle_package()` r=ahal
+
+The `pypi` action uses `pip` to fetch a package and its dependencies
+
+Differential Revision: https://phabricator.services.mozilla.com/D115925
+
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -271,16 +271,18 @@ class VirtualenvManager(VirtualenvHelper
+ 
+         The manifest file consists of colon-delimited fields. The first field
+         specifies the action. The remaining fields are arguments to that
+         action. The following actions are supported:
+ 
+         filename.pth -- Adds the path given as argument to filename.pth under
+             the virtualenv site packages directory.
+ 
++        pypi -- Fetch the package, plus dependencies, from PyPI.
++
+         thunderbird -- This denotes the action as to only occur for Thunderbird
+             checkouts. The initial "thunderbird" field is stripped, then the
+             remaining line is processed like normal. e.g.
+             "thunderbird:pth:python/foo"
+ 
+         packages.txt -- Denotes that the specified path is a child manifest. It
+             will be read and processed as if its contents were concatenated
+             into the manifest being read.
+@@ -319,16 +321,23 @@ class VirtualenvManager(VirtualenvHelper
+                     # This path is relative to the .pth file.  Using a
+                     # relative path allows the srcdir/objdir combination
+                     # to be moved around (as long as the paths relative to
+                     # each other remain the same).
+                     f.write("%s\n" % os.path.relpath(path, python_lib))
+             elif action == "thunderbird":
+                 if is_thunderbird:
+                     handle_package(*package.split(":", maxsplit=1))
++            elif action == "pypi":
++                if len(package.split("==")) != 2:
++                    raise Exception(
++                        "Expected pypi package version to be pinned in the "
++                        'format "package==version", found "{}"'.format(package)
++                    )
++                self.install_pip_package(package)
+             else:
+                 raise Exception("Unknown action: %s" % action)
+ 
+         # We always target the OS X deployment target that Python itself was
+         # built with, regardless of what's in the current environment. If we
+         # don't do # this, we may run into a Python bug. See
+         # http://bugs.python.org/issue9516 and bug 659881.
+         #

+ 148 - 0
mozilla-release/patches/1712133-11-91a1.patch

@@ -0,0 +1,148 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1623941897 0
+# Node ID 06df3dc28c5874d22eefd375bd270aa649794861
+# Parent  54191dca4667a7ea687a4751cb86dc1494be5a1e
+Bug 1712133: Validate that pypi dependencies are installed r=ahal
+
+Check that all expected pypi packages are installed
+when checking if a virtualenv is up-to-date.
+
+Differential Revision: https://phabricator.services.mozilla.com/D117712
+
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -3,16 +3,17 @@
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ # This file contains code for populating the virtualenv environment for
+ # Mozilla's build system. It is typically called as part of configure.
+ 
+ from __future__ import absolute_import, print_function, unicode_literals
+ 
+ import argparse
++import json
+ import os
+ import platform
+ import shutil
+ import subprocess
+ import sys
+ 
+ 
+ IS_NATIVE_WIN = (sys.platform == 'win32' and os.sep == '\\')
+@@ -181,19 +182,34 @@ class VirtualenvManager(VirtualenvHelper
+         # python, or we have the Python version that was used to create the
+         # virtualenv. If this fails, it is likely system Python has been
+         # upgraded, and our virtualenv would not be usable.
+         orig_version = self.get_exe_info()
+         hexversion = self.python_executable_hexversion(python)
+         if (python != self.python_path) and (hexversion != orig_version):
+             return False
+ 
++        packages = self.packages()
++        pypi_packages = [package for action, package in packages if action == "pypi"]
++        if pypi_packages:
++            pip_json = self._run_pip(
++                ["list", "--format", "json"], capture_output=True
++            ).stdout
++            installed_packages = json.loads(pip_json)
++            installed_packages = {
++                package["name"]: package["version"] for package in installed_packages
++            }
++            for pypi_package in pypi_packages:
++                name, version = pypi_package.split("==")
++                if installed_packages.get(name, None) != version:
++                    return False
++
+         # recursively check sub packages.txt files
+         submanifests = [
+-            package for action, package in self.packages() if action == "packages.txt"
++            package for action, package in packages if action == "packages.txt"
+         ]
+         for submanifest in submanifests:
+             submanifest = os.path.join(self.topsrcdir, submanifest)
+             submanager = VirtualenvManager(self.topsrcdir,
+                                            self.virtualenv_root,
+                                            self.log_handle,
+                                            submanifest)
+             if not submanager.up_to_date(python):
+@@ -497,17 +513,17 @@ class VirtualenvManager(VirtualenvHelper
+                 # setup_requires directive for the package. Since we're manually
+                 # controlling our build environment, build isolation isn't a
+                 # concern and we can disable that feature. Note that this is
+                 # safe and doesn't risk trampling any other packages that may be
+                 # installed due to passing `--no-deps --no-index` as well.
+                 '--no-build-isolation',
+             ])
+ 
+-        return self._run_pip(args)
++        return self._run_pip(args, stderr=subprocess.STDOUT)
+ 
+     def install_pip_requirements(
+         self, path, require_hashes=True, quiet=False, vendored=False
+     ):
+         """Install a pip requirements.txt file.
+ 
+         The supplied path is a text file containing pip requirement
+         specifiers.
+@@ -526,17 +542,17 @@ class VirtualenvManager(VirtualenvHelper
+             args.append('--require-hashes')
+ 
+         if quiet:
+             args.append('--quiet')
+ 
+         if vendored:
+             args.extend(["--no-deps", "--no-index"])
+ 
+-        return self._run_pip(args)
++        return self._run_pip(args, stderr=subprocess.STDOUT)
+ 
+     def _disable_pip_outdated_warning(self):
+         """Disables the pip outdated warning by changing pip's 'installer'
+ 
+         "pip" has behaviour to ensure that it doesn't print it's "outdated"
+         warning if it's part of a Linux distro package. This is because
+         Linux distros generally have a slightly out-of-date pip package
+         that they know to be stable, and users aren't always able to
+@@ -577,35 +593,33 @@ class VirtualenvManager(VirtualenvHelper
+             None,
+         )
+         if not pip_dist_info:
+             raise Exception("Failed to find pip dist-info in new virtualenv")
+ 
+         with open(os.path.join(site_packages, pip_dist_info, "INSTALLER"), "w") as file:
+             file.write("mach")
+ 
+-    def _run_pip(self, args):
++    def _run_pip(self, args, **kwargs):
++        kwargs.setdefault("check", True)
++
+         env = os.environ.copy()
+         env.setdefault("ARCHFLAGS", get_archflags())
+         env = ensure_subprocess_env(env)
+ 
+         # It's tempting to call pip natively via pip.main(). However,
+         # the current Python interpreter may not be the virtualenv python.
+         # This will confuse pip and cause the package to attempt to install
+         # against the executing interpreter. By creating a new process, we
+         # force the virtualenv's interpreter to be used and all is well.
+         # It /might/ be possible to cheat and set sys.executable to
+         # self.python_path. However, this seems more risk than it's worth.
+         pip = os.path.join(self.bin_path, 'pip')
+-        subprocess.check_call(
+-            [pip] + args,
+-            stderr=subprocess.STDOUT,
+-            cwd=self.topsrcdir,
+-            env=env,
+-            universal_newlines=True,
++        return subprocess.run(
++            [pip] + args, cwd=self.topsrcdir, env=env, universal_newlines=True, **kwargs
+         )
+ 
+ 
+ def get_archflags():
+     # distutils will use the architecture of the running Python instance when building packages.
+     # However, it's possible for the Xcode Python to be a universal binary (x86_64 and
+     # arm64) without the associated macOS SDK supporting arm64, thereby causing a build
+     # failure. To avoid this, we explicitly influence the build to only target a single

+ 69 - 69
mozilla-release/patches/1713377-PARTIAL-91a1.patch

@@ -2,7 +2,7 @@
 # User Mitchell Hentges <mhentges@mozilla.com>
 # Date 1623858796 0
 # Node ID 1537ac197686ec43a21608fb60a89123411255d2
-# Parent  8bae702a8d3201b01839460be6461ef57a21705f
+# Parent  3f6b2c4e9b163208da7e369a2acac04824f29098
 Bug 1713377: Change vendoring to use wheels where possible r=ahal,glandium
 
 Vendoring wheels has three benefits:
@@ -44,72 +44,72 @@ Differential Revision: https://phabricator.services.mozilla.com/D116512
 diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt
 --- a/build/common_virtualenv_packages.txt
 +++ b/build/common_virtualenv_packages.txt
-@@ -22,57 +22,58 @@ mozilla.pth:testing/marionette/puppeteer
- packages.txt:testing/mozbase/packages.txt
- mozilla.pth:testing/talos
- mozilla.pth:testing/web-platform/tests/tools/six
- mozilla.pth:testing/web-platform/tests/tools/wptrunner
- mozilla.pth:testing/web-platform/tests/tools/wptserve
- mozilla.pth:testing/xpcshell
- mozilla.pth:third_party/python/appdirs
- mozilla.pth:third_party/python/atomicwrites
--mozilla.pth:third_party/python/attrs/src
-+mozilla.pth:third_party/python/attrs
- mozilla.pth:third_party/python/blessings
- mozilla.pth:third_party/python/cbor2
- mozilla.pth:third_party/python/chardet
- mozilla.pth:third_party/python/Click
--mozilla.pth:third_party/python/compare-locales
-+mozilla.pth:third_party/python/certifi
-+mozilla.pth:third_party/python/compare_locales
- mozilla.pth:third_party/python/cookies
- mozilla.pth:third_party/python/cram
- mozilla.pth:third_party/python/distro
- mozilla.pth:third_party/python/dlmanager
--mozilla.pth:third_party/python/ecdsa/src
-+mozilla.pth:third_party/python/ecdsa
- mozilla.pth:third_party/python/fluent.migrate
- mozilla.pth:third_party/python/fluent.syntax
- mozilla.pth:third_party/python/funcsigs
- mozilla.pth:third_party/python/gyp/pylib
- mozilla.pth:third_party/python/idna
- mozilla.pth:third_party/python/importlib_metadata
- mozilla.pth:third_party/python/jsmin
- mozilla.pth:third_party/python/json-e
- mozilla.pth:third_party/python/mock-1.0.0
--mozilla.pth:third_party/python/more-itertools
-+mozilla.pth:third_party/python/more_itertools
- mozilla.pth:third_party/python/pathspec
- mozilla.pth:third_party/python/pluggy
- mozilla.pth:third_party/python/ply
- mozilla.pth:third_party/python/py
- mozilla.pth:third_party/python/pyasn1
- mozilla.pth:third_party/python/pyasn1-modules
- mozilla.pth:third_party/python/pylru
- mozilla.pth:third_party/python/pystache
--mozilla.pth:third_party/python/pytest/src
-+mozilla.pth:third_party/python/pytest
- mozilla.pth:third_party/python/python-hglib
- mozilla.pth:third_party/python/pytoml
- mozilla.pth:third_party/python/PyYAML/lib3/
- mozilla.pth:third_party/python/redo
- mozilla.pth:third_party/python/requests
- mozilla.pth:third_party/python/requests-unixsocket
- mozilla.pth:third_party/python/responses
- mozilla.pth:third_party/python/rsa
- mozilla.pth:third_party/python/six
- mozilla.pth:third_party/python/slugid
--mozilla.pth:third_party/python/typing_extensions/src_py3
--mozilla.pth:third_party/python/urllib3/src
-+mozilla.pth:third_party/python/typing_extensions
-+mozilla.pth:third_party/python/urllib3
- mozilla.pth:third_party/python/voluptuous
- mozilla.pth:third_party/python/yamllint
- mozilla.pth:third_party/python/zipp
- mozilla.pth:tools
- mozilla.pth:tools/docs
- mozilla.pth:xpcom/idl-parser
- mozilla.pth:xpcom/typelib/xpt/tools
+@@ -39,57 +39,58 @@ pth:testing/mozbase/moztest
+ pth:testing/mozbase/mozversion
+ pth:testing/talos
+ pth:testing/web-platform/tests/tools/six
+ pth:testing/web-platform/tests/tools/wptrunner
+ pth:testing/web-platform/tests/tools/wptserve
+ pth:testing/xpcshell
+ pth:third_party/python/appdirs
+ pth:third_party/python/atomicwrites
+-pth:third_party/python/attrs/src
++pth:third_party/python/attrs
+ pth:third_party/python/blessings
+ pth:third_party/python/cbor2
+ pth:third_party/python/chardet
+ pth:third_party/python/Click
+-pth:third_party/python/compare-locales
++pth:third_party/python/certifi
++pth:third_party/python/compare_locales
+ pth:third_party/python/cookies
+ pth:third_party/python/cram
+ pth:third_party/python/distro
+ pth:third_party/python/dlmanager
+-pth:third_party/python/ecdsa/src
++pth:third_party/python/ecdsa
+ pth:third_party/python/fluent.migrate
+ pth:third_party/python/fluent.syntax
+ pth:third_party/python/funcsigs
+ pth:third_party/python/gyp/pylib
+ pth:third_party/python/idna
+ pth:third_party/python/importlib_metadata
+ pth:third_party/python/jsmin
+ pth:third_party/python/json-e
+ pth:third_party/python/mock-1.0.0
+-pth:third_party/python/more-itertools
++pth:third_party/python/more_itertools
+ pth:third_party/python/pathspec
+ pth:third_party/python/pluggy
+ pth:third_party/python/ply
+ pth:third_party/python/py
+ pth:third_party/python/pyasn1
+ pth:third_party/python/pyasn1-modules
+ pth:third_party/python/pylru
+ pth:third_party/python/pystache
+-pth:third_party/python/pytest/src
++pth:third_party/python/pytest
+ pth:third_party/python/python-hglib
+ pth:third_party/python/pytoml
+ pth:third_party/python/PyYAML/lib3/
+ pth:third_party/python/redo
+ pth:third_party/python/requests
+ pth:third_party/python/requests-unixsocket
+ pth:third_party/python/responses
+ pth:third_party/python/rsa
+ pth:third_party/python/six
+ pth:third_party/python/slugid
+-pth:third_party/python/typing_extensions/src_py3
+-pth:third_party/python/urllib3/src
++pth:third_party/python/typing_extensions
++pth:third_party/python/urllib3
+ pth:third_party/python/voluptuous
+ pth:third_party/python/yamllint
+ pth:third_party/python/zipp
+ pth:tools
+ pth:tools/docs
+ pth:xpcom/idl-parser
+ pth:xpcom/typelib/xpt/tools
 diff --git a/python/mozbuild/mozbuild/vendor/vendor_python.py b/python/mozbuild/mozbuild/vendor/vendor_python.py
 --- a/python/mozbuild/mozbuild/vendor/vendor_python.py
 +++ b/python/mozbuild/mozbuild/vendor/vendor_python.py
@@ -232,7 +232,7 @@ diff --git a/python/mozbuild/mozbuild/vendor/vendor_python.py b/python/mozbuild/
 diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
 --- a/python/mozbuild/mozbuild/virtualenv.py
 +++ b/python/mozbuild/mozbuild/virtualenv.py
-@@ -527,45 +527,64 @@ class VirtualenvManager(VirtualenvHelper
+@@ -485,45 +485,64 @@ class VirtualenvManager(VirtualenvHelper
          The supplied package is specified using a pip requirement specifier.
          e.g. 'foo' or 'foo==1.0'.
  
@@ -277,7 +277,7 @@ diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/v
 +                (d for d in os.listdir(package) if d.endswith(".dist-info")), None
 +            )
  
--        return self._run_pip(args)
+-        return self._run_pip(args, stderr=subprocess.STDOUT)
 +        with TemporaryDirectory() as tmp:
 +            if vendored_dist_info_dir:
 +                # This is a vendored wheel. We have to re-pack it in order for pip

+ 95 - 0
mozilla-release/patches/1714688-4-91a1.patch

@@ -0,0 +1,95 @@
+# HG changeset patch
+# User surajeet310 <surajeet310@gmail.com>
+# Date 1623703291 0
+# Node ID 8c07e39f8dbdb3e07da5994cc7b884d2559b9776
+# Parent  c4e02cbabd999bc47fa0dd79368249a10d461844
+Bug 1714688 - Removed 'if PY2' logic from python/mozrelease r=mhentges
+
+Python2 is no longer used in Mozrelease
+
+Differential Revision: https://phabricator.services.mozilla.com/D117583
+
+diff --git a/python/mozrelease/mozrelease/versions.py b/python/mozrelease/mozrelease/versions.py
+--- a/python/mozrelease/mozrelease/versions.py
++++ b/python/mozrelease/mozrelease/versions.py
+@@ -1,27 +1,16 @@
+ # 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/.
+ 
+ from __future__ import absolute_import
+ 
+ from distutils.version import StrictVersion, LooseVersion
+ import re
+-from six import PY2
+-
+-
+-def _cmp(cls, first, other):
+-    # Because the __cmp__ metamethod was removed in the switch to Python 3, the
+-    # interface of the distutils.version.*Version classes changed in a
+-    # backwards-incompatible way. Call this instead of first.__cmp__(other) or
+-    # first._cmp(other) to handle both possibilities.
+-    if PY2:
+-        return cls.__cmp__(first, other)
+-    return cls._cmp(first, other)
+ 
+ 
+ class MozillaVersionCompareMixin():
+     def __cmp__(self, other):
+         # We expect this function to never be called.
+         raise AssertionError()
+ 
+     def _cmp(self, other):
+@@ -35,50 +24,34 @@ class MozillaVersionCompareMixin():
+             # If our version ends with esr, coerce through MozillaVersion ending up with
+             # a StrictVersion if possible
+             has_esr.add('self')
+             self = MozillaVersion(str(self)[:-3])  # strip ESR from end of string
+         if isinstance(other, LooseModernMozillaVersion) or \
+                 isinstance(self, LooseModernMozillaVersion):
+             # If we're still LooseVersion for self or other, run LooseVersion compare
+             # Being sure to pass through Loose Version type first
+-            val = _cmp(LooseVersion,
++            val = LooseVersion._cmp(
+                        LooseModernMozillaVersion(str(self)),
+                        LooseModernMozillaVersion(str(other)))
+         else:
+             # No versions are loose, therefore we can use StrictVersion
+-            val = _cmp(StrictVersion, self, other)
++            val = StrictVersion._cmp(self, other)
+         if has_esr.isdisjoint(set(['other', 'self'])) or \
+                 has_esr.issuperset(set(['other', 'self'])):
+             #  If both had esr string or neither, then _cmp() was accurate
+             return val
+         elif val != 0:
+             # cmp is accurate here even if esr is present in only 1 compare, since
+             # versions are not equal
+             return val
+         elif 'other' in has_esr:
+             return -1  # esr is not greater than non esr
+         return 1  # non esr is greater than esr
+ 
+-    # These method definitions can be deleted when we drop support for Python 2.
+-    def __eq__(self, other):
+-        return self._cmp(other) == 0
+-
+-    def __lt__(self, other):
+-        return self._cmp(other) < 0
+-
+-    def __le__(self, other):
+-        return self._cmp(other) <= 0
+-
+-    def __gt__(self, other):
+-        return self._cmp(other) > 0
+-
+-    def __ge__(self, other):
+-        return self._cmp(other) >= 0
+-
+ 
+ class ModernMozillaVersion(MozillaVersionCompareMixin, StrictVersion):
+     """A version class that is slightly less restrictive than StrictVersion.
+        Instead of just allowing "a" or "b" as prerelease tags, it allows any
+        alpha. This allows us to support the once-shipped "3.6.3plugin1" and
+        similar versions."""
+     version_re = re.compile(r"""^(\d+) \. (\d+) (\. (\d+))?
+                                 ([a-zA-Z]+(\d+))?$""", re.VERBOSE)

+ 210 - 0
mozilla-release/patches/1714688-5-91a1.patch

@@ -0,0 +1,210 @@
+# HG changeset patch
+# User surajeet310 <surajeet310@gmail.com>
+# Date 1623785481 0
+# Node ID ceac5a7590dec4e48e30dd307d2d7f79c8c8a85b
+# Parent  af58157fcaa607307a41bbdc9c6d557b1625a672
+Bug 1714688 - Removed 'if PY2'/'if PY3' logic from python/mozbuild r=mhentges
+
+Python2 is no longer used in Mozbuild.
+
+Differential Revision: https://phabricator.services.mozilla.com/D117561
+
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -13,19 +13,16 @@ import platform
+ import shutil
+ import subprocess
+ import sys
+ 
+ 
+ IS_NATIVE_WIN = (sys.platform == 'win32' and os.sep == '\\')
+ IS_CYGWIN = (sys.platform == 'cygwin')
+ 
+-PY2 = sys.version_info[0] == 2
+-PY3 = sys.version_info[0] == 3
+-
+ UPGRADE_WINDOWS = '''
+ Please upgrade to the latest MozillaBuild development environment. See
+ https://developer.mozilla.org/en-US/docs/Developer_Guide/Build_Instructions/Windows_Prerequisites
+ '''.lstrip()
+ 
+ UPGRADE_OTHER = '''
+ Run |mach bootstrap| to ensure your system is up to date.
+ 
+@@ -35,37 +32,31 @@ defined by the $PATH environment variabl
+ '''.lstrip()
+ 
+ here = os.path.abspath(os.path.dirname(__file__))
+ 
+ 
+ # We can't import six.ensure_binary() or six.ensure_text() because this module
+ # has to run stand-alone.  Instead we'll implement an abbreviated version of the
+ # checks it does.
+-if PY3:
+-    text_type = str
+-    binary_type = bytes
+-else:
+-    text_type = unicode
+-    binary_type = str
+ 
+ 
+ def ensure_binary(s, encoding='utf-8'):
+-    if isinstance(s, text_type):
++    if isinstance(s, str):
+         return s.encode(encoding, errors='strict')
+-    elif isinstance(s, binary_type):
++    elif isinstance(s, bytes):
+         return s
+     else:
+         raise TypeError("not expecting type '%s'" % type(s))
+ 
+ 
+ def ensure_text(s, encoding='utf-8'):
+-    if isinstance(s, binary_type):
++    if isinstance(s, bytes):
+         return s.decode(encoding, errors='strict')
+-    elif isinstance(s, text_type):
++    elif isinstance(s, str):
+         return s
+     else:
+         raise TypeError("not expecting type '%s'" % type(s))
+ 
+ 
+ class VirtualenvHelper(object):
+     """Contains basic logic for getting information about virtualenvs."""
+ 
+@@ -231,20 +222,17 @@ class VirtualenvManager(VirtualenvHelper
+         if hasattr(self.log_handle, 'fileno'):
+             return subprocess.call(*args, stdout=self.log_handle,
+                                    stderr=subprocess.STDOUT, **kwargs)
+ 
+         proc = subprocess.Popen(*args, stdout=subprocess.PIPE,
+                                 stderr=subprocess.STDOUT, **kwargs)
+ 
+         for line in proc.stdout:
+-            if PY2:
+-                self.log_handle.write(line)
+-            else:
+-                self.log_handle.write(line.decode('UTF-8'))
++            self.log_handle.write(line.decode("UTF-8"))
+ 
+         return proc.wait()
+ 
+     def create(self, python):
+         """Create a new, empty virtualenv.
+ 
+         Receives the path to virtualenv's virtualenv.py script (which will be
+         called out to), the path to create the virtualenv in, and a handle to
+@@ -269,23 +257,22 @@ class VirtualenvManager(VirtualenvHelper
+                     self.virtualenv_root, result))
+ 
+         self.write_exe_info(python)
+         self._disable_pip_outdated_warning()
+ 
+         return self.virtualenv_root
+ 
+     def packages(self):
+-        mode = 'rU' if PY2 else 'r'
+-        with open(self.manifest_path, mode) as fh:
++        with open(self.manifest_path, "r") as fh:
+             packages = [line.rstrip().split(':')
+                         for line in fh]
+         return packages
+ 
+-    def populate(self, ignore_sitecustomize=False):
++    def populate(self):
+         """Populate the virtualenv.
+ 
+         The manifest file consists of colon-delimited fields. The first field
+         specifies the action. The remaining fields are arguments to that
+         action. The following actions are supported:
+ 
+         filename.pth -- Adds the path given as argument to filename.pth under
+             the virtualenv site packages directory.
+@@ -326,17 +313,17 @@ class VirtualenvManager(VirtualenvHelper
+             if package[0] == 'packages.txt':
+                 assert len(package) == 2
+ 
+                 src = os.path.join(self.topsrcdir, package[1])
+                 assert os.path.isfile(src), "'%s' does not exist" % src
+                 submanager = VirtualenvManager(
+                     self.topsrcdir, self.virtualenv_root, self.log_handle, src,
+                     populate_local_paths=self.populate_local_paths)
+-                submanager.populate(ignore_sitecustomize=True)
++                submanager.populate()
+             elif package[0].endswith(".pth"):
+                 assert len(package) == 2
+ 
+                 if not self.populate_local_paths:
+                     return
+ 
+                 path = os.path.join(self.topsrcdir, package[1])
+ 
+@@ -392,28 +379,16 @@ class VirtualenvManager(VirtualenvHelper
+ 
+                 old_env_variables[k] = os.environ[k]
+                 del os.environ[k]
+ 
+             for package in packages:
+                 handle_package(package)
+ 
+         finally:
+-            # This hack isn't necessary for Python 3, or for the
+-            # out-of-objdir virtualenvs.
+-            if PY2 and self.populate_local_paths and not ignore_sitecustomize:
+-                with open(
+-                    os.path.join(os.path.dirname(python_lib), "sitecustomize.py"),
+-                    mode="w",
+-                ) as sitecustomize:
+-                    sitecustomize.write(
+-                        '# Importing mach_bootstrap has the side effect of\n'
+-                        '# installing an import hook\n'
+-                        'import mach_bootstrap\n')
+-
+             os.environ.pop('MACOSX_DEPLOYMENT_TARGET', None)
+ 
+             if old_target is not None:
+                 os.environ['MACOSX_DEPLOYMENT_TARGET'] = old_target
+ 
+             os.environ.update(old_env_variables)
+ 
+     def call_setup(self, directory, arguments):
+@@ -628,17 +603,17 @@ class VirtualenvManager(VirtualenvHelper
+         # It /might/ be possible to cheat and set sys.executable to
+         # self.python_path. However, this seems more risk than it's worth.
+         pip = os.path.join(self.bin_path, 'pip')
+         subprocess.check_call(
+             [pip] + args,
+             stderr=subprocess.STDOUT,
+             cwd=self.topsrcdir,
+             env=env,
+-            universal_newlines=PY3
++            universal_newlines=True,
+         )
+ 
+ 
+ def get_archflags():
+     # distutils will use the architecture of the running Python instance when building packages.
+     # However, it's possible for the Xcode Python to be a universal binary (x86_64 and
+     # arm64) without the associated macOS SDK supporting arm64, thereby causing a build
+     # failure. To avoid this, we explicitly influence the build to only target a single
+@@ -679,17 +654,17 @@ def ensure_subprocess_env(env, encoding=
+     This will convert all keys and values to bytes on Python 2, and text on
+     Python 3.
+ 
+     Args:
+         env (dict): Environment to ensure.
+         encoding (str): Encoding to use when converting to/from bytes/text
+                         (default: utf-8).
+     """
+-    ensure = ensure_binary if PY2 else ensure_text
++    ensure = ensure_text
+ 
+     try:
+         return {
+             ensure(k, encoding=encoding): ensure(v, encoding=encoding)
+             for k, v in env.iteritems()
+         }
+     except AttributeError:
+         return {

+ 350 - 0
mozilla-release/patches/1717645-1-92a1.patch

@@ -0,0 +1,350 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1628176457 0
+# Node ID 13d016bcc12c88f99dbd2a974a6011dbe94d09cc
+# Parent  d902b0ca43e8d2a394b11f01fdd32fb74dde95d6
+Bug 1717645: Resolve nested virtualenv requirements up-front r=ahal
+
+This simplifies consumer logic, since they get the parsed list of pypi
+and pth requirements, as well as the list of input files that were
+parsed.
+
+One benefit of this simplification is that we no longer
+recursively create VirtualenvManagers.
+
+Note that mach_bootstrap cannot (yet) take advantage
+of `ParseMachEnvRequirements` because of a dependency cycle:
+* `mach_bootstrap` must set up the `sys.path` to import
+  `ParseMachEnvRequirements`.
+* `mach_bootstrap` would want `ParseMachEnvRequirements` to
+  determine which paths to add to the `sys.path`.
+
+Differential Revision: https://phabricator.services.mozilla.com/D119685
+
+diff --git a/python/mozbuild/mozbuild/requirements.py b/python/mozbuild/mozbuild/requirements.py
+new file mode 100644
+--- /dev/null
++++ b/python/mozbuild/mozbuild/requirements.py
+@@ -0,0 +1,96 @@
++# 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
++
++
++class PthSpecifier:
++    def __init__(self, path):
++        self.path = path
++
++
++class PypiSpecifier:
++    def __init__(self, package_name, version, full_specifier):
++        self.package_name = package_name
++        self.version = version
++        self.full_specifier = full_specifier
++
++
++class MachEnvRequirements:
++    """Requirements associated with a "virtualenv_packages.txt" definition
++
++    Represents the dependencies of a virtualenv. The source files consist
++    of colon-delimited fields. The first field
++    specifies the action. The remaining fields are arguments to that
++    action. The following actions are supported:
++
++    pth -- Adds the path given as argument to "mach.pth" under
++        the virtualenv site packages directory.
++
++    pypi -- Fetch the package, plus dependencies, from PyPI.
++
++    packages.txt -- Denotes that the specified path is a child manifest. It
++        will be read and processed as if its contents were concatenated
++        into the manifest being read.
++
++    thunderbird -- This denotes the action as to only occur for Thunderbird
++        checkouts. The initial "thunderbird" field is stripped, then the
++        remaining line is processed like normal. e.g.
++        "thunderbird:pth:python/foo"
++    """
++
++    def __init__(self):
++        self.requirements_paths = []
++        self.pth_requirements = []
++        self.pypi_requirements = []
++
++    @classmethod
++    def from_requirements_definition(
++        cls, topsrcdir, is_thunderbird, requirements_definition
++    ):
++        requirements = cls()
++        _parse_mach_env_requirements(
++            requirements, requirements_definition, topsrcdir, is_thunderbird
++        )
++        return requirements
++
++
++def _parse_mach_env_requirements(
++    requirements_output, root_requirements_path, topsrcdir, is_thunderbird
++):
++    def _parse_requirements_line(line):
++        action, params = line.rstrip().split(":", maxsplit=1)
++        if action == "pth":
++            requirements_output.pth_requirements.append(PthSpecifier(params))
++        elif action == "pypi":
++            if len(params.split("==")) != 2:
++                raise Exception(
++                    "Expected pypi package version to be pinned in the "
++                    'format "package==version", found "{}"'.format(params)
++                )
++            package_name, version = params.split("==")
++            requirements_output.pypi_requirements.append(
++                PypiSpecifier(package_name, version, params)
++            )
++        elif action == "packages.txt":
++            nested_definition_path = os.path.join(topsrcdir, params)
++            assert os.path.isfile(nested_definition_path)
++            _parse_requirements_definition_file(nested_definition_path)
++        elif action == "thunderbird":
++            if is_thunderbird:
++                _parse_requirements_line(params)
++        else:
++            raise Exception("Unknown requirements definition action: %s" % action)
++
++    def _parse_requirements_definition_file(requirements_path):
++        """Parse requirements file into list of requirements"""
++        requirements_output.requirements_paths.append(requirements_path)
++
++        with open(requirements_path, "r") as requirements_file:
++            lines = [line for line in requirements_file]
++
++        for line in lines:
++            _parse_requirements_line(line)
++
++    _parse_requirements_definition_file(root_requirements_path)
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -159,67 +159,55 @@ class VirtualenvManager(VirtualenvHelper
+ 
+         Args:
+             python: Full path string to the Python executable that this virtualenv
+                 should be running.  If the Python executable passed in to this
+                 argument is not the same version as the Python the virtualenv was
+                 built with then this method will return False.
+         """
+ 
+-        deps = [self.manifest_path, __file__]
+-
+         # check if virtualenv exists
+         if not os.path.exists(self.virtualenv_root) or \
+                 not os.path.exists(self.activate_path):
+             return False
+ 
++        env_requirements = self._requirements()
++        deps = [__file__] + env_requirements.requirements_paths
++
+         # Modifications to our package dependency list or to this file mean the
+         # virtualenv should be rebuilt.
+         activate_mtime = os.path.getmtime(self.activate_path)
+         dep_mtime = max(os.path.getmtime(p) for p in deps)
+         if dep_mtime > activate_mtime:
+             return False
+ 
+         # Verify that the Python we're checking here is either the virutalenv
+         # python, or we have the Python version that was used to create the
+         # virtualenv. If this fails, it is likely system Python has been
+         # upgraded, and our virtualenv would not be usable.
+         orig_version = self.get_exe_info()
+         hexversion = self.python_executable_hexversion(python)
+         if (python != self.python_path) and (hexversion != orig_version):
+             return False
+ 
+-        packages = self.packages()
+-        pypi_packages = [package for action, package in packages if action == "pypi"]
+-        if pypi_packages:
++        if env_requirements.pypi_requirements:
+             pip_json = self._run_pip(
+                 ["list", "--format", "json"], capture_output=True
+             ).stdout
+             installed_packages = json.loads(pip_json)
+             installed_packages = {
+                 package["name"]: package["version"] for package in installed_packages
+             }
+-            for pypi_package in pypi_packages:
+-                name, version = pypi_package.split("==")
+-                if installed_packages.get(name, None) != version:
++            for requirement in env_requirements.pypi_requirements:
++                if (
++                    installed_packages.get(requirement.package_name, None)
++                    != requirement.version
++                ):
+                     return False
+ 
+-        # recursively check sub packages.txt files
+-        submanifests = [
+-            package for action, package in packages if action == "packages.txt"
+-        ]
+-        for submanifest in submanifests:
+-            submanifest = os.path.join(self.topsrcdir, submanifest)
+-            submanager = VirtualenvManager(self.topsrcdir,
+-                                           self.virtualenv_root,
+-                                           self.log_handle,
+-                                           submanifest)
+-            if not submanager.up_to_date(python):
+-                return False
+-
+         return True
+ 
+     def ensure(self, python=sys.executable):
+         """Ensure the virtualenv is present and up to date.
+ 
+         If the virtualenv is up to date, this does nothing. Otherwise, it
+         creates and populates the virtualenv as necessary.
+ 
+@@ -273,93 +261,48 @@ class VirtualenvManager(VirtualenvHelper
+                 'Failed to create virtualenv: %s (virtualenv.py retcode: %s)' % (
+                     self.virtualenv_root, result))
+ 
+         self.write_exe_info(python)
+         self._disable_pip_outdated_warning()
+ 
+         return self.virtualenv_root
+ 
+-    def packages(self):
+-        with open(self.manifest_path, "r") as fh:
+-            return [line.rstrip().split(":", maxsplit=1) for line in fh]
++    def _requirements(self):
++        try:
++            # When `virtualenv.py` is invoked from an existing Mach process,
++            # import MachEnvRequirements in the expected way.
++            from mozbuild.requirements import MachEnvRequirements
++        except ImportError:
++            # When `virtualenv.py` is invoked standalone, import
++            # MachEnvRequirements from the adjacent "standalone"
++            # requirements module.
++            from requirements import MachEnvRequirements
++
++        thunderbird_dir = os.path.join(self.topsrcdir, "comm")
++        is_thunderbird = os.path.exists(thunderbird_dir) and bool(
++            os.listdir(thunderbird_dir)
++        )
++        return MachEnvRequirements.from_requirements_definition(
++            self.topsrcdir, is_thunderbird, self.manifest_path
++        )
+ 
+     def populate(self):
+         """Populate the virtualenv.
+ 
+-        The manifest file consists of colon-delimited fields. The first field
+-        specifies the action. The remaining fields are arguments to that
+-        action. The following actions are supported:
+-
+-        filename.pth -- Adds the path given as argument to filename.pth under
+-            the virtualenv site packages directory.
+-
+-        pypi -- Fetch the package, plus dependencies, from PyPI.
+-
+-        thunderbird -- This denotes the action as to only occur for Thunderbird
+-            checkouts. The initial "thunderbird" field is stripped, then the
+-            remaining line is processed like normal. e.g.
+-            "thunderbird:pth:python/foo"
+-
+-        packages.txt -- Denotes that the specified path is a child manifest. It
+-            will be read and processed as if its contents were concatenated
+-            into the manifest being read.
+-
+-        set-variable -- Set the given environment variable; e.g.
+-            `set-variable FOO=1`.
+-
+         Note that the Python interpreter running this function should be the
+         one from the virtualenv. If it is the system Python or if the
+         environment is not configured properly, packages could be installed
+         into the wrong place. This is how virtualenv's work.
+         """
+         import distutils.sysconfig
+ 
+-        thunderbird_dir = os.path.join(self.topsrcdir, "comm")
+-        is_thunderbird = os.path.exists(thunderbird_dir) and bool(
+-            os.listdir(thunderbird_dir)
+-        )
+-        python_lib = distutils.sysconfig.get_python_lib()
+-
+-        def handle_package(action, package):
+-            if action == "packages.txt":
+-                src = os.path.join(self.topsrcdir, package)
+-                assert os.path.isfile(src), "'%s' does not exist" % src
+-                submanager = VirtualenvManager(
+-                    self.topsrcdir, self.virtualenv_root, self.log_handle, src,
+-                    populate_local_paths=self.populate_local_paths)
+-                submanager.populate()
+-            elif action == "pth":
+-                if not self.populate_local_paths:
+-                    return
+-
+-                path = os.path.join(self.topsrcdir, package)
+-
+-                with open(os.path.join(python_lib, "mach.pth"), "a") as f:
+-                    # This path is relative to the .pth file.  Using a
+-                    # relative path allows the srcdir/objdir combination
+-                    # to be moved around (as long as the paths relative to
+-                    # each other remain the same).
+-                    f.write("%s\n" % os.path.relpath(path, python_lib))
+-            elif action == "thunderbird":
+-                if is_thunderbird:
+-                    handle_package(*package.split(":", maxsplit=1))
+-            elif action == "pypi":
+-                if len(package.split("==")) != 2:
+-                    raise Exception(
+-                        "Expected pypi package version to be pinned in the "
+-                        'format "package==version", found "{}"'.format(package)
+-                    )
+-                self.install_pip_package(package)
+-            else:
+-                raise Exception("Unknown action: %s" % action)
+-
+         # We always target the OS X deployment target that Python itself was
+         # built with, regardless of what's in the current environment. If we
+-        # don't do # this, we may run into a Python bug. See
++        # don't do this, we may run into a Python bug. See
+         # http://bugs.python.org/issue9516 and bug 659881.
+         #
+         # Note that this assumes that nothing compiled in the virtualenv is
+         # shipped as part of a distribution. If we do ship anything, the
+         # deployment target here may be different from what's targeted by the
+         # shipping binaries and # virtualenv-produced binaries may fail to
+         # work.
+         #
+@@ -383,18 +326,30 @@ class VirtualenvManager(VirtualenvHelper
+             old_env_variables = {}
+             for k in IGNORE_ENV_VARIABLES:
+                 if k not in os.environ:
+                     continue
+ 
+                 old_env_variables[k] = os.environ[k]
+                 del os.environ[k]
+ 
+-            for current_action, current_package in self.packages():
+-                handle_package(current_action, current_package)
++            env_requirements = self._requirements()
++            if self.populate_local_paths:
++                python_lib = distutils.sysconfig.get_python_lib()
++                with open(os.path.join(python_lib, "mach.pth"), "a") as f:
++                    for pth_requirement in env_requirements.pth_requirements:
++                        path = os.path.join(self.topsrcdir, pth_requirement.path)
++                        # This path is relative to the .pth file.  Using a
++                        # relative path allows the srcdir/objdir combination
++                        # to be moved around (as long as the paths relative to
++                        # each other remain the same).
++                        f.write("{}\n".format(os.path.relpath(path, python_lib)))
++
++            for pypi_requirement in env_requirements.pypi_requirements:
++                self.install_pip_package(pypi_requirement.full_specifier)
+ 
+         finally:
+             os.environ.pop('MACOSX_DEPLOYMENT_TARGET', None)
+ 
+             if old_target is not None:
+                 os.environ['MACOSX_DEPLOYMENT_TARGET'] = old_target
+ 
+             os.environ.update(old_env_variables)

+ 168 - 0
mozilla-release/patches/1717645-2-92a1.patch

@@ -0,0 +1,168 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1628176457 0
+# Node ID 719348d541d8d45ad507232aafdc32c4b64b0362
+# Parent  019ba105eac6da12b36cdfd7c07d6554bc9a6946
+Bug 1717645: Check virtualenv pths are up-to-date r=ahal
+
+It's possible for a virtualenv to have an incorrect list of directories
+to add to the sys.path, such as the following cases:
+* Its creation got cancelled halfway through
+* The list of pths changed in a new revision
+* It got modified by an external tool
+
+By validating the list of provided pths against the list of required
+pths, we can ensure that the virtualenv is more dependably up-to-date.
+
+Differential Revision: https://phabricator.services.mozilla.com/D119686
+
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -13,16 +13,17 @@ import os
+ import platform
+ import shutil
+ import subprocess
+ import sys
+ 
+ 
+ IS_NATIVE_WIN = (sys.platform == 'win32' and os.sep == '\\')
+ IS_CYGWIN = (sys.platform == 'cygwin')
++PTH_FILENAME = "mach.pth"
+ 
+ UPGRADE_WINDOWS = '''
+ Please upgrade to the latest MozillaBuild development environment. See
+ https://developer.mozilla.org/en-US/docs/Developer_Guide/Build_Instructions/Windows_Prerequisites
+ '''.lstrip()
+ 
+ UPGRADE_OTHER = '''
+ Run |mach bootstrap| to ensure your system is up to date.
+@@ -183,16 +184,42 @@ class VirtualenvManager(VirtualenvHelper
+         # python, or we have the Python version that was used to create the
+         # virtualenv. If this fails, it is likely system Python has been
+         # upgraded, and our virtualenv would not be usable.
+         orig_version = self.get_exe_info()
+         hexversion = self.python_executable_hexversion(python)
+         if (python != self.python_path) and (hexversion != orig_version):
+             return False
+ 
++        if env_requirements.pth_requirements and self.populate_local_paths:
++            try:
++                with open(
++                    os.path.join(self._site_packages_dir(), PTH_FILENAME)
++                ) as file:
++                    pth_lines = file.read().strip().split("\n")
++            except FileNotFoundError:
++                return False
++
++            current_paths = [
++                os.path.normcase(
++                    os.path.abspath(os.path.join(self._site_packages_dir(), path))
++                )
++                for path in pth_lines
++            ]
++
++            required_paths = [
++                os.path.normcase(
++                    os.path.abspath(os.path.join(self.topsrcdir, pth.path))
++                )
++                for pth in env_requirements.pth_requirements
++            ]
++
++            if current_paths != required_paths:
++                return False
++
+         if env_requirements.pypi_requirements:
+             pip_json = self._run_pip(
+                 ["list", "--format", "json"], capture_output=True
+             ).stdout
+             installed_packages = json.loads(pip_json)
+             installed_packages = {
+                 package["name"]: package["version"] for package in installed_packages
+             }
+@@ -329,17 +356,17 @@ class VirtualenvManager(VirtualenvHelper
+                     continue
+ 
+                 old_env_variables[k] = os.environ[k]
+                 del os.environ[k]
+ 
+             env_requirements = self._requirements()
+             if self.populate_local_paths:
+                 python_lib = distutils.sysconfig.get_python_lib()
+-                with open(os.path.join(python_lib, "mach.pth"), "a") as f:
++                with open(os.path.join(python_lib, PTH_FILENAME), "a") as f:
+                     for pth_requirement in env_requirements.pth_requirements:
+                         path = os.path.join(self.topsrcdir, pth_requirement.path)
+                         # This path is relative to the .pth file.  Using a
+                         # relative path allows the srcdir/objdir combination
+                         # to be moved around (as long as the paths relative to
+                         # each other remain the same).
+                         f.write("{}\n".format(os.path.relpath(path, python_lib)))
+ 
+@@ -537,32 +564,17 @@ class VirtualenvManager(VirtualenvHelper
+         or a different value (e.g.: a distro).
+ 
+         We can take advantage of this behaviour by telling pip
+         that it was installed by "mach", so it won't print the
+         warning.
+ 
+         https://github.com/pypa/pip/blob/5ee933aab81273da3691c97f2a6e7016ecbe0ef9/src/pip/_internal/self_outdated_check.py#L100-L101 # noqa F401
+         """
+-
+-        # Defer "distutils" import until this function is called so that
+-        # "mach bootstrap" doesn't fail due to Linux distro python-distutils
+-        # package not being installed.
+-        # By the time this function is called, "distutils" must be installed
+-        # because it's needed by the "virtualenv" package.
+-        from distutils import dist
+-
+-        distribution = dist.Distribution({"script_args": "--no-user-cfg"})
+-        installer = distribution.get_command_obj("install")
+-        installer.prefix = os.path.normpath(self.virtualenv_root)
+-        installer.finalize_options()
+-
+-        # Path to virtualenv's "site-packages" directory
+-        site_packages = installer.install_purelib
+-
++        site_packages = self._site_packages_dir()
+         pip_dist_info = next(
+             (
+                 file
+                 for file in os.listdir(site_packages)
+                 if file.startswith("pip-") and file.endswith(".dist-info")
+             ),
+             None,
+         )
+@@ -586,16 +598,32 @@ class VirtualenvManager(VirtualenvHelper
+         # force the virtualenv's interpreter to be used and all is well.
+         # It /might/ be possible to cheat and set sys.executable to
+         # self.python_path. However, this seems more risk than it's worth.
+         pip = os.path.join(self.bin_path, 'pip')
+         return subprocess.run(
+             [pip] + args, cwd=self.topsrcdir, env=env, universal_newlines=True, **kwargs
+         )
+ 
++    def _site_packages_dir(self):
++        # Defer "distutils" import until this function is called so that
++        # "mach bootstrap" doesn't fail due to Linux distro python-distutils
++        # package not being installed.
++        # By the time this function is called, "distutils" must be installed
++        # because it's needed by the "virtualenv" package.
++        from distutils import dist
++
++        distribution = dist.Distribution({"script_args": "--no-user-cfg"})
++        installer = distribution.get_command_obj("install")
++        installer.prefix = os.path.normpath(self.virtualenv_root)
++        installer.finalize_options()
++
++        # Path to virtualenv's "site-packages" directory
++        return installer.install_purelib
++
+ 
+ def get_archflags():
+     # distutils will use the architecture of the running Python instance when building packages.
+     # However, it's possible for the Xcode Python to be a universal binary (x86_64 and
+     # arm64) without the associated macOS SDK supporting arm64, thereby causing a build
+     # failure. To avoid this, we explicitly influence the build to only target a single
+     # architecture - our current architecture.
+     return "-arch {}".format(platform.machine())

+ 34 - 0
mozilla-release/patches/1717645-3-92a1.patch

@@ -0,0 +1,34 @@
+# HG changeset patch
+# User Mitchell Hentges <mhentges@mozilla.com>
+# Date 1628176458 0
+# Node ID 3a844a148590581c9b75c5bae8c8829fea24fc7d
+# Parent  9b39f6277254c5f0553f00e046b9a4e9ca104da3
+Bug 1717645: Fix up_to_date for Python 3.6 r=ahal
+
+Python 3.6 doesn't support the `capture_output` option, so use
+`stdout=subprocess.PIPE` instead.
+
+Differential Revision: https://phabricator.services.mozilla.com/D120027
+
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -212,17 +212,17 @@ class VirtualenvManager(VirtualenvHelper
+                 for pth in env_requirements.pth_requirements
+             ]
+ 
+             if current_paths != required_paths:
+                 return False
+ 
+         if env_requirements.pypi_requirements:
+             pip_json = self._run_pip(
+-                ["list", "--format", "json"], capture_output=True
++                ["list", "--format", "json"], stdout=subprocess.PIPE
+             ).stdout
+             installed_packages = json.loads(pip_json)
+             installed_packages = {
+                 package["name"]: package["version"] for package in installed_packages
+             }
+             for requirement in env_requirements.pypi_requirements:
+                 if (
+                     installed_packages.get(requirement.package_name, None)

+ 27 - 27
mozilla-release/patches/1723031-1-94a1.patch

@@ -2,7 +2,7 @@
 # User Mitchell Hentges <mhentges@mozilla.com>
 # Date 1632841169 0
 # Node ID 3aafa68a8527a33b26de30310cae03d1570c27be
-# Parent  addded08d081925b5d3fac8326e9de3b80f4554e
+# Parent  4b96720035b77314ebd4af0a4d5d634b4b18dd5d
 Bug 1723031: Vendors `packaging`, `pyparsing` library r=ahal
 
 This will allow us to parse and compare pip package versions the same
@@ -15,32 +15,32 @@ Differential Revision: https://phabricator.services.mozilla.com/D122888
 diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt
 --- a/build/common_virtualenv_packages.txt
 +++ b/build/common_virtualenv_packages.txt
-@@ -44,23 +44,25 @@ mozilla.pth:third_party/python/fluent.sy
- mozilla.pth:third_party/python/funcsigs
- mozilla.pth:third_party/python/gyp/pylib
- mozilla.pth:third_party/python/idna
- mozilla.pth:third_party/python/importlib_metadata
- mozilla.pth:third_party/python/jsmin
- mozilla.pth:third_party/python/json-e
- mozilla.pth:third_party/python/mock-1.0.0
- mozilla.pth:third_party/python/more_itertools
-+mozilla.pth:third_party/python/packaging
- mozilla.pth:third_party/python/pathspec
- mozilla.pth:third_party/python/pluggy
- mozilla.pth:third_party/python/ply
- mozilla.pth:third_party/python/py
- mozilla.pth:third_party/python/pyasn1
- mozilla.pth:third_party/python/pyasn1-modules
- mozilla.pth:third_party/python/pylru
-+mozilla.pth:third_party/python/pyparsing
- mozilla.pth:third_party/python/pystache
- mozilla.pth:third_party/python/pytest
- mozilla.pth:third_party/python/python-hglib
- mozilla.pth:third_party/python/pytoml
- mozilla.pth:third_party/python/PyYAML/lib3/
- mozilla.pth:third_party/python/redo
- mozilla.pth:third_party/python/requests
- mozilla.pth:third_party/python/requests-unixsocket
+@@ -61,23 +61,25 @@ pth:third_party/python/fluent.syntax
+ pth:third_party/python/funcsigs
+ pth:third_party/python/gyp/pylib
+ pth:third_party/python/idna
+ pth:third_party/python/importlib_metadata
+ pth:third_party/python/jsmin
+ pth:third_party/python/json-e
+ pth:third_party/python/mock-1.0.0
+ pth:third_party/python/more_itertools
++pth:third_party/python/packaging
+ pth:third_party/python/pathspec
+ pth:third_party/python/pluggy
+ pth:third_party/python/ply
+ pth:third_party/python/py
+ pth:third_party/python/pyasn1
+ pth:third_party/python/pyasn1-modules
+ pth:third_party/python/pylru
++pth:third_party/python/pyparsing
+ pth:third_party/python/pystache
+ pth:third_party/python/pytest
+ pth:third_party/python/python-hglib
+ pth:third_party/python/pytoml
+ pth:third_party/python/PyYAML/lib3/
+ pth:third_party/python/redo
+ pth:third_party/python/requests
+ pth:third_party/python/requests-unixsocket
 diff --git a/third_party/python/packaging/packaging-21.0.dist-info/LICENSE b/third_party/python/packaging/packaging-21.0.dist-info/LICENSE
 new file mode 100644
 --- /dev/null

+ 22 - 22
mozilla-release/patches/1730712-1-94a1.patch

@@ -2,7 +2,7 @@
 # User Mitchell Hentges <mhentges@mozilla.com>
 # Date 1632841170 0
 # Node ID 004ede2c67a34957c1f146bf7fe2620cfda900b1
-# Parent  85fb375ea7b1b6dc5ea0e7fa5378c65e0ab05012
+# Parent  4c5e324d2471b4667e49ad19eb7afee95b791e5b
 Bug 1730712: Use local vendored `certifi` instead of WPT's r=ahal
 
 Both of them are version `2018.4.16`, but our local one is vendored in a
@@ -21,24 +21,24 @@ Differential Revision: https://phabricator.services.mozilla.com/D126282
 diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt
 --- a/build/common_virtualenv_packages.txt
 +++ b/build/common_virtualenv_packages.txt
-@@ -25,19 +25,19 @@ mozilla.pth:testing/web-platform/tests/t
- mozilla.pth:testing/web-platform/tests/tools/wptrunner
- mozilla.pth:testing/web-platform/tests/tools/wptserve
- mozilla.pth:testing/xpcshell
- mozilla.pth:third_party/python/appdirs
- mozilla.pth:third_party/python/atomicwrites
- mozilla.pth:third_party/python/attrs
- mozilla.pth:third_party/python/blessings
- mozilla.pth:third_party/python/cbor2
-+mozilla.pth:third_party/python/certifi
- mozilla.pth:third_party/python/chardet
- mozilla.pth:third_party/python/Click
--mozilla.pth:third_party/python/certifi
- mozilla.pth:third_party/python/compare_locales
- mozilla.pth:third_party/python/cookies
- mozilla.pth:third_party/python/cram
- mozilla.pth:third_party/python/distro
- mozilla.pth:third_party/python/dlmanager
- mozilla.pth:third_party/python/ecdsa
- mozilla.pth:third_party/python/fluent.migrate
- mozilla.pth:third_party/python/fluent.syntax
+@@ -42,19 +42,19 @@ pth:testing/web-platform/tests/tools/six
+ pth:testing/web-platform/tests/tools/wptrunner
+ pth:testing/web-platform/tests/tools/wptserve
+ pth:testing/xpcshell
+ pth:third_party/python/appdirs
+ pth:third_party/python/atomicwrites
+ pth:third_party/python/attrs
+ pth:third_party/python/blessings
+ pth:third_party/python/cbor2
++pth:third_party/python/certifi
+ pth:third_party/python/chardet
+ pth:third_party/python/Click
+-pth:third_party/python/certifi
+ pth:third_party/python/compare_locales
+ pth:third_party/python/cookies
+ pth:third_party/python/cram
+ pth:third_party/python/distro
+ pth:third_party/python/dlmanager
+ pth:third_party/python/ecdsa
+ pth:third_party/python/fluent.migrate
+ pth:third_party/python/fluent.syntax

+ 22 - 17
mozilla-release/patches/TOP-1906540-mozdevice-removal-mozilla-25320.patch

@@ -1,9 +1,30 @@
 # HG changeset patch
 # User Ian Neal <iann_cvs@blueyonder.co.uk>
 # Date 1720395449 -3600
-# Parent  63f68757be77fff8536d39b0cfd069493a6a38d5
+# Parent  1f95eabdb279da6f5754efe15fd52b7ecf648d5f
 Bug 1906540 - Remove mozrunner devices and mozdevice from SeaMonkey. r=frg a=frg
 
+diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt
+--- a/build/common_virtualenv_packages.txt
++++ b/build/common_virtualenv_packages.txt
+@@ -17,17 +17,16 @@ pth:testing
+ pth:testing/firefox-ui/harness
+ pth:testing/marionette/client
+ pth:testing/marionette/harness
+ pth:testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py
+ pth:testing/marionette/puppeteer/firefox
+ pth:testing/mozbase/manifestparser
+ pth:testing/mozbase/mozcrash
+ pth:testing/mozbase/mozdebug
+-pth:testing/mozbase/mozdevice
+ pth:testing/mozbase/mozfile
+ pth:testing/mozbase/mozhttpd
+ pth:testing/mozbase/mozinfo
+ pth:testing/mozbase/mozinstall
+ pth:testing/mozbase/mozleak
+ pth:testing/mozbase/mozlog
+ pth:testing/mozbase/moznetwork
+ pth:testing/mozbase/mozprocess
 diff --git a/config/rules.mk b/config/rules.mk
 --- a/config/rules.mk
 +++ b/config/rules.mk
@@ -8644,22 +8665,6 @@ diff --git a/testing/mozbase/mozversion/mozversion/mozversion.py b/testing/mozba
      return version._info
  
  
-diff --git a/testing/mozbase/packages.txt b/testing/mozbase/packages.txt
---- a/testing/mozbase/packages.txt
-+++ b/testing/mozbase/packages.txt
-@@ -1,12 +1,11 @@
- manifestparser.pth:testing/mozbase/manifestparser
- mozcrash.pth:testing/mozbase/mozcrash
- mozdebug.pth:testing/mozbase/mozdebug
--mozdevice.pth:testing/mozbase/mozdevice
- mozfile.pth:testing/mozbase/mozfile
- mozhttpd.pth:testing/mozbase/mozhttpd
- mozinfo.pth:testing/mozbase/mozinfo
- mozinstall.pth:testing/mozbase/mozinstall
- mozleak.pth:testing/mozbase/mozleak
- mozlog.pth:testing/mozbase/mozlog
- moznetwork.pth:testing/mozbase/moznetwork
- mozprocess.pth:testing/mozbase/mozprocess
 diff --git a/testing/mozharness/configs/android/androidarm_4_3.py b/testing/mozharness/configs/android/androidarm_4_3.py
 deleted file mode 100644
 --- a/testing/mozharness/configs/android/androidarm_4_3.py

+ 93 - 63
mozilla-release/patches/TOP-NOBUG-1712804fix-25320.patch

@@ -1,7 +1,7 @@
 # HG changeset patch
 # User Myckel Habets <gentoo-bugs@habets-dobben.nl>
 # Date 1728397275 -7200
-# Parent  7cd8685cd44a618b542e1e81a1713b8da394109c
+# Parent  b5b6c76668b4ac9486f106e68142f54eeec9fbda
 No Bug - Replace hardcoded Thunderbird with comm project in build packages. r=frg a=frg
 
 Rename the "Thunderbird" logic of Bug 1712804 to "commproject".
@@ -14,49 +14,96 @@ diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_pack
 @@ -1,9 +1,9 @@
 -thunderbird:packages.txt:comm/build/virtualenv_packages.txt
 +commproject:packages.txt:comm/build/virtualenv_packages.txt
- mozilla.pth:build
- mozilla.pth:config
- mozilla.pth:config/mozunit
- mozilla.pth:dom/bindings
- mozilla.pth:dom/bindings/parser
- mozilla.pth:layout/tools/reftest
- mozilla.pth:python/mach
- mozilla.pth:python/mozboot
-diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
---- a/python/mozbuild/mozbuild/virtualenv.py
-+++ b/python/mozbuild/mozbuild/virtualenv.py
-@@ -285,20 +285,20 @@ class VirtualenvManager(VirtualenvHelper
+ pth:build
+ pth:config
+ pth:config/mozunit
+ pth:dom/bindings
+ pth:dom/bindings/parser
+ pth:layout/tools/reftest
+ pth:python/mach
+ pth:python/mozboot
+diff --git a/python/mozbuild/mozbuild/requirements.py b/python/mozbuild/mozbuild/requirements.py
+--- a/python/mozbuild/mozbuild/requirements.py
++++ b/python/mozbuild/mozbuild/requirements.py
+@@ -29,40 +29,40 @@ class MachEnvRequirements:
+         the virtualenv site packages directory.
  
-         The manifest file consists of colon-delimited fields. The first field
-         specifies the action. The remaining fields are arguments to that
-         action. The following actions are supported:
+     pypi -- Fetch the package, plus dependencies, from PyPI.
  
-         filename.pth -- Adds the path given as argument to filename.pth under
-             the virtualenv site packages directory.
+     packages.txt -- Denotes that the specified path is a child manifest. It
+         will be read and processed as if its contents were concatenated
+         into the manifest being read.
  
--        thunderbird -- This denotes the action as to only occur for Thunderbird
--            checkouts. The initial "thunderbird" field is stripped, then the
-+        commproject -- This denotes the action as to only occur for comm project
-+            checkouts. The initial "commproject" field is stripped, then the
-             remaining line is processed like normal. e.g.
--            "thunderbird:comms.pth:python/foo"
-+            "commproject:comms.pth:python/foo"
+-    thunderbird -- This denotes the action as to only occur for Thunderbird
+-        checkouts. The initial "thunderbird" field is stripped, then the
++    commproject -- This denotes the action as to only occur for comm project
++        checkouts. The initial "commproject" field is stripped, then the
+         remaining line is processed like normal. e.g.
+-        "thunderbird:pth:python/foo"
++        "commproject:pth:python/foo"
+     """
  
-         packages.txt -- Denotes that the specified path is a child manifest. It
-             will be read and processed as if its contents were concatenated
-             into the manifest being read.
+     def __init__(self):
+         self.requirements_paths = []
+         self.pth_requirements = []
+         self.pypi_requirements = []
  
-         windows -- This denotes that the action should only be taken when run
-             on Windows.
+     @classmethod
+     def from_requirements_definition(
+-        cls, topsrcdir, is_thunderbird, requirements_definition
++        cls, topsrcdir, is_commproject, requirements_definition
+     ):
+         requirements = cls()
+         _parse_mach_env_requirements(
+-            requirements, requirements_definition, topsrcdir, is_thunderbird
++            requirements, requirements_definition, topsrcdir, is_commproject
+         )
+         return requirements
  
-@@ -310,19 +310,19 @@ class VirtualenvManager(VirtualenvHelper
  
-         Note that the Python interpreter running this function should be the
-         one from the virtualenv. If it is the system Python or if the
-         environment is not configured properly, packages could be installed
-         into the wrong place. This is how virtualenv's work.
-         """
-         import distutils.sysconfig
+ def _parse_mach_env_requirements(
+-    requirements_output, root_requirements_path, topsrcdir, is_thunderbird
++    requirements_output, root_requirements_path, topsrcdir, is_commproject
+ ):
+     def _parse_requirements_line(line):
+         action, params = line.rstrip().split(":", maxsplit=1)
+         if action == "pth":
+             requirements_output.pth_requirements.append(PthSpecifier(params))
+         elif action == "pypi":
+             if len(params.split("==")) != 2:
+                 raise Exception(
+@@ -72,18 +72,18 @@ def _parse_mach_env_requirements(
+             package_name, version = params.split("==")
+             requirements_output.pypi_requirements.append(
+                 PypiSpecifier(package_name, version, params)
+             )
+         elif action == "packages.txt":
+             nested_definition_path = os.path.join(topsrcdir, params)
+             assert os.path.isfile(nested_definition_path)
+             _parse_requirements_definition_file(nested_definition_path)
+-        elif action == "thunderbird":
+-            if is_thunderbird:
++        elif action == "commproject":
++            if is_commproject:
+                 _parse_requirements_line(params)
+         else:
+             raise Exception("Unknown requirements definition action: %s" % action)
+ 
+     def _parse_requirements_definition_file(requirements_path):
+         """Parse requirements file into list of requirements"""
+         requirements_output.requirements_paths.append(requirements_path)
+ 
+diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/virtualenv.py
+--- a/python/mozbuild/mozbuild/virtualenv.py
++++ b/python/mozbuild/mozbuild/virtualenv.py
+@@ -299,22 +299,22 @@ class VirtualenvManager(VirtualenvHelper
+             # import MachEnvRequirements in the expected way.
+             from mozbuild.requirements import MachEnvRequirements
+         except ImportError:
+             # When `virtualenv.py` is invoked standalone, import
+             # MachEnvRequirements from the adjacent "standalone"
+             # requirements module.
+             from requirements import MachEnvRequirements
  
 -        thunderbird_dir = os.path.join(self.topsrcdir, "comm")
 -        is_thunderbird = os.path.exists(thunderbird_dir) and bool(
@@ -65,31 +112,14 @@ diff --git a/python/mozbuild/mozbuild/virtualenv.py b/python/mozbuild/mozbuild/v
 +        is_commproject = os.path.exists(commproject_dir) and bool(
 +            os.listdir(commproject_dir)
          )
-         packages = self.packages()
-         python_lib = distutils.sysconfig.get_python_lib()
- 
-         def handle_package(package):
-             if package[0] == 'packages.txt':
-                 assert len(package) == 2
+         return MachEnvRequirements.from_requirements_definition(
+-            self.topsrcdir, is_thunderbird, self.manifest_path
++            self.topsrcdir, is_commproject, self.manifest_path
+         )
  
-@@ -341,18 +341,18 @@ class VirtualenvManager(VirtualenvHelper
-                 path = os.path.join(self.topsrcdir, package[1])
+     def populate(self):
+         """Populate the virtualenv.
  
-                 with open(os.path.join(python_lib, package[0]), 'a') as f:
-                     # This path is relative to the .pth file.  Using a
-                     # relative path allows the srcdir/objdir combination
-                     # to be moved around (as long as the paths relative to
-                     # each other remain the same).
-                     f.write("%s\n" % os.path.relpath(path, python_lib))
--            elif package[0] == "thunderbird":
--                if is_thunderbird:
-+            elif package[0] == "commproject":
-+                if is_commproject:
-                     handle_package(package[1:])
-             elif package[0] in ("windows", "!windows"):
-                 for_win = not package[0].startswith('!')
-                 is_win = sys.platform == 'win32'
-                 if is_win == for_win:
-                     handle_package(package[1:])
-             else:
-                 raise Exception("Unknown action: %s" % package[0])
+         Note that the Python interpreter running this function should be the
+         one from the virtualenv. If it is the system Python or if the
+         environment is not configured properly, packages could be installed

+ 21 - 21
mozilla-release/patches/TOP-NOBUG-remove-web-platform-25320.patch

@@ -1,7 +1,7 @@
 # HG changeset patch
 # User Ian Neal <iann_cvs@blueyonder.co.uk>
 # Date 1722118398 -3600
-# Parent  4f0e2c77fbd8e642aac3c8b1f09612102465e247
+# Parent  1b3445349f673876cc76769a509516119836517c
 NOBUG - remove testing/web-platform. r=frg a=frg
 
 diff --git a/.flake8 b/.flake8
@@ -28,26 +28,26 @@ diff --git a/.flake8 b/.flake8
 diff --git a/build/common_virtualenv_packages.txt b/build/common_virtualenv_packages.txt
 --- a/build/common_virtualenv_packages.txt
 +++ b/build/common_virtualenv_packages.txt
-@@ -16,19 +16,16 @@ mozilla.pth:python/mozversioncontrol
- mozilla.pth:testing
- mozilla.pth:testing/firefox-ui/harness
- mozilla.pth:testing/marionette/client
- mozilla.pth:testing/marionette/harness
- mozilla.pth:testing/marionette/harness/marionette_harness/runner/mixins/browsermob-proxy-py
- mozilla.pth:testing/marionette/puppeteer/firefox
- packages.txt:testing/mozbase/packages.txt
- mozilla.pth:testing/talos
--mozilla.pth:testing/web-platform/tests/tools/six
--mozilla.pth:testing/web-platform/tests/tools/wptrunner
--mozilla.pth:testing/web-platform/tests/tools/wptserve
- mozilla.pth:testing/xpcshell
- mozilla.pth:third_party/python/appdirs
- mozilla.pth:third_party/python/atomicwrites
- mozilla.pth:third_party/python/attrs
- mozilla.pth:third_party/python/blessings
- mozilla.pth:third_party/python/cbor2
- mozilla.pth:third_party/python/certifi
- mozilla.pth:third_party/python/chardet
+@@ -32,19 +32,16 @@ pth:testing/mozbase/moznetwork
+ pth:testing/mozbase/mozprocess
+ pth:testing/mozbase/mozprofile
+ pth:testing/mozbase/mozrunner
+ pth:testing/mozbase/mozsystemmonitor
+ pth:testing/mozbase/mozscreenshot
+ pth:testing/mozbase/moztest
+ pth:testing/mozbase/mozversion
+ pth:testing/talos
+-pth:testing/web-platform/tests/tools/six
+-pth:testing/web-platform/tests/tools/wptrunner
+-pth:testing/web-platform/tests/tools/wptserve
+ pth:testing/xpcshell
+ pth:third_party/python/appdirs
+ pth:third_party/python/atomicwrites
+ pth:third_party/python/attrs
+ pth:third_party/python/blessings
+ pth:third_party/python/cbor2
+ pth:third_party/python/certifi
+ pth:third_party/python/chardet
 diff --git a/js/src/tests/jstests.py b/js/src/tests/jstests.py
 --- a/js/src/tests/jstests.py
 +++ b/js/src/tests/jstests.py

+ 16 - 4
mozilla-release/patches/series

@@ -7038,10 +7038,10 @@ NOBUG-20210216-9b29bb9d-87a1.patch
 1712382-3-90a1.patch
 1712804-1-90a1.patch
 1712804-2-90a1.patch
-1712133-1-90a1.patch
-1712133-2-90a1.patch
-1712133-3-90a1.patch
-1712133-4-90a1.patch
+1712133-01-90a1.patch
+1712133-02-90a1.patch
+1712133-03-90a1.patch
+1712133-04-90a1.patch
 1712819-1-90a1.patch
 1712819-2-90a1.patch
 1704784-90a1.patch
@@ -7074,6 +7074,15 @@ NOBUG-20210216-9b29bb9d-87a1.patch
 1714641-11-91a1.patch
 1714641-12-91a1.patch
 1714641-13-91a1.patch
+1714688-4-91a1.patch
+1714688-5-91a1.patch
+1712133-05-91a1.patch
+1712133-06-91a1.patch
+1712133-07-91a1.patch
+1712133-08-91a1.patch
+1712133-09-91a1.patch
+1712133-10-91a1.patch
+1712133-11-91a1.patch
 1714244-91a1.patch
 1711872-91a1.patch
 1713610-91a1.patch
@@ -7095,6 +7104,9 @@ NOBUG-20210216-9b29bb9d-87a1.patch
 1720031-7813.patch
 1722204-7813.patch
 1722227-removecasting-2539.patch
+1717645-1-92a1.patch
+1717645-2-92a1.patch
+1717645-3-92a1.patch
 1714632-92a1.patch
 1720703-92a1.patch
 1721149-92a1.patch