mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
--make-deps fixes (#5873)
This commit is contained in:
parent
74e4f78687
commit
3de3813ca0
@ -6,8 +6,9 @@ use std::path::{Path, PathBuf};
|
||||
use chrono::{DateTime, Datelike, Timelike, Utc};
|
||||
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
||||
use codespan_reporting::term;
|
||||
use ecow::{eco_format, EcoString};
|
||||
use ecow::eco_format;
|
||||
use parking_lot::RwLock;
|
||||
use pathdiff::diff_paths;
|
||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||
use typst::diag::{
|
||||
bail, At, Severity, SourceDiagnostic, SourceResult, StrResult, Warned,
|
||||
@ -188,7 +189,7 @@ pub fn compile_once(
|
||||
|
||||
match output {
|
||||
// Export the PDF / PNG.
|
||||
Ok(()) => {
|
||||
Ok(outputs) => {
|
||||
let duration = start.elapsed();
|
||||
|
||||
if config.watching {
|
||||
@ -202,7 +203,7 @@ pub fn compile_once(
|
||||
print_diagnostics(world, &[], &warnings, config.diagnostic_format)
|
||||
.map_err(|err| eco_format!("failed to print diagnostics ({err})"))?;
|
||||
|
||||
write_make_deps(world, config)?;
|
||||
write_make_deps(world, config, outputs)?;
|
||||
open_output(config)?;
|
||||
}
|
||||
|
||||
@ -226,12 +227,15 @@ pub fn compile_once(
|
||||
fn compile_and_export(
|
||||
world: &mut SystemWorld,
|
||||
config: &mut CompileConfig,
|
||||
) -> Warned<SourceResult<()>> {
|
||||
) -> Warned<SourceResult<Vec<Output>>> {
|
||||
match config.output_format {
|
||||
OutputFormat::Html => {
|
||||
let Warned { output, warnings } = typst::compile::<HtmlDocument>(world);
|
||||
let result = output.and_then(|document| export_html(&document, config));
|
||||
Warned { output: result, warnings }
|
||||
Warned {
|
||||
output: result.map(|()| vec![config.output.clone()]),
|
||||
warnings,
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
let Warned { output, warnings } = typst::compile::<PagedDocument>(world);
|
||||
@ -257,9 +261,14 @@ fn export_html(document: &HtmlDocument, config: &CompileConfig) -> SourceResult<
|
||||
}
|
||||
|
||||
/// Export to a paged target format.
|
||||
fn export_paged(document: &PagedDocument, config: &CompileConfig) -> SourceResult<()> {
|
||||
fn export_paged(
|
||||
document: &PagedDocument,
|
||||
config: &CompileConfig,
|
||||
) -> SourceResult<Vec<Output>> {
|
||||
match config.output_format {
|
||||
OutputFormat::Pdf => export_pdf(document, config),
|
||||
OutputFormat::Pdf => {
|
||||
export_pdf(document, config).map(|()| vec![config.output.clone()])
|
||||
}
|
||||
OutputFormat::Png => {
|
||||
export_image(document, config, ImageExportFormat::Png).at(Span::detached())
|
||||
}
|
||||
@ -327,7 +336,7 @@ fn export_image(
|
||||
document: &PagedDocument,
|
||||
config: &CompileConfig,
|
||||
fmt: ImageExportFormat,
|
||||
) -> StrResult<()> {
|
||||
) -> StrResult<Vec<Output>> {
|
||||
// Determine whether we have indexable templates in output
|
||||
let can_handle_multiple = match config.output {
|
||||
Output::Stdout => false,
|
||||
@ -383,7 +392,7 @@ fn export_image(
|
||||
&& config.export_cache.is_cached(*i, &page.frame)
|
||||
&& path.exists()
|
||||
{
|
||||
return Ok(());
|
||||
return Ok(Output::Path(path.to_path_buf()));
|
||||
}
|
||||
|
||||
Output::Path(path.to_owned())
|
||||
@ -392,11 +401,9 @@ fn export_image(
|
||||
};
|
||||
|
||||
export_image_page(config, page, &output, fmt)?;
|
||||
Ok(())
|
||||
Ok(output)
|
||||
})
|
||||
.collect::<Result<Vec<()>, EcoString>>()?;
|
||||
|
||||
Ok(())
|
||||
.collect::<StrResult<Vec<Output>>>()
|
||||
}
|
||||
|
||||
mod output_template {
|
||||
@ -501,14 +508,25 @@ impl ExportCache {
|
||||
/// Writes a Makefile rule describing the relationship between the output and
|
||||
/// its dependencies to the path specified by the --make-deps argument, if it
|
||||
/// was provided.
|
||||
fn write_make_deps(world: &mut SystemWorld, config: &CompileConfig) -> StrResult<()> {
|
||||
fn write_make_deps(
|
||||
world: &mut SystemWorld,
|
||||
config: &CompileConfig,
|
||||
outputs: Vec<Output>,
|
||||
) -> StrResult<()> {
|
||||
let Some(ref make_deps_path) = config.make_deps else { return Ok(()) };
|
||||
let Output::Path(output_path) = &config.output else {
|
||||
bail!("failed to create make dependencies file because output was stdout")
|
||||
};
|
||||
let Some(output_path) = output_path.as_os_str().to_str() else {
|
||||
let Ok(output_paths) = outputs
|
||||
.into_iter()
|
||||
.filter_map(|o| match o {
|
||||
Output::Path(path) => Some(path.into_os_string().into_string()),
|
||||
Output::Stdout => None,
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
else {
|
||||
bail!("failed to create make dependencies file because output path was not valid unicode")
|
||||
};
|
||||
if output_paths.is_empty() {
|
||||
bail!("failed to create make dependencies file because output was stdout")
|
||||
}
|
||||
|
||||
// Based on `munge` in libcpp/mkdeps.cc from the GCC source code. This isn't
|
||||
// perfect as some special characters can't be escaped.
|
||||
@ -522,6 +540,10 @@ fn write_make_deps(world: &mut SystemWorld, config: &CompileConfig) -> StrResult
|
||||
res.push('$');
|
||||
slashes = 0;
|
||||
}
|
||||
':' => {
|
||||
res.push('\\');
|
||||
slashes = 0;
|
||||
}
|
||||
' ' | '\t' => {
|
||||
// `munge`'s source contains a comment here that says: "A
|
||||
// space or tab preceded by 2N+1 backslashes represents N
|
||||
@ -544,18 +566,29 @@ fn write_make_deps(world: &mut SystemWorld, config: &CompileConfig) -> StrResult
|
||||
|
||||
fn write(
|
||||
make_deps_path: &Path,
|
||||
output_path: &str,
|
||||
output_paths: Vec<String>,
|
||||
root: PathBuf,
|
||||
dependencies: impl Iterator<Item = PathBuf>,
|
||||
) -> io::Result<()> {
|
||||
let mut file = File::create(make_deps_path)?;
|
||||
let current_dir = std::env::current_dir()?;
|
||||
let relative_root = diff_paths(&root, ¤t_dir).unwrap_or(root.clone());
|
||||
|
||||
file.write_all(munge(output_path).as_bytes())?;
|
||||
for (i, output_path) in output_paths.into_iter().enumerate() {
|
||||
if i != 0 {
|
||||
file.write_all(b" ")?;
|
||||
}
|
||||
file.write_all(munge(&output_path).as_bytes())?;
|
||||
}
|
||||
file.write_all(b":")?;
|
||||
for dependency in dependencies {
|
||||
let Some(dependency) =
|
||||
dependency.strip_prefix(&root).unwrap_or(&dependency).to_str()
|
||||
else {
|
||||
let relative_dependency = match dependency.strip_prefix(&root) {
|
||||
Ok(root_relative_dependency) => {
|
||||
relative_root.join(root_relative_dependency)
|
||||
}
|
||||
Err(_) => dependency,
|
||||
};
|
||||
let Some(relative_dependency) = relative_dependency.to_str() else {
|
||||
// Silently skip paths that aren't valid unicode so we still
|
||||
// produce a rule that will work for the other paths that can be
|
||||
// processed.
|
||||
@ -563,14 +596,14 @@ fn write_make_deps(world: &mut SystemWorld, config: &CompileConfig) -> StrResult
|
||||
};
|
||||
|
||||
file.write_all(b" ")?;
|
||||
file.write_all(munge(dependency).as_bytes())?;
|
||||
file.write_all(munge(relative_dependency).as_bytes())?;
|
||||
}
|
||||
file.write_all(b"\n")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
write(make_deps_path, output_path, world.root().to_owned(), world.dependencies())
|
||||
write(make_deps_path, output_paths, world.root().to_owned(), world.dependencies())
|
||||
.map_err(|err| {
|
||||
eco_format!("failed to create make dependencies file due to IO error ({err})")
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user