Source code

Revision control

Copy as Markdown

Other Tools

# 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, print_function, unicode_literals
import sys
import logging
from mach.decorators import CommandArgument, Command, SubCommand
from mozbuild.vendor.moz_yaml import load_moz_yaml, MozYamlVerifyError
# Fun quirk of ./mach - you can specify a default argument as well as subcommands.
# If the default argument matches a subcommand, the subcommand gets called. If it
# doesn't, we wind up in the default command.
@Command(
"vendor",
category="misc",
description="Vendor third-party dependencies into the source repository.",
)
@CommandArgument(
"--check-for-update",
action="store_true",
help="For scripted use, prints the new commit to update to, or nothing if up to date.",
default=False,
)
@CommandArgument(
"--add-to-exports",
action="store_true",
help="Will attempt to add new header files into any relevant EXPORTS block.",
default=False,
)
@CommandArgument(
"--ignore-modified",
action="store_true",
help="Ignore modified files in current checkout.",
default=False,
)
@CommandArgument("-r", "--revision", help="Repository tag or commit to update to.")
@CommandArgument(
"-f",
"--force",
action="store_true",
help="Force a re-vendor even if we're up to date",
)
@CommandArgument(
"--verify", "-v", action="store_true", help="(Only) verify the manifest."
)
@CommandArgument(
"--patch-mode",
help="Select how vendored patches will be imported. 'none' skips patch import, and"
"'only' imports patches and skips library vendoring.",
default="",
)
@CommandArgument("library", nargs=1, help="The moz.yaml file of the library to vendor.")
def vendor(
command_context,
library,
revision,
ignore_modified=False,
check_for_update=False,
add_to_exports=False,
force=False,
verify=False,
patch_mode="",
):
"""
Vendor third-party dependencies into the source repository.
Vendoring rust and python can be done with ./mach vendor [rust/python].
Vendoring other libraries can be done with ./mach vendor [arguments] path/to/file.yaml
"""
library = library[0]
assert library not in ["rust", "python"]
command_context.populate_logger()
command_context.log_manager.enable_unstructured()
if check_for_update:
logging.disable(level=logging.CRITICAL)
try:
manifest = load_moz_yaml(library)
if verify:
print("%s: OK" % library)
sys.exit(0)
except MozYamlVerifyError as e:
print(e)
sys.exit(1)
if "vendoring" not in manifest:
raise Exception(
"Cannot perform update actions if we don't have a 'vendoring' section in the moz.yaml"
)
if patch_mode and patch_mode not in ["none", "only"]:
print(
"Unknown patch mode given '%s'. Please use one of: 'none' or 'only'."
% patch_mode
)
sys.exit(1)
if (
manifest["vendoring"].get("patches", [])
and not patch_mode
and not check_for_update
):
print(
"Patch mode was not given when required. Please use one of: 'none' or 'only'"
)
sys.exit(1)
if patch_mode == "only" and not manifest["vendoring"].get("patches", []):
print(
"Patch import was specified for %s but there are no vendored patches defined."
% library
)
sys.exit(1)
if not ignore_modified and not check_for_update:
check_modified_files(command_context)
elif ignore_modified and not check_for_update:
print(
"Because you passed --ignore-modified we will not be "
+ "able to detect spurious upstream updates."
)
if not revision:
revision = "HEAD"
from mozbuild.vendor.vendor_manifest import VendorManifest
vendor_command = command_context._spawn(VendorManifest)
vendor_command.vendor(
command_context,
library,
manifest,
revision,
ignore_modified,
check_for_update,
force,
add_to_exports,
patch_mode,
)
sys.exit(0)
def check_modified_files(command_context):
"""
Ensure that there aren't any uncommitted changes to files
in the working copy, since we're going to change some state
on the user.
"""
modified = command_context.repository.get_changed_files("M")
if modified:
command_context.log(
logging.ERROR,
"modified_files",
{},
"""You have uncommitted changes to the following files:
{files}
Please commit or stash these changes before vendoring, or re-run with `--ignore-modified`.
""".format(
files="\n".join(sorted(modified))
),
)
sys.exit(1)
# =====================================================================
@SubCommand(
"vendor",
"rust",
description="Vendor rust crates from crates.io into third_party/rust",
)
@CommandArgument(
"--ignore-modified",
action="store_true",
help="Ignore modified files in current checkout",
default=False,
)
@CommandArgument(
"--build-peers-said-large-imports-were-ok",
action="store_true",
help=(
"Permit overly-large files to be added to the repository. "
"To get permission to set this, raise a question in the #build "
"channel at https://chat.mozilla.org."
),
default=False,
)
@CommandArgument(
"--issues-json",
help="Path to a code-review issues.json file to write out",
)
def vendor_rust(command_context, **kwargs):
from mozbuild.vendor.vendor_rust import VendorRust
vendor_command = command_context._spawn(VendorRust)
issues_json = kwargs.pop("issues_json", None)
ok = vendor_command.vendor(**kwargs)
if issues_json:
with open(issues_json, "w") as fh:
fh.write(vendor_command.serialize_issues_json())
sys.exit(0 if ok else 1)
# =====================================================================
@SubCommand(
"vendor",
"python",
description="Vendor Python packages from pypi.org into third_party/python. "
"Some extra files like docs and tests will automatically be excluded."
"Installs the packages listed in third_party/python/requirements.in and "
"their dependencies.",
virtualenv_name="vendor",
)
@CommandArgument(
"--keep-extra-files",
action="store_true",
default=False,
help="Keep all files, including tests and documentation.",
)
def vendor_python(command_context, keep_extra_files):
from mozbuild.vendor.vendor_python import VendorPython
vendor_command = command_context._spawn(VendorPython)
vendor_command.vendor(keep_extra_files)