oxide_cli/templates/
install.rs1use std::path::Path;
2
3use anyhow::Result;
4use reqwest::Client;
5use serde::Deserialize;
6
7use crate::{
8 AppContext,
9 auth::token::get_auth_user,
10 cache::{get_cached_template, update_templates_cache},
11 utils::archive::download_and_extract,
12};
13
14#[derive(Deserialize)]
15struct TemplateInfoRes {
16 archive_url: String,
17 commit_sha: String,
18 subdir: Option<String>,
19}
20
21async fn get_template_info(
22 template_name: &str,
23 client: &Client,
24 auth_path: &Path,
25 backend_url: &str,
26) -> Result<TemplateInfoRes> {
27 let user = get_auth_user(auth_path)?;
28
29 let res: TemplateInfoRes = client
30 .get(format!("{backend_url}/template/{template_name}/url"))
31 .bearer_auth(user.token)
32 .header("Content-Type", "application/json")
33 .send()
34 .await?
35 .error_for_status()?
36 .json()
37 .await?;
38
39 Ok(res)
40}
41
42pub async fn install_template(ctx: &AppContext, template_name: &str) -> Result<()> {
43 let info = get_template_info(template_name, &ctx.client, &ctx.paths.auth, &ctx.backend_url).await?;
44
45 if let Some(cached) = get_cached_template(ctx, template_name)?
47 && cached.commit_sha == info.commit_sha
48 && ctx.paths.templates.join(template_name).exists()
49 {
50 println!("Template '{}' is already up to date", template_name);
51 return Ok(());
52 }
53
54 let dest = ctx.paths.templates.join(template_name);
55
56 {
57 let mut guard = ctx.cleanup_state.lock().unwrap_or_else(|e| e.into_inner());
58 *guard = Some(dest.clone());
59 }
60
61 download_and_extract(
62 &ctx.client,
63 &info.archive_url,
64 &dest,
65 info.subdir.as_deref(),
66 )
67 .await?;
68
69 {
70 let mut guard = ctx.cleanup_state.lock().unwrap_or_else(|e| e.into_inner());
71 *guard = None;
72 }
73
74 update_templates_cache(
75 &ctx.paths.templates,
76 Path::new(template_name),
77 &info.commit_sha,
78 )?;
79 println!("Template successfully downloaded");
80
81 Ok(())
82}