Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add packages sub-commands #8

Merged
merged 2 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ envhub-providers = {path = "../providers", version = "0.1.0"}
envhub-stow = {path = "../stow", version = "0.1.0"}
envhub-types = {path = "../types", version = "0.1.0"}
hcl-rs = "0.14.2"
owo-colors = "3.5.0"
tokio = {version = "1.28.2", features = ["full"]}
toml = "0.7.4"
52 changes: 48 additions & 4 deletions crates/cli/src/cmd/package.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,59 @@
use anyhow::Error;
use owo_colors::OwoColorize;

pub fn add(_package: &str) -> Result<(), Error> {
// switch_env(None, config)?;
use crate::{
cmd::r#use::use_environment,
helpers::{read_envhub_file, write_envhub_file},
};

pub fn add(package: &str, apply: bool) -> Result<(), Error> {
let mut config = read_envhub_file(".")?;
let mut packages = config.packages.unwrap_or_default();
if packages.contains(&package.to_string()) {
println!("Package {} already in envhub file", package.cyan());
return Ok(());
}
packages.push(package.to_string());
config.packages = Some(packages);
write_envhub_file(".", &config)?;
println!("Package {} added to envhub file", package.cyan());
if apply {
use_environment(".")?;
}
Ok(())
}

pub fn list() -> Result<(), Error> {
let config = read_envhub_file(".")?;
println!("Packages found in envhub file:\n");
for package in config.packages.unwrap_or_default() {
println!("* {}", package.cyan());
}
println!("");
Ok(())
}

pub fn remove(_package: &str) -> Result<(), Error> {
// switch_env(None, config)?;
pub fn remove(package: &str, apply: bool) -> Result<(), Error> {
let mut config = read_envhub_file(".")?;
let mut packages = config.packages.unwrap_or_default();
if !packages.contains(&package.to_string()) {
println!(
"{} Package {} not in envhub file",
"[✗]".red(),
package.cyan()
);
return Ok(());
}
packages.retain(|x| x != package);
config.packages = Some(packages);
write_envhub_file(".", &config)?;
println!(
"{} Package {} removed from envhub file",
"[✓]".bright_green(),
package.cyan()
);
if apply {
use_environment(".")?;
}
Ok(())
}
10 changes: 10 additions & 0 deletions crates/cli/src/cmd/use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ pub fn use_environment(name: &str) -> Result<(), Error> {

switch_env(Some(&home_manager_dir), &config)?;

let state = toml::to_string(&config)?;

if config.symlink_manager == Some("stow".into()) {
let target = std::env::var("HOME")?;
let package = "dotfiles";
Expand All @@ -51,5 +53,13 @@ pub fn use_environment(name: &str) -> Result<(), Error> {
),
)?;

fs::write(
format!("{}/.envhub/envhub.toml", std::env::var("HOME")?),
format!(
"# This file is automatically @generated by envhub.\n# It is not intended for manual editing.\n\n{}",
state
),
)?;

Ok(())
}
52 changes: 52 additions & 0 deletions crates/cli/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,59 @@ pub fn read_envhub_file(dir: &str) -> Result<Configuration, Error> {
}
}

pub fn write_envhub_file(dir: &str, config: &Configuration) -> Result<(), Error> {
let mut path = format!("{}/envhub.hcl", dir);

if !fs::metadata(&path).is_ok() {
path = format!("{}/envhub.toml", dir);
}

if !fs::metadata(&path).is_ok() {
panic!("No `envhub.toml` or `envhub.hcl` file found in {}", dir)
}

let ext = path.split(".").last().unwrap();
match ext {
"toml" => {
let content = toml::to_string_pretty(&config)?;
fs::write(&path, content)?;
Ok(())
}
"hcl" => {
let content = hcl::to_string(&config)?;
fs::write(&path, content)?;
Ok(())
}
_ => panic!("Unknown file extension: {}", ext),
}
}

fn sync_packages(config: &Configuration) -> Result<(), Error> {
let current_state = fs::read_to_string(format!("{}/.envhub/envhub.toml", env::var("HOME")?))?;
let current_config: Configuration = toml::from_str(&current_state)?;
let current_packages = current_config.packages.clone().unwrap_or_default();
let packages = config.packages.clone().unwrap_or_default();
for package in current_packages {
if !packages.contains(&package) {
let pm: Box<dyn PackageManager> =
match current_config.package_manager.as_ref().unwrap().as_str() {
"homebrew" => Box::new(Homebrew::new()),
"brew" => Box::new(Homebrew::new()),
"pkgx" => Box::new(Pkgx::new()),
"devbox" => Box::new(Devbox::new()),
_ => panic!("Unknown package manager"),
};
pm.uninstall(&package)?;
}
}
Ok(())
}

pub fn install_packages(config: &Configuration) -> Result<(), Error> {
if fs::metadata(format!("{}/.envhub/envhub.toml", env::var("HOME")?)).is_ok() {
self::sync_packages(config)?;
}

let packages = config.packages.clone().unwrap_or_default();
let pm: Box<dyn PackageManager> = match config.package_manager.as_ref().unwrap().as_str() {
"homebrew" => Box::new(Homebrew::new()),
Expand Down
21 changes: 15 additions & 6 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,17 @@ fn cli() -> Command<'static> {
.subcommand(
Command::new("add")
.about("Add a package to the environment")
.arg(arg!(<package>)),
.arg(arg!(<package>))
.arg(arg!(--apply "Apply the configuration after adding a package")),
)
.subcommand(
Command::new("remove")
.alias("rm")
.about("Remove a package from the environment")
.arg(arg!(--apply "Apply the configuration after removing a package"))
.arg(arg!(<package>)),
)
.subcommand(Command::new("list").about("List all packages in the environment")),
.subcommand(Command::new("list").alias("ls").about("List all packages in the environment")),
)
.subcommand(
Command::new("env")
Expand All @@ -76,10 +79,11 @@ fn cli() -> Command<'static> {
)
.subcommand(
Command::new("remove")
.alias("rm")
.about("Remove an environment variable from the environment")
.arg(arg!(<key>).required(true).index(1)),
)
.subcommand(Command::new("list").about("List all environment variables")),
.subcommand(Command::new("list").alias("ls").about("List all environment variables")),
)
.subcommand(
Command::new("file")
Expand All @@ -99,10 +103,11 @@ fn cli() -> Command<'static> {
)
.subcommand(
Command::new("remove")
.alias("rm")
.about("Remove a file from the environment")
.arg(arg!(<key>).required(true).index(1)),
)
.subcommand(Command::new("list").about("List all files")),
.subcommand(Command::new("list").alias("ls").about("List all files")),
)
.subcommand(
Command::new("use")
Expand Down Expand Up @@ -159,8 +164,12 @@ async fn main() -> Result<(), Error> {
_ => cli().print_help().unwrap(),
},
Some(("package", args)) => match args.subcommand() {
Some(("add", args)) => cmd::package::add(args.value_of("package").unwrap())?,
Some(("remove", args)) => cmd::package::remove(args.value_of("package").unwrap())?,
Some(("add", args)) => {
cmd::package::add(args.value_of("package").unwrap(), args.is_present("apply"))?
}
Some(("remove", args)) => {
cmd::package::remove(args.value_of("package").unwrap(), args.is_present("apply"))?
}
Some(("list", _)) => cmd::package::list()?,
_ => cli().print_help().unwrap(),
},
Expand Down
17 changes: 17 additions & 0 deletions crates/pkgs/src/pkgx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,21 @@ impl Pkgx {
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 {
Expand Down Expand Up @@ -70,6 +85,8 @@ impl PackageManager for Pkgx {
}

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")
Expand Down
3 changes: 3 additions & 0 deletions crates/providers/src/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ impl Github {
}

impl Provider for Github {
fn name(&self) -> &str {
"github"
}
fn load(&self, repo: &str) -> Result<(), Error> {
let url = format!("https://github.com/{}", repo);
self.clone(&url, repo)?;
Expand Down
1 change: 1 addition & 0 deletions crates/providers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ pub mod local;
pub mod s3;

pub trait Provider {
fn name(&self) -> &str;
fn load(&self, name: &str) -> Result<(), Error>;
}
3 changes: 3 additions & 0 deletions crates/providers/src/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ impl Local {
}

impl Provider for Local {
fn name(&self) -> &str {
"local"
}
fn load(&self, name: &str) -> Result<(), Error> {
self.copy(name)?;
Ok(())
Expand Down
3 changes: 3 additions & 0 deletions crates/providers/src/s3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ impl S3 {
}

impl Provider for S3 {
fn name(&self) -> &str {
"s3"
}
fn load(&self, name: &str) -> Result<(), Error> {
self.download(name)?;
Ok(())
Expand Down
6 changes: 3 additions & 3 deletions examples/pkgx/envhub.hcl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
packages = [
"jq",
"vim.org/vim",
"aws"
"aws",
"jq"
]

envs {
Expand All @@ -12,4 +12,4 @@ file ".screenrc" {
source = "dotfiles/.screenrc"
}

package_manager = "pkgx"
package_manager = "pkgx"