Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Introduce bundle serve command. #1195

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/bundles/src/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,10 @@
InputOrigin::Other,
))
}

fn input_path(&mut self, name: &str, status: &mut dyn StatusBackend) -> OpenResult<PathBuf> {
self.ensure_file_availability(name, status)
}

Check warning on line 664 in crates/bundles/src/cache.rs

View check run for this annotation

Codecov / codecov/patch

crates/bundles/src/cache.rs#L662-L664

Added lines #L662 - L664 were not covered by tests
}

impl<CB: CacheBackend> Bundle for CachingBundle<CB> {
Expand Down
9 changes: 9 additions & 0 deletions crates/io_base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,15 @@
}
}

/// Return the path of an input file if it happens to be stored on the file system.
///
/// A minimal implementation can always return [`OpenResult::NotAvailable`].
/// If a file is on the file system, it is preferred by the "bundle serve" command to return a
/// local path rather than dumping the contents.
fn input_path(&mut self, _name: &str, _status: &mut dyn StatusBackend) -> OpenResult<PathBuf> {
OpenResult::NotAvailable
}

Check warning on line 495 in crates/io_base/src/lib.rs

View check run for this annotation

Codecov / codecov/patch

crates/io_base/src/lib.rs#L493-L495

Added lines #L493 - L495 were not covered by tests

/// Open the "primary" input file, which in the context of TeX is the main
/// input that it's given. When the build is being done using the
/// filesystem and the input is a file on the filesystem, this function
Expand Down
74 changes: 74 additions & 0 deletions src/bin/tectonic/v2cli/commands/bundle.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use clap::{Parser, Subcommand};
use std::io::Write;
use tectonic::{
config::PersistentConfig,
docmodel::{DocumentExt, DocumentSetupOptions},
errors::Result,
io::{InputFeatures, OpenResult},
tt_note,
};
use tectonic_bundles::Bundle;
Expand Down Expand Up @@ -60,20 +62,26 @@
#[command(name = "search")]
/// Filter the list of filenames contained in the bundle
Search(BundleSearchCommand),

#[command(name = "serve")]
/// Dump the contents of files requested on standard input
Serve(BundleServeCommand),
}

impl TectonicCommand for BundleCommand {
fn customize(&self, cc: &mut CommandCustomizations) {
match &self.command {
BundleCommands::Cat(c) => c.customize(cc),
BundleCommands::Search(c) => c.customize(cc),
BundleCommands::Serve(c) => c.customize(cc),

Check warning on line 76 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L76

Added line #L76 was not covered by tests
}
}

fn execute(self, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
match self.command {
BundleCommands::Cat(c) => c.execute(config, status),
BundleCommands::Search(c) => c.execute(config, status),
BundleCommands::Serve(c) => c.execute(config, status),

Check warning on line 84 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L84

Added line #L84 was not covered by tests
}
}
}
Expand Down Expand Up @@ -138,3 +146,69 @@
Ok(0)
}
}

#[derive(Debug, Eq, PartialEq, Parser)]
struct BundleServeCommand {
/// Use only resource files cached locally
#[arg(short = 'C', long)]
only_cached: bool,
}

impl BundleServeCommand {
fn customize(&self, cc: &mut CommandCustomizations) {
cc.always_stderr = true;
}

Check warning on line 160 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L158-L160

Added lines #L158 - L160 were not covered by tests

fn execute(self, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
let mut bundle = get_a_bundle(config, self.only_cached, status)?;
let mut filename = String::new();
let stdin = std::io::stdin();
let mut stdout = std::io::stdout();

Check warning on line 166 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L162-L166

Added lines #L162 - L166 were not covered by tests
loop {
stdout.flush()?;
filename.clear();
match stdin.read_line(&mut filename) {
Err(error) => {
eprintln!("error: {error}");
return Ok(1);
}
Ok(0) => return Ok(0),

Check warning on line 175 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L168-L175

Added lines #L168 - L175 were not covered by tests
Ok(_) => {
let name = filename.trim_end();
let error = match bundle.input_path(name, status) {
OpenResult::Err(e) => e,
OpenResult::Ok(path) => {
let mut path = path.as_os_str().as_encoded_bytes();
let size = path.len() as u64;
stdout.write_all(&[b'P'])?;
stdout.write_all(&size.to_le_bytes())?;
let copied = std::io::copy(&mut path, &mut stdout)?;
assert!(size == copied);

Check warning on line 186 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L177-L186

Added lines #L177 - L186 were not covered by tests
continue;
}

Check warning on line 188 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L188

Added line #L188 was not covered by tests
OpenResult::NotAvailable => {
match bundle.input_open_name(name, status).must_exist() {
Ok(mut t) => {
let size = t.get_size()? as u64;
stdout.write_all(&[b'C'])?;
stdout.write_all(&size.to_le_bytes())?;
let copied = std::io::copy(&mut t, &mut stdout)?;
assert!(size == copied);

Check warning on line 196 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L190-L196

Added lines #L190 - L196 were not covered by tests
continue;
}
Err(e) => e,

Check warning on line 199 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L198-L199

Added lines #L198 - L199 were not covered by tests
}
}

Check warning on line 201 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L201

Added line #L201 was not covered by tests
};
let text = error.to_string();
let bytes = text.as_bytes();
let size = bytes.len() as u64;
stdout.write_all(&[b'E'])?;
stdout.write_all(&size.to_le_bytes())?;
stdout.write_all(&bytes)?;
}

Check warning on line 209 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L203-L209

Added lines #L203 - L209 were not covered by tests
};
stdout.flush().unwrap();

Check warning on line 211 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L211

Added line #L211 was not covered by tests
}
}

Check warning on line 213 in src/bin/tectonic/v2cli/commands/bundle.rs

View check run for this annotation

Codecov / codecov/patch

src/bin/tectonic/v2cli/commands/bundle.rs#L213

Added line #L213 was not covered by tests
}
Loading