... |
... |
@@ -91,16 +91,18 @@ GIT_MODULES = '.gitmodules' |
91
|
91
|
#
|
92
|
92
|
class GitMirror(SourceFetcher):
|
93
|
93
|
|
94
|
|
- def __init__(self, source, path, url, ref):
|
|
94
|
+ def __init__(self, source, path, url, ref, *, parent=None):
|
95
|
95
|
|
96
|
96
|
super().__init__()
|
97
|
97
|
self.source = source
|
98
|
|
- self.path = path
|
|
98
|
+ self.parent = parent
|
99
|
99
|
self.url = url
|
100
|
|
- self.ref = ref
|
101
|
100
|
self.mirror = os.path.join(source.get_mirror_directory(), utils.url_directory_name(url))
|
102
|
101
|
self.mark_download_url(url)
|
103
|
102
|
|
|
103
|
+ self._path = path
|
|
104
|
+ self._ref = ref
|
|
105
|
+
|
104
|
106
|
# Ensures that the mirror exists
|
105
|
107
|
def ensure(self, alias_override=None):
|
106
|
108
|
|
... |
... |
@@ -223,8 +225,7 @@ class GitMirror(SourceFetcher): |
223
|
225
|
fail="Failed to checkout git ref {}".format(self.ref),
|
224
|
226
|
cwd=fullpath)
|
225
|
227
|
|
226
|
|
- # List the submodules (path/url tuples) present at the given ref of this repo
|
227
|
|
- def submodule_list(self):
|
|
228
|
+ def _read_gitmodules(self):
|
228
|
229
|
modules = "{}:{}".format(self.ref, GIT_MODULES)
|
229
|
230
|
exit_code, output = self.source.check_output(
|
230
|
231
|
[self.source.host_git, 'show', modules], cwd=self.mirror)
|
... |
... |
@@ -247,10 +248,15 @@ class GitMirror(SourceFetcher): |
247
|
248
|
for section in parser.sections():
|
248
|
249
|
# validate section name against the 'submodule "foo"' pattern
|
249
|
250
|
if re.match(r'submodule "(.*)"', section):
|
250
|
|
- path = parser.get(section, 'path')
|
251
|
|
- url = parser.get(section, 'url')
|
|
251
|
+ yield (parser, section)
|
252
|
252
|
|
253
|
|
- yield (path, url)
|
|
253
|
+ # List the submodules (path/url tuples) present at the given ref of this repo
|
|
254
|
+ def submodule_list(self):
|
|
255
|
+ for parser, section in self._read_gitmodules():
|
|
256
|
+ path = parser.get(section, 'path')
|
|
257
|
+ url = parser.get(section, 'url')
|
|
258
|
+
|
|
259
|
+ yield (path, url)
|
254
|
260
|
|
255
|
261
|
# Fetch the ref which this mirror requires its submodule to have,
|
256
|
262
|
# at the given ref of this mirror.
|
... |
... |
@@ -287,6 +293,76 @@ class GitMirror(SourceFetcher): |
287
|
293
|
|
288
|
294
|
return None
|
289
|
295
|
|
|
296
|
+ def get_submodule_path(self, url):
|
|
297
|
+ for parser, section in self._read_gitmodules():
|
|
298
|
+ parsed_url = parser.get(section, 'url')
|
|
299
|
+ if parsed_url == url:
|
|
300
|
+ return parser.get(section, 'path')
|
|
301
|
+
|
|
302
|
+ raise SourceError("{}: No submodule found with url '{}'".format(self.source, url))
|
|
303
|
+
|
|
304
|
+ @property
|
|
305
|
+ def path(self):
|
|
306
|
+ if self._path is None:
|
|
307
|
+ self._path = self.parent.get_submodule_path(self.url)
|
|
308
|
+
|
|
309
|
+ return self._path
|
|
310
|
+
|
|
311
|
+ @property
|
|
312
|
+ def ref(self):
|
|
313
|
+ # The top-level GitMirror may have ref as None, submodules don't.
|
|
314
|
+ if self._ref is None and self.parent:
|
|
315
|
+ self._ref = self.parent.submodule_ref(self.path)
|
|
316
|
+
|
|
317
|
+ return self._ref
|
|
318
|
+
|
|
319
|
+ @ref.setter
|
|
320
|
+ def ref(self, ref):
|
|
321
|
+ self._ref = ref
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+# A SourceFetcher that may also check for, and have submodules of its own.
|
|
325
|
+class TopLevelGitMirror(GitMirror):
|
|
326
|
+ def __init__(self, source, path, url, ref):
|
|
327
|
+ super().__init__(source, path, url, ref)
|
|
328
|
+ self.auto_submodules = []
|
|
329
|
+
|
|
330
|
+ def fetch(self, alias_override=None):
|
|
331
|
+ super().fetch(alias_override)
|
|
332
|
+ self.refresh_submodules()
|
|
333
|
+
|
|
334
|
+ # auto_submodules do not have aliases, so don't need an override
|
|
335
|
+ for mirror in self.auto_submodules:
|
|
336
|
+ mirror.fetch()
|
|
337
|
+
|
|
338
|
+ # Refreshes the GitMirror objects for submodules
|
|
339
|
+ #
|
|
340
|
+ # Assumes that we have our mirror and we have the ref which we point to
|
|
341
|
+ #
|
|
342
|
+ def refresh_submodules(self):
|
|
343
|
+ self.ensure()
|
|
344
|
+
|
|
345
|
+ excluded_paths = list([s.path for s in self.source.manual_submodules])
|
|
346
|
+ submodules = []
|
|
347
|
+
|
|
348
|
+ # XXX Here we should issue a warning if either:
|
|
349
|
+ # A.) A submodule exists but is not defined in the element configuration
|
|
350
|
+ # B.) The element configuration configures submodules which dont exist at the current ref
|
|
351
|
+ #
|
|
352
|
+ for path, url in self.submodule_list():
|
|
353
|
+ if path in excluded_paths:
|
|
354
|
+ continue
|
|
355
|
+ else:
|
|
356
|
+ self.source.warn("Unexpected submodule detected with path '{}' and url '{}'"
|
|
357
|
+ .format(path, url))
|
|
358
|
+
|
|
359
|
+ ref = self.submodule_ref(path)
|
|
360
|
+ if ref is not None:
|
|
361
|
+ mirror = GitMirror(self, path, url, ref)
|
|
362
|
+ submodules.append(mirror)
|
|
363
|
+
|
|
364
|
+ self.auto_submodules = submodules
|
|
365
|
+
|
290
|
366
|
|
291
|
367
|
class GitSource(Source):
|
292
|
368
|
# pylint: disable=attribute-defined-outside-init
|
... |
... |
@@ -298,10 +374,10 @@ class GitSource(Source): |
298
|
374
|
self.node_validate(node, config_keys + Source.COMMON_CONFIG_KEYS)
|
299
|
375
|
|
300
|
376
|
self.original_url = self.node_get_member(node, str, 'url')
|
301
|
|
- self.mirror = GitMirror(self, '', self.original_url, ref)
|
|
377
|
+ self.mirror = TopLevelGitMirror(self, '', self.original_url, ref)
|
302
|
378
|
self.tracking = self.node_get_member(node, str, 'track', None)
|
303
|
379
|
self.checkout_submodules = self.node_get_member(node, bool, 'checkout-submodules', True)
|
304
|
|
- self.submodules = []
|
|
380
|
+ self.manual_submodules = []
|
305
|
381
|
|
306
|
382
|
# Parse a dict of submodule overrides, stored in the submodule_overrides
|
307
|
383
|
# and submodule_checkout_overrides dictionaries.
|
... |
... |
@@ -311,6 +387,9 @@ class GitSource(Source): |
311
|
387
|
for path, _ in self.node_items(modules):
|
312
|
388
|
submodule = self.node_get_member(modules, Mapping, path)
|
313
|
389
|
url = self.node_get_member(submodule, str, 'url', None)
|
|
390
|
+ submodule_mirror = GitMirror(self, None, url, None, parent=self.mirror)
|
|
391
|
+ self.manual_submodules.append(submodule_mirror)
|
|
392
|
+
|
314
|
393
|
self.submodule_overrides[path] = url
|
315
|
394
|
if 'checkout' in submodule:
|
316
|
395
|
checkout = self.node_get_member(submodule, bool, 'checkout')
|
... |
... |
@@ -384,7 +463,7 @@ class GitSource(Source): |
384
|
463
|
|
385
|
464
|
def init_workspace(self, directory):
|
386
|
465
|
# XXX: may wish to refactor this as some code dupe with stage()
|
387
|
|
- self.refresh_submodules()
|
|
466
|
+ self.mirror.refresh_submodules()
|
388
|
467
|
|
389
|
468
|
with self.timed_activity('Setting up workspace "{}"'.format(directory), silent_nested=True):
|
390
|
469
|
self.mirror.init_workspace(directory)
|
... |
... |
@@ -398,7 +477,7 @@ class GitSource(Source): |
398
|
477
|
# with submodules present (source needed fetching) and
|
399
|
478
|
# we may not know about the submodule yet come time to build.
|
400
|
479
|
#
|
401
|
|
- self.refresh_submodules()
|
|
480
|
+ self.mirror.refresh_submodules()
|
402
|
481
|
|
403
|
482
|
# Stage the main repo in the specified directory
|
404
|
483
|
#
|
... |
... |
@@ -414,17 +493,20 @@ class GitSource(Source): |
414
|
493
|
mirror.stage(directory)
|
415
|
494
|
|
416
|
495
|
def get_source_fetchers(self):
|
417
|
|
- self.refresh_submodules()
|
418
|
|
- return [self.mirror] + self.submodules
|
|
496
|
+ return [self.mirror] + self.manual_submodules
|
419
|
497
|
|
420
|
498
|
###########################################################
|
421
|
499
|
# Local Functions #
|
422
|
500
|
###########################################################
|
|
501
|
+ @property
|
|
502
|
+ def submodules(self):
|
|
503
|
+ return self.manual_submodules + self.mirror.auto_submodules
|
|
504
|
+
|
423
|
505
|
def have_all_refs(self):
|
424
|
506
|
if not self.mirror.has_ref():
|
425
|
507
|
return False
|
426
|
508
|
|
427
|
|
- self.refresh_submodules()
|
|
509
|
+ self.mirror.refresh_submodules()
|
428
|
510
|
for mirror in self.submodules:
|
429
|
511
|
if not os.path.exists(mirror.mirror):
|
430
|
512
|
return False
|
... |
... |
@@ -433,33 +515,6 @@ class GitSource(Source): |
433
|
515
|
|
434
|
516
|
return True
|
435
|
517
|
|
436
|
|
- # Refreshes the GitMirror objects for submodules
|
437
|
|
- #
|
438
|
|
- # Assumes that we have our mirror and we have the ref which we point to
|
439
|
|
- #
|
440
|
|
- def refresh_submodules(self):
|
441
|
|
- self.mirror.ensure()
|
442
|
|
- submodules = []
|
443
|
|
-
|
444
|
|
- # XXX Here we should issue a warning if either:
|
445
|
|
- # A.) A submodule exists but is not defined in the element configuration
|
446
|
|
- # B.) The element configuration configures submodules which dont exist at the current ref
|
447
|
|
- #
|
448
|
|
- for path, url in self.mirror.submodule_list():
|
449
|
|
-
|
450
|
|
- # Allow configuration to override the upstream
|
451
|
|
- # location of the submodules.
|
452
|
|
- override_url = self.submodule_overrides.get(path)
|
453
|
|
- if override_url:
|
454
|
|
- url = override_url
|
455
|
|
-
|
456
|
|
- ref = self.mirror.submodule_ref(path)
|
457
|
|
- if ref is not None:
|
458
|
|
- mirror = GitMirror(self, path, url, ref)
|
459
|
|
- submodules.append(mirror)
|
460
|
|
-
|
461
|
|
- self.submodules = submodules
|
462
|
|
-
|
463
|
518
|
|
464
|
519
|
# Plugin entry point
|
465
|
520
|
def setup():
|