2
2
3
3
from __future__ import annotations
4
4
5
+ import dataclasses
5
6
import datetime
6
7
import pathlib
7
8
import shlex
10
11
11
12
from libvcs ._internal .run import ProgressCallbackProtocol , run
12
13
from libvcs ._internal .types import StrOrBytesPath , StrPath
14
+ from libvcs ._vendor .version import InvalidVersion , parse
13
15
14
16
_CMD = t .Union [StrOrBytesPath , Sequence [StrOrBytesPath ]]
15
17
16
18
19
+ @dataclasses .dataclass
20
+ class GitVersionInfo :
21
+ """Information about the git version."""
22
+
23
+ version : str
24
+ """Git version string (e.g. '2.43.0')"""
25
+
26
+ version_info : tuple [int , int , int ] | None = None
27
+ """Tuple of (major, minor, micro) version numbers, or None if version invalid"""
28
+
29
+ cpu : str | None = None
30
+ """CPU architecture information"""
31
+
32
+ commit : str | None = None
33
+ """Commit associated with this build"""
34
+
35
+ sizeof_long : str | None = None
36
+ """Size of long in the compiled binary"""
37
+
38
+ sizeof_size_t : str | None = None
39
+ """Size of size_t in the compiled binary"""
40
+
41
+ shell_path : str | None = None
42
+ """Shell path configured in git"""
43
+
44
+
17
45
class Git :
18
46
"""Run commands directly on a git repository."""
19
47
@@ -1751,7 +1779,17 @@ def version(
1751
1779
check_returncode : bool | None = None ,
1752
1780
** kwargs : t .Any ,
1753
1781
) -> str :
1754
- """Version. Wraps `git version <https://git-scm.com/docs/git-version>`_.
1782
+ """Get git version. Wraps `git version <https://git-scm.com/docs/git-version>`_.
1783
+
1784
+ Parameters
1785
+ ----------
1786
+ build_options : bool, optional
1787
+ Include build options in the output with ``--build-options``
1788
+
1789
+ Returns
1790
+ -------
1791
+ str
1792
+ Raw version string output
1755
1793
1756
1794
Examples
1757
1795
--------
@@ -1773,6 +1811,78 @@ def version(
1773
1811
check_returncode = check_returncode ,
1774
1812
)
1775
1813
1814
+ def build_options (
1815
+ self ,
1816
+ * ,
1817
+ check_returncode : bool | None = None ,
1818
+ ** kwargs : t .Any ,
1819
+ ) -> GitVersionInfo :
1820
+ """Get detailed Git version information as a structured dataclass.
1821
+
1822
+ Runs ``git --version --build-options`` and parses the output.
1823
+
1824
+ Returns
1825
+ -------
1826
+ GitVersionInfo
1827
+ Dataclass containing structured information about the git version and build
1828
+
1829
+ Examples
1830
+ --------
1831
+ >>> git = Git(path=example_git_repo.path)
1832
+ >>> version_info = git.build_options()
1833
+ >>> isinstance(version_info, GitVersionInfo)
1834
+ True
1835
+ >>> isinstance(version_info.version, str)
1836
+ True
1837
+ """
1838
+ output = self .version (build_options = True , check_returncode = check_returncode )
1839
+
1840
+ # Parse the output into a structured format
1841
+ result = GitVersionInfo (version = "" )
1842
+
1843
+ # First line is always "git version X.Y.Z"
1844
+ lines = output .strip ().split ("\n " )
1845
+ if lines and lines [0 ].startswith ("git version " ):
1846
+ version_str = lines [0 ].replace ("git version " , "" ).strip ()
1847
+ result .version = version_str
1848
+
1849
+ # Parse semantic version components
1850
+ try :
1851
+ parsed_version = parse (version_str )
1852
+ result .version_info = (
1853
+ parsed_version .major ,
1854
+ parsed_version .minor ,
1855
+ parsed_version .micro ,
1856
+ )
1857
+ except InvalidVersion :
1858
+ # Fall back to string-only if can't be parsed
1859
+ result .version_info = None
1860
+
1861
+ # Parse additional build info
1862
+ for line in lines [1 :]:
1863
+ line = line .strip ()
1864
+ if not line :
1865
+ continue
1866
+
1867
+ if ":" in line :
1868
+ key , value = line .split (":" , 1 )
1869
+ key = key .strip ()
1870
+ value = value .strip ()
1871
+
1872
+ if key == "cpu" :
1873
+ result .cpu = value
1874
+ elif key == "sizeof-long" :
1875
+ result .sizeof_long = value
1876
+ elif key == "sizeof-size_t" :
1877
+ result .sizeof_size_t = value
1878
+ elif key == "shell-path" :
1879
+ result .shell_path = value
1880
+ # Special handling for the commit line which often has no colon
1881
+ elif "commit" in line :
1882
+ result .commit = line
1883
+
1884
+ return result
1885
+
1776
1886
def rev_parse (
1777
1887
self ,
1778
1888
* ,
0 commit comments