gitbolt 0.0.0.dev10__tar.gz → 0.0.0.dev12__tar.gz

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.
Files changed (36) hide show
  1. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/PKG-INFO +22 -3
  2. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/README.md +19 -0
  3. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/pyproject.toml +4 -4
  4. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/__init__.py +2 -1
  5. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/base.py +23 -7
  6. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/base.py +66 -8
  7. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/impl/simple.py +109 -18
  8. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/ls_tree.py +30 -8
  9. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt.egg-info/PKG-INFO +22 -3
  10. gitbolt-0.0.0.dev12/src/gitbolt.egg-info/requires.txt +8 -0
  11. gitbolt-0.0.0.dev10/src/gitbolt.egg-info/requires.txt +0 -8
  12. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/LICENSE +0 -0
  13. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/setup.cfg +0 -0
  14. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/_internal_init.py +0 -0
  15. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/add.py +0 -0
  16. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/constants.py +0 -0
  17. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/exceptions.py +0 -0
  18. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/__init__.py +0 -0
  19. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/_internal_init.py +0 -0
  20. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/add.py +0 -0
  21. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/constants.py +0 -0
  22. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/exceptions.py +0 -0
  23. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/impl/__init__.py +0 -0
  24. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/runner/__init__.py +0 -0
  25. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/runner/base.py +0 -0
  26. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/runner/simple_impl.py +0 -0
  27. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/git_subprocess/utils.py +0 -0
  28. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/ls_tree.py +0 -0
  29. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/models.py +0 -0
  30. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/py.typed +0 -0
  31. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/pytest_plugin.py +0 -0
  32. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt/utils.py +0 -0
  33. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt.egg-info/SOURCES.txt +0 -0
  34. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt.egg-info/dependency_links.txt +0 -0
  35. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt.egg-info/entry_points.txt +0 -0
  36. {gitbolt-0.0.0.dev10 → gitbolt-0.0.0.dev12}/src/gitbolt.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitbolt
3
- Version: 0.0.0.dev10
3
+ Version: 0.0.0.dev12
4
4
  Summary: Fast, flexible and type-safe Git commands in Python.
5
5
  Author-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
6
6
  Maintainer-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
@@ -26,8 +26,8 @@ Classifier: Typing :: Typed
26
26
  Requires-Python: >=3.12
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
- Requires-Dist: vt-err-hndlr>=0.0.0dev3
30
- Requires-Dist: vt-commons>=0.0.1.dev4
29
+ Requires-Dist: vt-err-hndlr>=0.0.0dev5
30
+ Requires-Dist: vt-commons>=0.0.1.dev9
31
31
  Provides-Extra: pygit2
32
32
  Requires-Dist: pygit2; extra == "pygit2"
33
33
  Provides-Extra: test
@@ -64,6 +64,7 @@ Dynamic: license-file
64
64
  * 🧪 **Terminal Functions:** Git subcommands are terminal functions.
65
65
  * 🧼 **Idiomatic Python:** Write commands in idiomatic Python at compile-time and be confident they’ll execute smoothly at runtime.
66
66
  * 🎀 **Add-ons:** Special features provided to ease programming with git. These can be added if required.
67
+ * 💻 **CLI-cmd:** Take commands from cli and run in `gitbolt`.
67
68
 
68
69
  ---
69
70
 
@@ -340,6 +341,24 @@ git.subcmd_unchecked.run(['--version']) # run the version option for git.
340
341
  git.subcmd_unchecked.run(['version']) # run the version subcommand.
341
342
  ```
342
343
 
344
+ #### 💻 Run commands received from CLI
345
+
346
+ Introduced in `0.0.0dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
347
+
348
+ While making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example
349
+ would be to make a system that receives CLI commands and does certain modifications/additions inside `gitbolt` before
350
+ actually running them. An example:
351
+
352
+ ```python
353
+ from gitbolt.git_subprocess.impl.simple import CLISimpleGitCommand
354
+
355
+ opts = ["--no-pager", "--namespace", "n1"] # options received from outside your program.
356
+ envs = dict(GIT_AUTHOR_NAME="ss") # env-vars received form outside your program.
357
+ git = CLISimpleGitCommand(opts=opts, envs=envs)
358
+
359
+ # these can later be overridden
360
+ git = git.git_opts_override(namespace="n2")
361
+ ```
343
362
 
