1use anyhow::{bail, Context, Result};
2use serde::Deserialize;
3use std::path::Path;
4
5const LATEST_BLUEPRINT_WORKING_VERSION: &str = "3.54.0";
6
7pub const BLUEPRINT_CSS: &str = include_str!("blueprint.css");
8
9pub fn download_css(dest: impl AsRef<Path>) -> Result<()> {
11 let version = download_from_npm_package(
12 "@blueprintjs/core",
13 LATEST_BLUEPRINT_WORKING_VERSION,
14 Path::new("package/lib/css/blueprint.css"),
15 dest,
16 )
17 .context("while downloading CSS of @blueprintjs/core")?;
18 log::info!("Blueprint CSS updated to: {}", version);
19 Ok(())
20}
21
22pub fn download_from_npm_package(
24 package_name: &str,
25 version: &str,
26 src: impl AsRef<Path>,
27 dest: impl AsRef<Path>,
28) -> Result<String> {
29 let src = src.as_ref();
30 let dest = dest.as_ref();
31
32 let version = if version.is_empty() || version == "latest" {
33 let info: PackageInfo =
34 ureq::get(format!("https://registry.npmjs.org/{}", package_name).as_str())
35 .call()?
36 .into_json()?;
37
38 info.dist_tags.latest
39 } else {
40 version.to_string()
41 };
42
43 let resp = ureq::get(
44 format!(
45 "https://registry.npmjs.org/{}/-/{}-{}.tgz",
46 package_name,
47 package_name
48 .split_once('/')
49 .map(|(_, name)| name)
50 .unwrap_or(package_name),
51 version,
52 )
53 .as_str(),
54 )
55 .call()?;
56
57 let mut archive = tar::Archive::new(flate2::read::GzDecoder::new(resp.into_reader()));
58
59 let blueprint_css = archive.entries()?.find(|entry| {
60 entry
61 .as_ref()
62 .ok()
63 .and_then(|entry| entry.path().map(|path| path == src).ok())
64 .unwrap_or(false)
65 });
66
67 if let Some(entry) = blueprint_css {
68 let mut entry = entry.unwrap();
69 entry.unpack(dest)?;
70 Ok(version)
71 } else {
72 bail!("could not find `{}` in archive!", src.display());
73 }
74}
75
76#[derive(Deserialize)]
77struct PackageInfo {
78 #[serde(rename = "dist-tags")]
79 dist_tags: PackageDistTags,
80}
81
82#[derive(Deserialize)]
83struct PackageDistTags {
84 latest: String,
85}