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:
Jonathan Kelley authored and GitHub committed 2025-06-24 18:21:25 -07:00
1 parent a899f9f08e
commit dd53ce72a7
14 files changed
+279 -93

No files matched your search

+22
View File
@@ -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());
+58 -6
View File
@@ -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)]
+14 -4
View File
@@ -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)
}
}
+15 -6
View File
@@ -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();
}
+2 -7
View File
@@ -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> {
+20 -18
View File
@@ -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>,
}
+13 -1
View File
@@ -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,
}
+8 -5
View File
@@ -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),
}
+7 -4
View File
@@ -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 {
+21 -14
View File
@@ -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);
+17 -15
View File
@@ -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 = [
"",
+33 -3
View File
@@ -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())
+47 -8
View File
@@ -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")