344
363
  ---
345
364
 
@@ -28,6 +28,7 @@
28
28
  * 🧪 **Terminal Functions:** Git subcommands are terminal functions.
29
29
  * 🧼 **Idiomatic Python:** Write commands in idiomatic Python at compile-time and be confident they’ll execute smoothly at runtime.
30
30
  * 🎀 **Add-ons:** Special features provided to ease programming with git. These can be added if required.
31
+ * 💻 **CLI-cmd:** Take commands from cli and run in `gitbolt`.
31
32
 
32
33
  ---
33
34
 
@@ -304,6 +305,24 @@ git.subcmd_unchecked.run(['--version']) # run the version option for git.
304
305
  git.subcmd_unchecked.run(['version']) # run the version subcommand.
305
306
  ```
306
307
 
308
+ #### 💻 Run commands received from CLI
309
+
310
+ Introduced in `0.0.0dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
311
+
312
+ While making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example
313
+ would be to make a system that receives CLI commands and does certain modifications/additions inside `gitbolt` before
314
+ actually running them. An example:
315
+
316
+ ```python
317
+ from gitbolt.git_subprocess.impl.simple import CLISimpleGitCommand
318
+
319
+ opts = ["--no-pager", "--namespace", "n1"] # options received from outside your program.
320
+ envs = dict(GIT_AUTHOR_NAME="ss") # env-vars received form outside your program.
321
+ git = CLISimpleGitCommand(opts=opts, envs=envs)
322
+
323
+ # these can later be overridden
324
+ git = git.git_opts_override(namespace="n2")
325
+ ```
307
326
 
308
327
  ---
309
328
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gitbolt"
3
- version = "0.0.0dev10"
3
+ version = "0.0.0dev12"
4
4
  description = "Fast, flexible and type-safe Git commands in Python."
5
5
  requires-python = ">=3.12"
6
6
  readme = "README.md"
@@ -36,8 +36,8 @@ classifiers = [
36
36
  "Typing :: Typed"
37
37
  ]
38
38
  dependencies = [
39
- "vt-err-hndlr >= 0.0.0dev3",
40
- "vt-commons >= 0.0.1.dev4",
39
+ "vt-err-hndlr >= 0.0.0dev5",
40
+ "vt-commons >= 0.0.1.dev9",
41
41
  ]
42
42
 
43
43
  [project.optional-dependencies]
@@ -49,7 +49,7 @@ test = ['pytest']
49
49
  # btw, this error doesn't show in the latest developer version. So, this error will go away with 1.17.0 relase
50
50
  dev = ["mypy==1.15.0", "ruff"]
51
51
  doc = ['sphinx', 'sphinx-argparse']
52
- test = ["pytest", 'pytest-cov']
52
+ test = ["pytest", 'pytest-cov', "pytest-xdist"]
53
53
  multitest = ['tox']
54
54
 
55
55
 
@@ -23,6 +23,7 @@ from gitbolt.constants import GIT_DIR as GIT_DIR
23
23
  # endregion
24
24
 
25
25
 
26
+ # TODO: check failing test on macos
26
27
  def get_git(git_root_dir: Path = Path.cwd()) -> Git:
27
28
  """
28
29
  Get operational and programmatic ``Git``.
@@ -34,7 +35,7 @@ def get_git(git_root_dir: Path = Path.cwd()) -> Git:
34
35
  >>> import subprocess
35
36
  >>> import gitbolt
36
37
  >>> git = gitbolt.get_git()
37
- >>> assert git.version == subprocess.run(['git', 'version'], capture_output=True, text=True).stdout.strip()
38
+ >>> assert git.version().version() == subprocess.run(['git', 'version'], capture_output=True, text=True).stdout.strip()
38
39
 
39
40
  :param git_root_dir: Path to the git repo root directory. Defaults to current working directory.
40
41
  """
@@ -230,8 +230,29 @@ class Version(GitSubCommand, Protocol):
230
230
  Interface for ``git version`` command.
