diff --git a/src/bindgen.rs b/src/bindgen.rs index 61d9ac18..f4646443 100644 --- a/src/bindgen.rs +++ b/src/bindgen.rs @@ -3,6 +3,7 @@ use emoji; use error::Error; use progressbar::Step; +use std::path::Path; use std::process::Command; use PBAR; @@ -30,7 +31,7 @@ pub fn cargo_install_wasm_bindgen(step: &Step) -> Result<(), Error> { /// Run the `wasm-bindgen` CLI to generate bindings for the current crate's /// `.wasm`. pub fn wasm_bindgen_build( - path: &str, + path: &Path, name: &str, disable_dts: bool, target: &str, diff --git a/src/build.rs b/src/build.rs index 1744f995..c568d911 100644 --- a/src/build.rs +++ b/src/build.rs @@ -3,6 +3,7 @@ use emoji; use error::Error; use progressbar::Step; +use std::path::Path; use std::process::Command; use PBAR; @@ -46,7 +47,7 @@ fn ensure_nightly() -> Result<(), Error> { /// Run `cargo build` with the `nightly` toolchain and targetting /// `wasm32-unknown-unknown`. -pub fn cargo_build_wasm(path: &str, debug: bool, step: &Step) -> Result<(), Error> { +pub fn cargo_build_wasm(path: &Path, debug: bool, step: &Step) -> Result<(), Error> { let msg = format!("{}Compiling to WASM...", emoji::CYCLONE); PBAR.step(step, &msg); let output = { diff --git a/src/command/init.rs b/src/command/init.rs index bec96f89..c405a80b 100644 --- a/src/command/init.rs +++ b/src/command/init.rs @@ -11,14 +11,15 @@ use progressbar::Step; use readme; use slog::Logger; use std::fs; +use std::path::{Path, PathBuf}; use std::time::Instant; use PBAR; /// Construct our `pkg` directory in the crate. -pub fn create_pkg_dir(path: &str, step: &Step) -> Result<(), Error> { +pub fn create_pkg_dir(path: &Path, step: &Step) -> Result<(), Error> { let msg = format!("{}Creating a pkg directory...", emoji::FOLDER); PBAR.step(step, &msg); - let pkg_dir_path = format!("{}/pkg", path); + let pkg_dir_path = path.join("pkg"); fs::create_dir_all(pkg_dir_path)?; Ok(()) } @@ -38,7 +39,7 @@ pub enum InitMode { /// Everything required to configure and run the `wasm-pack init` command. pub struct Init { - crate_path: String, + crate_path: PathBuf, scope: Option, disable_dts: bool, target: String, @@ -51,7 +52,7 @@ type InitStep = fn(&mut Init, &Step, &Logger) -> Result<(), Error>; impl Init { /// Construct a new `Init` command. pub fn new( - path: Option, + path: Option, scope: Option, disable_dts: bool, target: String, @@ -121,15 +122,16 @@ impl Init { info!(&log, "Done in {}.", &duration); info!( &log, - "Your WASM pkg is ready to publish at {}/pkg.", &self.crate_path + "Your WASM pkg is ready to publish at {:#?}.", + &self.crate_path.join("pkg") ); PBAR.message(&format!("{} Done in {}", emoji::SPARKLE, &duration)); PBAR.message(&format!( - "{} Your WASM pkg is ready to publish at {}/pkg.", + "{} Your WASM pkg is ready to publish at {:#?}.", emoji::PACKAGE, - &self.crate_path + &self.crate_path.join("pkg") )); Ok(()) } @@ -152,15 +154,14 @@ impl Init { info!(&log, "Building wasm..."); build::cargo_build_wasm(&self.crate_path, self.debug, step)?; - #[cfg(not(target_os = "windows"))] info!( &log, - "wasm built at {}/target/wasm32-unknown-unknown/release.", &self.crate_path - ); - #[cfg(target_os = "windows")] - info!( - &log, - "wasm built at {}\\target\\wasm32-unknown-unknown\\release.", &self.crate_path + "wasm built at {:#?}.", + &self + .crate_path + .join("target") + .join("wasm32-unknown-unknown") + .join("release") ); Ok(()) } @@ -168,7 +169,7 @@ impl Init { fn step_create_dir(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { info!(&log, "Creating a pkg directory..."); create_pkg_dir(&self.crate_path, step)?; - info!(&log, "Created a pkg directory at {}.", &self.crate_path); + info!(&log, "Created a pkg directory at {:#?}.", &self.crate_path); Ok(()) } @@ -181,15 +182,10 @@ impl Init { &self.target, step, )?; - #[cfg(not(target_os = "windows"))] - info!( - &log, - "Wrote a package.json at {}/pkg/package.json.", &self.crate_path - ); - #[cfg(target_os = "windows")] info!( &log, - "Wrote a package.json at {}\\pkg\\package.json.", &self.crate_path + "Wrote a package.json at {:#?}.", + &self.crate_path.join("pkg").join("package.json") ); Ok(()) } @@ -197,15 +193,10 @@ impl Init { fn step_copy_readme(&mut self, step: &Step, log: &Logger) -> Result<(), Error> { info!(&log, "Copying readme from crate..."); readme::copy_from_crate(&self.crate_path, step)?; - #[cfg(not(target_os = "windows"))] - info!( - &log, - "Copied readme from crate to {}/pkg.", &self.crate_path - ); - #[cfg(target_os = "windows")] info!( &log, - "Copied readme from crate to {}\\pkg.", &self.crate_path + "Copied readme from crate to {:#?}.", + &self.crate_path.join("pkg") ); Ok(()) } @@ -217,19 +208,11 @@ impl Init { info!(&log, "Getting the crate name from the manifest..."); self.crate_name = manifest::get_crate_name(&self.crate_path)?; - #[cfg(not(target_os = "windows"))] - info!( - &log, - "Got crate name {} from the manifest at {}/Cargo.toml.", - &self.crate_name, - &self.crate_path - ); - #[cfg(target_os = "windows")] info!( &log, - "Got crate name {} from the manifest at {}\\Cargo.toml.", + "Got crate name {:#?} from the manifest at {:#?}.", &self.crate_name, - &self.crate_path + &self.crate_path.join("Cargo.toml") ); Ok(()) } @@ -244,15 +227,10 @@ impl Init { self.debug, step, )?; - #[cfg(not(target_os = "windows"))] - info!( - &log, - "wasm bindings were built at {}/pkg.", &self.crate_path - ); - #[cfg(target_os = "windows")] info!( &log, - "wasm bindings were built at {}\\pkg.", &self.crate_path + "wasm bindings were built at {:#?}.", + &self.crate_path.join("pkg") ); Ok(()) } diff --git a/src/command/mod.rs b/src/command/mod.rs index 2f477b9b..2b9ed8dc 100644 --- a/src/command/mod.rs +++ b/src/command/mod.rs @@ -12,6 +12,7 @@ use self::pack::pack; use self::publish::publish; use error::Error; use slog::Logger; +use std::path::PathBuf; use std::result; use PBAR; @@ -22,7 +23,8 @@ pub enum Command { /// 🐣 initialize a package.json based on your compiled wasm! Init { /// The path to the Rust crate. - path: Option, + #[structopt(parse(from_os_str))] + path: Option, /// The npm scope to use in package.json, if any. #[structopt(long = "scope", short = "s")] @@ -49,15 +51,17 @@ pub enum Command { #[structopt(name = "pack")] /// 🍱 create a tar of your npm package but don't publish! Pack { - /// The path to the Rust crate. - path: Option, + /// The path to the Rust crate. + #[structopt(parse(from_os_str))] + path: Option, }, #[structopt(name = "publish")] /// 🎆 pack up your npm package and publish! Publish { /// The path to the Rust crate. - path: Option, + #[structopt(parse(from_os_str))] + path: Option, }, #[structopt(name = "login", alias = "adduser", alias = "add-user")] diff --git a/src/command/pack.rs b/src/command/pack.rs index c9c9ffd4..fe1ca5ff 100644 --- a/src/command/pack.rs +++ b/src/command/pack.rs @@ -2,26 +2,28 @@ use command::utils::{find_pkg_directory, set_crate_path}; use error::Error; use npm; use slog::Logger; +use std::path::PathBuf; use std::result; use PBAR; /// Executes the 'npm pack' command on the 'pkg' directory /// which creates a tarball that can be published to the NPM registry -pub fn pack(path: Option, log: &Logger) -> result::Result<(), Error> { +pub fn pack(path: Option, log: &Logger) -> result::Result<(), Error> { let crate_path = set_crate_path(path); info!(&log, "Packing up the npm package..."); let pkg_directory = find_pkg_directory(&crate_path).ok_or(Error::PkgNotFound { message: format!( - "Unable to find the pkg directory at path '{}', or in a child directory of '{}'", + "Unable to find the pkg directory at path {:#?}, or in a child directory of {:#?}", &crate_path, &crate_path ), })?; npm::npm_pack(&pkg_directory.to_string_lossy())?; - #[cfg(not(target_os = "windows"))] - info!(&log, "Your package is located at {}/pkg", &crate_path); - #[cfg(target_os = "windows")] - info!(&log, "Your package is located at {}\\pkg", &crate_path); + info!( + &log, + "Your package is located at {:#?}", + crate_path.join("pkg") + ); PBAR.message("🎒 packed up your package!"); Ok(()) diff --git a/src/command/publish.rs b/src/command/publish.rs index 2fb295f4..2d67365d 100644 --- a/src/command/publish.rs +++ b/src/command/publish.rs @@ -2,19 +2,20 @@ use command::utils::{find_pkg_directory, set_crate_path}; use error::Error; use npm; use slog::Logger; +use std::path::PathBuf; use std::result; use PBAR; /// Creates a tarball from a 'pkg' directory /// and publishes it to the NPM registry -pub fn publish(path: Option, log: &Logger) -> result::Result<(), Error> { +pub fn publish(path: Option, log: &Logger) -> result::Result<(), Error> { let crate_path = set_crate_path(path); info!(&log, "Publishing the npm package..."); info!(&log, "npm info located in the npm debug log"); let pkg_directory = find_pkg_directory(&crate_path).ok_or(Error::PkgNotFound { message: format!( - "Unable to find the pkg directory at path '{}', or in a child directory of '{}'", + "Unable to find the pkg directory at path '{:#?}', or in a child directory of '{:#?}'", &crate_path, &crate_path ), })?; diff --git a/src/command/utils.rs b/src/command/utils.rs index 925f5275..3e0fb705 100644 --- a/src/command/utils.rs +++ b/src/command/utils.rs @@ -4,10 +4,10 @@ use std::path::{Path, PathBuf}; /// If an explicit path is given, then use it, otherwise assume the current /// directory is the crate path. -pub fn set_crate_path(path: Option) -> String { +pub fn set_crate_path(path: Option) -> PathBuf { let crate_path = match path { Some(p) => p, - None => ".".to_string(), + None => PathBuf::from("."), }; crate_path @@ -15,10 +15,9 @@ pub fn set_crate_path(path: Option) -> String { /// Locates the pkg directory from a specific path /// Returns None if unable to find the 'pkg' directory -pub fn find_pkg_directory(guess_path: &str) -> Option { - let path = PathBuf::from(guess_path); - if is_pkg_directory(&path) { - return Some(path); +pub fn find_pkg_directory(path: &Path) -> Option { + if is_pkg_directory(path) { + return Some(path.to_owned()); } path.read_dir().ok().and_then(|entries| { diff --git a/src/manifest.rs b/src/manifest.rs index a6628c65..36e69dfe 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -2,6 +2,7 @@ use std::fs::File; use std::io::prelude::*; +use std::path::Path; use console::style; use emoji; @@ -60,8 +61,8 @@ struct Repository { url: String, } -fn read_cargo_toml(path: &str) -> Result { - let manifest_path = format!("{}/Cargo.toml", path); +fn read_cargo_toml(path: &Path) -> Result { + let manifest_path = path.join("Cargo.toml"); let mut cargo_file = File::open(manifest_path)?; let mut cargo_contents = String::new(); cargo_file.read_to_string(&mut cargo_contents)?; @@ -125,7 +126,7 @@ impl CargoManifest { /// Generate a package.json file inside in `./pkg`. pub fn write_package_json( - path: &str, + path: &Path, scope: &Option, disable_dts: bool, target: &str, @@ -141,7 +142,7 @@ pub fn write_package_json( }; PBAR.step(step, &msg); - let pkg_file_path = format!("{}/pkg/package.json", path); + let pkg_file_path = path.join("pkg").join("package.json"); let mut pkg_file = File::create(pkg_file_path)?; let crate_data = read_cargo_toml(path)?; let npm_data = crate_data.into_npm(scope, disable_dts, target); @@ -162,12 +163,12 @@ pub fn write_package_json( } /// Get the crate name for the crate at the given path. -pub fn get_crate_name(path: &str) -> Result { +pub fn get_crate_name(path: &Path) -> Result { Ok(read_cargo_toml(path)?.package.name) } /// Check that the crate the given path is properly configured. -pub fn check_crate_config(path: &str, step: &Step) -> Result<(), Error> { +pub fn check_crate_config(path: &Path, step: &Step) -> Result<(), Error> { let msg = format!("{}Checking crate configuration...", emoji::WRENCH); PBAR.step(&step, &msg); check_wasm_bindgen(path)?; @@ -175,7 +176,7 @@ pub fn check_crate_config(path: &str, step: &Step) -> Result<(), Error> { Ok(()) } -fn check_wasm_bindgen(path: &str) -> Result<(), Error> { +fn check_wasm_bindgen(path: &Path) -> Result<(), Error> { if read_cargo_toml(path)?.dependencies.map_or(false, |x| { !x.wasm_bindgen.unwrap_or("".to_string()).is_empty() }) { @@ -187,7 +188,7 @@ fn check_wasm_bindgen(path: &str) -> Result<(), Error> { )) } -fn check_crate_type(path: &str) -> Result<(), Error> { +fn check_crate_type(path: &Path) -> Result<(), Error> { if read_cargo_toml(path)?.lib.map_or(false, |lib| { lib.crate_type .map_or(false, |types| types.iter().any(|s| s == "cdylib")) diff --git a/src/readme.rs b/src/readme.rs index 5f631e08..d59d4960 100644 --- a/src/readme.rs +++ b/src/readme.rs @@ -2,17 +2,18 @@ use error::Error; use std::fs; +use std::path::Path; use emoji; use progressbar::Step; use PBAR; /// Copy the crate's README into the `pkg` directory. -pub fn copy_from_crate(path: &str, step: &Step) -> Result<(), Error> { +pub fn copy_from_crate(path: &Path, step: &Step) -> Result<(), Error> { let msg = format!("{}Copying over your README...", emoji::DANCERS); PBAR.step(step, &msg); - let crate_readme_path = format!("{}/README.md", path); - let new_readme_path = format!("{}/pkg/README.md", path); + let crate_readme_path = path.join("README.md"); + let new_readme_path = path.join("pkg").join("README.md"); if let Err(_) = fs::copy(&crate_readme_path, &new_readme_path) { PBAR.warn("origin crate has no README"); }; diff --git a/tests/manifest/main.rs b/tests/manifest/main.rs index cf661969..9594b8ac 100644 --- a/tests/manifest/main.rs +++ b/tests/manifest/main.rs @@ -8,49 +8,55 @@ mod utils; use std::collections::HashSet; use std::fs; +use std::path::PathBuf; use wasm_pack::manifest; #[test] fn it_gets_the_crate_name_default_path() { - assert!(manifest::get_crate_name(".").is_ok()); - assert_eq!(manifest::get_crate_name(".").unwrap(), "wasm-pack"); + let path = &PathBuf::from("."); + assert!(manifest::get_crate_name(path).is_ok()); + assert_eq!(manifest::get_crate_name(path).unwrap(), "wasm-pack"); } #[test] fn it_gets_the_crate_name_provided_path() { - assert!(manifest::get_crate_name("tests/fixtures/js-hello-world").is_ok()); - assert_eq!( - manifest::get_crate_name("tests/fixtures/js-hello-world").unwrap(), - "js-hello-world" - ); + let path = &PathBuf::from("tests/fixtures/js-hello-world"); + assert!(manifest::get_crate_name(path).is_ok()); + assert_eq!(manifest::get_crate_name(path).unwrap(), "js-hello-world"); } #[test] fn it_checks_has_cdylib_default_path() { let step = wasm_pack::progressbar::Step::new(1); - assert!(manifest::check_crate_config(".", &step).is_err()); + assert!(manifest::check_crate_config(&PathBuf::from("."), &step).is_err()); } #[test] fn it_checks_has_cdylib_provided_path() { let step = wasm_pack::progressbar::Step::new(1); - assert!(manifest::check_crate_config("tests/fixtures/js-hello-world", &step).is_ok()); + assert!( + manifest::check_crate_config(&PathBuf::from("tests/fixtures/js-hello-world"), &step) + .is_ok() + ); } #[test] fn it_checks_has_cdylib_wrong_crate_type() { let step = wasm_pack::progressbar::Step::new(1); - assert!(manifest::check_crate_config("tests/fixtures/bad-cargo-toml", &step).is_err()); + assert!( + manifest::check_crate_config(&PathBuf::from("tests/fixtures/bad-cargo-toml"), &step) + .is_err() + ); } #[test] fn it_creates_a_package_json_default_path() { let step = wasm_pack::progressbar::Step::new(1); - let path = ".".to_string(); + let path = PathBuf::from("."); wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!(manifest::write_package_json(&path, &None, false, "", &step).is_ok()); - let package_json_path = format!("{}/pkg/package.json", &path); + let package_json_path = &path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); assert!(utils::read_package_json(&path).is_ok()); let pkg = utils::read_package_json(&path).unwrap(); @@ -75,10 +81,10 @@ fn it_creates_a_package_json_default_path() { #[test] fn it_creates_a_package_json_provided_path() { let step = wasm_pack::progressbar::Step::new(1); - let path = "tests/fixtures/js-hello-world".to_string(); + let path = PathBuf::from("tests/fixtures/js-hello-world"); wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!(manifest::write_package_json(&path, &None, false, "", &step).is_ok()); - let package_json_path = format!("{}/pkg/package.json", &path); + let package_json_path = &path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); assert!(utils::read_package_json(&path).is_ok()); let pkg = utils::read_package_json(&path).unwrap(); @@ -96,12 +102,12 @@ fn it_creates_a_package_json_provided_path() { #[test] fn it_creates_a_package_json_provided_path_with_scope() { let step = wasm_pack::progressbar::Step::new(1); - let path = "tests/fixtures/scopes".to_string(); + let path = PathBuf::from("tests/fixtures/scopes"); wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!( manifest::write_package_json(&path, &Some("test".to_string()), false, "", &step).is_ok() ); - let package_json_path = format!("{}/pkg/package.json", &path); + let package_json_path = &path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); assert!(utils::read_package_json(&path).is_ok()); let pkg = utils::read_package_json(&path).unwrap(); @@ -119,10 +125,10 @@ fn it_creates_a_package_json_provided_path_with_scope() { #[test] fn it_creates_a_pkg_json_with_correct_files_on_node() { let step = wasm_pack::progressbar::Step::new(1); - let path = ".".to_string(); + let path = PathBuf::from("."); wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!(manifest::write_package_json(&path, &None, false, "nodejs", &step).is_ok()); - let package_json_path = format!("{}/pkg/package.json", &path); + let package_json_path = &path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); assert!(utils::read_package_json(&path).is_ok()); let pkg = utils::read_package_json(&path).unwrap(); @@ -148,10 +154,10 @@ fn it_creates_a_pkg_json_with_correct_files_on_node() { #[test] fn it_creates_a_package_json_with_correct_keys_when_types_are_skipped() { let step = wasm_pack::progressbar::Step::new(1); - let path = ".".to_string(); + let path = PathBuf::from("."); wasm_pack::command::init::create_pkg_dir(&path, &step).unwrap(); assert!(manifest::write_package_json(&path, &None, true, "", &step).is_ok()); - let package_json_path = format!("{}/pkg/package.json", &path); + let package_json_path = &path.join("pkg").join("package.json"); assert!(fs::metadata(package_json_path).is_ok()); assert!(utils::read_package_json(&path).is_ok()); let pkg = utils::read_package_json(&path).unwrap(); @@ -174,11 +180,15 @@ fn it_creates_a_package_json_with_correct_keys_when_types_are_skipped() { #[test] fn it_errors_when_wasm_bindgen_is_not_declared() { let step = wasm_pack::progressbar::Step::new(1); - assert!(manifest::check_crate_config("tests/fixtures/bad-cargo-toml", &step).is_err()); + assert!( + manifest::check_crate_config(&PathBuf::from("tests/fixtures/bad-cargo-toml"), &step) + .is_err() + ); } #[test] fn it_does_not_error_when_wasm_bindgen_is_declared() { let step = wasm_pack::progressbar::Step::new(1); - assert!(manifest::check_crate_config("tests/fixtures/js-hello-world", &step).is_ok()); + let path = PathBuf::from("tests/fixtures/js-hello-world"); + assert!(manifest::check_crate_config(&path, &step).is_ok()); } diff --git a/tests/manifest/utils.rs b/tests/manifest/utils.rs index 25add464..cc3d6098 100644 --- a/tests/manifest/utils.rs +++ b/tests/manifest/utils.rs @@ -1,5 +1,6 @@ use std::fs::File; use std::io::prelude::*; +use std::path::Path; use failure::Error; use serde_json; @@ -23,8 +24,8 @@ pub struct Repository { pub url: String, } -pub fn read_package_json(path: &str) -> Result { - let manifest_path = format!("{}/pkg/package.json", path); +pub fn read_package_json(path: &Path) -> Result { + let manifest_path = path.join("pkg").join("package.json"); let mut pkg_file = File::open(manifest_path)?; let mut pkg_contents = String::new(); pkg_file.read_to_string(&mut pkg_contents)?; diff --git a/tests/readme/main.rs b/tests/readme/main.rs index 65d59da4..337a70f4 100644 --- a/tests/readme/main.rs +++ b/tests/readme/main.rs @@ -4,16 +4,17 @@ extern crate wasm_pack; mod utils; use std::fs; +use std::path::PathBuf; use wasm_pack::readme; #[test] fn it_copies_a_readme_default_path() { let step = wasm_pack::progressbar::Step::new(1); - let path = ".".to_string(); + let path = PathBuf::from("."); assert!(readme::copy_from_crate(&path, &step).is_ok()); - let crate_readme_path = format!("{}/README.md", &path); - let pkg_readme_path = format!("{}/pkg/README.md", &path); + let crate_readme_path = &path.join("README.md"); + let pkg_readme_path = &path.join("pkg").join("README.md"); assert!(fs::metadata(&pkg_readme_path).is_ok()); let crate_readme = utils::read_file(&crate_readme_path).unwrap(); let pkg_readme = utils::read_file(&pkg_readme_path).unwrap(); @@ -23,10 +24,10 @@ fn it_copies_a_readme_default_path() { #[test] fn it_creates_a_package_json_provided_path() { let step = wasm_pack::progressbar::Step::new(1); - let path = "tests/fixtures/js-hello-world".to_string(); + let path = PathBuf::from("tests/fixtures/js-hello-world"); assert!(readme::copy_from_crate(&path, &step).is_ok()); - let crate_readme_path = format!("{}/README.md", &path); - let pkg_readme_path = format!("{}/pkg/README.md", &path); + let crate_readme_path = &path.join("README.md"); + let pkg_readme_path = &path.join("pkg").join("README.md"); assert!(fs::metadata(&pkg_readme_path).is_ok()); let crate_readme = utils::read_file(&crate_readme_path).unwrap(); let pkg_readme = utils::read_file(&pkg_readme_path).unwrap(); diff --git a/tests/readme/utils.rs b/tests/readme/utils.rs index 64f85195..c5e2bbf5 100644 --- a/tests/readme/utils.rs +++ b/tests/readme/utils.rs @@ -1,9 +1,9 @@ +use failure::Error; use std::fs::File; use std::io::Read; +use std::path::Path; -use failure::Error; - -pub fn read_file(path: &str) -> Result { +pub fn read_file(path: &Path) -> Result { let mut file = File::open(path)?; let mut contents = String::new(); file.read_to_string(&mut contents)?;