@@ -63,7 +63,7 @@ def _list_dependencies_by_crate(path: pathlib.Path, *, basedir: pathlib.Path, ca
63
63
metadata = _cargo_metadata (cwd = path .parent )
64
64
65
65
# First, collects source files in the same crate.
66
- common_result = set (_source_files_in_same_targets (path , _related_source_files (metadata )))
66
+ common_result = set (_source_files_in_same_targets (path , _related_source_files (basedir , metadata )))
67
67
68
68
main_package_and_target = _find_target (metadata , path )
69
69
if not main_package_and_target :
@@ -132,14 +132,15 @@ def from_dep_kind(cls, kind: str):
132
132
continue
133
133
depended_target = next (filter (_is_lib_or_proc_macro , depended_package ['targets' ]), None )
134
134
if depended_target :
135
- related_source_files = _related_source_files (_cargo_metadata_by_manifest_path (pathlib .Path (depended_package ["manifest_path" ])))
135
+ related_source_files = _related_source_files (basedir , _cargo_metadata_by_manifest_path (pathlib .Path (depended_package ["manifest_path" ])))
136
136
ret |= _source_files_in_same_targets (pathlib .Path (depended_target ['src_path' ]), related_source_files )
137
137
return sorted (ret )
138
138
139
139
140
- def _related_source_files (metadata : Dict [str , Any ]) -> Dict [pathlib .Path , FrozenSet [pathlib .Path ]]:
140
+ def _related_source_files (basedir : pathlib . Path , metadata : Dict [str , Any ]) -> Dict [pathlib .Path , FrozenSet [pathlib .Path ]]:
141
141
"""Collects all of the `.rs` files recognized by a workspace.
142
142
143
+ :param basedir: A parameter from `Language.list_dependencies`.
143
144
:param metadata: Output of `cargo metadata`
144
145
:returns: A (main source file) → (other related files) map
145
146
"""
@@ -159,24 +160,36 @@ def _related_source_files(metadata: Dict[str, Any]) -> Dict[pathlib.Path, Frozen
159
160
160
161
targets_in_workspace = itertools .chain .from_iterable (p ['targets' ] for p in metadata ['packages' ] if p ['id' ] in metadata ['workspace_members' ])
161
162
for target in targets_in_workspace :
162
- # Finds a **latest** `.d` file that contains a line in the following format, and parses the line.
163
+ # Finds the **latest** "dep-info" file that contains a line in the following format, and parses the line.
163
164
#
164
165
# ```
165
- # <absolute path to the `.d` file itself>: <relative path to the root source file> <relative/aboslute paths to the other related files>...
166
+ # <relative/ absolute path to the `.d` file itself>: <relative/absolute path to the root source file> <relative/aboslute paths to the other related files>...
166
167
# ```
167
- d_file_paths = sorted (
168
+ #
169
+ # - https://github.com/rust-lang/cargo/blob/rust-1.49.0/src/cargo/core/compiler/fingerprint.rs#L1979-L1997
170
+ # - https://github.com/rust-lang/cargo/blob/rust-1.49.0/src/cargo/core/compiler/fingerprint.rs#L1824-L1830
171
+ dep_info_paths = sorted (
168
172
pathlib .Path (metadata ['target_directory' ], 'debug' , 'deps' ).glob (f'{ target ["name" ].replace ("-" , "_" )} -*.d' ),
169
173
key = lambda p : p .stat ().st_mtime_ns ,
170
174
reverse = True ,
171
175
)
172
- for d_file_path in d_file_paths :
173
- with open (d_file_path ) as d_file :
174
- d_file_content = d_file .read ()
175
- for line in d_file_content .splitlines ():
176
- words = line .split (':' )
177
- if len (words ) == 2 and pathlib .Path (words [0 ]) == d_file_path :
178
- # Ignores paths like `/dev/null` or `/usr/share/foo/bar` (if any).
179
- paths = [pathlib .Path (metadata ['workspace_root' ], s ) for s in words [1 ].split () if not pathlib .Path (s ).is_absolute ()]
176
+ for dep_info_path in dep_info_paths :
177
+ with open (dep_info_path ) as file :
178
+ dep_info = file .read ()
179
+ for line in dep_info .splitlines ():
180
+ ss = line .split (': ' )
181
+ if len (ss ) == 2 and pathlib .Path (metadata ['workspace_root' ], ss [0 ]) == dep_info_path :
182
+ paths = []
183
+ it = iter (ss [1 ].split ())
184
+ for s in it :
185
+ while s .endswith ('\\ ' ):
186
+ s = s .rstrip ('\\ ' )
187
+ s += ' '
188
+ s += next (it )
189
+ path = pathlib .Path (metadata ['workspace_root' ], s )
190
+ # Ignores paths like `/dev/null` or `/usr/share/foo/bar` (if any).
191
+ if any (path .parts [:i + 1 ] == basedir .parts for i , _ in enumerate (path .parts )):
192
+ paths .append (path )
180
193
if paths [:1 ] == [pathlib .Path (target ['src_path' ])]:
181
194
ret [paths [0 ]] = frozenset (paths [1 :])
182
195
break
0 commit comments