Skip to content

Commit

Permalink
Merge pull request #48 from tsirysndr/feat/slackpkg-installer
Browse files Browse the repository at this point in the history
feat: add slackpkg installer
  • Loading branch information
tsirysndr authored Jun 12, 2023
2 parents 54c81ac + 6376cc1 commit 5bfa6aa
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 1 deletion.
11 changes: 10 additions & 1 deletion crates/core/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use anyhow::Error;
use crosup_installers::{
apk::ApkInstaller, apt::AptInstaller, brew::BrewInstaller, curl::CurlInstaller,
dnf::DnfInstaller, emerge::EmergeInstaller, git::GitInstaller, nix::NixInstaller,
pacman::PacmanInstaller, yum::YumInstaller, zypper::ZypperInstaller, Installer,
pacman::PacmanInstaller, slackpkg::SlackpkgInstaller, yum::YumInstaller,
zypper::ZypperInstaller, Installer,
};
use crosup_macros::{
add_vertex, add_vertex_with_condition, convert_generic_installer, downcast_installer,
Expand Down Expand Up @@ -31,6 +32,7 @@ pub struct Vertex {
apk: Option<ApkInstaller>,
pacman: Option<PacmanInstaller>,
emerge: Option<EmergeInstaller>,
slackpkg: Option<SlackpkgInstaller>,
}

impl From<Box<dyn Installer + 'static>> for Vertex {
Expand All @@ -54,6 +56,7 @@ impl From<Box<dyn Installer + 'static>> for Vertex {
apk: downcast_installer!("apk", installer, ApkInstaller),
pacman: downcast_installer!("pacman", installer, PacmanInstaller),
emerge: downcast_installer!("emerge", installer, EmergeInstaller),
slackpkg: downcast_installer!("slackpkg", installer, SlackpkgInstaller),
}
}
}
Expand All @@ -72,6 +75,7 @@ impl Into<Box<dyn Installer>> for Vertex {
"apk" => Box::new(self.apk.unwrap()),
"pacman" => Box::new(self.pacman.unwrap()),
"emerge" => Box::new(self.emerge.unwrap()),
"slackpkg" => Box::new(self.slackpkg.unwrap()),
_ => panic!("Unknown installer: {}", self.name),
}
}
Expand Down Expand Up @@ -129,6 +133,10 @@ pub fn autodetect_installer(config: &mut Configuration) {
convert_generic_installer!(config, generic_install, apk);
"apk"
}
"slackware" => {
convert_generic_installer!(config, generic_install, slackpkg);
"slackpkg"
}
_ => panic!("Unsupported OS: {}", os),
};

Expand Down Expand Up @@ -192,6 +200,7 @@ pub fn build_installer_graph(
add_vertex!(graph, ApkInstaller, config, apk, pkg, session);
add_vertex!(graph, PacmanInstaller, config, pacman, pkg, session);
add_vertex!(graph, EmergeInstaller, config, emerge, pkg, session);
add_vertex!(graph, SlackpkgInstaller, config, slackpkg, pkg, session);
add_vertex_with_condition!(graph, BrewInstaller, config, brew, pkg, session);

setup_dependencies(&mut graph);
Expand Down
1 change: 1 addition & 0 deletions crates/installers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub mod emerge;
pub mod git;
pub mod nix;
pub mod pacman;
pub mod slackpkg;
pub mod yum;
pub mod zypper;

Expand Down
125 changes: 125 additions & 0 deletions crates/installers/src/slackpkg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use anyhow::Error;
use crosup_macros::{check_version, exec_sh_with_output, slackpkg_install};
use crosup_types::slackpkg::Package;
use owo_colors::OwoColorize;
use ssh2::Session;
use std::{any::Any, io::BufRead, process::Stdio};

use super::Installer;

#[derive(Default, Clone)]
pub struct SlackpkgInstaller {
pub name: String,
pub version: String,
pub dependencies: Vec<String>,
pub slackpkg_dependencies: Vec<String>,
pub packages: Option<Vec<String>>,
pub postinstall: Option<String>,
pub version_check: Option<String>,
pub provider: String,
pub session: Option<Session>,
}

impl From<Package> for SlackpkgInstaller {
fn from(pkg: Package) -> Self {
Self {
name: pkg.name,
packages: pkg.packages,
slackpkg_dependencies: pkg.depends_on.unwrap_or(vec![]),
provider: "slackpkg".into(),
version_check: pkg.version_check,
..Default::default()
}
}
}

impl SlackpkgInstaller {
pub fn install_dependencies(&self) -> Result<(), Error> {
if self.slackpkg_dependencies.is_empty() {
return Ok(());
}

println!(
"-> Installing dependencies for {}",
self.name.bright_green()
);
let deps = self.slackpkg_dependencies.join(" ");
slackpkg_install!(deps, self.session.clone());
Ok(())
}

fn postinstall(&self) -> Result<(), Error> {
if let Some(command) = self.postinstall.clone() {
println!(
"-> Running postinstall command:\n{}",
command.bright_green()
);
for cmd in command.split("\n") {
exec_sh_with_output!(cmd, self.session.clone());
}
}
Ok(())
}
}

impl Installer for SlackpkgInstaller {
fn install(&self) -> Result<(), Error> {
if self.is_installed().is_ok() {
if self.is_installed().unwrap() {
println!(
"-> {} is already installed, skipping",
self.name().bright_green()
);
return Ok(());
}
}

self.install_dependencies()?;

if let Some(packages) = self.packages.clone() {
let packages = packages.join(" ");
let command = format!("sudo slackpkg install {}", packages);
println!("-> Running {}", command.bright_green());
slackpkg_install!(packages, self.session.clone());
}

self.postinstall()?;
Ok(())
}

fn is_installed(&self) -> Result<bool, Error> {
if let Some(command) = self.version_check.clone() {
println!(
"-> Checking if {} is already installed",
self.name.bright_green()
);
check_version!(self, command, self.session.clone());
return Ok(true);
}
Ok(false)
}

fn name(&self) -> &str {
&self.name
}

fn version(&self) -> &str {
&self.version
}

fn dependencies(&self) -> Vec<String> {
self.dependencies.clone()
}

fn is_default(&self) -> bool {
true
}

fn provider(&self) -> &str {
&self.provider
}

fn as_any(&self) -> &dyn Any {
self
}
}
30 changes: 30 additions & 0 deletions crates/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,36 @@ macro_rules! emerge_install {
};
}

