1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use std::{
    env, fs,
    process::{Command, Stdio},
};

use crate::PackageManager;
use anyhow::Error;

pub struct Pkgx {}

impl Pkgx {
    pub fn new() -> Self {
        Self {}
    }

    pub fn write_command(&self, name: &str) -> Result<(), Error> {
        let org = name.split("/").next().unwrap();
        let package = name.split("/").last().unwrap();

        let mut command = "#!/bin/sh\n".to_string();
        command.push_str(&format!("exec pkgx +{} -- {} \"$@\"", org, package));
        fs::write(
            format!("{}/.local/bin/{}", env::var("HOME")?, package),
            command,
        )?;

        let mut child = Command::new("sh")
            .arg("-c")
            .arg(format!("chmod +x ~/.local/bin/{}", package))
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn()?;
        child.wait()?;
        Ok(())
    }

    pub fn setup_path(&self, rc_file: &str) -> Result<(), Error> {
        let mut child = Command::new("sh")
            .arg("-c")
            .arg(format!(
                "type pkgx > /dev/null || echo \'PATH=$HOME/.local/bin:$PATH\' >> ~/{}",
                rc_file
            ))
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn()?;
        child.wait()?;
        Ok(())
    }
}

impl PackageManager for Pkgx {
    fn install(&self, name: &str) -> Result<(), Error> {
        self.setup()?;
        if name.split("/").count() == 2 {
            return self.write_command(name);
        }

        let mut child = Command::new("sh")
            .arg("-c")
            .arg(format!(
                "[ ! -f ~/.local/bin/{} ] && pkgx install {}",
                name, name
            ))
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn()?;
        child.wait()?;
        Ok(())
    }

    fn uninstall(&self, name: &str) -> Result<(), Error> {
        let mut child = Command::new("sh")
            .arg("-c")
            .arg(format!("rm ~/.local/bin/{}", name))
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn()?;
        child.wait()?;
        Ok(())
    }

    fn setup(&self) -> Result<(), Error> {
        self.setup_path(".bashrc")?;
        self.setup_path(".zshrc")?;
        let mut child = Command::new("sh")
            .arg("-c")
            .arg("type pkgx > /dev/null || curl -fsS https://pkgx.sh | sh")
            .stdin(Stdio::inherit())
            .stdout(Stdio::inherit())
            .stderr(Stdio::inherit())
            .spawn()?;
        child.wait()?;
        Ok(())
    }
}