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