libkelp/lib/cli/
install.rs

1use crate::lib::{
2    config::loader::load_cfg,
3    fsutil::{
4        copy::copy,
5        paths::{get_ins_root, get_root},
6    },
7    structs::{config::KelpDotConfig, pm::PackageManager},
8    util::{
9        exec::get_root_exec_program,
10        os::{get_host_os, is_os},
11        pm::get_distro_pm,
12        scripts::run_script,
13    },
14};
15use anyhow::Context;
16use kelpdot_macros::*;
17use std::{path::Path, process::Command};
18pub fn install() -> anyhow::Result<()> {
19    let root = get_root()?;
20    cyan_print!("[INFO] Installing dotfiles {}", root);
21    debug_print!("Building OS list...");
22    let os = get_host_os()?;
23    let insroot = get_ins_root()?;
24    debug_print!("Install root: {}", insroot);
25    cyan_print!("Found OS {}", os.prettyname);
26    let config: KelpDotConfig = load_cfg(root.clone())?;
27    if let Some(scripts) = config.prerun {
28        for script in scripts {
29            cyan_print!("[PRERUN] Running script {}", script.path);
30            run_script(root.clone(), script)?;
31        }
32    }
33    if let Some(files) = config.homefiles {
34        let home_files_path = format!("{}/home", root);
35        for file in files {
36            if let Some(distro) = &file.onlyon {
37                if &os.name != distro && !os.submatches.iter().any(|mat| mat == distro) {
38                    debug_print!("Not installing file {} because host != onlyon", file);
39                    break;
40                }
41            }
42            let home =
43                std::env::var("HOME").with_context(|| red!("Unable to get env var $HOME!"))?; // Get $HOME path or crash
44            debug_print!("Home: {}", home);
45            if Path::new(&format!("{}/{}", home_files_path, file.path)).exists() {
46                cyan_print!("[INFO] Installing {}", file);
47                copy(
48                    format!("{}/{}", home_files_path, file.path),
49                    format!("{}/{}/{}", insroot, home, file.path),
50                )?;
51            }
52        }
53    }
54    // The work of rootfiles copy is **really** different:
55    // Firstly we check if file exist
56    // We create a Shell script with required files copies
57    // We execute it as root
58    // DONE!
59    if let Some(files) = config.rootfiles {
60        let mut bash_code = String::from("#!/usr/bin/env sh\n#This script has been auto-generated and will be runned by KelpDot\n#It isn't intended to be modified manually\n");
61        for file in files {
62            if let Some(distro) = &file.onlyon {
63                if &os.name != distro && !os.submatches.iter().any(|mat| mat == distro) {
64                    debug_print!("Not installing file {} because host != onlyon", file);
65                    break;
66                }
67            }
68            let fpath = format!("{}{}", root, file.path);
69            // ShBang isn't really needed, I know
70            let path = Path::new(&fpath);
71            let inspath = format!("{}/{}", insroot, &file.path);
72            let dest_parent = Path::new(&inspath).parent().unwrap().to_str().unwrap();
73            if path.exists() {
74                bash_code = format!(
75                    "{}if [[ ! -d {} ]]\nthen\nmkdir -p {}\nfi\ncp -r {} {}\n",
76                    bash_code,
77                    dest_parent,
78                    dest_parent,
79                    path.to_str().unwrap(),
80                    dest_parent
81                );
82            }
83        }
84        std::fs::write("/tmp/kelpdot_install.sh", bash_code)?;
85        let rexec = get_root_exec_program()?;
86        Command::new(&rexec) // Use SH because some systems symlinks it to bash / zsh / ash
87            .arg("sh")
88            .arg("/tmp/kelpdot_install.sh")
89            .status()
90            .with_context(|| red!("Unable to call rootfiles install script!"))?;
91    }
92    // Check if we need to install packages
93    if let Some(packages) = config.packages {
94        let mut pm = get_distro_pm()?;
95        if let Some(gentoo) = packages.gentoo {
96            if is_os("gentoo")? {
97                if let Some(pkgs) = gentoo.packages {
98                    pm.install_packages(pkgs)?;
99                }
100                if let Some(file) = gentoo.with_file {
101                    let mut packages: Vec<String> = Vec::new();
102                    let filepath = format!("{}/{}", root, file);
103                    let fpath = Path::new(&filepath);
104                    if fpath.exists() {
105                        let contents = std::fs::read_to_string(filepath)?;
106                        contents.lines().into_iter().for_each(|x| {
107                            packages.push(String::from(x));
108                        });
109                    }
110                    pm.install_packages(packages)?;
111                }
112            }
113        }
114    }
115    if let Some(scripts) = config.postrun {
116        for script in scripts {
117            cyan_print!("[POSTRUN] Running script {}", script.path);
118            run_script(root.clone(), script)?;
119        }
120    }
121    Ok(())
122}