2024-01-01 14:58:21 -05:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2019-09-03 22:12:21 -04:00
2022-06-27 16:54:09 -04:00
mod args ;
2021-02-15 21:50:27 -05:00
mod auth_tokens ;
2021-10-10 17:26:22 -04:00
mod cache ;
2023-11-05 17:58:59 -05:00
mod cdp ;
2021-10-10 17:26:22 -04:00
mod emit ;
2020-10-12 07:25:25 -04:00
mod errors ;
2023-05-01 14:35:23 -04:00
mod factory ;
2020-05-11 17:33:36 -04:00
mod file_fetcher ;
2024-05-16 03:09:35 -04:00
mod graph_container ;
2021-12-16 05:45:41 -05:00
mod graph_util ;
2020-05-11 17:33:36 -04:00
mod http_util ;
2022-11-21 08:36:26 -05:00
mod js ;
2024-03-01 16:34:13 -05:00
mod jsr ;
2020-12-07 05:46:39 -05:00
mod lsp ;
2020-10-13 07:35:35 -04:00
mod module_loader ;
2022-10-05 10:06:44 -04:00
mod napi ;
2022-08-20 11:31:33 -04:00
mod node ;
2022-08-10 15:23:58 -04:00
mod npm ;
2020-10-12 07:25:25 -04:00
mod ops ;
2021-10-10 17:26:22 -04:00
mod resolver ;
2020-11-30 14:35:12 -05:00
mod standalone ;
2024-07-09 23:06:08 -04:00
mod task_runner ;
2020-11-19 13:19:34 -05:00
mod tools ;
2020-11-02 14:41:20 -05:00
mod tsc ;
2022-11-28 17:28:54 -05:00
mod util ;
2020-10-12 07:25:25 -04:00
mod version ;
2022-08-11 16:59:12 -04:00
mod worker ;
2020-05-11 17:33:36 -04:00
2022-06-27 16:54:09 -04:00
use crate ::args ::flags_from_vec ;
use crate ::args ::DenoSubcommand ;
use crate ::args ::Flags ;
2024-04-29 16:43:05 -04:00
use crate ::args ::DENO_FUTURE ;
2024-05-16 03:09:35 -04:00
use crate ::graph_container ::ModuleGraphContainer ;
2022-11-28 17:28:54 -05:00
use crate ::util ::display ;
2023-01-24 23:03:03 -05:00
use crate ::util ::v8 ::get_v8_flags_from_env ;
use crate ::util ::v8 ::init_v8_flags ;
2022-06-27 16:54:09 -04:00
2024-04-24 15:45:49 -04:00
use deno_runtime ::WorkerExecutionMode ;
2024-01-23 09:33:07 -05:00
pub use deno_runtime ::UNSTABLE_GRANULAR_FLAGS ;
2022-12-09 09:40:48 -05:00
use deno_core ::anyhow ::Context ;
2020-09-14 12:48:57 -04:00
use deno_core ::error ::AnyError ;
2022-04-26 19:06:10 -04:00
use deno_core ::error ::JsError ;
2023-05-17 17:49:57 -04:00
use deno_core ::futures ::FutureExt ;
2023-08-23 19:03:05 -04:00
use deno_core ::unsync ::JoinHandle ;
2024-01-22 16:31:12 -05:00
use deno_npm ::resolution ::SnapshotFromLockfileError ;
2022-09-02 16:53:23 -04:00
use deno_runtime ::fmt_errors ::format_js_error ;
2023-06-09 07:52:51 -04:00
use deno_runtime ::tokio_util ::create_and_run_current_thread_with_maybe_metrics ;
2024-02-07 11:25:14 -05:00
use deno_terminal ::colors ;
2023-05-01 14:35:23 -04:00
use factory ::CliFactory ;
2020-05-11 17:33:36 -04:00
use std ::env ;
2023-05-17 17:49:57 -04:00
use std ::future ::Future ;
2020-05-11 17:33:36 -04:00
use std ::path ::PathBuf ;
2022-02-16 13:14:19 -05:00
2023-05-17 17:49:57 -04:00
/// Ensures that all subcommands return an i32 exit code and an [`AnyError`] error type.
trait SubcommandOutput {
fn output ( self ) -> Result < i32 , AnyError > ;
}
impl SubcommandOutput for Result < i32 , AnyError > {
fn output ( self ) -> Result < i32 , AnyError > {
self
}
}
impl SubcommandOutput for Result < ( ) , AnyError > {
fn output ( self ) -> Result < i32 , AnyError > {
self . map ( | _ | 0 )
}
}
impl SubcommandOutput for Result < ( ) , std ::io ::Error > {
fn output ( self ) -> Result < i32 , AnyError > {
self . map ( | _ | 0 ) . map_err ( | e | e . into ( ) )
}
}
/// Ensure that the subcommand runs in a task, rather than being directly executed. Since some of these
/// futures are very large, this prevents the stack from getting blown out from passing them by value up
/// the callchain (especially in debug mode when Rust doesn't have a chance to elide copies!).
#[ inline(always) ]
fn spawn_subcommand < F : Future < Output = T > + 'static , T : SubcommandOutput > (
f : F ,
) -> JoinHandle < Result < i32 , AnyError > > {
2023-09-30 12:06:38 -04:00
// the boxed_local() is important in order to get windows to not blow the stack in debug
deno_core ::unsync ::spawn (
async move { f . map ( | r | r . output ( ) ) . await } . boxed_local ( ) ,
)
2023-05-17 17:49:57 -04:00
}
2022-12-09 09:40:48 -05:00
async fn run_subcommand ( flags : Flags ) -> Result < i32 , AnyError > {
2023-05-17 17:49:57 -04:00
let handle = match flags . subcommand . clone ( ) {
2024-02-29 14:12:04 -05:00
DenoSubcommand ::Add ( add_flags ) = > spawn_subcommand ( async {
tools ::registry ::add ( flags , add_flags ) . await
} ) ,
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Bench ( bench_flags ) = > spawn_subcommand ( async {
2023-06-15 13:09:37 -04:00
if bench_flags . watch . is_some ( ) {
2023-06-14 18:29:19 -04:00
tools ::bench ::run_benchmarks_with_watch ( flags , bench_flags ) . await
2022-12-09 09:40:48 -05:00
} else {
2023-06-14 18:29:19 -04:00
tools ::bench ::run_benchmarks ( flags , bench_flags ) . await
2022-12-09 09:40:48 -05:00
}
2023-05-17 17:49:57 -04:00
} ) ,
DenoSubcommand ::Bundle ( bundle_flags ) = > spawn_subcommand ( async {
tools ::bundle ::bundle ( flags , bundle_flags ) . await
} ) ,
2021-09-03 19:33:35 -04:00
DenoSubcommand ::Doc ( doc_flags ) = > {
2023-11-01 11:25:05 -04:00
spawn_subcommand ( async { tools ::doc ::doc ( flags , doc_flags ) . await } )
2021-09-03 19:33:35 -04:00
}
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Eval ( eval_flags ) = > spawn_subcommand ( async {
2022-12-09 09:40:48 -05:00
tools ::run ::eval_command ( flags , eval_flags ) . await
2023-05-17 17:49:57 -04:00
} ) ,
DenoSubcommand ::Cache ( cache_flags ) = > spawn_subcommand ( async move {
2024-03-11 23:48:00 -04:00
let factory = CliFactory ::from_flags ( flags ) ? ;
2023-05-01 14:35:23 -04:00
let emitter = factory . emitter ( ) ? ;
2024-05-16 03:09:35 -04:00
let main_graph_container =
factory . main_module_graph_container ( ) . await ? ;
main_graph_container
2023-04-14 16:22:33 -04:00
. load_and_type_check_files ( & cache_flags . files )
. await ? ;
2024-05-18 11:42:03 -04:00
emitter . cache_module_emits ( & main_graph_container . graph ( ) ) . await
2023-05-17 17:49:57 -04:00
} ) ,
DenoSubcommand ::Check ( check_flags ) = > spawn_subcommand ( async move {
2024-03-11 23:48:00 -04:00
let factory = CliFactory ::from_flags ( flags ) ? ;
2024-05-16 03:09:35 -04:00
let main_graph_container =
factory . main_module_graph_container ( ) . await ? ;
main_graph_container
2023-04-14 16:22:33 -04:00
. load_and_type_check_files ( & check_flags . files )
2023-05-17 17:49:57 -04:00
. await
} ) ,
DenoSubcommand ::Compile ( compile_flags ) = > spawn_subcommand ( async {
tools ::compile ::compile ( flags , compile_flags ) . await
} ) ,
DenoSubcommand ::Coverage ( coverage_flags ) = > spawn_subcommand ( async {
tools ::coverage ::cover_files ( flags , coverage_flags ) . await
} ) ,
2023-06-14 18:29:19 -04:00
DenoSubcommand ::Fmt ( fmt_flags ) = > {
spawn_subcommand (
async move { tools ::fmt ::format ( flags , fmt_flags ) . await } ,
)
}
2022-08-19 19:37:05 -04:00
DenoSubcommand ::Init ( init_flags ) = > {
2024-03-11 23:48:00 -04:00
spawn_subcommand ( async {
// make compiler happy since init_project is sync
tokio ::task ::yield_now ( ) . await ;
tools ::init ::init_project ( init_flags )
} )
2022-08-19 19:37:05 -04:00
}
2021-09-03 19:33:35 -04:00
DenoSubcommand ::Info ( info_flags ) = > {
2023-05-17 17:49:57 -04:00
spawn_subcommand ( async { tools ::info ::info ( flags , info_flags ) . await } )
}
DenoSubcommand ::Install ( install_flags ) = > spawn_subcommand ( async {
tools ::installer ::install_command ( flags , install_flags ) . await
} ) ,
2023-09-15 20:42:09 -04:00
DenoSubcommand ::Jupyter ( jupyter_flags ) = > spawn_subcommand ( async {
tools ::jupyter ::kernel ( flags , jupyter_flags ) . await
} ) ,
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Uninstall ( uninstall_flags ) = > spawn_subcommand ( async {
2024-03-27 18:45:57 -04:00
tools ::installer ::uninstall ( uninstall_flags )
2023-05-17 17:49:57 -04:00
} ) ,
DenoSubcommand ::Lsp = > spawn_subcommand ( async { lsp ::start ( ) . await } ) ,
DenoSubcommand ::Lint ( lint_flags ) = > spawn_subcommand ( async {
2022-12-09 09:40:48 -05:00
if lint_flags . rules {
2023-07-25 17:24:06 -04:00
tools ::lint ::print_rules_list (
lint_flags . json ,
lint_flags . maybe_rules_tags ,
) ;
2023-05-17 17:49:57 -04:00
Ok ( ( ) )
2022-12-09 09:40:48 -05:00
} else {
2023-06-14 18:29:19 -04:00
tools ::lint ::lint ( flags , lint_flags ) . await
2022-12-09 09:40:48 -05:00
}
2023-05-17 17:49:57 -04:00
} ) ,
2021-09-03 19:33:35 -04:00
DenoSubcommand ::Repl ( repl_flags ) = > {
2023-05-17 17:49:57 -04:00
spawn_subcommand ( async move { tools ::repl ::run ( flags , repl_flags ) . await } )
2021-09-03 19:33:35 -04:00
}
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Run ( run_flags ) = > spawn_subcommand ( async move {
2022-12-09 09:40:48 -05:00
if run_flags . is_stdin ( ) {
tools ::run ::run_from_stdin ( flags ) . await
} else {
2024-04-24 15:45:49 -04:00
tools ::run ::run_script ( WorkerExecutionMode ::Run , flags , run_flags . watch ) . await
2022-12-09 09:40:48 -05:00
}
2023-05-17 17:49:57 -04:00
} ) ,
2024-04-24 15:45:49 -04:00
DenoSubcommand ::Serve ( serve_flags ) = > spawn_subcommand ( async move {
tools ::run ::run_script ( WorkerExecutionMode ::Serve , flags , serve_flags . watch ) . await
} ) ,
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Task ( task_flags ) = > spawn_subcommand ( async {
2022-12-09 09:40:48 -05:00
tools ::task ::execute_script ( flags , task_flags ) . await
2023-05-17 17:49:57 -04:00
} ) ,
2021-09-03 19:33:35 -04:00
DenoSubcommand ::Test ( test_flags ) = > {
2023-05-17 17:49:57 -04:00
spawn_subcommand ( async {
2023-06-15 13:09:37 -04:00
if let Some ( ref coverage_dir ) = test_flags . coverage_dir {
2024-05-22 23:04:12 -04:00
if test_flags . clean {
let _ = std ::fs ::remove_dir_all ( coverage_dir ) ;
}
2023-05-17 17:49:57 -04:00
std ::fs ::create_dir_all ( coverage_dir )
. with_context ( | | format! ( " Failed creating: {coverage_dir} " ) ) ? ;
// this is set in order to ensure spawned processes use the same
// coverage directory
env ::set_var (
" DENO_UNSTABLE_COVERAGE_DIR " ,
PathBuf ::from ( coverage_dir ) . canonicalize ( ) ? ,
) ;
}
2022-12-09 09:40:48 -05:00
2023-06-15 13:09:37 -04:00
if test_flags . watch . is_some ( ) {
2023-06-14 18:29:19 -04:00
tools ::test ::run_tests_with_watch ( flags , test_flags ) . await
2023-05-17 17:49:57 -04:00
} else {
2023-06-14 18:29:19 -04:00
tools ::test ::run_tests ( flags , test_flags ) . await
2023-05-17 17:49:57 -04:00
}
} )
2021-09-03 19:33:35 -04:00
}
2021-12-21 09:49:27 -05:00
DenoSubcommand ::Completions ( completions_flags ) = > {
2023-05-17 17:49:57 -04:00
spawn_subcommand ( async move {
display ::write_to_stdout_ignore_sigpipe ( & completions_flags . buf )
} )
2022-12-09 09:40:48 -05:00
}
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Types = > spawn_subcommand ( async move {
2024-01-14 12:29:17 -05:00
let types = tsc ::get_types_declaration_file_text ( ) ;
2023-05-17 17:49:57 -04:00
display ::write_to_stdout_ignore_sigpipe ( types . as_bytes ( ) )
} ) ,
2023-11-29 13:52:25 -05:00
#[ cfg(feature = " upgrade " ) ]
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Upgrade ( upgrade_flags ) = > spawn_subcommand ( async {
tools ::upgrade ::upgrade ( flags , upgrade_flags ) . await
} ) ,
2023-11-29 13:52:25 -05:00
#[ cfg(not(feature = " upgrade " )) ]
DenoSubcommand ::Upgrade ( _ ) = > exit_with_message (
" This deno was built without the \" upgrade \" feature. Please upgrade using the installation method originally used to install Deno. " ,
1 ,
) ,
2023-05-17 17:49:57 -04:00
DenoSubcommand ::Vendor ( vendor_flags ) = > spawn_subcommand ( async {
tools ::vendor ::vendor ( flags , vendor_flags ) . await
} ) ,
2023-11-23 18:38:07 -05:00
// TODO:
DenoSubcommand ::Publish ( publish_flags ) = > spawn_subcommand ( async {
tools ::registry ::publish ( flags , publish_flags ) . await
} ) ,
2023-05-17 17:49:57 -04:00
} ;
handle . await ?
2020-11-26 09:17:45 -05:00
}
2024-05-08 22:45:06 -04:00
#[ allow(clippy::print_stderr) ]
2021-12-20 08:49:05 -05:00
fn setup_panic_hook ( ) {
// This function does two things inside of the panic hook:
// - Tokio does not exit the process when a task panics, so we define a custom
// panic hook to implement this behaviour.
// - We print a message to stderr to indicate that this is a bug in Deno, and
// should be reported to us.
2021-09-07 19:34:27 -04:00
let orig_hook = std ::panic ::take_hook ( ) ;
std ::panic ::set_hook ( Box ::new ( move | panic_info | {
2021-12-20 08:49:05 -05:00
eprintln! ( " \n ============================================================ " ) ;
eprintln! ( " Deno has panicked. This is a bug in Deno. Please report this " ) ;
eprintln! ( " at https://github.com/denoland/deno/issues/new. " ) ;
eprintln! ( " If you can reliably reproduce this panic, include the " ) ;
eprintln! ( " reproduction steps and re-run with the RUST_BACKTRACE=1 env " ) ;
eprintln! ( " var set and include the backtrace in your report. " ) ;
eprintln! ( ) ;
2022-07-14 17:52:44 -04:00
eprintln! ( " Platform: {} {} " , env ::consts ::OS , env ::consts ::ARCH ) ;
2021-12-20 08:49:05 -05:00
eprintln! ( " Version: {} " , version ::deno ( ) ) ;
2022-07-14 17:52:44 -04:00
eprintln! ( " Args: {:?} " , env ::args ( ) . collect ::< Vec < _ > > ( ) ) ;
2021-12-20 08:49:05 -05:00
eprintln! ( ) ;
2021-09-07 19:34:27 -04:00
orig_hook ( panic_info ) ;
std ::process ::exit ( 1 ) ;
} ) ) ;
}
2024-05-08 22:45:06 -04:00
#[ allow(clippy::print_stderr) ]
2023-11-29 13:52:25 -05:00
fn exit_with_message ( message : & str , code : i32 ) -> ! {
eprintln! (
" {}: {} " ,
colors ::red_bold ( " error " ) ,
message . trim_start_matches ( " error: " )
) ;
std ::process ::exit ( code ) ;
}
2024-03-31 10:58:19 -04:00
fn exit_for_error ( error : AnyError ) -> ! {
let mut error_string = format! ( " {error:?} " ) ;
let mut error_code = 1 ;
2022-10-25 12:20:07 -04:00
2024-03-31 10:58:19 -04:00
if let Some ( e ) = error . downcast_ref ::< JsError > ( ) {
error_string = format_js_error ( e ) ;
} else if let Some ( SnapshotFromLockfileError ::IntegrityCheckFailed ( e ) ) =
error . downcast_ref ::< SnapshotFromLockfileError > ( )
{
error_string = e . to_string ( ) ;
error_code = 10 ;
2021-01-07 13:06:08 -05:00
}
2024-03-31 10:58:19 -04:00
exit_with_message ( & error_string , error_code ) ;
2021-01-07 13:06:08 -05:00
}
2024-05-08 22:45:06 -04:00
#[ allow(clippy::print_stderr) ]
2024-01-23 09:33:07 -05:00
pub ( crate ) fn unstable_exit_cb ( feature : & str , api_name : & str ) {
eprintln! (
" Unstable API '{api_name}'. The `--unstable-{}` flag must be provided. " ,
feature
) ;
2023-10-12 11:55:50 -04:00
std ::process ::exit ( 70 ) ;
}
2024-01-23 09:33:07 -05:00
// TODO(bartlomieju): remove when `--unstable` flag is removed.
2024-05-08 22:45:06 -04:00
#[ allow(clippy::print_stderr) ]
2024-01-23 09:33:07 -05:00
pub ( crate ) fn unstable_warn_cb ( feature : & str , api_name : & str ) {
2023-10-12 11:55:50 -04:00
eprintln! (
2024-01-23 09:33:07 -05:00
" ⚠️ {} " ,
colors ::yellow ( format! (
" The `{}` API was used with `--unstable` flag. The `--unstable` flag is deprecated and will be removed in Deno 2.0. Use granular `--unstable-{}` instead. \n Learn more at: https://docs.deno.com/runtime/manual/tools/unstable_flags " ,
api_name , feature
) )
2023-10-12 11:55:50 -04:00
) ;
}
2020-11-26 09:17:45 -05:00
pub fn main ( ) {
2021-12-20 08:49:05 -05:00
setup_panic_hook ( ) ;
2021-10-25 11:16:16 -04:00
2022-11-28 17:28:54 -05:00
util ::unix ::raise_fd_limit ( ) ;
util ::windows ::ensure_stdio_open ( ) ;
2020-11-26 09:17:45 -05:00
#[ cfg(windows) ]
colors ::enable_ansi ( ) ; // For Windows 10
2024-06-06 23:37:53 -04:00
deno_runtime ::deno_permissions ::set_prompt_callbacks (
2022-12-19 14:31:19 -05:00
Box ::new ( util ::draw_thread ::DrawThread ::hide ) ,
Box ::new ( util ::draw_thread ::DrawThread ::show ) ,
) ;
2020-11-26 09:17:45 -05:00
2024-03-22 17:03:56 -04:00
let args : Vec < _ > = env ::args_os ( ) . collect ( ) ;
2022-12-09 09:40:48 -05:00
let future = async move {
2024-05-26 00:13:20 -04:00
// NOTE(lucacasonato): due to new PKU feature introduced in V8 11.6 we need to
// initialize the V8 platform on a parent thread of all threads that will spawn
// V8 isolates.
let flags = resolve_flags_and_init ( args ) ? ;
run_subcommand ( flags ) . await
2024-03-31 10:58:19 -04:00
} ;
2024-01-23 09:33:07 -05:00
2024-03-31 10:58:19 -04:00
match create_and_run_current_thread_with_maybe_metrics ( future ) {
Ok ( exit_code ) = > std ::process ::exit ( exit_code ) ,
Err ( err ) = > exit_for_error ( err ) ,
}
}
2021-05-11 00:54:10 -04:00
2024-03-31 10:58:19 -04:00
fn resolve_flags_and_init (
args : Vec < std ::ffi ::OsString > ,
) -> Result < Flags , AnyError > {
let flags = match flags_from_vec ( args ) {
Ok ( flags ) = > flags ,
Err ( err @ clap ::Error { .. } )
if err . kind ( ) = = clap ::error ::ErrorKind ::DisplayHelp
| | err . kind ( ) = = clap ::error ::ErrorKind ::DisplayVersion = >
{
2024-07-09 18:57:00 -04:00
// Ignore results to avoid BrokenPipe errors.
let _ = err . print ( ) ;
2024-03-31 10:58:19 -04:00
std ::process ::exit ( 0 ) ;
}
Err ( err ) = > exit_for_error ( AnyError ::from ( err ) ) ,
} ;
// TODO(bartlomieju): remove when `--unstable` flag is removed.
if flags . unstable_config . legacy_flag_enabled {
2024-05-08 22:45:06 -04:00
#[ allow(clippy::print_stderr) ]
2024-03-31 10:58:19 -04:00
if matches! ( flags . subcommand , DenoSubcommand ::Check ( _ ) ) {
2024-05-08 22:45:06 -04:00
// can't use log crate because that's not setup yet
2024-03-31 10:58:19 -04:00
eprintln! (
" ⚠️ {} " ,
colors ::yellow (
" The `--unstable` flag is not needed for `deno check` anymore. "
)
) ;
} else {
eprintln! (
" ⚠️ {} " ,
colors ::yellow (
" The `--unstable` flag is deprecated and will be removed in Deno 2.0. Use granular `--unstable-*` flags instead. \n Learn more at: https://docs.deno.com/runtime/manual/tools/unstable_flags "
)
) ;
}
}
2022-02-15 07:33:46 -05:00
2024-03-31 10:58:19 -04:00
let default_v8_flags = match flags . subcommand {
// Using same default as VSCode:
// https://github.com/microsoft/vscode/blob/48d4ba271686e8072fc6674137415bc80d936bc7/extensions/typescript-language-features/src/configuration/configuration.ts#L213-L214
DenoSubcommand ::Lsp = > vec! [ " --max-old-space-size=3072 " . to_string ( ) ] ,
2024-04-29 16:43:05 -04:00
_ = > {
if * DENO_FUTURE {
// deno_ast removes TypeScript `assert` keywords, so this flag only affects JavaScript
// TODO(petamoriken): Need to check TypeScript `assert` keywords in deno_ast
vec! [ " --no-harmony-import-assertions " . to_string ( ) ]
} else {
2024-07-09 13:26:45 -04:00
vec! [
// If we're still in v1.X version we want to support import assertions.
// V8 12.6 unshipped the support by default, so force it by passing a
// flag.
" --harmony-import-assertions " . to_string ( ) ,
// Verify with DENO_FUTURE for now.
" --no-maglev " . to_string ( ) ,
]
2024-04-29 16:43:05 -04:00
}
}
2022-02-15 07:33:46 -05:00
} ;
2020-05-11 17:33:36 -04:00
2024-03-31 10:58:19 -04:00
init_v8_flags ( & default_v8_flags , & flags . v8_flags , get_v8_flags_from_env ( ) ) ;
deno_core ::JsRuntime ::init_platform ( None ) ;
util ::logger ::init ( flags . log_level ) ;
2021-11-27 18:45:38 -05:00
2024-03-31 10:58:19 -04:00
Ok ( flags )
2018-06-15 19:43:23 -04:00
}