--make-deps fixes (#5873)

This commit is contained in:
Matthew Toohey 2025-02-18 13:04:40 -05:00 committed by GitHub
parent 74e4f78687
commit 3de3813ca0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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, &current_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})")
})