oranda_generate_css/
lib.rs
1pub mod errors;
2
3extern crate axoasset;
4extern crate camino;
5extern crate directories;
6extern crate miette;
7extern crate thiserror;
8
9use crate::errors::Result;
10use axoasset::LocalAsset;
11use camino::{Utf8Path, Utf8PathBuf};
12use directories::ProjectDirs;
13use std::env;
14use std::io::Write;
15use std::process::Command;
16
17const MANIFEST_PATH: &str = env!("CARGO_MANIFEST_DIR");
18const CSS_SRC_PATH: &str = "../oranda-css/css/main.css";
19const TAILWIND_SRC_PATH: &str = "../oranda-css/tailwind.config.js";
20const DEFAULT_CSS_OUTPUT_DIR: &str = "../oranda-css/dist";
21
22fn manifest_dir() -> &'static Utf8Path {
23 Utf8Path::new(MANIFEST_PATH)
24}
25
26pub fn default_css_output_dir() -> Utf8PathBuf {
27 manifest_dir().join(DEFAULT_CSS_OUTPUT_DIR)
28}
29
30pub fn build_css(dist_dir: &Utf8Path) -> Result<()> {
31 let binary_path = tailwind_path()?;
32
33 tracing::info!("Building oranda CSS using Tailwind...");
34 let css_src_path = manifest_dir().join(CSS_SRC_PATH);
35 let tailwind_config_path = manifest_dir().join(TAILWIND_SRC_PATH);
36 let output_path = dist_dir.join("oranda.css");
37 let output = Command::new(binary_path)
38 .args([
39 "-c",
40 tailwind_config_path.as_str(),
41 "-i",
42 css_src_path.as_str(),
43 "-o",
44 output_path.as_str(),
45 "--minify",
46 ])
47 .output()?;
48 std::io::stderr().write_all(&output.stderr)?;
49 output
50 .status
51 .success()
52 .then_some(true)
53 .expect("Tailwind failed to compile CSS!");
54
55 Ok(())
56}
57
58fn tailwind_path() -> Result<Utf8PathBuf> {
65 let result = Command::new("tailwindcss").arg("--help").status();
67 if let Ok(status) = result {
68 if status.success() {
69 tracing::info!("Found Tailwind binary on the path!");
70
71 return Ok(Utf8PathBuf::from("tailwindcss"));
72 }
73 } else {
75 tracing::info!(?result, "Couldn't find Tailwind binary");
76 }
77
78 let project_dir = ProjectDirs::from("dev", "axo", "oranda")
80 .expect("Unable to create cache dir for downloading Tailwind!");
81 let cache_dir = project_dir.cache_dir();
82 let double = match (env::consts::OS, env::consts::ARCH) {
84 ("linux", "x86_64") => "linux-x64",
85 ("linux", "aarch64") => "linux-arm64",
86 ("linux", "arm") => "linux-armv7",
87 ("macos", "x86_64") => "macos-x64",
88 ("macos", "aarch64") => "macos-arm64",
89 ("windows", "x86_64") => "windows-x64.exe",
90 ("windows", "aarch64") => "windows-arm64.exe",
91 _ => "linux-x64",
92 };
93 let mut binary_path = Utf8PathBuf::from(cache_dir.display().to_string());
94 LocalAsset::create_dir_all(&binary_path)?;
95 binary_path.push(format!("tailwindcss-{double}"));
96 if !binary_path.exists() {
97 tracing::info!("Fetching Tailwind binary from GitHub release...");
99 let url = format!(
100 "https://github.com/tailwindlabs/tailwindcss/releases/latest/download/tailwindcss-{double}"
101 );
102 let handle = tokio::runtime::Handle::current();
103 let response = handle.block_on(reqwest::get(url))?;
104 let bytes = handle.block_on(response.bytes())?;
105 let file = LocalAsset::new(&binary_path, Vec::from(bytes))?;
106 file.write(
107 binary_path
108 .parent()
109 .expect("Tailwind binary path has no parent!?"),
110 )?;
111
112 #[cfg(target_family = "unix")]
114 {
115 use std::os::unix::prelude::PermissionsExt;
116 let user_execute = std::fs::Permissions::from_mode(0o755);
117 std::fs::set_permissions(&binary_path, user_execute)?;
118 }
119 }
120
121 Ok(binary_path)
122}