commit e69e4526aae66ea89f607fa53e3f7fadbf5d6ee5
parent ca020108f463f1b847b0b27f4cb50f0578da07be
Author: Stefan Koch <programming@stefan-koch.name>
Date: Sat, 14 Sep 2019 17:11:59 +0200
implement execution of TOML configuration
Diffstat:
7 files changed, 167 insertions(+), 60 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -33,6 +33,7 @@ version = "0.1.0"
dependencies = [
"git2 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -117,6 +118,11 @@ dependencies = [
]
[[package]]
+name = "linked-hash-map"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -199,11 +205,25 @@ dependencies = [
]
[[package]]
+name = "serde"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "smallvec"
version = "0.6.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "toml"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -253,6 +273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum libgit2-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2078aec6f4b16d1b89f6a72e4f6eb1e75ffa85312023291e89c6d3087bc8fb"
"checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
+"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
@@ -264,7 +285,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
+"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
"checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61"
diff --git a/Cargo.toml b/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2018"
[dependencies]
git2 = "0.10.0"
rand = "0.7.0"
+toml = { version = "0.5", features = ["preserve_order"] }
diff --git a/src/execution.rs b/src/execution.rs
@@ -0,0 +1,27 @@
+use std::process::Command;
+
+use crate::pipeline;
+
+pub fn execute(pipelines: &Vec<pipeline::Pipeline>) {
+ for pipeline in pipelines {
+ execute_pipeline(pipeline);
+ }
+}
+
+pub fn execute_pipeline(pipeline: &pipeline::Pipeline) {
+ println!("Executing Pipeline \"{}\"", pipeline.name);
+
+ for cmd in &pipeline.commands {
+ // TODO: Successful argument parsing needs a lot more details,
+ // e.g. for quoted arguments like myprogram "argument 1"
+ // but for a first shot this works
+ let parts: Vec<&str> = cmd.split(" ").collect();
+
+ let status = Command::new(parts[0])
+ .args(&parts[1..])
+ .status()
+ .expect(&format!("failed to run {}", cmd));
+
+ assert!(status.success());
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
@@ -0,0 +1,40 @@
+use std::path::PathBuf;
+
+use rand::Rng;
+use rand::distributions::Alphanumeric;
+
+mod vcs;
+mod pipeline;
+mod execution;
+
+use crate::vcs::CodeSource;
+
+fn random_dir() -> String {
+ rand::thread_rng()
+ .sample_iter(&Alphanumeric)
+ .take(10)
+ .collect::<String>()
+}
+
+pub fn run(repo_url: &str) {
+ let repo = vcs::Git {
+ src: String::from(repo_url),
+ };
+
+ // generate a temp unique work dir
+ let mut tempdir = PathBuf::from("/tmp/cinderella");
+ tempdir.push(random_dir());
+
+ let workdir = repo.fetch(&tempdir).expect("could not clone repo");
+
+ println!("Workdir is at {:?}", workdir.path);
+
+ let mut cinderella_file = workdir.path.clone();
+ cinderella_file.push(".cinderella.toml");
+
+ if let Some(pipelines) = pipeline::load_pipeline(".cinderella.toml") {
+ execution::execute(&pipelines);
+ } else {
+ println!("No Cinderella configuration found");
+ }
+}
diff --git a/src/main.rs b/src/main.rs
@@ -1,62 +1,4 @@
-use std::error::Error;
-use std::fs;
-use std::path::{Path, PathBuf};
-use git2::Repository;
-
-use rand::Rng;
-use rand::distributions::Alphanumeric;
-
-// TODO: Move this to a sourcecontrol/git module later
-trait CodeSource {
- fn fetch(&self, target: &Path) -> Result<WorkDir, Box<Error>>;
-}
-
-struct Git {
- src: String,
-}
-
-struct WorkDir {
- path: PathBuf,
-}
-
-impl CodeSource for Git {
- fn fetch(&self, target: &Path) -> Result<WorkDir, Box<Error>> {
- let repo = Repository::clone(&self.src, target)?;
- let path = repo.workdir()
- .expect("Newly cloned repo is expected to have a workdir");
-
- Ok(WorkDir {
- path: path.to_path_buf(),
- })
- }
-}
-
-impl Drop for WorkDir {
- fn drop(&mut self) {
- // TODO: Only write this error to a log file, but do not panic
- fs::remove_dir_all(&self.path)
- .expect("Could not delete work dir");
- }
-}
-
-fn random_dir() -> String {
- rand::thread_rng()
- .sample_iter(&Alphanumeric)
- .take(10)
- .collect::<String>()
-}
-
fn main() {
- println!("Hello, Cinderella!");
-
- let repo = Git {
- src: String::from("https://github.com/aufziehvogel/CInderella.git"),
- };
-
- // generate a temp unique work dir
- let mut tempdir = PathBuf::from("/tmp/cinderella");
- tempdir.push(random_dir());
-
- let workdir = repo.fetch(&tempdir).expect("could not clone repo");
- println!("Workdir is at {:?}", workdir.path);
+ // TODO: Entrypoint must be flexible
+ cinderella::run("https://github.com/aufziehvogel/CInderella.git")
}
diff --git a/src/pipeline.rs b/src/pipeline.rs
@@ -0,0 +1,37 @@
+use std::fs;
+use toml::Value;
+
+#[derive(Debug)]
+pub struct Pipeline {
+ pub name: String,
+ pub commands: Vec<String>,
+}
+
+pub fn load_pipeline(path: &str) -> Option<Vec<Pipeline>> {
+ if let Ok(contents) = fs::read_to_string(path) {
+ let data = contents.parse::<Value>().unwrap();
+
+ let res: Vec<Pipeline> = data.as_table().unwrap().iter()
+ .filter_map(|(key, value)| {
+ if value.is_table() {
+ // TODO: Better handle unwrap here and return error when
+ // file is invalid
+ Some(Pipeline {
+ name: key.to_string(),
+ commands: value["commands"].as_array().unwrap().iter()
+ .map(|cmd| String::from(cmd.as_str().unwrap()))
+ .collect(),
+ })
+ } else {
+ None
+ }
+ }).collect();
+
+ Some(res)
+ } else {
+ // TODO: Should we differentiate more? Like:
+ // - file does not exist: None
+ // - file does exist, but cannot be read: Error
+ None
+ }
+}
diff --git a/src/vcs.rs b/src/vcs.rs
@@ -0,0 +1,37 @@
+use std::error::Error;
+use std::fs;
+use std::path::{Path, PathBuf};
+
+use git2::Repository;
+
+pub trait CodeSource {
+ fn fetch(&self, target: &Path) -> Result<WorkDir, Box<Error>>;
+}
+
+pub struct Git {
+ pub src: String,
+}
+
+pub struct WorkDir {
+ pub path: PathBuf,
+}
+
+impl CodeSource for Git {
+ fn fetch(&self, target: &Path) -> Result<WorkDir, Box<Error>> {
+ let repo = Repository::clone(&self.src, target)?;
+ let path = repo.workdir()
+ .expect("Newly cloned repo is expected to have a workdir");
+
+ Ok(WorkDir {
+ path: path.to_path_buf(),
+ })
+ }
+}
+
+impl Drop for WorkDir {
+ fn drop(&mut self) {
+ // TODO: Only write this error to a log file, but do not panic
+ fs::remove_dir_all(&self.path)
+ .expect("Could not delete work dir");
+ }
+}