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
gitbolt/add.py
ADDED
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# coding=utf-8
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Helper interfaces specific to ``git add`` subcommand.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import abstractmethod
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Protocol, Unpack, override, Literal
|
|
11
|
+
|
|
12
|
+
from gitbolt._internal_init import errmsg_creator
|
|
13
|
+
from gitbolt.exceptions import GitExitingException
|
|
14
|
+
from gitbolt.models import GitAddOpts
|
|
15
|
+
from vt.utils.commons.commons.core_py import has_atleast_one_arg, ensure_atleast_one_arg
|
|
16
|
+
from vt.utils.errors.error_specs import ERR_DATA_FORMAT_ERR, ERR_INVALID_USAGE
|
|
17
|
+
from vt.utils.errors.error_specs.utils import require_type
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AddArgsValidator(Protocol):
|
|
21
|
+
"""
|
|
22
|
+
The argument validator for ``git add`` subcommand.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def validate(
|
|
27
|
+
self,
|
|
28
|
+
pathspec: str | None = None,
|
|
29
|
+
*pathspecs: str,
|
|
30
|
+
pathspec_from_file: Path | Literal["-"] | None = None,
|
|
31
|
+
pathspec_stdin: str | None = None,
|
|
32
|
+
pathspec_file_nul: bool = False,
|
|
33
|
+
**add_opts: Unpack[GitAddOpts],
|
|
34
|
+
) -> None:
|
|
35
|
+
"""
|
|
36
|
+
Validate the inputs provided to the ``git add`` command.
|
|
37
|
+
|
|
38
|
+
This function ensures logical and type-safe usage of arguments that map to the
|
|
39
|
+
``git add`` subcommand, enforcing mutual exclusivity, argument completeness,
|
|
40
|
+
and correct typing.
|
|
41
|
+
|
|
42
|
+
Specifically, it validates:
|
|
43
|
+
|
|
44
|
+
* That at least one of ``pathspec`` or ``pathspecs`` is provided unless using ``pathspec_from_file``.
|
|
45
|
+
* That ``pathspec_from_file`` and ``pathspec_stdin`` are not used alongside direct pathspecs.
|
|
46
|
+
* That if ``pathspec_from_file == '-'``, then ``pathspec_stdin`` must be provided.
|
|
47
|
+
* That ``pathspec_stdin`` is not provided unless ``pathspec_from_file == '-'``.
|
|
48
|
+
* That ``pathspec_file_nul`` is a boolean.
|
|
49
|
+
* That each field in ``add_opts`` is correctly typed according to the GitAddOpts spec.
|
|
50
|
+
|
|
51
|
+
All validations will raise a ``GitExitingException`` with a specific exit code depending
|
|
52
|
+
on the nature of the failure:
|
|
53
|
+
|
|
54
|
+
* ``TypeError`` leads to ``ERR_DATA_FORMAT_ERR``.
|
|
55
|
+
* ``ValueError`` leads to ``ERR_INVALID_USAGE``.
|
|
56
|
+
|
|
57
|
+
See: `git add documentation <https://git-scm.com/docs/git-add>`_.
|
|
58
|
+
|
|
59
|
+
:param pathspec: A direct file or directory to stage. Cannot be used with ``pathspec_from_file``.
|
|
60
|
+
:type pathspec: str | None
|
|
61
|
+
:param pathspecs: Additional pathspecs to stage.
|
|
62
|
+
:type pathspecs: str
|
|
63
|
+
:param pathspec_from_file: A file to read pathspecs from. Use ``'-'`` to read from stdin.
|
|
64
|
+
:type pathspec_from_file: Path | Literal['-'] | None
|
|
65
|
+
:param pathspec_stdin: Required if ``pathspec_from_file == '-'``. Denotes stdin content.
|
|
66
|
+
:type pathspec_stdin: str | None
|
|
67
|
+
:param pathspec_file_nul: Whether input lines in ``pathspec_from_file`` are NUL-separated.
|
|
68
|
+
:type pathspec_file_nul: bool
|
|
69
|
+
:param add_opts: Options accepted by the ``git add`` subcommand.
|
|
70
|
+
:type add_opts: Unpack[GitAddOpts]
|
|
71
|
+
:raises GitExitingException: When validation fails.
|
|
72
|
+
"""
|
|
73
|
+
...
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class UtilAddArgsValidator(AddArgsValidator):
|
|
77
|
+
"""
|
|
78
|
+
Independent utility function sort of interface to perform add() arguments validation.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
@override
|
|
82
|
+
def validate(
|
|
83
|
+
self,
|
|
84
|
+
pathspec: str | None = None,
|
|
85
|
+
*pathspecs: str,
|
|
86
|
+
pathspec_from_file: Path | Literal["-"] | None = None,
|
|
87
|
+
pathspec_stdin: str | None = None,
|
|
88
|
+
pathspec_file_nul: bool = False,
|
|
89
|
+
**add_opts: Unpack[GitAddOpts],
|
|
90
|
+
) -> None:
|
|
91
|
+
"""
|
|
92
|
+
Examples::
|
|
93
|
+
|
|
94
|
+
>>> UtilAddArgsValidator().validate("README.md", verbose=True)
|
|
95
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file='-', pathspec_stdin="README.md")
|
|
96
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file=Path("list.txt"))
|
|
97
|
+
>>> UtilAddArgsValidator().validate("foo/bar.txt", dry_run=True)
|
|
98
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file=Path("paths.txt"), pathspec_file_nul=True)
|
|
99
|
+
>>> UtilAddArgsValidator().validate("a.txt", "b.txt", force=True, chmod="+x")
|
|
100
|
+
|
|
101
|
+
Invalid Examples::
|
|
102
|
+
|
|
103
|
+
>>> UtilAddArgsValidator().validate("file.txt", pathspec_file_nul=True)
|
|
104
|
+
Traceback (most recent call last):
|
|
105
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_file_nul and pathspec are not allowed together
|
|
106
|
+
|
|
107
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file='-', pathspec_stdin=None)
|
|
108
|
+
Traceback (most recent call last):
|
|
109
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_stdin must be provided when pathspec_form_file is -
|
|
110
|
+
|
|
111
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file=Path("x.txt"), pathspec_stdin="foo")
|
|
112
|
+
Traceback (most recent call last):
|
|
113
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_stdin is not allowed unless pathspec_from_file is '-'.
|
|
114
|
+
|
|
115
|
+
>>> UtilAddArgsValidator().validate(123) # type: ignore[arg-type]
|
|
116
|
+
Traceback (most recent call last):
|
|
117
|
+
gitbolt.exceptions.GitExitingException: TypeError: pathspec must be a string.
|
|
118
|
+
|
|
119
|
+
>>> UtilAddArgsValidator().validate("README.md", pathspec_from_file=Path("foo"))
|
|
120
|
+
Traceback (most recent call last):
|
|
121
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec and pathspec_from_file are not allowed together
|
|
122
|
+
|
|
123
|
+
>>> UtilAddArgsValidator().validate("README.md", chmod="bad") # type: ignore[arg-type]
|
|
124
|
+
Traceback (most recent call last):
|
|
125
|
+
gitbolt.exceptions.GitExitingException: ValueError: Unexpected chmod value. Choose from '+x' and '-x'.
|
|
126
|
+
|
|
127
|
+
>>> UtilAddArgsValidator().validate("README.md", verbose="true") # type: ignore[arg-type]
|
|
128
|
+
Traceback (most recent call last):
|
|
129
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'verbose' must be a boolean
|
|
130
|
+
|
|
131
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file="file.txt") # type: ignore[arg-type]
|
|
132
|
+
Traceback (most recent call last):
|
|
133
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'pathspec_from_file' must be a pathlib.Path or the string literal '-'.
|
|
134
|
+
|
|
135
|
+
>>> UtilAddArgsValidator().validate(pathspec_stdin="README.md")
|
|
136
|
+
Traceback (most recent call last):
|
|
137
|
+
gitbolt.exceptions.GitExitingException: ValueError: Either pathspec or pathspec_from_file is required
|
|
138
|
+
|
|
139
|
+
>>> UtilAddArgsValidator().validate(pathspec="a.py",
|
|
140
|
+
... chmod="777") # type: ignore[arg-type] # expected +x, -x or None # provided int
|
|
141
|
+
Traceback (most recent call last):
|
|
142
|
+
gitbolt.exceptions.GitExitingException: ValueError: Unexpected chmod value. Choose from '+x' and '-x'.
|
|
143
|
+
|
|
144
|
+
>>> UtilAddArgsValidator().validate(pathspec="a.py",
|
|
145
|
+
... no_all="yes") # type: ignore[arg-type] # expected bool # provided int
|
|
146
|
+
Traceback (most recent call last):
|
|
147
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'no_all' must be either True, False, or None
|
|
148
|
+
|
|
149
|
+
>>> UtilAddArgsValidator().validate(pathspec="a.py",
|
|
150
|
+
... renormalize="sometimes") # type: ignore[arg-type] # expected bool # provided str
|
|
151
|
+
Traceback (most recent call last):
|
|
152
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'renormalize' must be a boolean
|
|
153
|
+
|
|
154
|
+
>>> UtilAddArgsValidator().validate(verbose=True)
|
|
155
|
+
Traceback (most recent call last):
|
|
156
|
+
gitbolt.exceptions.GitExitingException: ValueError: Either pathspec or pathspec_from_file is required
|
|
157
|
+
"""
|
|
158
|
+
self.mandate_required_arguments(
|
|
159
|
+
pathspec,
|
|
160
|
+
*pathspecs,
|
|
161
|
+
pathspec_from_file=pathspec_from_file,
|
|
162
|
+
pathspec_stdin=pathspec_stdin,
|
|
163
|
+
)
|
|
164
|
+
self.validate_exclusive_args(
|
|
165
|
+
pathspec,
|
|
166
|
+
*pathspecs,
|
|
167
|
+
pathspec_from_file=pathspec_from_file,
|
|
168
|
+
pathspec_stdin=pathspec_stdin,
|
|
169
|
+
pathspec_file_nul=pathspec_file_nul,
|
|
170
|
+
)
|
|
171
|
+
self.validate_git_add_opts(**add_opts)
|
|
172
|
+
self.validate_non_git_add_opts(
|
|
173
|
+
pathspec_file_nul, pathspec_from_file, pathspec_stdin
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def mandate_required_arguments(
|
|
177
|
+
self,
|
|
178
|
+
pathspec: str | None,
|
|
179
|
+
*pathspecs: str,
|
|
180
|
+
pathspec_from_file: Path | Literal["-"] | None,
|
|
181
|
+
pathspec_stdin: str | None,
|
|
182
|
+
):
|
|
183
|
+
"""
|
|
184
|
+
One of ``pathspec``, ``pathspec_from_file`` or ``pathspec_from_file=- pathspec_stdin`` must be provided.
|
|
185
|
+
|
|
186
|
+
Examples:
|
|
187
|
+
|
|
188
|
+
* All three provided, no issue:
|
|
189
|
+
|
|
190
|
+
>>> UtilAddArgsValidator().mandate_required_arguments('add.py', 'more-add.py', 'even-more.txt',
|
|
191
|
+
... pathspec_from_file=Path('a-file.txt'), pathspec_stdin='a str')
|
|
192
|
+
|
|
193
|
+
* Pairs provided, no issue:
|
|
194
|
+
|
|
195
|
+
>>> UtilAddArgsValidator().mandate_required_arguments('add.py', 'more-add.py', 'even-more.txt',
|
|
196
|
+
... pathspec_from_file=Path('a-file.txt'), pathspec_stdin=None)
|
|
197
|
+
>>> UtilAddArgsValidator().mandate_required_arguments('add.py', 'more-add.py', 'even-more.txt',
|
|
198
|
+
... pathspec_from_file=None, pathspec_stdin='a stdin str')
|
|
199
|
+
>>> UtilAddArgsValidator().mandate_required_arguments(None, pathspec_from_file=Path('a-file.txt'),
|
|
200
|
+
... pathspec_stdin='a stdin str')
|
|
201
|
+
|
|
202
|
+
* Provided single required, no issue:
|
|
203
|
+
|
|
204
|
+
>>> UtilAddArgsValidator().mandate_required_arguments('add.py', pathspec_from_file=None, pathspec_stdin=None)
|
|
205
|
+
>>> UtilAddArgsValidator().mandate_required_arguments('add.py', 'more-add.py', 'even-more.txt', pathspec_from_file=None, pathspec_stdin=None)
|
|
206
|
+
>>> UtilAddArgsValidator().mandate_required_arguments(None, pathspec_from_file=Path('a-file.txt'), pathspec_stdin=None)
|
|
207
|
+
|
|
208
|
+
* Provided ``pathspec_stdin`` with pathpec_from_file=-``, no issue:
|
|
209
|
+
|
|
210
|
+
>>> UtilAddArgsValidator().mandate_required_arguments(None, pathspec_from_file='-', pathspec_stdin='stdin pathspec')
|
|
211
|
+
|
|
212
|
+
Error examples:
|
|
213
|
+
|
|
214
|
+
* No mandatory args provided:
|
|
215
|
+
|
|
216
|
+
>>> UtilAddArgsValidator().mandate_required_arguments(None, pathspec_from_file=None, pathspec_stdin=None)
|
|
217
|
+
Traceback (most recent call last):
|
|
218
|
+
gitbolt.exceptions.GitExitingException: ValueError: Either pathspec or pathspec_from_file is required
|
|
219
|
+
|
|
220
|
+
* ``pathspec_stdin`` not provided when ``pathspec_from_file=-``:
|
|
221
|
+
|
|
222
|
+
>>> UtilAddArgsValidator().mandate_required_arguments(None, pathspec_from_file='-', pathspec_stdin=None)
|
|
223
|
+
Traceback (most recent call last):
|
|
224
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_stdin must be provided when pathspec_form_file is -
|
|
225
|
+
|
|
226
|
+
:raises GitExitingException: if no mandatory args are provided.
|
|
227
|
+
"""
|
|
228
|
+
if (
|
|
229
|
+
not has_atleast_one_arg(pathspec, *pathspecs, enforce_type=False)
|
|
230
|
+
and pathspec_from_file is None
|
|
231
|
+
):
|
|
232
|
+
errmsg = errmsg_creator.at_least_one_required(
|
|
233
|
+
"pathspec", "pathspec_from_file"
|
|
234
|
+
)
|
|
235
|
+
raise GitExitingException(
|
|
236
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
237
|
+
) from ValueError(errmsg)
|
|
238
|
+
if pathspec_from_file == "-" and pathspec_stdin is None:
|
|
239
|
+
errmsg = "pathspec_stdin must be provided when pathspec_form_file is -"
|
|
240
|
+
raise GitExitingException(
|
|
241
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
242
|
+
) from ValueError(errmsg)
|
|
243
|
+
|
|
244
|
+
def validate_exclusive_args(
|
|
245
|
+
self,
|
|
246
|
+
pathspec: str | None,
|
|
247
|
+
*pathspecs: str,
|
|
248
|
+
pathspec_from_file: Path | Literal["-"] | None,
|
|
249
|
+
pathspec_stdin: str | None,
|
|
250
|
+
pathspec_file_nul: bool | None,
|
|
251
|
+
) -> None:
|
|
252
|
+
"""
|
|
253
|
+
Method added so that subclasses may override as they please.
|
|
254
|
+
|
|
255
|
+
Check that exclusive args are not provided together.
|
|
256
|
+
|
|
257
|
+
Examples::
|
|
258
|
+
|
|
259
|
+
>>> UtilAddArgsValidator().validate("file.txt", pathspec_file_nul=True)
|
|
260
|
+
Traceback (most recent call last):
|
|
261
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_file_nul and pathspec are not allowed together
|
|
262
|
+
|
|
263
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file='-', pathspec_stdin=None)
|
|
264
|
+
Traceback (most recent call last):
|
|
265
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_stdin must be provided when pathspec_form_file is -
|
|
266
|
+
|
|
267
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file='-')
|
|
268
|
+
Traceback (most recent call last):
|
|
269
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_stdin must be provided when pathspec_form_file is -
|
|
270
|
+
|
|
271
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file=Path("x.txt"), pathspec_stdin="foo")
|
|
272
|
+
Traceback (most recent call last):
|
|
273
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec_stdin is not allowed unless pathspec_from_file is '-'.
|
|
274
|
+
|
|
275
|
+
>>> UtilAddArgsValidator().validate("README.md", pathspec_from_file=Path("foo"))
|
|
276
|
+
Traceback (most recent call last):
|
|
277
|
+
gitbolt.exceptions.GitExitingException: ValueError: pathspec and pathspec_from_file are not allowed together
|
|
278
|
+
|
|
279
|
+
>>> UtilAddArgsValidator().validate(pathspec_from_file="file.txt") # type: ignore[arg-type]
|
|
280
|
+
Traceback (most recent call last):
|
|
281
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'pathspec_from_file' must be a pathlib.Path or the string literal '-'.
|
|
282
|
+
|
|
283
|
+
>>> UtilAddArgsValidator().validate(pathspec_stdin="README.md")
|
|
284
|
+
Traceback (most recent call last):
|
|
285
|
+
gitbolt.exceptions.GitExitingException: ValueError: Either pathspec or pathspec_from_file is required
|
|
286
|
+
|
|
287
|
+
:raises GitExitingException: if exclusive args are provided together.
|
|
288
|
+
"""
|
|
289
|
+
if has_atleast_one_arg(pathspec, *pathspecs, enforce_type=False):
|
|
290
|
+
try:
|
|
291
|
+
ensure_atleast_one_arg(pathspec, *pathspecs, enforce_type=str)
|
|
292
|
+
except TypeError as te:
|
|
293
|
+
raise GitExitingException(
|
|
294
|
+
"pathspec must be a string.", exit_code=ERR_DATA_FORMAT_ERR
|
|
295
|
+
) from te
|
|
296
|
+
|
|
297
|
+
if pathspec_from_file is not None:
|
|
298
|
+
errmsg = errmsg_creator.not_allowed_together(
|
|
299
|
+
"pathspec", "pathspec_from_file"
|
|
300
|
+
)
|
|
301
|
+
raise GitExitingException(
|
|
302
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
303
|
+
) from ValueError(errmsg)
|
|
304
|
+
if pathspec_stdin is not None:
|
|
305
|
+
errmsg = errmsg_creator.not_allowed_together(
|
|
306
|
+
"pathspec", "pathspec_stdin"
|
|
307
|
+
)
|
|
308
|
+
raise GitExitingException(
|
|
309
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
310
|
+
) from ValueError(errmsg)
|
|
311
|
+
if pathspec_file_nul:
|
|
312
|
+
errmsg = errmsg_creator.not_allowed_together(
|
|
313
|
+
"pathspec_file_nul", "pathspec"
|
|
314
|
+
)
|
|
315
|
+
raise GitExitingException(
|
|
316
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
317
|
+
) from ValueError(errmsg)
|
|
318
|
+
if pathspec_from_file == "-" and pathspec_stdin is None:
|
|
319
|
+
errmsg = errmsg_creator.all_required(
|
|
320
|
+
"pathspec_stdin",
|
|
321
|
+
"pathspec_from_file",
|
|
322
|
+
suffix=" when pathspec_from_file is '-'.",
|
|
323
|
+
)
|
|
324
|
+
raise GitExitingException(
|
|
325
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
326
|
+
) from ValueError(errmsg)
|
|
327
|
+
if pathspec_from_file != "-" and pathspec_stdin is not None:
|
|
328
|
+
errmsg = "pathspec_stdin is not allowed unless pathspec_from_file is '-'."
|
|
329
|
+
raise GitExitingException(
|
|
330
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
331
|
+
) from ValueError(errmsg)
|
|
332
|
+
|
|
333
|
+
# region validate_git_add_opts
|
|
334
|
+
def validate_git_add_opts(self, **add_opts: Unpack[GitAddOpts]) -> None:
|
|
335
|
+
"""
|
|
336
|
+
Validate Git add command specific options.
|
|
337
|
+
Delegates to specialized validation methods.
|
|
338
|
+
|
|
339
|
+
>>> UtilAddArgsValidator().validate_git_add_opts(verbose=True, chmod='+x', no_all=False)
|
|
340
|
+
>>> UtilAddArgsValidator().validate_git_add_opts(verbose='yes') # type: ignore[arg-type] # expected bool provided str
|
|
341
|
+
Traceback (most recent call last):
|
|
342
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'verbose' must be a boolean
|
|
343
|
+
"""
|
|
344
|
+
self.validate_bool_args(**add_opts)
|
|
345
|
+
self.validate_tri_state_args(**add_opts)
|
|
346
|
+
self.validate_chmod_arg(add_opts.get("chmod"))
|
|
347
|
+
|
|
348
|
+
# region validate_bool_args
|
|
349
|
+
def validate_bool_args(self, **bool_add_opts: Unpack[GitAddOpts]) -> None:
|
|
350
|
+
"""
|
|
351
|
+
Validate boolean Git add options like 'verbose', 'dry_run', etc.
|
|
352
|
+
|
|
353
|
+
>>> UtilAddArgsValidator().validate_bool_args(verbose=True)
|
|
354
|
+
>>> UtilAddArgsValidator().validate_bool_args(verbose='true') # type: ignore[arg-type] # expected bool provided str
|
|
355
|
+
Traceback (most recent call last):
|
|
356
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'verbose' must be a boolean
|
|
357
|
+
"""
|
|
358
|
+
if "verbose" in bool_add_opts:
|
|
359
|
+
self.validate_verbose_bool_arg(bool_add_opts["verbose"])
|
|
360
|
+
if "dry_run" in bool_add_opts:
|
|
361
|
+
self.validate_dry_run_bool_arg(bool_add_opts["dry_run"])
|
|
362
|
+
if "force" in bool_add_opts:
|
|
363
|
+
self.validate_force_bool_arg(bool_add_opts["force"])
|
|
364
|
+
if "interactive" in bool_add_opts:
|
|
365
|
+
self.validate_interactive_bool_arg(bool_add_opts["interactive"])
|
|
366
|
+
if "patch" in bool_add_opts:
|
|
367
|
+
self.validate_patch_bool_arg(bool_add_opts["patch"])
|
|
368
|
+
if "edit" in bool_add_opts:
|
|
369
|
+
self.validate_edit_bool_arg(bool_add_opts["edit"])
|
|
370
|
+
if "sparse" in bool_add_opts:
|
|
371
|
+
self.validate_sparse_bool_arg(bool_add_opts["sparse"])
|
|
372
|
+
if "intent_to_add" in bool_add_opts:
|
|
373
|
+
self.validate_intent_to_add_bool_arg(bool_add_opts["intent_to_add"])
|
|
374
|
+
if "refresh" in bool_add_opts:
|
|
375
|
+
self.validate_refresh_bool_arg(bool_add_opts["refresh"])
|
|
376
|
+
if "ignore_errors" in bool_add_opts:
|
|
377
|
+
self.validate_ignore_errors_bool_arg(bool_add_opts["ignore_errors"])
|
|
378
|
+
if "ignore_missing" in bool_add_opts:
|
|
379
|
+
self.validate_ignore_missing_bool_arg(bool_add_opts["ignore_missing"])
|
|
380
|
+
if "renormalize" in bool_add_opts:
|
|
381
|
+
self.validate_renormalize_bool_arg(bool_add_opts["renormalize"])
|
|
382
|
+
|
|
383
|
+
def validate_verbose_bool_arg(self, verbose: bool) -> None:
|
|
384
|
+
"""Validate `verbose` argument.
|
|
385
|
+
|
|
386
|
+
>>> UtilAddArgsValidator().validate_verbose_bool_arg(True)
|
|
387
|
+
>>> UtilAddArgsValidator().validate_verbose_bool_arg('yes') # type: ignore[arg-type] # expected bool provided str
|
|
388
|
+
Traceback (most recent call last):
|
|
389
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'verbose' must be a boolean
|
|
390
|
+
"""
|
|
391
|
+
require_type(verbose, "verbose", bool, GitExitingException)
|
|
392
|
+
|
|
393
|
+
def validate_dry_run_bool_arg(self, dry_run: bool) -> None:
|
|
394
|
+
"""Validate `dry_run` argument.
|
|
395
|
+
|
|
396
|
+
>>> UtilAddArgsValidator().validate_dry_run_bool_arg(False)
|
|
397
|
+
>>> UtilAddArgsValidator().validate_dry_run_bool_arg(1) # type: ignore[arg-type] # expected bool provided int
|
|
398
|
+
Traceback (most recent call last):
|
|
399
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'dry_run' must be a boolean
|
|
400
|
+
"""
|
|
401
|
+
require_type(dry_run, "dry_run", bool, GitExitingException)
|
|
402
|
+
|
|
403
|
+
def validate_force_bool_arg(self, force: bool) -> None:
|
|
404
|
+
"""Validate `force` argument.
|
|
405
|
+
|
|
406
|
+
>>> UtilAddArgsValidator().validate_force_bool_arg(True)
|
|
407
|
+
>>> UtilAddArgsValidator().validate_force_bool_arg('true') # type: ignore[arg-type] # expected bool provided str
|
|
408
|
+
Traceback (most recent call last):
|
|
409
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'force' must be a boolean
|
|
410
|
+
"""
|
|
411
|
+
require_type(force, "force", bool, GitExitingException)
|
|
412
|
+
|
|
413
|
+
def validate_interactive_bool_arg(self, interactive: bool) -> None:
|
|
414
|
+
"""Validate `interactive` argument.
|
|
415
|
+
|
|
416
|
+
>>> UtilAddArgsValidator().validate_interactive_bool_arg(False)
|
|
417
|
+
>>> UtilAddArgsValidator().validate_interactive_bool_arg('false') # type: ignore[arg-type] # expected bool provided str
|
|
418
|
+
Traceback (most recent call last):
|
|
419
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'interactive' must be a boolean
|
|
420
|
+
"""
|
|
421
|
+
require_type(interactive, "interactive", bool, GitExitingException)
|
|
422
|
+
|
|
423
|
+
def validate_patch_bool_arg(self, patch: bool) -> None:
|
|
424
|
+
"""Validate `patch` argument.
|
|
425
|
+
|
|
426
|
+
>>> UtilAddArgsValidator().validate_patch_bool_arg(True)
|
|
427
|
+
>>> UtilAddArgsValidator().validate_patch_bool_arg(0.1) # type: ignore[arg-type] # expected bool provided float
|
|
428
|
+
Traceback (most recent call last):
|
|
429
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'patch' must be a boolean
|
|
430
|
+
"""
|
|
431
|
+
require_type(patch, "patch", bool, GitExitingException)
|
|
432
|
+
|
|
433
|
+
def validate_edit_bool_arg(self, edit: bool) -> None:
|
|
434
|
+
"""Validate `edit` argument.
|
|
435
|
+
|
|
436
|
+
>>> UtilAddArgsValidator().validate_edit_bool_arg(True)
|
|
437
|
+
>>> UtilAddArgsValidator().validate_edit_bool_arg('no') # type: ignore[arg-type] # expected bool provided str
|
|
438
|
+
Traceback (most recent call last):
|
|
439
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'edit' must be a boolean
|
|
440
|
+
"""
|
|
441
|
+
require_type(edit, "edit", bool, GitExitingException)
|
|
442
|
+
|
|
443
|
+
def validate_sparse_bool_arg(self, sparse: bool) -> None:
|
|
444
|
+
"""Validate `sparse` argument.
|
|
445
|
+
|
|
446
|
+
>>> UtilAddArgsValidator().validate_sparse_bool_arg(True)
|
|
447
|
+
>>> UtilAddArgsValidator().validate_sparse_bool_arg(None) # type: ignore[arg-type] # expected bool provided None
|
|
448
|
+
Traceback (most recent call last):
|
|
449
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'sparse' must be a boolean
|
|
450
|
+
"""
|
|
451
|
+
require_type(sparse, "sparse", bool, GitExitingException)
|
|
452
|
+
|
|
453
|
+
def validate_intent_to_add_bool_arg(self, intent_to_add: bool) -> None:
|
|
454
|
+
"""Validate `intent_to_add` argument.
|
|
455
|
+
|
|
456
|
+
>>> UtilAddArgsValidator().validate_intent_to_add_bool_arg(False)
|
|
457
|
+
>>> UtilAddArgsValidator().validate_intent_to_add_bool_arg('maybe') # type: ignore[arg-type] # expected bool provided str
|
|
458
|
+
Traceback (most recent call last):
|
|
459
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'intent_to_add' must be a boolean
|
|
460
|
+
"""
|
|
461
|
+
require_type(intent_to_add, "intent_to_add", bool, GitExitingException)
|
|
462
|
+
|
|
463
|
+
def validate_refresh_bool_arg(self, refresh: bool) -> None:
|
|
464
|
+
"""Validate `refresh` argument.
|
|
465
|
+
|
|
466
|
+
>>> UtilAddArgsValidator().validate_refresh_bool_arg(True)
|
|
467
|
+
>>> UtilAddArgsValidator().validate_refresh_bool_arg([]) # type: ignore[arg-type] # expected bool provided list
|
|
468
|
+
Traceback (most recent call last):
|
|
469
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'refresh' must be a boolean
|
|
470
|
+
"""
|
|
471
|
+
require_type(refresh, "refresh", bool, GitExitingException)
|
|
472
|
+
|
|
473
|
+
def validate_ignore_errors_bool_arg(self, ignore_errors: bool) -> None:
|
|
474
|
+
"""Validate `ignore_errors` argument.
|
|
475
|
+
|
|
476
|
+
>>> UtilAddArgsValidator().validate_ignore_errors_bool_arg(True)
|
|
477
|
+
>>> UtilAddArgsValidator().validate_ignore_errors_bool_arg('error') # type: ignore[arg-type] # expected bool provided str
|
|
478
|
+
Traceback (most recent call last):
|
|
479
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'ignore_errors' must be a boolean
|
|
480
|
+
"""
|
|
481
|
+
require_type(ignore_errors, "ignore_errors", bool, GitExitingException)
|
|
482
|
+
|
|
483
|
+
def validate_ignore_missing_bool_arg(self, ignore_missing: bool) -> None:
|
|
484
|
+
"""Validate `ignore_missing` argument.
|
|
485
|
+
|
|
486
|
+
>>> UtilAddArgsValidator().validate_ignore_missing_bool_arg(False)
|
|
487
|
+
>>> UtilAddArgsValidator().validate_ignore_missing_bool_arg('none') # type: ignore[arg-type] # expected bool provided str
|
|
488
|
+
Traceback (most recent call last):
|
|
489
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'ignore_missing' must be a boolean
|
|
490
|
+
"""
|
|
491
|
+
require_type(ignore_missing, "ignore_missing", bool, GitExitingException)
|
|
492
|
+
|
|
493
|
+
def validate_renormalize_bool_arg(self, renormalize: bool) -> None:
|
|
494
|
+
"""
|
|
495
|
+
Validate `renormalize` argument.
|
|
496
|
+
|
|
497
|
+
>>> UtilAddArgsValidator().validate_renormalize_bool_arg(True)
|
|
498
|
+
>>> UtilAddArgsValidator().validate_renormalize_bool_arg('false') # type: ignore[arg-type] # expected bool provided str
|
|
499
|
+
Traceback (most recent call last):
|
|
500
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'renormalize' must be a boolean
|
|
501
|
+
"""
|
|
502
|
+
require_type(renormalize, "renormalize", bool, GitExitingException)
|
|
503
|
+
|
|
504
|
+
# endregion
|
|
505
|
+
|
|
506
|
+
# region validate_tri_state_args
|
|
507
|
+
def validate_tri_state_args(self, **tri_state_add_opts: Unpack[GitAddOpts]) -> None:
|
|
508
|
+
"""
|
|
509
|
+
Validate tri-state arguments that accept True, False, or None.
|
|
510
|
+
|
|
511
|
+
>>> UtilAddArgsValidator().validate_tri_state_args(no_all=None)
|
|
512
|
+
>>> UtilAddArgsValidator().validate_tri_state_args(no_all='yes') # type: ignore[arg-type] # expected [bool | None] provided str
|
|
513
|
+
Traceback (most recent call last):
|
|
514
|
+
...
|
|
515
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'no_all' must be either True, False, or None
|
|
516
|
+
"""
|
|
517
|
+
if "no_all" in tri_state_add_opts:
|
|
518
|
+
self.validate_no_all_tri_state_arg(tri_state_add_opts["no_all"])
|
|
519
|
+
if "no_ignore_removal" in tri_state_add_opts:
|
|
520
|
+
self.validate_no_ignore_removal_tri_state_arg(
|
|
521
|
+
tri_state_add_opts["no_ignore_removal"]
|
|
522
|
+
)
|
|
523
|
+
|
|
524
|
+
def validate_no_all_tri_state_arg(self, no_all: bool | None) -> None:
|
|
525
|
+
"""
|
|
526
|
+
Validate `no_all` tri-state argument.
|
|
527
|
+
|
|
528
|
+
>>> UtilAddArgsValidator().validate_no_all_tri_state_arg(True)
|
|
529
|
+
>>> UtilAddArgsValidator().validate_no_all_tri_state_arg(None)
|
|
530
|
+
>>> UtilAddArgsValidator().validate_no_all_tri_state_arg('bad') # type: ignore[arg-type] # expected [bool | None] provided str
|
|
531
|
+
Traceback (most recent call last):
|
|
532
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'no_all' must be either True, False, or None
|
|
533
|
+
"""
|
|
534
|
+
if no_all not in (True, False, None):
|
|
535
|
+
errmsg = "'no_all' must be either True, False, or None"
|
|
536
|
+
raise GitExitingException(
|
|
537
|
+
errmsg, exit_code=ERR_DATA_FORMAT_ERR
|
|
538
|
+
) from TypeError(errmsg)
|
|
539
|
+
|
|
540
|
+
def validate_no_ignore_removal_tri_state_arg(
|
|
541
|
+
self, no_ignore_removal: bool | None
|
|
542
|
+
) -> None:
|
|
543
|
+
"""
|
|
544
|
+
Validate `no_ignore_removal` tri-state argument.
|
|
545
|
+
|
|
546
|
+
>>> UtilAddArgsValidator().validate_no_ignore_removal_tri_state_arg(False)
|
|
547
|
+
>>> UtilAddArgsValidator().validate_no_ignore_removal_tri_state_arg('nope') # type: ignore[arg-type] # expected [bool | None] provided str
|
|
548
|
+
Traceback (most recent call last):
|
|
549
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'no_ignore_removal' must be either True, False, or None
|
|
550
|
+
"""
|
|
551
|
+
if no_ignore_removal not in (True, False, None):
|
|
552
|
+
errmsg = "'no_ignore_removal' must be either True, False, or None"
|
|
553
|
+
raise GitExitingException(
|
|
554
|
+
errmsg, exit_code=ERR_DATA_FORMAT_ERR
|
|
555
|
+
) from TypeError(errmsg)
|
|
556
|
+
|
|
557
|
+
# endregion
|
|
558
|
+
|
|
559
|
+
def validate_chmod_arg(self, chmod: Literal["+x", "-x"] | None) -> None:
|
|
560
|
+
"""
|
|
561
|
+
Validate `chmod` argument.
|
|
562
|
+
|
|
563
|
+
>>> UtilAddArgsValidator().validate_chmod_arg('+x')
|
|
564
|
+
>>> UtilAddArgsValidator().validate_chmod_arg(None)
|
|
565
|
+
>>> UtilAddArgsValidator().validate_chmod_arg('bad') # type: ignore[arg-type] # expected Literal[+x, -x] provided str
|
|
566
|
+
Traceback (most recent call last):
|
|
567
|
+
gitbolt.exceptions.GitExitingException: ValueError: Unexpected chmod value. Choose from '+x' and '-x'.
|
|
568
|
+
"""
|
|
569
|
+
if chmod:
|
|
570
|
+
if chmod not in ("+x", "-x"):
|
|
571
|
+
errmsg = errmsg_creator.errmsg_for_choices(
|
|
572
|
+
emphasis="chmod", choices=["+x", "-x"]
|
|
573
|
+
)
|
|
574
|
+
raise GitExitingException(
|
|
575
|
+
errmsg, exit_code=ERR_INVALID_USAGE
|
|
576
|
+
) from ValueError(errmsg)
|
|
577
|
+
|
|
578
|
+
# endregion
|
|
579
|
+
|
|
580
|
+
# region validate_non_git_add_opts
|
|
581
|
+
def validate_non_git_add_opts(
|
|
582
|
+
self,
|
|
583
|
+
pathspec_file_nul: bool,
|
|
584
|
+
pathspec_from_file: Path | Literal["-"] | None,
|
|
585
|
+
pathspec_stdin: str | None,
|
|
586
|
+
) -> None:
|
|
587
|
+
"""
|
|
588
|
+
Validate non-GitAddOpts arguments like pathspec_from_file and pathspec_stdin.
|
|
589
|
+
|
|
590
|
+
>>> validator = UtilAddArgsValidator()
|
|
591
|
+
>>> validator.validate_non_git_add_opts(False, None, None)
|
|
592
|
+
>>> validator.validate_non_git_add_opts(True, '-', 'abc')
|
|
593
|
+
>>> validator.validate_non_git_add_opts(True, '-', 123) # type: ignore[arg-type] # expected str # provided int
|
|
594
|
+
Traceback (most recent call last):
|
|
595
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'pathspec_stdin' must be a string
|
|
596
|
+
"""
|
|
597
|
+
self.validate_pathspec_file_nul(pathspec_file_nul)
|
|
598
|
+
self.validate_pathspec_from_file(pathspec_from_file)
|
|
599
|
+
self.validate_pathspec_stdin(pathspec_stdin)
|
|
600
|
+
|
|
601
|
+
def validate_pathspec_file_nul(self, pathspec_file_nul: bool) -> None:
|
|
602
|
+
"""
|
|
603
|
+
Validate `pathspec_file_nul` argument.
|
|
604
|
+
|
|
605
|
+
>>> UtilAddArgsValidator().validate_pathspec_file_nul(True)
|
|
606
|
+
>>> UtilAddArgsValidator().validate_pathspec_file_nul('yes') # type: ignore[arg-type] # expected bool # provided str
|
|
607
|
+
Traceback (most recent call last):
|
|
608
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'pathspec_file_nul' must be a boolean
|
|
609
|
+
"""
|
|
610
|
+
require_type(pathspec_file_nul, "pathspec_file_nul", bool, GitExitingException)
|
|
611
|
+
|
|
612
|
+
def validate_pathspec_from_file(
|
|
613
|
+
self, pathspec_from_file: Path | Literal["-"] | None
|
|
614
|
+
) -> None:
|
|
615
|
+
"""
|
|
616
|
+
Validate `pathspec_from_file` argument.
|
|
617
|
+
|
|
618
|
+
>>> UtilAddArgsValidator().validate_pathspec_from_file(Path("foo.txt"))
|
|
619
|
+
>>> UtilAddArgsValidator().validate_pathspec_from_file('-')
|
|
620
|
+
>>> UtilAddArgsValidator().validate_pathspec_from_file(123) # type: ignore[arg-type] # expected Path | Literal['-'] # provided int
|
|
621
|
+
Traceback (most recent call last):
|
|
622
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'pathspec_from_file' must be a pathlib.Path or the string literal '-'.
|
|
623
|
+
>>> UtilAddArgsValidator().validate_pathspec_from_file('file.txt') # type: ignore[arg-type] # expected Path | Literal['-'] # provided str
|
|
624
|
+
Traceback (most recent call last):
|
|
625
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'pathspec_from_file' must be a pathlib.Path or the string literal '-'.
|
|
626
|
+
"""
|
|
627
|
+
if pathspec_from_file is not None:
|
|
628
|
+
if (
|
|
629
|
+
not isinstance(pathspec_from_file, (Path, str))
|
|
630
|
+
or pathspec_from_file != "-"
|
|
631
|
+
and not isinstance(pathspec_from_file, Path)
|
|
632
|
+
):
|
|
633
|
+
errmsg = "'pathspec_from_file' must be a pathlib.Path or the string literal '-'."
|
|
634
|
+
raise GitExitingException(
|
|
635
|
+
errmsg, exit_code=ERR_DATA_FORMAT_ERR
|
|
636
|
+
) from TypeError(errmsg)
|
|
637
|
+
|
|
638
|
+
def validate_pathspec_stdin(self, pathspec_stdin: str | None):
|
|
639
|
+
"""
|
|
640
|
+
|
|
641
|
+
Validate `pathspec_stdin` argument.
|
|
642
|
+
|
|
643
|
+
>>> UtilAddArgsValidator().validate_pathspec_stdin('-')
|
|
644
|
+
>>> UtilAddArgsValidator().validate_pathspec_stdin('some stdin')
|
|
645
|
+
>>> UtilAddArgsValidator().validate_pathspec_stdin(123) # type: ignore[arg-type] # expected str # provided int
|
|
646
|
+
Traceback (most recent call last):
|
|
647
|
+
gitbolt.exceptions.GitExitingException: TypeError: 'pathspec_stdin' must be a string
|
|
648
|
+
"""
|
|
649
|
+
if pathspec_stdin is not None:
|
|
650
|
+
require_type(pathspec_stdin, "pathspec_stdin", str, GitExitingException)
|
|
651
|
+
|
|
652
|
+
# endregion
|