use std::fs::read_to_string;
use std::path::PathBuf;
use std::{fs, path::Path};
use regex::Regex;
use std::io;
use typst_kit::download::{DownloadState, Progress};
use typst_syntax::package::PackageManifest;
pub mod dryrun;
pub mod git;
pub mod macros;
pub mod output;
pub mod paths;
pub mod specs;
pub mod state;
use crate::utpm_bail;
use self::state::Result;
pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
fn inner(src: &mut PathBuf, dst: &mut PathBuf) -> io::Result<()> {
fs::create_dir_all(&dst)?;
for entry in fs::read_dir(&src)? {
let entry = entry?;
let ty = entry.file_type()?;
let name = entry.file_name();
src.push(&name);
dst.push(&name);
if ty.is_dir() && name != ".utpm" {
inner(src, dst)?;
} else {
fs::copy(&src, &dst)?;
}
src.pop();
dst.pop();
}
Ok(())
}
inner(
&mut src.as_ref().to_path_buf(),
&mut dst.as_ref().to_path_buf(),
)
}
pub fn try_find_path(s: impl AsRef<Path>) -> Result<PathBuf> {
let manifest_path = PathBuf::from_iter([s.as_ref(), "typst.toml".as_ref()]);
if !manifest_path.try_exists()? {
utpm_bail!(Manifest);
}
Ok(manifest_path)
}
pub fn try_find(s: impl AsRef<Path>) -> Result<PackageManifest> {
let e = read_to_string(try_find_path(s)?)?;
let f: PackageManifest = toml::from_str(&e)?;
Ok(f)
}
#[cfg(not(windows))]
pub fn symlink_all(origin: impl AsRef<Path>, new_path: impl AsRef<Path>) -> io::Result<()> {
use std::os::unix::fs::symlink;
symlink(origin, new_path)
}
#[cfg(windows)]
pub fn symlink_all(origin: impl AsRef<Path>, new_path: impl AsRef<Path>) -> io::Result<()> {
use std::os::windows::fs::symlink_dir;
symlink_dir(origin, new_path)
}
pub fn regex_package() -> Regex {
Regex::new(r"^@([a-zA-Z]+)\/([a-zA-Z]+(?:\-[a-zA-Z]+)?)\:(\d+)\.(\d+)\.(\d+)$").unwrap()
}
pub fn regex_import() -> Regex {
Regex::new(r#"\#import \"@([a-zA-Z]+)\/([a-zA-Z]+(?:\-[a-zA-Z]+)?)\:(\d+)\.(\d+)\.(\d+)\""#)
.unwrap()
}
pub fn write_manifest(data: &PackageManifest) -> Result<()> {
let tomlfy: String = toml::to_string_pretty(data)?;
if !crate::utils::dryrun::get_dry_run() {
std::fs::write(Path::new("./typst.toml"), tomlfy)?;
}
Ok(())
}
pub struct ProgressPrint {}
impl Progress for ProgressPrint {
fn print_start(&mut self) {}
fn print_progress(&mut self, _state: &DownloadState) {}
fn print_finish(&mut self, _state: &DownloadState) {}
}
mod tests {
#[test]
fn regex() {
let re = super::regex_package();
assert!(re.is_match("@preview/package:2.0.1"));
assert!(!re.is_match("@preview/package-:2.0.1"));
assert!(re.is_match("@local/package-A:2.0.1"));
assert!(re.is_match("@local/package-a:2.0.1"));
assert!(re.is_match("@local/AAAAAAAAAAAAAA:2.0.1"));
assert!(!re.is_match("@local/p:1..1"));
assert!(re.is_match("@a/p:1.0.1"));
assert!(!re.is_match("@a/p:v1.0.1"));
assert!(!re.is_match("@/p:1.0.1"));
assert!(!re.is_match("p:1.0.1"));
assert!(!re.is_match("@a/p"));
}
}