mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
101 lines
3.3 KiB
Rust
101 lines
3.3 KiB
Rust
use std::fs::{create_dir, create_dir_all};
|
|
|
|
use ecow::eco_format;
|
|
use typst::{
|
|
diag::{bail, HintedStrResult, Warned},
|
|
layout::PagedDocument,
|
|
};
|
|
use typst_kit::package::{DEFAULT_PACKAGES_SUBDIR, DEFAULT_VENDOR_SUBDIR};
|
|
|
|
use crate::{
|
|
args::VendorCommand, compile::print_diagnostics, set_failed, world::SystemWorld,
|
|
};
|
|
use typst::World;
|
|
|
|
/// Execute a vendor command.
|
|
pub fn vendor(command: &VendorCommand) -> HintedStrResult<()> {
|
|
let mut world = SystemWorld::new(&command.input, &command.world, &command.process)?;
|
|
|
|
// Reset everything and ensure that the main file is present.
|
|
world.reset();
|
|
world.source(world.main()).map_err(|err| err.to_string())?;
|
|
|
|
let Warned { output, warnings } = typst::compile::<PagedDocument>(&world);
|
|
|
|
match output {
|
|
Ok(_) => {
|
|
copy_deps(&mut world)?;
|
|
print_diagnostics(&world, &[], &warnings, command.process.diagnostic_format)
|
|
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
|
}
|
|
|
|
// Print diagnostics.
|
|
Err(errors) => {
|
|
set_failed();
|
|
print_diagnostics(
|
|
&world,
|
|
&errors,
|
|
&warnings,
|
|
command.process.diagnostic_format,
|
|
)
|
|
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
Err(err) => {
|
|
bail!("failed to check existence of vendor directory: {:?}", err);
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
// 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
|
|
// from the vendor directory since it is higher priority.
|
|
let all_deps = world
|
|
.dependencies()
|
|
.filter_map(|dep_path| {
|
|
let path = dep_path.to_str().unwrap();
|
|
path.find(DEFAULT_PACKAGES_SUBDIR).map(|pos| {
|
|
let dependency_path = &path[pos + DEFAULT_PACKAGES_SUBDIR.len() + 1..];
|
|
(dep_path.clone(), vendor_dir.join(dependency_path))
|
|
})
|
|
})
|
|
.collect::<Vec<_>>();
|
|
|
|
for (from_data_path, to_vendor_path) in all_deps {
|
|
if let Some(parent) = to_vendor_path.parent() {
|
|
match parent.try_exists() {
|
|
Ok(false) => {
|
|
if let Err(err) = create_dir_all(parent) {
|
|
bail!(
|
|
"failed to create package inside the vendor directory: {:?}",
|
|
err
|
|
);
|
|
}
|
|
}
|
|
Err(err) => {
|
|
bail!("failed to check existence of a package inside the vendor directory: {:?}", err);
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
if let Err(err) = std::fs::copy(from_data_path, to_vendor_path) {
|
|
bail!("failed to copy dependency to vendor directory: {:?}", err);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|