diff --git a/src/dist/component/components.rs b/src/dist/component/components.rs index 66d06a9169..f755e308e4 100644 --- a/src/dist/component/components.rs +++ b/src/dist/component/components.rs @@ -147,11 +147,18 @@ impl ComponentBuilder { utils::write_line("component", &mut file, &abs_path, &part.encode())?; } - // Add component to components file + // Add component to components file, sorting it to avoid depending + // on the order components were installed in. + let names = self.components.list()?; + let mut names: Vec<_> = names.into_iter().map(|c| c.name).collect(); + names.push(self.name.clone()); + names.sort(); + let mut contents = names.join("\n"); + contents.push('\n'); let path = self.components.rel_components_file(); let abs_path = self.components.prefix.abs_path(&path); self.tx.modify_file(path)?; - utils::append_file("components", &abs_path, &self.name)?; + utils::write_file("components", &abs_path, &contents)?; // Drop in the version file for future use self.components.write_version(&mut self.tx)?; diff --git a/tests/suite/dist_install.rs b/tests/suite/dist_install.rs index 36775f984c..680a3a8571 100644 --- a/tests/suite/dist_install.rs +++ b/tests/suite/dist_install.rs @@ -144,6 +144,32 @@ fn multiple_component_install() { assert!(components.find("mycomponent2").unwrap().is_some()); } +#[test] +fn components_file_is_independent_of_install_order() { + // Deliberately not in sorted order. + let names = ["rustc", "cargo", "rust-std"]; + let mock = MockInstallerBuilder { + components: names + .iter() + .map(|name| MockComponentBuilder { + name: name.to_string(), + files: vec![MockFile::new(format!("bin/{name}"), b"data")], + }) + .collect(), + }; + + let cx = DistContext::new(Some(mock)).unwrap(); + let (mut tx, components, pkg) = cx.start().unwrap(); + for name in names { + tx = pkg.install(&components, name, None, tx).unwrap(); + } + tx.commit(); + + let components_path = cx.prefix.manifest_file("components"); + let contents = utils::read_file("components", &components_path).unwrap(); + assert_eq!(contents, "cargo\nrust-std\nrustc\n"); +} + #[test] fn uninstall() { let mock = MockInstallerBuilder {