gitbolt 0.0.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitbolt/__init__.py +18 -0
- gitbolt/_internal_init.py +18 -0
- gitbolt/add.py +652 -0
- gitbolt/base.py +333 -0
- gitbolt/exceptions.py +46 -0
- gitbolt/git_subprocess/__init__.py +14 -0
- gitbolt/git_subprocess/_internal_init.py +9 -0
- gitbolt/git_subprocess/add.py +484 -0
- gitbolt/git_subprocess/base.py +436 -0
- gitbolt/git_subprocess/constants.py +13 -0
- gitbolt/git_subprocess/exceptions.py +110 -0
- gitbolt/git_subprocess/impl/__init__.py +6 -0
- gitbolt/git_subprocess/impl/simple.py +185 -0
- gitbolt/git_subprocess/ls_tree.py +384 -0
- gitbolt/git_subprocess/runner/__init__.py +8 -0
- gitbolt/git_subprocess/runner/base.py +64 -0
- gitbolt/git_subprocess/runner/simple_impl.py +89 -0
- gitbolt/git_subprocess/utils.py +179 -0
- gitbolt/ls_tree.py +155 -0
- gitbolt/models.py +686 -0
- gitbolt/py.typed +0 -0
- gitbolt/utils.py +179 -0
- gitbolt-0.0.0.dev1.dist-info/METADATA +308 -0
- gitbolt-0.0.0.dev1.dist-info/RECORD +27 -0
- gitbolt-0.0.0.dev1.dist-info/WHEEL +5 -0
- gitbolt-0.0.0.dev1.dist-info/licenses/LICENSE +201 -0
- gitbolt-0.0.0.dev1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding=utf-8
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Simple and direct implementations of git commands using subprocess calls.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import ABC
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import override
|
|
13
|
+
|
|
14
|
+
from vt.utils.commons.commons.op import RootDirOp
|
|
15
|
+
|
|
16
|
+
from gitbolt.add import AddArgsValidator
|
|
17
|
+
from gitbolt.git_subprocess import (
|
|
18
|
+
GitCommand,
|
|
19
|
+
VersionCommand,
|
|
20
|
+
LsTreeCommand,
|
|
21
|
+
GitSubcmdCommand,
|
|
22
|
+
AddCommand,
|
|
23
|
+
)
|
|
24
|
+
from gitbolt.git_subprocess.add import AddCLIArgsBuilder
|
|
25
|
+
from gitbolt.git_subprocess.constants import VERSION_CMD
|
|
26
|
+
from gitbolt.git_subprocess.ls_tree import LsTreeCLIArgsBuilder
|
|
27
|
+
from gitbolt.git_subprocess.runner import GitCommandRunner
|
|
28
|
+
from gitbolt.git_subprocess.runner.simple_impl import SimpleGitCR
|
|
29
|
+
from gitbolt.ls_tree import LsTreeArgsValidator
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class GitSubcmdCommandImpl(GitSubcmdCommand, ABC):
|
|
33
|
+
def __init__(self, git: GitCommand):
|
|
34
|
+
self._underlying_git = git
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def underlying_git(self) -> GitCommand:
|
|
38
|
+
return self._underlying_git
|
|
39
|
+
|
|
40
|
+
def _set_underlying_git(self, git: "GitCommand") -> None:
|
|
41
|
+
self._underlying_git = git
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class VersionCommandImpl(VersionCommand, GitSubcmdCommandImpl):
|
|
45
|
+
@override
|
|
46
|
+
def version(self, build_options: bool = False) -> str:
|
|
47
|
+
self._require_valid_args(build_options)
|
|
48
|
+
main_cmd_args = self.underlying_git.build_main_cmd_args()
|
|
49
|
+
sub_cmd_args = [VERSION_CMD]
|
|
50
|
+
if build_options:
|
|
51
|
+
sub_cmd_args.append("--build-options")
|
|
52
|
+
return self.underlying_git.runner.run_git_command(
|
|
53
|
+
main_cmd_args, sub_cmd_args, check=True, text=True, capture_output=True
|
|
54
|
+
).stdout.strip()
|
|
55
|
+
|
|
56
|
+
def clone(self) -> "VersionCommandImpl":
|
|
57
|
+
return VersionCommandImpl(self.underlying_git)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class LsTreeCommandImpl(LsTreeCommand, GitSubcmdCommandImpl):
|
|
61
|
+
def __init__(
|
|
62
|
+
self,
|
|
63
|
+
git_root_dir: Path,
|
|
64
|
+
git: GitCommand,
|
|
65
|
+
*,
|
|
66
|
+
args_validator: LsTreeArgsValidator | None = None,
|
|
67
|
+
cli_args_builder: LsTreeCLIArgsBuilder | None = None,
|
|
68
|
+
):
|
|
69
|
+
"""
|
|
70
|
+
``ls-tree`` cli command implementation using subprocess.
|
|
71
|
+
|
|
72
|
+
:param git_root_dir: Path to the Git repository root.
|
|
73
|
+
:param git: Underlying Git command interface.
|
|
74
|
+
:param args_validator: Optional custom argument validator. If None, uses the default from superclass.
|
|
75
|
+
:param cli_args_builder: Optional CLI args builder. If None, uses the default from superclass.
|
|
76
|
+
"""
|
|
77
|
+
super().__init__(git)
|
|
78
|
+
self._git_root_dir = git_root_dir
|
|
79
|
+
self._args_validator = args_validator or super().args_validator
|
|
80
|
+
self._cli_args_builder = cli_args_builder or super().cli_args_builder
|
|
81
|
+
|
|
82
|
+
@override
|
|
83
|
+
@property
|
|
84
|
+
def root_dir(self) -> Path:
|
|
85
|
+
return self._git_root_dir
|
|
86
|
+
|
|
87
|
+
@override
|
|
88
|
+
@property
|
|
89
|
+
def args_validator(self) -> LsTreeArgsValidator:
|
|
90
|
+
return self._args_validator
|
|
91
|
+
|
|
92
|
+
@override
|
|
93
|
+
@property
|
|
94
|
+
def cli_args_builder(self) -> LsTreeCLIArgsBuilder:
|
|
95
|
+
return self._cli_args_builder
|
|
96
|
+
|
|
97
|
+
def clone(self) -> "LsTreeCommandImpl":
|
|
98
|
+
return LsTreeCommandImpl(self.root_dir, self.underlying_git)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class AddCommandImpl(AddCommand, GitSubcmdCommandImpl):
|
|
102
|
+
def __init__(
|
|
103
|
+
self,
|
|
104
|
+
root_dir: Path,
|
|
105
|
+
git: GitCommand,
|
|
106
|
+
*,
|
|
107
|
+
args_validator: AddArgsValidator | None = None,
|
|
108
|
+
cli_args_builder: AddCLIArgsBuilder | None = None,
|
|
109
|
+
):
|
|
110
|
+
super().__init__(git)
|
|
111
|
+
self._root_dir = root_dir
|
|
112
|
+
self._args_validator = args_validator or super().args_validator
|
|
113
|
+
self._cli_args_builder = cli_args_builder or super().cli_args_builder
|
|
114
|
+
|
|
115
|
+
@override
|
|
116
|
+
@property
|
|
117
|
+
def root_dir(self) -> Path:
|
|
118
|
+
return self._root_dir
|
|
119
|
+
|
|
120
|
+
@override
|
|
121
|
+
@property
|
|
122
|
+
def args_validator(self) -> AddArgsValidator:
|
|
123
|
+
return self._args_validator
|
|
124
|
+
|
|
125
|
+
@override
|
|
126
|
+
@property
|
|
127
|
+
def cli_args_builder(self) -> AddCLIArgsBuilder:
|
|
128
|
+
return self._cli_args_builder
|
|
129
|
+
|
|
130
|
+
def clone(self) -> "AddCommandImpl":
|
|
131
|
+
return AddCommandImpl(self.root_dir, self.underlying_git)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class SimpleGitCommand(GitCommand, RootDirOp):
|
|
135
|
+
def __init__(
|
|
136
|
+
self,
|
|
137
|
+
git_root_dir: Path = Path.cwd(),
|
|
138
|
+
runner: GitCommandRunner = SimpleGitCR(),
|
|
139
|
+
*,
|
|
140
|
+
version_subcmd: VersionCommand | None = None,
|
|
141
|
+
ls_tree_subcmd: LsTreeCommand | None = None,
|
|
142
|
+
add_subcmd: AddCommand | None = None,
|
|
143
|
+
):
|
|
144
|
+
super().__init__(runner)
|
|
145
|
+
self.git_root_dir = git_root_dir
|
|
146
|
+
self._version_subcmd = version_subcmd or VersionCommandImpl(self)
|
|
147
|
+
self._ls_tree = ls_tree_subcmd or LsTreeCommandImpl(self.root_dir, self)
|
|
148
|
+
self._add_subcmd = add_subcmd or AddCommandImpl(self.root_dir, self)
|
|
149
|
+
|
|
150
|
+
@override
|
|
151
|
+
@property
|
|
152
|
+
def version_subcmd(self) -> VersionCommand:
|
|
153
|
+
return self._version_subcmd
|
|
154
|
+
|
|
155
|
+
@override
|
|
156
|
+
@property
|
|
157
|
+
def ls_tree_subcmd(self) -> LsTreeCommand:
|
|
158
|
+
return self._ls_tree
|
|
159
|
+
|
|
160
|
+
@override
|
|
161
|
+
@property
|
|
162
|
+
def add_subcmd(self) -> AddCommand:
|
|
163
|
+
return self._add_subcmd
|
|
164
|
+
|
|
165
|
+
@override
|
|
166
|
+
def clone(self) -> "SimpleGitCommand":
|
|
167
|
+
# region obtain class instance
|
|
168
|
+
cloned = SimpleGitCommand(
|
|
169
|
+
self.root_dir,
|
|
170
|
+
self.runner,
|
|
171
|
+
version_subcmd=self.version_subcmd,
|
|
172
|
+
ls_tree_subcmd=self.ls_tree_subcmd,
|
|
173
|
+
add_subcmd=self.add_subcmd,
|
|
174
|
+
)
|
|
175
|
+
# endregion
|
|
176
|
+
# region clone protected members
|
|
177
|
+
cloned._main_cmd_opts = self._main_cmd_opts
|
|
178
|
+
cloned._env_vars = self._env_vars
|
|
179
|
+
# endregion
|
|
180
|
+
return cloned
|
|
181
|
+
|
|
182
|
+
@override
|
|
183
|
+
@property
|
|
184
|
+
def root_dir(self) -> Path:
|
|
185
|
+
return self.git_root_dir
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding=utf-8
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Helper interfaces for ``git ls-tree`` subcommand with default implementation for subprocess calls.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import abstractmethod
|
|
9
|
+
from typing import Protocol, Unpack, override
|
|
10
|
+
|
|
11
|
+
from gitbolt.git_subprocess.constants import LS_TREE_CMD
|
|
12
|
+
from gitbolt.models import GitLsTreeOpts
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class LsTreeCLIArgsBuilder(Protocol):
|
|
16
|
+
"""
|
|
17
|
+
Interface to facilitate building of cli arguments for ``git ls-tree`` subcommand.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def build(self, tree_ish: str, **ls_tree_opts: Unpack[GitLsTreeOpts]) -> list[str]:
|
|
22
|
+
"""
|
|
23
|
+
Build the complete list of subcommand arguments to be passed to ``git ls-tree``.
|
|
24
|
+
|
|
25
|
+
This method assembles the subcommand portion of the git command invocation, such as
|
|
26
|
+
in ``git --no-pager ls-tree -r HEAD``, where ``-r HEAD`` is the subcommand argument list.
|
|
27
|
+
|
|
28
|
+
It delegates the formation of each argument to protected helper methods to allow
|
|
29
|
+
easier overriding and testing of individual components.
|
|
30
|
+
|
|
31
|
+
Includes support for:
|
|
32
|
+
|
|
33
|
+
- Boolean flags (e.g., -r, -t, --name-only)
|
|
34
|
+
- Optional key-value arguments (e.g., --abbrev=N, --format=FMT)
|
|
35
|
+
- Required tree-ish identifier
|
|
36
|
+
- Optional file path list
|
|
37
|
+
|
|
38
|
+
:param tree_ish: A tree-ish identifier (commit SHA, branch name, etc.).
|
|
39
|
+
:param ls_tree_opts: Keyword arguments mapping to supported options for ``git ls-tree``.
|
|
40
|
+
:return: Complete list of subcommand arguments.
|
|
41
|
+
:raises GitExitingException: if undesired argument type or argument combination is supplied.
|
|
42
|
+
"""
|
|
43
|
+
...
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class IndividuallyOverridableLTCAB(LsTreeCLIArgsBuilder):
|
|
47
|
+
"""
|
|
48
|
+
Individually Overridable Ls Tree CLI Args Builder.
|
|
49
|
+
|
|
50
|
+
Build CLI args to run ``git ls-tree`` subcommand in a subprocess. This class is independent in its working and
|
|
51
|
+
provides interface to individually override each arg former for fine-grained control.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
@override
|
|
55
|
+
def build(self, tree_ish: str, **ls_tree_opts: Unpack[GitLsTreeOpts]) -> list[str]:
|
|
56
|
+
"""
|
|
57
|
+
Build the full list of arguments to be passed to ``git ls-tree``.
|
|
58
|
+
|
|
59
|
+
This includes flags, optional arguments, tree-ish identifier, and optional paths.
|
|
60
|
+
|
|
61
|
+
>>> builder = IndividuallyOverridableLTCAB()
|
|
62
|
+
|
|
63
|
+
* Basic case: only tree-ish::
|
|
64
|
+
|
|
65
|
+
>>> builder.build("HEAD")
|
|
66
|
+
['ls-tree', 'HEAD']
|
|
67
|
+
|
|
68
|
+
* With single boolean option::
|
|
69
|
+
|
|
70
|
+
>>> builder.build("HEAD", r=True)
|
|
71
|
+
['ls-tree', '-r', 'HEAD']
|
|
72
|
+
|
|
73
|
+
* With multiple boolean flags::
|
|
74
|
+
|
|
75
|
+
>>> builder.build("HEAD", r=True, t=True, d=True)
|
|
76
|
+
['ls-tree', '-d', '-r', '-t', 'HEAD']
|
|
77
|
+
|
|
78
|
+
* Long listing format::
|
|
79
|
+
|
|
80
|
+
>>> builder.build("HEAD", long=True)
|
|
81
|
+
['ls-tree', '-l', 'HEAD']
|
|
82
|
+
|
|
83
|
+
* All common flags::
|
|
84
|
+
|
|
85
|
+
>>> builder.build("HEAD", r=True, t=True, long=True, z=True,
|
|
86
|
+
... name_only=True, full_name=True, full_tree=True)
|
|
87
|
+
['ls-tree', '-r', '-t', '-l', '-z', '--name-only', '--full-name', '--full-tree', 'HEAD']
|
|
88
|
+
|
|
89
|
+
* With --name-status::
|
|
90
|
+
|
|
91
|
+
>>> builder.build("HEAD", name_status=True)
|
|
92
|
+
['ls-tree', '--name-status', 'HEAD']
|
|
93
|
+
|
|
94
|
+
* With --object-only::
|
|
95
|
+
|
|
96
|
+
>>> builder.build("HEAD", object_only=True)
|
|
97
|
+
['ls-tree', '--object-only', 'HEAD']
|
|
98
|
+
|
|
99
|
+
* With --abbrev (edge cases)::
|
|
100
|
+
|
|
101
|
+
>>> builder.build("HEAD", abbrev=0)
|
|
102
|
+
['ls-tree', '--abbrev=0', 'HEAD']
|
|
103
|
+
>>> builder.build("HEAD", abbrev=40)
|
|
104
|
+
['ls-tree', '--abbrev=40', 'HEAD']
|
|
105
|
+
>>> builder.build("HEAD", abbrev=7)
|
|
106
|
+
['ls-tree', '--abbrev=7', 'HEAD']
|
|
107
|
+
|
|
108
|
+
* With --format::
|
|
109
|
+
|
|
110
|
+
>>> builder.build("HEAD", format_="%(objectname)")
|
|
111
|
+
['ls-tree', '--format=%(objectname)', 'HEAD']
|
|
112
|
+
>>> builder.build("HEAD", format_="")
|
|
113
|
+
['ls-tree', '--format=', 'HEAD']
|
|
114
|
+
|
|
115
|
+
* With paths::
|
|
116
|
+
|
|
117
|
+
>>> builder.build("HEAD", path=["src", "README.md"])
|
|
118
|
+
['ls-tree', 'HEAD', 'src', 'README.md']
|
|
119
|
+
|
|
120
|
+
* With flags and paths::
|
|
121
|
+
|
|
122
|
+
>>> builder.build("HEAD", r=True, path=["src/module.py"])
|
|
123
|
+
['ls-tree', '-r', 'HEAD', 'src/module.py']
|
|
124
|
+
|
|
125
|
+
* All supported options::
|
|
126
|
+
|
|
127
|
+
>>> builder.build(
|
|
128
|
+
... "HEAD",
|
|
129
|
+
... d=True,
|
|
130
|
+
... r=True,
|
|
131
|
+
... t=True,
|
|
132
|
+
... long=True,
|
|
133
|
+
... z=True,
|
|
134
|
+
... name_only=True,
|
|
135
|
+
... name_status=False,
|
|
136
|
+
... object_only=True,
|
|
137
|
+
... full_name=True,
|
|
138
|
+
... full_tree=True,
|
|
139
|
+
... abbrev=10,
|
|
140
|
+
... format_="%(objectname) %(path)",
|
|
141
|
+
... path=["dir1", "dir2/file.txt"]
|
|
142
|
+
... )
|
|
143
|
+
['ls-tree', '-d', '-r', '-t', '-l', '-z', '--name-only', '--object-only', '--full-name', '--full-tree', '--abbrev=10', '--format=%(objectname) %(path)', 'HEAD', 'dir1', 'dir2/file.txt']
|
|
144
|
+
|
|
145
|
+
* Empty or falsy values, mostly will fail at validation::
|
|
146
|
+
|
|
147
|
+
>>> builder.build("HEAD", d=False,
|
|
148
|
+
... abbrev=None, # type: ignore[arg-type] # expected int provided None
|
|
149
|
+
... path=[],
|
|
150
|
+
... format_=None) # type: ignore[arg-type] # expected str provided None
|
|
151
|
+
['ls-tree', 'HEAD']
|
|
152
|
+
"""
|
|
153
|
+
sub_cmd_args = [LS_TREE_CMD]
|
|
154
|
+
|
|
155
|
+
sub_cmd_args.extend(self.d_arg(ls_tree_opts.get("d")))
|
|
156
|
+
sub_cmd_args.extend(self.r_arg(ls_tree_opts.get("r")))
|
|
157
|
+
sub_cmd_args.extend(self.t_arg(ls_tree_opts.get("t")))
|
|
158
|
+
sub_cmd_args.extend(self.long_arg(ls_tree_opts.get("long")))
|
|
159
|
+
sub_cmd_args.extend(self.z_arg(ls_tree_opts.get("z")))
|
|
160
|
+
sub_cmd_args.extend(self.name_only_arg(ls_tree_opts.get("name_only")))
|
|
161
|
+
sub_cmd_args.extend(self.name_status_arg(ls_tree_opts.get("name_status")))
|
|
162
|
+
sub_cmd_args.extend(self.object_only_arg(ls_tree_opts.get("object_only")))
|
|
163
|
+
sub_cmd_args.extend(self.full_name_arg(ls_tree_opts.get("full_name")))
|
|
164
|
+
sub_cmd_args.extend(self.full_tree_arg(ls_tree_opts.get("full_tree")))
|
|
165
|
+
|
|
166
|
+
sub_cmd_args.extend(self.abbrev_arg(ls_tree_opts.get("abbrev")))
|
|
167
|
+
sub_cmd_args.extend(self.format_arg(ls_tree_opts.get("format_")))
|
|
168
|
+
|
|
169
|
+
sub_cmd_args.extend(self.tree_ish_arg(tree_ish))
|
|
170
|
+
sub_cmd_args.extend(self.path_args(ls_tree_opts.get("path")))
|
|
171
|
+
|
|
172
|
+
return sub_cmd_args
|
|
173
|
+
|
|
174
|
+
def d_arg(self, d: bool | None) -> list[str]:
|
|
175
|
+
"""
|
|
176
|
+
Return ``-d`` if `d` is True.
|
|
177
|
+
|
|
178
|
+
:param d: Whether to include the ``-d`` option.
|
|
179
|
+
:return: List containing ``-d`` if applicable.
|
|
180
|
+
|
|
181
|
+
>>> IndividuallyOverridableLTCAB().d_arg(True)
|
|
182
|
+
['-d']
|
|
183
|
+
>>> IndividuallyOverridableLTCAB().d_arg(False)
|
|
184
|
+
[]
|
|
185
|
+
>>> IndividuallyOverridableLTCAB().d_arg(None)
|
|
186
|
+
[]
|
|
187
|
+
"""
|
|
188
|
+
return ["-d"] if d else []
|
|
189
|
+
|
|
190
|
+
def r_arg(self, r: bool | None) -> list[str]:
|
|
191
|
+
"""
|
|
192
|
+
Return ``-r`` if `r` is True.
|
|
193
|
+
|
|
194
|
+
:param r: Whether to include the ``-r`` option.
|
|
195
|
+
:return: List containing ``-r`` if applicable.
|
|
196
|
+
|
|
197
|
+
>>> IndividuallyOverridableLTCAB().r_arg(True)
|
|
198
|
+
['-r']
|
|
199
|
+
>>> IndividuallyOverridableLTCAB().r_arg(False)
|
|
200
|
+
[]
|
|
201
|
+
>>> IndividuallyOverridableLTCAB().r_arg(None)
|
|
202
|
+
[]
|
|
203
|
+
"""
|
|
204
|
+
return ["-r"] if r else []
|
|
205
|
+
|
|
206
|
+
def t_arg(self, t: bool | None) -> list[str]:
|
|
207
|
+
"""
|
|
208
|
+
Return ``-t`` if `t` is True.
|
|
209
|
+
|
|
210
|
+
:param t: Whether to include the ``-t`` option.
|
|
211
|
+
:return: List containing ``-t`` if applicable.
|
|
212
|
+
|
|
213
|
+
>>> IndividuallyOverridableLTCAB().t_arg(True)
|
|
214
|
+
['-t']
|
|
215
|
+
>>> IndividuallyOverridableLTCAB().t_arg(False)
|
|
216
|
+
[]
|
|
217
|
+
>>> IndividuallyOverridableLTCAB().t_arg(None)
|
|
218
|
+
[]
|
|
219
|
+
"""
|
|
220
|
+
return ["-t"] if t else []
|
|
221
|
+
|
|
222
|
+
def long_arg(self, long: bool | None) -> list[str]:
|
|
223
|
+
"""
|
|
224
|
+
Return ``-l`` if `long` is True.
|
|
225
|
+
|
|
226
|
+
:param long: Whether to include the ``-l`` option.
|
|
227
|
+
:return: List containing ``-l`` if applicable.
|
|
228
|
+
|
|
229
|
+
>>> IndividuallyOverridableLTCAB().long_arg(True)
|
|
230
|
+
['-l']
|
|
231
|
+
>>> IndividuallyOverridableLTCAB().long_arg(False)
|
|
232
|
+
[]
|
|
233
|
+
>>> IndividuallyOverridableLTCAB().long_arg(None)
|
|
234
|
+
[]
|
|
235
|
+
"""
|
|
236
|
+
return ["-l"] if long else []
|
|
237
|
+
|
|
238
|
+
def z_arg(self, z: bool | None) -> list[str]:
|
|
239
|
+
"""
|
|
240
|
+
Return ``-z`` if `z` is True.
|
|
241
|
+
|
|
242
|
+
:param z: Whether to include the ``-z`` option.
|
|
243
|
+
:return: List containing ``-z`` if applicable.
|
|
244
|
+
|
|
245
|
+
>>> IndividuallyOverridableLTCAB().z_arg(True)
|
|
246
|
+
['-z']
|
|
247
|
+
>>> IndividuallyOverridableLTCAB().z_arg(False)
|
|
248
|
+
[]
|
|
249
|
+
>>> IndividuallyOverridableLTCAB().z_arg(None)
|
|
250
|
+
[]
|
|
251
|
+
"""
|
|
252
|
+
return ["-z"] if z else []
|
|
253
|
+
|
|
254
|
+
def name_only_arg(self, name_only: bool | None) -> list[str]:
|
|
255
|
+
"""
|
|
256
|
+
Return ``--name-only`` if applicable.
|
|
257
|
+
|
|
258
|
+
>>> IndividuallyOverridableLTCAB().name_only_arg(True)
|
|
259
|
+
['--name-only']
|
|
260
|
+
>>> IndividuallyOverridableLTCAB().name_only_arg(False)
|
|
261
|
+
[]
|
|
262
|
+
>>> IndividuallyOverridableLTCAB().name_only_arg(None)
|
|
263
|
+
[]
|
|
264
|
+
"""
|
|
265
|
+
return ["--name-only"] if name_only else []
|
|
266
|
+
|
|
267
|
+
def name_status_arg(self, name_status: bool | None) -> list[str]:
|
|
268
|
+
"""
|
|
269
|
+
Return ``--name-status`` if applicable.
|
|
270
|
+
|
|
271
|
+
>>> IndividuallyOverridableLTCAB().name_status_arg(True)
|
|
272
|
+
['--name-status']
|
|
273
|
+
>>> IndividuallyOverridableLTCAB().name_status_arg(False)
|
|
274
|
+
[]
|
|
275
|
+
>>> IndividuallyOverridableLTCAB().name_status_arg(None)
|
|
276
|
+
[]
|
|
277
|
+
"""
|
|
278
|
+
return ["--name-status"] if name_status else []
|
|
279
|
+
|
|
280
|
+
def object_only_arg(self, object_only: bool | None) -> list[str]:
|
|
281
|
+
"""
|
|
282
|
+
Return ``--object-only`` if applicable.
|
|
283
|
+
|
|
284
|
+
>>> IndividuallyOverridableLTCAB().object_only_arg(True)
|
|
285
|
+
['--object-only']
|
|
286
|
+
>>> IndividuallyOverridableLTCAB().object_only_arg(False)
|
|
287
|
+
[]
|
|
288
|
+
>>> IndividuallyOverridableLTCAB().object_only_arg(None)
|
|
289
|
+
[]
|
|
290
|
+
"""
|
|
291
|
+
return ["--object-only"] if object_only else []
|
|
292
|
+
|
|
293
|
+
def full_name_arg(self, full_name: bool | None) -> list[str]:
|
|
294
|
+
"""
|
|
295
|
+
Return ``--full-name`` if applicable.
|
|
296
|
+
|
|
297
|
+
>>> IndividuallyOverridableLTCAB().full_name_arg(True)
|
|
298
|
+
['--full-name']
|
|
299
|
+
>>> IndividuallyOverridableLTCAB().full_name_arg(False)
|
|
300
|
+
[]
|
|
301
|
+
>>> IndividuallyOverridableLTCAB().full_name_arg(None)
|
|
302
|
+
[]
|
|
303
|
+
"""
|
|
304
|
+
return ["--full-name"] if full_name else []
|
|
305
|
+
|
|
306
|
+
def full_tree_arg(self, full_tree: bool | None) -> list[str]:
|
|
307
|
+
"""
|
|
308
|
+
Return ``--full-tree`` if applicable.
|
|
309
|
+
|
|
310
|
+
>>> IndividuallyOverridableLTCAB().full_tree_arg(True)
|
|
311
|
+
['--full-tree']
|
|
312
|
+
>>> IndividuallyOverridableLTCAB().full_tree_arg(False)
|
|
313
|
+
[]
|
|
314
|
+
>>> IndividuallyOverridableLTCAB().full_tree_arg(None)
|
|
315
|
+
[]
|
|
316
|
+
"""
|
|
317
|
+
return ["--full-tree"] if full_tree else []
|
|
318
|
+
|
|
319
|
+
def abbrev_arg(self, abbrev: int | None) -> list[str]:
|
|
320
|
+
"""
|
|
321
|
+
Format ``--abbrev=N`` if `abbrev` is provided.
|
|
322
|
+
|
|
323
|
+
:param abbrev: Abbreviation length (0-40 inclusive).
|
|
324
|
+
:return: List containing formatted option or empty list.
|
|
325
|
+
|
|
326
|
+
>>> IndividuallyOverridableLTCAB().abbrev_arg(None)
|
|
327
|
+
[]
|
|
328
|
+
>>> IndividuallyOverridableLTCAB().abbrev_arg(7)
|
|
329
|
+
['--abbrev=7']
|
|
330
|
+
>>> IndividuallyOverridableLTCAB().abbrev_arg(0)
|
|
331
|
+
['--abbrev=0']
|
|
332
|
+
>>> IndividuallyOverridableLTCAB().abbrev_arg(40)
|
|
333
|
+
['--abbrev=40']
|
|
334
|
+
"""
|
|
335
|
+
return [f"--abbrev={abbrev}"] if abbrev is not None else []
|
|
336
|
+
|
|
337
|
+
def format_arg(self, _format: str | None) -> list[str]:
|
|
338
|
+
"""
|
|
339
|
+
Format ``--format=...`` if `_format` is provided.
|
|
340
|
+
|
|
341
|
+
:param _format: A valid format string.
|
|
342
|
+
:return: List containing formatted option or empty list.
|
|
343
|
+
|
|
344
|
+
>>> IndividuallyOverridableLTCAB().format_arg(None)
|
|
345
|
+
[]
|
|
346
|
+
>>> IndividuallyOverridableLTCAB().format_arg('%(objectname)')
|
|
347
|
+
['--format=%(objectname)']
|
|
348
|
+
>>> IndividuallyOverridableLTCAB().format_arg('')
|
|
349
|
+
['--format=']
|
|
350
|
+
"""
|
|
351
|
+
return [f"--format={_format}"] if _format is not None else []
|
|
352
|
+
|
|
353
|
+
def tree_ish_arg(self, tree_ish: str) -> list[str]:
|
|
354
|
+
"""
|
|
355
|
+
Return the required tree-ish identifier as a single-element list.
|
|
356
|
+
|
|
357
|
+
This value is typically a commit SHA, branch name, tag, or other valid tree reference
|
|
358
|
+
and is appended at the end of the formed git subcommand options, just before path(s).
|
|
359
|
+
|
|
360
|
+
>>> IndividuallyOverridableLTCAB().tree_ish_arg("HEAD")
|
|
361
|
+
['HEAD']
|
|
362
|
+
>>> IndividuallyOverridableLTCAB().tree_ish_arg("origin/main")
|
|
363
|
+
['origin/main']
|
|
364
|
+
>>> IndividuallyOverridableLTCAB().tree_ish_arg("a1b2c3d")
|
|
365
|
+
['a1b2c3d']
|
|
366
|
+
>>> IndividuallyOverridableLTCAB().tree_ish_arg("")
|
|
367
|
+
['']
|
|
368
|
+
"""
|
|
369
|
+
return [tree_ish]
|
|
370
|
+
|
|
371
|
+
def path_args(self, path: list[str] | None) -> list[str]:
|
|
372
|
+
"""
|
|
373
|
+
Return the list of paths (if any) passed to ``git ls-tree``.
|
|
374
|
+
|
|
375
|
+
If `path` is None or an empty list, this returns an empty list.
|
|
376
|
+
|
|
377
|
+
>>> IndividuallyOverridableLTCAB().path_args(["src", "README.md"])
|
|
378
|
+
['src', 'README.md']
|
|
379
|
+
>>> IndividuallyOverridableLTCAB().path_args([])
|
|
380
|
+
[]
|
|
381
|
+
>>> IndividuallyOverridableLTCAB().path_args(None)
|
|
382
|
+
[]
|
|
383
|
+
"""
|
|
384
|
+
return path if path else []
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding=utf-8
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Git command runner interfaces to run subprocess calls.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from abc import abstractmethod
|
|
11
|
+
from subprocess import CompletedProcess
|
|
12
|
+
from typing import Protocol, overload, Any, Literal
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class GitCommandRunner(Protocol):
|
|
16
|
+
"""
|
|
17
|
+
Interface to facilitate running git commands in subprocess.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
@overload
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def run_git_command(
|
|
23
|
+
self,
|
|
24
|
+
main_cmd_args: list[str],
|
|
25
|
+
subcommand_args: list[str],
|
|
26
|
+
*subprocess_run_args: Any,
|
|
27
|
+
_input: str,
|
|
28
|
+
text: Literal[True],
|
|
29
|
+
**subprocess_run_kwargs: Any,
|
|
30
|
+
) -> CompletedProcess[str]: ...
|
|
31
|
+
|
|
32
|
+
@overload
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def run_git_command(
|
|
35
|
+
self,
|
|
36
|
+
main_cmd_args: list[str],
|
|
37
|
+
subcommand_args: list[str],
|
|
38
|
+
*subprocess_run_args: Any,
|
|
39
|
+
_input: bytes,
|
|
40
|
+
text: Literal[False],
|
|
41
|
+
**subprocess_run_kwargs: Any,
|
|
42
|
+
) -> CompletedProcess[bytes]: ...
|
|
43
|
+
|
|
44
|
+
@overload
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def run_git_command(
|
|
47
|
+
self,
|
|
48
|
+
main_cmd_args: list[str],
|
|
49
|
+
subcommand_args: list[str],
|
|
50
|
+
*subprocess_run_args: Any,
|
|
51
|
+
text: Literal[True],
|
|
52
|
+
**subprocess_run_kwargs: Any,
|
|
53
|
+
) -> CompletedProcess[str]: ...
|
|
54
|
+
|
|
55
|
+
@overload
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def run_git_command(
|
|
58
|
+
self,
|
|
59
|
+
main_cmd_args: list[str],
|
|
60
|
+
subcommand_args: list[str],
|
|
61
|
+
*subprocess_run_args: Any,
|
|
62
|
+
text: Literal[False] = ...,
|
|
63
|
+
**subprocess_run_kwargs: Any,
|
|
64
|
+
) -> CompletedProcess[bytes]: ...
|