add --offline, --locked, remove dioxus branding if dioxus is not being used explicitly (#4155)
* wip: add some spin logging * wipe dioxus branding if not being used by dioxus * add --locked, --offline, --frozen * properly git init with `dx new` and `dx init` * dont panic in verbosity * Move build-assets to "tools" * change ui for dx new offline * pin tauri-bundle * pin tauri * run tailwind once
This commit is contained in:
1 parent
a899f9f08e
commit
dd53ce72a7
14 files changed
+279
-93
No files matched your search
@@ -390,6 +390,7 @@ pub(crate) struct BuildRequest {
|
||||
pub(crate) link_err_file: Arc<NamedTempFile>,
|
||||
pub(crate) rustc_wrapper_args_file: Arc<NamedTempFile>,
|
||||
pub(crate) base_path: Option<String>,
|
||||
pub(crate) using_dioxus_explicitly: bool,
|
||||
}
|
||||
|
||||
/// dx can produce different "modes" of a build. A "regular" build is a "base" build. The Fat and Thin
|
||||
@@ -757,6 +758,7 @@ impl BuildRequest {
|
||||
package,
|
||||
main_target,
|
||||
rustflags,
|
||||
using_dioxus_explicitly,
|
||||
skip_assets: args.skip_assets,
|
||||
base_path: args.base_path.clone(),
|
||||
wasm_split: args.wasm_split,
|
||||
@@ -1132,6 +1134,14 @@ impl BuildRequest {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Run the tailwind build before bundling anything else
|
||||
crate::TailwindCli::run_once(
|
||||
self.package_manifest_dir(),
|
||||
self.config.application.tailwind_input.clone(),
|
||||
self.config.application.tailwind_output.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let asset_dir = self.asset_dir();
|
||||
|
||||
// First, clear the asset dir of any files that don't exist in the new manifest
|
||||
@@ -2147,6 +2157,18 @@ impl BuildRequest {
|
||||
};
|
||||
cargo_args.push(self.executable_name().to_string());
|
||||
|
||||
// Set offline/locked/frozen
|
||||
let lock_opts = crate::VERBOSITY.get().cloned().unwrap_or_default();
|
||||
if lock_opts.frozen {
|
||||
cargo_args.push("--frozen".to_string());
|
||||
}
|
||||
if lock_opts.locked {
|
||||
cargo_args.push("--locked".to_string());
|
||||
}
|
||||
if lock_opts.offline {
|
||||
cargo_args.push("--offline".to_string());
|
||||
}
|
||||
|
||||
// Merge in extra args. Order shouldn't really matter.
|
||||
cargo_args.extend(self.extra_cargo_args.clone());
|
||||
cargo_args.push("--".to_string());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use crate::TraceSrc;
|
||||
use cargo_generate::{GenerateArgs, TemplatePath};
|
||||
use cargo_generate::{GenerateArgs, TemplatePath, Vcs};
|
||||
use std::path::Path;
|
||||
|
||||
pub(crate) static DEFAULT_TEMPLATE: &str = "gh:dioxuslabs/dioxus-template";
|
||||
@@ -46,15 +46,25 @@ pub struct Create {
|
||||
/// Default values can be overridden with `--option`
|
||||
#[clap(short, long)]
|
||||
yes: bool,
|
||||
|
||||
/// Specify the VCS used to initialize the generated template.
|
||||
/// Options: `git`, `none`.
|
||||
#[arg(long, value_parser)]
|
||||
vcs: Option<Vcs>,
|
||||
}
|
||||
|
||||
impl Create {
|
||||
pub fn create(mut self) -> Result<StructuredOutput> {
|
||||
pub async fn create(mut self) -> Result<StructuredOutput> {
|
||||
// Project name defaults to directory name.
|
||||
if self.name.is_none() {
|
||||
self.name = Some(create::name_from_path(&self.path)?);
|
||||
}
|
||||
|
||||
// Perform a connectivity check so we just don't it around doing nothing if there's a network error
|
||||
if self.template.is_none() {
|
||||
connectivity_check().await?;
|
||||
}
|
||||
|
||||
// If no template is specified, use the default one and set the branch to the latest release.
|
||||
resolve_template_and_branch(&mut self.template, &mut self.branch);
|
||||
|
||||
@@ -72,14 +82,13 @@ impl Create {
|
||||
init: true,
|
||||
name: self.name,
|
||||
silent: self.yes,
|
||||
vcs: Some(cargo_generate::Vcs::Git),
|
||||
vcs: self.vcs,
|
||||
template_path: TemplatePath {
|
||||
auto_path: self.template,
|
||||
branch: self.branch,
|
||||
revision: self.revision,
|
||||
subfolder: self.subtemplate,
|
||||
tag: self.tag,
|
||||
|
||||
..Default::default()
|
||||
},
|
||||
verbose: crate::logging::VERBOSITY
|
||||
@@ -93,7 +102,7 @@ impl Create {
|
||||
tracing::debug!(dx_src = ?TraceSrc::Dev, "Creating new project with args: {args:#?}");
|
||||
let path = cargo_generate::generate(args)?;
|
||||
|
||||
_ = post_create(&path);
|
||||
_ = post_create(&path, &self.vcs.unwrap_or(Vcs::Git));
|
||||
|
||||
Ok(StructuredOutput::Success)
|
||||
}
|
||||
@@ -145,7 +154,7 @@ pub(crate) fn name_from_path(path: &Path) -> Result<String> {
|
||||
}
|
||||
|
||||
/// Post-creation actions for newly setup crates.
|
||||
pub(crate) fn post_create(path: &Path) -> Result<()> {
|
||||
pub(crate) fn post_create(path: &Path, vcs: &Vcs) -> Result<()> {
|
||||
let parent_dir = path.parent();
|
||||
let metadata = if parent_dir.is_none() {
|
||||
None
|
||||
@@ -168,6 +177,7 @@ pub(crate) fn post_create(path: &Path) -> Result<()> {
|
||||
|
||||
// 1. Add the new project to the workspace, if it exists.
|
||||
// This must be executed first in order to run `cargo fmt` on the new project.
|
||||
let is_workspace = metadata.is_some();
|
||||
metadata.and_then(|metadata| {
|
||||
let cargo_toml_path = &metadata.workspace_root.join("Cargo.toml");
|
||||
let cargo_toml_str = std::fs::read_to_string(cargo_toml_path).ok()?;
|
||||
@@ -223,6 +233,11 @@ pub(crate) fn post_create(path: &Path) -> Result<()> {
|
||||
let mut file = std::fs::File::create(readme_path)?;
|
||||
file.write_all(new_readme.as_bytes())?;
|
||||
|
||||
// 5. Run git init
|
||||
if !is_workspace {
|
||||
vcs.initialize(path, Some("main"), true)?;
|
||||
}
|
||||
|
||||
tracing::info!(dx_src = ?TraceSrc::Dev, "Generated project at {}\n\n`cd` to your project and run `dx serve` to start developing.\nMore information is available in the generated `README.md`.\n\nBuild cool things! ✌️", path.display());
|
||||
|
||||
Ok(())
|
||||
@@ -239,6 +254,43 @@ fn remove_triple_newlines(string: &str) -> String {
|
||||
new_string
|
||||
}
|
||||
|
||||
/// Perform a health check against github itself before we attempt to download any templates hosted
|
||||
/// on github.
|
||||
pub(crate) async fn connectivity_check() -> Result<()> {
|
||||
if crate::VERBOSITY
|
||||
.get()
|
||||
.map(|f| f.offline)
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
use crate::styles::{GLOW_STYLE, LINK_STYLE};
|
||||
let client = reqwest::Client::new();
|
||||
for x in 0..=5 {
|
||||
tokio::select! {
|
||||
res = client.head("https://github.com/DioxusLabs/").header("User-Agent", "dioxus-cli").send() => {
|
||||
if res.is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_millis(2000)).await;
|
||||
},
|
||||
_ = tokio::time::sleep(std::time::Duration::from_millis(if x == 1 { 500 } else { 2000 })) => {}
|
||||
}
|
||||
if x == 0 {
|
||||
println!("{GLOW_STYLE}warning{GLOW_STYLE:#}: Waiting for {LINK_STYLE}https://github.com/dioxuslabs{LINK_STYLE:#}...")
|
||||
} else {
|
||||
println!(
|
||||
"{GLOW_STYLE}warning{GLOW_STYLE:#}: ({x}/5) Taking a while, maybe your internet is down?"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Err(Error::Network(
|
||||
"Error connecting to template repository. Try cloning the template manually or add `dioxus` to a `cargo new` project.".to_string(),
|
||||
))
|
||||
}
|
||||
|
||||
// todo: re-enable these tests with better parallelization
|
||||
//
|
||||
// #[cfg(test)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use cargo_generate::{GenerateArgs, TemplatePath};
|
||||
use cargo_generate::{GenerateArgs, TemplatePath, Vcs};
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Parser)]
|
||||
#[clap(name = "init")]
|
||||
@@ -43,15 +43,25 @@ pub struct Init {
|
||||
/// Default values can be overridden with `--option`
|
||||
#[clap(short, long)]
|
||||
yes: bool,
|
||||
|
||||
/// Specify the VCS used to initialize the generated template.
|
||||
/// Options: `git`, `none`.
|
||||
#[arg(long, value_parser)]
|
||||
vcs: Option<Vcs>,
|
||||
}
|
||||
|
||||
impl Init {
|
||||
pub fn init(mut self) -> Result<StructuredOutput> {
|
||||
pub async fn init(mut self) -> Result<StructuredOutput> {
|
||||
// Project name defaults to directory name.
|
||||
if self.name.is_none() {
|
||||
self.name = Some(create::name_from_path(&self.path)?);
|
||||
}
|
||||
|
||||
// Perform a connectivity check so we just don't it around doing nothing if there's a network error
|
||||
if self.template.is_none() {
|
||||
create::connectivity_check().await?;
|
||||
}
|
||||
|
||||
// If no template is specified, use the default one and set the branch to the latest release.
|
||||
create::resolve_template_and_branch(&mut self.template, &mut self.branch);
|
||||
|
||||
@@ -64,7 +74,7 @@ impl Init {
|
||||
init: true,
|
||||
name: self.name,
|
||||
silent: self.yes,
|
||||
vcs: Some(cargo_generate::Vcs::Git),
|
||||
vcs: self.vcs,
|
||||
template_path: TemplatePath {
|
||||
auto_path: self.template,
|
||||
branch: self.branch,
|
||||
@@ -77,7 +87,7 @@ impl Init {
|
||||
};
|
||||
create::restore_cursor_on_sigint();
|
||||
let path = cargo_generate::generate(args)?;
|
||||
_ = create::post_create(&path);
|
||||
_ = create::post_create(&path, &self.vcs.unwrap_or(Vcs::Git));
|
||||
Ok(StructuredOutput::Success)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,10 +70,6 @@ pub(crate) enum Commands {
|
||||
#[clap(name = "run")]
|
||||
Run(run::RunArgs),
|
||||
|
||||
/// Build the assets for a specific target.
|
||||
#[clap(name = "assets")]
|
||||
BuildAssets(build_assets::BuildAssets),
|
||||
|
||||
/// Init a new project for Dioxus in the current directory (by default).
|
||||
/// Will attempt to keep your project in a good state.
|
||||
#[clap(name = "init")]
|
||||
@@ -103,6 +99,18 @@ pub(crate) enum Commands {
|
||||
/// Update the Dioxus CLI to the latest version.
|
||||
#[clap(name = "self-update")]
|
||||
SelfUpdate(update::SelfUpdate),
|
||||
|
||||
/// Run a dioxus build tool. IE `build-assets`, etc
|
||||
#[clap(name = "tools")]
|
||||
#[clap(subcommand)]
|
||||
Tools(BuildTools),
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub enum BuildTools {
|
||||
/// Build the assets for a specific target.
|
||||
#[clap(name = "assets")]
|
||||
BuildAssets(build_assets::BuildAssets),
|
||||
}
|
||||
|
||||
impl Display for Commands {
|
||||
@@ -119,8 +127,8 @@ impl Display for Commands {
|
||||
Commands::Check(_) => write!(f, "check"),
|
||||
Commands::Bundle(_) => write!(f, "bundle"),
|
||||
Commands::Run(_) => write!(f, "run"),
|
||||
Commands::BuildAssets(_) => write!(f, "assets"),
|
||||
Commands::SelfUpdate(_) => write!(f, "self-update"),
|
||||
Commands::Tools(_) => write!(f, "tools"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -156,8 +164,9 @@ pub mod styles {
|
||||
pub(crate) const INVALID: Style = AnsiColor::Yellow.on_default().effects(Effects::BOLD);
|
||||
|
||||
// extra styles for styling logs
|
||||
// we can style stuff using the ansi sequences like: "hotpatched in {GLOW_STYLE}{}{GLOW_STYLE:X}ms"
|
||||
// we can style stuff using the ansi sequences like: "hotpatched in {GLOW_STYLE}{}{GLOW_STYLE:#}ms"
|
||||
pub(crate) const GLOW_STYLE: Style = AnsiColor::Yellow.on_default();
|
||||
pub(crate) const NOTE_STYLE: Style = AnsiColor::Green.on_default();
|
||||
pub(crate) const LINK_STYLE: Style = AnsiColor::Blue.on_default();
|
||||
pub(crate) const ERROR_STYLE: Style = AnsiColor::Red.on_default();
|
||||
}
|
||||
@@ -86,12 +86,8 @@ where
|
||||
let mut subcommand = matches.subcommand();
|
||||
while let Some((name, sub_matches)) = subcommand {
|
||||
match name {
|
||||
"@client" => {
|
||||
client = Some(sub_matches);
|
||||
}
|
||||
"@server" => {
|
||||
server = Some(sub_matches);
|
||||
}
|
||||
"@client" => client = Some(sub_matches),
|
||||
"@server" => server = Some(sub_matches),
|
||||
_ => {}
|
||||
}
|
||||
subcommand = sub_matches.subcommand();
|
||||
@@ -117,7 +113,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Chain together multiple target commands
|
||||
#[derive(Debug, Subcommand, Clone)]
|
||||
#[command(subcommand_precedence_over_arg = true)]
|
||||
pub(crate) enum PlatformOverrides<T: Args> {
|
||||
|
||||
@@ -2,48 +2,50 @@ use crate::cli::*;
|
||||
use crate::Platform;
|
||||
use target_lexicon::Triple;
|
||||
|
||||
const HELP_HEADING: &str = "Target Options";
|
||||
|
||||
/// A single target to build for
|
||||
#[derive(Clone, Debug, Default, Deserialize, Parser)]
|
||||
pub(crate) struct TargetArgs {
|
||||
/// Build platform: support Web & Desktop [default: "default_platform"]
|
||||
#[clap(long, value_enum)]
|
||||
#[clap(long, value_enum, help_heading = HELP_HEADING)]
|
||||
pub(crate) platform: Option<Platform>,
|
||||
|
||||
/// Build in release mode [default: false]
|
||||
#[clap(long, short)]
|
||||
#[clap(long, short, help_heading = HELP_HEADING)]
|
||||
#[serde(default)]
|
||||
pub(crate) release: bool,
|
||||
|
||||
/// The package to build
|
||||
#[clap(short, long)]
|
||||
#[clap(short, long, help_heading = HELP_HEADING)]
|
||||
pub(crate) package: Option<String>,
|
||||
|
||||
/// Build a specific binary [default: ""]
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) bin: Option<String>,
|
||||
|
||||
/// Build a specific example [default: ""]
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) example: Option<String>,
|
||||
|
||||
/// Build the app with custom a profile
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) profile: Option<String>,
|
||||
|
||||
/// Space separated list of features to activate
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) features: Vec<String>,
|
||||
|
||||
/// Don't include the default features in the build
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) no_default_features: bool,
|
||||
|
||||
/// Include all features in the build
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) all_features: bool,
|
||||
|
||||
/// Rustc platform triple
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) target: Option<Triple>,
|
||||
|
||||
/// Extra arguments passed to `cargo`
|
||||
@@ -52,7 +54,7 @@ pub(crate) struct TargetArgs {
|
||||
///
|
||||
/// This can include stuff like, "--locked", "--frozen", etc. Note that `dx` sets many of these
|
||||
/// args directly from other args in this command.
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) cargo_args: Option<String>,
|
||||
|
||||
/// Extra arguments passed to `rustc`. This can be used to customize the linker, or other flags.
|
||||
@@ -62,36 +64,36 @@ pub(crate) struct TargetArgs {
|
||||
///
|
||||
/// cargo rustc -- -Clink-arg=-Wl,-blah
|
||||
///
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) rustc_args: Option<String>,
|
||||
|
||||
/// Skip collecting assets from dependencies [default: false]
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
#[serde(default)]
|
||||
pub(crate) skip_assets: bool,
|
||||
|
||||
/// Inject scripts to load the wasm and js files for your dioxus app if they are not already present [default: true]
|
||||
#[clap(long, default_value_t = true)]
|
||||
#[clap(long, default_value_t = true, help_heading = HELP_HEADING)]
|
||||
pub(crate) inject_loading_scripts: bool,
|
||||
|
||||
/// Experimental: Bundle split the wasm binary into multiple chunks based on `#[wasm_split]` annotations [default: false]
|
||||
#[clap(long, default_value_t = false)]
|
||||
#[clap(long, default_value_t = false, help_heading = HELP_HEADING)]
|
||||
pub(crate) wasm_split: bool,
|
||||
|
||||
/// Generate debug symbols for the wasm binary [default: true]
|
||||
///
|
||||
/// This will make the binary larger and take longer to compile, but will allow you to debug the
|
||||
/// wasm binary
|
||||
#[clap(long, default_value_t = true)]
|
||||
#[clap(long, default_value_t = true, help_heading = HELP_HEADING)]
|
||||
pub(crate) debug_symbols: bool,
|
||||
|
||||
/// Are we building for a device or just the simulator.
|
||||
/// If device is false, then we'll build for the simulator
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) device: Option<bool>,
|
||||
|
||||
/// The base path the build will fetch assets relative to. This will override the
|
||||
/// base path set in the `dioxus` config.
|
||||
#[clap(long)]
|
||||
#[clap(long, help_heading = HELP_HEADING)]
|
||||
pub(crate) base_path: Option<String>,
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser, Clone, Copy, Debug)]
|
||||
#[derive(Parser, Clone, Copy, Debug, Default)]
|
||||
pub struct Verbosity {
|
||||
/// Use verbose output [default: false]
|
||||
#[clap(long, global = true)]
|
||||
@@ -13,4 +13,16 @@ pub struct Verbosity {
|
||||
/// Output logs in JSON format
|
||||
#[clap(long, global = true)]
|
||||
pub(crate) json_output: bool,
|
||||
|
||||
/// Assert that `Cargo.lock` will remain unchanged
|
||||
#[clap(long, global = true, help_heading = "Manifest Options")]
|
||||
pub(crate) locked: bool,
|
||||
|
||||
/// Run without accessing the network
|
||||
#[clap(long, global = true, help_heading = "Manifest Options")]
|
||||
pub(crate) offline: bool,
|
||||
|
||||
/// Equivalent to specifying both --locked and --offline
|
||||
#[clap(long, global = true, help_heading = "Manifest Options")]
|
||||
pub(crate) frozen: bool,
|
||||
}
|
||||
@@ -27,24 +27,27 @@ pub(crate) enum Error {
|
||||
#[error("Invalid proxy URL: {0}")]
|
||||
InvalidProxy(#[from] hyper::http::uri::InvalidUri),
|
||||
|
||||
#[error("Failed to establish proxy: {0}")]
|
||||
#[error("Establishing proxy: {0}")]
|
||||
ProxySetup(String),
|
||||
|
||||
#[error("Failed to bundle project: {0}")]
|
||||
#[error("Bundling project: {0}")]
|
||||
BundleFailed(#[from] tauri_bundler::Error),
|
||||
|
||||
#[error("Failed to perform hotpatch: {0}")]
|
||||
#[error("Performing hotpatch: {0}")]
|
||||
PatchingFailed(#[from] crate::build::PatchError),
|
||||
|
||||
#[error("Failed to read object file: {0}")]
|
||||
#[error("Reading object file: {0}")]
|
||||
ObjectReadFailed(#[from] object::Error),
|
||||
|
||||
#[error("{0}")]
|
||||
CapturedPanic(String),
|
||||
|
||||
#[error("Failed to render template: {0}")]
|
||||
#[error("Rendering template error: {0}")]
|
||||
TemplateParse(#[from] handlebars::RenderError),
|
||||
|
||||
#[error("Network connectivity error: {0}")]
|
||||
Network(String),
|
||||
|
||||
#[error(transparent)]
|
||||
Other(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ async fn main() {
|
||||
let args = TraceController::initialize();
|
||||
let result = match args.action {
|
||||
Commands::Translate(opts) => opts.translate(),
|
||||
Commands::New(opts) => opts.create(),
|
||||
Commands::Init(opts) => opts.init(),
|
||||
Commands::New(opts) => opts.create().await,
|
||||
Commands::Init(opts) => opts.init().await,
|
||||
Commands::Config(opts) => opts.config().await,
|
||||
Commands::Autoformat(opts) => opts.autoformat().await,
|
||||
Commands::Check(opts) => opts.check().await,
|
||||
@@ -61,8 +61,8 @@ async fn main() {
|
||||
Commands::Serve(opts) => opts.serve().await,
|
||||
Commands::Bundle(opts) => opts.bundle().await,
|
||||
Commands::Run(opts) => opts.run().await,
|
||||
Commands::BuildAssets(opts) => opts.run().await,
|
||||
Commands::SelfUpdate(opts) => opts.self_update().await,
|
||||
Commands::Tools(BuildTools::BuildAssets(opts)) => opts.run().await,
|
||||
};
|
||||
|
||||
// Provide a structured output for third party tools that can consume the output of the CLI
|
||||
@@ -71,7 +71,10 @@ async fn main() {
|
||||
tracing::debug!(json = ?output);
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("{err}");
|
||||
eprintln!(
|
||||
"{ERROR_STYLE}failed:{ERROR_STYLE:#} {err}",
|
||||
ERROR_STYLE = styles::ERROR_STYLE
|
||||
);
|
||||
|
||||
tracing::error!(
|
||||
json = ?StructuredOutput::Error {
|
||||
|
||||
@@ -37,25 +37,32 @@ pub(crate) use update::*;
|
||||
/// - I want us to be able to detect a `server_fn` in the project and then upgrade from a static server
|
||||
/// to a dynamic one on the fly.
|
||||
pub(crate) async fn serve_all(args: ServeArgs, tracer: &mut TraceController) -> Result<()> {
|
||||
// This is our default splash screen. We might want to make this a fancier splash screen in the future
|
||||
// Also, these commands might not be the most important, but it's all we've got enabled right now
|
||||
tracing::info!(
|
||||
r#"-----------------------------------------------------------------
|
||||
Serving your Dioxus app! 🚀
|
||||
• Press {GLOW_STYLE}`ctrl+c`{GLOW_STYLE:#} to exit the server
|
||||
• Press {GLOW_STYLE}`r`{GLOW_STYLE:#} to rebuild the app
|
||||
• Press {GLOW_STYLE}`p`{GLOW_STYLE:#} to toggle automatic rebuilds
|
||||
• Press {GLOW_STYLE}`v`{GLOW_STYLE:#} to toggle verbose logging
|
||||
• Press {GLOW_STYLE}`/`{GLOW_STYLE:#} for more commands and shortcuts
|
||||
Learn more at {LINK_STYLE}https://dioxuslabs.com/learn/0.7/getting_started{LINK_STYLE:#}
|
||||
----------------------------------------------------------------"#,
|
||||
);
|
||||
|
||||
// Load the args into a plan, resolving all tooling, build dirs, arguments, decoding the multi-target, etc
|
||||
let mut builder = AppServer::start(args).await?;
|
||||
let mut devserver = WebServer::start(&builder)?;
|
||||
let mut screen = Output::start(builder.interactive).await?;
|
||||
|
||||
// This is our default splash screen. We might want to make this a fancier splash screen in the future
|
||||
// Also, these commands might not be the most important, but it's all we've got enabled right now
|
||||
tracing::info!(
|
||||
r#"-----------------------------------------------------------------
|
||||
Serving your app: {binname}! 🚀
|
||||
• Press {GLOW_STYLE}`ctrl+c`{GLOW_STYLE:#} to exit the server
|
||||
• Press {GLOW_STYLE}`r`{GLOW_STYLE:#} to rebuild the app
|
||||
• Press {GLOW_STYLE}`p`{GLOW_STYLE:#} to toggle automatic rebuilds
|
||||
• Press {GLOW_STYLE}`v`{GLOW_STYLE:#} to toggle verbose logging
|
||||
• Press {GLOW_STYLE}`/`{GLOW_STYLE:#} for more commands and shortcuts{extra}
|
||||
----------------------------------------------------------------"#,
|
||||
binname = builder.client.build.executable_name(),
|
||||
extra = if builder.client.build.using_dioxus_explicitly {
|
||||
format!(
|
||||
"\n Learn more at {LINK_STYLE}https://dioxuslabs.com/learn/0.7/getting_started{LINK_STYLE:#}"
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
);
|
||||
|
||||
loop {
|
||||
// Draw the state of the server to the screen
|
||||
screen.render(&builder, &devserver);
|
||||
|
||||
@@ -165,7 +165,7 @@ impl Output {
|
||||
}
|
||||
|
||||
pub(crate) fn remote_shutdown(interactive: bool) -> io::Result<()> {
|
||||
if interactive {
|
||||
if interactive && crossterm::terminal::is_raw_mode_enabled().unwrap_or(true) {
|
||||
stdout()
|
||||
.execute(Show)?
|
||||
.execute(DisableFocusChange)?
|
||||
@@ -766,21 +766,23 @@ impl Output {
|
||||
let links_list: [_; 2] =
|
||||
Layout::vertical([Constraint::Length(1), Constraint::Length(1)]).areas(bottom);
|
||||
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
"Read the docs: ".gray(),
|
||||
"https://dioxuslabs.com/0.6/docs".blue(),
|
||||
])),
|
||||
links_list[0],
|
||||
);
|
||||
if state.runner.client.build.using_dioxus_explicitly {
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
"Read the docs: ".gray(),
|
||||
"https://dioxuslabs.com/0.6/docs".blue(),
|
||||
])),
|
||||
links_list[0],
|
||||
);
|
||||
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
"Video tutorials: ".gray(),
|
||||
"https://youtube.com/@DioxusLabs".blue(),
|
||||
])),
|
||||
links_list[1],
|
||||
);
|
||||
frame.render_widget(
|
||||
Paragraph::new(Line::from(vec![
|
||||
"Video tutorials: ".gray(),
|
||||
"https://youtube.com/@DioxusLabs".blue(),
|
||||
])),
|
||||
links_list[1],
|
||||
);
|
||||
}
|
||||
|
||||
let cmds = [
|
||||
"",
|
||||
|
||||
@@ -19,6 +19,35 @@ impl TailwindCli {
|
||||
Self { version }
|
||||
}
|
||||
|
||||
pub(crate) async fn run_once(
|
||||
manifest_dir: PathBuf,
|
||||
input_path: Option<PathBuf>,
|
||||
output_path: Option<PathBuf>,
|
||||
) -> Result<()> {
|
||||
let Some(tailwind) = Self::autodetect(&manifest_dir) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
if !tailwind.get_binary_path()?.exists() {
|
||||
tracing::info!("Installing tailwindcss@{}", tailwind.version);
|
||||
tailwind.install_github().await?;
|
||||
}
|
||||
|
||||
let output = tailwind
|
||||
.run(&manifest_dir, input_path, output_path, false)?
|
||||
.wait_with_output()
|
||||
.await?;
|
||||
|
||||
if !output.stderr.is_empty() {
|
||||
tracing::warn!(
|
||||
"Warnings while running tailwind: {}",
|
||||
String::from_utf8_lossy(&output.stdout)
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn serve(
|
||||
manifest_dir: PathBuf,
|
||||
input_path: Option<PathBuf>,
|
||||
@@ -36,7 +65,7 @@ impl TailwindCli {
|
||||
|
||||
// the tw watcher blocks on stdin, and `.wait()` will drop stdin
|
||||
// unfortunately the tw watcher just deadlocks in this case, so we take the stdin manually
|
||||
let mut proc = tailwind.watch(&manifest_dir, input_path, output_path)?;
|
||||
let mut proc = tailwind.run(&manifest_dir, input_path, output_path, true)?;
|
||||
let stdin = proc.stdin.take();
|
||||
proc.wait().await?;
|
||||
drop(stdin);
|
||||
@@ -76,11 +105,12 @@ impl TailwindCli {
|
||||
Self::new(Self::V3_TAG.to_string())
|
||||
}
|
||||
|
||||
pub(crate) fn watch(
|
||||
pub(crate) fn run(
|
||||
&self,
|
||||
manifest_dir: &Path,
|
||||
input_path: Option<PathBuf>,
|
||||
output_path: Option<PathBuf>,
|
||||
watch: bool,
|
||||
) -> Result<tokio::process::Child> {
|
||||
let binary_path = self.get_binary_path()?;
|
||||
|
||||
@@ -110,7 +140,7 @@ impl TailwindCli {
|
||||
.arg(input_path)
|
||||
.arg("--output")
|
||||
.arg(output_path)
|
||||
.arg("--watch")
|
||||
.args(watch.then_some("--watch"))
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::null())
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
use crate::styles::GLOW_STYLE;
|
||||
use crate::CliSettings;
|
||||
use crate::Result;
|
||||
use crate::{config::DioxusConfig, AndroidTools};
|
||||
use anyhow::Context;
|
||||
use ignore::gitignore::Gitignore;
|
||||
use krates::{semver::Version, KrateDetails};
|
||||
use krates::{semver::Version, KrateDetails, LockOptions};
|
||||
use krates::{Cmd, Krates, NodeId};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::{collections::HashSet, path::Path};
|
||||
use std::{path::PathBuf, time::Duration};
|
||||
use target_lexicon::Triple;
|
||||
use tokio::process::Command;
|
||||
|
||||
@@ -34,12 +35,50 @@ impl Workspace {
|
||||
return Ok(ws.clone());
|
||||
}
|
||||
|
||||
let cmd = Cmd::new();
|
||||
let mut builder = krates::Builder::new();
|
||||
builder.workspace(true);
|
||||
let krates = builder
|
||||
.build(cmd, |_| {})
|
||||
.context("Failed to run cargo metadata")?;
|
||||
let krates_future = tokio::task::spawn_blocking(|| {
|
||||
let manifest_options = crate::logging::VERBOSITY.get().unwrap();
|
||||
let lock_options = LockOptions {
|
||||
frozen: manifest_options.frozen,
|
||||
locked: manifest_options.locked,
|
||||
offline: manifest_options.offline,
|
||||
};
|
||||
|
||||
let mut cmd = Cmd::new();
|
||||
cmd.lock_opts(lock_options);
|
||||
|
||||
let mut builder = krates::Builder::new();
|
||||
builder.workspace(true);
|
||||
let res = builder
|
||||
.build(cmd, |_| {})
|
||||
.context("Failed to run cargo metadata");
|
||||
|
||||
if !lock_options.offline {
|
||||
if let Ok(res) = std::env::var("SIMULATE_SLOW_NETWORK") {
|
||||
std::thread::sleep(Duration::from_secs(res.parse().unwrap_or(5)));
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
});
|
||||
|
||||
let spin_future = async move {
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
println!("{GLOW_STYLE}warning{GLOW_STYLE:#}: Waiting for cargo-metadata...");
|
||||
tokio::time::sleep(Duration::from_millis(2000)).await;
|
||||
for x in 1..=5 {
|
||||
tokio::time::sleep(Duration::from_millis(2000)).await;
|
||||
println!(
|
||||
"{GLOW_STYLE}warning{GLOW_STYLE:#}: ({x}/5) Taking a while, maybe your internet is down?"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let krates = tokio::select! {
|
||||
f = krates_future => f.context("failed to run cargo metadata")??,
|
||||
_ = spin_future => return Err(crate::Error::Network(
|
||||
"cargo metadata took too long to respond, try again with --offline".to_string(),
|
||||
)),
|
||||
};
|
||||
|
||||
let settings = CliSettings::global_or_default();
|
||||
let sysroot = Command::new("rustc")
|
||||
|
||||
Reference in new issue
Block a user