Skip to main content

euv_cli/mode/
fn.rs

1use crate::*;
2
3/// Executes the build-only pipeline.
4///
5/// # Arguments
6///
7/// - `ModeArgs` - The CLI arguments.
8///
9/// # Returns
10///
11/// - `Result<(), EuvError>` - Indicates success or failure.
12pub async fn build_mode(mut args: ModeArgs) -> Result<(), EuvError> {
13    reconcile_args(&mut args);
14    args.set_crate_path(std::fs::canonicalize(args.get_crate_path()).map_err(
15        |error: io::Error| EuvError::IoPath {
16            message: String::from("Invalid crate-path"),
17            path: args.get_crate_path().clone(),
18            error,
19        },
20    )?);
21    let crate_path_str: String = args.get_crate_path().to_string_lossy().to_string();
22    if crate_path_str.starts_with(WINDOWS_UNC_PREFIX) {
23        args.set_crate_path(PathBuf::from(
24            crate_path_str
25                .strip_prefix(WINDOWS_UNC_PREFIX)
26                .unwrap_or(&crate_path_str),
27        ));
28    }
29    print_banner(Action::Build);
30    run_build_only_pipeline(&args).await?;
31    log::info!("Build completed. Exiting (build-only mode).");
32    Ok(())
33}
34
35/// Executes the format command.
36///
37/// # Arguments
38///
39/// - `FmtArgs` - The CLI arguments for the fmt command.
40///
41/// # Returns
42///
43/// - `Result<(), EuvError>` - Indicates success or failure.
44pub async fn fmt_mode(args: FmtArgs) -> Result<(), EuvError> {
45    let fmt_path: PathBuf = if args.get_path().is_absolute() {
46        args.get_path().clone()
47    } else {
48        std::env::current_dir()
49            .map_err(|error: io::Error| EuvError::Io {
50                message: String::from("Failed to get current directory"),
51                error,
52            })?
53            .join(args.get_path())
54    };
55    let mode: FmtMode = if args.get_check() {
56        FmtMode::Check
57    } else {
58        FmtMode::Write
59    };
60    format_dir(&fmt_path, mode).await
61}
62
63/// Executes the run mode (build + dev server + hot reload).
64///
65/// # Arguments
66///
67/// - `ModeArgs` - The CLI arguments.
68///
69/// # Returns
70///
71/// - `Result<(), EuvError>` - Indicates success or failure.
72pub async fn run_mode(mut args: ModeArgs) -> Result<(), EuvError> {
73    reconcile_args(&mut args);
74    args.set_crate_path(std::fs::canonicalize(args.get_crate_path()).map_err(
75        |error: io::Error| EuvError::IoPath {
76            message: String::from("Invalid crate-path"),
77            path: args.get_crate_path().clone(),
78            error,
79        },
80    )?);
81    let crate_path_str: String = args.get_crate_path().to_string_lossy().to_string();
82    if crate_path_str.starts_with(WINDOWS_UNC_PREFIX) {
83        args.set_crate_path(PathBuf::from(
84            crate_path_str
85                .strip_prefix(WINDOWS_UNC_PREFIX)
86                .unwrap_or(&crate_path_str),
87        ));
88    }
89    let www_route_prefix: String = args
90        .get_www_dir()
91        .replace(CHAR_SLASH_BACK, STR_SLASH_FORWARD);
92    let www_absolute: PathBuf = args.get_crate_path().join(args.get_www_dir());
93    let www_absolute: PathBuf = resolve_www_dir(&www_absolute).await;
94    let initial_html: String = match run_build_pipeline(&args, None).await {
95        Ok(html) => html,
96        Err(error) => {
97            log::error!("Initial build pipeline failed: {error}");
98            let import_path: String = resolve_import_path(&args);
99            let is_release: bool = resolve_build_mode(&args) == BuildMode::Release;
100            let custom_html: &Option<PathBuf> = args.try_get_index_html();
101            generate_html(&www_absolute, &import_path, is_release, custom_html).await?
102        }
103    };
104    print_banner(Action::Run);
105    let (reload_tx, _): (
106        broadcast::Sender<ReloadEvent>,
107        broadcast::Receiver<ReloadEvent>,
108    ) = broadcast::channel(16);
109    let state: Arc<AppState> = Arc::new(AppState::new(
110        RwLock::new(initial_html),
111        reload_tx.clone(),
112        RwLock::new(false),
113        args.clone(),
114    ));
115    let state_for_watch: Arc<AppState> = Arc::clone(&state);
116    tokio::spawn(async move {
117        if let Err(error) = watch_and_build(state_for_watch).await {
118            log::error!("Watch error: {error}");
119        }
120    });
121    let pkg_dir: PathBuf = resolve_pkg_dir(&args);
122    log::info!("Serving pkg from: {}", pkg_dir.display());
123    let mut server: Server = Server::default();
124    let mut server_config: ServerConfig = ServerConfig::default();
125    server_config.set_address(Server::format_bind_address(DEFAULT_HOST, args.get_port()));
126    server.server_config(server_config);
127    server.request_middleware::<RequestMiddleware>();
128    server.response_middleware::<ResponseMiddleware>();
129    server.route::<IndexRoute>(format!("{www_route_prefix}/{{path:.*}}"));
130    server.route::<ReloadRoute>(RELOAD_ROUTE);
131    if let Err(error) = set_global_state(Arc::clone(&state)) {
132        log::error!("Failed to set global state: {error}");
133    }
134    print_server_urls(args.get_port(), &www_route_prefix, INDEX_HTML_FILE_NAME);
135    let server_control_hook: ServerControlHook = server
136        .run()
137        .await
138        .map_err(|error: ServerError| EuvError::Server(error.to_string()))?;
139    server_control_hook.wait().await;
140    Ok(())
141}