diff --git a/levels/checkers/start-here.sh b/levels/checkers/start-here.sh index 8ee00ae..7b53f17 100644 --- a/levels/checkers/start-here.sh +++ b/levels/checkers/start-here.sh @@ -1,32 +1,32 @@ #!/bin/bash -source ./common.sh +source $(dirname $0)/common.sh read old new ref < /dev/stdin dump_dir=$(dump-commit-to-directory $new) -pushd dump_dir - # Check file existence. - if [ ! -f alice.txt ]; - then reject-solution "Alice is missing! Try again."; - fi +pushd $dump_dir + # Check file existence. + if [ ! -f alice.txt ]; + then reject-solution "Alice is missing! Try again."; + fi - if [ ! -f bob.txt ]; - then reject-solution "Bob is missing! Try again."; - fi + if [ ! -f bob.txt ]; + then reject-solution "Bob is missing! Try again."; + fi popd git fetch --tags --quiet # get all the tags but don't show them to the user # Check how many commits the user needed - should be two (the user commit + merge commit)! commit_amount=$( git log start-here-tag..$new --oneline | wc -l ) if [ $commit_amount -ne 1 ]; - then reject-solution "The files should have been added in a single commit, but I've found ${commit_amount} commits in the log. To reset and try again, delete your local start-here branch, checkout the original start-here branch again and try again."; + then reject-solution "The files should have been added in a single commit, but I've found ${commit_amount} commits in the log. To reset and try again, delete your local start-here branch, checkout the original start-here branch again and try again."; fi # We know that there's only one commit in the changes - otherwise it would have failed before. -number_of_files_changed=$( git diff --stat $old $new | grep "files changed" | awk ' {print $1} ' ) +number_of_files_changed=$( git diff --stat $old $new | grep "files changed" | awk ' {print $1} ' ) if [[ $number_of_files_changed -ne 2 ]] -then bad "More than 2 files were changed! Only add alice.txt and bob.txt. Check out the original branch and try again."; + then reject-solution "More than 2 files were changed! Only add alice.txt and bob.txt. Check out the original branch and try again."; fi diff --git a/levels/game-config.toml b/levels/game-config.toml index 6ade461..0e92a65 100644 --- a/levels/game-config.toml +++ b/levels/game-config.toml @@ -1,18 +1,36 @@ -[levels] -[levels.clone] +[[levels]] title = "clone" branch = "master" - solutionCheckers = [] + solution_checker = "echo No pushing to master. Read the README file; exit 1" flags = [] # ["start-here"], but it's implicit in the readme -[levels.start-here] +[[levels]] title = "start-here" branch = "start-here" - solutionChecker = "checkers/start-here.sh" + solution_checker = "hooks/checkers/start-here.sh" flags = ["merge-1"] -[levels.merge-1] +[[levels]] title = "merge-1" branch = "fizzling-vulture-pedial" - solutionChecker = "checkers/merge-1.sh" + solution_checker = "hooks/checkers/merge-1.sh" flags = ["merge-2", "log-1"] + +[[levels]] + title = "merge-2" + branch = "ironish-quartzic-brahmas" + solution_checker = "hooks/checkers/merge-2.sh" + flags = ["merge-3"] + +[[levels]] + title = "log-1" + branch = "akmite-radicle-garce" + solution_checker = "echo No pushing in this stage. ; exit 1" + flags = ["log-2"] + +[[levels]] + title = "log-2" + branch = "alibies-listwork-homotaxy" + solution_checker = "hooks/checkers/log-2.sh" + flags = ["log-3"] + diff --git a/scripts/generate-pre-receive-hook/.gitignore b/scripts/generate-pre-receive-hook/.gitignore new file mode 100644 index 0000000..1426e40 --- /dev/null +++ b/scripts/generate-pre-receive-hook/.gitignore @@ -0,0 +1,3 @@ +# Script puts files here by default. Let's avoid commiting them if possible +output/ + diff --git a/scripts/generate-pre-receive-hook/Cargo.toml b/scripts/generate-pre-receive-hook/Cargo.toml index 7619790..7e1c9db 100644 --- a/scripts/generate-pre-receive-hook/Cargo.toml +++ b/scripts/generate-pre-receive-hook/Cargo.toml @@ -8,4 +8,9 @@ edition = "2018" [dependencies] structopt = "0.3.13" +serde = { version = "1.0", features = ["derive"] } toml = "0.5" +tinytemplate = "1.0.4" +simple_logger = "1.6.0" +log = "0.4" + diff --git a/scripts/generate-pre-receive-hook/src/main.rs b/scripts/generate-pre-receive-hook/src/main.rs index 4c87075..f2034e1 100644 --- a/scripts/generate-pre-receive-hook/src/main.rs +++ b/scripts/generate-pre-receive-hook/src/main.rs @@ -1,31 +1,110 @@ +use log; +use log::{debug, info}; +use serde::{Deserialize, Serialize}; +use simple_logger; use std::fs; +use std::io::Write; use structopt::StructOpt; +use tinytemplate::TinyTemplate; +use toml; -// Search for a pattern in a file and display the lines that contain it. #[derive(Debug, StructOpt)] +#[structopt(about = "A script to generate the master pre-receive hook file.")] struct Cli { - // The path to the file to read - #[structopt(parse(from_os_str))] + #[structopt(parse(from_os_str), help = "Path to game config file to read")] game_config_path: std::path::PathBuf, + + #[structopt(parse(from_os_str), help = "Path to template file to read")] + template_path: std::path::PathBuf, + + #[structopt( + parse(from_os_str), + default_value = "output/pre-receive", + help = "Path to output file (creates if doesn't exist)" + )] + output_path: std::path::PathBuf, + + #[structopt( + short = "v", + long = "verbose", + help = "Show more information about the actions taken" + )] + verbose: bool, } +#[derive(Debug, Clone, Deserialize, Serialize)] struct Level { title: String, branch: String, - solution_checke: String, + solution_checker: String, flags: Vec, } +#[derive(Debug, Deserialize, Serialize)] struct GameConfig { levels: Vec, } +fn replace_flags_with_branch_names(game_config: &mut GameConfig) { + let levels_info = game_config.levels.clone(); + + for mut level in &mut game_config.levels { + let mut new_flags = Vec::new(); + for flag in &level.flags { + debug!("level {} flag {}", level.title, flag); + let mut levels_iterator = levels_info.iter(); + let found = levels_iterator.find(|&x| &x.title == flag); + match found { + Some(x) => { + debug!("replacing {} with {}", flag, x.branch); + new_flags.push(String::from(&x.branch)); + } + None => { + debug!("flag {} is final", flag); + new_flags.push(flag.to_string()); + } + } + } + level.flags = new_flags; + } +} + fn main() { let args = Cli::from_args(); - println!("Loading script from {:?}", args); - let game_config_file_contents = - fs::read_to_string(args.game_config_path).expect("Couldn't read the config file!"); + if args.verbose { + simple_logger::init_with_level(log::Level::Debug).unwrap(); + } else { + simple_logger::init_with_level(log::Level::Info).unwrap(); + }; + + info!("Reading script from {:?}", args.game_config_path); + let game_config_file_contents = fs::read_to_string(args.game_config_path).unwrap(); + + let mut game_config: GameConfig = toml::from_str(&game_config_file_contents).unwrap(); + debug!("Game config before editing: {:?}\n", game_config); + + replace_flags_with_branch_names(&mut game_config); + + debug!("Game config after editing: {:?}\n", game_config); + + info!("Reading template from {:?}", args.template_path); + let template_file_contents = fs::read_to_string(args.template_path).unwrap(); + + let mut tt = TinyTemplate::new(); + let template_name = "switch_case"; + tt.add_template(template_name, &template_file_contents) + .unwrap(); + let rendered = tt.render(template_name, &game_config).unwrap(); + + debug!("########## RENDERED TEMPLATE ##########"); + debug!("{}\n", rendered); + + let mut output_dir = args.output_path.clone(); + output_dir.pop(); + fs::create_dir_all(&output_dir).expect("Failed to create parent dir"); + let mut output_file = fs::File::create(&args.output_path).expect("Couldn't create file!"); + output_file.write_all(&rendered.as_bytes()).unwrap(); - println!("{}", game_config_file_contents); + info!("Wrote rendered file to {:?}", args.output_path); } diff --git a/scripts/generate-pre-receive-hook/template.tmpl b/scripts/generate-pre-receive-hook/template.tmpl new file mode 100644 index 0000000..64396f3 --- /dev/null +++ b/scripts/generate-pre-receive-hook/template.tmpl @@ -0,0 +1,19 @@ +#!/bin/bash + +read old new ref < /dev/stdin + +branch_name=$(echo $ref | awk 'BEGIN \{ FS = "/" } ; \{ print $NF }') + +print_flags () \{ + if [[ $# -eq 1 ]] + then echo "You won! The flag is "$1 + else + echo "You won! The flags are "$@ + fi +} + +case $branch_name in +{{ for level in levels }}{level.branch}) + echo $old $new $ref | {level.solution_checker} && print_flags{{ for levelflag in level.flags }} {levelflag}{{ endfor }} + ;; +{{ endfor }}esac