use std::fmt; use std::process::Command; /// Helper to create commands in one line. pub fn command(program: &str, args: &[&str]) -> Command { let mut command = Command::new(program); command.args(args); command } /// The supported package manager. #[derive(Copy, Clone)] pub enum PackageManager { /// The apt manager, availble on Debian, Ubuntu and others. Apt, /// The pacman manager, available on ArchLinux, Manjaro and others. Pacman, } impl PackageManager { /// Returns the command to install a page using the right package manager. pub fn install<'a>(&self, package: &'a str) -> Command { match self { PackageManager::Apt => command("sudo", &["apt", "install", package]), PackageManager::Pacman => command("sudo", &["pacman", "-S", package]), } } } /// All the installable components. #[derive(Copy, Clone)] pub enum Component { /// Whether the user is allowed to run sudo commands. Sudo, /// Git enables to clone repository, which is necessary for many components. Git, /// The configuration uses the zsh shell. Zsh, /// The configuration files. Dotfiles, } impl Component { /// List all components. pub fn all() -> Vec { vec![Component::Git, Component::Zsh, Component::Dotfiles] } /// Installs a component. pub fn install(self) -> Result<()> { match self { Component::Sudo => todo!(), Component::Git => todo!(), Component::Zsh => todo!(), Component::Dotfiles => todo!(), } } /// Returns a command that tests if a component is installed. pub fn is_installed(self) -> bool { match self { Component::Sudo => panic!("can't use is_installed() on Component::Sudo"), Component::Git => todo!(), Component::Zsh => todo!(), Component::Dotfiles => todo!(), } } /// Returns the dependencies of each component. pub fn dependencies(self) -> &'static [Component] { match self { Component::Sudo => &[], Component::Git => &[Component::Sudo], Component::Zsh => &[Component::Sudo], Component::Dotfiles => &[Component::Git], } } } impl fmt::Display for Component { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Component::Sudo => write!(fmt, "sudo"), Component::Git => write!(fmt, "git"), Component::Zsh => write!(fmt, "zsh"), Component::Dotfiles => write!(fmt, "dotfiles"), } } } /// The struct that holds the information about the install. pub struct Installer { /// All the components to install, and whether the users want to install them. components: Vec<(Component, bool)>, /// Where the users cursor is. cursor: usize, } impl Installer { /// Creates a new installer. pub fn new() -> Installer { Installer { components: Component::all().into_iter().map(|x| (x, true)).collect(), cursor: 0, } } /// Prints the installer. pub fn print(&self) { print!("{}", self); } } impl fmt::Display for Installer { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { for (index, (component, to_install)) in self.components.iter().enumerate() { writeln!( fmt, "{} [{}] {} (requires {})", if self.cursor == index { ">" } else { " " }, if *to_install { "x" } else { " " }, component, component .dependencies() .into_iter() .map(|x| format!("{}", x)) .collect::>() .join(", ") )?; } Ok(()) } } /// The error type of this library. pub enum Error {} impl fmt::Display for Error { fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) } } /// The result type of this library. pub type Result = std::result::Result; /// Runs the installer pub fn main() -> Result<()> { let installer = Installer::new(); installer.print(); Ok(()) }