FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
GitPython/git/objects/submodule/root.py at main · SashaMIT/GitPython · GitHub
SashaMIT
GitPython
Repository navigation
Code
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
GitPython
/
git
/
objects
/
submodule
/
root.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
480 lines (410 loc) · 20.8 KB
Breadcrumbs
GitPython
/
git
/
objects
/
submodule
/
root.py
Copy path
File metadata and controls
480 lines (410 loc) · 20.8 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
# This module is part of GitPython and is released under the
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
__all__
=
[
"RootModule"
,
"RootUpdateProgress"
]
import
logging
# typing -------------------------------------------------------------------
from
typing
import
TYPE_CHECKING
,
Union
import
git
from
git
.
exc
import
InvalidGitRepositoryError
from
git
.
types
import
Commit_ish
from
git
.
util
import
IterableList
from
.
base
import
Submodule
,
UpdateProgress
from
.
util
import
find_first_remote_branch
if
TYPE_CHECKING
:
from
git
.
repo
import
Repo
# ----------------------------------------------------------------------------
_logger
=
logging
.
getLogger
(
__name__
)
class
RootUpdateProgress
(
UpdateProgress
):
"""Utility class which adds more opcodes to
:class:`~git.objects.submodule.base.UpdateProgress`."""
REMOVE
,
PATHCHANGE
,
BRANCHCHANGE
,
URLCHANGE
=
[
1
<<
x
for
x
in
range
(
UpdateProgress
.
_num_op_codes
,
UpdateProgress
.
_num_op_codes
+
4
)
]
_num_op_codes
=
UpdateProgress
.
_num_op_codes
+
4
__slots__
=
()
BEGIN
=
RootUpdateProgress
.
BEGIN
END
=
RootUpdateProgress
.
END
REMOVE
=
RootUpdateProgress
.
REMOVE
BRANCHCHANGE
=
RootUpdateProgress
.
BRANCHCHANGE
URLCHANGE
=
RootUpdateProgress
.
URLCHANGE
PATHCHANGE
=
RootUpdateProgress
.
PATHCHANGE
class
RootModule
(
Submodule
):
"""A (virtual) root of all submodules in the given repository.
This can be used to more easily traverse all submodules of the
superproject (master repository).
"""
__slots__
=
()
k_root_name
=
"__ROOT__"
def
__init__
(
self
,
repo
:
"Repo"
)
->
None
:
# repo, binsha, mode=None, path=None, name = None, parent_commit=None, url=None, ref=None)
super
().
__init__
(
repo
,
binsha
=
self
.
NULL_BIN_SHA
,
mode
=
self
.
k_default_mode
,
path
=
""
,
name
=
self
.
k_root_name
,
parent_commit
=
repo
.
head
.
commit
,
url
=
""
,
branch_path
=
git
.
Head
.
to_full_path
(
self
.
k_head_default
),
)
def
_clear_cache
(
self
)
->
None
:
"""May not do anything."""
pass
# { Interface
def
update
(
# type: ignore[override]
self
,
previous_commit
:
Union
[
Commit_ish
,
str
,
None
]
=
None
,
recursive
:
bool
=
True
,
force_remove
:
bool
=
False
,
init
:
bool
=
True
,
to_latest_revision
:
bool
=
False
,
progress
:
Union
[
None
,
"RootUpdateProgress"
]
=
None
,
dry_run
:
bool
=
False
,
force_reset
:
bool
=
False
,
keep_going
:
bool
=
False
,
no_fetch
:
bool
=
False
,
)
->
"RootModule"
:
"""Update the submodules of this repository to the current HEAD commit.
This method behaves smartly by determining changes of the path of a submodule's
repository, next to changes to the to-be-checked-out commit or the branch to be
checked out. This works if the submodule's ID does not change.
Additionally it will detect addition and removal of submodules, which will be
handled gracefully.
:param previous_commit:
If set to a commit-ish, the commit we should use as the previous commit the
HEAD pointed to before it was set to the commit it points to now.
If ``None``, it defaults to ``HEAD@{1}`` otherwise.
:param recursive:
If ``True``, the children of submodules will be updated as well using the
same technique.
:param force_remove:
If submodules have been deleted, they will be forcibly removed. Otherwise
the update may fail if a submodule's repository cannot be deleted as changes
have been made to it.
(See :meth:`Submodule.update <git.objects.submodule.base.Submodule.update>`
for more information.)
:param init:
If we encounter a new module which would need to be initialized, then do it.
:param to_latest_revision:
If ``True``, instead of checking out the revision pointed to by this
submodule's sha, the checked out tracking branch will be merged with the
latest remote branch fetched from the repository's origin.
Unless `force_reset` is specified, a local tracking branch will never be
reset into its past, therefore the remote branch must be in the future for
this to have an effect.
:param force_reset:
If ``True``, submodules may checkout or reset their branch even if the
repository has pending changes that would be overwritten, or if the local
tracking branch is in the future of the remote tracking branch and would be
reset into its past.
:param progress:
:class:`RootUpdateProgress` instance, or ``None`` if no progress should be
sent.
:param dry_run:
If ``True``, operations will not actually be performed. Progress messages
will change accordingly to indicate the WOULD DO state of the operation.
:param keep_going:
If ``True``, we will ignore but log all errors, and keep going recursively.
Unless `dry_run` is set as well, `keep_going` could cause
subsequent/inherited errors you wouldn't see otherwise.
In conjunction with `dry_run`, this can be useful to anticipate all errors
when updating submodules.
:param no_fetch:
If ``True``, update using locally available objects and remote-tracking
refs without fetching or cloning. Cached refs are preserved and used even
when a submodule's URL changes.
:return:
self
"""
if
self
.
repo
.
bare
:
raise
InvalidGitRepositoryError
(
"Cannot update submodules in bare repositories"
)
# END handle bare
if
progress
is
None
:
progress
=
RootUpdateProgress
()
# END ensure progress is set
prefix
=
""
if
dry_run
:
prefix
=
"DRY-RUN: "
repo
=
self
.
repo
sms
:
"IterableList[Submodule]"
=
IterableList
(
"name"
)
try
:
# SETUP BASE COMMIT
###################
cur_commit
=
repo
.
head
.
commit
if
previous_commit
is
None
:
try
:
previous_commit
=
repo
.
commit
(
repo
.
head
.
log_entry
(
-
1
).
oldhexsha
)
if
previous_commit
.
binsha
==
previous_commit
.
NULL_BIN_SHA
:
raise
IndexError
# END handle initial commit
except
IndexError
:
# In new repositories, there is no previous commit.
previous_commit
=
cur_commit
# END exception handling
else
:
previous_commit
=
repo
.
commit
(
previous_commit
)
# Obtain commit object.
# END handle previous commit
psms
:
"IterableList[Submodule]"
=
self
.
list_items
(
repo
,
parent_commit
=
previous_commit
)
sms
=
self
.
list_items
(
repo
)
spsms
=
set
(
psms
)
ssms
=
set
(
sms
)
# HANDLE REMOVALS
###################
rrsm
=
spsms
-
ssms
len_rrsm
=
len
(
rrsm
)
for
i
,
rsm
in
enumerate
(
rrsm
):
op
=
REMOVE
if
i
==
0
:
op
|=
BEGIN
# END handle begin
# Fake it into thinking its at the current commit to allow deletion
# of previous module. Trigger the cache to be updated before that.
progress
.
update
(
op
,
i
,
len_rrsm
,
prefix
+
"Removing submodule %r at %s"
%
(
rsm
.
name
,
rsm
.
abspath
),
)
rsm
.
_parent_commit
=
repo
.
head
.
commit
rsm
.
remove
(
configuration
=
False
,
module
=
True
,
force
=
force_remove
,
dry_run
=
dry_run
,
)
if
i
==
len_rrsm
-
1
:
op
|=
END
# END handle end
progress
.
update
(
op
,
i
,
len_rrsm
,
prefix
+
"Done removing submodule %r"
%
rsm
.
name
)
# END for each removed submodule
# HANDLE PATH RENAMES
#####################
# URL changes + branch changes.
csms
=
spsms
&
ssms
len_csms
=
len
(
csms
)
for
i
,
csm
in
enumerate
(
csms
):
psm
:
"Submodule"
=
psms
[
csm
.
name
]
sm
:
"Submodule"
=
sms
[
csm
.
name
]
# PATH CHANGES
##############
if
sm
.
path
!=
psm
.
path
and
psm
.
module_exists
():
progress
.
update
(
BEGIN
|
PATHCHANGE
,
i
,
len_csms
,
prefix
+
"Moving repository of submodule %r from %s to %s"
%
(
sm
.
name
,
psm
.
abspath
,
sm
.
abspath
),
)
# Move the module to the new path.
if
not
dry_run
:
psm
.
move
(
sm
.
path
,
module
=
True
,
configuration
=
False
)
# END handle dry_run
progress
.
update
(
END
|
PATHCHANGE
,
i
,
len_csms
,
prefix
+
"Done moving repository of submodule %r"
%
sm
.
name
,
)
# END handle path changes
if
sm
.
module_exists
():
# HANDLE URL CHANGE
###################
if
sm
.
url
!=
psm
.
url
:
# When fetching, add the new remote and remove the old one.
# This way, if the url just changes, the commits will not have
# to be re-retrieved.
nn
=
"__new_origin__"
smm
=
sm
.
module
()
rmts
=
smm
.
remotes
# Don't do anything if we already have the url we search in
# place.
if
len
([
r
for
r
in
rmts
if
r
.
url
==
sm
.
url
])
==
0
:
progress
.
update
(
BEGIN
|
URLCHANGE
,
i
,
len_csms
,
prefix
+
"Changing url of submodule %r from %s to %s"
%
(
sm
.
name
,
psm
.
url
,
sm
.
url
),
)
if
not
dry_run
:
previous_remote
=
None
for
remote
in
rmts
:
if
remote
.
url
==
psm
.
url
:
previous_remote
=
remote
break
# END if urls match
# END for each remote
# If we didn't find a matching remote, but have exactly
# one, we can safely use this one.
if
previous_remote
is
None
:
if
len
(
rmts
)
==
1
:
previous_remote
=
rmts
[
0
]
else
:
# If we have not found any remote with the
# original URL we may not have a name. This is a
# special case, and its okay to fail here.
# Alternatively we could just generate a unique
# name and leave all existing ones in place.
raise
InvalidGitRepositoryError
(
"Couldn't find original remote-repo at url %r"
%
psm
.
url
)
# END handle one single remote
# END handle check we found a remote
if
no_fetch
:
# A new remote would have no cached refs. Preserve
# the existing refs and tracking configuration for
# offline updates instead of replacing the remote.
previous_remote
.
set_url
(
git
.
Git
.
polish_url
(
sm
.
url
,
expand_vars
=
False
))
else
:
assert
nn
not
in
[
r
.
name
for
r
in
rmts
]
smr
=
smm
.
create_remote
(
nn
,
sm
.
url
)
smr
.
fetch
(
progress
=
progress
)
# If we have a tracking branch, it should be available
# in the new remote as well.
if
len
([
r
for
r
in
smr
.
refs
if
r
.
remote_head
==
sm
.
branch_name
])
==
0
:
raise
ValueError
(
"Submodule branch named %r was not available in new submodule remote at %r"
%
(
sm
.
branch_name
,
sm
.
url
)
)
# END head is not detached
orig_name
=
previous_remote
.
name
smm
.
delete_remote
(
previous_remote
)
# NOTE: Currently we leave tags from the deleted remotes
# as well as separate tracking branches in the possibly
# totally changed repository (someone could have changed
# the url to another project). At some point, one might
# want to clean it up, but the danger is high to remove
# stuff the user has added explicitly.
# Rename the new remote back to what it was.
smr
.
rename
(
orig_name
)
# Early on, we verified that the our current tracking
# branch exists in the remote. Now we have to ensure
# that the sha we point to is still contained in the new
# remote tracking branch.
smsha
=
sm
.
binsha
found
=
False
rref
=
smr
.
refs
[
self
.
branch_name
]
for
c
in
rref
.
commit
.
traverse
():
if
c
.
binsha
==
smsha
:
found
=
True
break
# END traverse all commits in search for sha
# END for each commit
if
not
found
:
# Adjust our internal binsha to use the one of the
# remote this way, it will be checked out in the
# next step. This will change the submodule relative
# to us, so the user will be able to commit the
# change easily.
_logger
.
warning
(
"Current sha %s was not contained in the tracking
\
branch at the new remote, setting it the the remote's tracking branch"
,
sm
.
hexsha
,
)
sm
.
binsha
=
rref
.
commit
.
binsha
# END reset binsha
# NOTE: All checkout is performed by the base
# implementation of update.
# END handle dry_run
progress
.
update
(
END
|
URLCHANGE
,
i
,
len_csms
,
prefix
+
"Done adjusting url of submodule %r"
%
(
sm
.
name
),
)
# END skip remote handling if new url already exists in module
# END handle url
# HANDLE PATH CHANGES
#####################
if
sm
.
branch_path
!=
psm
.
branch_path
:
# Finally, create a new tracking branch which tracks the new
# remote branch.
progress
.
update
(
BEGIN
|
BRANCHCHANGE
,
i
,
len_csms
,
prefix
+
"Changing branch of submodule %r from %s to %s"
%
(
sm
.
name
,
psm
.
branch_path
,
sm
.
branch_path
),
)
if
not
dry_run
:
smm
=
sm
.
module
()
smmr
=
smm
.
remotes
# As the branch might not exist yet, fetch all remotes
# unless restricted to locally cached refs.
if
not
no_fetch
:
for
remote
in
smmr
:
remote
.
fetch
(
progress
=
progress
)
# END for each remote
try
:
tbr
=
git
.
Head
.
create
(
smm
,
sm
.
branch_name
,
logmsg
=
"branch: Created from HEAD"
,
)
except
OSError
:
# ...or reuse the existing one.
tbr
=
git
.
Head
(
smm
,
sm
.
branch_path
)
# END ensure tracking branch exists
tbr
.
set_tracking_branch
(
find_first_remote_branch
(
smmr
,
sm
.
branch_name
))
# NOTE: All head-resetting is done in the base
# implementation of update but we will have to checkout the
# new branch here. As it still points to the currently
# checked out commit, we don't do any harm.
# As we don't want to update working-tree or index, changing
# the ref is all there is to do.
smm
.
head
.
reference
=
tbr
# END handle dry_run
progress
.
update
(
END
|
BRANCHCHANGE
,
i
,
len_csms
,
prefix
+
"Done changing branch of submodule %r"
%
sm
.
name
,
)
# END handle branch
# END handle
# END for each common submodule
except
Exception
as
err
:
if
not
keep_going
:
raise
_logger
.
error
(
str
(
err
))
# END handle keep_going
# FINALLY UPDATE ALL ACTUAL SUBMODULES
######################################
for
sm
in
sms
:
# Update the submodule using the default method.
sm
.
update
(
recursive
=
False
,
init
=
init
,
to_latest_revision
=
to_latest_revision
,
progress
=
progress
,
dry_run
=
dry_run
,
force
=
force_reset
,
keep_going
=
keep_going
,
no_fetch
=
no_fetch
,
)
# Update recursively depth first - question is which inconsistent state will
# be better in case it fails somewhere. Defective branch or defective depth.
# The RootSubmodule type will never process itself, which was done in the
# previous expression.
if
recursive
:
# The module would exist by now if we are not in dry_run mode.
if
sm
.
module_exists
():
type
(
self
)(
sm
.
module
()).
update
(
recursive
=
True
,
force_remove
=
force_remove
,
init
=
init
,
to_latest_revision
=
to_latest_revision
,
progress
=
progress
,
dry_run
=
dry_run
,
force_reset
=
force_reset
,
keep_going
=
keep_going
,
no_fetch
=
no_fetch
,
)
# END handle dry_run
# END handle recursive
# END for each submodule to update
return
self
def
module
(
self
)
->
"Repo"
:
""":return: The actual repository containing the submodules"""
return
self
.
repo
# } END interface
# } END classes
Back
|
FazBrowse Home
|
New Git URL