@@ -529,30 +529,21 @@ impl<'a> DistributableToolchain<'a> {
529529
530530 // Installed only.
531531 pub ( crate ) fn add_component ( & self , mut component : Component ) -> Result < ( ) > {
532- if !self . 0 . exists ( ) {
533- return Err ( RustupError :: ToolchainNotInstalled ( self . 0 . name . to_owned ( ) ) . into ( ) ) ;
534- }
535-
536- let toolchain = & self . 0 . name ;
537- let toolchain = ToolchainDesc :: from_str ( toolchain) . expect ( "must be valid" ) ;
538-
539- let prefix = InstallPrefix :: from ( self . 0 . path . to_owned ( ) ) ;
540- let manifestation = Manifestation :: open ( prefix, toolchain. target . clone ( ) ) ?;
541-
542- if let Some ( manifest) = manifestation. load_manifest ( ) ? {
532+ if let Some ( desc) = self . get_toolchain_desc_with_manifest ( ) ? {
543533 // Rename the component if necessary.
544- if let Some ( c) = manifest. rename_component ( & component) {
534+ if let Some ( c) = desc . manifest . rename_component ( & component) {
545535 component = c;
546536 }
547537
548538 // Validate the component name
549- let rust_pkg = manifest
539+ let rust_pkg = desc
540+ . manifest
550541 . packages
551542 . get ( "rust" )
552543 . expect ( "manifest should contain a rust package" ) ;
553544 let targ_pkg = rust_pkg
554545 . targets
555- . get ( & toolchain. target )
546+ . get ( & desc . toolchain . target )
556547 . expect ( "installed manifest should have a known target" ) ;
557548
558549 if !targ_pkg. components . contains ( & component) {
@@ -562,8 +553,12 @@ impl<'a> DistributableToolchain<'a> {
562553 } else {
563554 return Err ( RustupError :: UnknownComponent {
564555 name : self . 0 . name . to_string ( ) ,
565- component : component. description ( & manifest) ,
566- suggestion : self . get_component_suggestion ( & component, & manifest, false ) ,
556+ component : component. description ( & desc. manifest ) ,
557+ suggestion : self . get_component_suggestion (
558+ & component,
559+ & desc. manifest ,
560+ false ,
561+ ) ,
567562 }
568563 . into ( ) ) ;
569564 }
@@ -574,13 +569,13 @@ impl<'a> DistributableToolchain<'a> {
574569 remove_components : vec ! [ ] ,
575570 } ;
576571
577- manifestation. update (
578- & manifest,
572+ desc . manifestation . update (
573+ & desc . manifest ,
579574 changes,
580575 false ,
581576 & self . download_cfg ( ) ,
582577 & self . download_cfg ( ) . notify_handler ,
583- & toolchain. manifest_name ( ) ,
578+ & desc . toolchain . manifest_name ( ) ,
584579 false ,
585580 ) ?;
586581
@@ -737,17 +732,7 @@ impl<'a> DistributableToolchain<'a> {
737732
738733 // Installed only.
739734 pub ( crate ) fn get_manifest ( & self ) -> Result < Option < Manifest > > {
740- if !self . 0 . exists ( ) {
741- bail ! ( RustupError :: ToolchainNotInstalled ( self . 0 . name( ) . to_owned( ) ) ) ;
742- }
743-
744- let toolchain = & self . 0 . name ( ) ;
745- let toolchain = ToolchainDesc :: from_str ( toolchain) ?;
746-
747- let prefix = InstallPrefix :: from ( self . 0 . path ( ) . to_owned ( ) ) ;
748- let manifestation = Manifestation :: open ( prefix, toolchain. target ) ?;
749-
750- manifestation. load_manifest ( )
735+ Ok ( self . get_toolchain_desc_with_manifest ( ) ?. map ( |d| d. manifest ) )
751736 }
752737
753738 // Not installed only?
@@ -802,102 +787,53 @@ impl<'a> DistributableToolchain<'a> {
802787 }
803788 }
804789
805- // Installed only.
806- pub fn list_components ( & self ) -> Result < Vec < ComponentStatus > > {
790+ pub ( crate ) fn get_toolchain_desc_with_manifest (
791+ & self ,
792+ ) -> Result < Option < ToolchainDescWithManifest > > {
807793 if !self . 0 . exists ( ) {
808794 bail ! ( RustupError :: ToolchainNotInstalled ( self . 0 . name. to_owned( ) ) ) ;
809795 }
810-
811796 let toolchain = & self . 0 . name ;
812797 let toolchain = ToolchainDesc :: from_str ( toolchain)
813798 . context ( RustupError :: ComponentsUnsupported ( self . 0 . name . to_string ( ) ) ) ?;
814799
815800 let prefix = InstallPrefix :: from ( self . 0 . path . to_owned ( ) ) ;
816801 let manifestation = Manifestation :: open ( prefix, toolchain. target . clone ( ) ) ?;
802+ Ok ( manifestation
803+ . load_manifest ( ) ?
804+ . map ( |manifest| ToolchainDescWithManifest {
805+ toolchain,
806+ manifestation,
807+ manifest,
808+ } ) )
809+ }
817810
818- if let Some ( manifest) = manifestation. load_manifest ( ) ? {
819- let config = manifestation. read_config ( ) ?;
820-
821- // Return all optional components of the "rust" package for the
822- // toolchain's target triple.
823- let mut res = Vec :: new ( ) ;
824-
825- let rust_pkg = manifest
826- . packages
827- . get ( "rust" )
828- . expect ( "manifest should contain a rust package" ) ;
829- let targ_pkg = rust_pkg
830- . targets
831- . get ( & toolchain. target )
832- . expect ( "installed manifest should have a known target" ) ;
833-
834- for component in & targ_pkg. components {
835- let installed = config
836- . as_ref ( )
837- . map ( |c| component. contained_within ( & c. components ) )
838- . unwrap_or ( false ) ;
839-
840- let component_target = TargetTriple :: new ( & component. target ( ) ) ;
841-
842- // Get the component so we can check if it is available
843- let component_pkg = manifest
844- . get_package ( component. short_name_in_manifest ( ) )
845- . unwrap_or_else ( |_| {
846- panic ! (
847- "manifest should contain component {}" ,
848- & component. short_name( & manifest)
849- )
850- } ) ;
851- let component_target_pkg = component_pkg
852- . targets
853- . get ( & component_target)
854- . expect ( "component should have target toolchain" ) ;
855-
856- res. push ( ComponentStatus {
857- component : component. clone ( ) ,
858- name : component. name ( & manifest) ,
859- installed,
860- available : component_target_pkg. available ( ) ,
861- } ) ;
862- }
863-
864- res. sort_by ( |a, b| a. component . cmp ( & b. component ) ) ;
865-
866- Ok ( res)
811+ pub fn list_components ( & self ) -> Result < Vec < ComponentStatus > > {
812+ if let Some ( toolchain) = self . get_toolchain_desc_with_manifest ( ) ? {
813+ toolchain. list_components ( )
867814 } else {
868815 Err ( RustupError :: ComponentsUnsupported ( self . 0 . name . to_string ( ) ) . into ( ) )
869816 }
870817 }
871818
872819 // Installed only.
873820 pub ( crate ) fn remove_component ( & self , mut component : Component ) -> Result < ( ) > {
874- // Overlapping code with get_manifest :/.
875- if !self . 0 . exists ( ) {
876- return Err ( RustupError :: ToolchainNotInstalled ( self . 0 . name . to_owned ( ) ) . into ( ) ) ;
877- }
878-
879- let toolchain = & self . 0 . name ;
880- let toolchain = ToolchainDesc :: from_str ( toolchain) . expect ( "must be valid" ) ;
881-
882- let prefix = InstallPrefix :: from ( self . 0 . path . to_owned ( ) ) ;
883- let manifestation = Manifestation :: open ( prefix, toolchain. target . clone ( ) ) ?;
884-
885- if let Some ( manifest) = manifestation. load_manifest ( ) ? {
821+ if let Some ( desc) = self . get_toolchain_desc_with_manifest ( ) ? {
886822 // Rename the component if necessary.
887- if let Some ( c) = manifest. rename_component ( & component) {
823+ if let Some ( c) = desc . manifest . rename_component ( & component) {
888824 component = c;
889825 }
890826
891- let dist_config = manifestation. read_config ( ) ?. unwrap ( ) ;
827+ let dist_config = desc . manifestation . read_config ( ) ?. unwrap ( ) ;
892828 if !dist_config. components . contains ( & component) {
893829 let wildcard_component = component. wildcard ( ) ;
894830 if dist_config. components . contains ( & wildcard_component) {
895831 component = wildcard_component;
896832 } else {
897833 return Err ( RustupError :: UnknownComponent {
898834 name : self . 0 . name . to_string ( ) ,
899- component : component. description ( & manifest) ,
900- suggestion : self . get_component_suggestion ( & component, & manifest, true ) ,
835+ component : component. description ( & desc . manifest ) ,
836+ suggestion : self . get_component_suggestion ( & component, & desc . manifest , true ) ,
901837 }
902838 . into ( ) ) ;
903839 }
@@ -908,13 +844,13 @@ impl<'a> DistributableToolchain<'a> {
908844 remove_components : vec ! [ component] ,
909845 } ;
910846
911- manifestation. update (
912- & manifest,
847+ desc . manifestation . update (
848+ & desc . manifest ,
913849 changes,
914850 false ,
915851 & self . download_cfg ( ) ,
916852 & self . download_cfg ( ) . notify_handler ,
917- & toolchain. manifest_name ( ) ,
853+ & desc . toolchain . manifest_name ( ) ,
918854 false ,
919855 ) ?;
920856
@@ -972,6 +908,68 @@ impl<'a> DistributableToolchain<'a> {
972908 }
973909}
974910
911+ /// Helper type to avoid parsing a manifest more than once
912+ pub ( crate ) struct ToolchainDescWithManifest {
913+ toolchain : ToolchainDesc ,
914+ manifestation : Manifestation ,
915+ pub manifest : Manifest ,
916+ }
917+
918+ impl ToolchainDescWithManifest {
919+ pub ( crate ) fn list_components ( & self ) -> Result < Vec < ComponentStatus > > {
920+ let config = self . manifestation . read_config ( ) ?;
921+
922+ // Return all optional components of the "rust" package for the
923+ // toolchain's target triple.
924+ let mut res = Vec :: new ( ) ;
925+
926+ let rust_pkg = self
927+ . manifest
928+ . packages
929+ . get ( "rust" )
930+ . expect ( "manifest should contain a rust package" ) ;
931+ let targ_pkg = rust_pkg
932+ . targets
933+ . get ( & self . toolchain . target )
934+ . expect ( "installed manifest should have a known target" ) ;
935+
936+ for component in & targ_pkg. components {
937+ let installed = config
938+ . as_ref ( )
939+ . map ( |c| component. contained_within ( & c. components ) )
940+ . unwrap_or ( false ) ;
941+
942+ let component_target = TargetTriple :: new ( & component. target ( ) ) ;
943+
944+ // Get the component so we can check if it is available
945+ let component_pkg = self
946+ . manifest
947+ . get_package ( component. short_name_in_manifest ( ) )
948+ . unwrap_or_else ( |_| {
949+ panic ! (
950+ "manifest should contain component {}" ,
951+ & component. short_name( & self . manifest)
952+ )
953+ } ) ;
954+ let component_target_pkg = component_pkg
955+ . targets
956+ . get ( & component_target)
957+ . expect ( "component should have target toolchain" ) ;
958+
959+ res. push ( ComponentStatus {
960+ component : component. clone ( ) ,
961+ name : component. name ( & self . manifest ) ,
962+ installed,
963+ available : component_target_pkg. available ( ) ,
964+ } ) ;
965+ }
966+
967+ res. sort_by ( |a, b| a. component . cmp ( & b. component ) ) ;
968+
969+ Ok ( res)
970+ }
971+ }
972+
975973impl < ' a > InstalledToolchain < ' a > for DistributableToolchain < ' a > {
976974 fn installed_paths ( & self ) -> Result < Vec < InstalledPath < ' a > > > {
977975 let path = & self . 0 . path ;
0 commit comments