use std::{
path::{Path, PathBuf},
process::exit,
time::Instant,
};
use anyhow::Result;
use clap::Parser;
use mongo_task_generator::{
generate_configuration, Dependencies, ExecutionConfiguration, ProjectInfo,
};
use serde::Deserialize;
use tracing::{event, Level};
use tracing_subscriber::fmt::format;
const DEFAULT_EVG_AUTH_FILE: &str = "~/.evergreen.yml";
const DEFAULT_EVG_PROJECT_FILE: &str = "etc/evergreen.yml";
const DEFAULT_RESMOKE_COMMAND: &str = "python buildscripts/resmoke.py";
const DEFAULT_BURN_IN_TESTS_COMMAND: &str = "python buildscripts/burn_in_tests.py";
const DEFAULT_TARGET_DIRECTORY: &str = "generated_resmoke_config";
#[derive(Debug, Deserialize)]
struct EvgExpansions {
pub project: String,
pub revision: String,
pub task_name: String,
pub version_id: String,
}
impl EvgExpansions {
pub fn from_yaml_file(path: &Path) -> Result<Self> {
let contents = std::fs::read_to_string(path)?;
Ok(serde_yaml::from_str(&contents)?)
}
pub fn config_location(&self) -> String {
format!(
"{}/{}/generate_tasks/generated-config-{}.tgz",
self.project, self.revision, self.version_id
)
}
}
#[derive(Parser, Debug)]
struct Args {
#[clap(long, parse(from_os_str), default_value = DEFAULT_EVG_PROJECT_FILE)]
evg_project_file: PathBuf,
#[clap(long, parse(from_os_str))]
expansion_file: PathBuf,
#[clap(long, parse(from_os_str), default_value = DEFAULT_EVG_AUTH_FILE)]
evg_auth_file: PathBuf,
#[clap(long, parse(from_os_str), default_value = DEFAULT_TARGET_DIRECTORY)]
target_directory: PathBuf,
#[clap(long)]
use_task_split_fallback: bool,
#[clap(long, default_value = DEFAULT_RESMOKE_COMMAND)]
resmoke_command: String,
#[clap(long, parse(from_os_str))]
generate_sub_tasks_config: Option<PathBuf>,
#[clap(long)]
burn_in: bool,
#[clap(long, default_value = DEFAULT_BURN_IN_TESTS_COMMAND)]
burn_in_tests_command: String,
}
fn configure_logging() {
let format = format::json();
let subscriber = tracing_subscriber::fmt().event_format(format).finish();
tracing::subscriber::set_global_default(subscriber).unwrap();
}
#[tokio::main]
async fn main() {
let args = Args::parse();
configure_logging();
let gen_sub_tasks_config_file = &args.generate_sub_tasks_config.map(|p| expand_path(&p));
let evg_expansions = EvgExpansions::from_yaml_file(&args.expansion_file)
.expect("Error reading expansions file.");
let project_info = ProjectInfo::new(
&args.evg_project_file,
&evg_expansions.project,
gen_sub_tasks_config_file.as_ref(),
);
let execution_config = ExecutionConfiguration {
project_info: &project_info,
evg_auth_file: &expand_path(&args.evg_auth_file),
use_task_split_fallback: args.use_task_split_fallback,
resmoke_command: &args.resmoke_command,
target_directory: &expand_path(&args.target_directory),
generating_task: &evg_expansions.task_name,
config_location: &evg_expansions.config_location(),
gen_burn_in: args.burn_in,
burn_in_tests_command: &args.burn_in_tests_command,
};
let deps = Dependencies::new(execution_config).unwrap();
let start = Instant::now();
let result = generate_configuration(&deps, &args.target_directory).await;
event!(
Level::INFO,
"generation completed: {duration_secs} seconds",
duration_secs = start.elapsed().as_secs()
);
if let Err(err) = result {
eprintln!("Error encountered during execution: {:?}", err);
exit(1);
}
}
fn expand_path(path: &Path) -> PathBuf {
let path_str = path.to_str().unwrap();
let expanded = shellexpand::full(path_str).unwrap();
PathBuf::from(expanded.to_string())
}