diff --git a/Cargo.lock b/Cargo.lock index 1e00a29762..9d6d2ac5c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1350,6 +1350,7 @@ dependencies = [ "same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1433,6 +1434,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde_json" @@ -2171,6 +2185,7 @@ dependencies = [ "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" "checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum serde_urlencoded 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" diff --git a/Cargo.toml b/Cargo.toml index b46552f07b..f1c0504ad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ remove_dir_all = "0.5.1" same-file = "1" scopeguard = "1" semver = "0.9" +serde = { version = "1.0", features = ["derive"] } sha2 = "0.8" strsim = "0.9.1" tar = "0.4.26" diff --git a/README.md b/README.md index 504b8863e6..22341462c8 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ And it runs on all platforms Rust supports, including Windows. * [Working with custom toolchains](#working-with-custom-toolchains-and-local-builds) * [Working with network proxies](#working-with-network-proxies) * [Examples](#examples) +* [Configuration files](#configuration-files) * [Environment variables](#environment-variables) * [Other installation methods](#other-installation-methods) * [Security](#security) @@ -639,6 +640,17 @@ Command | Description `rustup toolchain help` | Show the `help` page for a subcommand (like `toolchain`) `rustup man cargo` | \(*Unix only*\) View the man page for a given command (like `cargo`) +## Configuration files + +Rustup has a settings file in [TOML](https://github.com/toml-lang/toml) format +at `${RUSTUP_HOME}/settings.toml`. The schema for this file is not part of the +public interface for rustup - the rustup CLI should be used to query and set +settings. + +On Unix operating systems a fallback settings file is consulted for some +settings. This fallback file is located at `/etc/rustup/settings.toml` and +currently can define only `default_toolchain`. + ## Environment variables diff --git a/src/config.rs b/src/config.rs index d99822a160..7a9a3ef367 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,6 +11,7 @@ use pgp::{Deserializable, SignedPublicKey}; use crate::dist::{dist, temp}; use crate::errors::*; +use crate::fallback_settings::FallbackSettings; use crate::notifications::*; use crate::settings::{Settings, SettingsFile, DEFAULT_METADATA_VERSION}; use crate::toolchain::{Toolchain, UpdateStatus}; @@ -108,10 +109,13 @@ impl Display for PgpPublicKey { } } +pub const UNIX_FALLBACK_SETTINGS: &str = "/etc/rustup/settings.toml"; + pub struct Cfg { pub profile_override: Option, pub rustup_dir: PathBuf, pub settings_file: SettingsFile, + pub fallback_settings: Option, pub toolchains_dir: PathBuf, pub update_hash_dir: PathBuf, pub download_dir: PathBuf, @@ -133,6 +137,13 @@ impl Cfg { let settings_file = SettingsFile::new(rustup_dir.join("settings.toml")); + // Centralised file for multi-user systems to provide admin/distributor set initial values. + let fallback_settings = if cfg!(not(windows)) { + FallbackSettings::new(PathBuf::from(UNIX_FALLBACK_SETTINGS))? + } else { + None + }; + let toolchains_dir = rustup_dir.join("toolchains"); let update_hash_dir = rustup_dir.join("update-hashes"); let download_dir = rustup_dir.join("downloads"); @@ -191,6 +202,7 @@ impl Cfg { profile_override: None, rustup_dir, settings_file, + fallback_settings, toolchains_dir, update_hash_dir, download_dir, @@ -365,9 +377,7 @@ impl Cfg { } pub fn find_default(&self) -> Result>> { - let opt_name = self - .settings_file - .with(|s| Ok(s.default_toolchain.clone()))?; + let opt_name = self.get_default()?; if let Some(name) = opt_name { let toolchain = self @@ -509,7 +519,14 @@ impl Cfg { } pub fn get_default(&self) -> Result> { - self.settings_file.with(|s| Ok(s.default_toolchain.clone())) + let user_opt = self.settings_file.with(|s| Ok(s.default_toolchain.clone())); + if let Some(fallback_settings) = &self.fallback_settings { + match user_opt { + Err(_) | Ok(None) => return Ok(fallback_settings.default_toolchain.clone()), + _ => {} + }; + }; + user_opt } pub fn list_toolchains(&self) -> Result> { diff --git a/src/errors.rs b/src/errors.rs index 13c4dc4c81..3b2a10c4c9 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -343,6 +343,9 @@ error_chain! { display("component {} was automatically added because it is required for toolchain '{}'", c, t) } + ParsingFallbackSettings(e: toml::de::Error) { + description("error parsing settings") + } ParsingSettings(e: toml::de::Error) { description("error parsing settings") } diff --git a/src/fallback_settings.rs b/src/fallback_settings.rs new file mode 100644 index 0000000000..036c60ae70 --- /dev/null +++ b/src/fallback_settings.rs @@ -0,0 +1,41 @@ +use crate::errors::*; +use crate::utils::utils; +use serde::Deserialize; +use std::error::Error; +use std::io; +use std::path::Path; + +#[derive(Clone, Debug, Deserialize, PartialEq)] +pub struct FallbackSettings { + pub default_toolchain: Option, +} + +impl Default for FallbackSettings { + fn default() -> Self { + Self { + default_toolchain: None, + } + } +} + +impl FallbackSettings { + pub fn new>(path: P) -> Result> { + // Users cannot fix issues with missing/unreadable/invalid centralised files, but logging isn't setup early so + // we can't simply trap all errors and log diagnostics. Ideally we would, and then separate these into different + // sorts of issues, logging messages about errors that should be fixed. Instead we trap some conservative errors + // that hopefully won't lead to too many tickets. + match utils::read_file("fallback settings", path.as_ref()) { + Err(e @ Error(ErrorKind::ReadingFile { .. }, _)) => { + let io_err = e.source().unwrap().downcast_ref::().unwrap(); + match io_err.kind() { + io::ErrorKind::NotFound | io::ErrorKind::PermissionDenied => Ok(None), + _ => Err(e.into()), + } + } + Err(e) => Err(e), + Ok(file_contents) => Ok(Some( + toml::from_str(&file_contents).map_err(ErrorKind::ParsingFallbackSettings)?, + )), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 75f67b7d35..b8ab600d01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,6 +58,7 @@ pub mod diskio; pub mod dist; pub mod env_var; pub mod errors; +pub mod fallback_settings; mod install; mod notifications; pub mod settings;