From f73501c2221a7fc27ed34b2de5f075305561e724 Mon Sep 17 00:00:00 2001 From: Matt Godbolt Date: Mon, 30 Sep 2024 13:31:32 -0500 Subject: [PATCH] Support symlink installation --- rozy/src/app.rs | 13 ++++++++ rozy/src/installers/mod.rs | 1 + rozy/src/installers/symlink.rs | 48 ++++++++++++++++++++++++++++ rozy/test_resource/unittest.ozy.yaml | 6 ++++ 4 files changed, 68 insertions(+) create mode 100644 rozy/src/installers/symlink.rs diff --git a/rozy/src/app.rs b/rozy/src/app.rs index d34013b..927d720 100644 --- a/rozy/src/app.rs +++ b/rozy/src/app.rs @@ -11,6 +11,7 @@ use crate::installers::shell::Shell; use crate::installers::single_binary_zip::SingleBinaryZip; use crate::installers::tarball::Tarball; use crate::installers::zip::Zip; +use crate::installers::symlink::Symlink; pub enum AppType { SingleBinaryZip, @@ -20,6 +21,7 @@ pub enum AppType { Conda, Pip, Zip, + Symlink } pub struct App { @@ -78,6 +80,7 @@ impl App { "pip" => AppType::Pip, "conda" => AppType::Conda, "zip" => AppType::Zip, + "symlink" => AppType::Symlink, _ => { return Err(anyhow!("App type {} not yet supported", &app_type[..])); } @@ -100,6 +103,7 @@ impl App { AppType::File => Box::new(File::new(name, &version, &app_config)?), AppType::Conda => Box::new(Conda::new(name, &version, &app_config)?), AppType::Pip => Box::new(Pip::new(name, &version, &app_config)?), + AppType::Symlink => Box::new(Symlink::new(name, &version, &app_config)?), }; let executable_path = match app_config.get("executable_path") { @@ -327,4 +331,13 @@ mod tests { "file installer for file_app v.6.6.0" ); } + #[test] + fn symlink_test() { + let config = get_test_config(); + let file_app = App::new(&"symilnk_app".to_string(), &config).expect("Failed to construct App"); + assert_eq!( + file_app.installer.describe(), + "symlink installer for file_app v.5.6.7" + ); + } } diff --git a/rozy/src/installers/mod.rs b/rozy/src/installers/mod.rs index fbc636b..969580f 100644 --- a/rozy/src/installers/mod.rs +++ b/rozy/src/installers/mod.rs @@ -4,5 +4,6 @@ pub mod installer; pub mod pip; pub mod shell; pub mod single_binary_zip; +pub mod symlink; pub mod tarball; pub mod zip; diff --git a/rozy/src/installers/symlink.rs b/rozy/src/installers/symlink.rs new file mode 100644 index 0000000..299f7df --- /dev/null +++ b/rozy/src/installers/symlink.rs @@ -0,0 +1,48 @@ +use super::installer::Installer; + +use anyhow::{anyhow, Context, Error, Result}; + +pub struct Symlink { + name: String, + version: String, + path: std::path::PathBuf, +} + +impl Symlink { + pub fn new( + name: &String, + version: &str, + app_config: &serde_yaml::Mapping, + ) -> Result { + let path = match app_config.get("path") { + Some(serde_yaml::Value::String(path)) => std::path::Path::new(path), + _ => { + return Err(anyhow!("Expected a string path in config for {}", name)); + } + }; + + Ok(Symlink { + name: name.clone(), + version: version.to_string(), + path: path.to_owned() + }) + } +} + +impl Installer for Symlink { + fn install(&self, to_dir: &std::path::Path) -> Result<()> { + eprintln!("Running {}", self.describe()); + std::fs::create_dir_all(to_dir)?; + + if !self.path.exists() { + return Err(anyhow!("Destination symlink {} doesn't exist", self.path.display())) + } + + let file = to_dir.join(&self.name); + std::os::unix::fs::symlink(&self.path, &file).context(anyhow!("Unable to symlink {} to {}", self.path.display(), file.display())) + } + + fn describe(&self) -> String { + format!("symlink installer for {} v.{}", self.name, self.version) + } +} diff --git a/rozy/test_resource/unittest.ozy.yaml b/rozy/test_resource/unittest.ozy.yaml index 5e426ed..43bc5e5 100644 --- a/rozy/test_resource/unittest.ozy.yaml +++ b/rozy/test_resource/unittest.ozy.yaml @@ -65,3 +65,9 @@ apps: version: 1.10.1 type: single_binary_zip url: some_url_1 + symlink_app: + version: 5.6.7 + type: symlink + path: /nfs/some/symlink_app/{version} + package: pip_package + executable_path: bin/symlink_app