123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- import json
- import shlex
- import subprocess
- from typing import (
- Any,
- Dict,
- Iterable,
- List,
- Optional,
- Tuple,
- Union
- )
- from dataladmetadatamodel.log import logger
- from dataladmetadatamodel.mapper.reference import Reference
- def execute(arguments: Union[str, List[str]],
- stdin_content: Optional[Union[str, bytes]] = None) -> Any:
- logger.debug(f"gitbackend: execute({arguments}, {stdin_content})")
- return subprocess.run(
- shlex.split(arguments) if isinstance(arguments, str) else arguments,
- input=(
- stdin_content.encode()
- if isinstance(stdin_content, str)
- else stdin_content),
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- def checked_execute(arguments: Union[str, List[str]],
- stdin_content: Optional[Union[str, bytes]] = None
- ) -> Tuple[List[str], List[str]]:
- result = execute(arguments, stdin_content)
- if result.returncode != 0:
- raise RuntimeError(
- f"Command failed (exit code: {result.returncode}) "
- f"{' '.join(arguments)}:\n"
- f"STDOUT:\n"
- f"{result.stdout.decode()}"
- f"STDERR:\n"
- f"{result.stderr.decode()}")
- return (
- result.stdout.decode().splitlines(),
- result.stderr.decode().splitlines())
- def git_command_line(repo_dir: str,
- command: str,
- arguments: List[str]
- ) -> List[str]:
- return [
- "git",
- "-P",
- "--git-dir",
- repo_dir + "/.git",
- command
- ] + arguments
- def git_text_result(cmd_line):
- result = checked_execute(cmd_line)[0]
- return "\n".join(result)
- def adapt_for_remote(repo_dir: str, object_reference: str) -> str:
- from dataladmetadatamodel.mapper.gitmapper.localcache import (
- cache_object,
- get_cache_realm,
- )
- if Reference.is_remote(repo_dir):
- cache_object(repo_dir, object_reference)
- return str(get_cache_realm(repo_dir))
- return repo_dir
- def git_load_str(repo_dir: str, object_reference: str) -> str:
- repo_dir = adapt_for_remote(repo_dir, object_reference)
- cmd_line = git_command_line(repo_dir, "show", [object_reference])
- return git_text_result(cmd_line)
- def git_load_json(repo_dir: str, object_reference: str) -> Union[Dict, List]:
- repo_dir = adapt_for_remote(repo_dir, object_reference)
- return json.loads(git_load_str(repo_dir, object_reference))
- def git_init(repo_dir: str) -> None:
- cmd_line = ["git", "init", repo_dir]
- checked_execute(cmd_line)
- def git_object_exists_locally(repo_dir: str,
- object_reference) -> bool:
- cmd_line = git_command_line(repo_dir, "cat-file", ["-e", object_reference])
- return execute(cmd_line).returncode == 0
- def git_read_tree_node(repo_dir: str,
- object_reference) -> List[str]:
- repo_dir = adapt_for_remote(repo_dir, object_reference)
- cmd_line = git_command_line(repo_dir, "cat-file", ["-p", object_reference])
- return checked_execute(cmd_line)[0]
- def git_ls_tree(repo_dir, object_reference) -> List[str]:
- repo_dir = adapt_for_remote(repo_dir, object_reference)
- cmd_line = git_command_line(repo_dir, "ls-tree", [object_reference])
- return checked_execute(cmd_line)[0]
- def git_ls_tree_recursive(repo_dir, object_reference, show_intermediate=False) -> List[str]:
- repo_dir = adapt_for_remote(repo_dir, object_reference)
- if show_intermediate is True:
- cmd_line = git_command_line(repo_dir, "ls-tree", ["-r", "-t", object_reference])
- else:
- cmd_line = git_command_line(repo_dir, "ls-tree", ["-r", object_reference])
- return checked_execute(cmd_line)[0]
- def git_save_str(repo_dir, content: str) -> str:
- cmd_line = git_command_line(repo_dir, "hash-object", ["-w", "--stdin"])
- return checked_execute(cmd_line, stdin_content=content)[0][0]
- def git_save_file_list(repo_dir, file_list: List[str]) -> List[str]:
- cmd_line = git_command_line(
- repo_dir,
- "hash-object",
- ["-w", "--no-filters", "--stdin-paths"])
- return checked_execute(
- cmd_line,
- stdin_content="\n".join(file_list))[0]
- def git_save_json(repo_dir, json_object: Union[Dict, List]) -> str:
- return git_save_str(repo_dir, json.dumps(json_object))
- def git_save_tree_node(repo_dir,
- entry_set: Iterable[Tuple[str, str, str, str]]
- ) -> str:
- tree_spec = "\n".join([
- f"{flag} {node_type} {object_hash}\t{name}"
- for flag, node_type, object_hash, name in entry_set
- ]) + "\n"
- cmd_line = git_command_line(repo_dir, "mktree", ["--missing", ])
- return checked_execute(cmd_line, stdin_content=tree_spec)[0][0]
- def git_save_tree(repo_dir,
- entry_set: Iterable[Tuple[str, str, str, str]]
- ) -> str:
- tree_spec = "\n".join([
- f"{flag} {node_type} {object_hash}\t{name}"
- for flag, node_type, object_hash, name in entry_set
- ]) + "\n"
- cmd_line = git_command_line(repo_dir, "mktree", ["--missing", ])
- return checked_execute(cmd_line, stdin_content=tree_spec)[0][0]
- def git_update_ref(repo_dir: str, ref_name: str, location: str) -> None:
- cmd_line = git_command_line(
- repo_dir,
- "update-ref",
- [ref_name, location])
- checked_execute(cmd_line)
- def git_fetch_object(repo_dir: str,
- remote_repo: str,
- remote_reference: str):
- return git_fetch_reference(repo_dir, remote_repo, remote_reference)
- def git_fetch_reference(repo_dir: str,
- remote_repo: str,
- remote_reference: str,
- local_reference: Optional[str] = None):
- cmd_line = git_command_line(
- repo_dir,
- "fetch",
- [
- remote_repo,
- "-f",
- "--no-tags",
- "--no-recurse-submodules",
- remote_reference + (
- f":{local_reference}"
- if local_reference is not None
- else ""
- )
- ]
- )
- checked_execute(cmd_line)
|