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