Skip to content

Commit 60a88fd

Browse files
[MINOR] Add support for the remaining .gitmodules attributes (#34)
* [MINOR] Add support for the remainder of .gitmodules attributes - Adds all remaining .gitmodules "submodule" attributes to objects.Submodule: update, branch, ignore, shallow, fetchRecurseSubmodules (keyed as recurse) - Modifies read_gitmodules._read_gitmodules_file_content to use configparser instead of regex to simplify matching optional keys - Modifies any tests requiring direct Submodule instantiation, and adds a few extra arguments to test the extension --------- Authored-by: Daniel Guzman <dhguzman@berkeley.edu>
1 parent c156f77 commit 60a88fd

File tree

3 files changed

+82
-36
lines changed

3 files changed

+82
-36
lines changed

gitlab_submodule/objects.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,29 @@ def __init__(self,
1212
parent_ref: str,
1313
name: str,
1414
path: str,
15-
url: str):
15+
url: str,
16+
branch: Optional[str] = None,
17+
ignore: Optional[str] = None,
18+
update: Optional[str] = None,
19+
recurse: bool = False,
20+
shallow: bool = False):
21+
1622
self.parent_project = parent_project
1723
self.parent_ref = parent_ref
1824
self.name = name
1925
self.path = path
2026
self.url = url
27+
self.branch = branch
28+
self.ignore = ignore
29+
self.update = update
30+
self.recurse = recurse
31+
self.shallow = shallow
2132

2233
def keys(self):
23-
return {'parent_project', 'parent_ref', 'name', 'path', 'url'}
34+
return {
35+
'parent_project', 'parent_ref', 'name', 'path', 'url',
36+
'update', 'branch', 'ignore', 'shallow', 'recurse'
37+
}
2438

2539
def __getitem__(self, key):
2640
if key in self.keys():
@@ -42,13 +56,20 @@ def to_str(key):
4256
return class_part + ' => {' + ', '.join(attributes) + '}'
4357

4458
def __repr__(self):
45-
return '{} ({}, {}, {}, {}, {})'.format(
59+
return '{} ({})'.format(
4660
self.__class__.__name__,
47-
repr(self.parent_project),
48-
f"'{self.parent_ref}'",
49-
f"'{self.name}'",
50-
f"'{self.path}'",
51-
f"'{self.url}'",
61+
", ".join((
62+
repr(self.parent_project),
63+
repr(self.parent_ref),
64+
repr(self.name),
65+
repr(self.path),
66+
repr(self.url),
67+
repr(self.branch),
68+
repr(self.ignore),
69+
repr(self.update),
70+
repr(self.recurse),
71+
repr(self.shallow),
72+
))
5273
)
5374

5475

gitlab_submodule/read_gitmodules.py

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import configparser
12
import re
2-
from typing import Iterable, List, Optional, Tuple
3+
from typing import Iterable, List, Optional, Union
34

45
from gitlab.v4.objects import Project
56

@@ -18,14 +19,12 @@ def iterate_project_submodules(
1819
gitmodules_file_content = _get_gitmodules_file_content(project, ref)
1920
if not gitmodules_file_content:
2021
return []
21-
for (name, url, path) in _read_gitmodules_file_content(
22+
for kwargs in _read_gitmodules_file_content(
2223
gitmodules_file_content):
2324
yield Submodule(
2425
parent_project=project,
2526
parent_ref=ref if ref else project.default_branch,
26-
name=name,
27-
url=url,
28-
path=path)
27+
**kwargs)
2928

3029

3130
def _get_gitmodules_file_content(project: Project,
@@ -40,15 +39,30 @@ def _get_gitmodules_file_content(project: Project,
4039

4140

4241
def _read_gitmodules_file_content(
43-
gitmodules_file_content: str) -> Iterable[Tuple[str, str, str]]:
44-
"""Some basic regex extractions to parse content of .gitmodules file
45-
"""
46-
name_regex = r'\[submodule "([a-zA-Z0-9\.\-/_]+)"\]'
47-
path_regex = r'path ?= ?([a-zA-Z0-9\.\-/_]+)'
48-
url_regex = r'url ?= ?([a-zA-Z0-9\.\-/_:@]+)'
49-
names = re.findall(name_regex, gitmodules_file_content)
50-
paths = re.findall(path_regex, gitmodules_file_content)
51-
urls = re.findall(url_regex, gitmodules_file_content)
52-
if not (len(names) == len(paths) == len(urls)):
53-
raise RuntimeError('Failed parsing the .gitmodules content')
54-
return zip(names, urls, paths)
42+
gitmodules_file_content: str
43+
) -> Iterable[dict[str, Union[None, bool, str]]]:
44+
"""Parses contents of .gitmodule file using configparser"""
45+
config = configparser.ConfigParser()
46+
config.optionxform = str
47+
config.read_string(gitmodules_file_content)
48+
stropts = ('branch', 'ignore', 'update')
49+
boolopts = ('recurse', 'shallow')
50+
name_regex = r'submodule "([a-zA-Z0-9\.\-/_]+)"'
51+
for section in config.sections():
52+
try:
53+
kwargs = {
54+
'name': re.match(name_regex, section).group(1),
55+
'path': config.get(section, 'path'),
56+
'url': config.get(section, 'url')
57+
}
58+
except (AttributeError, KeyError):
59+
raise RuntimeError('Failed parsing the .gitmodules contnet')
60+
kwargs.update(
61+
(opt, config.get(section, opt, fallback=None))
62+
for opt in stropts
63+
)
64+
kwargs.update(
65+
(opt, config.getboolean(section, opt, fallback=False))
66+
for opt in boolopts
67+
)
68+
yield kwargs

tests/test_objects.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,15 @@ def test_Submodule_as_dict(self):
3838
parent_ref='main',
3939
name='test_submodule',
4040
url='git@gitlab.com:test/submodule',
41-
path='include/test_submodule'
41+
path='include/test_submodule',
42+
update='rebase'
4243
)
4344
submodule_dict = dict(submodule)
44-
self.assertEqual(len(submodule_dict.keys()), 5)
45+
self.assertEqual(len(submodule_dict.keys()), 10)
4546
self.assertEqual(submodule_dict['parent_ref'], 'main')
4647
self.assertEqual(submodule_dict['name'], 'test_submodule')
48+
self.assertEqual(submodule_dict['update'], 'rebase')
49+
self.assertEqual(submodule_dict['branch'], None)
4750

4851
def test_Submodule_str(self):
4952
mock_project = DictMock()
@@ -57,11 +60,13 @@ def test_Submodule_str(self):
5760
)
5861
self.assertEqual(
5962
"<class 'Submodule'> => {"
63+
"'branch': None, 'ignore': None, "
6064
"'name': 'test_submodule', "
6165
"'parent_project': <class 'DictMock'> => {'id': 123456789}, "
6266
"'parent_ref': 'main', "
6367
"'path': 'include/test_submodule', "
64-
"'url': 'git@gitlab.com:test/submodule'}",
68+
"'recurse': False, 'shallow': False, "
69+
"'update': None, 'url': 'git@gitlab.com:test/submodule'}",
6570
str(submodule)
6671
)
6772

@@ -73,11 +78,13 @@ def test_Submodule_repr(self):
7378
parent_ref='main',
7479
name='test_submodule',
7580
url='git@gitlab.com:test/submodule',
76-
path='include/test_submodule'
81+
path='include/test_submodule',
82+
branch='development'
7783
)
7884
self.assertEqual(
7985
"Submodule ({'id': 123456789}, 'main', 'test_submodule',"
80-
" 'include/test_submodule', 'git@gitlab.com:test/submodule')",
86+
" 'include/test_submodule', 'git@gitlab.com:test/submodule',"
87+
" 'development', None, None, False, False)",
8188
repr(submodule)
8289
)
8390