231
231
  """
232
232
 
233
+ class VersionInfo:
234
+ @abstractmethod
235
+ def version(self) -> str: ...
236
+
237
+ @abstractmethod
238
+ def semver(self) -> tuple: ...
239
+
240
+ class VersionWithBuildInfo(VersionInfo):
241
+ @abstractmethod
242
+ def build_options(self) -> dict[str, str]: ...
243
+
244
+ @overload
245
+ @abstractmethod
246
+ def version(self) -> VersionInfo: ...
247
+
248
+ @overload
233
249
  @abstractmethod
234
- def version(self, build_options: bool = False) -> str:
250
+ def version(self, build_options: Literal[True]) -> VersionWithBuildInfo: ...
251
+
252
+ @abstractmethod
253
+ def version(
254
+ self, build_options: Literal[True, False] = False
255
+ ) -> VersionInfo | VersionWithBuildInfo:
235
256
  """
236
257
  All the parameters are mirrors of the parameters of ``git version`` CLI command
237
258
  from `git version documentation <https://git-scm.com/docs/git-version>`_.
@@ -276,14 +297,12 @@ class Git(CanOverrideGitOpts, CanOverrideGitEnvs, Protocol):
276
297
  Class designed analogous to documentation provided on `git documentation <https://git-scm.com/docs/git>`_.
277
298
  """
278
299
 
279
- @property
280
- def version(self) -> str:
300
+ def version(self) -> Version.VersionInfo:
281
301
  """
282
302
  :return: current git version.
283
303
  """
284
304
  return self.version_subcmd.version()
285
305
 
286
- @property
287
306
  @abstractmethod
288
307
  def exec_path(self) -> Path:
289
308
  """
@@ -291,7 +310,6 @@ class Git(CanOverrideGitOpts, CanOverrideGitEnvs, Protocol):
291
310
  """
292
311
  ...
293
312
 
294
- @property
295
313
  @abstractmethod
296
314
  def html_path(self) -> Path:
297
315
  """
@@ -299,7 +317,6 @@ class Git(CanOverrideGitOpts, CanOverrideGitEnvs, Protocol):
299
317
  """
300
318
  ...
301
319
 
302
- @property
303
320
  @abstractmethod
304
321
  def info_path(self) -> Path:
305
322
  """
@@ -307,7 +324,6 @@ class Git(CanOverrideGitOpts, CanOverrideGitEnvs, Protocol):
307
324
  """
308
325
  ...
309
326
 
310
- @property
311
327
  @abstractmethod
312
328
  def man_path(self) -> Path:
313
329
  """
@@ -8,14 +8,17 @@ Git command interfaces with default implementation using subprocess calls.
8
8
  from __future__ import annotations
9
9
 
10
10
  from abc import abstractmethod, ABC
11
+ from collections.abc import Callable
11
12
  from pathlib import Path
12
13
  from subprocess import CompletedProcess
13
14
  from typing import override, Protocol, Unpack, Self, overload, Literal, Any
14
15
 
15
16
  from vt.utils.commons.commons.core_py import is_unset, not_none_not_unset
16
17
  from vt.utils.commons.commons.op import RootDirOp
18
+ from vt.utils.errors.error_specs import ERR_INVALID_USAGE
17
19
 
18
20
  from gitbolt import Git, Version, LsTree, GitSubCommand, HasGitUnderneath, Add
21
+ from gitbolt.exceptions import GitExitingException
19
22
  from gitbolt.git_subprocess.add import AddCLIArgsBuilder, IndividuallyOverridableACAB
