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
|
||||
|
||||
[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::fs::{metadata, symlink_metadata};
|
||||
use std::path::PathBuf;
|
||||
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.
|
||||
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);
|
||||
command.args(args);
|
||||
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.
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum PackageManager {
|
||||
|
@ -22,14 +79,16 @@ 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::Apt => {
|
||||
command("sh", &["-c", &format!("sudo apt install -y {}", package)])
|
||||
}
|
||||
PackageManager::Pacman => command("sudo", &["pacman", "-S", package]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// All the installable components.
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Component {
|
||||
/// Whether the user is allowed to run sudo commands.
|
||||
Sudo,
|
||||
|
@ -42,31 +101,66 @@ pub enum Component {
|
|||
|
||||
/// The configuration files.
|
||||
Dotfiles,
|
||||
|
||||
/// The zshrc config file
|
||||
Zshrc,
|
||||
|
||||
/// The oh my zsh repository.
|
||||
OhMyZsh,
|
||||
}
|
||||
|
||||
impl Component {
|
||||
/// List all components.
|
||||
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.
|
||||
pub fn install(self) -> Result<()> {
|
||||
match self {
|
||||
Component::Sudo => todo!(),
|
||||
Component::Git => todo!(),
|
||||
Component::Zsh => todo!(),
|
||||
Component::Dotfiles => todo!(),
|
||||
}
|
||||
self.install_command(PackageManager::Apt).output().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 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!(),
|
||||
Component::Sudo => true,
|
||||
Component::Git => test_command("git"),
|
||||
Component::Zsh => test_command("zsh"),
|
||||
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::Zsh => &[Component::Sudo],
|
||||
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::Zsh => write!(fmt, "zsh"),
|
||||
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) {
|
||||
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 {
|
||||
|
@ -121,7 +246,7 @@ impl fmt::Display for Installer {
|
|||
for (index, (component, to_install)) in self.components.iter().enumerate() {
|
||||
writeln!(
|
||||
fmt,
|
||||
"{} [{}] {} (requires {})",
|
||||
"{} [{}] {} (requires {}{})",
|
||||
if self.cursor == index { ">" } else { " " },
|
||||
if *to_install { "x" } else { " " },
|
||||
component,
|
||||
|
@ -130,7 +255,12 @@ impl fmt::Display for Installer {
|
|||
.into_iter()
|
||||
.map(|x| format!("{}", x))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
.join(", "),
|
||||
if component.is_installed() {
|
||||
", already installed"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -153,5 +283,6 @@ pub type Result<T> = std::result::Result<T, Error>;
|
|||
pub fn main() -> Result<()> {
|
||||
let installer = Installer::new();
|
||||
installer.print();
|
||||
installer.start()?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue