diff --git a/doc/psidk/src/development/services/rust-service/package.md b/doc/psidk/src/development/services/rust-service/package.md index 14f2fe3f6..882d48cba 100644 --- a/doc/psidk/src/development/services/rust-service/package.md +++ b/doc/psidk/src/development/services/rust-service/package.md @@ -12,6 +12,7 @@ The available fields are: - `plugin`: May be present on any crate that builds a service. The value is a crate that should be built with `cargo component` and uploaded as `/plugin.wasm` - `flags`: [Flags](../../../specifications/data-formats/package.md#serviceservicejson) for the service. - `postinstall`: An array of actions to run when the package is installed. May be specified on the top-level crate or on any service. Actions from a single `postinstall` will be run in order. The order of actions from multiple crates is unspecified. +- `data`: An array of `{src, dst}` paths to upload to the service. `src` is relative to the location of Cargo.toml. If `src` is a directory, its contents will be included recursively. - `dependencies`: Additional packages, not build by cargo, that the package depends on. Example: @@ -32,6 +33,8 @@ server = "example" plugin = "example-plugin" # Run the service's init action postinstall = [{sender="tpack", service="tpack", method="init", rawData="0000"}] +# Upload the UI +data = [{src = "ui/", dst = "/"}] [package.metadata.psibase.dependencies] HttpServer = "0.12.0" diff --git a/rust/cargo-psibase/src/package.rs b/rust/cargo-psibase/src/package.rs index 1ec19267c..cdc82a29f 100644 --- a/rust/cargo-psibase/src/package.rs +++ b/rust/cargo-psibase/src/package.rs @@ -14,6 +14,12 @@ use std::io::{BufReader, Seek, Write}; use std::path::{Path, PathBuf}; use zip::write::{FileOptions, ZipWriter}; +#[derive(Serialize, Deserialize, Default)] +struct DataFiles { + src: String, + dst: String, +} + #[derive(Serialize, Deserialize, Default)] #[serde(default)] pub struct PsibaseMetadata { @@ -25,6 +31,7 @@ pub struct PsibaseMetadata { dependencies: HashMap, services: Option>, postinstall: Option>, + data: Vec, } impl PsibaseMetadata { @@ -104,7 +111,7 @@ fn should_build_package( filename: &Path, meta: &Meta, services: &[(&String, ServiceInfo, PathBuf)], - data: &[(&String, &str, PathBuf)], + data: &[(&String, String, PathBuf)], postinstall: &[Action], ) -> Result { let timestamp = if let Ok(metadata) = filename.metadata() { @@ -148,7 +155,7 @@ fn should_build_package( return Ok(true); } let account: AccountNumber = service.parse()?; - new_data.push((account.value, *dest)); + new_data.push((account.value, dest.as_str())); } existing_data.sort(); new_data.sort(); @@ -164,6 +171,35 @@ fn should_build_package( Ok(false) } +fn add_files<'a>( + service: &'a String, + src: &Path, + dest: &String, + out: &mut Vec<(&'a String, String, PathBuf)>, +) -> Result<(), anyhow::Error> { + if src.is_file() { + out.push((service, dest.clone(), src.to_path_buf())); + } else if src.is_dir() { + for entry in src.read_dir()? { + let entry = entry?; + add_files( + service, + &entry.path(), + &(dest.clone() + + "/" + + entry.file_name().to_str().ok_or_else(|| { + anyhow!( + "non-unicode file name: {}", + entry.file_name().to_string_lossy() + ) + })?), + out, + )?; + } + } + Ok(()) +} + pub async fn build_package( args: &Args, metadata: &MetadataIndex<'_>, @@ -257,6 +293,17 @@ pub async fn build_package( }; plugins.push((plugin, &package.name, "/plugin.wasm", &id.repr)); } + for data in &pmeta.data { + let src = package.manifest_path.parent().unwrap().join(&data.src); + let mut dest = data.dst.clone(); + if !dest.starts_with('/') { + dest = "/".to_string() + &dest; + } + if dest.ends_with('/') { + dest.pop(); + } + add_files(&package.name, src.as_std_path(), &dest, &mut data_files)?; + } services.push((&package.name, info, &package.id.repr)); if let Some(actions) = &pmeta.postinstall { postinstall.extend_from_slice(actions.as_slice()); @@ -313,7 +360,7 @@ pub async fn build_package( plugin ))? }; - data_files.push((service, path, paths.pop().unwrap())) + data_files.push((service, path.to_string(), paths.pop().unwrap())) } let out_dir = get_package_dir(args, metadata); diff --git a/rust/test_package/query/Cargo.toml b/rust/test_package/query/Cargo.toml index db6df3a13..7822a2cfe 100644 --- a/rust/test_package/query/Cargo.toml +++ b/rust/test_package/query/Cargo.toml @@ -10,6 +10,7 @@ publish = false [package.metadata.psibase] plugin = "tpack-plugin" +data = [{src = "../ui", dst = "/"}] [dependencies] psibase = { path = "../../psibase", version = "0.12.0" } diff --git a/rust/test_package/ui/index.html b/rust/test_package/ui/index.html new file mode 100644 index 000000000..350147c29 --- /dev/null +++ b/rust/test_package/ui/index.html @@ -0,0 +1,5 @@ + + + Lorem ipsum dolor sit amet + +