waterui_cli/hydrolysis/
backend.rs1use std::path::{Path, PathBuf};
4
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 backend::Backend,
9 build::BuildOptions,
10 device::Artifact,
11 hydrolysis::platform::{
12 build_hydrolysis, clean_hydrolysis, is_hydrolysis_platform, package_hydrolysis,
13 },
14 platform::{PackageOptions, TargetBackend, TargetPlatform},
15 project::Project,
16 templates::{self, TemplateContext},
17};
18
19#[derive(Debug, Serialize, Deserialize, Clone)]
21pub struct HydrolysisBackend {
22 #[serde(
23 default = "default_hydrolysis_project_path",
24 skip_serializing_if = "is_default_hydrolysis_project_path"
25 )]
26 project_path: PathBuf,
27}
28
29impl HydrolysisBackend {
30 #[must_use]
32 pub fn new() -> Self {
33 Self {
34 project_path: default_hydrolysis_project_path(),
35 }
36 }
37
38 #[must_use]
40 pub fn with_project_path(mut self, path: impl Into<PathBuf>) -> Self {
41 self.project_path = path.into();
42 self
43 }
44
45 #[must_use]
47 pub const fn project_path(&self) -> &PathBuf {
48 &self.project_path
49 }
50
51 pub async fn requires_regeneration(project: &Project) -> eyre::Result<bool> {
59 let backend_dir = project.backend_path::<Self>();
60 let ctx = Self::template_context(project).await?;
61 let outputs = templates::hydrolysis::rendered_outputs(
62 &ctx,
63 &project.hydrolysis_backend_crate_name(),
64 )?;
65 for (relative, expected) in outputs {
66 let path = backend_dir.join(&relative);
67 let per_run_binding = relative == Path::new("src/preview_symbol.rs")
71 || relative == Path::new("src/preview_test.rs");
72 match std::fs::read(&path) {
73 Ok(existing) if per_run_binding || existing == expected => {}
74 Ok(_) | Err(_) => return Ok(true),
75 }
76 }
77 Ok(false)
78 }
79
80 async fn template_context(project: &Project) -> eyre::Result<TemplateContext> {
83 let manifest = project.manifest();
84 let app_name = manifest
85 .package
86 .name
87 .chars()
88 .filter(|c| c.is_alphanumeric())
89 .collect::<String>();
90 Ok(TemplateContext::for_project_manifest(
91 manifest,
92 project.crate_name().clone(),
93 app_name,
94 &project.resolved_framework().await?,
95 )
96 .with_backend_project_path(project.backend_path::<Self>())
97 .with_project_root_path(project.root().to_path_buf())
98 .with_webview_enabled(project.uses_standard_webview().await?)
99 .with_chromium_enabled(project.links_runtime_package("waterui-chromium").await?)
100 .with_browser_engine(project.linked_browser_engine().await?))
101 }
102}
103
104impl Default for HydrolysisBackend {
105 fn default() -> Self {
106 Self::new()
107 }
108}
109
110impl Backend for HydrolysisBackend {
111 const DEFAULT_PATH: &'static str = "hydrolysis";
112
113 const CACHE_PATHS: &'static [&'static str] = &["Cargo.lock"];
117
118 fn path(&self) -> &Path {
119 &self.project_path
120 }
121
122 async fn init(project: &Project) -> Result<Self, crate::backend::FailToInitBackend> {
123 let project_path = default_hydrolysis_project_path();
124 let ctx = Self::template_context(project)
125 .await
126 .map_err(crate::backend::FailToInitBackend::Config)?;
127
128 templates::hydrolysis::scaffold(
129 &project.backend_path::<Self>(),
130 &ctx,
131 &project.hydrolysis_backend_crate_name(),
132 )
133 .await
134 .map_err(crate::backend::FailToInitBackend::Io)?;
135
136 Ok(Self { project_path })
137 }
138
139 fn supports(&self, platform: TargetPlatform) -> bool {
140 is_hydrolysis_platform(platform)
141 }
142
143 async fn build(
144 &self,
145 project: &Project,
146 platform: TargetPlatform,
147 options: BuildOptions,
148 ) -> eyre::Result<PathBuf> {
149 project
150 .browser_runtime_plan(platform, TargetBackend::Hydrolysis)
151 .await?;
152 build_hydrolysis(project, platform, options).await
153 }
154
155 async fn package(
156 &self,
157 project: &Project,
158 platform: TargetPlatform,
159 options: PackageOptions,
160 ) -> eyre::Result<Artifact> {
161 package_hydrolysis(project, platform, options).await
162 }
163
164 async fn clean(&self, project: &Project, _platform: TargetPlatform) -> eyre::Result<()> {
165 clean_hydrolysis(project).await
166 }
167}
168
169fn default_hydrolysis_project_path() -> PathBuf {
170 PathBuf::from("hydrolysis")
171}
172
173fn is_default_hydrolysis_project_path(s: &Path) -> bool {
174 s == Path::new("hydrolysis")
175}