4 compression
::{CompressionFormat, CompressionFormats}
,
7 use anyhow
::{bail, Context, Result}
;
8 use std
::io
::{Read, Write}
;
15 /// The name of the product, for display.
16 #[clap(value_name = "NAME")]
17 product_name
: String
= "Product",
19 /// The name of the package tarball.
20 #[clap(value_name = "NAME")]
21 package_name
: String
= "package",
23 /// The directory under lib/ where the manifest lives.
24 #[clap(value_name = "DIR")]
25 rel_manifest_dir
: String
= "packagelib",
27 /// The string to print after successful installation.
28 #[clap(value_name = "MESSAGE")]
29 success_message
: String
= "Installed.",
31 /// Places to look for legacy manifests to uninstall.
32 #[clap(value_name = "DIRS")]
33 legacy_manifest_dirs
: String
= "",
35 /// Installers to combine.
36 #[clap(value_name = "FILE,FILE")]
37 input_tarballs
: String
= "",
39 /// Directory containing files that should not be installed.
40 #[clap(value_name = "DIR")]
41 non_installed_overlay
: String
= "",
43 /// The directory to do temporary work.
44 #[clap(value_name = "DIR")]
45 work_dir
: String
= "./workdir",
47 /// The location to put the final image and tarball.
48 #[clap(value_name = "DIR")]
49 output_dir
: String
= "./dist",
51 /// The formats used to compress the tarball
52 #[clap(value_name = "FORMAT", default_value_t)]
53 compression_formats
: CompressionFormats
,
58 /// Combines the installer tarballs.
59 pub fn run(self) -> Result
<()> {
60 create_dir_all(&self.work_dir
)?
;
62 let package_dir
= Path
::new(&self.work_dir
).join(&self.package_name
);
63 if package_dir
.exists() {
64 remove_dir_all(&package_dir
)?
;
66 create_dir_all(&package_dir
)?
;
68 // Merge each installer into the work directory of the new installer.
69 let components
= create_new_file(package_dir
.join("components"))?
;
70 for input_tarball
in self
74 .filter(|s
| !s
.is_empty())
76 // Extract the input tarballs
78 CompressionFormat
::detect_from_path(input_tarball
).ok_or_else(|| {
79 anyhow
::anyhow
!("couldn't figure out the format of {}", input_tarball
)
81 Archive
::new(compression
.decode(input_tarball
)?
)
82 .unpack(&self.work_dir
)
85 "unable to extract '{}' into '{}'",
86 &input_tarball
, self.work_dir
91 input_tarball
.trim_end_matches(&format
!(".tar.{}", compression
.extension()));
92 let pkg_name
= Path
::new(pkg_name
).file_name().unwrap();
93 let pkg_dir
= Path
::new(&self.work_dir
).join(&pkg_name
);
95 // Verify the version number.
96 let mut version
= String
::new();
97 open_file(pkg_dir
.join("rust-installer-version"))
98 .and_then(|mut file
| Ok(file
.read_to_string(&mut version
)?
))
99 .with_context(|| format
!("failed to read version in '{}'", input_tarball
))?
;
100 if version
.trim().parse() != Ok(crate::RUST_INSTALLER_VERSION
) {
101 bail
!("incorrect installer version in {}", input_tarball
);
104 // Copy components to the new combined installer.
105 let mut pkg_components
= String
::new();
106 open_file(pkg_dir
.join("components"))
107 .and_then(|mut file
| Ok(file
.read_to_string(&mut pkg_components
)?
))
108 .with_context(|| format
!("failed to read components in '{}'", input_tarball
))?
;
109 for component
in pkg_components
.split_whitespace() {
110 // All we need to do is copy the component directory. We could
111 // move it, but rustbuild wants to reuse the unpacked package
112 // dir for OS-specific installers on macOS and Windows.
113 let component_dir
= package_dir
.join(&component
);
114 create_dir(&component_dir
)?
;
115 copy_recursive(&pkg_dir
.join(&component
), &component_dir
)?
;
117 // Merge the component name.
118 writeln
!(&components
, "{}", component
).context("failed to write new components")?
;
123 // Write the installer version.
124 let version
= package_dir
.join("rust-installer-version");
126 create_new_file(version
)?
,
128 crate::RUST_INSTALLER_VERSION
130 .context("failed to write new installer version")?
;
133 if !self.non_installed_overlay
.is_empty() {
134 copy_recursive(self.non_installed_overlay
.as_ref(), &package_dir
)?
;
137 // Generate the install script.
138 let output_script
= package_dir
.join("install.sh");
139 let mut scripter
= Scripter
::default();
141 .product_name(self.product_name
)
142 .rel_manifest_dir(self.rel_manifest_dir
)
143 .success_message(self.success_message
)
144 .legacy_manifest_dirs(self.legacy_manifest_dirs
)
145 .output_script(path_to_str(&output_script
)?
.into());
148 // Make the tarballs.
149 create_dir_all(&self.output_dir
)?
;
150 let output
= Path
::new(&self.output_dir
).join(&self.package_name
);
151 let mut tarballer
= Tarballer
::default();
153 .work_dir(self.work_dir
)
154 .input(self.package_name
)
155 .output(path_to_str(&output
)?
.into())
156 .compression_formats(self.compression_formats
.clone());