Skip to content

WIP: Profiles #1541

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rustup-init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ OPTIONS:
--default-host <default-host> Choose a default host triple
--default-toolchain <default-toolchain> Choose a default toolchain to install
--default-toolchain none Do not install any toolchains
--profile [minimal|default|complete] Choose a profile
EOF
}

Expand Down
1 change: 1 addition & 0 deletions src/rustup-cli/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ fn run_rustup() -> Result<()> {
let opts = self_update::InstallOpts {
default_host_triple: TargetTriple::from_host_or_build().to_string(),
default_toolchain: "stable".to_string(),
profile: String::new(),
no_modify_path: false,
};
if cfg!(windows) {
Expand Down
23 changes: 21 additions & 2 deletions src/rustup-cli/self_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ use regex::Regex;
pub struct InstallOpts {
pub default_host_triple: String,
pub default_toolchain: String,
pub profile: String,
pub no_modify_path: bool,
}

Expand Down Expand Up @@ -274,7 +275,12 @@ pub fn install(no_prompt: bool, verbose: bool, mut opts: InstallOpts) -> Result<
// FIXME: Someday we can stop setting up the symlink, and when
// we do that we can stop creating ~/.rustup as well.
utils::create_rustup_home()?;
maybe_install_rust(&opts.default_toolchain, &opts.default_host_triple, verbose)?;
maybe_install_rust(
&opts.default_toolchain,
&opts.profile,
&opts.default_host_triple,
verbose,
)?;

if cfg!(unix) {
let ref env_file = utils::cargo_home()?.join("env");
Expand Down Expand Up @@ -606,10 +612,12 @@ fn current_install_opts(opts: &InstallOpts) -> String {

- ` `default host triple: `{}`
- ` `default toolchain: `{}`
- ` `profile: `{}`
- modify PATH variable: `{}`
",
opts.default_host_triple,
opts.default_toolchain,
opts.profile,
if !opts.no_modify_path { "yes" } else { "no" }
)
}
Expand All @@ -631,6 +639,11 @@ fn customize_install(mut opts: InstallOpts) -> Result<InstallOpts> {
&opts.default_toolchain,
)?;

opts.profile = common::question_str(
"Profile (which tools and data to install)? (minimal/default/complete)",
&opts.profile,
)?;

opts.no_modify_path =
!common::question_bool("Modify PATH variable? (y/n)", !opts.no_modify_path)?;

Expand Down Expand Up @@ -762,8 +775,14 @@ pub fn install_proxies() -> Result<()> {
Ok(())
}

fn maybe_install_rust(toolchain_str: &str, default_host_triple: &str, verbose: bool) -> Result<()> {
fn maybe_install_rust(
toolchain_str: &str,
profile_str: &str,
default_host_triple: &str,
verbose: bool,
) -> Result<()> {
let ref cfg = common::set_globals(verbose)?;
cfg.set_profile(profile_str)?;

// If there is already an install, then `toolchain_str` may not be
// a toolchain the user actually wants. Don't do anything. FIXME:
Expand Down
8 changes: 8 additions & 0 deletions src/rustup-cli/setup_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ pub fn main() -> Result<()> {
.takes_value(true)
.help("Choose a default toolchain to install"),
)
.arg(
Arg::with_name("profile")
.long("profile")
.takes_value(true)
.help("Choose a profile to install"),
)
.arg(
Arg::with_name("no-modify-path")
.long("no-modify-path")
Expand All @@ -55,11 +61,13 @@ pub fn main() -> Result<()> {
.map(|s| s.to_owned())
.unwrap_or_else(|| TargetTriple::from_host_or_build().to_string());
let default_toolchain = matches.value_of("default-toolchain").unwrap_or("stable");
let profile = matches.value_of("profile").unwrap_or("default");
let no_modify_path = matches.is_present("no-modify-path");

let opts = InstallOpts {
default_host_triple: default_host,
default_toolchain: default_toolchain.to_owned(),
profile: profile.to_owned(),
no_modify_path: no_modify_path,
};

Expand Down
75 changes: 62 additions & 13 deletions src/rustup-dist/src/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use errors::*;
use notifications::*;
use rustup_utils::{self, utils};
use prefix::InstallPrefix;
use manifest::Component;
use manifest::Manifest as ManifestV2;
use manifest::Component;
use manifestation::{Changes, Manifestation, UpdateStatus};
use download::DownloadCfg;

Expand Down Expand Up @@ -434,6 +434,29 @@ impl<'a> Manifest<'a> {
}
}

#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub enum Profile {
Minimal,
Default,
Complete,
}

impl Profile {
pub fn from_str(name: &str) -> Result<Self> {
match name {
"minimal" | "m" => Ok(Profile::Minimal),
"default" | "d" | "" => Ok(Profile::Default),
"complete" | "c" => Ok(Profile::Complete),
_ => Err(ErrorKind::InvalidProfile(name.to_owned()).into()),
}
}

// Non-required components that were required before profiles exist.
pub fn legacy_profile() -> Vec<String> {
vec!["rust-docs".to_owned()]
}
}

impl fmt::Display for TargetTriple {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.0.fmt(f)
Expand Down Expand Up @@ -474,6 +497,16 @@ impl fmt::Display for ToolchainDesc {
}
}

impl fmt::Display for Profile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Profile::Minimal => write!(f, "minimal"),
Profile::Default => write!(f, "default"),
Profile::Complete => write!(f, "complete"),
}
}
}

// Installs or updates a toolchain from a dist server. If an initial
// install then it will be installed with the default components. If
// an upgrade then all the existing components will be upgraded.
Expand All @@ -483,20 +516,23 @@ pub fn update_from_dist<'a>(
download: DownloadCfg<'a>,
update_hash: Option<&Path>,
toolchain: &ToolchainDesc,
profile: Profile,
prefix: &InstallPrefix,
add: &[Component],
remove: &[Component],
force_update: bool,
) -> Result<Option<String>> {
let fresh_install = !prefix.path().exists();
let profile = if fresh_install {
Some(profile)
} else {
None
};

let res = update_from_dist_(
download,
update_hash,
toolchain,
profile,
prefix,
add,
remove,
force_update,
);

Expand All @@ -511,23 +547,17 @@ pub fn update_from_dist<'a>(
res
}

