CLI fixes for hotpatching the playground (#4715)
* add component subcommand * add dx component add, remove and list commands * handle rust dependencies * handle component dependencies * fetch remote registries * sort components before listing them * remove local dependency * move te component manifest into the dioxus workspace * add additional instalation instructions the first time the component module is created * fix mod name * fix clippy * improve docs and move to the main branch of components * fix typos * more typos * undo const-serialize changes * remove a few unwraps * Allow adding multiple components at once and add a `--all` flag * add options to the config for the base path, global asset path and default registry * component_path -> component_dir * component_dir is always relative to the crate root * fix clippy * fix hot patching with a base path * read the hot patch file from stdin instead of a CLI arg to allow for longer inputs * fix request imports * wip: code style changes * rename to "components" instead of "component" * bump lock * move to method on request * read until eof in the case of pretty json * strip is now copy --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
1 parent
79613f9db9
commit
987e41de16
6 files changed
+1715
-1739
No files matched your search
Generated
+1654
-1698
File diff suppressed because it is too large.
Load diff
+1
-1
@@ -250,7 +250,7 @@ futures-util = { version = "0.3", default-features = false }
|
|||||||
rustc-hash = "2.1.1"
|
rustc-hash = "2.1.1"
|
||||||
wasm-bindgen = "0.2.100"
|
wasm-bindgen = "0.2.100"
|
||||||
wasm-bindgen-futures = "0.4.50"
|
wasm-bindgen-futures = "0.4.50"
|
||||||
js-sys = "0.3.77"
|
js-sys = "0.3"
|
||||||
web-sys = { version = "0.3.77", default-features = false }
|
web-sys = { version = "0.3.77", default-features = false }
|
||||||
html_parser = "0.7.0"
|
html_parser = "0.7.0"
|
||||||
thiserror = "2.0.12"
|
thiserror = "2.0.12"
|
||||||
|
|||||||
@@ -640,7 +640,6 @@ impl AppBuilder {
|
|||||||
) -> Result<JumpTable> {
|
) -> Result<JumpTable> {
|
||||||
let original = self.build.main_exe();
|
let original = self.build.main_exe();
|
||||||
let new = self.build.patch_exe(res.time_start);
|
let new = self.build.patch_exe(res.time_start);
|
||||||
let triple = self.build.triple.clone();
|
|
||||||
let asset_dir = self.build.asset_dir();
|
let asset_dir = self.build.asset_dir();
|
||||||
|
|
||||||
// Hotpatch asset!() calls
|
// Hotpatch asset!() calls
|
||||||
@@ -688,7 +687,7 @@ impl AppBuilder {
|
|||||||
|
|
||||||
tracing::debug!("Patching {} -> {}", original.display(), new.display());
|
tracing::debug!("Patching {} -> {}", original.display(), new.display());
|
||||||
|
|
||||||
let mut jump_table = crate::build::create_jump_table(&new, &triple, cache)?;
|
let mut jump_table = self.build.create_jump_table(&new, cache)?;
|
||||||
|
|
||||||
// If it's android, we need to copy the assets to the device and then change the location of the patch
|
// If it's android, we need to copy the assets to the device and then change the location of the patch
|
||||||
if self.build.bundle == BundleFormat::Android {
|
if self.build.bundle == BundleFormat::Android {
|
||||||
@@ -697,16 +696,6 @@ impl AppBuilder {
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebase the wasm binary to be relocatable once the jump table is generated
|
|
||||||
if triple.architecture == target_lexicon::Architecture::Wasm32 {
|
|
||||||
// Make sure we use the dir relative to the public dir, so the web can load it as a proper URL
|
|
||||||
//
|
|
||||||
// ie we would've shipped `/Users/foo/Projects/dioxus/target/dx/project/debug/web/public/wasm/lib.wasm`
|
|
||||||
// but we want to ship `/wasm/lib.wasm`
|
|
||||||
jump_table.lib =
|
|
||||||
PathBuf::from("/").join(jump_table.lib.strip_prefix(self.build.root_dir()).unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
let changed_files = match &res.mode {
|
let changed_files = match &res.mode {
|
||||||
BuildMode::Thin { changed_files, .. } => changed_files.clone(),
|
BuildMode::Thin { changed_files, .. } => changed_files.clone(),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
|
|||||||
@@ -290,24 +290,7 @@ impl HotpatchModuleCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a jump table for the given original and patch files.
|
pub fn create_windows_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Result<JumpTable> {
|
||||||
pub fn create_jump_table(
|
|
||||||
patch: &Path,
|
|
||||||
triple: &Triple,
|
|
||||||
cache: &HotpatchModuleCache,
|
|
||||||
) -> Result<JumpTable> {
|
|
||||||
// Symbols are stored differently based on the platform, so we need to handle them differently.
|
|
||||||
// - Wasm requires the walrus crate and actually modifies the patch file
|
|
||||||
// - windows requires the pdb crate and pdb files
|
|
||||||
// - nix requires the object crate
|
|
||||||
match triple.operating_system {
|
|
||||||
OperatingSystem::Windows => create_windows_jump_table(patch, cache),
|
|
||||||
_ if triple.architecture == Architecture::Wasm32 => create_wasm_jump_table(patch, cache),
|
|
||||||
_ => create_native_jump_table(patch, triple, cache),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn create_windows_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Result<JumpTable> {
|
|
||||||
use pdb::FallibleIterator;
|
use pdb::FallibleIterator;
|
||||||
let old_name_to_addr = &cache.symbol_table;
|
let old_name_to_addr = &cache.symbol_table;
|
||||||
|
|
||||||
@@ -361,7 +344,7 @@ fn create_windows_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Resul
|
|||||||
///
|
///
|
||||||
/// This does not work for WASM since the `object` crate does not support emitting the WASM format,
|
/// This does not work for WASM since the `object` crate does not support emitting the WASM format,
|
||||||
/// and because WASM requires more logic to handle the wasm-bindgen transformations.
|
/// and because WASM requires more logic to handle the wasm-bindgen transformations.
|
||||||
fn create_native_jump_table(
|
pub fn create_native_jump_table(
|
||||||
patch: &Path,
|
patch: &Path,
|
||||||
triple: &Triple,
|
triple: &Triple,
|
||||||
cache: &HotpatchModuleCache,
|
cache: &HotpatchModuleCache,
|
||||||
@@ -416,7 +399,7 @@ fn create_native_jump_table(
|
|||||||
/// to manually satisfy them here, removing their need to be imported.
|
/// to manually satisfy them here, removing their need to be imported.
|
||||||
///
|
///
|
||||||
/// <https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md>
|
/// <https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md>
|
||||||
fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Result<JumpTable> {
|
pub fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Result<JumpTable> {
|
||||||
let name_to_ifunc_old = &cache.symbol_ifunc_map;
|
let name_to_ifunc_old = &cache.symbol_ifunc_map;
|
||||||
let old = &cache.old_wasm;
|
let old = &cache.old_wasm;
|
||||||
let old_symbols =
|
let old_symbols =
|
||||||
|
|||||||
@@ -349,6 +349,7 @@ use std::{
|
|||||||
},
|
},
|
||||||
time::{SystemTime, UNIX_EPOCH},
|
time::{SystemTime, UNIX_EPOCH},
|
||||||
};
|
};
|
||||||
|
use subsecond_types::JumpTable;
|
||||||
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
use target_lexicon::{Architecture, OperatingSystem, Triple};
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use tokio::{io::AsyncBufReadExt, process::Command};
|
use tokio::{io::AsyncBufReadExt, process::Command};
|
||||||
@@ -2334,6 +2335,48 @@ impl BuildRequest {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn create_jump_table(
|
||||||
|
&self,
|
||||||
|
patch: &Path,
|
||||||
|
cache: &HotpatchModuleCache,
|
||||||
|
) -> Result<JumpTable> {
|
||||||
|
use crate::build::patch::{
|
||||||
|
create_native_jump_table, create_wasm_jump_table, create_windows_jump_table,
|
||||||
|
};
|
||||||
|
|
||||||
|
let root_dir = self.root_dir();
|
||||||
|
let base_path = self.base_path();
|
||||||
|
let triple = &self.triple;
|
||||||
|
|
||||||
|
// Symbols are stored differently based on the platform, so we need to handle them differently.
|
||||||
|
// - Wasm requires the walrus crate and actually modifies the patch file
|
||||||
|
// - windows requires the pdb crate and pdb files
|
||||||
|
// - nix requires the object crate
|
||||||
|
let mut jump_table = match triple.operating_system {
|
||||||
|
OperatingSystem::Windows => create_windows_jump_table(patch, cache)?,
|
||||||
|
_ if triple.architecture == Architecture::Wasm32 => {
|
||||||
|
create_wasm_jump_table(patch, cache)?
|
||||||
|
}
|
||||||
|
_ => create_native_jump_table(patch, triple, cache)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
// root_dir: &Path,
|
||||||
|
// base_path: Option<&str>,
|
||||||
|
// Rebase the wasm binary to be relocatable once the jump table is generated
|
||||||
|
if triple.architecture == target_lexicon::Architecture::Wasm32 {
|
||||||
|
// Make sure we use the dir relative to the public dir, so the web can load it as a proper URL
|
||||||
|
//
|
||||||
|
// ie we would've shipped `/Users/foo/Projects/dioxus/target/dx/project/debug/web/public/wasm/lib.wasm`
|
||||||
|
// but we want to ship `/wasm/lib.wasm`
|
||||||
|
jump_table.lib = PathBuf::from(
|
||||||
|
"/".to_string() + base_path.unwrap_or_default().trim_start_matches('/'),
|
||||||
|
)
|
||||||
|
.join(jump_table.lib.strip_prefix(root_dir).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(jump_table)
|
||||||
|
}
|
||||||
|
|
||||||
/// Automatically detect the linker flavor based on the target triple and any custom linkers.
|
/// Automatically detect the linker flavor based on the target triple and any custom linkers.
|
||||||
///
|
///
|
||||||
/// This tries to replicate what rustc does when selecting the linker flavor based on the linker
|
/// This tries to replicate what rustc does when selecting the linker flavor based on the linker
|
||||||
@@ -3567,7 +3610,7 @@ impl BuildRequest {
|
|||||||
|
|
||||||
// Get the strip setting from the profile or the profile it inherits from
|
// Get the strip setting from the profile or the profile it inherits from
|
||||||
fn get_strip(profile: &Profile, profiles: &Profiles) -> Option<StripSetting> {
|
fn get_strip(profile: &Profile, profiles: &Profiles) -> Option<StripSetting> {
|
||||||
profile.strip.clone().or_else(|| {
|
profile.strip.or_else(|| {
|
||||||
// If we can't find the strip setting, check if we inherit from another profile
|
// If we can't find the strip setting, check if we inherit from another profile
|
||||||
profile.inherits.as_ref().and_then(|inherits| {
|
profile.inherits.as_ref().and_then(|inherits| {
|
||||||
let profile = match inherits.as_str() {
|
let profile = match inherits.as_str() {
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ use crate::{
|
|||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use dioxus_dx_wire_format::StructuredBuildArtifacts;
|
use dioxus_dx_wire_format::StructuredBuildArtifacts;
|
||||||
|
use std::io::Read;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
const HELP_HEADING: &str = "Hotpatching a binary";
|
const HELP_HEADING: &str = "Hotpatching a binary";
|
||||||
|
|
||||||
/// Patches a single binary, but takes the same arguments as a `cargo build`.
|
/// Patches a single binary, but takes the same arguments as a `cargo build` and the serialized output from `dx build --fat-binary` as input.
|
||||||
|
///
|
||||||
|
/// This is intended to be used with something like `dx build --fat-binary >> output.json` and then
|
||||||
|
/// `cat output.json | dx hotpatch --aslr-reference 0x12345678` to produce a hotpatched binary.
|
||||||
///
|
///
|
||||||
/// By default, patches the client, but you can set patch_server to true to patch the server instead.
|
/// By default, patches the client, but you can set patch_server to true to patch the server instead.
|
||||||
#[derive(Clone, Debug, Parser)]
|
#[derive(Clone, Debug, Parser)]
|
||||||
@@ -18,10 +22,6 @@ pub struct HotpatchTip {
|
|||||||
#[clap(long, num_args = 0..=1, default_missing_value="true", help_heading = HELP_HEADING)]
|
#[clap(long, num_args = 0..=1, default_missing_value="true", help_heading = HELP_HEADING)]
|
||||||
pub patch_server: Option<bool>,
|
pub patch_server: Option<bool>,
|
||||||
|
|
||||||
/// The serialized output from the `dx build --fat-binary` command
|
|
||||||
#[clap(long, help_heading = HELP_HEADING)]
|
|
||||||
pub serialized_artifacts: String,
|
|
||||||
|
|
||||||
/// The ASLR reference of the running app being patched. Used to generate sensible offsets for patched code.
|
/// The ASLR reference of the running app being patched. Used to generate sensible offsets for patched code.
|
||||||
#[clap(long, help_heading = HELP_HEADING)]
|
#[clap(long, help_heading = HELP_HEADING)]
|
||||||
pub aslr_reference: u64,
|
pub aslr_reference: u64,
|
||||||
@@ -49,8 +49,13 @@ impl HotpatchTip {
|
|||||||
&targets.client
|
&targets.client
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut serialized_artifacts = String::new();
|
||||||
|
std::io::stdin()
|
||||||
|
.lock()
|
||||||
|
.read_to_string(&mut serialized_artifacts)
|
||||||
|
.context("Failed to read serialized build artifacts from stdin")?;
|
||||||
let structured_build_artifacts =
|
let structured_build_artifacts =
|
||||||
serde_json::from_str::<StructuredBuildArtifacts>(&self.serialized_artifacts)
|
serde_json::from_str::<StructuredBuildArtifacts>(&serialized_artifacts)
|
||||||
.context("Failed to parse structured build artifacts")?;
|
.context("Failed to parse structured build artifacts")?;
|
||||||
|
|
||||||
let StructuredBuildArtifacts {
|
let StructuredBuildArtifacts {
|
||||||
@@ -82,7 +87,7 @@ impl HotpatchTip {
|
|||||||
let patch_exe = request.patch_exe(artifacts.time_start);
|
let patch_exe = request.patch_exe(artifacts.time_start);
|
||||||
|
|
||||||
Ok(StructuredOutput::Hotpatch {
|
Ok(StructuredOutput::Hotpatch {
|
||||||
jump_table: crate::build::create_jump_table(&patch_exe, &request.triple, &cache)?,
|
jump_table: request.create_jump_table(&patch_exe, &cache)?,
|
||||||
artifacts: artifacts.into_structured_output(),
|
artifacts: artifacts.into_structured_output(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user