Skip to content

Commit 3e822d5

Browse files
committed
Replace GitPython implementation with pygit2 one
Signed-off-by: Tobias Wolf <wolf@b1-systems.de>
1 parent a4c3480 commit 3e822d5

File tree

10 files changed

+172
-120
lines changed

10 files changed

+172
-120
lines changed

.github/actions/features_parse/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ outputs:
1111
runs:
1212
using: composite
1313
steps:
14-
- uses: gardenlinux/python-gardenlinux-lib/.github/actions/setup@0.9.0
14+
- uses: gardenlinux/python-gardenlinux-lib/.github/actions/setup@0.10.0
1515
- id: result
1616
shell: bash
1717
run: |

.github/actions/flavors_parse/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ outputs:
1313
runs:
1414
using: composite
1515
steps:
16-
- uses: gardenlinux/python-gardenlinux-lib/.github/actions/setup@0.9.0
16+
- uses: gardenlinux/python-gardenlinux-lib/.github/actions/setup@0.10.0
1717
- id: matrix
1818
shell: bash
1919
run: |

.github/actions/setup/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: Installs the given GardenLinux Python library
44
inputs:
55
version:
66
description: GardenLinux Python library version
7-
default: "0.9.0"
7+
default: "0.10.0"
88
python_version:
99
description: Python version to setup
1010
default: "3.13"

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "gardenlinux"
3-
version = "0.9.0"
3+
version = "0.10.0"
44
description = "Contains tools to work with the features directory of gardenlinux, for example deducting dependencies from feature sets or validating cnames"
55
authors = ["Garden Linux Maintainers <contact@gardenlinux.io>"]
66
license = "Apache-2.0"
@@ -13,10 +13,10 @@ apt-repo = "^0.5"
1313
boto3 = "^1.40.10"
1414
click = "^8.2.1"
1515
cryptography = "^45.0.6"
16-
gitpython = "^3.1.45"
1716
jsonschema = "^4.25.0"
1817
networkx = "^3.5"
1918
oras = "^0.2.37"
19+
pygit2 = "^1.18.2"
2020
pygments = "^2.19.2"
2121
PyYAML = "^6.0.2"
2222

src/gardenlinux/flavors/__main__.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from .parser import Parser
1919
from ..constants import GL_REPOSITORY_URL
20-
from ..git import Git
20+
from ..git import Repository
2121

2222

2323
def _get_flavors_file_data(flavors_file):
@@ -140,20 +140,13 @@ def main():
140140
args = parse_args()
141141

142142
try:
143-
flavors_data = _get_flavors_file_data(Path(Git().root, "flavors.yaml"))
143+
flavors_data = _get_flavors_file_data(Path(Repository().root, "flavors.yaml"))
144144
except (GitError, RuntimeError):
145145
with TemporaryDirectory() as git_directory:
146-
repo = Repo.clone_from(
147-
GL_REPOSITORY_URL, git_directory, no_origin=True, sparse=True
148-
)
149-
150-
ref = repo.heads.main
151-
152-
if args.commit is not None:
153-
ref = ref.set_commit(args.commit)
146+
repo = Repository.checkout_repo_sparse(git_directory, ["flavors.yaml"], repo_url=GL_REPOSITORY_URL, commit=args.commit)
154147

155148
flavors_data = _get_flavors_file_data(
156-
Path(repo.working_dir, "flavors.yaml")
149+
Path(repo.root, "flavors.yaml")
157150
)
158151

