@@ -5,6 +5,7 @@ use std::fs;
55use std:: path:: { Path , PathBuf } ;
66
77use anyhow:: { bail, Context , Result } ;
8+ use cargo_metadata:: MetadataCommand ;
89use cargo_toml:: { Dependency , Manifest } ;
910use normpath:: PathExt ;
1011
@@ -44,6 +45,7 @@ impl<'a> SplicerKind<'a> {
4445 pub fn new (
4546 manifests : & ' a HashMap < PathBuf , Manifest > ,
4647 splicing_manifest : & ' a SplicingManifest ,
48+ cargo : & Path ,
4749 ) -> Result < Self > {
4850 // First check for any workspaces in the provided manifests
4951 let workspace_owned: HashMap < & PathBuf , & Manifest > = manifests
@@ -67,7 +69,33 @@ impl<'a> SplicerKind<'a> {
6769 bail ! ( "When splicing manifests, there can only be 1 root workspace manifest" ) ;
6870 }
6971
72+ // This is an error case - we've detected some manifests are in a workspace, but can't
73+ // find it.
74+ // This block is just for trying to give as useful an error message as possible in this
75+ // case.
76+ if workspace_roots. is_empty ( ) {
77+ let sorted_manifests: BTreeSet < _ > = manifests. keys ( ) . collect ( ) ;
78+ for manifest_path in sorted_manifests {
79+ let metadata_result = MetadataCommand :: new ( )
80+ . cargo_path ( cargo)
81+ . current_dir ( manifest_path. parent ( ) . unwrap ( ) )
82+ . manifest_path ( manifest_path)
83+ . no_deps ( )
84+ . exec ( ) ;
85+ if let Ok ( metadata) = metadata_result {
86+ let label = Label :: from_absolute_path (
87+ metadata. workspace_root . join ( "Cargo.toml" ) . as_std_path ( ) ,
88+ ) ;
89+ if let Ok ( label) = label {
90+ bail ! ( "Missing root workspace manifest. Please add the following label to the `manifests` key: \" {}\" " , label) ;
91+ }
92+ }
93+ }
94+ bail ! ( "Missing root workspace manifest. Please add the label of the workspace root to the `manifests` key" ) ;
95+ }
96+
7097 // Ensure all workspace owned manifests are members of the one workspace root
98+ // UNWRAP: Safe because we've checked workspace_roots isn't empty.
7199 let ( root_manifest_path, root_manifest) = workspace_roots. drain ( ) . last ( ) . unwrap ( ) ;
72100 let external_workspace_members: BTreeSet < String > = workspace_packages
73101 . into_iter ( )
@@ -470,8 +498,9 @@ impl Splicer {
470498 }
471499
472500 /// Build a new workspace root
473- pub fn splice_workspace ( & self ) -> Result < SplicedManifest > {
474- SplicerKind :: new ( & self . manifests , & self . splicing_manifest ) ?. splice ( & self . workspace_dir )
501+ pub fn splice_workspace ( & self , cargo : & Path ) -> Result < SplicedManifest > {
502+ SplicerKind :: new ( & self . manifests , & self . splicing_manifest , cargo) ?
503+ . splice ( & self . workspace_dir )
475504 }
476505}
477506
@@ -706,6 +735,10 @@ mod test {
706735 ( PathBuf :: from ( "cargo" ) , PathBuf :: from ( "rustc" ) )
707736 }
708737
738+ fn cargo ( ) -> PathBuf {
739+ get_cargo_and_rustc_paths ( ) . 0
740+ }
741+
709742 fn generate_metadata ( manifest_path : & Path ) -> cargo_metadata:: Metadata {
710743 let manifest_dir = manifest_path. parent ( ) . unwrap_or_else ( || {
711744 panic ! (
@@ -746,16 +779,28 @@ mod test {
746779 }
747780
748781 fn mock_cargo_toml ( path : & Path , name : & str ) -> cargo_toml:: Manifest {
782+ mock_cargo_toml_with_dependencies ( path, name, & [ ] )
783+ }
784+
785+ fn mock_cargo_toml_with_dependencies (
786+ path : & Path ,
787+ name : & str ,
788+ deps : & [ & str ] ,
789+ ) -> cargo_toml:: Manifest {
749790 let manifest = cargo_toml:: Manifest :: from_str ( & textwrap:: dedent ( & format ! (
750791 r#"
751792 [package]
752- name = "{}"
793+ name = "{name }"
753794 version = "0.0.1"
754795
755796 [lib]
756797 path = "lib.rs"
798+
799+ [dependencies]
800+ {dependencies}
757801 "# ,
758- name
802+ name = name,
803+ dependencies = deps. join( "\n " )
759804 ) ) )
760805 . unwrap ( ) ;
761806
@@ -809,7 +854,12 @@ mod test {
809854 . join ( "root_pkg" )
810855 . join ( pkg)
811856 . join ( "Cargo.toml" ) ;
812- mock_cargo_toml ( & manifest_path, pkg) ;
857+ let deps = if pkg == & "sub_pkg_b" {
858+ vec ! [ r#"sub_pkg_a = { path = "../sub_pkg_a" }"# ]
859+ } else {
860+ vec ! [ ]
861+ } ;
862+ mock_cargo_toml_with_dependencies ( & manifest_path, pkg, & deps) ;
813863
814864 splicing_manifest. manifests . insert (
815865 manifest_path,
@@ -842,6 +892,9 @@ mod test {
842892 let manifest_path = root_pkg. join ( "Cargo.toml" ) ;
843893 fs:: create_dir_all ( & manifest_path. parent ( ) . unwrap ( ) ) . unwrap ( ) ;
844894 fs:: write ( & manifest_path, toml:: to_string ( & manifest) . unwrap ( ) ) . unwrap ( ) ;
895+ {
896+ File :: create ( root_pkg. join ( "BUILD.bazel" ) ) . unwrap ( ) ;
897+ }
845898
846899 let sub_pkg_a = root_pkg. join ( "sub_pkg_a" ) ;
847900 let sub_pkg_b = root_pkg. join ( "sub_pkg_b" ) ;
@@ -855,7 +908,7 @@ mod test {
855908
856909 splicing_manifest. manifests . insert (
857910 manifest_path,
858- Label :: from_str ( "//pkg_root :Cargo.toml" ) . unwrap ( ) ,
911+ Label :: from_str ( "//root_pkg :Cargo.toml" ) . unwrap ( ) ,
859912 ) ;
860913
861914 ( splicing_manifest, cache_dir)
@@ -977,7 +1030,7 @@ mod test {
9771030 let workspace_manifest =
9781031 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
9791032 . unwrap ( )
980- . splice_workspace ( )
1033+ . splice_workspace ( & cargo ( ) )
9811034 . unwrap ( ) ;
9821035
9831036 // Ensure metadata is valid
@@ -1010,7 +1063,7 @@ mod test {
10101063 let workspace_manifest =
10111064 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
10121065 . unwrap ( )
1013- . splice_workspace ( )
1066+ . splice_workspace ( & cargo ( ) )
10141067 . unwrap ( ) ;
10151068
10161069 // Ensure metadata is valid
@@ -1041,15 +1094,15 @@ mod test {
10411094 // Remove everything but the root manifest
10421095 splicing_manifest
10431096 . manifests
1044- . retain ( |_, label| * label == Label :: from_str ( "//pkg_root :Cargo.toml" ) . unwrap ( ) ) ;
1097+ . retain ( |_, label| * label == Label :: from_str ( "//root_pkg :Cargo.toml" ) . unwrap ( ) ) ;
10451098 assert_eq ! ( splicing_manifest. manifests. len( ) , 1 ) ;
10461099
10471100 // Splice the workspace
10481101 let workspace_root = tempfile:: tempdir ( ) . unwrap ( ) ;
10491102 let workspace_manifest =
10501103 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
10511104 . unwrap ( )
1052- . splice_workspace ( ) ;
1105+ . splice_workspace ( & cargo ( ) ) ;
10531106
10541107 assert ! ( workspace_manifest. is_err( ) ) ;
10551108
@@ -1062,6 +1115,33 @@ mod test {
10621115 ) ;
10631116 }
10641117
1118+ #[ test]
1119+ fn splice_workspace_report_missing_root ( ) {
1120+ let ( mut splicing_manifest, _cache_dir) = mock_splicing_manifest_with_workspace ( ) ;
1121+
1122+ // Remove everything but the root manifest
1123+ splicing_manifest
1124+ . manifests
1125+ . retain ( |_, label| * label != Label :: from_str ( "//root_pkg:Cargo.toml" ) . unwrap ( ) ) ;
1126+ assert_eq ! ( splicing_manifest. manifests. len( ) , 2 ) ;
1127+
1128+ // Splice the workspace
1129+ let workspace_root = tempfile:: tempdir ( ) . unwrap ( ) ;
1130+ let workspace_manifest =
1131+ Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
1132+ . unwrap ( )
1133+ . splice_workspace ( & cargo ( ) ) ;
1134+
1135+ assert ! ( workspace_manifest. is_err( ) ) ;
1136+
1137+ // Ensure both the missing manifests are mentioned in the error string
1138+ let err_str = format ! ( "{:?}" , & workspace_manifest) ;
1139+ assert ! (
1140+ err_str. contains( "Missing root workspace manifest" )
1141+ && err_str. contains( "//root_pkg:Cargo.toml" )
1142+ ) ;
1143+ }
1144+
10651145 #[ test]
10661146 fn splice_workspace_report_external_workspace_members ( ) {
10671147 let ( mut splicing_manifest, _cache_dir) = mock_splicing_manifest_with_workspace ( ) ;
@@ -1101,7 +1181,7 @@ mod test {
11011181 let workspace_manifest =
11021182 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
11031183 . unwrap ( )
1104- . splice_workspace ( ) ;
1184+ . splice_workspace ( & cargo ( ) ) ;
11051185
11061186 assert ! ( workspace_manifest. is_err( ) ) ;
11071187
@@ -1124,7 +1204,7 @@ mod test {
11241204 let workspace_manifest =
11251205 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
11261206 . unwrap ( )
1127- . splice_workspace ( )
1207+ . splice_workspace ( & cargo ( ) )
11281208 . unwrap ( ) ;
11291209
11301210 // Ensure metadata is valid
@@ -1153,7 +1233,7 @@ mod test {
11531233 let workspace_manifest =
11541234 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
11551235 . unwrap ( )
1156- . splice_workspace ( )
1236+ . splice_workspace ( & cargo ( ) )
11571237 . unwrap ( ) ;
11581238
11591239 // Check the default resolver version
@@ -1202,7 +1282,7 @@ mod test {
12021282 let workspace_manifest =
12031283 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
12041284 . unwrap ( )
1205- . splice_workspace ( )
1285+ . splice_workspace ( & cargo ( ) )
12061286 . unwrap ( ) ;
12071287
12081288 // Check the specified resolver version
@@ -1253,7 +1333,7 @@ mod test {
12531333 let workspace_root = tempfile:: tempdir ( ) . unwrap ( ) ;
12541334 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
12551335 . unwrap ( )
1256- . splice_workspace ( )
1336+ . splice_workspace ( & cargo ( ) )
12571337 . unwrap ( ) ;
12581338
12591339 let cargo_config = workspace_root. as_ref ( ) . join ( ".cargo" ) . join ( "config.toml" ) ;
@@ -1286,7 +1366,7 @@ mod test {
12861366 let workspace_root = tempfile:: tempdir ( ) . unwrap ( ) ;
12871367 Splicer :: new ( workspace_root. as_ref ( ) . to_path_buf ( ) , splicing_manifest)
12881368 . unwrap ( )
1289- . splice_workspace ( )
1369+ . splice_workspace ( & cargo ( ) )
12901370 . unwrap ( ) ;
12911371
12921372 let cargo_config = workspace_root. as_ref ( ) . join ( ".cargo" ) . join ( "config.toml" ) ;
@@ -1313,7 +1393,7 @@ mod test {
13131393 let workspace_root = temp_dir. as_ref ( ) . join ( "workspace_root" ) ;
13141394 let splicing_result = Splicer :: new ( workspace_root. clone ( ) , splicing_manifest)
13151395 . unwrap ( )
1316- . splice_workspace ( ) ;
1396+ . splice_workspace ( & cargo ( ) ) ;
13171397
13181398 // Ensure cargo config files in parent directories lead to errors
13191399 assert ! ( splicing_result. is_err( ) ) ;
0 commit comments