From 141125778455fb1cdfe8c46dc2a935b81304038b Mon Sep 17 00:00:00 2001
From: Ron Williams <ron.williams@englishbluffcg.com>
Date: Wed, 8 Mar 2023 14:18:45 -0800
Subject: [PATCH] add ability to read package = recipe from filesystem config

---
 src/bin/installer.rs  | 28 ++++++++++++++++++++++++++--
 src/config/general.rs |  5 ++++-
 src/config/package.rs | 21 ++++++++++++++++-----
 src/lib.rs            | 17 +++++++++++++----
 4 files changed, 59 insertions(+), 12 deletions(-)

diff --git a/src/bin/installer.rs b/src/bin/installer.rs
index ed73800..f6b729d 100644
--- a/src/bin/installer.rs
+++ b/src/bin/installer.rs
@@ -9,6 +9,8 @@ use std::path::Path;
 
 use arg_parser::ArgParser;
 
+use redox_installer::PackageConfig;
+
 fn main() {
     let stderr = io::stderr();
     let mut stderr = stderr.lock();
@@ -16,10 +18,14 @@ fn main() {
     let mut parser = ArgParser::new(4)
         .add_opt("b", "cookbook")
         .add_opt("c", "config")
+        .add_flag(&["cooking"])
         .add_flag(&["l", "list-packages"])
         .add_flag(&["live"]);
     parser.parse(env::args());
 
+    // Allow filesystem config to specify recipe or package, enabling mixed recipe/binary build
+    let cooking = parser.found("cooking");
+
     let mut config_data = String::new();
     let mut config = if let Some(path) = parser.get_opt("config") {
         match fs::File::open(&path) {
@@ -58,9 +64,27 @@ fn main() {
         ..Default::default()
     });
 
+    // Add command line flags to config, command line takes priority
+    if cooking {
+        config.general.cooking = Some(true);
+    }
+
     if parser.found("list-packages") {
-        for (packagename, _package) in &config.packages {
-            println!("{}", packagename);
+        for (packagename, package) in &config.packages {
+            if config.general.cooking == Some(true) {
+                // Only print the names of packages that are relevant to the cookbook
+                match package {
+                    PackageConfig::Build(rule) if rule == "recipe" => {
+                        println!("{}", packagename);
+                    }
+                    PackageConfig::Build(rule) if rule == "recipe_no_fetch" => {
+                        println!("{}", packagename);
+                    }
+                    _ => {}
+                }
+            } else {
+                println!("{}", packagename);
+            }
         }
     } else {
         let cookbook = if let Some(path) = parser.get_opt("cookbook") {
diff --git a/src/config/general.rs b/src/config/general.rs
index 95704c6..20a591b 100644
--- a/src/config/general.rs
+++ b/src/config/general.rs
@@ -1,4 +1,7 @@
 #[derive(Clone, Debug, Default, Deserialize)]
 pub struct GeneralConfig {
-    pub prompt: bool
+    pub prompt: bool,
+    // Allow filesystem config to select recipe or package
+    #[serde(skip)]
+    pub cooking: Option<bool>,
 }
diff --git a/src/config/package.rs b/src/config/package.rs
index 8bb5e80..f2df773 100644
--- a/src/config/package.rs
+++ b/src/config/package.rs
@@ -1,6 +1,17 @@
-#[derive(Clone, Debug, Default, Deserialize)]
-pub struct PackageConfig {
-    pub version: Option<String>,
-    pub git: Option<String>,
-    pub path: Option<String>,
+#[derive(Clone, Debug, Deserialize)]
+#[serde(untagged)]
+pub enum PackageConfig {
+    Empty,
+    Build(String),
+    Spec {
+        version: Option<String>,
+        git: Option<String>,
+        path: Option<String>,
+    }
+}
+
+impl Default for PackageConfig {
+    fn default() -> Self {
+        Self::Empty
+    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index fad7a62..2d86a93 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -101,12 +101,20 @@ fn install_packages<S: AsRef<str>>(config: &Config, dest: &str, cookbook: Option
             fs::create_dir(&dest_pkg).unwrap();
         }
 
-        for (packagename, _package) in &config.packages {
-            println!("Installing package {}", packagename);
+        for (packagename, package) in &config.packages {
             let pkgar_path = format!("{}/{}/repo/{}/{}.pkgar",
                                      env::current_dir().unwrap().to_string_lossy(),
                                      cookbook.as_ref(), target, packagename);
-            if Path::new(&pkgar_path).exists() {
+            let from_remote = match (config.general.cooking, package) {
+                (Some(true), PackageConfig::Empty) => true,
+                (Some(true), PackageConfig::Spec { version: None, git: None, path: None }) => true,
+                _ => false
+            };
+            if from_remote {
+                println!("Installing package from remote: {}", packagename);
+                repo.fetch(&packagename).unwrap().install(dest).unwrap();
+            } else if Path::new(&pkgar_path).exists() {
+                println!("Installing package from local repo: {}", packagename);
                 let public_path = format!("{}/{}/build/id_ed25519.pub.toml",
                                           env::current_dir().unwrap().to_string_lossy(),
                                           cookbook.as_ref());
@@ -115,6 +123,7 @@ fn install_packages<S: AsRef<str>>(config: &Config, dest: &str, cookbook: Option
                 let head_path = format!("{}/{}.pkgar_head", dest_pkg, packagename);
                 pkgar::split(&public_path, &pkgar_path, &head_path, Option::<&str>::None).unwrap();
             } else {
+                println!("Installing package tar.gz from local repo: {}", packagename);
                 let path = format!("{}/{}/repo/{}/{}.tar.gz",
                                    env::current_dir().unwrap().to_string_lossy(),
                                    cookbook.as_ref(), target, packagename);
@@ -123,7 +132,7 @@ fn install_packages<S: AsRef<str>>(config: &Config, dest: &str, cookbook: Option
         }
     } else {
         for (packagename, _package) in &config.packages {
-            println!("Installing package {}", packagename);
+            println!("Installing package from remote: {}", packagename);
             repo.fetch(&packagename).unwrap().install(dest).unwrap();
         }
     }
-- 
GitLab