1- use std:: env;
1+ use std:: { env, path :: PathBuf } ;
22
33use anyhow:: { anyhow, Context , Result } ;
44use cargo_metadata:: {
5- camino :: Utf8PathBuf , Metadata , MetadataCommand , Package , PackageName , Target , TargetKind ,
5+ Metadata , MetadataCommand , Package , PackageName , Target , TargetKind ,
66} ;
77use clap:: Parser ;
88
@@ -96,10 +96,15 @@ impl TryFrom<&TargetKind> for HermesTargetKind {
9696 }
9797}
9898
99+ pub struct Roots {
100+ pub workspace : PathBuf ,
101+ pub roots : Vec < ( PackageName , HermesTargetKind , PathBuf ) > ,
102+ }
103+
99104/// Resolves all verification roots.
100105///
101106/// Each entry represents a distinct compilation artifact to be verified.
102- pub fn resolve_roots ( args : & Args ) -> Result < Vec < ( PackageName , HermesTargetKind , Utf8PathBuf ) > > {
107+ pub fn resolve_roots ( args : & Args ) -> Result < Roots > {
103108 let mut cmd = MetadataCommand :: new ( ) ;
104109
105110 if let Some ( path) = & args. manifest . manifest_path {
@@ -111,10 +116,13 @@ pub fn resolve_roots(args: &Args) -> Result<Vec<(PackageName, HermesTargetKind,
111116 args. features . forward_metadata ( & mut cmd) ;
112117
113118 let metadata = cmd. exec ( ) . context ( "Failed to run 'cargo metadata'" ) ?;
119+ check_for_external_deps ( & metadata) ?;
114120
115121 let selected_packages = resolve_packages ( & metadata, & args. workspace ) ?;
116122
117- let mut roots = Vec :: new ( ) ;
123+ let mut roots =
124+ Roots { workspace : metadata. workspace_root . as_std_path ( ) . to_owned ( ) , roots : Vec :: new ( ) } ;
125+
118126 for package in selected_packages {
119127 log:: trace!( "Scanning package: {}" , package. name) ;
120128
@@ -126,7 +134,11 @@ pub fn resolve_roots(args: &Args) -> Result<Vec<(PackageName, HermesTargetKind,
126134 }
127135
128136 for ( target, kind) in targets {
129- roots. push ( ( package. name . clone ( ) , kind. clone ( ) , target. src_path . clone ( ) ) ) ;
137+ roots. roots . push ( (
138+ package. name . clone ( ) ,
139+ kind. clone ( ) ,
140+ target. src_path . as_std_path ( ) . to_owned ( ) ,
141+ ) ) ;
130142 }
131143 }
132144
@@ -254,3 +266,35 @@ fn resolve_targets<'a>(
254266
255267 Ok ( selected_artifacts)
256268}
269+
270+ // TODO: Eventually, we'll want to support external path dependencies by
271+ // rewriting the path in the `Cargo.toml` in the shadow copy.
272+
273+ /// Scans the package graph to ensure all local dependencies are contained
274+ /// within the workspace root. Returns an error if an external path dependency
275+ /// is found.
276+ pub fn check_for_external_deps ( metadata : & Metadata ) -> Result < ( ) > {
277+ let workspace_root = metadata. workspace_root . as_std_path ( ) ;
278+
279+ for pkg in & metadata. packages {
280+ // We only care about packages that are "local" (source is None).
281+ // If source is Some(...), it's from crates.io or git, which is fine
282+ // (handled by Cargo).
283+ if pkg. source . is_none ( ) {
284+ let pkg_path = pkg. manifest_path . as_std_path ( ) ;
285+
286+ // Check if the package lives outside the workspace tree
287+ if !pkg_path. starts_with ( workspace_root) {
288+ anyhow:: bail!(
289+ "Unsupported external dependency: '{}' at {:?}.\n \
290+ Hermes currently only supports verifying workspaces where all local \
291+ dependencies are contained within the workspace root.",
292+ pkg. name,
293+ pkg_path
294+ ) ;
295+ }
296+ }
297+ }
298+
299+ Ok ( ( ) )
300+ }
0 commit comments