Skip to content

Commit 5194d43

Browse files
authored
Feature: prefer tectonic-biber as the biber executable (#1166)
2 parents fbfcb8e + 52a000d commit 5194d43

File tree

6 files changed

+105
-31
lines changed

6 files changed

+105
-31
lines changed

Cargo.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ watchexec = "8.0"
9898
watchexec-filterer-globset = "8.0"
9999
watchexec-signals = "5.0"
100100
watchexec-supervisor = "5.0"
101+
which = "8.0"
101102
zip = { version = "4.0", default-features = false, features = ["deflate"] }
102103
clap_complete = "4.5.1"
103104
walkdir = "2"

docs/src/ref/v2cli.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,13 @@ nextonic show shell-completions --help
7272

7373
The V2 interface also supports external commands. If you run `tectonic -X cmd`, where `cmd` is NOT built into Tectonic, Tectonic will search for a binary called `tectonic-cmd` and run it if it exists.
7474

75+
In particular, if a `tectonic-biber` binary is found it will be preferred over
76+
the regular `biber` binary when generating bibliography with the `biblatex`
77+
package. This may help resolve [possible version mismatch][biber-mismatch]
78+
between `biber` and the bundled `biblatex` files when there are multiple TeX
79+
installations on a system.
7580

76-
81+
[biber-mismatch]: https://github.com/tectonic-typesetting/tectonic/issues/893
7782

7883
## Migration plan
7984

src/driver.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use tectonic_io_base::{
3737
stdstreams::{BufferedPrimaryIo, GenuineStdoutIo},
3838
InputHandle, IoProvider, OpenResult, OutputHandle,
3939
};
40+
use which::which;
4041

4142
use crate::{
4243
ctry, errmsg,
@@ -1683,7 +1684,7 @@ impl ProcessingSession {
16831684
Some(RerunReason::Bibtex)
16841685
} else {
16851686
warnings = self.tex_pass(None, status)?;
1686-
let maybe_biber = self.check_biber_requirement()?;
1687+
let maybe_biber = self.check_biber_requirement(status)?;
16871688

16881689
if let Some(biber) = maybe_biber {
16891690
self.bs.external_tool_pass(&biber, status)?;
@@ -2034,7 +2035,10 @@ impl ProcessingSession {
20342035
/// `loqreq` package to figure out what files `biber` needs. This
20352036
/// functionality should probably become more generic, but I don't have a
20362037
/// great sense as to how widely-used `logreq` is.
2037-
fn check_biber_requirement(&self) -> Result<Option<ExternalToolPass>> {
2038+
fn check_biber_requirement(
2039+
&self,
2040+
status: &mut dyn StatusBackend,
2041+
) -> Result<Option<ExternalToolPass>> {
20382042
// Is there a `.run.xml` file?
20392043

20402044
let mut run_xml_path = PathBuf::from(&self.primary_input_tex_path);
@@ -2057,10 +2061,36 @@ impl ProcessingSession {
20572061
);
20582062

20592063
let mut argv = match s {
2060-
(true, Ok(text)) => text.split_whitespace().map(|x| x.to_owned()).collect(),
2064+
(true, Ok(text)) if !text.trim().is_empty() => {
2065+
text.split_whitespace().map(|x| x.to_owned()).collect()
2066+
}
2067+
// when `TECTONIC_TEST_FAKE_BIBER` is empty, proceed to discover
2068+
// the biber binary as follows.
20612069
_ => vec!["biber".to_owned()],
20622070
};
20632071

2072+
// Moreover, we allow an override of the biber executable, to cope with
2073+
// possible version mismatch of the bundled biblatex package, as filed
2074+
// in issue #893. Since PR #1103, the `tectonic-biber` override can
2075+
// also be invoked with `tectonic -X biber`.
2076+
let find_by = |binary_name: &str| -> Option<String> {
2077+
if let Ok(pathbuf) = which(binary_name) {
2078+
if let Some(biber_path) = pathbuf.to_str() {
2079+
return Some(biber_path.to_owned());
2080+
}
2081+
}
2082+
None
2083+
};
2084+
2085+
let mut use_tectonic_biber_override = false;
2086+
for binary_name in ["./tectonic-biber", "tectonic-biber"] {
2087+
if let Some(biber_path) = find_by(binary_name) {
2088+
argv = vec![biber_path];
2089+
use_tectonic_biber_override = true;
2090+
break;
2091+
}
2092+
}
2093+
20642094
let mut extra_requires = HashSet::new();
20652095

20662096
// Do a sketchy XML parse to see if there's info about a biber
@@ -2227,6 +2257,9 @@ impl ProcessingSession {
22272257
// No biber invocation, in the end.
22282258
None
22292259
} else {
2260+
if use_tectonic_biber_override {
2261+
tt_note!(status, "using `tectonic-biber`, found at {}", argv[0]);
2262+
}
22302263
Some(ExternalToolPass {
22312264
argv,
22322265
extra_requires,

tests/executable.rs

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// Copyright 2016-2022 the Tectonic Project
21
// Licensed under the MIT License.
32

43
use lazy_static::lazy_static;
@@ -265,11 +264,17 @@ fn bad_outfmt_1() {
265264
}
266265

267266
fn run_with_biber(args: &str, stdin: &str) -> Output {
267+
run_with_biber_exe(None, args, stdin, &["subdirectory/empty.bib"])
268+
}
269+
270+
fn run_with_biber_exe(executable: Option<&str>, args: &str, stdin: &str, files: &[&str]) -> Output {
268271
let fmt_arg = get_plain_format_arg();
269-
let tempdir = setup_and_copy_files(&["subdirectory/empty.bib"]);
272+
let tempdir = setup_and_copy_files(files);
270273
let mut command = prep_tectonic(tempdir.path(), &[&fmt_arg, "-"]);
271274

272-
let test_cmd = if cfg!(windows) {
275+
let test_cmd = if let Some(exe) = executable {
276+
format!("{exe} {args}")
277+
} else if cfg!(windows) {
273278
format!(
274279
"cmd /c {} {}",
275280
util::test_path(&["fake-biber.bat"]).display(),
@@ -355,28 +360,9 @@ fn biber_failure() {
355360

356361
#[test]
357362
fn biber_no_such_tool() {
358-
let fmt_arg = get_plain_format_arg();
359-
let tempdir = setup_and_copy_files(&[]);
360-
let mut command = prep_tectonic(tempdir.path(), &[&fmt_arg, "-"]);
361-
362-
command.env("TECTONIC_TEST_FAKE_BIBER", "ohnothereisnobiberprogram");
363-
364363
const REST: &str = r"\bye";
365364
let tex = format!("{BIBER_TRIGGER_TEX}{REST}");
366-
367-
command
368-
.stdin(Stdio::piped())
369-
.stdout(Stdio::piped())
370-
.stderr(Stdio::piped());
371-
println!("running {command:?}");
372-
let mut child = command.spawn().expect("tectonic failed to start");
373-
374-
write!(child.stdin.as_mut().unwrap(), "{tex}")
375-
.expect("failed to send data to tectonic subprocess");
376-
377-
let output = child
378-
.wait_with_output()
379-
.expect("failed to wait on tectonic subprocess");
365+
let output = run_with_biber_exe(Some("ohnothereisnobiberprogram"), "", &tex, &[]);
380366
error_or_panic(&output);
381367
}
382368

@@ -387,9 +373,7 @@ fn biber_signal() {
387373
error_or_panic(&output);
388374
}
389375

390-
#[test]
391-
fn biber_success() {
392-
const REST: &str = r"
376+
const BIBER_VALIDATE_TEX: &str = r"
393377
\ifsecond
394378
\ifnum\input{biberout.qqq}=456\relax
395379
a
@@ -398,11 +382,30 @@ a
398382
\fi
399383
\fi
400384
\bye";
401-
let tex = format!("{BIBER_TRIGGER_TEX}{REST}");
385+
386+
#[test]
387+
fn biber_success() {
388+
let tex = format!("{BIBER_TRIGGER_TEX}{BIBER_VALIDATE_TEX}");
402389
let output = run_with_biber("success", &tex);
403390
success_or_panic(&output);
404391
}
405392

393+
/// Test `tectonic-biber` override: when no args passed, fall back to $PATH
394+
/// lookup for `tectonic-biber` first, and then `biber`. Currently defined in:
395+
/// [`tectonic::driver::ProcessingSession::check_biber_requirement`]
396+
#[cfg(unix)]
397+
#[test]
398+
fn biber_tectonic_override() {
399+
let tex = format!("{BIBER_TRIGGER_TEX}{BIBER_VALIDATE_TEX}");
400+
let output = run_with_biber_exe(
401+
Some(""),
402+
"", // no args passed
403+
&tex,
404+
&["subdirectory/empty.bib", "tectonic-biber"],
405+
);
406+
success_or_panic(&output);
407+
}
408+
406409
/// #844: biber input with absolute path blows away the file
407410
///
408411
/// We need to create a separate temporary directory to see if the abspath input

tests/executable/tectonic-biber

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#! /bin/sh
2+
# Copyright 2021 the Tetonic Project
3+
# Licensed under the MIT License.
4+
5+
# A stand-in for biber for our testing framework.
6+
7+
echo "tectonic-biber says success and makes a file"
8+
echo 456 >biberout.qqq

0 commit comments

Comments
 (0)