Skip to content

Commit d3d56be

Browse files
committed
Use error-chain for more informative errors
1 parent 4f6e020 commit d3d56be

File tree

8 files changed

+178
-93
lines changed

8 files changed

+178
-93
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ name = "rust-installer"
99
path = "src/main.rs"
1010

1111
[dependencies]
12+
error-chain = "0.10.0"
1213
flate2 = "0.2.19"
1314
tar = "0.4.11"
1415
walkdir = "1.0.7"

src/combiner.rs

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@
99
// except according to those terms.
1010

1111
use std::fs;
12-
use std::io::{self, Read, Write};
12+
use std::io::{Read, Write};
1313
use std::path::Path;
1414
use flate2::read::GzDecoder;
1515
use tar::Archive;
1616

17+
use errors::*;
1718
use super::Scripter;
1819
use super::Tarballer;
19-
use remove_dir_all::*;
2020
use util::*;
2121

2222
actor!{
@@ -53,55 +53,60 @@ actor!{
5353

5454
impl Combiner {
5555
/// Combine the installer tarballs
56-
pub fn run(self) -> io::Result<()> {
57-
fs::create_dir_all(&self.work_dir)?;
56+
pub fn run(self) -> Result<()> {
57+
create_dir_all(&self.work_dir)?;
5858

5959
let package_dir = Path::new(&self.work_dir).join(&self.package_name);
6060
if package_dir.exists() {
6161
remove_dir_all(&package_dir)?;
6262
}
63-
fs::create_dir_all(&package_dir)?;
63+
create_dir_all(&package_dir)?;
6464

6565
// Merge each installer into the work directory of the new installer
66-
let components = fs::File::create(package_dir.join("components"))?;
66+
let components = fs::File::create(package_dir.join("components"))
67+
.chain_err(|| "failed to create a new components file")?;
6768
for input_tarball in self.input_tarballs.split(',').map(str::trim).filter(|s| !s.is_empty()) {
6869
// Extract the input tarballs
69-
let input = fs::File::open(&input_tarball)?;
70-
let deflated = GzDecoder::new(input)?;
71-
Archive::new(deflated).unpack(&self.work_dir)?;
70+
fs::File::open(&input_tarball)
71+
.and_then(GzDecoder::new)
72+
.and_then(|tar| Archive::new(tar).unpack(&self.work_dir))
73+
.chain_err(|| format!("unable to extract '{}' into '{}'",
74+
&input_tarball, self.work_dir))?;
7275

7376
let pkg_name = input_tarball.trim_right_matches(".tar.gz");
7477
let pkg_name = Path::new(pkg_name).file_name().unwrap();
7578
let pkg_dir = Path::new(&self.work_dir).join(&pkg_name);
7679

7780
// Verify the version number
7881
let mut version = String::new();
79-
fs::File::open(pkg_dir.join("rust-installer-version"))?
80-
.read_to_string(&mut version)?;
82+
fs::File::open(pkg_dir.join("rust-installer-version"))
83+
.and_then(|mut file| file.read_to_string(&mut version))
84+
.chain_err(|| format!("failed to read version in '{}'", input_tarball))?;
8185
if version.trim().parse() != Ok(::RUST_INSTALLER_VERSION) {
82-
let msg = format!("incorrect installer version in {}", input_tarball);
83-
return Err(io::Error::new(io::ErrorKind::Other, msg));
86+
bail!("incorrect installer version in {}", input_tarball);
8487
}
8588

8689
// Move components to the new combined installer
8790
let mut pkg_components = String::new();
88-
fs::File::open(pkg_dir.join("components"))?
89-
.read_to_string(&mut pkg_components)?;
91+
fs::File::open(pkg_dir.join("components"))
92+
.and_then(|mut file| file.read_to_string(&mut pkg_components))
93+
.chain_err(|| format!("failed to read components in '{}'", input_tarball))?;
9094
for component in pkg_components.split_whitespace() {
9195
// All we need to do is move the component directory
9296
let component_dir = package_dir.join(&component);
93-
fs::rename(&pkg_dir.join(&component), &component_dir)?;
97+
rename(&pkg_dir.join(&component), component_dir)?;
9498

9599
// Merge the component name
96-
writeln!(&components, "{}", component)?;
100+
writeln!(&components, "{}", component)
101+
.chain_err(|| "failed to write new components")?;
97102
}
98103
}
99104
drop(components);
100105

101106
// Write the installer version
102-
let version = fs::File::create(package_dir.join("rust-installer-version"))?;
103-
writeln!(&version, "{}", ::RUST_INSTALLER_VERSION)?;
104-
drop(version);
107+
fs::File::create(package_dir.join("rust-installer-version"))
108+
.and_then(|file| writeln!(&file, "{}", ::RUST_INSTALLER_VERSION))
109+
.chain_err(|| "failed to write new installer version")?;
105110

106111
// Copy the overlay
107112
if !self.non_installed_overlay.is_empty() {
@@ -115,16 +120,16 @@ impl Combiner {
115120
.rel_manifest_dir(self.rel_manifest_dir)
116121
.success_message(self.success_message)
117122
.legacy_manifest_dirs(self.legacy_manifest_dirs)
118-
.output_script(output_script.to_str().unwrap());
123+
.output_script(path_to_str(&output_script)?);
119124
scripter.run()?;
120125

121126
// Make the tarballs
122-
fs::create_dir_all(&self.output_dir)?;
127+
create_dir_all(&self.output_dir)?;
123128
let output = Path::new(&self.output_dir).join(&self.package_name);
124129
let mut tarballer = Tarballer::default();
125130
tarballer.work_dir(self.work_dir)
126131
.input(self.package_name)
127-
.output(output.to_str().unwrap());
132+
.output(path_to_str(&output)?);
128133
tarballer.run()?;
129134

130135
Ok(())

src/generator.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99
// except according to those terms.
1010

1111
use std::fs;
12-
use std::io::{self, Write};
12+
use std::io::Write;
1313
use std::path::Path;
1414

15+
use errors::*;
1516
use super::Scripter;
1617
use super::Tarballer;
17-
use remove_dir_all::*;
1818
use util::*;
1919

2020
actor!{
@@ -57,8 +57,8 @@ actor!{
5757

5858
impl Generator {
5959
/// Generate the actual installer tarball
60-
pub fn run(self) -> io::Result<()> {
61-
fs::create_dir_all(&self.work_dir)?;
60+
pub fn run(self) -> Result<()> {
61+
create_dir_all(&self.work_dir)?;
6262

6363
let package_dir = Path::new(&self.work_dir).join(&self.package_name);
6464
if package_dir.exists() {
@@ -67,18 +67,18 @@ impl Generator {
6767

6868
// Copy the image and write the manifest
6969
let component_dir = package_dir.join(&self.component_name);
70-
fs::create_dir_all(&component_dir)?;
70+
create_dir_all(&component_dir)?;
7171
copy_and_manifest(self.image_dir.as_ref(), &component_dir, &self.bulk_dirs)?;
7272

7373
// Write the component name
74-
let components = fs::File::create(package_dir.join("components"))?;
75-
writeln!(&components, "{}", self.component_name)?;
76-
drop(components);
74+
fs::File::create(package_dir.join("components"))
75+
.and_then(|file| writeln!(&file, "{}", self.component_name))
76+
.chain_err(|| "failed to write the component file")?;
7777

7878
// Write the installer version (only used by combine-installers.sh)
79-
let version = fs::File::create(package_dir.join("rust-installer-version"))?;
80-
writeln!(&version, "{}", ::RUST_INSTALLER_VERSION)?;
81-
drop(version);
79+
fs::File::create(package_dir.join("rust-installer-version"))
80+
.and_then(|file| writeln!(&file, "{}", ::RUST_INSTALLER_VERSION))
81+
.chain_err(|| "failed to write the installer version")?;
8282

8383
// Copy the overlay
8484
if !self.non_installed_overlay.is_empty() {
@@ -92,24 +92,24 @@ impl Generator {
9292
.rel_manifest_dir(self.rel_manifest_dir)
9393
.success_message(self.success_message)
9494
.legacy_manifest_dirs(self.legacy_manifest_dirs)
95-
.output_script(output_script.to_str().unwrap());
95+
.output_script(path_to_str(&output_script)?);
9696
scripter.run()?;
9797

9898
// Make the tarballs
99-
fs::create_dir_all(&self.output_dir)?;
99+
create_dir_all(&self.output_dir)?;
100100
let output = Path::new(&self.output_dir).join(&self.package_name);
101101
let mut tarballer = Tarballer::default();
102102
tarballer.work_dir(self.work_dir)
103103
.input(self.package_name)
104-
.output(output.to_str().unwrap());
104+
.output(path_to_str(&output)?);
105105
tarballer.run()?;
106106

107107
Ok(())
108108
}
109109
}
110110

111111
/// Copies the `src` directory recursively to `dst`, writing `manifest.in` too.
112-
fn copy_and_manifest(src: &Path, dst: &Path, bulk_dirs: &str) -> io::Result<()> {
112+
fn copy_and_manifest(src: &Path, dst: &Path, bulk_dirs: &str) -> Result<()> {
113113
let manifest = fs::File::create(dst.join("manifest.in"))?;
114114
let bulk_dirs: Vec<_> = bulk_dirs.split(',')
115115
.filter(|s| !s.is_empty())

src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#[macro_use]
12+
extern crate error_chain;
1113
extern crate flate2;
1214
extern crate tar;
1315
extern crate walkdir;
@@ -21,6 +23,16 @@ extern crate kernel32;
2123
#[macro_use]
2224
extern crate lazy_static;
2325

26+
mod errors {
27+
error_chain!{
28+
foreign_links {
29+
Io(::std::io::Error);
30+
StripPrefix(::std::path::StripPrefixError);
31+
WalkDir(::walkdir::Error);
32+
}
33+
}
34+
}
35+
2436
#[macro_use]
2537
mod util;
2638

@@ -32,6 +44,7 @@ mod generator;
3244
mod scripter;
3345
mod tarballer;
3446

47+
pub use errors::{Result, Error, ErrorKind};
3548
pub use combiner::Combiner;
3649
pub use generator::Generator;
3750
pub use scripter::Scripter;

src/main.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
#[macro_use]
22
extern crate clap;
3+
#[macro_use]
4+
extern crate error_chain;
35
extern crate installer;
46

7+
use errors::*;
58
use clap::{App, ArgMatches};
6-
use installer::*;
79

8-
fn main() {
10+
mod errors {
11+
error_chain!{
12+
links {
13+
Installer(::installer::Error, ::installer::ErrorKind);
14+
}
15+
}
16+
}
17+
18+
quick_main!(run);
19+
20+
fn run() -> Result<()> {
921
let yaml = load_yaml!("main.yml");
1022
let matches = App::from_yaml(yaml).get_matches();
1123

@@ -29,8 +41,8 @@ macro_rules! parse(
2941
}
3042
);
3143

32-
fn combine(matches: &ArgMatches) {
33-
let combiner = parse!(matches => Combiner {
44+
fn combine(matches: &ArgMatches) -> Result<()> {
45+
let combiner = parse!(matches => installer::Combiner {
3446
"product-name" => product_name,
3547
"package-name" => package_name,
3648
"rel-manifest-dir" => rel_manifest_dir,
@@ -42,14 +54,11 @@ fn combine(matches: &ArgMatches) {
4254
"output-dir" => output_dir,
4355
});
4456

45-
if let Err(e) = combiner.run() {
46-
println!("failed to combine installers: {}", e);
47-
std::process::exit(1);
48-
}
57+
combiner.run().chain_err(|| "failed to combine installers")
4958
}
5059

51-
fn generate(matches: &ArgMatches) {
52-
let generator = parse!(matches => Generator {
60+
fn generate(matches: &ArgMatches) -> Result<()> {
61+
let generator = parse!(matches => installer::Generator {
5362
"product-name" => product_name,
5463
"component-name" => component_name,
5564
"package-name" => package_name,
@@ -63,36 +72,27 @@ fn generate(matches: &ArgMatches) {
6372
"output-dir" => output_dir,
6473
});
6574

66-
if let Err(e) = generator.run() {
67-
println!("failed to generate installer: {}", e);
68-
std::process::exit(1);
69-
}
75+
generator.run().chain_err(|| "failed to generate installer")
7076
}
7177

72-
fn script(matches: &ArgMatches) {
73-
let scripter = parse!(matches => Scripter {
78+
fn script(matches: &ArgMatches) -> Result<()> {
79+
let scripter = parse!(matches => installer::Scripter {
7480
"product-name" => product_name,
7581
"rel-manifest-dir" => rel_manifest_dir,
7682
"success-message" => success_message,
7783
"legacy-manifest-dirs" => legacy_manifest_dirs,
7884
"output-script" => output_script,
7985
});
8086

81-
if let Err(e) = scripter.run() {
82-
println!("failed to generate installation script: {}", e);
83-
std::process::exit(1);
84-
}
87+
scripter.run().chain_err(|| "failed to generate installation script")
8588
}
8689

87-
fn tarball(matches: &ArgMatches) {
88-
let tarballer = parse!(matches => Tarballer {
90+
fn tarball(matches: &ArgMatches) -> Result<()> {
91+
let tarballer = parse!(matches => installer::Tarballer {
8992
"input" => input,
9093
"output" => output,
9194
"work-dir" => work_dir,
9295
});
9396

94-
if let Err(e) = tarballer.run() {
95-
println!("failed to generate tarballs: {}", e);
96-
std::process::exit(1);
97-
}
97+
tarballer.run().chain_err(|| "failed to generate tarballs")
9898
}

src/scripter.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
// except according to those terms.
1010

1111
use std::fs;
12-
use std::io::{self, Write};
12+
use std::io::Write;
1313

1414
// Needed to set the script mode to executable.
1515
#[cfg(unix)]
1616
use std::os::unix::fs::OpenOptionsExt;
1717
// FIXME: what about Windows? Are default ACLs executable?
1818

19+
use errors::*;
20+
1921
const TEMPLATE: &'static str = include_str!("../install-template.sh");
2022

2123

@@ -41,7 +43,7 @@ actor!{
4143

4244
impl Scripter {
4345
/// Generate the actual installer script
44-
pub fn run(self) -> io::Result<()> {
46+
pub fn run(self) -> Result<()> {
4547
// Replace dashes in the success message with spaces (our arg handling botches spaces)
4648
// (TODO: still needed? kept for compatibility for now...)
4749
let product_name = self.product_name.replace('-', " ");
@@ -60,8 +62,9 @@ impl Scripter {
6062
let mut options = fs::OpenOptions::new();
6163
options.write(true).create_new(true);
6264
#[cfg(unix)] options.mode(0o755);
63-
let output = options.open(self.output_script)?;
64-
writeln!(&output, "{}", script)
65+
options.open(&self.output_script)
66+
.and_then(|mut output| output.write_all(script.as_ref()))
67+
.chain_err(|| format!("failed to write output script '{}'", self.output_script))
6568
}
6669
}
6770

0 commit comments

Comments
 (0)