Experiment with futures
This commit is contained in:
parent
907fbf95db
commit
2d3e3688fa
44 changed files with 2081 additions and 1242 deletions
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::borrow::Borrow;
|
||||
use std::error::Error;
|
||||
use std::fs::File as FsFile;
|
||||
|
|
@ -44,24 +45,29 @@ impl<_C, C, D, P> Cert<_C, C, D, P> {
|
|||
|
||||
const DAYS_IN_SECONDS: u32 = 24 * 60 * 60;
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<_C: CommandRunner, C: Borrow<_C>, D: AsRef<str>, P: AsRef<Path>> Symbol for Cert<_C, C, D, P> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.cert_path.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let output = self.command_runner.borrow().run_with_args(
|
||||
"openssl",
|
||||
args![
|
||||
"x509",
|
||||
"-in",
|
||||
self.cert_path.as_ref(),
|
||||
"-noout",
|
||||
"-subject",
|
||||
"-checkend",
|
||||
(30 * DAYS_IN_SECONDS).to_string(),
|
||||
],
|
||||
)?;
|
||||
let output = self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_with_args(
|
||||
"openssl",
|
||||
args![
|
||||
"x509",
|
||||
"-in",
|
||||
self.cert_path.as_ref(),
|
||||
"-noout",
|
||||
"-subject",
|
||||
"-checkend",
|
||||
(30 * DAYS_IN_SECONDS).to_string(),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
if output.status.success()
|
||||
&& output.stdout
|
||||
== format!(
|
||||
|
|
@ -83,6 +89,7 @@ impl<_C: CommandRunner, C: Borrow<_C>, D: AsRef<str>, P: AsRef<Path>> Symbol for
|
|||
self.cert_path.as_ref(),
|
||||
],
|
||||
)
|
||||
.await
|
||||
.is_ok(),
|
||||
)
|
||||
} else if output.status.code() == Some(1)
|
||||
|
|
@ -99,18 +106,22 @@ impl<_C: CommandRunner, C: Borrow<_C>, D: AsRef<str>, P: AsRef<Path>> Symbol for
|
|||
}
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
let output = self.command_runner.borrow().get_output(
|
||||
"acme-tiny",
|
||||
args![
|
||||
"--account-key",
|
||||
self.account_key_path.as_ref(),
|
||||
"--csr",
|
||||
self.csr_path.as_ref(),
|
||||
"--acme-dir",
|
||||
self.challenges_path.as_ref(),
|
||||
],
|
||||
)?;
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
let output = self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.get_output(
|
||||
"acme-tiny",
|
||||
args![
|
||||
"--account-key",
|
||||
self.account_key_path.as_ref(),
|
||||
"--csr",
|
||||
self.csr_path.as_ref(),
|
||||
"--acme-dir",
|
||||
self.challenges_path.as_ref(),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
let mut file = FsFile::create(self.cert_path.as_ref())?;
|
||||
file.write_all(&output)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::fs::{metadata, File};
|
||||
use std::io::copy;
|
||||
|
|
@ -22,8 +23,9 @@ impl<S, D, I> Concat<S, D, I> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<S: AsRef<[I]>, D: AsRef<Path>, I: AsRef<Path>> Symbol for Concat<S, D, I> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let target = self.target.as_ref();
|
||||
if !target.exists() {
|
||||
return Ok(false);
|
||||
|
|
@ -37,7 +39,7 @@ impl<S: AsRef<[I]>, D: AsRef<Path>, I: AsRef<Path>> Symbol for Concat<S, D, I> {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
let mut file = File::create(self.target.as_ref())?;
|
||||
for source in self.sources.as_ref() {
|
||||
copy(&mut File::open(source)?, &mut file)?;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::command_runner::{is_success, CommandRunner};
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -19,23 +20,27 @@ impl<'r, U, R> Cron<'r, String, U, R> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<C: AsRef<str>, U: AsRef<str>, R: CommandRunner> Symbol for Cron<'_, C, U, R> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let tab = self
|
||||
.command_runner
|
||||
.get_output("crontab", args!["-l", "-u", self.user.as_ref()])?;
|
||||
.get_output("crontab", args!["-l", "-u", self.user.as_ref()])
|
||||
.await?;
|
||||
Ok(tab == self.content.as_ref().as_bytes())
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
let output = self.command_runner.run_with_args_and_stdin(
|
||||
"crontab",
|
||||
args!["-u", self.user.as_ref(), "-",],
|
||||
self.content.as_ref(),
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
is_success(
|
||||
self
|
||||
.command_runner
|
||||
.run(
|
||||
"crontab",
|
||||
args!["-u", self.user.as_ref(), "-",],
|
||||
self.content.as_ref(),
|
||||
)
|
||||
.await,
|
||||
)?;
|
||||
if !output.status.success() {
|
||||
return Err(String::from_utf8(output.stderr)?.into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
use std::io;
|
||||
|
|
@ -15,8 +16,9 @@ impl<P> Dir<P> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<P: AsRef<Path>> Symbol for Dir<P> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.path.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
|
@ -30,7 +32,7 @@ impl<P: AsRef<Path>> Symbol for Dir<P> {
|
|||
Ok(true)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
fs::create_dir(self.path.as_ref()).map_err(|e| Box::new(e) as Box<dyn Error>)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::fs::File as FsFile;
|
||||
use std::io::{Read, Write};
|
||||
|
|
@ -16,8 +17,9 @@ impl<D, C> File<D, C> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<D: AsRef<Path>, C: AsRef<str>> Symbol for File<D, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.path.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
|
@ -35,7 +37,7 @@ impl<D: AsRef<Path>, C: AsRef<str>> Symbol for File<D, C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
let mut file = FsFile::create(self.path.as_ref())?;
|
||||
file.write_all(self.content.as_ref().as_bytes())?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use crate::async_utils::try_join;
|
||||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::borrow::Borrow;
|
||||
use std::error::Error;
|
||||
use std::ffi::OsStr;
|
||||
|
|
@ -28,47 +30,121 @@ impl<C, _C, P, S, B> Checkout<_C, C, P, S, B> {
|
|||
}
|
||||
|
||||
impl<C: CommandRunner, _C: Borrow<C>, P: AsRef<Path>, S, B> Checkout<C, _C, P, S, B> {
|
||||
fn _run_in_target_repo(&self, args: &[impl AsRef<OsStr>]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let mut new_args = vec![OsStr::new("-C"), self.target.as_ref().as_ref()];
|
||||
async fn run_git(&self, args: &[impl AsRef<OsStr>]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let mut new_args = Vec::with_capacity(args.len() + 2);
|
||||
new_args.extend_from_slice(args!["-C", self.target.as_ref()]);
|
||||
new_args.extend(args.iter().map(AsRef::as_ref));
|
||||
self.command_runner.borrow().get_output("git", &new_args)
|
||||
self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.get_output("git", &new_args)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<C: CommandRunner, _C: Borrow<C>, P: AsRef<Path>, S: AsRef<str>, B: AsRef<str>> Symbol
|
||||
for Checkout<C, _C, P, S, B>
|
||||
{
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.target.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
self._run_in_target_repo(&["fetch", self.source.as_ref(), self.branch.as_ref()])?;
|
||||
// git rev-list resolves tag objects
|
||||
let fetch_head = self._run_in_target_repo(&["rev-list", "-1", "FETCH_HEAD"])?;
|
||||
let head = self._run_in_target_repo(&["rev-list", "-1", "HEAD"])?;
|
||||
let fetch_head_f = async {
|
||||
self
|
||||
.run_git(args!["fetch", self.source, self.branch])
|
||||
.await?;
|
||||
// git rev-list resolves tag objects
|
||||
self.run_git(&["rev-list", "-1", "FETCH_HEAD"]).await
|
||||
};
|
||||
let head_f = self.run_git(&["rev-list", "-1", "HEAD"]);
|
||||
let (fetch_head, head) = try_join!(fetch_head_f, head_f)?;
|
||||
Ok(fetch_head == head)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
if !self.target.as_ref().exists() {
|
||||
return self.command_runner.borrow().run_successfully(
|
||||
"git",
|
||||
args![
|
||||
"clone",
|
||||
"--depth",
|
||||
"1",
|
||||
"-b",
|
||||
self.branch.as_ref(),
|
||||
self.source.as_ref(),
|
||||
self.target.as_ref(),
|
||||
],
|
||||
);
|
||||
self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_successfully(
|
||||
"git",
|
||||
args![
|
||||
"clone",
|
||||
"--depth",
|
||||
"1",
|
||||
"-b",
|
||||
self.branch.as_ref(),
|
||||
self.source.as_ref(),
|
||||
self.target.as_ref(),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
self
|
||||
.run_git(&["fetch", self.source.as_ref(), self.branch.as_ref()])
|
||||
.await?;
|
||||
self.run_git(&["merge", "FETCH_HEAD"]).await?;
|
||||
}
|
||||
self._run_in_target_repo(&["fetch", self.source.as_ref(), self.branch.as_ref()])?;
|
||||
self._run_in_target_repo(&["merge", "FETCH_HEAD"])?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {}
|
||||
mod test {
|
||||
use super::Checkout;
|
||||
use crate::async_utils::run;
|
||||
use crate::async_utils::sleep;
|
||||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::cell::RefCell;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::io::Result as IoResult;
|
||||
use std::os::unix::process::ExitStatusExt;
|
||||
use std::process::{ExitStatus, Output};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
struct DummyCommandRunner {
|
||||
pub args: RefCell<Vec<Vec<OsString>>>,
|
||||
}
|
||||
#[async_trait(?Send)]
|
||||
impl CommandRunner for DummyCommandRunner {
|
||||
async fn run(&self, program: &str, args: &[&OsStr], stdin: &str) -> IoResult<Output> {
|
||||
assert_eq!(program, "git");
|
||||
assert_eq!(stdin, "");
|
||||
sleep(Duration::from_millis(50)).await;
|
||||
self
|
||||
.args
|
||||
.borrow_mut()
|
||||
.push(args.iter().map(|a| a.to_os_string()).collect());
|
||||
Ok(Output {
|
||||
status: ExitStatus::from_raw(0),
|
||||
stdout: vec![],
|
||||
stderr: vec![],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let c = DummyCommandRunner {
|
||||
args: RefCell::new(vec![]),
|
||||
};
|
||||
let checkout: Checkout<DummyCommandRunner, _, _, _, _> =
|
||||
Checkout::new("target", "source", "branch", &c);
|
||||
let start = Instant::now();
|
||||
assert!(run(checkout.target_reached()).unwrap());
|
||||
let end = Instant::now();
|
||||
assert_eq!(
|
||||
c.args.into_inner(),
|
||||
[
|
||||
["-C", "target", "fetch", "source", "branch"],
|
||||
["-C", "target", "rev-list", "-1", "HEAD"],
|
||||
["-C", "target", "rev-list", "-1", "FETCH_HEAD"]
|
||||
]
|
||||
);
|
||||
assert!((end - start).as_millis() >= 100);
|
||||
assert!((end - start).as_millis() < 150);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
mod checkout;
|
||||
//pub mod submodules;
|
||||
pub mod submodules;
|
||||
|
||||
pub use checkout::Checkout;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,20 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
|
||||
|
||||
pub struct GitSubmodules<'a, P: AsRef<Path>, C: CommandRunner> {
|
||||
#[derive(Debug)]
|
||||
pub struct GitSubmodules<'a, P, C> {
|
||||
target: P,
|
||||
command_runner: &'a C,
|
||||
}
|
||||
|
||||
impl<'a, P: AsRef<Path>, C: CommandRunner> GitSubmodules<'a, P, C> {
|
||||
impl<'a, P, C> GitSubmodules<'a, P, C> {
|
||||
pub fn new(target: P, command_runner: &'a C) -> Self {
|
||||
GitSubmodules {
|
||||
Self {
|
||||
target,
|
||||
command_runner,
|
||||
}
|
||||
|
|
@ -27,20 +28,25 @@ impl<P: AsRef<Path>, C: CommandRunner> fmt::Display for GitSubmodules<'_, P, C>
|
|||
}
|
||||
|
||||
impl<P: AsRef<Path>, C: CommandRunner> GitSubmodules<'_, P, C> {
|
||||
fn _run_in_target_repo(&self, args: &[&OsStr]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
async fn _run_in_target_repo(&self, args: &[&OsStr]) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
let mut new_args: Vec<&OsStr> = vec![];
|
||||
new_args.extend_from_slice(args!["-C", self.target.as_ref()]);
|
||||
new_args.extend_from_slice(args);
|
||||
self.command_runner.get_output("git", &new_args)
|
||||
self.command_runner.get_output("git", &new_args).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<P: AsRef<Path>, C: CommandRunner> Symbol for GitSubmodules<'_, P, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.target.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
let output = String::from_utf8(self._run_in_target_repo(args!["submodule", "status"])?)?;
|
||||
let output = String::from_utf8(
|
||||
self
|
||||
._run_in_target_repo(args!["submodule", "status"])
|
||||
.await?,
|
||||
)?;
|
||||
Ok(
|
||||
output
|
||||
.lines()
|
||||
|
|
@ -48,21 +54,12 @@ impl<P: AsRef<Path>, C: CommandRunner> Symbol for GitSubmodules<'_, P, C> {
|
|||
)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self._run_in_target_repo(args!["submodule", "update", "--init"])?;
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
._run_in_target_repo(args!["submodule", "update", "--init"])
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b> {
|
||||
Box::new(SymbolAction::new(runner, self))
|
||||
}
|
||||
|
||||
fn into_action<'b>(self: Box<Self>, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b>
|
||||
where
|
||||
Self: 'b,
|
||||
{
|
||||
Box::new(OwnedSymbolAction::new(runner, *self))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::storage::Storage;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -19,37 +20,45 @@ impl<'a, D, S, C: CommandRunner> Database<'a, D, S, C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
async fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
let b = self
|
||||
.command_runner
|
||||
.get_output("mariadb", args!["--skip-column-names", "-B", "-e", sql])?;
|
||||
.get_output("mariadb", args!["--skip-column-names", "-B", "-e", sql])
|
||||
.await?;
|
||||
Ok(String::from_utf8(b)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<D: AsRef<str>, S: Storage, C: CommandRunner> Symbol for Database<'_, D, S, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Ok(
|
||||
self
|
||||
.run_sql(&format!("SHOW DATABASES LIKE '{}'", self.db_name.as_ref()))?
|
||||
.run_sql(&format!("SHOW DATABASES LIKE '{}'", self.db_name.as_ref()))
|
||||
.await?
|
||||
.trim_end()
|
||||
== self.db_name.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.run_sql(&format!("CREATE DATABASE {}", self.db_name.as_ref()))?;
|
||||
self.command_runner.run_successfully(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"mariadb '{}' < {}",
|
||||
self.db_name.as_ref(),
|
||||
self.seed_file.read_filename()?.to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.run_sql(&format!("CREATE DATABASE {}", self.db_name.as_ref()))
|
||||
.await?;
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"mariadb '{}' < {}",
|
||||
self.db_name.as_ref(),
|
||||
self.seed_file.read_filename()?.to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use std::error::Error;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::command_runner::CommandRunner;
|
||||
use crate::storage::Storage;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Dump<'a, N, C, S> {
|
||||
|
|
@ -21,34 +21,39 @@ impl<'a, N, C: CommandRunner, S> Dump<'a, N, C, S> {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
async fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
let b = self
|
||||
.command_runner
|
||||
.get_output("mariadb", args!["--skip-column-names", "-B", "-e", sql])?;
|
||||
.get_output("mariadb", args!["--skip-column-names", "-B", "-e", sql])
|
||||
.await?;
|
||||
Ok(String::from_utf8(b)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<N: AsRef<str>, C: CommandRunner, S: Storage> Symbol for Dump<'_, N, C, S> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let dump_date = self.storage.recent_date()?;
|
||||
let _modified_date = self.run_sql(&format!("select UNIX_TIMESTAMP(MAX(UPDATE_TIME)) from information_schema.tables WHERE table_schema = '{}'", self.db_name.as_ref()))?;
|
||||
let _modified_date = self.run_sql(&format!("select UNIX_TIMESTAMP(MAX(UPDATE_TIME)) from information_schema.tables WHERE table_schema = '{}'", self.db_name.as_ref())).await?;
|
||||
let modified_date = _modified_date.trim_end();
|
||||
Ok(modified_date != "NULL" && u64::from_str(modified_date)? <= dump_date)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.run_successfully(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"mysqldump '{}' > {}",
|
||||
self.db_name.as_ref(),
|
||||
self.storage.write_filename().to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"mysqldump '{}' > {}",
|
||||
self.db_name.as_ref(),
|
||||
self.storage.write_filename().to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -16,32 +17,37 @@ impl<'a, U: AsRef<str>, C: CommandRunner> User<'a, U, C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
async fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
let b = self
|
||||
.command_runner
|
||||
.get_output("mariadb", args!["--skip-column-names", "-B", "-e", sql])?;
|
||||
.get_output("mariadb", args!["--skip-column-names", "-B", "-e", sql])
|
||||
.await?;
|
||||
Ok(String::from_utf8(b)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<U: AsRef<str>, C: CommandRunner> Symbol for User<'_, U, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Ok(
|
||||
self
|
||||
.run_sql(&format!(
|
||||
"SELECT User FROM mysql.user WHERE User = '{}' AND plugin = 'unix_socket'",
|
||||
self.user_name.as_ref()
|
||||
))?
|
||||
))
|
||||
.await?
|
||||
.trim_end()
|
||||
== self.user_name.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.run_sql(&format!(
|
||||
"GRANT ALL ON {0}.* TO {0} IDENTIFIED VIA unix_socket",
|
||||
self.user_name.as_ref()
|
||||
))?;
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.run_sql(&format!(
|
||||
"GRANT ALL ON {0}.* TO {0} IDENTIFIED VIA unix_socket",
|
||||
self.user_name.as_ref()
|
||||
))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
|
||||
// Symbol
|
||||
#[async_trait(?Send)]
|
||||
pub trait Symbol {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>>;
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>>;
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>>;
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
pub mod acme;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
|
@ -29,37 +30,39 @@ impl<T: AsRef<Path>, C: CommandRunner> fmt::Display for Install<'_, T, C> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<T: AsRef<Path>, C: CommandRunner> Symbol for Install<'_, T, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.target.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
let result = self.command_runner.run_with_args(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!("cd '{}' && npm ls", self.target.as_ref().to_str().unwrap()),
|
||||
],
|
||||
)?;
|
||||
Ok(
|
||||
result.status.success()
|
||||
&& !String::from_utf8(result.stdout)
|
||||
.unwrap()
|
||||
.contains("(empty)"),
|
||||
)
|
||||
let output = self
|
||||
.command_runner
|
||||
.get_output(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!("cd '{}' && npm ls", self.target.as_ref().to_str().unwrap()),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
Ok(!String::from_utf8(output).unwrap().contains("(empty)"))
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.run_successfully(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"cd '{}' && npm install --production --unsafe-perm",
|
||||
self.target.as_ref().to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"cd '{}' && npm install --production --unsafe-perm",
|
||||
self.target.as_ref().to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::borrow::Borrow;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
|
@ -27,10 +28,11 @@ impl<_C, C, P, U> Owner<_C, C, P, U> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, U: AsRef<str>> Symbol
|
||||
for Owner<_C, C, P, U>
|
||||
{
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.path.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
|
@ -39,10 +41,14 @@ impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, U: AsRef<str>> Symbol
|
|||
Ok(actual_uid == target_uid)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.borrow().run_successfully(
|
||||
"chown",
|
||||
args!["-R", self.user_name.as_ref(), self.path.as_ref()],
|
||||
)
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_successfully(
|
||||
"chown",
|
||||
args!["-R", self.user_name.as_ref(), self.path.as_ref()],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PostgreSQLDatabase<'a, N: AsRef<str>, S: AsRef<str>, C: CommandRunner> {
|
||||
name: N,
|
||||
seed_file: S,
|
||||
|
|
@ -18,11 +20,14 @@ impl<'a, N: AsRef<str>, S: AsRef<str>, C: CommandRunner> PostgreSQLDatabase<'a,
|
|||
}
|
||||
}
|
||||
|
||||
fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
let b = self.command_runner.get_output(
|
||||
"su",
|
||||
args!["-", "postgres", "-c", format!("psql -t -c \"{}\"", sql)],
|
||||
)?;
|
||||
async fn run_sql(&self, sql: &str) -> Result<String, Box<dyn Error>> {
|
||||
let b = self
|
||||
.command_runner
|
||||
.get_output(
|
||||
"su",
|
||||
args!["-", "postgres", "-c", format!("psql -t -c \"{}\"", sql)],
|
||||
)
|
||||
.await?;
|
||||
Ok(String::from_utf8(b)?)
|
||||
}
|
||||
}
|
||||
|
|
@ -35,54 +40,65 @@ impl<N: AsRef<str>, S: AsRef<str>, C: CommandRunner> fmt::Display
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<N: AsRef<str>, S: AsRef<str>, C: CommandRunner> Symbol for PostgreSQLDatabase<'_, N, S, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Ok(
|
||||
self
|
||||
.run_sql(&format!(
|
||||
"SELECT datname FROM pg_database WHERE datname LIKE '{}'",
|
||||
self.name.as_ref()
|
||||
))?
|
||||
))
|
||||
.await?
|
||||
.trim()
|
||||
== self.name.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.run_successfully(
|
||||
"su",
|
||||
args![
|
||||
"-",
|
||||
"postgres",
|
||||
"-c",
|
||||
format!("createuser {}", self.name.as_ref())
|
||||
],
|
||||
)?;
|
||||
self.command_runner.run_successfully(
|
||||
"su",
|
||||
args![
|
||||
"-",
|
||||
"postgres",
|
||||
"-c",
|
||||
format!(
|
||||
"createdb -E UTF8 -T template0 -O {} {0}",
|
||||
self.name.as_ref()
|
||||
),
|
||||
],
|
||||
)?;
|
||||
self.command_runner.run_successfully(
|
||||
"su",
|
||||
args![
|
||||
"-",
|
||||
"postgres",
|
||||
"-c",
|
||||
format!(
|
||||
"psql '{}' < {}",
|
||||
self.name.as_ref(),
|
||||
self.seed_file.as_ref()
|
||||
),
|
||||
],
|
||||
)
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"su",
|
||||
args![
|
||||
"-",
|
||||
"postgres",
|
||||
"-c",
|
||||
format!("createuser {}", self.name.as_ref())
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"su",
|
||||
args![
|
||||
"-",
|
||||
"postgres",
|
||||
"-c",
|
||||
format!(
|
||||
"createdb -E UTF8 -T template0 -O {} {0}",
|
||||
self.name.as_ref()
|
||||
),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"su",
|
||||
args![
|
||||
"-",
|
||||
"postgres",
|
||||
"-c",
|
||||
format!(
|
||||
"psql '{}' < {}",
|
||||
self.name.as_ref(),
|
||||
self.seed_file.as_ref()
|
||||
),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::storage::Storage;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::borrow::Borrow;
|
||||
use std::error::Error;
|
||||
use std::fs;
|
||||
|
|
@ -36,10 +37,11 @@ impl<_C, C, P, S> SavedDirectory<_C, C, P, S> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, S: Storage> Symbol
|
||||
for SavedDirectory<_C, C, P, S>
|
||||
{
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let metadata = fs::metadata(self.path.as_ref());
|
||||
// Check if dir exists
|
||||
if let Err(e) = metadata {
|
||||
|
|
@ -57,26 +59,34 @@ impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, S: Storage> Symbol
|
|||
}
|
||||
|
||||
let dump_date = self.storage.recent_date()?;
|
||||
let output = self.command_runner.borrow().get_output(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"find {} -printf '%T@\\n' | sort -r | head -n1 | grep '^[0-9]\\+' -o",
|
||||
self.path.as_ref().to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)?;
|
||||
let output = self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.get_output(
|
||||
"sh",
|
||||
args![
|
||||
"-c",
|
||||
format!(
|
||||
"find {} -printf '%T@\\n' | sort -r | head -n1 | grep '^[0-9]\\+' -o",
|
||||
self.path.as_ref().to_str().unwrap()
|
||||
),
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
let modified_date = u64::from_str(String::from_utf8(output)?.trim_end())?;
|
||||
if if self.dir == StorageDirection::Store {
|
||||
modified_date > dump_date
|
||||
} else {
|
||||
dump_date > modified_date
|
||||
} {
|
||||
let output = self.command_runner.borrow().run_with_args(
|
||||
"diff",
|
||||
args!["-rq", self.storage.read_filename()?, self.path.as_ref()],
|
||||
)?;
|
||||
let output = self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_with_args(
|
||||
"diff",
|
||||
args!["-rq", self.storage.read_filename()?, self.path.as_ref()],
|
||||
)
|
||||
.await?;
|
||||
match output.status.code() {
|
||||
Some(0) => Ok(true),
|
||||
Some(1) => Ok(false),
|
||||
|
|
@ -87,21 +97,30 @@ impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, S: Storage> Symbol
|
|||
}
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
if self.dir == StorageDirection::Load {
|
||||
self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_successfully("rm", args!["-rf", self.path.as_ref()])?;
|
||||
self.command_runner.borrow().run_successfully(
|
||||
"cp",
|
||||
args!["-a", self.storage.read_filename()?, self.path.as_ref()],
|
||||
)
|
||||
.run_successfully("rm", args!["-rf", self.path.as_ref()])
|
||||
.await?;
|
||||
self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_successfully(
|
||||
"cp",
|
||||
args!["-a", self.storage.read_filename()?, self.path.as_ref()],
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
self.command_runner.borrow().run_successfully(
|
||||
"cp",
|
||||
args!["-a", self.path.as_ref(), self.storage.write_filename()],
|
||||
)
|
||||
self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_successfully(
|
||||
"cp",
|
||||
args!["-a", self.path.as_ref(), self.storage.write_filename()],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::borrow::Borrow;
|
||||
use std::error::Error;
|
||||
use std::marker::PhantomData;
|
||||
|
|
@ -21,15 +22,20 @@ impl<_C, C, S> ReloadService<_C, C, S> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<S: AsRef<str>, _C: CommandRunner, C: Borrow<_C>> Symbol for ReloadService<_C, C, S> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.borrow().run_successfully(
|
||||
"systemctl",
|
||||
args!["reload-or-restart", self.service.as_ref()],
|
||||
)
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.borrow()
|
||||
.run_successfully(
|
||||
"systemctl",
|
||||
args!["reload-or-restart", self.service.as_ref()],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use crate::async_utils::sleep;
|
||||
use crate::command_runner::{CommandRunner, SetuidCommandRunner};
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -29,10 +30,10 @@ impl<S: AsRef<Path>, U: AsRef<str>, R: CommandRunner> UserService<'static, S, U,
|
|||
}
|
||||
|
||||
impl<S: AsRef<Path>, U: AsRef<str>, R: CommandRunner> UserService<'_, S, U, R> {
|
||||
fn systemctl_wait_for_dbus(&self, args: &[&OsStr]) -> Result<String, Box<dyn Error>> {
|
||||
async fn systemctl_wait_for_dbus(&self, args: &[&OsStr]) -> Result<String, Box<dyn Error>> {
|
||||
let mut tries = 5;
|
||||
loop {
|
||||
let result = self.command_runner.run_with_args("systemctl", args)?;
|
||||
let result = self.command_runner.run_with_args("systemctl", args).await?;
|
||||
if result.status.success() {
|
||||
return Ok(String::from_utf8(result.stdout)?.trim_end().to_string());
|
||||
} else {
|
||||
|
|
@ -46,28 +47,35 @@ impl<S: AsRef<Path>, U: AsRef<str>, R: CommandRunner> UserService<'_, S, U, R> {
|
|||
if tries == 0 {
|
||||
return Err("Gave up waiting for dbus to appear".to_string().into());
|
||||
}
|
||||
sleep(Duration::from_millis(500));
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
|
||||
fn check_if_service(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn check_if_service(&self) -> Result<bool, Box<dyn Error>> {
|
||||
loop {
|
||||
let active_state = self.systemctl_wait_for_dbus(args![
|
||||
"--user",
|
||||
"show",
|
||||
"--property",
|
||||
"ActiveState",
|
||||
self.service_name,
|
||||
])?;
|
||||
let active_state = self
|
||||
.systemctl_wait_for_dbus(args![
|
||||
"--user",
|
||||
"show",
|
||||
"--property",
|
||||
"ActiveState",
|
||||
self.service_name,
|
||||
])
|
||||
.await?;
|
||||
match active_state.as_ref() {
|
||||
"ActiveState=activating" => sleep(Duration::from_millis(500)),
|
||||
"ActiveState=activating" => sleep(Duration::from_millis(500)).await,
|
||||
"ActiveState=active" => return Ok(true),
|
||||
"ActiveState=failed" => {
|
||||
return Err(
|
||||
String::from_utf8(self.command_runner.get_output(
|
||||
"journalctl",
|
||||
args!["--user", format!("--user-unit={}", self.service_name)],
|
||||
)?)?
|
||||
String::from_utf8(
|
||||
self
|
||||
.command_runner
|
||||
.get_output(
|
||||
"journalctl",
|
||||
args!["--user", format!("--user-unit={}", self.service_name)],
|
||||
)
|
||||
.await?,
|
||||
)?
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
|
|
@ -77,24 +85,29 @@ impl<S: AsRef<Path>, U: AsRef<str>, R: CommandRunner> UserService<'_, S, U, R> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<S: AsRef<Path>, U: AsRef<str>, R: CommandRunner> Symbol for UserService<'_, S, U, R> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
self.check_if_service()
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
self.check_if_service().await
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.systemctl_wait_for_dbus(args!["--user", "enable", self.service_name])?;
|
||||
self.systemctl_wait_for_dbus(args!["--user", "restart", self.service_name])?;
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.systemctl_wait_for_dbus(args!["--user", "enable", self.service_name])
|
||||
.await?;
|
||||
self
|
||||
.systemctl_wait_for_dbus(args!["--user", "restart", self.service_name])
|
||||
.await?;
|
||||
|
||||
loop {
|
||||
if !(self.check_if_service()?) {
|
||||
if !(self.check_if_service().await?) {
|
||||
return Err("Generic error".into());
|
||||
}
|
||||
|
||||
if self.socket_path.as_ref().exists() {
|
||||
return Ok(());
|
||||
}
|
||||
sleep(Duration::from_millis(500));
|
||||
sleep(Duration::from_millis(500)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::path::Path;
|
||||
|
||||
|
|
@ -18,16 +19,18 @@ impl<'a, U, C> UserSession<'a, U, C> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<U: AsRef<str>, C: CommandRunner> Symbol for UserSession<'_, U, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let path = Path::new("/var/lib/systemd/linger").join(self.user_name.as_ref());
|
||||
Ok(path.exists())
|
||||
// Could also do `loginctl show-user ${self.user_name} | grep -F 'Linger=yes`
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully("loginctl", args!["enable-linger", self.user_name.as_ref()])
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::borrow::Borrow;
|
||||
use std::error::Error;
|
||||
use std::path::Path;
|
||||
|
|
@ -23,37 +24,43 @@ impl<C, D, K, P> Csr<C, D, K, P> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<C: CommandRunner, D: Borrow<str>, K: Borrow<Path>, P: Borrow<Path>> Symbol
|
||||
for Csr<C, D, K, P>
|
||||
{
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.csr_path.borrow().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let output = self.command_runner.get_stderr(
|
||||
"openssl",
|
||||
args!["req", "-in", self.csr_path.borrow(), "-noout", "-verify",],
|
||||
)?;
|
||||
let output = self
|
||||
.command_runner
|
||||
.get_stderr(
|
||||
"openssl",
|
||||
args!["req", "-in", self.csr_path.borrow(), "-noout", "-verify",],
|
||||
)
|
||||
.await?;
|
||||
Ok(output == b"verify OK\n")
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.run_successfully(
|
||||
"openssl",
|
||||
args![
|
||||
"req",
|
||||
"-new",
|
||||
"-sha256",
|
||||
"-key",
|
||||
self.key_path.borrow(),
|
||||
"-out",
|
||||
self.csr_path.borrow(),
|
||||
"-subj",
|
||||
format!("/CN={}", self.domain.borrow()),
|
||||
],
|
||||
)?;
|
||||
Ok(())
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"openssl",
|
||||
args![
|
||||
"req",
|
||||
"-new",
|
||||
"-sha256",
|
||||
"-key",
|
||||
self.key_path.borrow(),
|
||||
"-out",
|
||||
self.csr_path.borrow(),
|
||||
"-subj",
|
||||
format!("/CN={}", self.domain.borrow()),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::path::Path;
|
||||
|
||||
|
|
@ -22,37 +23,44 @@ impl<C, P> Key<C, P> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<C: CommandRunner, P: AsRef<Path>> Symbol for Key<C, P> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
if !self.file_path.as_ref().exists() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
let stdout = self.command_runner.get_output(
|
||||
"openssl",
|
||||
args![
|
||||
"rsa",
|
||||
"-in",
|
||||
self.file_path.as_ref(),
|
||||
"-noout",
|
||||
"-check",
|
||||
"-text",
|
||||
],
|
||||
)?;
|
||||
let stdout = self
|
||||
.command_runner
|
||||
.get_output(
|
||||
"openssl",
|
||||
args![
|
||||
"rsa",
|
||||
"-in",
|
||||
self.file_path.as_ref(),
|
||||
"-noout",
|
||||
"-check",
|
||||
"-text",
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
// FIXME check bytes
|
||||
Ok(stdout.ends_with(b"RSA key ok\n"))
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.run_successfully(
|
||||
"openssl",
|
||||
args![
|
||||
"genrsa",
|
||||
"-out",
|
||||
self.file_path.as_ref(),
|
||||
self.get_bytes().to_string(),
|
||||
],
|
||||
)
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"openssl",
|
||||
args![
|
||||
"genrsa",
|
||||
"-out",
|
||||
self.file_path.as_ref(),
|
||||
self.get_bytes().to_string(),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -17,11 +18,13 @@ impl<U, C> User<U, C> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<U: AsRef<str>, C: CommandRunner> Symbol for User<U, C> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let output = self
|
||||
.command_runner
|
||||
.run_with_args("getent", args!["passwd", self.user_name.as_ref()])?;
|
||||
.run_with_args("getent", args!["passwd", self.user_name.as_ref()])
|
||||
.await?;
|
||||
match output.status.code() {
|
||||
Some(2) => Ok(false),
|
||||
Some(0) => Ok(true),
|
||||
|
|
@ -29,21 +32,24 @@ impl<U: AsRef<str>, C: CommandRunner> Symbol for User<U, C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self.command_runner.run_successfully(
|
||||
"adduser",
|
||||
args![
|
||||
// "-m", // Necessary for Fedora, not accepted in Debian
|
||||
"--system",
|
||||
self.user_name.as_ref(),
|
||||
],
|
||||
)?;
|
||||
Ok(())
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"adduser",
|
||||
args![
|
||||
// "-m", // Necessary for Fedora, not accepted in Debian
|
||||
"--system",
|
||||
self.user_name.as_ref(),
|
||||
],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::async_utils::run;
|
||||
use crate::command_runner::StdCommandRunner;
|
||||
use crate::symbols::user::User;
|
||||
use crate::symbols::Symbol;
|
||||
|
|
@ -54,7 +60,7 @@ mod test {
|
|||
user_name: "nonexisting",
|
||||
command_runner: StdCommandRunner,
|
||||
};
|
||||
assert_eq!(symbol.target_reached().unwrap(), false);
|
||||
assert_eq!(run(symbol.target_reached()).unwrap(), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -63,6 +69,6 @@ mod test {
|
|||
user_name: "root",
|
||||
command_runner: StdCommandRunner,
|
||||
};
|
||||
assert_eq!(symbol.target_reached().unwrap(), true);
|
||||
assert_eq!(run(symbol.target_reached()).unwrap(), true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use regex::Regex;
|
||||
use std::error::Error;
|
||||
use std::fs::File as FsFile;
|
||||
|
|
@ -5,9 +8,6 @@ use std::io;
|
|||
use std::io::{BufRead, BufReader};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Plugin<'a, P, N, R> {
|
||||
base: P,
|
||||
|
|
@ -33,8 +33,9 @@ impl<'a, P: AsRef<Path>, N: AsRef<str>, R: CommandRunner> Plugin<'a, P, N, R> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<P: AsRef<Path>, N: AsRef<str>, R: CommandRunner> Symbol for Plugin<'_, P, N, R> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let base_path = self.get_path();
|
||||
if !base_path.exists() {
|
||||
return Ok(false);
|
||||
|
|
@ -65,23 +66,26 @@ impl<P: AsRef<Path>, N: AsRef<str>, R: CommandRunner> Symbol for Plugin<'_, P, N
|
|||
}
|
||||
}
|
||||
}
|
||||
let upstream = self.command_runner.get_output(
|
||||
"curl",
|
||||
args![
|
||||
"--form",
|
||||
format!(
|
||||
r###"plugins={{"plugins":{{"{0}/{0}.php":{{"Version":"{1}", "PluginURI":"{2}"}}}}}}"###,
|
||||
self.name.as_ref(),
|
||||
version,
|
||||
plugin_uri
|
||||
),
|
||||
"https://api.wordpress.org/plugins/update-check/1.1/",
|
||||
],
|
||||
)?;
|
||||
let upstream = self
|
||||
.command_runner
|
||||
.get_output(
|
||||
"curl",
|
||||
args![
|
||||
"--form",
|
||||
format!(
|
||||
r###"plugins={{"plugins":{{"{0}/{0}.php":{{"Version":"{1}", "PluginURI":"{2}"}}}}}}"###,
|
||||
self.name.as_ref(),
|
||||
version,
|
||||
plugin_uri
|
||||
),
|
||||
"https://api.wordpress.org/plugins/update-check/1.1/",
|
||||
],
|
||||
)
|
||||
.await?;
|
||||
Ok(String::from_utf8(upstream)?.contains(r###""plugins":[]"###))
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
let source = format!(
|
||||
"https://downloads.wordpress.org/plugin/{}.zip",
|
||||
self.name.as_ref()
|
||||
|
|
@ -89,13 +93,18 @@ impl<P: AsRef<Path>, N: AsRef<str>, R: CommandRunner> Symbol for Plugin<'_, P, N
|
|||
let zip = format!("/tmp/{}.zip", self.name.as_ref());
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully("curl", args![source, "-o", zip])?;
|
||||
.run_successfully("curl", args![source, "-o", zip])
|
||||
.await?;
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully("rm", args!["-rf", self.get_path()])?;
|
||||
self.command_runner.run_successfully(
|
||||
"unzip",
|
||||
args![zip, "-d", self.base.as_ref().join("wp-content/plugins")],
|
||||
)
|
||||
.run_successfully("rm", args!["-rf", self.get_path()])
|
||||
.await?;
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully(
|
||||
"unzip",
|
||||
args![zip, "-d", self.base.as_ref().join("wp-content/plugins")],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use crate::command_runner::CommandRunner;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use regex::Regex;
|
||||
use std::cmp::max;
|
||||
use std::error::Error;
|
||||
|
|
@ -59,8 +60,9 @@ impl<C: AsRef<str>, D: AsRef<Path>, R: CommandRunner> Translation<'_, C, D, R> {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<C: AsRef<str>, D: AsRef<Path>, R: CommandRunner> Symbol for Translation<'_, C, D, R> {
|
||||
fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
let mut newest = String::new();
|
||||
let match_date = Regex::new("(?m)^\"PO-Revision-Date: (.+)\\+0000\\\\n\"$").unwrap();
|
||||
for (_, target) in self.get_pairs() {
|
||||
|
|
@ -86,14 +88,17 @@ impl<C: AsRef<str>, D: AsRef<Path>, R: CommandRunner> Symbol for Translation<'_,
|
|||
}
|
||||
}
|
||||
}
|
||||
let upstream = self.command_runner.get_output(
|
||||
"curl",
|
||||
args![format!(
|
||||
"https://api.wordpress.org/core/version-check/1.7/?version={}&locale={}",
|
||||
self.version,
|
||||
self.locale.as_ref()
|
||||
)],
|
||||
)?;
|
||||
let upstream = self
|
||||
.command_runner
|
||||
.get_output(
|
||||
"curl",
|
||||
args![format!(
|
||||
"https://api.wordpress.org/core/version-check/1.7/?version={}&locale={}",
|
||||
self.version,
|
||||
self.locale.as_ref()
|
||||
)],
|
||||
)
|
||||
.await?;
|
||||
Ok(String::from_utf8(upstream)?.contains(&format!(
|
||||
r###"language":"{}","version":"{}","updated":"{}"###,
|
||||
self.locale.as_ref(),
|
||||
|
|
@ -102,11 +107,12 @@ impl<C: AsRef<str>, D: AsRef<Path>, R: CommandRunner> Symbol for Translation<'_,
|
|||
)))
|
||||
}
|
||||
|
||||
fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
for (source, target) in self.get_pairs() {
|
||||
self
|
||||
.command_runner
|
||||
.run_successfully("curl", args!["--compressed", "-o", target, source,])?;
|
||||
.run_successfully("curl", args!["--compressed", "-o", target, source,])
|
||||
.await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue