123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- # python3
- # Copyright 2021 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- """Helper functions for general tasks.
- Helps for things such as generating versions, paths, and crate names."""
- from __future__ import annotations
- import os
- import sys
- from typing import Any, List
- from lib import consts
- def _find_chromium_root(cwd: str) -> list[str]:
- """Finds and returns the path from the root of the Chromium tree."""
- # This file is at tools/crates/lib/common.py, so 4 * '..' will take us up
- # to the root chromium dir.
- path_components_to_root = [os.path.abspath(__file__)] + [os.pardir] * 4
- abs_root_path = os.path.join(*path_components_to_root)
- path_from_root = os.path.relpath(cwd, abs_root_path)
- def split_path(p: str) -> list[str]:
- if not p: return []
- head, tail = os.path.split(p)
- tail_l = [] if tail == "." else [tail]
- return split_path(head) + tail_l
- return split_path(path_from_root)
- # The path from the root of the chromium tree to the current working directory
- # as a list of path components. If chromium's src.git is rooted at `/f/b/src``,
- # and the this tool is run from `/f/b/src/in/there`, then the value here would
- # be `["in", "there"]`. If the tool is run from the root `/f/b/src` then the
- # value here is `[]`.
- _PATH_FROM_CHROMIUM_ROOT = _find_chromium_root(os.getcwd())
- def crate_name_normalized(crate_name: str) -> str:
- """Normalizes a crate name for GN and file paths."""
- return crate_name.replace("-", "_").replace(".", "_")
- def version_is_complete(version_str: str) -> bool:
- """Returns whether the `version_str` is fully resolved or not.
- A full version includes MAJOR.MINOR.PATCH components."""
- parts = _version_to_parts(version_str)
- # This supports semmvers with pre-release and build flags.
- # https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions
- return len(parts) >= 3
- def _version_to_parts(version_str: str) -> list[str]:
- """Converts a version string into its MAJOR.MINOR.PATCH parts."""
- # TODO(danakj): This does not support pre-release or build versions such as
- # 1.0.0-alpha.1 or 1.0.0+1234 at this time. We only need support it if we
- # want to include such a crate in our tree.
- # https://semver.org/#backusnaur-form-grammar-for-valid-semver-versions
- # TODO(danakj): It would be real nice to introduce a SemmVer type instead of
- # using strings, which sometimes hold partial versions, and sometimes use
- # dots as separators or underscores.
- parts = version_str.split(".")
- assert len(parts) >= 1 and len(parts) <= 3, \
- "The version \"{}\" is an invalid semmver.".format(version_str)
- return parts
- def version_epoch_dots(version_str: str) -> str:
- """Returns a version epoch from a given version string.
- Returns a string with `.` as the component separator."""
- parts = _version_to_parts(version_str)
- if parts[0] != "0":
- return ".".join(parts[:1])
- elif parts[1] != "0":
- return ".".join(parts[:2])
- else:
- return ".".join(parts[:3])
- def version_epoch_normalized(version_str: str) -> str:
- """Returns a version epoch from a given version string.
- Returns a string with `_` as the component separator."""
- parts = _version_to_parts(version_str)
- if parts[0] != "0":
- return "_".join(parts[:1])
- elif parts[1] != "0":
- return "_".join(parts[:2])
- else:
- return "_".join(parts[:3])
- def gn_third_party_path(rel_path: list[str] = []) -> str:
- """Returns the full GN path to the root of all third_party crates."""
- path = _PATH_FROM_CHROMIUM_ROOT + consts.THIRD_PARTY
- return "//" + "/".join(path + rel_path)
- def gn_crate_path(crate_name: str, version: str,
- rel_path: list[str] = []) -> str:
- """Returns the full GN path to a crate that is in third_party. This is the
- path to the crate's BUILD.gn file."""
- name = crate_name_normalized(crate_name)
- epoch = "v" + version_epoch_normalized(version)
- path = _PATH_FROM_CHROMIUM_ROOT + consts.THIRD_PARTY + [name, epoch]
- return "//" + "/".join(path + rel_path)
- def os_third_party_dir(rel_path: list[str] = []) -> str:
- """The relative OS disk path to the top of the third party Rust directory
- where all third party crates are found, along with third_party.toml."""
- return os.path.join(*consts.THIRD_PARTY, *rel_path)
- def os_crate_name_dir(crate_name: str, rel_path: list[str] = []) -> str:
- """The relative OS disk path to a third party crate's top-most directory
- where all versions of that crate are found."""
- return os_third_party_dir(rel_path=[crate_name_normalized(crate_name)] +
- rel_path)
- def os_crate_version_dir(crate_name: str,
- version: str,
- rel_path: list[str] = []) -> str:
- """The relative OS disk path to a third party crate's versioned directory
- where BUILD.gn and README.chromium are found."""
- epoch = "v" + version_epoch_normalized(version)
- return os_crate_name_dir(crate_name, rel_path=[epoch] + rel_path)
- def os_crate_cargo_dir(crate_name: str, version: str,
- rel_path: list[str] = []) -> str:
- """The relative OS disk path to a third party crate's Cargo root.
- This directory is where Cargo.toml and the Rust source files are found. This
- is where the crate is extracted when it is downloaded."""
- return os_crate_version_dir(crate_name,
- version,
- rel_path=consts.CRATE_INNER_DIR + rel_path)
- def crate_download_url(crate: str, version: str) -> str:
- """Returns the crates.io URL to download the crate."""
- return consts.CRATES_IO_DOWNLOAD.format(crate=crate, version=version)
- def crate_view_url(crate: str) -> str:
- """Returns the crates.io URL to see info about the crate."""
- return consts.CRATES_IO_VIEW.format(crate=crate)
- def load_toml(path: str) -> dict[str, Any]:
- """Loads a file at the path and parses it as a TOML file.
- This is a helper for times when you don't need the raw text content of the
- TOML file.
- Returns:
- A dictionary of the contents of the TOML file."""
- with open(path, "r") as cargo_file:
- toml_string = cargo_file.read()
- import toml
- return dict(toml.loads(toml_string))
- def print_same_line(s: str, fill_num_chars: int, done: bool = False) -> int:
- """A helper to repeatedly print to the same line.
- Args:
- s: The text to be printed.
- fill_num_chars: This should be `0` on the first call to
- print_same_line() for a series of prints to the same output line. Then
- it should be the return value of the previous call to
- print_same_line() repeatedly until `done` is True, at which time the
- cursor will be moved to the next output line.
- done: On the final call to print_same_line() for a given line of output,
- pass `True` to have the cursor move to the next line.
- Returns:
- The number of characters that were written, which should be passed as
- `fill_num_chars` on the next call. At the end of printing over the same
- line, finish by calling with `done` set to true, which will move to the
- next line."""
- s += " " * (fill_num_chars - len(s))
- if not done:
- print("\r" + s, end="")
- else:
- print("\r" + s)
- return len(s)
|