diesel_migration_runner/
main.rs

1use std::collections::BTreeMap;
2use std::io::Write;
3
4use camino::Utf8PathBuf;
5use clap::Parser;
6use testcontainers::ImageExt;
7use testcontainers::core::IntoContainerPort;
8use testcontainers::runners::AsyncRunner;
9
10#[derive(clap::Parser)]
11struct Args {
12    #[clap(long, env = "DIESEL_CLI_TOOL")]
13    diesel_cli_tool: Utf8PathBuf,
14
15    #[clap(long, env = "DATABASE_IMAGE_LOAD_TOOL")]
16    database_image_load_tool: Utf8PathBuf,
17
18    #[clap(long, env = "OUTPUT_FILE")]
19    output_file: Utf8PathBuf,
20
21    #[clap(long, env = "RUSTFMT_TOOL")]
22    rustfmt_tool: Utf8PathBuf,
23
24    #[clap(long, env = "RUSTFMT_CONFIG_PATH")]
25    rustfmt_config_path: Utf8PathBuf,
26
27    #[clap(long, env = "SCHEMA_FILE")]
28    schema_file: Utf8PathBuf,
29}
30
31#[tokio::main]
32async fn main() {
33    let args = Args::parse();
34
35    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
36
37    log::info!("running container load tool");
38
39    let output = tokio::process::Command::new(args.database_image_load_tool)
40        .output()
41        .await
42        .expect("failed to run database image load tool");
43
44    if !output.status.success() {
45        std::io::stderr().write_all(&output.stdout).expect("failed to write stdout");
46        std::io::stderr().write_all(&output.stderr).expect("failed to write stderr");
47        panic!("failed to run database image load tool");
48    }
49
50    let container_digest = String::from_utf8(output.stdout).expect("failed to read stdout");
51    let container_digest = container_digest.lines().next().expect("failed to read container digest");
52    let container_digest = container_digest.trim();
53    let (image, tag) = container_digest.split_once(':').expect("failed to read container digest");
54
55    log::info!("starting container: {image}:{tag}");
56
57    let container = testcontainers::GenericImage::new(image, tag)
58        .with_exposed_port(5432.tcp())
59        .with_wait_for(testcontainers::core::WaitFor::message_on_either_std(
60            "database system is ready to accept connections",
61        ))
62        .with_env_var("POSTGRES_PASSWORD", "scuffle")
63        .start()
64        .await
65        .expect("failed to start container");
66
67    let port = container.get_host_port_ipv4(5432).await.expect("failed to get host port");
68    let url = container.get_host().await.expect("failed to get host");
69
70    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
71
72    let db_url = format!("postgres://postgres:scuffle@{url}:{port}/scuffle");
73    log::info!("database url: {db_url}");
74
75    log::info!("applying migrations");
76    let output = tokio::process::Command::new(&args.diesel_cli_tool)
77        .env("DATABASE_URL", &db_url)
78        .arg("database")
79        .arg("reset")
80        .output()
81        .await
82        .expect("failed to run diesel cli tool");
83
84    if !output.status.success() {
85        std::io::stderr().write_all(&output.stdout).expect("failed to write stdout");
86        std::io::stderr().write_all(&output.stderr).expect("failed to write stderr");
87        panic!("failed to run diesel cli tool");
88    }
89
90    let output = tokio::process::Command::new(&args.rustfmt_tool)
91        .arg("--config-path")
92        .arg(&args.rustfmt_config_path)
93        .arg(&args.schema_file)
94        .output()
95        .await
96        .expect("failed to run rustfmt");
97    if !output.status.success() {
98        std::io::stderr().write_all(&output.stdout).expect("failed to write stdout");
99        std::io::stderr().write_all(&output.stderr).expect("failed to write stderr");
100        panic!("failed to run rustfmt");
101    }
102
103    let content = std::fs::read_to_string(&args.schema_file).expect("failed to read schema file");
104    let json =
105        serde_json::to_string(&BTreeMap::from_iter([(args.schema_file, content)])).expect("failed to serialize output");
106
107    std::fs::write(args.output_file, json).expect("failed to write output file");
108}