diff --git a/examples/basic/.perseus/server/src/main.rs b/examples/basic/.perseus/server/src/main.rs index cf789945cb..4d8cd3827f 100644 --- a/examples/basic/.perseus/server/src/main.rs +++ b/examples/basic/.perseus/server/src/main.rs @@ -19,6 +19,8 @@ use std::fs; #[cfg(feature = "integration-actix-web")] #[actix_web::main] async fn main() -> std::io::Result<()> { + println!("WARNING: The Actix Web integration uses a beta version of Actix Web, and is considered unstable. It is not recommended for production usage."); + use actix_web::{App, HttpServer}; use perseus_actix_web::configurer; diff --git a/packages/perseus-cli/src/bin/main.rs b/packages/perseus-cli/src/bin/main.rs index e000b5f360..ed958534c7 100644 --- a/packages/perseus-cli/src/bin/main.rs +++ b/packages/perseus-cli/src/bin/main.rs @@ -154,7 +154,7 @@ fn core(dir: PathBuf) -> Result { Subcommand::Snoop(snoop_subcmd) => match snoop_subcmd { SnoopSubcommand::Build => snoop_build(dir)?, SnoopSubcommand::WasmBuild => snoop_wasm_build(dir)?, - SnoopSubcommand::Serve => snoop_server(dir)?, + SnoopSubcommand::Serve(snoop_serve_opts) => snoop_server(dir, snoop_serve_opts)?, }, Subcommand::Prep => { // The `.perseus/` directory has already been set up in the preliminaries, so we don't need to do anything here diff --git a/packages/perseus-cli/src/deploy.rs b/packages/perseus-cli/src/deploy.rs index d8251ad3f1..a6f194e953 100644 --- a/packages/perseus-cli/src/deploy.rs +++ b/packages/perseus-cli/src/deploy.rs @@ -1,5 +1,6 @@ use crate::errors::*; use crate::export; +use crate::parse::Integration; use crate::parse::{DeployOpts, ExportOpts, ServeOpts}; use crate::serve; use fs_extra::copy_items; @@ -15,7 +16,7 @@ pub fn deploy(dir: PathBuf, opts: DeployOpts) -> Result { let exit_code = if opts.export_static { deploy_export(dir, opts.output)? } else { - deploy_full(dir, opts.output)? + deploy_full(dir, opts.output, opts.integration)? }; Ok(exit_code) @@ -23,7 +24,7 @@ pub fn deploy(dir: PathBuf, opts: DeployOpts) -> Result { /// Deploys the user's app in its entirety, with a bundled server. This can return any kind of error because deploying involves working /// with other subcommands. -fn deploy_full(dir: PathBuf, output: String) -> Result { +fn deploy_full(dir: PathBuf, output: String, integration: Integration) -> Result { // Build everything for production, not running the server let (serve_exit_code, server_path) = serve( dir.clone(), @@ -32,6 +33,7 @@ fn deploy_full(dir: PathBuf, output: String) -> Result { no_build: false, release: true, standalone: true, + integration, }, )?; if serve_exit_code != 0 { diff --git a/packages/perseus-cli/src/parse.rs b/packages/perseus-cli/src/parse.rs index 86ece2d8f6..f3391cb39c 100644 --- a/packages/perseus-cli/src/parse.rs +++ b/packages/perseus-cli/src/parse.rs @@ -14,6 +14,32 @@ pub struct Opts { pub subcmd: Subcommand, } +#[derive(Parser, PartialEq, Eq)] +pub enum Integration { + ActixWeb, + Warp, +} +// We use an `enum` for this so we don't get errors from Cargo about non-existent feature flags, overly verbose but fails quickly +impl std::str::FromStr for Integration { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "actix-web" => Ok(Self::ActixWeb), + "warp" => Ok(Self::Warp), + _ => Err("invalid integration name".into()), + } + } +} +impl ToString for Integration { + fn to_string(&self) -> String { + match self { + Self::ActixWeb => "actix-web".to_string(), + Self::Warp => "warp".to_string(), + } + } +} + #[derive(Parser)] pub enum Subcommand { Build(BuildOpts), @@ -61,6 +87,9 @@ pub struct ServeOpts { /// Make the final binary standalone (this is used in `perseus deploy` only, don't manually invoke it unless you have a good reason!) #[clap(long)] pub standalone: bool, + /// The server integration to use + #[clap(short, long, default_value = "warp")] + pub integration: Integration, } /// Removes `.perseus/` entirely for updates or to fix corruptions #[derive(Parser)] @@ -81,6 +110,9 @@ pub struct DeployOpts { /// Export you app to purely static files (see `export`) #[clap(short, long)] pub export_static: bool, + /// The server integration to use (only affects non-exported deployments) + #[clap(short, long, default_value = "warp")] + pub integration: Integration, } /// Runs the `tinker` action of plugins, which lets them modify the Perseus engine #[derive(Parser)] @@ -100,5 +132,12 @@ pub enum SnoopSubcommand { /// Snoops on the Wasm building process (mostly for debugging errors) WasmBuild, /// Snoops on the server process (run `perseus build` before this) - Serve, + Serve(SnoopServeOpts), +} + +#[derive(Parser)] +pub struct SnoopServeOpts { + /// The server integration to use + #[clap(short, long, default_value = "warp")] + pub integration: Integration, } diff --git a/packages/perseus-cli/src/serve.rs b/packages/perseus-cli/src/serve.rs index b98b74cf2e..5e49f48dea 100644 --- a/packages/perseus-cli/src/serve.rs +++ b/packages/perseus-cli/src/serve.rs @@ -1,7 +1,7 @@ use crate::build::{build_internal, finalize}; use crate::cmd::{cfg_spinner, run_stage}; use crate::errors::*; -use crate::parse::ServeOpts; +use crate::parse::{Integration, ServeOpts}; use crate::thread::{spawn_thread, ThreadHandle}; use console::{style, Emoji}; use indicatif::{MultiProgress, ProgressBar}; @@ -37,10 +37,18 @@ fn build_server( exec: Arc>, is_release: bool, is_standalone: bool, + integration: Integration, ) -> Result< ThreadHandle Result, Result>, ExecutionError, > { + // If we're using the Actix Web integration, warn that it's unstable + // A similar warning is emitted for snooping on it + // TODO Remove this once Actix Web v4.0.0 goes stable + if integration == Integration::ActixWeb { + println!("WARNING: The Actix Web integration uses a beta version of Actix Web, and is considered unstable. It is not recommended for production usage.") + } + let num_steps = match did_build { true => 4, false => 2, @@ -69,11 +77,13 @@ fn build_server( "{} build --message-format json {} {}", env::var("PERSEUS_CARGO_PATH").unwrap_or_else(|_| "cargo".to_string()), if is_release { "--release" } else { "" }, - if is_standalone { - "--features standalone" - } else { - "" - } + // Enable the appropriate integration + format!( + "--features integration-{} {} --no-default-features", + integration.to_string(), + // We'll also handle whether or not it's standalone because that goes under the `--features` flag + if is_standalone { "standalone" } else { "" } + ) )], &sb_target, &sb_spinner, @@ -198,6 +208,7 @@ pub fn serve(dir: PathBuf, opts: ServeOpts) -> Result<(i32, Option), Exe Arc::clone(&exec), opts.release, opts.standalone, + opts.integration, )?; // Only build if the user hasn't set `--no-build`, handling non-zero exit codes if did_build { diff --git a/packages/perseus-cli/src/snoop.rs b/packages/perseus-cli/src/snoop.rs index 6b4e344786..4a6904fab1 100644 --- a/packages/perseus-cli/src/snoop.rs +++ b/packages/perseus-cli/src/snoop.rs @@ -1,4 +1,5 @@ use crate::errors::*; +use crate::parse::SnoopServeOpts; use std::env; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -59,12 +60,17 @@ pub fn snoop_wasm_build(dir: PathBuf) -> Result { } /// Runs the commands to run the server directly so the user can see detailed logs. -pub fn snoop_server(dir: PathBuf) -> Result { +pub fn snoop_server(dir: PathBuf, opts: SnoopServeOpts) -> Result { let target = dir.join(".perseus/server"); run_cmd_directly( format!( - "{} run", - env::var("PERSEUS_CARGO_PATH").unwrap_or_else(|_| "cargo".to_string()) + "{} run {}", + env::var("PERSEUS_CARGO_PATH").unwrap_or_else(|_| "cargo".to_string()), + // Enable the appropriate feature for a non-default server integration + format!( + "--features integration-{} --no-default-features", + opts.integration.to_string() + ) ), &target, )