feat: add --submit <part> to cargo solve

This commit is contained in:
Felix Spöttel 2022-12-07 21:37:57 +01:00
parent 0908ad602b
commit 9e8672d9b4
6 changed files with 134 additions and 25 deletions

View file

@ -3,5 +3,8 @@ scaffold = "run --bin scaffold --quiet --release -- "
download = "run --bin download --quiet --release -- "
read = "run --bin read --quiet --release -- "
solve = "run --bin"
solve = "run --bin solve --quiet --release -- "
all = "run"
[env]
AOC_YEAR = "2022"

View file

@ -7,14 +7,12 @@ use std::process;
struct Args {
day: u8,
year: Option<u16>,
}
fn parse_args() -> Result<Args, pico_args::Error> {
let mut args = pico_args::Arguments::from_env();
Ok(Args {
day: args.free_from_str()?,
year: args.opt_value_from_str(["-y", "--year"])?,
})
}
@ -32,7 +30,7 @@ fn main() {
process::exit(1);
}
match aoc_cli::download(args.day, args.year) {
match aoc_cli::download(args.day) {
Ok(cmd_output) => {
if !cmd_output.status.success() {
process::exit(1);

View file

@ -7,14 +7,12 @@ use std::process;
struct Args {
day: u8,
year: Option<u16>,
}
fn parse_args() -> Result<Args, pico_args::Error> {
let mut args = pico_args::Arguments::from_env();
Ok(Args {
day: args.free_from_str()?,
year: args.opt_value_from_str(["-y", "--year"])?,
})
}
@ -32,7 +30,7 @@ fn main() {
process::exit(1);
}
match aoc_cli::read(args.day, args.year) {
match aoc_cli::read(args.day) {
Ok(cmd_output) => {
if !cmd_output.status.success() {
process::exit(1);

View file

@ -18,8 +18,8 @@ pub fn part_two(input: &str) -> Option<u32> {
fn main() {
let input = &advent_of_code::read_file("inputs", DAY);
advent_of_code::solve!(1, part_one, input);
advent_of_code::solve!(2, part_two, input);
advent_of_code::solve!(DAY, 1, part_one, input);
advent_of_code::solve!(DAY, 2, part_two, input);
}
#[cfg(test)]

58
src/bin/solve.rs Normal file
View file

@ -0,0 +1,58 @@
/*
* This file contains template code.
* There is no need to edit this file unless you want to change template functionality.
*/
use std::process::{self, Command, Stdio};
struct Args {
day: u8,
release: bool,
submit: Option<u8>,
}
fn parse_args() -> Result<Args, pico_args::Error> {
let mut args = pico_args::Arguments::from_env();
Ok(Args {
day: args.free_from_str()?,
release: args.contains("--release"),
submit: args.opt_value_from_str("--submit")?,
})
}
fn run_solution(day: u8, release: bool, submit_part: Option<u8>) -> Result<(), std::io::Error> {
let day_padded = format!("{:02}", day);
let mut cmd_args = vec!["run".to_string(), "--bin".to_string(), day_padded];
if release {
cmd_args.push("--release".to_string());
}
if let Some(submit_part) = submit_part {
cmd_args.push("--".to_string());
cmd_args.push("--submit".to_string());
cmd_args.push(submit_part.to_string())
}
let mut cmd = Command::new("cargo")
.args(&cmd_args)
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.spawn()?;
cmd.wait()?;
Ok(())
}
fn main() {
let args = match parse_args() {
Ok(args) => args,
Err(e) => {
eprintln!("Failed to process arguments: {}", e);
process::exit(1);
}
};
run_solution(args.day, args.release, args.submit).unwrap();
}

View file

@ -14,10 +14,42 @@ pub const ANSI_RESET: &str = "\x1b[0m";
#[macro_export]
macro_rules! solve {
($part:expr, $solver:ident, $input:expr) => {{
use advent_of_code::{ANSI_BOLD, ANSI_ITALIC, ANSI_RESET};
($day:expr, $part:expr, $solver:ident, $input:expr) => {{
use advent_of_code::{ANSI_BOLD, ANSI_ITALIC, ANSI_RESET, aoc_cli};
use std::fmt::Display;
use std::time::Instant;
use std::env;
use std::process;
fn submit_if_requested<T: Display>(result: T) {
let args: Vec<String> = env::args().collect();
if args.contains(&"--submit".into()) {
if aoc_cli::check().is_err() {
eprintln!("command \"aoc\" not found or not callable. Try running \"cargo install aoc-cli\" to install it.");
process::exit(1);
}
if args.len() < 3 {
eprintln!("Unexpected command-line input. Format: cargo solve 1 --submit 1");
process::exit(1);
}
let part_index = args.iter().position(|x| x == "--submit").unwrap() + 1;
let part_submit = match args[part_index].parse::<u8>() {
Ok(x) => x,
Err(_) => {
eprintln!("Unexpected command-line input. Format: cargo solve 1 --submit 1");
process::exit(1);
}
};
if part_submit == $part {
println!("Submitting puzzle answer for part {}...", $part);
aoc_cli::submit($day, $part, result).unwrap();
}
}
}
fn print_result<T: Display>(func: impl FnOnce(&str) -> Option<T>, input: &str) {
let timer = Instant::now();
@ -29,6 +61,7 @@ macro_rules! solve {
"{} {}(elapsed: {:.2?}){}",
result, ANSI_ITALIC, elapsed, ANSI_RESET
);
submit_if_requested(result);
}
None => {
println!("not solved.")
@ -127,10 +160,10 @@ mod tests {
pub mod aoc_cli {
use std::{
fmt::Display,
fs::create_dir_all,
process::{Command, Output, Stdio},
};
#[derive(Debug)]
pub enum AocCliError {
CommandNotFound,
CommandNotCallable,
@ -159,17 +192,25 @@ pub mod aoc_cli {
Ok(())
}
pub fn read(day: u8, year: Option<u16>) -> Result<Output, AocCliError> {
// TODO: output local puzzle if present.
let args = build_args("read", &[], day, year);
pub fn read(day: u8) -> Result<Output, AocCliError> {
let puzzle_path = get_puzzle_path(day);
let args = build_args(
"read",
&[
"--description-only".into(),
"--puzzle-file".into(),
puzzle_path,
],
day,
);
call_aoc_cli(&args)
}
pub fn download(day: u8, year: Option<u16>) -> Result<Output, AocCliError> {
pub fn download(day: u8) -> Result<Output, AocCliError> {
let input_path = get_input_path(day);
let puzzle_path = get_puzzle_path(day);
create_dir_all("src/puzzles").map_err(|_| AocCliError::IoError)?;
let args = build_args(
"download",
@ -181,7 +222,6 @@ pub mod aoc_cli {
puzzle_path.to_string(),
],
day,
year,
);
let output = call_aoc_cli(&args)?;
@ -196,6 +236,14 @@ pub mod aoc_cli {
}
}
pub fn submit<T: Display>(day: u8, part: u8, result: T) -> Result<Output, AocCliError> {
// workaround: the argument order is inverted for submit.
let mut args = build_args("submit", &[], day);
args.push(part.to_string());
args.push(result.to_string());
call_aoc_cli(&args)
}
fn get_input_path(day: u8) -> String {
let day_padded = format!("{:02}", day);
format!("src/inputs/{}.txt", day_padded)
@ -206,10 +254,17 @@ pub mod aoc_cli {
format!("src/puzzles/{}.md", day_padded)
}
fn build_args(command: &str, args: &[String], day: u8, year: Option<u16>) -> Vec<String> {
fn get_year() -> Option<u16> {
match std::env::var("AOC_YEAR") {
Ok(x) => x.parse().ok().or(None),
Err(_) => None,
}
}
fn build_args(command: &str, args: &[String], day: u8) -> Vec<String> {
let mut cmd_args = args.to_vec();
if let Some(year) = year {
if let Some(year) = get_year() {
cmd_args.push("--year".into());
cmd_args.push(year.to_string());
}
@ -220,10 +275,7 @@ pub mod aoc_cli {
}
fn call_aoc_cli(args: &[String]) -> Result<Output, AocCliError> {
if cfg!(debug_assertions) {
println!("Calling >aoc with: {}", args.join(" "));
}
println!("Calling >aoc with: {}", args.join(" "));
Command::new("aoc")
.args(args)
.stdout(Stdio::inherit())