pub fn update_from_dist_<'a>(
fn update_from_dist_<'a>(
download: DownloadCfg<'a>,
update_hash: Option<&Path>,
toolchain: &ToolchainDesc,
profile: Option<Profile>,
prefix: &InstallPrefix,
add: &[Component],
remove: &[Component],
force_update: bool,
) -> Result<Option<String>> {
let toolchain_str = toolchain.to_string();
let manifestation = Manifestation::open(prefix.clone(), toolchain.target.clone())?;

let changes = Changes {
add_extensions: add.to_owned(),
remove_extensions: remove.to_owned(),
};

// TODO: Add a notification about which manifest version is going to be used
(download.notify_handler)(Notification::DownloadingManifest(&toolchain_str));
match dl_v2_manifest(download, update_hash, toolchain) {
Expand All @@ -536,6 +566,25 @@ pub fn update_from_dist_<'a>(
&m.date,
m.get_rust_version().ok(),
));

let add_extensions = match profile {
Some(profile) => {
m.get_profile_components(profile)
.map(|v| v
.iter()
.map(|name| Component { pkg: name.to_owned(), target: Some(TargetTriple::from_host_or_build()) })
.collect::<Vec<Component>>()
)
.unwrap_or_else(|_| Profile::legacy_profile().into_iter().map(|s| Component { pkg: s, target: Some(TargetTriple::from_host_or_build()) }).collect())
}
None => Vec::new(),
};

let changes = Changes {
add_extensions,
remove_extensions: Vec::new(),
};