@@ -157,7 +164,8 @@ def test_Subproject_str(self):
157164
parent_ref='main',
158165
name='test_submodule',
159166
url='git@gitlab.com:test/submodule',
160-
path='include/test_submodule'
167+
path='include/test_submodule',
168+
branch='development'
161169
)
162170
mock_project = DictMock()
163171
mock_project.name = 'project'
@@ -175,11 +183,13 @@ def test_Subproject_str(self):
175183
)
176184
self.assertEqual(
177185
" 'submodule': <class 'Submodule'> => {"
186+
"'branch': 'development', 'ignore': None, "
178187
"'name': 'test_submodule', "
179188
"'parent_project': <class 'DictMock'> => {'id': '123456789'}, "
180189
"'parent_ref': 'main', "
181190
"'path': 'include/test_submodule', "
182-
"'url': 'git@gitlab.com:test/submodule'},",
191+
"'recurse': False, 'shallow': False, "
192+
"'update': None, 'url': 'git@gitlab.com:test/submodule'},",
183193
str_lines[1]
184194
)
185195
self.assertEqual(
@@ -201,7 +211,8 @@ def test_Subproject_repr(self):
201211
parent_ref='main',
202212
name='test_submodule',
203213
url='git@gitlab.com:test/submodule',
204-
path='include/test_submodule'
214+
path='include/test_submodule',
215+
branch='development'
205216
)
206217
mock_project = DictMock()
207218
mock_project.name = 'project'
@@ -218,9 +229,9 @@ def test_Subproject_repr(self):
218229
str_lines[0]
219230
)
220231
self.assertEqual(
221-
" Submodule ({'id': '123456789'}, 'main', "
222-
"'test_submodule', 'include/test_submodule', "
223-
"'git@gitlab.com:test/submodule'),",
232+
" Submodule ({'id': '123456789'}, 'main', 'test_submodule',"
233+
" 'include/test_submodule', 'git@gitlab.com:test/submodule',"
234+
" 'development', None, None, False, False),",
224235
str_lines[1]
225236
)
226237
self.assertEqual(

0 commit comments

Comments
 (0)