11use cargo:: core:: dependency:: DepKind ;
2+ use cargo:: core:: PackageIdSpec ;
23use cargo:: core:: Workspace ;
34use cargo:: ops:: cargo_remove:: remove;
45use cargo:: ops:: cargo_remove:: RemoveOptions ;
56use cargo:: ops:: resolve_ws;
67use cargo:: util:: command_prelude:: * ;
8+ use cargo:: util:: toml_mut:: dependency:: Dependency ;
9+ use cargo:: util:: toml_mut:: dependency:: Source ;
710use cargo:: util:: toml_mut:: manifest:: DepTable ;
811use cargo:: util:: toml_mut:: manifest:: LocalManifest ;
912use cargo:: CargoResult ;
@@ -74,22 +77,22 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
7477 . get_many :: < String > ( "dependencies" )
7578 . expect ( "required(true)" )
7679 . cloned ( )
77- . collect ( ) ;
80+ . collect :: < Vec < _ > > ( ) ;
7881
7982 let section = parse_section ( args) ;
8083
8184 let options = RemoveOptions {
8285 config,
8386 spec,
84- dependencies,
87+ dependencies : & dependencies ,
8588 section,
8689 dry_run,
8790 } ;
8891 remove ( & options) ?;
8992
9093 if !dry_run {
91- // Clean up workspace dependencies
92- gc_workspace ( & workspace, & options . dependencies ) ?;
94+ // Clean up the workspace
95+ gc_workspace ( & workspace) ?;
9396
9497 // Reload the workspace since we've changed dependencies
9598 let ws = args. workspace ( config) ?;
@@ -121,8 +124,9 @@ fn parse_section(args: &ArgMatches) -> DepTable {
121124 table
122125}
123126
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 < ( ) > {
126130 let mut manifest: toml_edit:: Document =
127131 cargo_util:: paths:: read ( workspace. root_manifest ( ) ) ?. parse ( ) ?;
128132
@@ -131,39 +135,91 @@ fn gc_workspace(workspace: &Workspace<'_>, dependencies: &[String]) -> CargoResu
131135 . map ( |p| LocalManifest :: try_new ( p. manifest_path ( ) ) )
132136 . collect :: < CargoResult < Vec < _ > > > ( ) ?;
133137
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+ } )
156149 } )
157- } )
158- }
150+ . collect :: < CargoResult < Vec < _ > > > ( ) ?;
159151
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
163154 . get_mut ( "workspace" )
164155 . and_then ( |t| t. get_mut ( "dependencies" ) )
165156 {
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" ) {
166206 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+ }
168220 }
221+
222+ cargo_util:: paths:: write ( workspace. root_manifest ( ) , manifest. to_string ( ) . as_bytes ( ) ) ?;
223+
224+ Ok ( ( ) )
169225}
0 commit comments