1
1
//! Core of cargo-remove command
2
2
3
3
use crate :: core:: Package ;
4
+ use crate :: core:: Workspace ;
4
5
use crate :: util:: toml_mut:: manifest:: DepTable ;
5
6
use crate :: util:: toml_mut:: manifest:: LocalManifest ;
6
7
use crate :: CargoResult ;
@@ -22,7 +23,7 @@ pub struct RemoveOptions<'a> {
22
23
}
23
24
24
25
/// Remove dependencies from a manifest
25
- pub fn remove ( options : & RemoveOptions < ' _ > ) -> CargoResult < ( ) > {
26
+ pub fn remove ( workspace : & Workspace < ' _ > , options : & RemoveOptions < ' _ > ) -> CargoResult < ( ) > {
26
27
let dep_table = options
27
28
. section
28
29
. to_table ( )
@@ -33,7 +34,17 @@ pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
33
34
let manifest_path = options. spec . manifest_path ( ) . to_path_buf ( ) ;
34
35
let mut manifest = LocalManifest :: try_new ( & manifest_path) ?;
35
36
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
+
36
45
for dep in & options. dependencies {
46
+ let is_workspace_dep = dependency_is_workspace ( dep, & dep_table, & manifest) ;
47
+
37
48
let section = if dep_table. len ( ) >= 3 {
38
49
format ! ( "{} for target `{}`" , & dep_table[ 2 ] , & dep_table[ 1 ] )
39
50
} else {
@@ -50,6 +61,21 @@ pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
50
61
// crate, then we need to drop any explicitly activated features on
51
62
// that crate.
52
63
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
+ }
53
79
}
54
80
55
81
if options. dry_run {
@@ -59,7 +85,46 @@ pub fn remove(options: &RemoveOptions<'_>) -> CargoResult<()> {
59
85
. warn ( "aborting remove due to dry run" ) ?;
60
86
} else {
61
87
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
+ }
62
95
}
63
96
64
97
Ok ( ( ) )
65
98
}
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