11//! Core of cargo-remove command
22
33use crate :: core:: Package ;
4+ use crate :: core:: Workspace ;
45use crate :: util:: toml_mut:: manifest:: DepTable ;
56use crate :: util:: toml_mut:: manifest:: LocalManifest ;
67use crate :: CargoResult ;
@@ -22,7 +23,7 @@ pub struct RemoveOptions<'a> {
2223}
2324
2425/// Remove dependencies from a manifest
25- pub fn remove ( options : & RemoveOptions < ' _ > ) -> CargoResult < ( ) > {
26+ pub fn remove ( workspace : & Workspace < ' _ > , options : & RemoveOptions < ' _ > ) -> CargoResult < ( ) > {
2627 let dep_table = options
2728 . section
2829 . to_table ( )
@@ -33,7 +34,17 @@ pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
3334 let manifest_path = options. spec . manifest_path ( ) . to_path_buf ( ) ;
3435 let mut manifest = LocalManifest :: try_new ( & manifest_path) ?;
3536
37+ let mut workspace_manifest = if workspace. is_virtual ( ) {
38+ let data = cargo_util:: paths:: read ( workspace. root_manifest ( ) ) ?;
39+ let manifest: toml_edit:: Document = data. parse ( ) ?;
40+ Some ( manifest)
41+ } else {
42+ None
43+ } ;
44+
3645 for dep in & options. dependencies {
46+ let is_workspace_dep = dependency_is_workspace ( dep, & dep_table, & manifest) ;
47+
3748 let section = if dep_table. len ( ) >= 3 {
3849 format ! ( "{} for target `{}`" , & dep_table[ 2 ] , & dep_table[ 1 ] )
3950 } else {
@@ -50,6 +61,21 @@ pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
5061 // crate, then we need to drop any explicitly activated features on
5162 // that crate.
5263 manifest. gc_dep ( dep) ;
64+
65+ // If this was the last instance of a workspace dependency, remove it
66+ // from the workspace dependencies.
67+ if is_workspace_dep {
68+ if let Some ( workspace_manifest) = & mut workspace_manifest {
69+ if !dependency_in_workspace ( dep, options. spec , workspace) {
70+ remove_dependency_from_workspace ( dep, workspace_manifest) ;
71+
72+ options
73+ . config
74+ . shell ( )
75+ . status ( "Removing" , format ! ( "{dep} from workspace dependencies" ) ) ?;
76+ }
77+ }
78+ }
5379 }
5480
5581 if options. dry_run {
@@ -59,7 +85,46 @@ pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
5985 . warn ( "aborting remove due to dry run" ) ?;
6086 } else {
6187 manifest. write ( ) ?;
88+
89+ if let Some ( workspace_manifest) = workspace_manifest {
90+ cargo_util:: paths:: write (
91+ workspace. root_manifest ( ) ,
92+ workspace_manifest. to_string ( ) . as_bytes ( ) ,
93+ ) ?;
94+ }
6295 }
6396
6497 Ok ( ( ) )
6598}
99+
100+ /// Get whether or not a dependency is marked as `workspace`.
101+ fn dependency_is_workspace ( dep : & str , dep_table : & [ String ] , manifest : & LocalManifest ) -> bool {
102+ if let Ok ( toml_edit:: Item :: Table ( table) ) = manifest. get_table ( dep_table) {
103+ let value = table. get ( dep) . and_then ( |i| i. get ( "workspace" ) ) ;
104+ if let Some ( toml_edit:: Item :: Value ( value) ) = value {
105+ return value. as_bool ( ) == Some ( true ) ;
106+ }
107+ }
108+
109+ false
110+ }
111+
112+ /// Get whether or not a dependency is depended upon in a workspace.
113+ fn dependency_in_workspace ( dep : & str , exclude : & Package , workspace : & Workspace < ' _ > ) -> bool {
114+ workspace. members ( ) . filter ( |p| * p != exclude) . any ( |p| {
115+ p. dependencies ( )
116+ . iter ( )
117+ . any ( |d| d. package_name ( ) . as_str ( ) == dep)
118+ } )
119+ }
120+
121+ /// Remove a dependency from a virtual workspace.
122+ fn remove_dependency_from_workspace ( dep : & str , virtual_manifest : & mut toml_edit:: Document ) {
123+ if let Some ( toml_edit:: Item :: Table ( table) ) = virtual_manifest
124+ . get_mut ( "workspace" )
125+ . and_then ( |t| t. get_mut ( "dependencies" ) )
126+ {
127+ table. set_implicit ( true ) ;
128+ table. remove ( dep) ;
129+ }
130+ }
0 commit comments