Getting shit working
This commit is contained in:
		
							parent
							
								
									153d28170b
								
							
						
					
					
						commit
						89838ae594
					
				@ -7,4 +7,3 @@ edition = "2018"
 | 
				
			|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[dependencies]
 | 
					[dependencies]
 | 
				
			||||||
termion = "1.5.5"
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										163
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										163
									
								
								src/lib.rs
									
									
									
									
									
								
							@ -1,13 +1,70 @@
 | 
				
			|||||||
 | 
					use std::ffi::OsStr;
 | 
				
			||||||
use std::fmt;
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					use std::fs::{metadata, symlink_metadata};
 | 
				
			||||||
 | 
					use std::path::PathBuf;
 | 
				
			||||||
use std::process::Command;
 | 
					use std::process::Command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					macro_rules! unwrap_or_false {
 | 
				
			||||||
 | 
					    ($expr: expr) => {
 | 
				
			||||||
 | 
					        match $expr {
 | 
				
			||||||
 | 
					            Ok(v) => v,
 | 
				
			||||||
 | 
					            Err(_) => return false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns the home directory.
 | 
				
			||||||
 | 
					pub fn home() -> PathBuf {
 | 
				
			||||||
 | 
					    PathBuf::from(std::env::var("HOME").unwrap())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A path from the user's home.
 | 
				
			||||||
 | 
					pub fn from_home(path: &str) -> PathBuf {
 | 
				
			||||||
 | 
					    home().join(path)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Tests that a command exists.
 | 
				
			||||||
 | 
					pub fn test_command(cmd: &str) -> bool {
 | 
				
			||||||
 | 
					    unwrap_or_false!(command("sh", &["-c", &format!("command -v {}", cmd)]).output())
 | 
				
			||||||
 | 
					        .status
 | 
				
			||||||
 | 
					        .success()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Helper to create commands in one line.
 | 
					/// Helper to create commands in one line.
 | 
				
			||||||
pub fn command(program: &str, args: &[&str]) -> Command {
 | 
					pub fn command<I, S>(program: &str, args: I) -> Command
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    I: IntoIterator<Item = S>,
 | 
				
			||||||
 | 
					    S: AsRef<OsStr>,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    let mut command = Command::new(program);
 | 
					    let mut command = Command::new(program);
 | 
				
			||||||
    command.args(args);
 | 
					    command.args(args);
 | 
				
			||||||
    command
 | 
					    command
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Helper to create commands for cloning a github repository.
 | 
				
			||||||
 | 
					pub fn github_clone<T: AsRef<OsStr>>(user: &str, repo: &str, dest: T) -> Command {
 | 
				
			||||||
 | 
					    command(
 | 
				
			||||||
 | 
					        "git",
 | 
				
			||||||
 | 
					        &[
 | 
				
			||||||
 | 
					            &"clone".as_ref(),
 | 
				
			||||||
 | 
					            &format!("https://github.com/{}/{}", user, repo).as_ref(),
 | 
				
			||||||
 | 
					            dest.as_ref(),
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Helper to create commands for cloning a gitea repository.
 | 
				
			||||||
 | 
					pub fn gitea_clone<T: AsRef<OsStr>>(user: &str, repo: &str, dest: T) -> Command {
 | 
				
			||||||
 | 
					    command(
 | 
				
			||||||
 | 
					        "git",
 | 
				
			||||||
 | 
					        &[
 | 
				
			||||||
 | 
					            &"clone".as_ref(),
 | 
				
			||||||
 | 
					            &format!("https://gitea.tforgione.fr/{}/{}", user, repo).as_ref(),
 | 
				
			||||||
 | 
					            dest.as_ref(),
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The supported package manager.
 | 
					/// The supported package manager.
 | 
				
			||||||
#[derive(Copy, Clone)]
 | 
					#[derive(Copy, Clone)]
 | 
				
			||||||
pub enum PackageManager {
 | 
					pub enum PackageManager {
 | 
				
			||||||
@ -22,14 +79,16 @@ impl PackageManager {
 | 
				
			|||||||
    /// Returns the command to install a page using the right package manager.
 | 
					    /// Returns the command to install a page using the right package manager.
 | 
				
			||||||
    pub fn install<'a>(&self, package: &'a str) -> Command {
 | 
					    pub fn install<'a>(&self, package: &'a str) -> Command {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            PackageManager::Apt => command("sudo", &["apt", "install", package]),
 | 
					            PackageManager::Apt => {
 | 
				
			||||||
 | 
					                command("sh", &["-c", &format!("sudo apt install -y {}", package)])
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            PackageManager::Pacman => command("sudo", &["pacman", "-S", package]),
 | 
					            PackageManager::Pacman => command("sudo", &["pacman", "-S", package]),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// All the installable components.
 | 
					/// All the installable components.
 | 
				
			||||||
#[derive(Copy, Clone)]
 | 
					#[derive(Copy, Clone, PartialEq, Eq)]
 | 
				
			||||||
pub enum Component {
 | 
					pub enum Component {
 | 
				
			||||||
    /// Whether the user is allowed to run sudo commands.
 | 
					    /// Whether the user is allowed to run sudo commands.
 | 
				
			||||||
    Sudo,
 | 
					    Sudo,
 | 
				
			||||||
@ -42,31 +101,66 @@ pub enum Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// The configuration files.
 | 
					    /// The configuration files.
 | 
				
			||||||
    Dotfiles,
 | 
					    Dotfiles,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The zshrc config file
 | 
				
			||||||
 | 
					    Zshrc,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// The oh my zsh repository.
 | 
				
			||||||
 | 
					    OhMyZsh,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Component {
 | 
					impl Component {
 | 
				
			||||||
    /// List all components.
 | 
					    /// List all components.
 | 
				
			||||||
    pub fn all() -> Vec<Component> {
 | 
					    pub fn all() -> Vec<Component> {
 | 
				
			||||||
        vec![Component::Git, Component::Zsh, Component::Dotfiles]
 | 
					        vec![
 | 
				
			||||||
 | 
					            Component::Git,
 | 
				
			||||||
 | 
					            Component::Zsh,
 | 
				
			||||||
 | 
					            Component::Dotfiles,
 | 
				
			||||||
 | 
					            Component::OhMyZsh,
 | 
				
			||||||
 | 
					            Component::Zshrc,
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns the command that installs a component.
 | 
				
			||||||
 | 
					    pub fn install_command(self, package_manager: PackageManager) -> Command {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Component::Sudo => panic!("you can't install sudo"),
 | 
				
			||||||
 | 
					            Component::Git => package_manager.install("git"),
 | 
				
			||||||
 | 
					            Component::Zsh => package_manager.install("zsh"),
 | 
				
			||||||
 | 
					            Component::Dotfiles => {
 | 
				
			||||||
 | 
					                gitea_clone("tforgione", "dotfiles", from_home(".config/dotfiles"))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Component::OhMyZsh => github_clone("ohmyzsh", "ohmyzsh", from_home(".config/ohmyzsh")),
 | 
				
			||||||
 | 
					            Component::Zshrc => command(
 | 
				
			||||||
 | 
					                "ln",
 | 
				
			||||||
 | 
					                &[
 | 
				
			||||||
 | 
					                    AsRef::<OsStr>::as_ref("-s"),
 | 
				
			||||||
 | 
					                    &from_home(".config/dotfiles/zshrc").as_ref(),
 | 
				
			||||||
 | 
					                    &from_home(".zshrc").as_ref(),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Installs a component.
 | 
					    /// Installs a component.
 | 
				
			||||||
    pub fn install(self) -> Result<()> {
 | 
					    pub fn install(self) -> Result<()> {
 | 
				
			||||||
        match self {
 | 
					        self.install_command(PackageManager::Apt).output().unwrap();
 | 
				
			||||||
            Component::Sudo => todo!(),
 | 
					        Ok(())
 | 
				
			||||||
            Component::Git => todo!(),
 | 
					 | 
				
			||||||
            Component::Zsh => todo!(),
 | 
					 | 
				
			||||||
            Component::Dotfiles => todo!(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Returns a command that tests if a component is installed.
 | 
					    /// Returns a command that tests if a component is installed.
 | 
				
			||||||
    pub fn is_installed(self) -> bool {
 | 
					    pub fn is_installed(self) -> bool {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Component::Sudo => panic!("can't use is_installed() on Component::Sudo"),
 | 
					            Component::Sudo => true,
 | 
				
			||||||
            Component::Git => todo!(),
 | 
					            Component::Git => test_command("git"),
 | 
				
			||||||
            Component::Zsh => todo!(),
 | 
					            Component::Zsh => test_command("zsh"),
 | 
				
			||||||
            Component::Dotfiles => todo!(),
 | 
					            Component::Dotfiles => {
 | 
				
			||||||
 | 
					                unwrap_or_false!(metadata(from_home(".config/dotfiles"))).is_dir()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Component::OhMyZsh => unwrap_or_false!(metadata(from_home(".config/ohmyzsh"))).is_dir(),
 | 
				
			||||||
 | 
					            Component::Zshrc => unwrap_or_false!(symlink_metadata(from_home(".zshrc")))
 | 
				
			||||||
 | 
					                .file_type()
 | 
				
			||||||
 | 
					                .is_symlink(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -77,6 +171,8 @@ impl Component {
 | 
				
			|||||||
            Component::Git => &[Component::Sudo],
 | 
					            Component::Git => &[Component::Sudo],
 | 
				
			||||||
            Component::Zsh => &[Component::Sudo],
 | 
					            Component::Zsh => &[Component::Sudo],
 | 
				
			||||||
            Component::Dotfiles => &[Component::Git],
 | 
					            Component::Dotfiles => &[Component::Git],
 | 
				
			||||||
 | 
					            Component::Zshrc => &[Component::Zsh, Component::Dotfiles],
 | 
				
			||||||
 | 
					            Component::OhMyZsh => &[Component::Git],
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -88,6 +184,8 @@ impl fmt::Display for Component {
 | 
				
			|||||||
            Component::Git => write!(fmt, "git"),
 | 
					            Component::Git => write!(fmt, "git"),
 | 
				
			||||||
            Component::Zsh => write!(fmt, "zsh"),
 | 
					            Component::Zsh => write!(fmt, "zsh"),
 | 
				
			||||||
            Component::Dotfiles => write!(fmt, "dotfiles"),
 | 
					            Component::Dotfiles => write!(fmt, "dotfiles"),
 | 
				
			||||||
 | 
					            Component::Zshrc => write!(fmt, "zshrc"),
 | 
				
			||||||
 | 
					            Component::OhMyZsh => write!(fmt, "ohmyzsh"),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -114,6 +212,33 @@ impl Installer {
 | 
				
			|||||||
    pub fn print(&self) {
 | 
					    pub fn print(&self) {
 | 
				
			||||||
        print!("{}", self);
 | 
					        print!("{}", self);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Runs the installer.
 | 
				
			||||||
 | 
					    pub fn start(&self) -> Result<()> {
 | 
				
			||||||
 | 
					        for (component, to_install) in &self.components {
 | 
				
			||||||
 | 
					            if *to_install {
 | 
				
			||||||
 | 
					                self.install_component(*component)?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Installs a component.
 | 
				
			||||||
 | 
					    pub fn install_component(&self, component: Component) -> Result<()> {
 | 
				
			||||||
 | 
					        if component.is_installed() || component == Component::Sudo {
 | 
				
			||||||
 | 
					            return Ok(());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        println!("Install {}", component);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for dep in component.dependencies() {
 | 
				
			||||||
 | 
					            self.install_component(*dep)?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if !component.is_installed() {
 | 
				
			||||||
 | 
					            component.install()?;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl fmt::Display for Installer {
 | 
					impl fmt::Display for Installer {
 | 
				
			||||||
@ -121,7 +246,7 @@ impl fmt::Display for Installer {
 | 
				
			|||||||
        for (index, (component, to_install)) in self.components.iter().enumerate() {
 | 
					        for (index, (component, to_install)) in self.components.iter().enumerate() {
 | 
				
			||||||
            writeln!(
 | 
					            writeln!(
 | 
				
			||||||
                fmt,
 | 
					                fmt,
 | 
				
			||||||
                "{} [{}] {} (requires {})",
 | 
					                "{} [{}] {} (requires {}{})",
 | 
				
			||||||
                if self.cursor == index { ">" } else { " " },
 | 
					                if self.cursor == index { ">" } else { " " },
 | 
				
			||||||
                if *to_install { "x" } else { " " },
 | 
					                if *to_install { "x" } else { " " },
 | 
				
			||||||
                component,
 | 
					                component,
 | 
				
			||||||
@ -130,7 +255,12 @@ impl fmt::Display for Installer {
 | 
				
			|||||||
                    .into_iter()
 | 
					                    .into_iter()
 | 
				
			||||||
                    .map(|x| format!("{}", x))
 | 
					                    .map(|x| format!("{}", x))
 | 
				
			||||||
                    .collect::<Vec<_>>()
 | 
					                    .collect::<Vec<_>>()
 | 
				
			||||||
                    .join(", ")
 | 
					                    .join(", "),
 | 
				
			||||||
 | 
					                if component.is_installed() {
 | 
				
			||||||
 | 
					                    ", already installed"
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    ""
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            )?;
 | 
					            )?;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
@ -153,5 +283,6 @@ pub type Result<T> = std::result::Result<T, Error>;
 | 
				
			|||||||
pub fn main() -> Result<()> {
 | 
					pub fn main() -> Result<()> {
 | 
				
			||||||
    let installer = Installer::new();
 | 
					    let installer = Installer::new();
 | 
				
			||||||
    installer.print();
 | 
					    installer.print();
 | 
				
			||||||
 | 
					    installer.start()?;
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user