# 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/.
# Utility package for working with moz.yaml files. # # Requires `pyyaml` and `voluptuous` # (both are in-tree under third_party/python)
import errno import os import re
import voluptuous import yaml from voluptuous import (
All,
Boolean,
FqdnUrl, In,
Invalid,
Length,
Match,
Msg,
Required,
Schema,
Unique,
) from yaml.error import MarkedYAMLError
# LICENSE file must exist, except for Rust crates which are exempted # because the license is required to be specified in the Cargo.toml file if require_license_file and"origin"in manifest:
files = [f.lower() for f in os.listdir(vendor_directory)] if ( not ( "license-file"in manifest["origin"] and manifest["origin"]["license-file"].lower() in files
) andnot ( "license"in files or"license.txt"in files or"license.rst"in files or"license.html"in files or"license.md"in files
) andnot ( "vendoring"in manifest and manifest["vendoring"].get("flavor", "regular") == "rust"
)
):
license = manifest["origin"]["license"] if isinstance(license, list):
license = "/".join(license) raise ValueError("Failed to find %s LICENSE file" % license)
# Cannot vendor without an origin. if"vendoring"in manifest and"origin"notin manifest: raise ValueError('"vendoring" requires an "origin"')
# Cannot vendor without a computer-readable revision. if"vendoring"in manifest and"revision"notin manifest["origin"]: raise ValueError( 'If "vendoring" is present, "revision" must be present in "origin"'
)
# The Rust and Individual Flavor type precludes a lot of options # individual-files could, in theory, use several of these, but until we have a use case let's # disallow them so we're not worrying about whether they work. When we need them we can make # sure they do. if ( "vendoring"in manifest and manifest["vendoring"].get("flavor", "regular") != "regular"
): for i in [ "skip-vendoring-steps", "keep", "exclude", "include", "generated",
]: if i in manifest["vendoring"]: raise ValueError("A non-regular flavor of update cannot use '%s'" % i)
if manifest["vendoring"].get("flavor", "regular") == "rust": for i in [ "update-actions",
]: if i in manifest["vendoring"]: raise ValueError("A rust flavor of update cannot use '%s'" % i)
# Ensure that only individual-files flavor uses those options if ( "vendoring"in manifest and manifest["vendoring"].get("flavor", "regular") != "individual-files"
): if ( "individual-files"in manifest["vendoring"] or"individual-files-list"in manifest["vendoring"]
): raise ValueError( "Only individual-files flavor of update can use 'individual-files'"
)
# Ensure that release-artifact is only used with tag tracking if"vendoring"in manifest and"release-artifact"in manifest["vendoring"]: if (
manifest["vendoring"].get("source-hosting") != "github" or manifest["vendoring"].get("tracking", "commit") != "tag"
): raise ValueError( "You can only use release-artifact with tag tracking from Github."
)
# Ensure that the individual-files flavor has all the correct options if ( "vendoring"in manifest and manifest["vendoring"].get("flavor", "regular") == "individual-files"
): # Because the only way we can determine the latest tag is by doing a local clone, # we don't want to do that for individual-files flavors because those flavors are # usually on gigantic repos we don't want to clone for such a simple thing. if manifest["vendoring"].get("tracking", "commit") == "tag": raise ValueError( "You cannot use tag tracking with the individual-files flavor. (Sorry.)"
)
# We need either individual-files or individual-files-list if ( "individual-files"notin manifest["vendoring"] and"individual-files-list"notin manifest["vendoring"]
): raise ValueError( "The individual-files flavor must include either "
+ "'individual-files' or 'individual-files-list'"
) # For whichever we have, make sure we don't have the other and we don't have # options we shouldn't or lack ones we should. if"individual-files"in manifest["vendoring"]: if"individual-files-list"in manifest["vendoring"]: raise ValueError( "individual-files-list is mutually exclusive with individual-files"
) if"individual-files-default-upstream"in manifest["vendoring"]: raise ValueError( "individual-files-default-upstream can only be used with individual-files-list"
) if"individual-files-default-destination"in manifest["vendoring"]: raise ValueError( "individual-files-default-destination can only be used "
+ "with individual-files-list"
) if"individual-files-list"in manifest["vendoring"]: if"individual-files"in manifest["vendoring"]: raise ValueError( "individual-files is mutually exclusive with individual-files-list"
) if"individual-files-default-upstream"notin manifest["vendoring"]: raise ValueError( "individual-files-default-upstream must be used with individual-files-list"
) if"individual-files-default-destination"notin manifest["vendoring"]: raise ValueError( "individual-files-default-destination must be used with individual-files-list"
)
if"updatebot"in manifest: # If there are Updatebot tasks, then certain fields must be present and # defaults need to be set. if"tasks"in manifest["updatebot"]: if"vendoring"notin manifest or"url"notin manifest["vendoring"]: raise ValueError( "If Updatebot tasks are specified, a vendoring url must be included."
)
if"try-preset"in manifest["updatebot"]: for f in ["fuzzy-query", "fuzzy-paths"]: if f in manifest["updatebot"]: raise ValueError( "If 'try-preset' is specified, then %s cannot be" % f
)
# Check for a simple YAML file with open(filename, "r") as f:
has_schema = False for line in f.readlines():
m = RE_SECTION(line) if m: if m.group(1) == "schema":
has_schema = True break ifnot has_schema: raise ValueError("Not simple YAML")
# Do type conversion for the few things that need it. # Everythig is parsed as a string to (a) not cause problems with revisions that # are only numerals and (b) not strip leading zeros from the numbers if we just # converted them to string def _schema_1_transform(manifest): if"updatebot"in manifest: if"tasks"in manifest["updatebot"]: for i in range(len(manifest["updatebot"]["tasks"])): if"enabled"in manifest["updatebot"]["tasks"][i]:
val = manifest["updatebot"]["tasks"][i]["enabled"]
manifest["updatebot"]["tasks"][i]["enabled"] = (
val.lower() == "true"or val.lower() == "yes"
) return manifest
class UpdateActions(object): """Voluptuous validator which verifies the update actions(s) are valid."""
def __call__(self, values): for v in values: if"action"notin v: raise Invalid("All file-update entries must specify a valid action") if v["action"] in ["copy-file", "move-file", "move-dir"]: if"from"notin v or"to"notin v or len(v.keys()) != 3: raise Invalid( "%s action must (only) specify 'from' and 'to' keys"
% v["action"]
) elif v["action"] in ["replace-in-file", "replace-in-file-regex"]: if ( "pattern"notin v or"with"notin v or"file"notin v or len(v.keys()) != 4
): raise Invalid( "replace-in-file action must (only) specify "
+ "'pattern', 'with', and 'file' keys"
) elif v["action"] == "delete-path": if"path"notin v or len(v.keys()) != 2: raise Invalid( "delete-path action must (only) specify the 'path' key"
) elif v["action"] == "run-script": if"script"notin v or"cwd"notin v: raise Invalid( "run-script action must specify 'script' and 'cwd' keys"
) if set(v.keys()) - set(["args", "cwd", "script", "action"]) != set(): raise Invalid( "run-script action may only specify 'script', 'cwd', and 'args' keys"
) elif v["action"] == "run-command": if"command"notin v or"cwd"notin v: raise Invalid( "run-command action must specify 'command' and 'cwd' keys"
) if set(v.keys()) - set(["args", "cwd", "command", "action"]) != set(): raise Invalid( "run-command action may only specify 'command', 'cwd', and 'args' keys"
) else: # This check occurs before the validator above, so the above is # redundant but we leave it to be verbose. raise Invalid("Supplied action " + v["action"] + " is invalid.") return values
def __repr__(self): return"UpdateActions"
class UpdatebotTasks(object): """Voluptuous validator which verifies the updatebot task(s) are valid."""
def __call__(self, values):
seenTaskTypes = set() for v in values: if"type"notin v: raise Invalid("All updatebot tasks must specify a valid type")
if v["type"] in seenTaskTypes: raise Invalid("Only one type of each task is currently supported")
seenTaskTypes.add(v["type"])
if v["type"] == "vendoring": for i in ["filter", "branch", "source-extensions"]: if i in v: raise Invalid( "'%s' is only valid for commit-alert task types" % i
) elif v["type"] == "commit-alert": pass else: # This check occurs before the validator above, so the above is # redundant but we leave it to be verbose. raise Invalid("Supplied type " + v["type"] + " is invalid.") return values
def __repr__(self): return"UpdatebotTasks"
class License(object): """Voluptuous validator which verifies the license(s) are valid as per our
allow list."""
def __call__(self, values): if isinstance(values, str):
values = [values] elifnot isinstance(values, list): raise Invalid("Must be string or list") for v in values: if v notin VALID_LICENSES: raise Invalid("Bad License") return values
def __repr__(self): return"License"
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.