From 476b79ddfc3e1744eb79a97776312fa373cb6e15 Mon Sep 17 00:00:00 2001 From: stelzo Date: Wed, 22 Jan 2025 01:19:19 +0100 Subject: [PATCH] add vendor dir name param --- crates/typst-cli/src/args.rs | 8 +++++++ crates/typst-cli/src/init.rs | 6 ++--- crates/typst-cli/src/package.rs | 6 ++++- crates/typst-cli/src/vendor.rs | 39 ++++++++++++++++++++------------- crates/typst-cli/src/world.rs | 18 +++++++-------- crates/typst-kit/src/package.rs | 10 ++++++--- 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/crates/typst-cli/src/args.rs b/crates/typst-cli/src/args.rs index 0b09094ff..32387985a 100644 --- a/crates/typst-cli/src/args.rs +++ b/crates/typst-cli/src/args.rs @@ -361,6 +361,14 @@ pub struct PackageArgs { value_name = "DIR" )] pub package_cache_path: Option, + + /// Custom vendor directory name. + #[clap( + long = "package-vendor-path", + env = "TYPST_PACKAGE_VENDOR_PATH", + value_name = "DIR" + )] + pub vendor_path: Option, } /// Common arguments to customize available fonts. diff --git a/crates/typst-cli/src/init.rs b/crates/typst-cli/src/init.rs index 0e0a5c646..c9da3434a 100644 --- a/crates/typst-cli/src/init.rs +++ b/crates/typst-cli/src/init.rs @@ -15,7 +15,7 @@ use crate::package; /// Execute an initialization command. pub fn init(command: &InitCommand) -> StrResult<()> { - let package_storage = package::storage(&command.package); + let package_storage = package::storage(&command.package, None); // Parse the package specification. If the user didn't specify the version, // we try to figure it out automatically by downloading the package index @@ -28,9 +28,9 @@ pub fn init(command: &InitCommand) -> StrResult<()> { StrResult::Ok(spec.at(version)) })?; - // Find or download the package. Vendoring does not make sense for initialization, so project_root is not needed. + // Find or download the package. Vendoring does not make sense for initialization, so vendor_dir is not needed. let package_path = - package_storage.prepare_package(&spec, &mut PrintDownload(&spec), None)?; + package_storage.prepare_package(&spec, &mut PrintDownload(&spec))?; // Parse the manifest. let manifest = parse_manifest(&package_path)?; diff --git a/crates/typst-cli/src/package.rs b/crates/typst-cli/src/package.rs index 6099ecaa9..48e95e97f 100644 --- a/crates/typst-cli/src/package.rs +++ b/crates/typst-cli/src/package.rs @@ -1,13 +1,17 @@ +use std::path::PathBuf; + use typst_kit::package::PackageStorage; use crate::args::PackageArgs; use crate::download; /// Returns a new package storage for the given args. -pub fn storage(args: &PackageArgs) -> PackageStorage { +pub fn storage(args: &PackageArgs, workdir: Option) -> PackageStorage { PackageStorage::new( + args.vendor_path.clone(), args.package_cache_path.clone(), args.package_path.clone(), download::downloader(), + workdir, ) } diff --git a/crates/typst-cli/src/vendor.rs b/crates/typst-cli/src/vendor.rs index a6e36a55a..41300e6e1 100644 --- a/crates/typst-cli/src/vendor.rs +++ b/crates/typst-cli/src/vendor.rs @@ -1,4 +1,7 @@ -use std::fs::{create_dir, create_dir_all}; +use std::{ + fs::{create_dir, create_dir_all}, + path::PathBuf, +}; use ecow::eco_format; use typst::{ @@ -24,7 +27,7 @@ pub fn vendor(command: &VendorCommand) -> HintedStrResult<()> { match output { Ok(_) => { - copy_deps(&mut world)?; + copy_deps(&mut world, &command.world.package.vendor_path)?; print_diagnostics(&world, &[], &warnings, command.process.diagnostic_format) .map_err(|err| eco_format!("failed to print diagnostics ({err})"))?; } @@ -45,20 +48,26 @@ pub fn vendor(command: &VendorCommand) -> HintedStrResult<()> { Ok(()) } -fn copy_deps(world: &mut SystemWorld) -> HintedStrResult<()> { - let vendor_dir = world.workdir().join(DEFAULT_VENDOR_SUBDIR); - - match vendor_dir.try_exists() { - Ok(false) => { - if let Err(err) = create_dir(vendor_dir.clone()) { - bail!("failed to create vendor directory: {:?}", err); +fn copy_deps( + world: &mut SystemWorld, + vendor_path: &Option, +) -> HintedStrResult<()> { + let vendor_dir = match vendor_path { + Some(path) => match path.canonicalize() { + Ok(path) => path, + Err(err) => { + if err.kind() == std::io::ErrorKind::NotFound { + if let Err(err) = create_dir(path) { + bail!("failed to create vendor directory: {:?}", err); + } + path.clone() + } else { + bail!("failed to canonicalize vendor directory path: {:?}", err); + } } - } - Err(err) => { - bail!("failed to check existence of vendor directory: {:?}", err); - } - _ => {} - } + }, + None => world.workdir().join(DEFAULT_VENDOR_SUBDIR), + }; // Must iterate two times in total. As soon as the parent directory is created, // world tries to read the subsequent files from the same package diff --git a/crates/typst-cli/src/world.rs b/crates/typst-cli/src/world.rs index c9058b5e9..60c182a7c 100644 --- a/crates/typst-cli/src/world.rs +++ b/crates/typst-cli/src/world.rs @@ -29,7 +29,7 @@ static STDIN_ID: LazyLock = /// A world that provides access to the operating system. pub struct SystemWorld { /// The working directory. - workdir: Option, + workdir: PathBuf, /// The root relative to which absolute paths are resolved. root: PathBuf, /// The input path. @@ -132,15 +132,18 @@ impl SystemWorld { None => Now::System(OnceLock::new()), }; + let env_workdir = std::env::current_dir().ok(); + let workdir = env_workdir.unwrap_or(PathBuf::from(".")); + Ok(Self { - workdir: std::env::current_dir().ok(), + workdir: workdir.clone(), root, main, library: LazyHash::new(library), book: LazyHash::new(fonts.book), fonts: fonts.fonts, slots: Mutex::new(HashMap::new()), - package_storage: package::storage(&world_args.package), + package_storage: package::storage(&world_args.package, Some(workdir)), now, }) } @@ -157,7 +160,7 @@ impl SystemWorld { /// The current working directory. pub fn workdir(&self) -> &Path { - self.workdir.as_deref().unwrap_or(Path::new(".")) + self.workdir.as_path() } /// Return all paths the last compilation depended on. @@ -380,12 +383,9 @@ fn system_path( // will be resolved. let buf; let mut root = project_root; + if let Some(spec) = id.package() { - buf = package_storage.prepare_package( - spec, - &mut PrintDownload(&spec), - Some(root), - )?; + buf = package_storage.prepare_package(spec, &mut PrintDownload(&spec))?; root = &buf; } diff --git a/crates/typst-kit/src/package.rs b/crates/typst-kit/src/package.rs index ea561f6a4..17df96ea9 100644 --- a/crates/typst-kit/src/package.rs +++ b/crates/typst-kit/src/package.rs @@ -28,6 +28,8 @@ pub const DEFAULT_VENDOR_SUBDIR: &str = "vendor"; /// on demand, if possible. #[derive(Debug)] pub struct PackageStorage { + /// The path at which packages are stored by the vendor command. + package_vendor_path: Option, /// The path at which non-local packages should be stored when downloaded. package_cache_path: Option, /// The path at which local packages are stored. @@ -42,11 +44,15 @@ impl PackageStorage { /// Creates a new package storage for the given package paths. Falls back to /// the recommended XDG directories if they are `None`. pub fn new( + package_vendor_path: Option, package_cache_path: Option, package_path: Option, downloader: Downloader, + workdir: Option, ) -> Self { Self { + package_vendor_path: package_vendor_path + .or_else(|| workdir.map(|workdir| workdir.join(DEFAULT_VENDOR_SUBDIR))), package_cache_path: package_cache_path.or_else(|| { dirs::cache_dir().map(|cache_dir| cache_dir.join(DEFAULT_PACKAGES_SUBDIR)) }), @@ -74,7 +80,6 @@ impl PackageStorage { &self, spec: &PackageSpec, progress: &mut dyn Progress, - project_root: Option<&Path>, ) -> PackageResult { let subdir = format!("{}/{}/{}", spec.namespace, spec.name, spec.version); @@ -86,8 +91,7 @@ impl PackageStorage { } // Read from vendor dir if it exists. - if let Some(project_root) = project_root { - let vendor_dir = project_root.join(DEFAULT_VENDOR_SUBDIR); + if let Some(vendor_dir) = &self.package_vendor_path { if let Ok(true) = vendor_dir.try_exists() { let dir = vendor_dir.join(&subdir); if dir.exists() {