Working on UI
This commit is contained in:
parent
89838ae594
commit
1d3c6c83e4
|
@ -7,3 +7,4 @@ 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]
|
||||||
|
dialoguer = "0.7.1"
|
||||||
|
|
120
src/lib.rs
120
src/lib.rs
|
@ -4,6 +4,8 @@ use std::fs::{metadata, symlink_metadata};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use dialoguer::{theme::SimpleTheme, Confirm, MultiSelect};
|
||||||
|
|
||||||
macro_rules! unwrap_or_false {
|
macro_rules! unwrap_or_false {
|
||||||
($expr: expr) => {
|
($expr: expr) => {
|
||||||
match $expr {
|
match $expr {
|
||||||
|
@ -171,22 +173,41 @@ 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::Zshrc => &[Component::Zsh, Component::Dotfiles, Component::OhMyZsh],
|
||||||
Component::OhMyZsh => &[Component::Git],
|
Component::OhMyZsh => &[Component::Git],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the str representation of the command.
|
||||||
|
pub fn to_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Component::Sudo => "sudo",
|
||||||
|
Component::Git => "git",
|
||||||
|
Component::Zsh => "zsh",
|
||||||
|
Component::Dotfiles => "dotfiles",
|
||||||
|
Component::Zshrc => "zshrc",
|
||||||
|
Component::OhMyZsh => "ohmyzsh",
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Component {
|
impl fmt::Display for Component {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
write!(
|
||||||
Component::Sudo => write!(fmt, "sudo"),
|
fmt,
|
||||||
Component::Git => write!(fmt, "git"),
|
"{} (requires {}{})",
|
||||||
Component::Zsh => write!(fmt, "zsh"),
|
self.to_str(),
|
||||||
Component::Dotfiles => write!(fmt, "dotfiles"),
|
self.dependencies()
|
||||||
Component::Zshrc => write!(fmt, "zshrc"),
|
.into_iter()
|
||||||
Component::OhMyZsh => write!(fmt, "ohmyzsh"),
|
.map(|x| x.to_str())
|
||||||
}
|
.collect::<Vec<_>>()
|
||||||
|
.join(", "),
|
||||||
|
if self.is_installed() {
|
||||||
|
", already installed"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,23 +215,52 @@ impl fmt::Display for Component {
|
||||||
pub struct Installer {
|
pub struct Installer {
|
||||||
/// All the components to install, and whether the users want to install them.
|
/// All the components to install, and whether the users want to install them.
|
||||||
components: Vec<(Component, bool)>,
|
components: Vec<(Component, bool)>,
|
||||||
|
|
||||||
/// Where the users cursor is.
|
|
||||||
cursor: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Installer {
|
impl Installer {
|
||||||
/// Creates a new installer.
|
/// Creates a new installer.
|
||||||
pub fn new() -> Installer {
|
pub fn new() -> Installer {
|
||||||
Installer {
|
Installer {
|
||||||
components: Component::all().into_iter().map(|x| (x, true)).collect(),
|
components: Component::all().into_iter().map(|x| (x, false)).collect(),
|
||||||
cursor: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prints the installer.
|
/// Asks interactively to the user which components to install.
|
||||||
pub fn print(&self) {
|
pub fn interact(&mut self) -> bool {
|
||||||
print!("{}", self);
|
let multiselected = self
|
||||||
|
.components
|
||||||
|
.iter()
|
||||||
|
.map(|(component, _)| format!("{}", component))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let defaults = self
|
||||||
|
.components
|
||||||
|
.iter()
|
||||||
|
.map(|(_, active)| *active)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let selections = MultiSelect::with_theme(&SimpleTheme)
|
||||||
|
.items(&multiselected[..])
|
||||||
|
.defaults(&defaults[..])
|
||||||
|
.interact()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for i in selections {
|
||||||
|
self.components[i].1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("The following components will be installed:");
|
||||||
|
for (comp, to_install) in &self.components {
|
||||||
|
if *to_install {
|
||||||
|
println!(" - {}", comp.to_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let message = "Is this correct?";
|
||||||
|
|
||||||
|
Confirm::with_theme(&SimpleTheme)
|
||||||
|
.with_prompt(message)
|
||||||
|
.interact()
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs the installer.
|
/// Runs the installer.
|
||||||
|
@ -228,7 +278,8 @@ impl Installer {
|
||||||
if component.is_installed() || component == Component::Sudo {
|
if component.is_installed() || component == Component::Sudo {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
println!("Install {}", component);
|
|
||||||
|
println!("Install {}", component.to_str());
|
||||||
|
|
||||||
for dep in component.dependencies() {
|
for dep in component.dependencies() {
|
||||||
self.install_component(*dep)?;
|
self.install_component(*dep)?;
|
||||||
|
@ -241,32 +292,6 @@ impl Installer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::<Vec<_>>()
|
|
||||||
.join(", "),
|
|
||||||
if component.is_installed() {
|
|
||||||
", already installed"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The error type of this library.
|
/// The error type of this library.
|
||||||
pub enum Error {}
|
pub enum Error {}
|
||||||
|
|
||||||
|
@ -281,8 +306,9 @@ pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
/// Runs the installer
|
/// Runs the installer
|
||||||
pub fn main() -> Result<()> {
|
pub fn main() -> Result<()> {
|
||||||
let installer = Installer::new();
|
let mut installer = Installer::new();
|
||||||
installer.print();
|
if installer.interact() {
|
||||||
installer.start()?;
|
installer.start()?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue