From 3c71ce019b7cb89f790983c0a086ff399334d387 Mon Sep 17 00:00:00 2001 From: Roey Darwish Dror Date: Thu, 22 Aug 2019 22:29:31 +0300 Subject: [PATCH] Add a command for editing the configuration --- src/config.rs | 49 ++++++++++++++++++++++++++++++++++++++++++------- src/main.rs | 5 +++++ src/utils.rs | 5 +++++ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/config.rs b/src/config.rs index 1cf0d5c6..4fced28f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,4 +1,5 @@ use super::error::{Error, ErrorKind}; +use super::utils::editor; use directories::BaseDirs; use failure::ResultExt; use lazy_static::lazy_static; @@ -8,6 +9,8 @@ use serde::Deserialize; use shellexpand; use std::collections::{BTreeMap, HashMap}; use std::fs::write; +use std::path::PathBuf; +use std::process::Command; use std::{env, fs}; use structopt::StructOpt; use toml; @@ -87,10 +90,7 @@ pub struct ConfigFile { } impl ConfigFile { - /// Read the configuration file. - /// - /// If the configuration file does not exist the function returns the default ConfigFile. - fn read(base_dirs: &BaseDirs) -> Result { + fn ensure(base_dirs: &BaseDirs) -> Result { let config_path = base_dirs.config_dir().join("topgrade.toml"); if !config_path.exists() { write(&config_path, include_str!("../config.example.toml")) @@ -100,12 +100,20 @@ impl ConfigFile { config_path.display(), e ); + e }) - .ok(); + .context(ErrorKind::Configuration)?; debug!("No configuration exists"); - return Ok(Default::default()); } + Ok(config_path) + } + + /// Read the configuration file. + /// + /// If the configuration file does not exist the function returns the default ConfigFile. + fn read(base_dirs: &BaseDirs) -> Result { + let config_path = Self::ensure(base_dirs)?; let mut result: Self = toml::from_str(&fs::read_to_string(config_path).context(ErrorKind::Configuration)?) .context(ErrorKind::Configuration)?; @@ -119,12 +127,29 @@ impl ConfigFile { Ok(result) } + + fn edit(base_dirs: &BaseDirs) -> Result<(), Error> { + let config_path = Self::ensure(base_dirs)?; + let editor = editor(); + + debug!("Editing {} with {}", config_path.display(), editor); + Command::new(editor) + .arg(config_path) + .spawn() + .and_then(|mut p| p.wait()) + .context(ErrorKind::Configuration)?; + Ok(()) + } } #[derive(StructOpt, Debug)] -#[structopt(name = "Topgrade")] +#[structopt(name = "Topgrade", raw(setting = "structopt::clap::AppSettings::ColoredHelp"))] /// Command line arguments pub struct CommandLineArgs { + /// Edit the configuration file + #[structopt(long = "edit-config")] + edit_config: bool, + /// Run inside tmux #[structopt(short = "t", long = "tmux")] run_in_tmux: bool, @@ -185,6 +210,11 @@ impl Config { }) } + /// Launch an editor to edit the configuration + pub fn edit(base_dirs: &BaseDirs) -> Result<(), Error> { + ConfigFile::edit(base_dirs) + } + /// The list of commands to run before performing any step. pub fn pre_commands(&self) -> &Option { &self.config_file.pre_commands @@ -244,4 +274,9 @@ impl Config { pub fn keep_at_end(&self) -> bool { self.opt.keep_at_end || env::var("TOPGRADE_KEEP_END").is_ok() } + + /// Whether to edit the configuration file + pub fn edit_config(&self) -> bool { + self.opt.edit_config + } } diff --git a/src/main.rs b/src/main.rs index e47c51ff..6ceb4ee0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,6 +67,11 @@ fn run() -> Result<(), Error> { let base_dirs = directories::BaseDirs::new().ok_or(ErrorKind::NoBaseDirectories)?; let config = Config::load(&base_dirs)?; + if config.edit_config() { + Config::edit(&base_dirs)?; + return Ok(()); + }; + if config.run_in_tmux() && env::var("TOPGRADE_INSIDE_TMUX").is_err() { #[cfg(unix)] { diff --git a/src/utils.rs b/src/utils.rs index 65048b5d..af45b6ab 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,6 @@ use super::error::{Error, ErrorKind}; use log::{debug, error}; +use std::env; use std::ffi::OsStr; use std::fmt::{self, Debug}; use std::path::{Component, Path, PathBuf}; @@ -138,6 +139,10 @@ impl<'a> fmt::Display for HumanizedPath<'a> { } } +pub fn editor() -> String { + env::var("EDITOR").unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" })) +} + #[cfg(test)] #[cfg(windows)] mod tests {