diff --git a/config.example.toml b/config.example.toml index 632385e2..9679e9a3 100644 --- a/config.example.toml +++ b/config.example.toml @@ -39,6 +39,13 @@ # Do not set the terminal title #set_title = false + +# Cleanup temporary or old files +#cleanup = true + +#[composer] +#self_update = true + # Commands to run before anything #[pre_commands] #"Emacs Snapshot" = "rm -rf ~/.emacs.d/elpa.bak && cp -rl ~/.emacs.d/elpa ~/.emacs.d/elpa.bak" @@ -46,6 +53,3 @@ # Custom commands #[commands] #"Python Environment" = "~/dev/.env/bin/pip install -i https://pypi.python.org/simple -U --upgrade-strategy eager jupyter" - -# Cleanup temporary or old files -#cleanup = true diff --git a/src/config.rs b/src/config.rs index 3c6f1912..6f575301 100644 --- a/src/config.rs +++ b/src/config.rs @@ -51,6 +51,11 @@ pub enum Step { Tldr, } +#[derive(Deserialize, Default, Debug)] +pub struct Composer { + self_update: Option, +} + #[derive(Deserialize, Default, Debug)] #[serde(deny_unknown_fields)] /// Configuration file @@ -73,6 +78,7 @@ pub struct ConfigFile { notify_each_step: Option, accept_all_windows_updates: Option, only: Option>, + composer: Option, } impl ConfigFile { @@ -356,6 +362,15 @@ impl Config { self.config_file.accept_all_windows_updates.unwrap_or(true) } + /// Whether Composer should update itself + pub fn composer_self_update(&self) -> bool { + self.config_file + .composer + .as_ref() + .and_then(|c| c.self_update) + .unwrap_or(false) + } + /// Whether to send a desktop notification at the beginning of every step #[allow(dead_code)] pub fn notify_each_step(&self) -> bool { diff --git a/src/main.rs b/src/main.rs index 3c2551a5..db76ae7e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -314,7 +314,7 @@ fn run() -> Result<()> { } if config.should_run(Step::Composer) { - runner.execute("composer", || generic::run_composer_update(&base_dirs, run_type))?; + runner.execute("composer", || generic::run_composer_update(&ctx))?; } #[cfg(not(any( diff --git a/src/steps/generic.rs b/src/steps/generic.rs index 4d8539d5..f1545f6e 100644 --- a/src/steps/generic.rs +++ b/src/steps/generic.rs @@ -1,6 +1,7 @@ use crate::error::{SkipStep, TopgradeError}; use crate::execution_context::ExecutionContext; -use crate::executor::{CommandExt, RunType}; +#[allow(unused_imports)] +use crate::executor::{CommandExt, ExecutorOutput, RunType}; use crate::terminal::{print_separator, shell}; use crate::utils::{self, PathExt}; use anyhow::Result; @@ -176,7 +177,7 @@ pub fn run_custom_command(name: &str, command: &str, ctx: &ExecutionContext) -> ctx.run_type().execute(shell()).arg("-c").arg(command).check_run() } -pub fn run_composer_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> { +pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> { let composer = utils::require("composer")?; let composer_home = Command::new(&composer) .args(&["global", "config", "--absolute", "--quiet", "home"]) @@ -185,16 +186,38 @@ pub fn run_composer_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<() .map(|s| PathBuf::from(s.trim()))? .require()?; - if !composer_home.is_descendant_of(base_dirs.home_dir()) { + if !composer_home.is_descendant_of(ctx.base_dirs().home_dir()) { return Err(SkipStep.into()); } print_separator("Composer"); + if ctx.config().composer_self_update() { + cfg_if::cfg_if! { + if #[cfg(unix)] { + // If self-update fails without sudo then there's probably an update + let has_update = match ctx.run_type().execute(&composer).arg("self-update").output()? { + ExecutorOutput::Wet(output) => !output.status.success(), + _ => false + }; + + if has_update { + ctx.run_type() + .execute(ctx.sudo().as_ref().unwrap()) + .arg(&composer) + .arg("self-update") + .check_run()?; + } + } else { + ctx.run_type().execute(&composer).arg("self-update").check_run()?; + } + } + } + let output = Command::new(&composer).args(&["global", "update"]).check_output()?; if output.contains("valet") { if let Some(valet) = utils::which("valet") { - run_type.execute(&valet).arg("install").check_run()?; + ctx.run_type().execute(&valet).arg("install").check_run()?; } }