summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorMatthew Toohey <contact@mtoohey.com>2025-02-18 13:04:40 -0500
committerGitHub <noreply@github.com>2025-02-18 18:04:40 +0000
commit3de3813ca06c332cd1eae14c64913725a9333aff (patch)
treebd2870f6cb8d54425af73153e7dab6e0034ef7e6 /crates
parent74e4f78687d7acb5db3d531959c956717cce837a (diff)
--make-deps fixes (#5873)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst-cli/src/compile.rs83
1 files changed, 58 insertions, 25 deletions
diff --git a/crates/typst-cli/src/compile.rs b/crates/typst-cli/src/compile.rs
index 515a777a..2b6a7d82 100644
--- a/crates/typst-cli/src/compile.rs
+++ b/crates/typst-cli/src/compile.rs
@@ -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})")
})