2
2
3
3
import itertools
4
4
from concurrent .futures import ThreadPoolExecutor
5
+ from typing import Callable , Iterable
5
6
6
7
import click
7
8
@@ -109,29 +110,37 @@ def fetch_components(cfg: Config):
109
110
+ "Please specify `--force` to discard them"
110
111
)
111
112
deps .setdefault (cdep .url , []).append (c )
112
- fetch_parallel (fetch_component , cfg , deps .values ())
113
+ do_parallel (fetch_component , cfg , deps .values ())
113
114
114
115
components = cfg .get_components ()
115
116
117
+ aliases : dict [str , list ] = {}
116
118
for alias , component in component_aliases .items ():
117
119
if alias == component :
118
120
# Nothing to setup for identity alias
119
121
continue
120
122
121
123
c = components [component ]
122
124
aspec = cspecs [alias ]
123
- adep = None
125
+ adep = c . dependency
124
126
if aspec .url != c .repo_url :
125
127
adep = cfg .register_dependency_repo (aspec .url )
126
- adep .register_component (alias , component_dir (cfg .work_dir , alias ))
127
-
128
- c .register_alias (alias , aspec .version , aspec .path )
129
- c .checkout_alias (alias , adep )
130
-
131
- create_alias_symlinks (cfg , c , alias )
132
-
133
-
134
- def fetch_component (cfg , dependencies ):
128
+ c .register_alias (alias , aspec .version , adep , aspec .path )
129
+ if adep .url in deps :
130
+ # NOTE(sg): if we already processed the dependency URL in the previous fetch
131
+ # stage, we can create all instance worktrees in parallel. We do so by using
132
+ # the alias name as the key for our "parallelization" dict.
133
+ aliases [alias ] = [(alias , c )]
134
+ else :
135
+ # Otherwise, we use adep.url as the parallelization key to avoid any race
136
+ # conditions when creating multiple worktrees from a not-yet-cloned
137
+ # dependency URL.
138
+ aliases .setdefault (adep .url , []).append ((alias , c ))
139
+
140
+ do_parallel (setup_alias , cfg , aliases .values ())
141
+
142
+
143
+ def fetch_component (cfg : Config , dependencies : Iterable ):
135
144
"""
136
145
Fetch all components of a MultiDependency object.
137
146
"""
@@ -141,7 +150,13 @@ def fetch_component(cfg, dependencies):
141
150
create_component_symlinks (cfg , c )
142
151
143
152
144
- def fetch_parallel (fetch_fun , cfg , to_fetch ):
153
+ def setup_alias (cfg : Config , aliases : Iterable ):
154
+ for alias , c in aliases :
155
+ c .checkout_alias (alias )
156
+ create_alias_symlinks (cfg , c , alias )
157
+
158
+
159
+ def do_parallel (fun : Callable [[Config , Iterable ], None ], cfg : Config , data : Iterable ):
145
160
"""
146
161
Fetch dependencies in parallel threads with ThreadPoolExecutor.
147
162
"""
@@ -150,7 +165,7 @@ def fetch_parallel(fetch_fun, cfg, to_fetch):
150
165
# that any exceptions raised in `fetch_fun` are propagated, cf.
151
166
# https://docs.python.org/3/library/concurrent.futures.html#executor-objects. We
152
167
# do so by simply materializing the iterator into a list.
153
- list (exe .map (fetch_fun , itertools .repeat (cfg ), to_fetch ))
168
+ list (exe .map (fun , itertools .repeat (cfg ), data ))
154
169
155
170
156
171
def register_components (cfg : Config ):
@@ -208,10 +223,10 @@ def register_components(cfg: Config):
208
223
c = registered_components [cn ]
209
224
aspec = cspecs [alias ]
210
225
226
+ adep = c .dependency
211
227
if aspec .url != c .repo_url :
212
228
adep = cfg .register_dependency_repo (aspec .url )
213
- adep .register_component (alias , component_dir (cfg .work_dir , alias ))
214
- c .register_alias (alias , aspec .version , aspec .path )
229
+ c .register_alias (alias , aspec .version , adep , aspec .path )
215
230
216
231
if not component_dir (cfg .work_dir , alias ).is_dir ():
217
232
raise click .ClickException (f"Missing alias checkout for '{ alias } as { cn } '" )
@@ -249,10 +264,10 @@ def fetch_packages(cfg: Config):
249
264
+ "Please specify `--force` to discard them"
250
265
)
251
266
deps .setdefault (pdep .url , []).append ((p , pkg ))
252
- fetch_parallel (fetch_package , cfg , deps .values ())
267
+ do_parallel (fetch_package , cfg , deps .values ())
253
268
254
269
255
- def fetch_package (cfg , dependencies ):
270
+ def fetch_package (cfg : Config , dependencies : Iterable ):
256
271
"""
257
272
Fetch all package dependencies of a MultiDependency object.
258
273
"""
0 commit comments