Repository: comtrya/comtrya (language: rust)

Issue:
New Package Provider - WinGet



Discussion / hints:

Fix patch:
diff --git a/src/actions/package/providers/mod.rs b/src/actions/package/providers/mod.rs
index d099a49e..cd3285e7 100644
--- a/src/actions/package/providers/mod.rs
+++ b/src/actions/package/providers/mod.rs
@@ -1,8 +1,10 @@
 mod aptitude;
 mod homebrew;
+mod winget;
 
 use self::aptitude::Aptitude;
 use self::homebrew::Homebrew;
+use self::winget::Winget;
 use crate::actions::ActionError;
 use serde::{Deserialize, Serialize};
 
@@ -14,6 +16,9 @@ pub enum PackageProviders {
     Homebrew,
     #[serde(alias = "aptitude", alias = "apt", alias = "apt-get")]
     Aptitude,
+
+    #[serde(alias = "winget")]
+    Winget,
 }
 
 impl PackageProviders {
@@ -21,6 +26,7 @@ impl PackageProviders {
         match self {
             PackageProviders::Homebrew => Box::new(Homebrew {}),
             PackageProviders::Aptitude => Box::new(Aptitude {}),
+            PackageProviders::Winget => Box::new(Winget {}),
         }
     }
 }
@@ -38,8 +44,8 @@ impl Default for PackageProviders {
             // For some reason, the Rust image is showing as this and
             // its Debian based?
             os_info::Type::OracleLinux => PackageProviders::Aptitude,
-
             os_info::Type::Macos => PackageProviders::Homebrew,
+            os_info::Type::Windows => PackageProviders::Winget,
 
             _ => panic!("Sorry, but we don't have a default provider for {} OS. Please be explicit when requesting a package installation with `provider: XYZ`.", info.os_type()),
         }
diff --git a/src/actions/package/providers/winget.rs b/src/actions/package/providers/winget.rs
new file mode 100644
index 00000000..a66d75cf
--- /dev/null
+++ b/src/actions/package/providers/winget.rs
@@ -0,0 +1,87 @@
+use super::PackageProvider;
+use crate::actions::{package::PackageVariant, ActionError};
+use serde::{Deserialize, Serialize};
+use std::process::Command;
+use tracing::{debug, trace, warn};
+use which::which;
+
+#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
+pub struct Winget {}
+
+impl PackageProvider for Winget {
+    fn name(&self) -> &str {
+        "Winget"
+    }
+
+    fn available(&self) -> bool {
+        match which("winget") {
+            Ok(_) => true,
+            Err(_) => {
+                warn!(message = "winget not available");
+                false
+            }
+        }
+    }
+
+    fn bootstrap(&self) -> Result<(), crate::actions::ActionError> {
+        // Not sure if we can automate this atm, we'll require it
+        // be installed upfront for the time being
+        Err(ActionError {
+            message: String::from("Winget is not available. Please install"),
+        })
+    }
+
+    fn has_repository(&self, _package: &PackageVariant) -> bool {
+        true
+    }
+
+    fn add_repository(&self, _package: &PackageVariant) -> Result<(), ActionError> {
+        Ok(())
+    }
+
+    fn query(&self, package: &PackageVariant) -> Vec<String> {
+        // Install all packages, make this smarter soon
+        package.packages()
+    }
+
+    fn install(&self, package: &PackageVariant) -> Result<(), ActionError> {
+        let result = package
+            .packages()
+            .into_iter()
+            .try_fold(vec![], |mut acc, p| {
+                match Command::new("winget")
+                    .args(&["install", "--silent"])
+                    .args(package.extra_args.clone())
+                    .arg(&p)
+                    .output()
+                {
+                    Ok(result) => {
+                        debug!("Installed {}", p.clone());
+
+                        acc.push(p);
+
+                        trace!("{:?}", String::from_utf8(result.stdout).unwrap());
+
+                        Ok(acc)
+                    }
+                    Err(error) => {
+                        debug!("Failed to install {}", p);
+                        trace!("{:?}", error.to_string());
+
+                        Err(ActionError {
+                            message: String::from(format!(
+                                "Failed to install {}, but successfully installed {:?}",
+                                p,
+                                acc.join(",")
+                            )),
+                        })
+                    }
+                }
+            });
+
+        match result {
+            Ok(_) => Ok(()),
+            Err(e) => Err(e),
+        }
+    }
+}


Test patch: