cinderella

[unmaintained] simple CI engine
Log | Files | Refs | README | LICENSE

commit ccd06709150b08234b4d77d24fc402599b6e6a8c
parent b4b4c67b1766a18b72b35af0d94dbc50e31fc4e8
Author: Stefan Koch <programming@stefan-koch.name>
Date:   Sun, 15 Sep 2019 15:25:00 +0200

allow to pass the branch to be checked out and built

Diffstat:
MCargo.lock | 16++++++++++++++++
MCargo.toml | 1+
Msrc/lib.rs | 46+++++++++++++++++++++++++++++++++-------------
Msrc/main.rs | 33+++++++++++++++++++++++++++++----
Msrc/pipeline.rs | 3++-
Msrc/vcs.rs | 40+++++++++++++++++++++++++++++++++-------
6 files changed, 114 insertions(+), 25 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -33,12 +33,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "cinderella" version = "0.1.0" dependencies = [ + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "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]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] name = "getrandom" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -251,6 +260,11 @@ dependencies = [ ] [[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "url" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -276,6 +290,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" "checksum git2 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "327d698f86a7ebdfeb86a4238ccdb004828939d3a3555b6ead679541d14e36c0" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" @@ -302,6 +317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75b414f6c464c879d7f9babf951f23bc3743fb7313c081b2e6ca719067ea9d61" "checksum vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "33dd455d0f96e90a75803cfeb7f948768c08d70a6de9a8d2362461935698bf95" "checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" diff --git a/Cargo.toml b/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Stefan Koch <programming@stefan-koch.name>"] edition = "2018" [dependencies] +getopts = "0.2" git2 = { version = "0.10.0", features = ["vendored-openssl"] } rand = "0.7.0" toml = { version = "0.5", features = ["preserve_order"] } diff --git a/src/lib.rs b/src/lib.rs @@ -9,35 +9,55 @@ mod pipeline; mod execution; use crate::vcs::CodeSource; +use crate::vcs::WorkingCopy; -fn random_dir() -> String { - rand::thread_rng() +pub struct RepoPointer { + pub repo_url: String, + pub branch: Option<String>, +} + +fn random_dir(base_path: &str) -> PathBuf { + let mut tempdir = PathBuf::from(base_path); + + let random_dirname = rand::thread_rng() .sample_iter(&Alphanumeric) .take(10) - .collect::<String>() + .collect::<String>(); + tempdir.push(random_dirname); + + tempdir } -pub fn run(repo_url: &str) { - let repo = vcs::Git { - src: String::from(repo_url), +fn cinderella_file(folder: &PathBuf) -> PathBuf { + let mut cinderella_file = folder.clone(); + cinderella_file.push(".cinderella.toml"); + + cinderella_file +} + +pub fn run(repo_ptr: &RepoPointer) { + let repo = vcs::GitSource { + src: String::from(&repo_ptr.repo_url), }; // generate a temp unique work dir - let mut tempdir = PathBuf::from("/tmp/cinderella"); - tempdir.push(random_dir()); - + let tempdir = random_dir("/tmp/cinderella"); let workdir = repo.fetch(&tempdir).expect("could not clone repo"); println!("Workdir is at {:?}", workdir.path); + // checkout the branch if a branch was provided + if let Some(branch) = &repo_ptr.branch { + println!("Switching to branch {}", branch); + workdir.checkout_branch(&branch); + } + // Switch to the exported work dir so that all commands // are executed there assert!(env::set_current_dir(&workdir.path).is_ok()); - let mut cinderella_file = workdir.path.clone(); - cinderella_file.push(".cinderella.toml"); - - if let Some(pipelines) = pipeline::load_pipeline(".cinderella.toml") { + let cinderella_file = cinderella_file(&workdir.path); + if let Some(pipelines) = pipeline::load_pipeline(&cinderella_file) { execution::execute(&pipelines); } else { println!("No Cinderella configuration found"); diff --git a/src/main.rs b/src/main.rs @@ -1,11 +1,36 @@ use std::env; +use getopts::Options; +use cinderella::RepoPointer; + +fn print_usage(program: &str, opts: Options) { + let brief = format!("Usage: {} REPO_URL [options]", program); + print!("{}", opts.usage(&brief)); +} + fn main() { let args: Vec<String> = env::args().collect(); + let program = args[0].clone(); + + let mut opts = Options::new(); + opts.optopt("b", "branch", "set the branch to checkout", "BRANCH"); - if args.len() > 1 { - cinderella::run(&args[1]) + let matches = match opts.parse(&args[1..]) { + Ok(m) => { m }, + Err(f) => { panic!(f.to_string()) }, + }; + + let repository_url = if !matches.free.is_empty() { + matches.free[0].clone() } else { - println!("Please specify the URL to a git repository"); - } + print_usage(&program, opts); + return; + }; + + let repo = RepoPointer { + repo_url: repository_url, + branch: matches.opt_str("b"), + }; + + cinderella::run(&repo) } diff --git a/src/pipeline.rs b/src/pipeline.rs @@ -1,4 +1,5 @@ use std::fs; +use std::path::PathBuf; use toml::Value; #[derive(Debug)] @@ -7,7 +8,7 @@ pub struct Pipeline { pub commands: Vec<String>, } -pub fn load_pipeline(path: &str) -> Option<Vec<Pipeline>> { +pub fn load_pipeline(path: &PathBuf) -> Option<Vec<Pipeline>> { if let Ok(contents) = fs::read_to_string(path) { let data = contents.parse::<Value>().unwrap(); diff --git a/src/vcs.rs b/src/vcs.rs @@ -5,30 +5,56 @@ use std::path::{Path, PathBuf}; use git2::Repository; pub trait CodeSource { - fn fetch(&self, target: &Path) -> Result<WorkDir, Box<dyn Error>>; + // TODO: Returned working copy here should be dynamic + fn fetch(&self, target: &Path) -> Result<GitWorkingCopy, Box<dyn Error>>; } -pub struct Git { +pub trait WorkingCopy { + fn checkout_branch(&self, branch: &str); +} + +pub struct GitSource { pub src: String, } -pub struct WorkDir { +pub struct GitWorkingCopy { pub path: PathBuf, + repo: Repository, } -impl CodeSource for Git { - fn fetch(&self, target: &Path) -> Result<WorkDir, Box<dyn Error>> { +impl CodeSource for GitSource { + fn fetch(&self, target: &Path) -> Result<GitWorkingCopy, Box<dyn Error>> { let repo = Repository::clone(&self.src, target)?; + let path = repo.workdir() .expect("Newly cloned repo is expected to have a workdir"); - Ok(WorkDir { + Ok(GitWorkingCopy { path: path.to_path_buf(), + repo: repo, }) } } -impl Drop for WorkDir { +impl WorkingCopy for GitWorkingCopy { + fn checkout_branch(&self, branch_name: &str) { + let revname = format!("refs/remotes/origin/{}", branch_name); + self.checkout_rev(&revname); + } +} + +impl GitWorkingCopy { + fn checkout_rev(&self, rev: &str) { + let obj = self.repo.revparse_single(rev).unwrap(); + + self.repo.checkout_tree( + &obj, + None + ); + } +} + +impl Drop for GitWorkingCopy { fn drop(&mut self) { // TODO: Only write this error to a log file, but do not panic fs::remove_dir_all(&self.path)