return match manifestation.update(
&m,
changes,
Expand Down
5 changes: 5 additions & 0 deletions src/rustup-dist/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ error_chain! {
description("invalid custom toolchain name")
display("invalid custom toolchain name: '{}'", t)
}
InvalidProfile(t: String) {
description("invalid profile name")
display("invalid profile name: '{}'; valid names are: \
`minimal`, `default`, and `complete`", t)
}
ChecksumFailed {
url: String,
expected: String,
Expand Down
49 changes: 45 additions & 4 deletions src/rustup-dist/src/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use toml;
use rustup_utils::toml_utils::*;

use std::collections::HashMap;
use dist::TargetTriple;
use dist::{Profile, TargetTriple};

pub const SUPPORTED_MANIFEST_VERSIONS: [&'static str; 1] = ["2"];
pub const DEFAULT_MANIFEST_VERSION: &'static str = "2";
Expand All @@ -26,6 +26,7 @@ pub struct Manifest {
pub date: String,
pub packages: HashMap<String, Package>,
pub renames: HashMap<String, String>,
pub profiles: HashMap<Profile, Vec<String>>,
}

#[derive(Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -82,7 +83,8 @@ impl Manifest {
manifest_version: version,
date: get_string(&mut table, "date", path)?,
packages: Self::table_to_packages(&mut table, path)?,
renames: Self::table_to_renames(table, path)?,
renames: Self::table_to_renames(&mut table, path)?,
profiles: Self::table_to_profiles(&mut table, path)?,
})
}
pub fn to_toml(self) -> toml::value::Table {
Expand All @@ -100,6 +102,9 @@ impl Manifest {
let packages = Self::packages_to_table(self.packages);
result.insert("pkg".to_owned(), toml::Value::Table(packages));

let profiles = Self::profiles_to_table(self.profiles);
result.insert("profiles".to_owned(), toml::Value::Table(profiles));

result
}

Expand Down Expand Up @@ -127,11 +132,11 @@ impl Manifest {
}

fn table_to_renames(
mut table: toml::value::Table,
table: &mut toml::value::Table,
path: &str,
) -> Result<HashMap<String, String>> {
let mut result = HashMap::new();
let rename_table = get_table(&mut table, "rename", path)?;
let rename_table = get_table(table, "rename", path)?;

for (k, v) in rename_table {
if let toml::Value::Table(mut t) = v {
Expand All @@ -151,6 +156,36 @@ impl Manifest {
result
}

fn table_to_profiles(
table: &mut toml::value::Table,
path: &str,
) -> Result<HashMap<Profile, Vec<String>>> {
let mut result = HashMap::new();
let profile_table = get_table(table, "profile", path)?;

for (k, v) in profile_table {
if let toml::Value::Array(a) = v {
let values = a.into_iter()
.filter_map(|v| match v {
toml::Value::String(s) => Some(s),
_ => None,
})
.collect();
result.insert(Profile::from_str(&k)?, values);
}
}

Ok(result)
}
fn profiles_to_table(profiles: HashMap<Profile, Vec<String>>) -> toml::value::Table {
let mut result = toml::value::Table::new();
for (profile, values) in profiles {
let array = values.into_iter().map(|v| toml::Value::String(v)).collect();
result.insert(profile.to_string(), toml::Value::Array(array));
}
result
}

pub fn get_package(&self, name: &str) -> Result<&Package> {
self.packages
.get(name)
Expand All @@ -161,6 +196,12 @@ impl Manifest {
self.get_package("rust").map(|p| &*p.version)
}

pub fn get_profile_components(&self, profile: Profile) -> Result<&Vec<String>> {
self.profiles
.get(&profile)
.ok_or_else(|| format!("profile not found: '{}'", profile).into())
}

fn validate_targeted_package(&self, tpkg: &TargetedPackage) -> Result<()> {
for c in tpkg.components.iter().chain(tpkg.extensions.iter()) {
let cpkg = self.get_package(&c.pkg)
Expand Down
4 changes: 2 additions & 2 deletions src/rustup-dist/src/manifestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ impl Manifestation {
///
/// `update` takes a manifest describing a release of Rust (which
/// may be either a freshly-downloaded one, or the same one used
/// for the previous install), as well as lists off extension
/// for the previous install), as well as lists of extension
/// components to add and remove.

/// From that it schedules a list of components to uninstall and
/// From that it schedules a list of components to install and
/// to uninstall to bring the installation up to date. It
/// downloads the components' packages. Then in a Transaction
/// uninstalls old packages and installs new packages, writes the
Expand Down
2 changes: 1 addition & 1 deletion src/rustup-utils/src/toml_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub fn get_array(
if let toml::Value::Array(s) = v {
Ok(s)
} else {
Err(ErrorKind::ExpectedType("table", path.to_owned() + key).into())
Err(ErrorKind::ExpectedType("array", path.to_owned() + key).into())
}
} else {
Ok(toml::value::Array::new())
Expand Down
Loading