@@ -114,8 +114,51 @@ def fetch_git_repo(git_url: str, commit: str) -> str:
114114 if head [:COMMIT_LEN ] != commit [:COMMIT_LEN ]:
115115 subprocess .run (['git' , 'fetch' , 'origin' , commit ], cwd = clone_dir , check = True )
116116 subprocess .run (['git' , 'checkout' , commit ], cwd = clone_dir , check = True )
117+
118+ # Get the submodules as they might contain dependencies. This is a noop if
119+ # there are no submodules in the repository
120+ subprocess .run (['git' , 'submodule' , 'update' , '--init' , '--recursive' ], cwd = clone_dir , check = True )
121+
117122 return clone_dir
118123
124+ def update_workspace_keys (pkg , workspace ):
125+ for key , item in pkg .items ():
126+ # There cannot be a 'workspace' key if the item is not a dict.
127+ if not isinstance (item , dict ):
128+ continue ;
129+
130+ # Recurse for keys under target.cfg(..)
131+ if key == 'target' :
132+ for target in item .values ():
133+ update_workspace_keys (target , workspace )
134+ continue ;
135+ # dev-dependencies and build-dependencies should reference root dependencies table from workspace
136+ elif key == 'dev-dependencies' or key == 'build-dependencies' :
137+ update_workspace_keys (item , workspace .get ('dependencies' , None ))
138+ continue ;
139+
140+ if not workspace or not key in workspace :
141+ continue ;
142+
143+ workspace_item = workspace [key ]
144+
145+ if 'workspace' in item :
146+ if isinstance (workspace_item , dict ):
147+ del item ['workspace' ]
148+
149+ for dep_key , workspace_value in workspace_item .items ():
150+ # features are additive
151+ if dep_key == 'features' and 'features' in item :
152+ item ['features' ] += workspace_value
153+ else :
154+ item [dep_key ] = workspace_value
155+ elif len (item ) > 1 :
156+ del item ['workspace' ]
157+ item .update ({ 'version' : workspace_item })
158+ else :
159+ pkg [key ] = workspace_item
160+ else :
161+ update_workspace_keys (item , workspace_item )
119162
120163class _GitPackage (NamedTuple ):
121164 path : str
@@ -127,18 +170,10 @@ def normalized(self) -> _TomlType:
127170 package = copy .deepcopy (self .package )
128171 if self .workspace is None :
129172 return package
130- for section_key , section in package .items ():
131- # XXX We ignore top-level lists here; maybe we should iterate over list items, too
132- if not isinstance (section , dict ):
133- continue
134- for key , value in section .items ():
135- if not isinstance (value , dict ):
136- continue
137- if not value .get ('workspace' ):
138- continue
139- package [section_key ][key ] = self .workspace [section_key ][key ]
140- return package
141173
174+ update_workspace_keys (package , self .workspace )
175+
176+ return package
142177
143178_GitPackagesType = Dict [str , _GitPackage ]
144179
@@ -148,13 +183,27 @@ async def get_git_repo_packages(git_url: str, commit: str) -> _GitPackagesType:
148183 git_repo_dir = fetch_git_repo (git_url , commit )
149184 packages : _GitPackagesType = {}
150185
186+ def get_cargo_toml_packages (root_dir : str , workspace : Optional [_TomlType ] = None ):
187+ assert not os .path .isabs (root_dir ) and os .path .isdir (root_dir )
188+
189+ with workdir (root_dir ):
190+ if os .path .exists ('Cargo.toml' ):
191+ cargo_toml = load_toml ('Cargo.toml' )
192+ workspace = cargo_toml .get ('workspace' ) or workspace
193+
194+ if 'package' in cargo_toml :
195+ packages [cargo_toml ['package' ]['name' ]] = _GitPackage (
196+ path = os .path .normpath (root_dir ),
197+ package = cargo_toml ,
198+ workspace = workspace
199+ )
200+ for child in os .scandir (root_dir ):
201+ if child .is_dir ():
202+ # the workspace can be referenced by any subdirectory
203+ get_cargo_toml_packages (child .path , workspace )
204+
151205 with workdir (git_repo_dir ):
152- if os .path .isfile ('Cargo.toml' ):
153- packages .update (await get_cargo_toml_packages (load_toml ('Cargo.toml' ), '.' ))
154- else :
155- for toml_path in glob .glob ('*/Cargo.toml' ):
156- packages .update (await get_cargo_toml_packages (load_toml (toml_path ),
157- os .path .dirname (toml_path )))
206+ get_cargo_toml_packages ('.' )
158207
159208 assert packages , f"No packages found in { git_repo_dir } "
160209 logging .debug (
@@ -168,68 +217,6 @@ async def get_git_repo_packages(git_url: str, commit: str) -> _GitPackagesType:
168217 return packages
169218
170219
171- async def get_cargo_toml_packages (root_toml : _TomlType , root_dir : str ) -> _GitPackagesType :
172- assert not os .path .isabs (root_dir ) and os .path .isdir (root_dir )
173- assert 'package' in root_toml or 'workspace' in root_toml
174- packages : _GitPackagesType = {}
175-
176- async def get_dep_packages (
177- entry : _TomlType ,
178- toml_dir : str ,
179- workspace : Optional [_TomlType ] = None ,
180- ):
181- assert not os .path .isabs (toml_dir )
182- # https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html
183- if 'dependencies' in entry :
184- for dep_name , dep in entry ['dependencies' ].items ():
185- if 'package' in dep :
186- dep_name = dep ['package' ]
187- if 'path' not in dep :
188- continue
189- if dep_name in packages :
190- continue
191- dep_dir = os .path .normpath (os .path .join (toml_dir , dep ['path' ]))
192- logging .debug ("Loading dependency %s from %s" , dep_name , dep_dir )
193- dep_toml = load_toml (os .path .join (dep_dir , 'Cargo.toml' ))
194- assert dep_toml ['package' ]['name' ] == dep_name , toml_dir
195- await get_dep_packages (dep_toml , dep_dir , workspace )
196- packages [dep_name ] = _GitPackage (
197- path = dep_dir ,
198- package = dep ,
199- workspace = workspace ,
200- )
201- if 'target' in entry :
202- for _ , target in entry ['target' ].items ():
203- await get_dep_packages (target , toml_dir )
204-
205- if 'package' in root_toml :
206- await get_dep_packages (root_toml , root_dir )
207- packages [root_toml ['package' ]['name' ]] = _GitPackage (
208- path = root_dir ,
209- package = root_toml ,
210- workspace = None ,
211- )
212-
213- if 'workspace' in root_toml :
214- for member in root_toml ['workspace' ].get ('members' , []):
215- for subpkg_toml in glob .glob (os .path .join (root_dir , member , 'Cargo.toml' )):
216- subpkg = os .path .normpath (os .path .dirname (subpkg_toml ))
217- logging .debug (
218- "Loading workspace member %s in %s" ,
219- subpkg_toml ,
220- os .path .abspath (root_dir ),
221- )
222- pkg_toml = load_toml (subpkg_toml )
223- await get_dep_packages (pkg_toml , subpkg , root_toml ['workspace' ])
224- packages [pkg_toml ['package' ]['name' ]] = _GitPackage (
225- path = subpkg ,
226- package = pkg_toml ,
227- workspace = root_toml ['workspace' ],
228- )
229-
230- return packages
231-
232-
233220_FlatpakSourceType = Dict [str , Any ]
234221
235222
0 commit comments