159152
combinations = Parser(flavors_data).filter(

src/gardenlinux/git/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
Git module
55
"""
66

7-
from .git import Git
7+
from .repository import Repository
88

9-
__all__ = ["Git"]
9+
__all__ = ["Repository"]

src/gardenlinux/git/git.py

Lines changed: 0 additions & 84 deletions
This file was deleted.

src/gardenlinux/git/repository.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# -*- coding: utf-8 -*-
2+
3+
from os import PathLike
4+
from pathlib import Path
5+
import sys
6+
7+
from pygit2 import init_repository, Oid
8+
from pygit2 import Repository as _Repository
9+
10+
from ..constants import GL_REPOSITORY_URL
11+
from ..logger import LoggerSetup
12+
13+
14+
class Repository(_Repository):
15+
"""
16+
Repository operations handler based on the given Git directory.
17+
18+
:author: Garden Linux Maintainers
19+
:copyright: Copyright 2024 SAP SE
20+
:package: gardenlinux
21+
:subpackage: git
22+
:since: 0.10.0
23+
:license: https://www.apache.org/licenses/LICENSE-2.0
24+
Apache License, Version 2.0
25+
"""
26+
27+
def __init__(self, git_directory=".", logger=None, **kwargs):
28+
"""
29+
Constructor __init__(Repository)
30+
31+
:param git_directory: Git directory
32+
:param logger: Logger instance
33+
34+
:since: 0.10.0
35+
"""
36+
37+
if logger is None or not logger.hasHandlers():
38+
logger = LoggerSetup.get_logger("gardenlinux.git")
39+
40+
if not isinstance(git_directory, PathLike):
41+
git_directory = Path(git_directory)
42+
43+
if not git_directory.exists():
44+
raise RuntimeError(f"Git directory given is invalid: {git_directory}")
45+
46+
_Repository.__init__(self, git_directory, **kwargs)
47+
48+
self._git_directory = git_directory
49+
self._logger = logger
50+
51+
@property
52+
def commit_id(self):
53+
"""
54+
Returns the commit ID for Git `HEAD`.
55+
56+
:return: (str) Git commit ID
57+
:since: 0.10.0
58+
"""
59+
60+
return str(self.root_repo.head.target)
61+
62+
@property
63+
def root(self):
64+
"""
65+
Returns the root directory of the current Git repository.
66+
67+
:return: (object) Git root directory
68+
:since: 0.10.0
69+
"""
70+
71+
root_dir = self.workdir
72+
73+
if self.is_bare:
74+
root_dir = self.path
75+
76+
usual_git_dir = Path(root_dir, ".git")
77+
78+
# Possible submodule Git repository. Validate repository containing `.git` directory.
79+
if self.path != str(usual_git_dir):
80+
try:
81+
repo = Repository(usual_git_dir, self._logger)
82+
83+
if self.path != repo.path:
84+
root_dir = repo.root
85+
except Exception as exc:
86+
self._logger.warning(f"Failed to inspect Git directory: {exc}")
87+
88+
self._logger.debug(f"Git root directory: {root_dir}")
89+
return Path(root_dir)
90+
91+
@property
92+
def root_repo(self):
93+
"""
94+
Returns the root Git `Repository` instance.
95+
96+
:return: (object) Git root `Repository` instance
97+
:since: 0.10.0
98+
"""
99+
100+
repo = self
101+
102+
if self._git_directory != self.root:
103+
repo = Repository(self.root, self._logger)
104+
105+
return repo
106+
107+
@staticmethod
108+
def checkout_repo(git_directory, repo_url=GL_REPOSITORY_URL, branch="main", commit=None, pathspecs=None, logger=None, **kwargs):
109+
"""
110+
Returns the root Git `Repo` instance.
111+
112+
:return: (object) Git `Repo` instance
113+
:since: 0.10.0
114+
"""
115+
116+
if not isinstance(git_directory, PathLike):
117+
git_directory = Path(git_directory)
118+
119+
if not git_directory.is_dir() or git_directory.match("/*"):
120+
raise RuntimeError("Git directory should not exist or be empty before checkout")
121+
122+
repo = init_repository(git_directory, origin_url=repo_url)
123+
repo.remotes["origin"].fetch()
124+
125+
if commit is None:
126+
refish = f"origin/{branch}"
127+
resolved = repo.resolve_refish(refish)
128+
commit = str(resolved[0].id)
129+
130+
checkout_tree_kwargs = kwargs
131+
if pathspecs is not None: checkout_tree_kwargs['paths'] = pathspecs
132+
repo.checkout_tree(repo[Oid(hex=commit)], **checkout_tree_kwargs)
133+
134+
return Repository(git_directory, logger)
135+
136+
@staticmethod
137+
def checkout_repo_sparse(git_directory, pathspecs=[], repo_url=GL_REPOSITORY_URL, branch="main", commit=None, logger=None, **kwargs):
138+
"""
139+
Sparse checkout given Git repository and return the `Repository` instance.
140+
141+
:return: (object) Git `Repository` instance
142+
:since: 0.10.0
143+
"""
144+
145+
# @TODO: pygit2 does not support sparse checkouts. We use the `paths` parameter at the moment.
146+
return Repository.checkout_repo(git_directory, repo_url=repo_url, branch=branch, commit=commit, pathspecs=pathspecs, logger=logger)

tests/constants.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
from gardenlinux.git import Git
3+
from gardenlinux.git import Repository
44

55
TEST_DATA_DIR = "test-data"
66
GL_ROOT_DIR = f"{TEST_DATA_DIR}/gardenlinux"
@@ -17,6 +17,6 @@
1717
TEST_ARCHITECTURES = ["arm64", "amd64"]
1818
TEST_FEATURE_STRINGS_SHORT = ["gardener_prod"]
1919
TEST_FEATURE_SET = "_slim,base,container"
20-
TEST_COMMIT = Git(GL_ROOT_DIR).commit_id[:8]
20+
TEST_COMMIT = Repository(GL_ROOT_DIR).commit_id[:8]
2121
TEST_VERSION = "1000.0"
2222
TEST_VERSION_STABLE = "1000"

0 commit comments

Comments
 (0)