Skip to content

Commit

Permalink
Add postinstall
Browse files Browse the repository at this point in the history
  • Loading branch information
swatanabe committed Sep 6, 2024
1 parent a5fdb11 commit a793ecf
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 31 deletions.
3 changes: 3 additions & 0 deletions doc/psidk/src/development/services/rust-service/package.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The available fields are:
- `server`: May be present on any crate that builds a service. The value is a crate which will handle HTTP requests sent to this service. The other crate will be built and included in the current package.
- `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.
- `dependencies`: Additional packages, not build by cargo, that the package depends on.

Example:
Expand All @@ -29,6 +30,8 @@ flags = []
server = "example"
# Plugin for the front end
plugin = "example-plugin"
# Run the service's init action
postinstall = [{sender="tpack", service="tpack", method="init", rawData="0000"}]

[package.metadata.psibase.dependencies]
HttpServer = "0.12.0"
Expand Down
85 changes: 54 additions & 31 deletions rust/cargo-psibase/src/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use crate::{build, build_plugin, Args, SERVICE_POLYFILL};
use anyhow::anyhow;
use cargo_metadata::{Metadata, Node, Package, PackageId};
use psibase::{
AccountNumber, Checksum256, ExactAccountNumber, Meta, PackageInfo, PackageRef, PackagedService,
ServiceInfo,
AccountNumber, Action, Checksum256, ExactAccountNumber, Meta, PackageInfo, PackageRef,
PackagedService, ServiceInfo,
};
use serde::{Deserialize, Serialize};
use serde_json::json;
Expand All @@ -24,6 +24,7 @@ pub struct PsibaseMetadata {
flags: Vec<String>,
dependencies: HashMap<String, String>,
services: Option<Vec<String>>,
postinstall: Option<Vec<Action>>,
}

impl PsibaseMetadata {
Expand Down Expand Up @@ -104,6 +105,7 @@ fn should_build_package(
meta: &Meta,
services: &[(&String, ServiceInfo, PathBuf)],
data: &[(&String, &str, PathBuf)],
postinstall: &[Action],
) -> Result<bool, anyhow::Error> {
let timestamp = if let Ok(metadata) = filename.metadata() {
metadata.modified()?
Expand Down Expand Up @@ -153,6 +155,12 @@ fn should_build_package(
if existing_data != new_data {
return Ok(true);
}
// check postinstall
let mut existing_postinstall = Vec::new();
existing.postinstall(&mut existing_postinstall)?;
if &existing_postinstall[..] != postinstall {
return Ok(true);
}
Ok(false)
}

Expand All @@ -168,6 +176,7 @@ pub async fn build_package(
let mut services = Vec::new();
let mut plugins = Vec::new();
let mut data_files = Vec::new();
let mut postinstall: Vec<Action> = Vec::new();

let get_dep = get_dep_type(|service, dep| {
let r = metadata.resolved.get(&service.id.repr.as_str()).unwrap();
Expand Down Expand Up @@ -203,6 +212,12 @@ pub async fn build_package(
visited.insert(root);
queue.push(root);
}
// Add postinstall from the root whether it is a service or not
if !visited.contains(root) {
if let Some(actions) = &meta.postinstall {
postinstall.extend_from_slice(actions.as_slice());
}
}
} else {
Err(anyhow!("Cannot package a virtual workspace"))?
}
Expand Down Expand Up @@ -243,6 +258,9 @@ pub async fn build_package(
plugins.push((plugin, &package.name, "/plugin.wasm", &id.repr));
}
services.push((&package.name, info, &package.id.repr));
if let Some(actions) = &pmeta.postinstall {
postinstall.extend_from_slice(actions.as_slice());
}
}
}

Expand Down Expand Up @@ -300,35 +318,40 @@ pub async fn build_package(

let out_dir = get_package_dir(args, metadata);
let out_path = out_dir.join(package_name.clone() + ".psi");
let mut file = if should_build_package(&out_path, &meta, &service_wasms, &data_files)? {
std::fs::create_dir_all(&out_dir)?;
let mut out = ZipWriter::new(
OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(&out_path)?,
);
let options: FileOptions = FileOptions::default();
out.start_file("meta.json", options)?;
write!(out, "{}", &serde_json::to_string(&meta)?)?;
for (service, info, path) in service_wasms {
out.start_file(format!("service/{}.wasm", service), options)?;
std::io::copy(&mut File::open(path)?, &mut out)?;
out.start_file(format!("service/{}.json", service), options)?;
write!(out, "{}", &serde_json::to_string(&info)?)?;
}
for (service, dest, src) in data_files {
out.start_file(format!("data/{}{}", service, dest), options)?;
std::io::copy(&mut File::open(src)?, &mut out)?;
}
let mut file = out.finish()?;
file.rewind()?;
file
} else {
File::open(out_path)?
};
let mut file =
if should_build_package(&out_path, &meta, &service_wasms, &data_files, &postinstall)? {
std::fs::create_dir_all(&out_dir)?;
let mut out = ZipWriter::new(
OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.open(&out_path)?,
);
let options: FileOptions = FileOptions::default();
out.start_file("meta.json", options)?;
write!(out, "{}", &serde_json::to_string(&meta)?)?;
for (service, info, path) in service_wasms {
out.start_file(format!("service/{}.wasm", service), options)?;
std::io::copy(&mut File::open(path)?, &mut out)?;
out.start_file(format!("service/{}.json", service), options)?;
write!(out, "{}", &serde_json::to_string(&info)?)?;
}
for (service, dest, src) in data_files {
out.start_file(format!("data/{}{}", service, dest), options)?;
std::io::copy(&mut File::open(src)?, &mut out)?;
}
if !postinstall.is_empty() {
out.start_file("script/postinstall.json", options)?;
write!(out, "{}", &serde_json::to_string(&postinstall)?)?;
}
let mut file = out.finish()?;
file.rewind()?;
file
} else {
File::open(out_path)?
};
// Calculate the package checksum
let mut hasher = Sha256::new();
std::io::copy(&mut file, &mut hasher)?;
Expand Down
2 changes: 2 additions & 0 deletions rust/psibase/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub type BlockNum = u32;
Deserialize,
SimpleObject,
InputObject,
PartialEq,
Eq,
)]
#[fracpack(fracpack_mod = "fracpack")]
#[to_key(psibase_mod = "crate")]
Expand Down
1 change: 1 addition & 0 deletions rust/test_package/service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ publish = false

[package.metadata.psibase]
server = "r-tpack"
postinstall = [{sender="tpack", service="tpack", method="init", rawData="0000"}]

[package.metadata.psibase.dependencies]
HttpServer = "0.12.0"
Expand Down
2 changes: 2 additions & 0 deletions rust/test_package/service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod service {
fn foo(value: i32) -> i32 {
value
}
#[action]
fn init() {}
}

#[psibase::test_case(packages("TestPackage"))]
Expand Down

0 comments on commit a793ecf

Please sign in to comment.