From 4320252f4607787f1fc1fa50a2ce99d8b2afab76 Mon Sep 17 00:00:00 2001 From: Brian May Date: Sun, 22 Dec 2024 17:33:50 +1100 Subject: [PATCH] feat: add cli support to build assets from executable See https://github.com/DioxusLabs/dioxus/discussions/3402#discussioncomment-11632372 --- packages/cli/src/cli/build_assets.rs | 63 ++++++++++++++++++++++++++++ packages/cli/src/cli/mod.rs | 6 +++ packages/cli/src/main.rs | 1 + 3 files changed, 70 insertions(+) create mode 100644 packages/cli/src/cli/build_assets.rs diff --git a/packages/cli/src/cli/build_assets.rs b/packages/cli/src/cli/build_assets.rs new file mode 100644 index 0000000000..3a68346598 --- /dev/null +++ b/packages/cli/src/cli/build_assets.rs @@ -0,0 +1,63 @@ +use std::{ + fs::create_dir_all, + path::{Path, PathBuf}, +}; + +use crate::{Result, StructuredOutput}; +use clap::Parser; +use dioxus_cli_opt::{process_file_to, AssetManifest}; +use tracing::debug; + +#[derive(Clone, Debug, Parser)] +pub struct BuildAssets { + /// The source executable to build assets for. + pub(crate) executable: PathBuf, + + /// The source directory for the assets. + pub(crate) source: PathBuf, + + /// The destination directory for the assets. + pub(crate) destination: PathBuf, +} + +impl BuildAssets { + pub async fn run(self) -> Result { + let mut manifest = AssetManifest::default(); + manifest.add_from_object_path(&self.executable)?; + + create_dir_all(&self.destination)?; + for (path, asset) in manifest.assets.iter() { + let relative_path = turn_asset_path_into_relative_path(path); + let source_path = self.source.join(relative_path); + let destination_path = self.destination.join(asset.bundled_path()); + debug!( + "Processing asset {} --> {} {:#?}", + source_path.display(), + destination_path.display(), + asset + ); + process_file_to(asset.options(), &source_path, &destination_path)?; + } + + Ok(StructuredOutput::Success) + } +} + +/// Hack to turn an absolute path into a relative path. +/// +/// For example, the executable path might have the absolute path: +/// "/build/lknys4lnckh88mxvi7pba1zsvgfyh1a1-source/assets/header.svg +/// +/// And we need a relative path to the source directory: +/// "assets/header.svg" +fn turn_asset_path_into_relative_path(asset_path: &Path) -> PathBuf { + let components = asset_path + .components() + .skip_while(|c| c.as_os_str() != "assets") + .collect::>(); + + components.iter().fold(PathBuf::new(), |mut acc, c| { + acc.push(c); + acc + }) +} diff --git a/packages/cli/src/cli/mod.rs b/packages/cli/src/cli/mod.rs index 1c3844e106..8e1fc2d227 100644 --- a/packages/cli/src/cli/mod.rs +++ b/packages/cli/src/cli/mod.rs @@ -1,5 +1,6 @@ pub(crate) mod autoformat; pub(crate) mod build; +pub(crate) mod build_assets; pub(crate) mod bundle; pub(crate) mod check; pub(crate) mod clean; @@ -95,6 +96,10 @@ pub(crate) enum Commands { #[clap(subcommand)] #[clap(name = "config")] Config(config::Config), + + /// Build the assets for a specific target. + #[clap(name = "build_assets")] + BuildAssets(build_assets::BuildAssets), } impl Display for Commands { @@ -112,6 +117,7 @@ impl Display for Commands { Commands::Bundle(_) => write!(f, "bundle"), Commands::Run(_) => write!(f, "run"), Commands::Doctor(_) => write!(f, "doctor"), + Commands::BuildAssets(_) => write!(f, "build_assets"), } } } diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index 3f92e9d0f5..0bdd69d81c 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -53,6 +53,7 @@ async fn main() { Commands::Bundle(opts) => opts.bundle().await, Commands::Run(opts) => opts.run().await, Commands::Doctor(opts) => opts.run().await, + Commands::BuildAssets(opts) => opts.run().await, }; // Provide a structured output for third party tools that can consume the output of the CLI