1- use std:: path:: PathBuf ;
1+ use miette:: Diagnostic ;
2+ use std:: { fs, path:: PathBuf } ;
3+ use thiserror:: Error as ThisError ;
24
35use clap:: { Parser , Subcommand } ;
46
5- use crate :: { conn, container, error:: Error , generate_live, generate_managed, CodegenSettings } ;
7+ use crate :: {
8+ config:: Config , conn, container, error:: Error , generate_live, generate_managed, CodegenSettings ,
9+ } ;
610
711/// Command line interface to interact with Cornucopia SQL.
812#[ derive( Parser , Debug ) ]
@@ -28,6 +32,13 @@ struct Args {
2832 /// Derive serde's `Serialize` trait for generated types.
2933 #[ clap( long) ]
3034 serialize : bool ,
35+ /// The location of the configuration file.
36+ #[ clap( short, long, default_value = default_config_path( ) ) ]
37+ config : PathBuf ,
38+ }
39+
40+ const fn default_config_path ( ) -> & ' static str {
41+ "cornucopia.toml"
3142}
3243
3344#[ derive( Debug , Subcommand ) ]
@@ -44,8 +55,26 @@ enum Action {
4455 } ,
4556}
4657
58+ /// Enumeration of the errors reported by the CLI.
59+ #[ derive( ThisError , Debug , Diagnostic ) ]
60+ pub enum CliError {
61+ /// An error occurred while loading the configuration file.
62+ #[ error( "Could not load config `{path}`: ({err})" ) ]
63+ MissingConfig { path : String , err : std:: io:: Error } ,
64+ /// An error occurred while parsing the configuration file.
65+ #[ error( "Could not parse config `{path}`: ({err})" ) ]
66+ ConfigContents {
67+ path : String ,
68+ err : Box < dyn std:: error:: Error + Send + Sync > ,
69+ } ,
70+ /// An error occurred while running the CLI.
71+ #[ error( transparent) ]
72+ #[ diagnostic( transparent) ]
73+ Internal ( #[ from] Error ) ,
74+ }
75+
4776// Main entrypoint of the CLI. Parses the args and calls the appropriate routines.
48- pub fn run ( ) -> Result < ( ) , Error > {
77+ pub fn run ( ) -> Result < ( ) , CliError > {
4978 let Args {
5079 podman,
5180 queries_path,
@@ -54,17 +83,40 @@ pub fn run() -> Result<(), Error> {
5483 sync,
5584 r#async,
5685 serialize,
86+ config,
5787 } = Args :: parse ( ) ;
5888
89+ let config = match fs:: read_to_string ( config. as_path ( ) ) {
90+ Ok ( contents) => match toml:: from_str ( & contents) {
91+ Ok ( config) => config,
92+ Err ( err) => {
93+ return Err ( CliError :: ConfigContents {
94+ path : config. to_string_lossy ( ) . into_owned ( ) ,
95+ err : err. into ( ) ,
96+ } ) ;
97+ }
98+ } ,
99+ Err ( err) => {
100+ if config. as_path ( ) . as_os_str ( ) != default_config_path ( ) {
101+ return Err ( CliError :: MissingConfig {
102+ path : config. to_string_lossy ( ) . into_owned ( ) ,
103+ err,
104+ } ) ;
105+ } else {
106+ Config :: default ( )
107+ }
108+ }
109+ } ;
59110 let settings = CodegenSettings {
60111 gen_async : r#async || !sync,
61112 gen_sync : sync,
62113 derive_ser : serialize,
114+ config,
63115 } ;
64116
65117 match action {
66118 Action :: Live { url } => {
67- let mut client = conn:: from_url ( & url) ?;
119+ let mut client = conn:: from_url ( & url) . map_err ( |e| CliError :: Internal ( e . into ( ) ) ) ?;
68120 generate_live ( & mut client, & queries_path, Some ( & destination) , settings) ?;
69121 }
70122 Action :: Schema { schema_files } => {
@@ -77,7 +129,7 @@ pub fn run() -> Result<(), Error> {
77129 settings,
78130 ) {
79131 container:: cleanup ( podman) . ok ( ) ;
80- return Err ( e ) ;
132+ return Err ( CliError :: Internal ( e ) ) ;
81133 }
82134 }
83135 } ;
0 commit comments