1
1
use cargo:: core:: dependency:: DepKind ;
2
+ use cargo:: core:: PackageIdSpec ;
2
3
use cargo:: core:: Workspace ;
3
4
use cargo:: ops:: cargo_remove:: remove;
4
5
use cargo:: ops:: cargo_remove:: RemoveOptions ;
5
6
use cargo:: ops:: resolve_ws;
6
7
use cargo:: util:: command_prelude:: * ;
8
+ use cargo:: util:: toml_mut:: dependency:: Dependency ;
9
+ use cargo:: util:: toml_mut:: dependency:: Source ;
7
10
use cargo:: util:: toml_mut:: manifest:: DepTable ;
8
11
use cargo:: util:: toml_mut:: manifest:: LocalManifest ;
9
12
use cargo:: CargoResult ;
@@ -74,22 +77,22 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
74
77
. get_many :: < String > ( "dependencies" )
75
78
. expect ( "required(true)" )
76
79
. cloned ( )
77
- . collect ( ) ;
80
+ . collect :: < Vec < _ > > ( ) ;
78
81
79
82
let section = parse_section ( args) ;
80
83
81
84
let options = RemoveOptions {
82
85
config,
83
86
spec,
84
- dependencies,
87
+ dependencies : & dependencies ,
85
88
section,
86
89
dry_run,
87
90
} ;
88
91
remove ( & options) ?;
89
92
90
93
if !dry_run {
91
- // Clean up workspace dependencies
92
- gc_workspace ( & workspace, & options . dependencies ) ?;
94
+ // Clean up the workspace
95
+ gc_workspace ( & workspace) ?;
93
96
94
97
// Reload the workspace since we've changed dependencies
95
98
let ws = args. workspace ( config) ?;
@@ -121,8 +124,9 @@ fn parse_section(args: &ArgMatches) -> DepTable {
121
124
table
122
125
}
123
126
124
- /// Clean up workspace dependencies which no longer have a reference to them.
125
- fn gc_workspace ( workspace : & Workspace < ' _ > , dependencies : & [ String ] ) -> CargoResult < ( ) > {
127
+ /// Clean up the workspace.dependencies, profile, patch, and replace sections of the root manifest
128
+ /// by removing dependencies which no longer have a reference to them.
129
+ fn gc_workspace ( workspace : & Workspace < ' _ > ) -> CargoResult < ( ) > {
126
130
let mut manifest: toml_edit:: Document =
127
131
cargo_util:: paths:: read ( workspace. root_manifest ( ) ) ?. parse ( ) ?;
128
132
@@ -131,39 +135,91 @@ fn gc_workspace(workspace: &Workspace<'_>, dependencies: &[String]) -> CargoResu
131
135
. map ( |p| LocalManifest :: try_new ( p. manifest_path ( ) ) )
132
136
. collect :: < CargoResult < Vec < _ > > > ( ) ?;
133
137
134
- for dep in dependencies {
135
- if !dep_in_workspace ( dep, & members) {
136
- remove_workspace_dep ( dep, & mut manifest) ;
137
- }
138
- }
139
-
140
- cargo_util:: paths:: write ( workspace. root_manifest ( ) , manifest. to_string ( ) . as_bytes ( ) ) ?;
141
-
142
- Ok ( ( ) )
143
- }
144
-
145
- /// Get whether or not a dependency is depended upon in a workspace.
146
- fn dep_in_workspace ( dep : & str , members : & [ LocalManifest ] ) -> bool {
147
- members. iter ( ) . any ( |manifest| {
148
- manifest. get_sections ( ) . iter ( ) . any ( |( _, table) | {
149
- table
150
- . as_table_like ( )
151
- . unwrap ( )
152
- . get ( dep)
153
- . and_then ( |t| t. get ( "workspace" ) )
154
- . and_then ( |v| v. as_bool ( ) )
155
- . unwrap_or ( false )
138
+ let dependencies = members
139
+ . iter ( )
140
+ . flat_map ( |manifest| {
141
+ manifest. get_sections ( ) . into_iter ( ) . flat_map ( |( _, table) | {
142
+ table
143
+ . as_table_like ( )
144
+ . unwrap ( )
145
+ . iter ( )
146
+ . map ( |( key, item) | Dependency :: from_toml ( & manifest. path , key, item) )
147
+ . collect :: < Vec < _ > > ( )
148
+ } )
156
149
} )
157
- } )
158
- }
150
+ . collect :: < CargoResult < Vec < _ > > > ( ) ?;
159
151
160
- /// Remove a dependency from a workspace manifest.
161
- fn remove_workspace_dep ( dep : & str , ws_manifest : & mut toml_edit:: Document ) {
162
- if let Some ( toml_edit:: Item :: Table ( table) ) = ws_manifest
152
+ // clean up workspace.dependencies
153
+ if let Some ( toml_edit:: Item :: Table ( deps_table) ) = manifest
163
154
. get_mut ( "workspace" )
164
155
. and_then ( |t| t. get_mut ( "dependencies" ) )
165
156
{
157
+ deps_table. set_implicit ( true ) ;
158
+ for ( key, item) in deps_table. iter_mut ( ) {
159
+ if !dependencies. iter ( ) . any ( |d| {
160
+ d. toml_key ( ) == key. get ( ) && matches ! ( d. source( ) , Some ( Source :: Workspace ( _) ) )
161
+ } ) {
162
+ * item = toml_edit:: Item :: None ;
163
+ }
164
+ }
165
+ }
166
+
167
+ // clean up the profile section
168
+ if let Some ( toml_edit:: Item :: Table ( profile_section_table) ) = manifest. get_mut ( "profile" ) {
169
+ profile_section_table. set_implicit ( true ) ;
170
+ for ( _, item) in profile_section_table. iter_mut ( ) {
171
+ if let toml_edit:: Item :: Table ( profile_table) = item {
172
+ profile_table. set_implicit ( true ) ;
173
+ if let Some ( toml_edit:: Item :: Table ( package_table) ) =
174
+ profile_table. get_mut ( "package" )
175
+ {
176
+ package_table. set_implicit ( true ) ;
177
+ for ( key, item) in package_table. iter_mut ( ) {
178
+ if let Ok ( spec) = PackageIdSpec :: parse ( key. get ( ) ) {
179
+ if !dependencies. iter ( ) . any ( |d| d. name == spec. name ( ) . as_str ( ) ) {
180
+ * item = toml_edit:: Item :: None ;
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }
186
+ }
187
+ }
188
+
189
+ // clean up patch section
190
+ if let Some ( toml_edit:: Item :: Table ( patch_section_table) ) = manifest. get_mut ( "patch" ) {
191
+ patch_section_table. set_implicit ( true ) ;
192
+ for ( _, item) in patch_section_table. iter_mut ( ) {
193
+ if let toml_edit:: Item :: Table ( patch_table) = item {
194
+ patch_table. set_implicit ( true ) ;
195
+ for ( key, item) in patch_table. iter_mut ( ) {
196
+ if !dependencies. iter ( ) . any ( |d| d. name == key. get ( ) ) {
197
+ * item = toml_edit:: Item :: None ;
198
+ }
199
+ }
200
+ }
201
+ }
202
+ }
203
+
204
+ // clean up replace section
205
+ if let Some ( toml_edit:: Item :: Table ( table) ) = manifest. get_mut ( "replace" ) {
166
206
table. set_implicit ( true ) ;
167
- table. remove ( dep) ;
207
+ for ( key, item) in table. iter_mut ( ) {
208
+ if let Ok ( spec) = PackageIdSpec :: parse ( key. get ( ) ) {
209
+ if !dependencies. iter ( ) . any ( |d| {
210
+ d. name == spec. name ( ) . as_str ( )
211
+ && d. version ( )
212
+ . and_then ( |v| semver:: VersionReq :: parse ( v) . ok ( ) )
213
+ . and_then ( |vq| spec. version ( ) . map ( |v| vq. matches ( v) ) )
214
+ . unwrap_or ( true )
215
+ } ) {
216
+ * item = toml_edit:: Item :: None ;
217
+ }
218
+ }
219
+ }
168
220
}
221
+
222
+ cargo_util:: paths:: write ( workspace. root_manifest ( ) , manifest. to_string ( ) . as_bytes ( ) ) ?;
223
+
224
+ Ok ( ( ) )
169
225
}
0 commit comments