Compare commits
	
		
			2 Commits
		
	
	
		
			d2ef322761
			...
			89ef66a694
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 89ef66a694 | |||
| 7d9e3d63b7 | 
							
								
								
									
										142
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										142
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -11,6 +11,73 @@ dependencies = [
 | 
				
			|||||||
 "memchr",
 | 
					 "memchr",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "autocfg"
 | 
				
			||||||
 | 
					version = "1.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "base64"
 | 
				
			||||||
 | 
					version = "0.13.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "bitflags"
 | 
				
			||||||
 | 
					version = "1.3.2"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "cfg-if"
 | 
				
			||||||
 | 
					version = "1.0.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crossbeam-channel"
 | 
				
			||||||
 | 
					version = "0.5.8"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					 "crossbeam-utils",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crossbeam-deque"
 | 
				
			||||||
 | 
					version = "0.8.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					 "crossbeam-epoch",
 | 
				
			||||||
 | 
					 "crossbeam-utils",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crossbeam-epoch"
 | 
				
			||||||
 | 
					version = "0.9.14"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "autocfg",
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					 "crossbeam-utils",
 | 
				
			||||||
 | 
					 "memoffset",
 | 
				
			||||||
 | 
					 "scopeguard",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "crossbeam-utils"
 | 
				
			||||||
 | 
					version = "0.8.15"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "cfg-if",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "ctor"
 | 
					name = "ctor"
 | 
				
			||||||
version = "0.2.0"
 | 
					version = "0.2.0"
 | 
				
			||||||
@ -39,6 +106,12 @@ dependencies = [
 | 
				
			|||||||
 "shared_child",
 | 
					 "shared_child",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "either"
 | 
				
			||||||
 | 
					version = "1.8.1"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "erased-serde"
 | 
					name = "erased-serde"
 | 
				
			||||||
version = "0.3.25"
 | 
					version = "0.3.25"
 | 
				
			||||||
@ -65,6 +138,15 @@ version = "0.4.1"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 | 
					checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "hermit-abi"
 | 
				
			||||||
 | 
					version = "0.2.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "inventory"
 | 
					name = "inventory"
 | 
				
			||||||
version = "0.3.5"
 | 
					version = "0.3.5"
 | 
				
			||||||
@ -93,6 +175,25 @@ version = "2.5.0"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 | 
					checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "memoffset"
 | 
				
			||||||
 | 
					version = "0.8.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "autocfg",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num_cpus"
 | 
				
			||||||
 | 
					version = "1.15.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "hermit-abi",
 | 
				
			||||||
 | 
					 "libc",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "once_cell"
 | 
					name = "once_cell"
 | 
				
			||||||
version = "1.17.1"
 | 
					version = "1.17.1"
 | 
				
			||||||
@ -127,6 +228,28 @@ dependencies = [
 | 
				
			|||||||
 "proc-macro2",
 | 
					 "proc-macro2",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rayon"
 | 
				
			||||||
 | 
					version = "1.7.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "either",
 | 
				
			||||||
 | 
					 "rayon-core",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "rayon-core"
 | 
				
			||||||
 | 
					version = "1.11.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "crossbeam-channel",
 | 
				
			||||||
 | 
					 "crossbeam-deque",
 | 
				
			||||||
 | 
					 "crossbeam-utils",
 | 
				
			||||||
 | 
					 "num_cpus",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "regex"
 | 
					name = "regex"
 | 
				
			||||||
version = "1.7.3"
 | 
					version = "1.7.3"
 | 
				
			||||||
@ -144,12 +267,25 @@ version = "0.6.29"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 | 
					checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "ron"
 | 
				
			||||||
 | 
					version = "0.8.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "base64",
 | 
				
			||||||
 | 
					 "bitflags",
 | 
				
			||||||
 | 
					 "serde",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "rustible"
 | 
					name = "rustible"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 "duct",
 | 
					 "duct",
 | 
				
			||||||
 | 
					 "rayon",
 | 
				
			||||||
 "regex",
 | 
					 "regex",
 | 
				
			||||||
 | 
					 "ron",
 | 
				
			||||||
 "serde",
 | 
					 "serde",
 | 
				
			||||||
 "serde_json",
 | 
					 "serde_json",
 | 
				
			||||||
 "snafu",
 | 
					 "snafu",
 | 
				
			||||||
@ -162,6 +298,12 @@ version = "1.0.13"
 | 
				
			|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
 | 
					checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "scopeguard"
 | 
				
			||||||
 | 
					version = "1.1.0"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "serde"
 | 
					name = "serde"
 | 
				
			||||||
version = "1.0.160"
 | 
					version = "1.0.160"
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,8 @@ typetag = "0.2"
 | 
				
			|||||||
# Error management
 | 
					# Error management
 | 
				
			||||||
#thiserror = "1"
 | 
					#thiserror = "1"
 | 
				
			||||||
snafu = "0.7"
 | 
					snafu = "0.7"
 | 
				
			||||||
 | 
					ron = "0.8"
 | 
				
			||||||
 | 
					rayon = "1.7"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[lib]
 | 
					[lib]
 | 
				
			||||||
name = "rustible"
 | 
					name = "rustible"
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1,3 @@
 | 
				
			|||||||
WIP ansible-like system for sysadmin in rust
 | 
					WIP ansible-like system for sysadmin in rust
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TODO: finish test.sh for testing things
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										6
									
								
								examples/facts.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								examples/facts.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					use rustible::Facts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    let facts = Facts::new();
 | 
				
			||||||
 | 
					    println!("rustible running system: {}", facts.os.family().as_str());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								examples/hello.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								examples/hello.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					use rustible::modules::{
 | 
				
			||||||
 | 
					    PlaybookRun,
 | 
				
			||||||
 | 
					    package::{PackageModule as Package, PackageState, PackageError},
 | 
				
			||||||
 | 
					    command::{CommandModule as Command, CommandError},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, serde::Serialize)]
 | 
				
			||||||
 | 
					pub enum PlaybookError {
 | 
				
			||||||
 | 
					    Command(CommandError),
 | 
				
			||||||
 | 
					    Package(PackageError),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<CommandError> for PlaybookError {
 | 
				
			||||||
 | 
					    fn from(e: CommandError) -> PlaybookError {
 | 
				
			||||||
 | 
					        PlaybookError::Command(e)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl From<PackageError> for PlaybookError {
 | 
				
			||||||
 | 
					    fn from(e: PackageError) -> PlaybookError {
 | 
				
			||||||
 | 
					        PlaybookError::Package(e)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() -> Result<(), PlaybookError> {
 | 
				
			||||||
 | 
					    let mut playbook = PlaybookRun::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let pkg = Package::new()
 | 
				
			||||||
 | 
					        .name("hello")
 | 
				
			||||||
 | 
					        .state(PackageState::Present)
 | 
				
			||||||
 | 
					        .build();
 | 
				
			||||||
 | 
					    playbook.run(pkg)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let cmd = Command::new()
 | 
				
			||||||
 | 
					        .program("hello")
 | 
				
			||||||
 | 
					        .arg("-g")
 | 
				
			||||||
 | 
					    	.arg("\"Welcome to rustible!\"")
 | 
				
			||||||
 | 
					        .build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let res = playbook.run(cmd)?;
 | 
				
			||||||
 | 
					    println!("STDOUT:\n{}", res.stdout().unwrap());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Ok(())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										88
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,11 +1,28 @@
 | 
				
			|||||||
use rustible::Facts;
 | 
					use ron::value::Value;
 | 
				
			||||||
 | 
					use serde::{Serialize, Deserialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::env::args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use rustible::Facts;
 | 
				
			||||||
use rustible::modules::{
 | 
					use rustible::modules::{
 | 
				
			||||||
    Module, PlaybookRun,
 | 
					    Module, PlaybookRun, ModuleSetup,
 | 
				
			||||||
    package::{PackageModule as Package, PackageState, PackageError},
 | 
					    package::{PackageModule as Package, PackageState, PackageError, PackageArgs},
 | 
				
			||||||
    command::{CommandModule as Command, CommandError},
 | 
					    command::{CommandModule as Command, CommandError, CommandArgs},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct DeclarativePlaybook {
 | 
				
			||||||
 | 
					    modules: Vec<DeclarativeModule>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 | 
				
			||||||
 | 
					pub struct DeclarativeModule {
 | 
				
			||||||
 | 
					    name: String,
 | 
				
			||||||
 | 
					    module: String,
 | 
				
			||||||
 | 
					    args: Value,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug, serde::Serialize)]
 | 
					#[derive(Clone, Debug, serde::Serialize)]
 | 
				
			||||||
pub enum PlaybookError {
 | 
					pub enum PlaybookError {
 | 
				
			||||||
    Command(CommandError),
 | 
					    Command(CommandError),
 | 
				
			||||||
@ -26,48 +43,35 @@ impl From<PackageError> for PlaybookError {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
fn main() -> Result<(), PlaybookError> {
 | 
					fn main() -> Result<(), PlaybookError> {
 | 
				
			||||||
    let facts = Facts::new();
 | 
					    let facts = Facts::new();
 | 
				
			||||||
    println!("Hello, world! Running system {}", facts.os.family().as_str());
 | 
					    
 | 
				
			||||||
 | 
					 | 
				
			||||||
    let mut playbook = PlaybookRun::new();
 | 
					    let mut playbook = PlaybookRun::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let cmd = Command::new().program("echo").args(&vec!("lol".to_string())).build();
 | 
					    let mut cli_args = args();
 | 
				
			||||||
    let res = cmd.run()?;
 | 
					    let test_playbook = cli_args.nth(1).expect("First argument should be playbook.ron");
 | 
				
			||||||
    println!("{}", res.success());
 | 
					    let test_shell = cli_args.nth(0).expect("Second argument should be test.sh");
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    let cmd = Command::new().program("echo").args(&vec!("lol".to_string())).build();
 | 
					 | 
				
			||||||
    playbook.run(cmd)?;
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    let cmd = Command::new()
 | 
					 | 
				
			||||||
        .creates("/tmp/lol")
 | 
					 | 
				
			||||||
        .program("touch")
 | 
					 | 
				
			||||||
        .arg("/tmp/lol")
 | 
					 | 
				
			||||||
        .build();
 | 
					 | 
				
			||||||
    playbook.run(cmd)?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let pkg = Package::new()
 | 
					    let test_playbook_content = std::fs::read_to_string(&test_playbook).unwrap();
 | 
				
			||||||
        .name("hello")
 | 
					 | 
				
			||||||
        .state(PackageState::Present)
 | 
					 | 
				
			||||||
        .build();
 | 
					 | 
				
			||||||
    playbook.run(pkg)?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let pkg = Package::new()
 | 
					    let playbook_ron: DeclarativePlaybook = ron::from_str(&test_playbook_content).unwrap();
 | 
				
			||||||
        .name("hello")
 | 
					 | 
				
			||||||
        .state(PackageState::Absent)
 | 
					 | 
				
			||||||
        .build();
 | 
					 | 
				
			||||||
    playbook.run(pkg)?;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let pkg = Package::new()
 | 
					    for task in playbook_ron.modules {
 | 
				
			||||||
        .name(vec!("hello", "sl"))
 | 
					        println!("{}", task.name);
 | 
				
			||||||
        .state(PackageState::Present)
 | 
					        match task.module.as_str() {
 | 
				
			||||||
        .build();
 | 
					            "command" => {
 | 
				
			||||||
    playbook.run(pkg)?;
 | 
					                let args: CommandArgs = task.args.into_rust().unwrap();
 | 
				
			||||||
 | 
					                let module = args.with_facts(&facts);
 | 
				
			||||||
    let pkg = Package::new()
 | 
					                playbook.run(module)?;
 | 
				
			||||||
        .name(&[ "hello", "sl" ])
 | 
					                //println!("{:?}", module);
 | 
				
			||||||
        .state(PackageState::Absent)
 | 
					            }, "package" => {
 | 
				
			||||||
        .build();
 | 
					                let args: PackageArgs = task.args.into_rust().unwrap();
 | 
				
			||||||
    playbook.run(pkg)?;
 | 
					                let module = args.with_facts(&facts);
 | 
				
			||||||
    playbook.print_json_pretty();
 | 
					                playbook.run(module)?;
 | 
				
			||||||
 | 
					                //println!("{:?}", module);
 | 
				
			||||||
 | 
					            }, _ => {
 | 
				
			||||||
 | 
					                unimplemented!();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(())
 | 
					    Ok(())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -9,11 +9,11 @@ use crate::utils::cmd::Cmd;
 | 
				
			|||||||
pub struct NoCmd;
 | 
					pub struct NoCmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct NoCondition;
 | 
					pub struct NoCondition;
 | 
				
			||||||
#[derive(Clone, Debug, Serialize)]
 | 
					#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
				
			||||||
pub struct CreatesCondition(pub PathBuf);
 | 
					pub struct CreatesCondition(pub PathBuf);
 | 
				
			||||||
#[derive(Clone, Debug, Serialize)]
 | 
					#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
				
			||||||
pub struct RemovesCondition(pub PathBuf);
 | 
					pub struct RemovesCondition(pub PathBuf);
 | 
				
			||||||
#[derive(Clone, Debug, Serialize)]
 | 
					#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
				
			||||||
pub struct BothConditions(pub CreatesCondition, pub RemovesCondition);
 | 
					pub struct BothConditions(pub CreatesCondition, pub RemovesCondition);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Build a [`CommandModule`].
 | 
					/// Build a [`CommandModule`].
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
use super::builder::{NoCondition, CreatesCondition, RemovesCondition, BothConditions};
 | 
					use super::builder::{NoCondition, CreatesCondition, RemovesCondition, BothConditions};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug, Serialize)]
 | 
					#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
				
			||||||
pub enum SomeCondition {
 | 
					pub enum SomeCondition {
 | 
				
			||||||
    #[serde(rename="creates")]
 | 
					    #[serde(rename="creates")]
 | 
				
			||||||
    Creates(CreatesCondition),
 | 
					    Creates(CreatesCondition),
 | 
				
			||||||
 | 
				
			|||||||
@ -12,13 +12,24 @@ use crate::{Module, ModuleSetup, Facts};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/// A copy of the argument passed to the [`CommandBuilder`],
 | 
					/// A copy of the argument passed to the [`CommandBuilder`],
 | 
				
			||||||
/// as returned serialized in the task run output
 | 
					/// as returned serialized in the task run output
 | 
				
			||||||
#[derive(Clone, Debug, Serialize)]
 | 
					#[derive(Clone, Debug, Serialize, Deserialize)]
 | 
				
			||||||
pub struct CommandArgs {
 | 
					pub struct CommandArgs {
 | 
				
			||||||
    #[serde(flatten)]
 | 
					    #[serde(flatten)]
 | 
				
			||||||
    pub args: Cmd,
 | 
					    pub args: Cmd,
 | 
				
			||||||
    pub condition: Option<SomeCondition>,
 | 
					    pub condition: Option<SomeCondition>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ModuleSetup<CommandModule, CommandArgs, CommandStatus, CommandError> for CommandArgs {
 | 
				
			||||||
 | 
					    fn with_facts(self, _facts: &Facts) -> CommandModule {
 | 
				
			||||||
 | 
					        CommandModule {
 | 
				
			||||||
 | 
					            cmd: self.args,
 | 
				
			||||||
 | 
					            condition: self.condition,
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct CommandModule {
 | 
					pub struct CommandModule {
 | 
				
			||||||
    cmd: Cmd,
 | 
					    cmd: Cmd,
 | 
				
			||||||
    condition: Option<SomeCondition>,
 | 
					    condition: Option<SomeCondition>,
 | 
				
			||||||
@ -92,6 +103,20 @@ impl CommandStatus {
 | 
				
			|||||||
            Self::Skipped(_c) => true,
 | 
					            Self::Skipped(_c) => true,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn stdout(&self) -> Option<String> {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Done(ret) => Some(ret.stdout.to_string()),
 | 
				
			||||||
 | 
					            Self::Skipped(_c) => None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn stderr(&self) -> Option<String> {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Done(ret) => Some(ret.stdout.to_string()),
 | 
				
			||||||
 | 
					            Self::Skipped(_c) => None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Return of a Command that was effectively run
 | 
					/// Return of a Command that was effectively run
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
 | 
					use rayon::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::utils::cmd::{Cmd, CmdOutput};
 | 
					use crate::utils::cmd::{Cmd, CmdOutput};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use super::{PackageError, PackageList, PackageManager};
 | 
					use super::{PackageError, PackageList, PackageManager, IntoPackageList};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// This structure is mostly used as an indirection for testing purposes.
 | 
					/// This structure is mostly used as an indirection for testing purposes.
 | 
				
			||||||
/// But you can use it to build your own apt commands.
 | 
					/// But you can use it to build your own apt commands.
 | 
				
			||||||
@ -40,6 +42,14 @@ impl AptCmd {
 | 
				
			|||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct AptManager;
 | 
					pub struct AptManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl AptManager {
 | 
				
			||||||
 | 
					    fn is_installed_list(&self, list: &PackageList) -> Result<bool, PackageError> {
 | 
				
			||||||
 | 
					        let res = Cmd::new("dpkg").arg("-s").args(list.list()).run()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(res.success)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl PackageManager for AptManager {
 | 
					impl PackageManager for AptManager {
 | 
				
			||||||
    fn name(&self) -> &'static str {
 | 
					    fn name(&self) -> &'static str {
 | 
				
			||||||
        "apt"
 | 
					        "apt"
 | 
				
			||||||
@ -54,7 +64,26 @@ impl PackageManager for AptManager {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn is_installed(&self, pkg: &str) -> Result<bool, PackageError> {
 | 
				
			||||||
 | 
					        let res = Cmd::new("dpkg").arg("-s").arg(pkg).run()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(res.success)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn install(&self, list: PackageList) -> Result<(), PackageError> {
 | 
					    fn install(&self, list: PackageList) -> Result<(), PackageError> {
 | 
				
			||||||
 | 
					        // Filter out already installed packages
 | 
				
			||||||
 | 
					         // let list: Vec<String> = list.list().par_iter().filter_map(|pkg| {
 | 
				
			||||||
 | 
					         //     if ! self.is_installed(&pkg).unwrap() {
 | 
				
			||||||
 | 
					         //         Some(pkg.to_string())
 | 
				
			||||||
 | 
					         //     } else {
 | 
				
			||||||
 | 
					         //         None
 | 
				
			||||||
 | 
					         //     }
 | 
				
			||||||
 | 
					         // }).collect();
 | 
				
			||||||
 | 
					        if self.is_installed_list(&list)? {
 | 
				
			||||||
 | 
					            return Ok(());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //let res = AptCmd::install(list.into_package_list()).run()?;
 | 
				
			||||||
        let res = AptCmd::install(list).run()?;
 | 
					        let res = AptCmd::install(list).run()?;
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
        if ! res.success {
 | 
					        if ! res.success {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,11 @@
 | 
				
			|||||||
use serde::Serialize;
 | 
					use serde::{Serialize, Deserialize};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
 | 
					use crate::utils::serde::string_or_seq_string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 | 
				
			||||||
#[serde(transparent)]
 | 
					#[serde(transparent)]
 | 
				
			||||||
pub struct PackageList {
 | 
					pub struct PackageList {
 | 
				
			||||||
 | 
					    #[serde(deserialize_with = "string_or_seq_string")]
 | 
				
			||||||
    pub list: Vec<String>,
 | 
					    pub list: Vec<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
use serde::Serialize;
 | 
					use serde::{Serialize, Deserialize, Deserializer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{Module, ModuleSetup};
 | 
					use crate::{Module, ModuleSetup};
 | 
				
			||||||
use crate::facts::{Facts, os::OsFamily};
 | 
					use crate::facts::{Facts, os::OsFamily};
 | 
				
			||||||
@ -19,12 +19,25 @@ pub use builder::{PackageArgsBuilder, NoManager};
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub type PackageStatus = ();
 | 
					pub type PackageStatus = ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
 | 
					#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 | 
				
			||||||
pub struct PackageArgs {
 | 
					pub struct PackageArgs {
 | 
				
			||||||
    name: PackageList,
 | 
					    name: PackageList,
 | 
				
			||||||
    state: PackageState,
 | 
					    state: PackageState,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ModuleSetup<PackageModule<Box<dyn PackageManager>>, PackageArgs, (), PackageError> for PackageArgs {
 | 
				
			||||||
 | 
					    fn with_facts(self, facts: &Facts) -> PackageModule<Box<dyn PackageManager>> {
 | 
				
			||||||
 | 
					        let manager: Box<dyn PackageManager> = match facts.os.family() {
 | 
				
			||||||
 | 
					            OsFamily::Debian => Box::new(AptManager),
 | 
				
			||||||
 | 
					            OsFamily::Archlinux => Box::new(PacmanManager),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PackageModule {
 | 
				
			||||||
 | 
					            args: self,
 | 
				
			||||||
 | 
					            manager,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
 | 
					#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
 | 
				
			||||||
pub enum PackageState {
 | 
					pub enum PackageState {
 | 
				
			||||||
    Present,
 | 
					    Present,
 | 
				
			||||||
@ -32,6 +45,21 @@ pub enum PackageState {
 | 
				
			|||||||
    Latest,
 | 
					    Latest,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<'de> Deserialize<'de> for PackageState {
 | 
				
			||||||
 | 
					    fn deserialize<D>(de: D) -> Result<Self, D::Error>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        D: Deserializer<'de>,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let variant = String::deserialize(de)?;
 | 
				
			||||||
 | 
					        Ok(match variant.as_str() {
 | 
				
			||||||
 | 
					            "present" => PackageState::Present,
 | 
				
			||||||
 | 
					            "absent" => PackageState::Absent,
 | 
				
			||||||
 | 
					            "latest" => PackageState::Latest,
 | 
				
			||||||
 | 
					            _other => unimplemented!(),
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, PartialEq, Eq)]
 | 
					#[derive(Debug, PartialEq, Eq)]
 | 
				
			||||||
pub struct PackageModule<Manager> {
 | 
					pub struct PackageModule<Manager> {
 | 
				
			||||||
    manager: Manager,
 | 
					    manager: Manager,
 | 
				
			||||||
@ -78,6 +106,12 @@ impl ModuleSetup<PackageModule<Box<dyn PackageManager>>, PackageArgs, (), Packag
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Stupid impl just for tests
 | 
				
			||||||
 | 
					impl ModuleSetup<PackageModule<Box<dyn PackageManager>>, PackageArgs, (), PackageError> for PackageModule<Box<dyn PackageManager>> {
 | 
				
			||||||
 | 
					    fn with_facts(self, _facts: &Facts) -> PackageModule<Box<dyn PackageManager>> {
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl PackageModule<NoManager> {
 | 
					impl PackageModule<NoManager> {
 | 
				
			||||||
    pub fn new() -> PackageArgsBuilder<builder::NoPackage, builder::NoState, builder::NoManager> {
 | 
					    pub fn new() -> PackageArgsBuilder<builder::NoPackage, builder::NoState, builder::NoManager> {
 | 
				
			||||||
@ -100,6 +134,7 @@ impl From<std::io::Error> for PackageError {
 | 
				
			|||||||
pub trait PackageManager: std::fmt::Debug {
 | 
					pub trait PackageManager: std::fmt::Debug {
 | 
				
			||||||
    fn name(&self) -> &'static str;
 | 
					    fn name(&self) -> &'static str;
 | 
				
			||||||
    fn update(&self) -> Result<(), PackageError>;
 | 
					    fn update(&self) -> Result<(), PackageError>;
 | 
				
			||||||
 | 
					    fn is_installed(&self, pkg: &str) -> Result<bool, PackageError>;
 | 
				
			||||||
    fn install(&self, list: PackageList) -> Result<(), PackageError>;
 | 
					    fn install(&self, list: PackageList) -> Result<(), PackageError>;
 | 
				
			||||||
    fn remove(&self, list: PackageList) -> Result<(), PackageError>;
 | 
					    fn remove(&self, list: PackageList) -> Result<(), PackageError>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,12 @@ impl PacmanCmd {
 | 
				
			|||||||
        cmd
 | 
					        cmd
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn is_installed(pkg: &str) -> PacmanCmd {
 | 
				
			||||||
 | 
					        let mut cmd = Self::new();
 | 
				
			||||||
 | 
					        cmd.0 = cmd.0.arg("-Qi").arg(pkg);
 | 
				
			||||||
 | 
					        cmd
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn install(list: PackageList) -> PacmanCmd {
 | 
					    pub fn install(list: PackageList) -> PacmanCmd {
 | 
				
			||||||
        let mut cmd = Self::new();
 | 
					        let mut cmd = Self::new();
 | 
				
			||||||
        cmd.0 = cmd.0.arg("-S").args(list.list());
 | 
					        cmd.0 = cmd.0.arg("-S").args(list.list());
 | 
				
			||||||
@ -56,6 +62,12 @@ impl PackageManager for PacmanManager {
 | 
				
			|||||||
        Ok(())
 | 
					        Ok(())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn is_installed(&self, pkg: &str) -> Result<bool, PackageError> {
 | 
				
			||||||
 | 
					        let res = PacmanCmd::is_installed(pkg).run()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(res.success)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn install(&self, list: PackageList) -> Result<(), PackageError> {
 | 
					    fn install(&self, list: PackageList) -> Result<(), PackageError> {
 | 
				
			||||||
        let res = PacmanCmd::install(list).run()?;
 | 
					        let res = PacmanCmd::install(list).run()?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,13 +3,17 @@ use duct::cmd as duct_cmd;
 | 
				
			|||||||
use std::collections::HashMap;
 | 
					use std::collections::HashMap;
 | 
				
			||||||
use std::path::PathBuf;
 | 
					use std::path::PathBuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize)]
 | 
					#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 | 
				
			||||||
pub struct Cmd {
 | 
					pub struct Cmd {
 | 
				
			||||||
    pub program: String,
 | 
					    program: String,
 | 
				
			||||||
    pub args: Vec<String>,
 | 
					    #[serde(default)]
 | 
				
			||||||
    pub stdin: Option<String>,
 | 
					    args: Vec<String>,
 | 
				
			||||||
    pub chdir: Option<PathBuf>,
 | 
					    #[serde(default)]
 | 
				
			||||||
    pub env: HashMap<String, String>,
 | 
					    stdin: Option<String>,
 | 
				
			||||||
 | 
					    #[serde(default)]
 | 
				
			||||||
 | 
					    chdir: Option<PathBuf>,
 | 
				
			||||||
 | 
					    #[serde(default)]
 | 
				
			||||||
 | 
					    env: HashMap<String, String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Cmd {
 | 
					impl Cmd {
 | 
				
			||||||
 | 
				
			|||||||
@ -1 +1,2 @@
 | 
				
			|||||||
pub mod cmd;
 | 
					pub mod cmd;
 | 
				
			||||||
 | 
					pub mod serde;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										34
									
								
								src/utils/serde.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/utils/serde.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
 | 
				
			||||||
 | 
					use serde::de::value::SeqAccessDeserializer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::fmt;
 | 
				
			||||||
 | 
					use std::marker::PhantomData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// https://stackoverflow.com/questions/41151080/deserialize-a-json-string-or-array-of-strings-into-a-vec
 | 
				
			||||||
 | 
					pub fn string_or_seq_string<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
 | 
				
			||||||
 | 
					    where D: Deserializer<'de>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct StringOrVec(PhantomData<Vec<String>>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    impl<'de> Visitor<'de> for StringOrVec {
 | 
				
			||||||
 | 
					        type Value = Vec<String>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
 | 
				
			||||||
 | 
					            formatter.write_str("string or list of strings")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
 | 
				
			||||||
 | 
					            where E: serde::de::Error
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Ok(vec![value.to_owned()])
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
 | 
				
			||||||
 | 
					            where S: SeqAccess<'de>
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            Deserialize::deserialize(SeqAccessDeserializer::new(visitor))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    deserializer.deserialize_any(StringOrVec(PhantomData))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										91
									
								
								test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										91
									
								
								test.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,91 @@
 | 
				
			|||||||
 | 
					#! /usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					help() {
 | 
				
			||||||
 | 
						echo "test.sh [SERVER]"
 | 
				
			||||||
 | 
						echo "Start the rustible test suite on a certain machine (localhost by default)"
 | 
				
			||||||
 | 
						echo "Requires lxc-ramdisk to be installed: https://kl.netlib.re/gitea/selfhoster1312/lxc-ramdisk"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					build() {
 | 
				
			||||||
 | 
						if cargo build --release 2>&1 >/dev/null; then
 | 
				
			||||||
 | 
							echo "$(pwd)"/target/release/rustible
 | 
				
			||||||
 | 
							ret=0
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							echo "BUILD FAILED."
 | 
				
			||||||
 | 
							ret=1
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return $ret
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					gen_rand_name() {
 | 
				
			||||||
 | 
						echo rustible-"$RANDOM"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					execute_localhost() {
 | 
				
			||||||
 | 
						while true; do
 | 
				
			||||||
 | 
							TEST_NAME="$(gen_rand_name)"
 | 
				
			||||||
 | 
							TEST_PATH=/tmp/"$TEST_NAME"
 | 
				
			||||||
 | 
							if [ ! -e "$TEST_PATH" ]; then
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo "Start test $TEST_NAME"
 | 
				
			||||||
 | 
						cp target/release/rustible "$TEST_PATH"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					execute_on_server() {
 | 
				
			||||||
 | 
						SERVER="$1"
 | 
				
			||||||
 | 
						if ssh "$SERVER" true >/dev/null 2>&1; then
 | 
				
			||||||
 | 
							echo "Connection to "$1" successful"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							echo "ERROR: Connection failed to "$1""
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while true; do
 | 
				
			||||||
 | 
							TEST_NAME="$(gen_rand_name)"
 | 
				
			||||||
 | 
							TEST_PATH=/tmp/"$TEST_NAME"
 | 
				
			||||||
 | 
							if ! ssh "$1" ls "$TEST_PATH" >/dev/null 2>&1; then
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
						  fi
 | 
				
			||||||
 | 
						done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						echo "Start test "$TEST_NAME" ("$TEST_PATH")"
 | 
				
			||||||
 | 
						if ! scp target/release/rustible "$SERVER":"$TEST_PATH"; then
 | 
				
			||||||
 | 
							echo "ERROR: Copy to "$SERVER" failed"
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Move to crate directory
 | 
				
			||||||
 | 
					OLDDIR="$(pwd)"
 | 
				
			||||||
 | 
					cd "$(dirname "$0")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Figure out rustible test binary path
 | 
				
			||||||
 | 
					BIN_PATH="$(build)"
 | 
				
			||||||
 | 
					if [ ! $? -eq 0 ]; then
 | 
				
			||||||
 | 
						# Compilation failed, abort
 | 
				
			||||||
 | 
						echo "$BIN_PATH"
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [[ "$1" = "" ]]; then
 | 
				
			||||||
 | 
						execute_localhost
 | 
				
			||||||
 | 
						ret=$?
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						case "$1" in
 | 
				
			||||||
 | 
							"help" | "-h" | "--help")
 | 
				
			||||||
 | 
								help
 | 
				
			||||||
 | 
								ret=0
 | 
				
			||||||
 | 
								;;
 | 
				
			||||||
 | 
							*)
 | 
				
			||||||
 | 
								execute_on_server "$1"
 | 
				
			||||||
 | 
								ret=$?
 | 
				
			||||||
 | 
								;;
 | 
				
			||||||
 | 
						esac
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					cd "$OLDDIR"
 | 
				
			||||||
 | 
					exit $ret
 | 
				
			||||||
							
								
								
									
										19
									
								
								tests/hello/playbook.ron
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/hello/playbook.ron
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					(
 | 
				
			||||||
 | 
					modules: [
 | 
				
			||||||
 | 
					  (
 | 
				
			||||||
 | 
					    name: "install hello",
 | 
				
			||||||
 | 
					    module: "package",
 | 
				
			||||||
 | 
					    args: (
 | 
				
			||||||
 | 
					      name: [ "hello", "cmake", "firefox-esr", "libreoffice", "make", "gcc", "zstd", "zlib1g", "zlib1g-dev", "zenity", "zenity-common", "yt-dlp", "yelp", "yelp-xsl", "xz-utils", "xserver-xorg", "xtrans-dev" ],
 | 
				
			||||||
 | 
					      state: "present",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  ), (
 | 
				
			||||||
 | 
					    name: "say hello",
 | 
				
			||||||
 | 
					    module: "command",
 | 
				
			||||||
 | 
					    args: (
 | 
				
			||||||
 | 
					      program: "hello",
 | 
				
			||||||
 | 
					      args: [ "-g", "welcome to rustible" ],
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
							
								
								
									
										7
									
								
								tests/hello/test.sh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tests/hello/test.sh
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#! /usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check that the playbook run returned "welcome to rustible"
 | 
				
			||||||
 | 
					echo "$STDOUT" | tail -n 3 | grep -P "\^"Welcome to rustible!\""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check that hello is effectively installed
 | 
				
			||||||
 | 
					hello -g "test" | grep -P "^test$"
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user