#[macro_export]
macro_rules! slackpkg_install {
($package:expr, $session:expr) => {
match $session {
Some(session) => {
let command = format!("sudo slackpkg install {}", $package);
crosup_ssh::exec(session.clone(), &command)?;
}
None => {
let mut child = std::process::Command::new("sh")
.arg("-c")
.arg(format!("sudo slackpkg {}", $package))
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()?;
let output = child.stdout.take().unwrap();
let output = std::io::BufReader::new(output);

for line in output.lines() {
println!("{}", line?);
}
let status = child.wait()?;
if !status.success() {
return Err(Error::msg(format!("Failed to install {}", $package)));
}
}
};
};
}

#[macro_export]
macro_rules! exec_sudo {
($command:expr, $session:expr) => {
Expand Down
8 changes: 8 additions & 0 deletions crates/types/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use super::{
install::InstallConfiguration,
nix::{default_nix_install, NixConfiguration},
pacman::PacmanConfiguration,
slackpkg::SlackpkgConfiguration,
yum::YumConfiguration,
zypper::ZypperConfiguration,
};
Expand Down Expand Up @@ -93,6 +94,12 @@ pub struct Configuration {
serialize_with = "hcl::ser::labeled_block"
)]
pub emerge: Option<IndexMap<String, EmergeConfiguration>>,

#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "hcl::ser::labeled_block"
)]
pub slackpkg: Option<IndexMap<String, SlackpkgConfiguration>>,
}

impl Default for Configuration {
Expand All @@ -110,6 +117,7 @@ impl Default for Configuration {
apk: None,
pacman: None,
emerge: None,
slackpkg: None,
}
}
}
34 changes: 34 additions & 0 deletions crates/types/src/install.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};

use crate::slackpkg;

use super::{apk, apt, brew, dnf, emerge, pacman, yum, zypper};

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
Expand Down Expand Up @@ -106,6 +108,12 @@ pub struct Package {
serialize_with = "hcl::ser::block"
)]
pub zypper: Option<zypper::Package>,

#[serde(
skip_serializing_if = "Option::is_none",
serialize_with = "hcl::ser::block"
)]
pub slackpkg: Option<slackpkg::Package>,
}

impl Into<brew::BrewConfiguration> for InstallConfiguration {
Expand Down Expand Up @@ -224,6 +232,20 @@ impl Into<zypper::ZypperConfiguration> for InstallConfiguration {
}
}

impl Into<slackpkg::SlackpkgConfiguration> for InstallConfiguration {
fn into(self) -> slackpkg::SlackpkgConfiguration {
let pkg = self
.pkg
.into_iter()
.map(|(name, pkg)| match pkg.slackpkg {
Some(slackpkg) => (name.clone(), slackpkg),
None => (name.clone(), slackpkg::Package { name, ..pkg.into() }),
})
.collect();
slackpkg::SlackpkgConfiguration { pkg }
}
}

impl Into<apk::Package> for Package {
fn into(self) -> apk::Package {
apk::Package {
Expand Down Expand Up @@ -327,3 +349,15 @@ impl Into<brew::Package> for Package {
}
}
}

impl Into<slackpkg::Package> for Package {
fn into(self) -> slackpkg::Package {
slackpkg::Package {
name: self.name,
packages: self.packages,
depends_on: self.depends_on,
postinstall: self.postinstall,
version_check: self.version_check,
}
}
}
1 change: 1 addition & 0 deletions crates/types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod install;
pub mod inventory;
pub mod nix;
pub mod pacman;
pub mod slackpkg;
pub mod yum;
pub mod zypper;

Expand Down
26 changes: 26 additions & 0 deletions crates/types/src/slackpkg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use indexmap::IndexMap;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct SlackpkgConfiguration {
#[serde(serialize_with = "hcl::ser::labeled_block")]
pub pkg: IndexMap<String, Package>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Package {
#[serde(skip_serializing, skip_deserializing)]
pub name: String,

#[serde(skip_serializing_if = "Option::is_none")]
pub packages: Option<Vec<String>>,

#[serde(skip_serializing_if = "Option::is_none")]
pub depends_on: Option<Vec<String>>,

#[serde(skip_serializing_if = "Option::is_none")]
pub postinstall: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
pub version_check: Option<String>,
}

0 comments on commit 5bfa6aa

Please sign in to comment.