waterui_cli/winui/
backend.rs1use std::path::{Path, PathBuf};
4
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 backend::Backend,
9 build::BuildOptions,
10 device::Artifact,
11 platform::{PackageOptions, TargetPlatform},
12 project::Project,
13 templates::{self, TemplateContext},
14 winui::platform::{build_winui, clean_winui, is_winui_platform, package_winui},
15};
16
17#[derive(Debug, Serialize, Deserialize, Clone)]
21pub struct WinUiBackend {
22 #[serde(
23 default = "default_winui_project_path",
24 skip_serializing_if = "is_default_winui_project_path"
25 )]
26 project_path: PathBuf,
27}
28
29impl WinUiBackend {
30 #[must_use]
32 pub fn new() -> Self {
33 Self {
34 project_path: default_winui_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> {
58 let backend_dir = project.backend_path::<Self>();
59 let ctx = Self::template_context(project).await?;
60 for (relative, expected) in
61 templates::winui::rendered_outputs(&ctx, &project.winui_backend_crate_name())?
62 {
63 match std::fs::read(backend_dir.join(relative)) {
64 Ok(existing) if existing == expected => {}
65 Ok(_) | Err(_) => return Ok(true),
66 }
67 }
68 Ok(false)
69 }
70
71 async fn template_context(project: &Project) -> eyre::Result<TemplateContext> {
72 let manifest = project.manifest();
73 let app_name = manifest
74 .package
75 .name
76 .chars()
77 .filter(|c| c.is_alphanumeric())
78 .collect::<String>();
79 Ok(TemplateContext::for_project_manifest(
80 manifest,
81 project.crate_name().clone(),
82 app_name,
83 &project.resolved_framework().await?,
84 )
85 .with_backend_project_path(project.backend_path::<Self>())
86 .with_project_root_path(project.root().to_path_buf()))
87 }
88}
89
90impl Default for WinUiBackend {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96impl Backend for WinUiBackend {
97 const DEFAULT_PATH: &'static str = "winui";
98
99 const CACHE_PATHS: &'static [&'static str] = &[];
103
104 fn path(&self) -> &Path {
105 &self.project_path
106 }
107
108 async fn init(project: &Project) -> Result<Self, crate::backend::FailToInitBackend> {
109 let project_path = default_winui_project_path();
110 let ctx = Self::template_context(project)
111 .await
112 .map_err(crate::backend::FailToInitBackend::Config)?;
113
114 templates::winui::scaffold(
115 &project.backend_path::<Self>(),
116 &ctx,
117 &project.winui_backend_crate_name(),
118 )
119 .await
120 .map_err(crate::backend::FailToInitBackend::Io)?;
121
122 Ok(Self { project_path })
123 }
124
125 fn supports(&self, platform: TargetPlatform) -> bool {
126 is_winui_platform(platform)
127 }
128
129 async fn build(
130 &self,
131 project: &Project,
132 _platform: TargetPlatform,
133 options: BuildOptions,
134 ) -> eyre::Result<PathBuf> {
135 build_winui(project, options).await
136 }
137
138 async fn package(
139 &self,
140 project: &Project,
141 _platform: TargetPlatform,
142 options: PackageOptions,
143 ) -> eyre::Result<Artifact> {
144 package_winui(project, options).await
145 }
146
147 async fn clean(&self, project: &Project, _platform: TargetPlatform) -> eyre::Result<()> {
148 clean_winui(project).await
149 }
150}
151
152fn default_winui_project_path() -> PathBuf {
153 PathBuf::from("winui")
154}
155
156fn is_default_winui_project_path(s: &Path) -> bool {
157 s == Path::new("winui")
158}