20
23
  from gitbolt.git_subprocess.ls_tree import (
21
24
  LsTreeCLIArgsBuilder,
@@ -239,25 +242,21 @@ class GitCommand(Git, ABC):
239
242
  # endregion
240
243
 
241
244
  @override
242
- @property
243
245
  def html_path(self) -> Path:
244
246
  html_path_str = "--html-path"
245
247
  return self._get_path(html_path_str)
246
248
 
247
249
  @override
248
- @property
249
250
  def info_path(self) -> Path:
250
251
  info_path_str = "--info-path"
251
252
  return self._get_path(info_path_str)
252
253
 
253
254
  @override
254
- @property
255
255
  def man_path(self) -> Path:
256
256
  man_path_str = "--man-path"
257
257
  return self._get_path(man_path_str)
258
258
 
259
259
  @override
260
- @property
261
260
  def exec_path(self) -> Path:
262
261
  exec_path_str = "--exec-path"
263
262
  return self._get_path(exec_path_str)
@@ -324,7 +323,66 @@ class GitSubcmdCommand(GitSubCommand, HasGitUnderneath["GitCommand"], Protocol):
324
323
 
325
324
 
326
325
  class VersionCommand(Version, GitSubcmdCommand, Protocol):
327
- pass
326
+ class _Cache:
327
+ def __init__(self):
328
+ self.version = None
329
+ self.semver = None
330
+ self.build_options = None
331
+
332
+ class VersionInfoForCmd(Version.VersionInfo):
333
+ def __init__(self, rosetta_supplier: Callable[[], str]):
334
+ self.rosetta_supplier = rosetta_supplier
335
+ self.rosetta: str | None = None
336
+ self._cache = VersionCommand._Cache()
337
+
338
+ @override
339
+ def version(self) -> str:
340
+ if self.rosetta is None:
341
+ self.rosetta = self.rosetta_supplier()
342
+ if self._cache.version is not None:
343
+ return self._cache.version
344
+ v_str = self.rosetta.splitlines()[0]
345
+ self._cache.version = v_str
346
+ return v_str
347
+
348
+ @override
349
+ def semver(self) -> tuple:
350
+ if self._cache.semver is not None:
351
+ return self._cache.semver
352
+ t_ver = self.version().split()[-1].split(".")
353
+ return tuple(t_ver)
354
+
355
+ @override
356
+ def __str__(self):
357
+ if self.rosetta is None:
358
+ self.rosetta = self.rosetta_supplier()
359
+ return self.rosetta
360
+
361
+ class VersionWithBuildInfoForCmd(VersionInfoForCmd, Version.VersionWithBuildInfo):
362
+ def __init__(
363
+ self, rosetta_supplier: Callable[[], str], splitter_expr: str = ": "
364
+ ):
365
+ super().__init__(rosetta_supplier)
366
+ self.splitter_expr = splitter_expr
367
+
368
+ @override
369
+ def build_options(self) -> dict[str, str]:
370
+ if self.rosetta is None:
371
+ self.rosetta = self.rosetta_supplier()
372
+ if self._cache.build_options is not None:
373
+ return self._cache.build_options
374
+ if not self.rosetta.splitlines()[1:]:
375
+ errmsg = "Unable to populate build_options as possibly --build-options switch wasn't used."
376
+ raise GitExitingException(
377
+ errmsg, exit_code=ERR_INVALID_USAGE
378
+ ) from ValueError(errmsg)
379
+
380
+ self._cache.build_options = {}
381
+ for b_str in self.rosetta.splitlines()[1:]:
382
+ if self.splitter_expr in b_str:
383
+ b_k, b_v = b_str.split(self.splitter_expr)
384
+ self._cache.build_options[b_k] = b_v
385
+ return self._cache.build_options
328
386
 
329
387
 
330
388
  class LsTreeCommand(LsTree, GitSubcmdCommand, Protocol):
@@ -525,9 +583,9 @@ class UncheckedSubcmd(GitSubcmdCommand, RootDirOp, Protocol):
525
583
  another_supplied_env = subprocess_run_kwargs.pop("env", None)
526
584
  if another_supplied_env:
527
585
  envs_vars.update(another_supplied_env)
528
- cwd = subprocess_run_kwargs.pop("cwd", None) or self.root_dir
529
- capture_output = subprocess_run_kwargs.pop("capture_output", None) or True
530
- check = subprocess_run_kwargs.pop("check", None) or True
586
+ cwd = subprocess_run_kwargs.pop("cwd", self.root_dir)
587
+ capture_output = subprocess_run_kwargs.pop("capture_output", True)
588
+ check = subprocess_run_kwargs.pop("check", True)
531
589
  # Run the git command
532
590
  result = self.underlying_git.runner.run_git_command(
533
591
  main_cmd_args,
@@ -9,10 +9,11 @@ from __future__ import annotations
9
9
 
10
10
  from abc import ABC
11
11
  from pathlib import Path
12
- from typing import override
12
+ from typing import override, Literal, overload
13
13
 
14
14
  from vt.utils.commons.commons.op import RootDirOp
15
15
 
16
+ from gitbolt.base import Version
16
17
  from gitbolt.add import AddArgsValidator
17
18
  from gitbolt.git_subprocess import (
18
19
  GitCommand,
@@ -43,22 +44,36 @@ class GitSubcmdCommandImpl(GitSubcmdCommand, ABC):
43
44
 
44
45
 
45
46
  class VersionCommandImpl(VersionCommand, GitSubcmdCommandImpl):
47
+ @overload
48
+ def version(self) -> Version.VersionInfo: ...
49
+
50
+ @overload
51
+ def version(self, build_options: Literal[True]) -> Version.VersionWithBuildInfo: ...
52
+
46
53
  @override
47
- def version(self, build_options: bool = False) -> str:
54
+ def version(
55
+ self, build_options: Literal[True, False] = False
56
+ ) -> Version.VersionInfo | Version.VersionWithBuildInfo:
48
57
  self._require_valid_args(build_options)
49
58
  main_cmd_args = self.underlying_git.build_main_cmd_args()
50
59
  sub_cmd_args = [VERSION_CMD]
51
60
  env_vars = self.underlying_git.build_git_envs()
52
61
  if build_options:
53
62
  sub_cmd_args.append("--build-options")
54
- return self.underlying_git.runner.run_git_command(
55
- main_cmd_args,
56
- sub_cmd_args,
57
- check=True,
58
- text=True,
59
- capture_output=True,
60
- env=env_vars,
61
- ).stdout.strip()
63
+
64
+ def rosetta_supplier():
65
+ return self.underlying_git.runner.run_git_command(
66
+ main_cmd_args,
67
+ sub_cmd_args,
68
+ check=True,
69
+ text=True,
70
+ capture_output=True,
71
+ env=env_vars,
72
+ ).stdout.strip()
73
+
74
+ if build_options:
75
+ return VersionCommand.VersionWithBuildInfoForCmd(rosetta_supplier)
76
+ return VersionCommand.VersionInfoForCmd(rosetta_supplier)
62
77
 
63
78
  def clone(self) -> "VersionCommandImpl":
64
79
  return VersionCommandImpl(self.underlying_git)
@@ -196,9 +211,21 @@ class SimpleGitCommand(GitCommand, RootDirOp):
196
211
  return add_subcmd
197
212
 
198
213
  @override
199
- def clone(self) -> "SimpleGitCommand":
214
+ def clone(self) -> SimpleGitCommand:
200
215
  # region obtain class instance
201
- cloned = SimpleGitCommand(
216
+ cloned = self._subclass_clone()
217
+ # endregion
218
+ # region clone protected members
219
+ cloned._main_cmd_opts = self._main_cmd_opts
220
+ cloned._env_vars = self._env_vars
221
+ # endregion
222
+ return cloned
223
+
224
+ def _subclass_clone(self) -> SimpleGitCommand:
225
+ """
226
+ :returns: clone as defined by the subclass.
227
+ """
228
+ return SimpleGitCommand(
202
229
  self.root_dir,
203
230
  self.runner,
204
231
  version_subcmd=self.version_subcmd,
@@ -206,12 +233,6 @@ class SimpleGitCommand(GitCommand, RootDirOp):
206
233
  add_subcmd=self.add_subcmd,
207
234
  subcmd_unchecked=self.subcmd_unchecked,
208
235
  )
209
- # endregion
210
- # region clone protected members
211
- cloned._main_cmd_opts = self._main_cmd_opts
212
- cloned._env_vars = self._env_vars
213
- # endregion
214
- return cloned
215
236
 
216
237
  @override
217
238
  @property
@@ -223,3 +244,73 @@ class SimpleGitCommand(GitCommand, RootDirOp):
223
244
  subcmd_unchecked = self._subcmd_unchecked.clone()
224
245
  subcmd_unchecked._set_underlying_git(self)
225
246
  return subcmd_unchecked
247
+
248
+
249
+ class CLISimpleGitCommand(SimpleGitCommand):
250
+ """
251
+ A simple git command that can run using CLI params.
252
+ """
253
+
254
+ def __init__(
255
+ self,
256
+ git_root_dir: Path = Path.cwd(),
257
+ runner: GitCommandRunner = SimpleGitCR(),
258
+ *,
259
+ opts: list[str] | None = None,
260
+ envs: dict[str, str] | None = None,
261
+ prefer_cli: bool = False,
262
+ version_subcmd: VersionCommand | None = None,
263
+ ls_tree_subcmd: LsTreeCommand | None = None,
264
+ add_subcmd: AddCommand | None = None,
265
+ subcmd_unchecked: UncheckedSubcmd | None = None,
266
+ ):
267
+ """
268
+ :param opts: main git cli options.
269
+ :param envs: main git cli env vars.
270
+ :param prefer_cli: cli opts and envs will be given priority over programmatically set opts and envs. Setting
271
+ this param to ``True`` will make cli opts and envs appear later in the opts and envs strings which will
272
+ make them override previously programmatically set opts and envs.
273
+ """
274
+ super().__init__(
275
+ git_root_dir,
276
+ runner,
277
+ version_subcmd=version_subcmd,
278
+ ls_tree_subcmd=ls_tree_subcmd,
279
+ add_subcmd=add_subcmd,
280
+ subcmd_unchecked=subcmd_unchecked,
281
+ )
282
+ self._main_cmd_cli_opts = opts
283
+ self._cmd_cli_envs = envs
284
+ self.prefer_cli = prefer_cli
285
+
286
+ @override
287
+ def build_main_cmd_args(self) -> list[str]:
288
+ if self._main_cmd_cli_opts:
289
+ if self.prefer_cli:
290
+ return super().build_main_cmd_args() + self._main_cmd_cli_opts
291
+ else:
292
+ return self._main_cmd_cli_opts + super().build_main_cmd_args()
293
+ return super().build_main_cmd_args()
294
+
295
+ @override
296
+ def build_git_envs(self) -> dict[str, str]:
297
+ if self._cmd_cli_envs:
298
+ if self.prefer_cli:
299
+ return super().build_git_envs() | self._cmd_cli_envs
300
+ else:
301
+ return self._cmd_cli_envs | super().build_git_envs()
302
+ return super().build_git_envs()
303
+
304
+ @override
305
+ def _subclass_clone(self) -> CLISimpleGitCommand:
306
+ return CLISimpleGitCommand(
307
+ self.root_dir,
308
+ self.runner,
309
+ opts=self._main_cmd_cli_opts,
310
+ envs=self._cmd_cli_envs,
311
+ prefer_cli=self.prefer_cli,
312
+ version_subcmd=self.version_subcmd,
313
+ ls_tree_subcmd=self.ls_tree_subcmd,
314
+ add_subcmd=self.add_subcmd,
315
+ subcmd_unchecked=self.subcmd_unchecked,
316
+ )
@@ -108,9 +108,25 @@ class IndividuallyOverridableLTCAB(LsTreeCLIArgsBuilder):
108
108
  * With --format::
109
109
 
110
110
  >>> builder.build("HEAD", format_="%(objectname)")
111
- ['ls-tree', '--format=%(objectname)', 'HEAD']
111
+ ['ls-tree', '--format', '%(objectname)', 'HEAD']
112
+
112
113
  >>> builder.build("HEAD", format_="")
113
- ['ls-tree', '--format=', 'HEAD']
114
+ ['ls-tree', '--format', '', 'HEAD']
115
+
116
+ >>> builder.build("HEAD", format_="''")
117
+ ['ls-tree', '--format', "''", 'HEAD']
118
+
119
+ >>> builder.build("HEAD", format_='""')
120
+ ['ls-tree', '--format', '""', 'HEAD']
121
+
122
+ >>> builder.build("HEAD", format_="%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)")
123
+ ['ls-tree', '--format', '%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)', 'HEAD']
124
+
125
+ >>> builder.build("HEAD", format_="'%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)'")
126
+ ['ls-tree', '--format', "'%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)'", 'HEAD']
127
+
128
+ >>> builder.build("HEAD", format_='"%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)"')
129
+ ['ls-tree', '--format', '"%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)"', 'HEAD']
114
130
 
115
131
  * With paths::
116
132
 
@@ -140,7 +156,7 @@ class IndividuallyOverridableLTCAB(LsTreeCLIArgsBuilder):
140
156
  ... format_="%(objectname) %(path)",
141
157
  ... path=["dir1", "dir2/file.txt"]
142
158
  ... )
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']
159
+ ['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
160
 
145
161
  * Empty or falsy values, mostly will fail at validation::
146
162
 
@@ -344,11 +360,17 @@ class IndividuallyOverridableLTCAB(LsTreeCLIArgsBuilder):
344
360
  >>> IndividuallyOverridableLTCAB().format_arg(None)
345
361
  []
346
362
  >>> 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 []
363
+ ['--format', '%(objectname)']
364
+ >>> IndividuallyOverridableLTCAB().format_arg('""')
365
+ ['--format', '""']
366
+ >>> IndividuallyOverridableLTCAB().format_arg("''")
367
+ ['--format', "''"]
368
+ >>> IndividuallyOverridableLTCAB().format_arg('%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)')
369
+ ['--format', '%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)']
370
+ >>> IndividuallyOverridableLTCAB().format_arg('"%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)"')
371
+ ['--format', '"%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)"']
372
+ """
373
+ return ["--format", _format] if _format is not None else []
352
374
 
353
375
  def tree_ish_arg(self, tree_ish: str) -> list[str]:
354
376
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitbolt
3
- Version: 0.0.0.dev10
3
+ Version: 0.0.0.dev12
4
4
  Summary: Fast, flexible and type-safe Git commands in Python.
5
5
  Author-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
6
6
  Maintainer-email: Suhas Krishna Srivastava <suhas.srivastava@vaastav.tech>
@@ -26,8 +26,8 @@ Classifier: Typing :: Typed
26
26
  Requires-Python: >=3.12
27
27
  Description-Content-Type: text/markdown
28
28
  License-File: LICENSE
29
- Requires-Dist: vt-err-hndlr>=0.0.0dev3
30
- Requires-Dist: vt-commons>=0.0.1.dev4
29
+ Requires-Dist: vt-err-hndlr>=0.0.0dev5
30
+ Requires-Dist: vt-commons>=0.0.1.dev9
31
31
  Provides-Extra: pygit2
32
32
  Requires-Dist: pygit2; extra == "pygit2"
33
33
  Provides-Extra: test
@@ -64,6 +64,7 @@ Dynamic: license-file
64
64
  * 🧪 **Terminal Functions:** Git subcommands are terminal functions.
65
65
  * 🧼 **Idiomatic Python:** Write commands in idiomatic Python at compile-time and be confident they’ll execute smoothly at runtime.
66
66
  * 🎀 **Add-ons:** Special features provided to ease programming with git. These can be added if required.
67
+ * 💻 **CLI-cmd:** Take commands from cli and run in `gitbolt`.
67
68
 
68
69
  ---
69
70
 
@@ -340,6 +341,24 @@ git.subcmd_unchecked.run(['--version']) # run the version option for git.
340
341
  git.subcmd_unchecked.run(['version']) # run the version subcommand.
341
342
  ```
342
343
 
344
+ #### 💻 Run commands received from CLI
345
+
346
+ Introduced in `0.0.0dev11` is the ability to take commands from CLI and run it inside `gitbolt`.
347
+
348
+ While making a system it may be required to run cli commands as received from cli using gitbolt. An obvious example
349
+ would be to make a system that receives CLI commands and does certain modifications/additions inside `gitbolt` before
350
+ actually running them. An example:
351
+
352
+ ```python
353
+ from gitbolt.git_subprocess.impl.simple import CLISimpleGitCommand
354
+
355
+ opts = ["--no-pager", "--namespace", "n1"] # options received from outside your program.
356
+ envs = dict(GIT_AUTHOR_NAME="ss") # env-vars received form outside your program.
357
+ git = CLISimpleGitCommand(opts=opts, envs=envs)
358
+
359
+ # these can later be overridden
360
+ git = git.git_opts_override(namespace="n2")
361
+ ```
343
362
 
344
363
  ---
345
364
 
@@ -0,0 +1,8 @@
1
+ vt-err-hndlr>=0.0.0dev5
2
+ vt-commons>=0.0.1.dev9
3
+
4
+ [pygit2]
5
+ pygit2
6
+
7
+ [test]
8
+ pytest
@@ -1,8 +0,0 @@
1
- vt-err-hndlr>=0.0.0dev3
2
- vt-commons>=0.0.1.dev4
3
-
4
- [pygit2]
5
- pygit2
6
-
7
- [test]
8
- pytest
File without changes
File without changes