/
niceSOFT
/
python3-setuptools_scm
Обзор
Документация
Войти
/
niceSOFT
/
python3-setuptools_scm
Код
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
vcs-versioning/src/vcs_versioning/_cli/__init__.py
232 строки
7 KB
pre-commit-ci[bot]
style: pre-commit fixes
03 авг 2026, 21:57
03 авг 2026, 21:57
8a32949
Код
Авторство
О чём код?
from __future__ import annotations import json import os import sys from collections.abc import Iterable if sys.version_info >= (3, 9): from importlib.resources import files else: from importlib.resources import read_text as _read_text from pathlib import Path from typing import TypedDict from vcs_versioning._overrides import ConfigOverridesDict from .. import _discover as discover from .._config import Configuration from .._get_version_impl import _get_version from .._pyproject_reading import PyProjectData from ._args import CliNamespace, get_cli_parser class OutputData(TypedDict, ConfigOverridesDict, total=False): version: str files: list[str] queries: list[str] def _get_version_for_cli(config: Configuration, opts: CliNamespace) -> str: """Get version string for CLI output, handling special cases and exceptions.""" if opts.no_version: return "0.0.0+no-version-was-requested.fake-version" version = _get_version( config, force_write_version_files=opts.force_write_version_files ) if version is None: raise SystemExit("ERROR: no version found for", opts) if opts.strip_dev: version = version.partition(".dev")[0] return version def main( args: list[str] | None = None, *, _given_pyproject_data: PyProjectData | None = None ) -> int: from .._environment import VcsEnvironment from ..overrides import GlobalOverrides # Apply global overrides for the entire CLI execution # Logging is automatically configured when entering the context with GlobalOverrides.from_env("SETUPTOOLS_SCM"): env = VcsEnvironment.from_env("SETUPTOOLS_SCM") parser = get_cli_parser("python -m vcs_versioning") opts = parser.parse_args(args, namespace=CliNamespace()) inferred_root: str = opts.root or "." pyproject = opts.config or _find_pyproject(inferred_root) try: config = env.build_config( name=pyproject, root=(os.path.abspath(opts.root) if opts.root is not None else None), pyproject_data=_given_pyproject_data, ) except (LookupError, FileNotFoundError) as ex: # no pyproject.toml OR no [tool.setuptools_scm] print( f"Warning: could not use {os.path.relpath(pyproject)}," " using default configuration.\n" f" Reason: {ex}.", file=sys.stderr, ) config = Configuration(root=inferred_root, _env=env) version = _get_version_for_cli(config, opts) return command(opts, version, config) def command(opts: CliNamespace, version: str, config: Configuration) -> int: data: OutputData = {} if opts.command == "ls": opts.query = ["files"] if opts.command == "create-archival-file": return _create_archival_file(opts, config) if opts.query == []: opts.no_version = True sys.stderr.write("Available queries:\n\n") opts.query = ["queries"] data["queries"] = ["files", *config.__dataclass_fields__] if opts.query is None: opts.query = [] if not opts.no_version: data["version"] = version if "files" in opts.query: from .._file_finders import find_files data["files"] = find_files(config.root) for q in opts.query: if q in ["files", "queries", "version"]: continue try: if q.startswith("_"): raise AttributeError() data[q] = getattr(config, q) # type: ignore[literal-required] except AttributeError: sys.stderr.write(f"Error: unknown query: '{q}'\n") return 1 PRINT_FUNCTIONS[opts.format](data) return 0 def print_json(data: OutputData) -> None: print(json.dumps(data, indent=2)) def print_plain(data: OutputData) -> None: version = data.pop("version", None) if version: print(version) files = data.pop("files", []) for file_ in files: print(file_) queries = data.pop("queries", []) for query in queries: print(query) if data: print("\n".join(map(str, data.values()))) def print_key_value(data: OutputData) -> None: for key, value in data.items(): if isinstance(value, str): print(f"{key} = {value}") else: assert isinstance(value, Iterable) str_value = "\n ".join(map(str, value)) print(f"{key} = {str_value}") PRINT_FUNCTIONS = { "json": print_json, "plain": print_plain, "key-value": print_key_value, } def _find_pyproject(parent: str) -> str: for directory in discover.walk_potential_roots(os.path.abspath(parent)): pyproject = os.path.join(directory, "pyproject.toml") if os.path.isfile(pyproject): return pyproject return os.path.abspath( "pyproject.toml" ) # use default name to trigger the default errors def _create_archival_file(opts: CliNamespace, config: Configuration) -> int: """Create .git_archival.txt file with appropriate content.""" archival_path = Path(config.root, ".git_archival.txt") # Check if file exists and force flag if archival_path.exists() and not opts.force: print( f"Error: {archival_path} already exists. Use --force to overwrite.", file=sys.stderr, ) return 1 # archival_template is guaranteed to be set by required mutually exclusive group assert opts.archival_template is not None # Load template content from package resources if sys.version_info >= (3, 9): content = files(__package__).joinpath(opts.archival_template).read_text("utf-8") else: content = _read_text(__package__, opts.archival_template, encoding="utf-8") # Print appropriate message based on template if opts.archival_template == "git_archival_stable.txt": print("Creating stable .git_archival.txt (recommended for releases)") elif opts.archival_template == "git_archival_full.txt": print("Creating full .git_archival.txt with branch information") print("WARNING: This can cause archive checksums to be unstable!") try: archival_path.write_text(content, encoding="utf-8") print(f"Created: {archival_path}") gitattributes_path = Path(config.root, ".gitattributes") needs_gitattributes = True if gitattributes_path.exists(): # TODO: more nuanced check later gitattributes_content = gitattributes_path.read_text("utf-8") if ( ".git_archival.txt" in gitattributes_content and "export-subst" in gitattributes_content ): needs_gitattributes = False if needs_gitattributes: print("\nNext steps:") print("1. Add this line to .gitattributes:") print(" .git_archival.txt export-subst") print("2. Commit both files:") print(" git add .git_archival.txt .gitattributes") print(" git commit -m 'add git archive support'") else: print("\nNext step:") print("Commit the archival file:") print(" git add .git_archival.txt") print(" git commit -m 'update git archival file'") return 0 except OSError as e: print(f"Error: Could not create {archival_path}: {e}", file=sys.stderr) return 1