-
Notifications
You must be signed in to change notification settings - Fork 216
/
main.rs
101 lines (86 loc) 路 3.2 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
mod commands;
#[cfg(test)]
mod error_tests;
mod logger;
use migration_core::{api::RpcApi, error::Error as CoreError};
use structopt::StructOpt;
/// When no subcommand is specified, the migration engine will default to starting as a JSON-RPC
/// server over stdio.
#[derive(Debug, StructOpt)]
#[structopt(version = env!("GIT_HASH"))]
struct MigrationEngineCli {
/// Run only a single command, then exit
#[structopt(short = "s", long)]
single_cmd: bool,
/// Path to the datamodel
#[structopt(short = "d", long, name = "FILE")]
datamodel: Option<String>,
#[structopt(subcommand)]
cli_subcommand: Option<SubCommand>,
}
#[derive(Debug, StructOpt)]
enum SubCommand {
/// Doesn't start a server, but allows running specific commands against Prisma.
#[structopt(name = "cli")]
Cli(commands::Cli),
}
impl SubCommand {
#[cfg(test)]
fn unwrap_cli(self) -> commands::Cli {
match self {
SubCommand::Cli(cli) => cli,
}
}
}
#[tokio::main]
async fn main() {
user_facing_errors::set_panic_hook();
logger::init_logger();
let input = MigrationEngineCli::from_args();
match input.cli_subcommand {
None => {
if let Some(datamodel_location) = input.datamodel.as_ref() {
start_engine(datamodel_location, input.single_cmd).await
} else {
panic!("Missing --datamodel");
}
}
Some(SubCommand::Cli(cli_command)) => {
tracing::info!(git_hash = env!("GIT_HASH"), "Starting migration engine CLI");
cli_command.run().await;
}
}
}
async fn start_engine(datamodel_location: &str, single_cmd: bool) -> ! {
use std::io::Read as _;
tracing::info!(git_hash = env!("GIT_HASH"), "Starting migration engine RPC server",);
let mut file = std::fs::File::open(datamodel_location).expect("error opening datamodel file");
let mut datamodel = String::new();
file.read_to_string(&mut datamodel).unwrap();
if single_cmd {
let api = RpcApi::new(&datamodel).await.unwrap();
let response = api.handle().unwrap();
println!("{}", response);
} else {
match RpcApi::new(&datamodel).await {
// Block the thread and handle IO in async until EOF.
Ok(api) => json_rpc_stdio::run(api.io_handler()).await.unwrap(),
Err(err) => {
let (error, exit_code) = match &err {
CoreError::DatamodelError(errors) => {
let error = user_facing_errors::UnknownError {
message: migration_core::api::pretty_print_datamodel_errors(errors, &datamodel)
.expect("rendering error"),
backtrace: Some(format!("{:?}", user_facing_errors::new_backtrace())),
};
(user_facing_errors::Error::from(error), 1)
}
_ => (migration_core::api::render_error(err), 255),
};
serde_json::to_writer(std::io::stdout().lock(), &error).expect("failed to write to stdout");
std::process::exit(exit_code)
}
}
}
std::process::exit(0);
}