]>
Commit | Line | Data |
---|---|---|
22607d1e XL |
1 | use super::Scripter; |
2 | use super::Tarballer; | |
9fa01778 | 3 | use crate::util::*; |
f035d41b | 4 | use anyhow::{bail, Context, Result}; |
416331ca XL |
5 | use flate2::read::GzDecoder; |
6 | use std::io::{Read, Write}; | |
7 | use std::path::Path; | |
8 | use tar::Archive; | |
22607d1e | 9 | |
416331ca | 10 | actor! { |
22607d1e XL |
11 | #[derive(Debug)] |
12 | pub struct Combiner { | |
416331ca | 13 | /// The name of the product, for display. |
22607d1e XL |
14 | product_name: String = "Product", |
15 | ||
416331ca | 16 | /// The name of the package tarball. |
22607d1e XL |
17 | package_name: String = "package", |
18 | ||
416331ca | 19 | /// The directory under lib/ where the manifest lives. |
22607d1e XL |
20 | rel_manifest_dir: String = "packagelib", |
21 | ||
416331ca | 22 | /// The string to print after successful installation. |
22607d1e XL |
23 | success_message: String = "Installed.", |
24 | ||
416331ca | 25 | /// Places to look for legacy manifests to uninstall. |
22607d1e XL |
26 | legacy_manifest_dirs: String = "", |
27 | ||
416331ca | 28 | /// Installers to combine. |
22607d1e XL |
29 | input_tarballs: String = "", |
30 | ||
416331ca | 31 | /// Directory containing files that should not be installed. |
22607d1e XL |
32 | non_installed_overlay: String = "", |
33 | ||
416331ca | 34 | /// The directory to do temporary work. |
22607d1e XL |
35 | work_dir: String = "./workdir", |
36 | ||
416331ca | 37 | /// The location to put the final image and tarball. |
22607d1e XL |
38 | output_dir: String = "./dist", |
39 | } | |
40 | } | |
41 | ||
42 | impl Combiner { | |
416331ca | 43 | /// Combines the installer tarballs. |
22607d1e XL |
44 | pub fn run(self) -> Result<()> { |
45 | create_dir_all(&self.work_dir)?; | |
46 | ||
47 | let package_dir = Path::new(&self.work_dir).join(&self.package_name); | |
48 | if package_dir.exists() { | |
49 | remove_dir_all(&package_dir)?; | |
50 | } | |
51 | create_dir_all(&package_dir)?; | |
52 | ||
416331ca | 53 | // Merge each installer into the work directory of the new installer. |
22607d1e | 54 | let components = create_new_file(package_dir.join("components"))?; |
416331ca XL |
55 | for input_tarball in self |
56 | .input_tarballs | |
57 | .split(',') | |
58 | .map(str::trim) | |
59 | .filter(|s| !s.is_empty()) | |
60 | { | |
22607d1e | 61 | // Extract the input tarballs |
ff7c6d11 | 62 | let tar = GzDecoder::new(open_file(&input_tarball)?); |
f035d41b | 63 | Archive::new(tar).unpack(&self.work_dir).with_context(|| { |
416331ca XL |
64 | format!( |
65 | "unable to extract '{}' into '{}'", | |
66 | &input_tarball, self.work_dir | |
67 | ) | |
68 | })?; | |
22607d1e | 69 | |
9fa01778 | 70 | let pkg_name = input_tarball.trim_end_matches(".tar.gz"); |
22607d1e XL |
71 | let pkg_name = Path::new(pkg_name).file_name().unwrap(); |
72 | let pkg_dir = Path::new(&self.work_dir).join(&pkg_name); | |
73 | ||
416331ca | 74 | // Verify the version number. |
22607d1e XL |
75 | let mut version = String::new(); |
76 | open_file(pkg_dir.join("rust-installer-version")) | |
416331ca | 77 | .and_then(|mut file| Ok(file.read_to_string(&mut version)?)) |
f035d41b | 78 | .with_context(|| format!("failed to read version in '{}'", input_tarball))?; |
9fa01778 | 79 | if version.trim().parse() != Ok(crate::RUST_INSTALLER_VERSION) { |
22607d1e XL |
80 | bail!("incorrect installer version in {}", input_tarball); |
81 | } | |
82 | ||
416331ca | 83 | // Copy components to the new combined installer. |
22607d1e XL |
84 | let mut pkg_components = String::new(); |
85 | open_file(pkg_dir.join("components")) | |
416331ca | 86 | .and_then(|mut file| Ok(file.read_to_string(&mut pkg_components)?)) |
f035d41b | 87 | .with_context(|| format!("failed to read components in '{}'", input_tarball))?; |
22607d1e | 88 | for component in pkg_components.split_whitespace() { |
416331ca | 89 | // All we need to do is copy the component directory. We could |
22607d1e XL |
90 | // move it, but rustbuild wants to reuse the unpacked package |
91 | // dir for OS-specific installers on macOS and Windows. | |
92 | let component_dir = package_dir.join(&component); | |
93 | create_dir(&component_dir)?; | |
94 | copy_recursive(&pkg_dir.join(&component), &component_dir)?; | |
95 | ||
416331ca | 96 | // Merge the component name. |
f035d41b | 97 | writeln!(&components, "{}", component).context("failed to write new components")?; |
22607d1e XL |
98 | } |
99 | } | |
100 | drop(components); | |
101 | ||
416331ca | 102 | // Write the installer version. |
22607d1e | 103 | let version = package_dir.join("rust-installer-version"); |
416331ca XL |
104 | writeln!( |
105 | create_new_file(version)?, | |
106 | "{}", | |
107 | crate::RUST_INSTALLER_VERSION | |
108 | ) | |
f035d41b | 109 | .context("failed to write new installer version")?; |
416331ca XL |
110 | |
111 | // Copy the overlay. | |
22607d1e XL |
112 | if !self.non_installed_overlay.is_empty() { |
113 | copy_recursive(self.non_installed_overlay.as_ref(), &package_dir)?; | |
114 | } | |
115 | ||
416331ca | 116 | // Generate the install script. |
22607d1e XL |
117 | let output_script = package_dir.join("install.sh"); |
118 | let mut scripter = Scripter::default(); | |
416331ca XL |
119 | scripter |
120 | .product_name(self.product_name) | |
22607d1e XL |
121 | .rel_manifest_dir(self.rel_manifest_dir) |
122 | .success_message(self.success_message) | |
123 | .legacy_manifest_dirs(self.legacy_manifest_dirs) | |
124 | .output_script(path_to_str(&output_script)?); | |
125 | scripter.run()?; | |
126 | ||
416331ca | 127 | // Make the tarballs. |
22607d1e XL |
128 | create_dir_all(&self.output_dir)?; |
129 | let output = Path::new(&self.output_dir).join(&self.package_name); | |
130 | let mut tarballer = Tarballer::default(); | |
416331ca XL |
131 | tarballer |
132 | .work_dir(self.work_dir) | |
22607d1e XL |
133 | .input(self.package_name) |
134 | .output(path_to_str(&output)?); | |
135 | tarballer.run()?; | |
136 | ||
137 | Ok(()) | |
138 | } | |
139 | } |