Added logging configuration

This commit is contained in:
rm-dr 2024-09-18 22:14:22 -07:00
parent 8ff504bde0
commit 2b4a87b130
No known key found for this signature in database
GPG Key ID: B4DF96450FAAD9F2
3 changed files with 108 additions and 149 deletions

View File

@ -46,7 +46,7 @@ The following are the available flags.
| Short | Full | Explanation |
|:------|:-------------------------------|:-------------------------------------------------------------------------------------------------------|
| `-b` | `--bundle <file_path>` | Use this directory or Zip-format bundle file to find resource files instead of the default |
| `-c` | `--chatter <level>` | How much chatter to print when running [default: `default`] [possible values: `default`, `minimal`] |
| `-c` | `--log <level>` | Maximum log level to print [default: `info`] [possible values: `debug`, `info`, `warn`, `error`] |
| | `--color <when>` | Enable/disable colorful log output [default: `auto`] [possible values: `always`, `auto`, `never`] |
| `-f` | `--format <path>` | The name of the "format" file used to initialize the TeX engine [default: `latex`] |
| `-h` | `--help` | Prints help information |

View File

@ -6,7 +6,7 @@
use std::{
convert::Infallible, env, ffi::OsString, fs, io::Write, path::Path, path::PathBuf, process,
str::FromStr, sync::Arc,
sync::Arc,
};
use structopt::{clap::AppSettings, StructOpt};
use tectonic::{
@ -15,16 +15,14 @@ use tectonic::{
ctry,
docmodel::{DocumentExt, DocumentSetupOptions, WorkspaceCreatorExt},
driver::PassSetting,
errors::{Result, SyncError},
status::{termcolor::TermcolorStatusBackend, ChatterLevel, StatusBackend},
tt_error, tt_note,
errors::Result,
};
use tectonic_bridge_core::{SecuritySettings, SecurityStance};
use tectonic_bundles::Bundle;
use tectonic_docmodel::workspace::{Workspace, WorkspaceCreator};
use tectonic_errors::prelude::anyhow;
use tectonic_status_base::plain::PlainStatusBackend;
use tokio::runtime;
use tracing::{error, info, Level};
use watchexec::event::ProcessEnd;
use watchexec::{
action::{Action, Outcome, PreSpawn},
@ -35,6 +33,8 @@ use watchexec::{
use watchexec_filterer_globset::GlobsetFilterer;
use watchexec_signals::Signal;
use crate::log::LogFormatter;
/// The main options for the "V2" command-line interface.
#[derive(Debug, StructOpt)]
#[structopt(
@ -43,23 +43,23 @@ use watchexec_signals::Signal;
setting(AppSettings::NoBinaryName)
)]
struct V2CliOptions {
/// How much chatter to print when running
/// Maximum log level to print when running
#[structopt(
long = "chatter",
short,
name = "level",
default_value = "default",
possible_values(&["default", "minimal"])
)]
chatter_level: String,
long = "log",
short,
name = "level",
default_value = "info",
possible_values(&["debug", "info", "warn", "error"])
)]
log_level: String,
/// Control colorization of output
#[structopt(
long = "color",
name = "when",
default_value = "auto",
possible_values(&["always", "auto", "never"])
)]
long = "color",
name = "when",
default_value = "auto",
possible_values(&["always", "auto", "never"])
)]
cli_color: String,
/// Use this URL to find resource files instead of the default
@ -106,7 +106,6 @@ pub fn v2_main(effective_args: &[OsString]) {
};
// Parse args -- this will exit if there are problems.
let args = V2CliOptions::from_iter(effective_args);
// Command-specific customizations before we do our centralized setup.
@ -116,44 +115,34 @@ pub fn v2_main(effective_args: &[OsString]) {
let mut customizations = CommandCustomizations::default();
args.command.customize(&mut customizations);
// Set up colorized output.
let chatter_level = if customizations.minimal_chatter {
ChatterLevel::Minimal
} else {
ChatterLevel::from_str(&args.chatter_level).unwrap()
// Set up logger
let log_level = match &*args.log_level {
"debug" => Level::DEBUG,
"info" => Level::INFO,
"warn" => Level::WARN,
"error" => Level::ERROR,
_ => unreachable!(),
};
let use_cli_color = match &*args.cli_color {
"always" => true,
"auto" => atty::is(atty::Stream::Stdout),
"never" => false,
_ => unreachable!(),
};
tracing_subscriber::fmt()
.with_max_level(log_level)
.event_format(LogFormatter::new(use_cli_color))
.init();
let mut status = if use_cli_color {
let mut sb = TermcolorStatusBackend::new(chatter_level);
sb.always_stderr(customizations.always_stderr);
Box::new(sb) as Box<dyn StatusBackend>
} else {
let mut sb = PlainStatusBackend::new(chatter_level);
sb.always_stderr(customizations.always_stderr);
Box::new(sb) as Box<dyn StatusBackend>
};
// For now ...
tt_note!(
status,
info!(
tectonic_log_source = "cli",
"\"version 2\" Tectonic command-line interface activated"
);
// Now that we've got colorized output, pass off to the inner function.
let code = match args.command.execute(config, &mut *status, args.web_bundle) {
let code = match args.command.execute(config, args.web_bundle) {
Ok(c) => c,
Err(e) => {
status.report_error(&SyncError::new(e).into());
error!(tectonic_log_source = "cli", "{}", e.0.to_string());
1
}
};
@ -216,21 +205,16 @@ impl Commands {
}
}
fn execute(
self,
config: PersistentConfig,
status: &mut dyn StatusBackend,
web_bundle: Option<String>,
) -> Result<i32> {
fn execute(self, config: PersistentConfig, web_bundle: Option<String>) -> Result<i32> {
match self {
Commands::Build(o) => o.execute(config, status, web_bundle),
Commands::Bundle(o) => o.execute(config, status),
Commands::Compile(o) => o.execute(config, status, web_bundle),
Commands::Dump(o) => o.execute(config, status),
Commands::New(o) => o.execute(config, status, web_bundle),
Commands::Init(o) => o.execute(config, status, web_bundle),
Commands::Show(o) => o.execute(config, status),
Commands::Watch(o) => o.execute(config, status),
Commands::Build(o) => o.execute(config, web_bundle),
Commands::Bundle(o) => o.execute(config),
Commands::Compile(o) => o.execute(config, web_bundle),
Commands::Dump(o) => o.execute(config),
Commands::New(o) => o.execute(config, web_bundle),
Commands::Init(o) => o.execute(config, web_bundle),
Commands::Show(o) => o.execute(config),
Commands::Watch(o) => o.execute(config),
Commands::External(args) => do_external(args),
}
}
@ -271,17 +255,15 @@ pub struct BuildCommand {
impl BuildCommand {
fn customize(&self, _cc: &mut CommandCustomizations) {}
fn execute(
self,
config: PersistentConfig,
status: &mut dyn StatusBackend,
web_bundle: Option<String>,
) -> Result<i32> {
fn execute(self, config: PersistentConfig, web_bundle: Option<String>) -> Result<i32> {
// `--web-bundle` is not actually used for `-X build`,
// so inform the user instead of ignoring silently.
if let Some(url) = web_bundle {
tt_note!(status, "--web-bundle {} ignored", &url);
tt_note!(status, "using workspace bundle configuration");
warn!(tectonic_log_source = "cli", "--web-bundle {} ignored", &url);
warn!(
tectonic_log_source = "cli",
"using workspace bundle configuration"
);
}
let ws = Workspace::open_from_environment()?;
let doc = ws.first_document();
@ -307,7 +289,7 @@ impl BuildCommand {
}
}
let mut builder = doc.setup_session(output_name, &setup_options, status)?;
let mut builder = doc.setup_session(output_name, &setup_options)?;
builder
.format_cache_path(config.format_cache_path()?)
@ -315,21 +297,29 @@ impl BuildCommand {
.keep_logs(self.keep_logs)
.print_stdout(self.print_stdout);
crate::compile::run_and_report(builder, status)?;
crate::compile::run_and_report(builder)?;
if self.open {
let out_file = doc.output_main_file(output_name);
if is_config_test_mode_activated() {
tt_note!(status, "not opening `{}` -- test mode", out_file.display());
info!(
tectonic_log_source = "cli",
"not opening `{}` -- test mode",
out_file.display()
);
} else {
tt_note!(status, "opening `{}`", out_file.display());
info!(
tectonic_log_source = "cli",
"opening `{}`",
out_file.display()
);
if let Err(e) = open::that(&out_file) {
tt_error!(
status,
"failed to open `{}` with system handler",
out_file.display();
e.into()
error!(
tectonic_log_source = "cli",
"failed to open `{}` with system handler: {}",
out_file.display(),
e
)
}
}
@ -366,19 +356,15 @@ impl BundleCommand {
}
}
fn execute(self, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
fn execute(self, config: PersistentConfig) -> Result<i32> {
match self.command {
BundleCommands::Cat(c) => c.execute(config, status),
BundleCommands::Search(c) => c.execute(config, status),
BundleCommands::Cat(c) => c.execute(config),
BundleCommands::Search(c) => c.execute(config),
}
}
}
fn get_a_bundle(
_config: PersistentConfig,
only_cached: bool,
status: &mut dyn StatusBackend,
) -> Result<Box<dyn Bundle>> {
fn get_a_bundle(_config: PersistentConfig, only_cached: bool) -> Result<Box<dyn Bundle>> {
use tectonic_docmodel::workspace::NoWorkspaceFoundError;
match Workspace::open_from_environment() {
@ -386,21 +372,20 @@ fn get_a_bundle(
let doc = ws.first_document();
let mut options: DocumentSetupOptions = Default::default();
options.only_cached(only_cached);
doc.bundle(&options, status)
doc.bundle(&options)
}
Err(e) => {
if e.downcast_ref::<NoWorkspaceFoundError>().is_none() {
Err(e.into())
} else {
tt_note!(
status,
info!(
tectonic_log_source = "setup",
"not in a document workspace; using the built-in default bundle"
);
Ok(Box::new(tectonic_bundles::get_fallback_bundle(
tectonic_engine_xetex::FORMAT_SERIAL,
only_cached,
status,
)?))
}
}
@ -422,11 +407,9 @@ impl BundleCatCommand {
cc.always_stderr = true;
}
fn execute(self, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
let mut bundle = get_a_bundle(config, self.only_cached, status)?;
let mut ih = bundle
.input_open_name(&self.filename, status)
.must_exist()?;
fn execute(self, config: PersistentConfig) -> Result<i32> {
let mut bundle = get_a_bundle(config, self.only_cached)?;
let mut ih = bundle.input_open_name(&self.filename).must_exist()?;
std::io::copy(&mut ih, &mut std::io::stdout())?;
Ok(0)
}
@ -447,9 +430,9 @@ impl BundleSearchCommand {
cc.always_stderr = true;
}
fn execute(self, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
let mut bundle = get_a_bundle(config, self.only_cached, status)?;
let files = bundle.all_files(status)?;
fn execute(self, config: PersistentConfig) -> Result<i32> {
let mut bundle = get_a_bundle(config, self.only_cached)?;
let files = bundle.all_files()?;
// Is there a better way to do this?
let filter: Box<dyn Fn(&str) -> bool> = if let Some(t) = self.term {
@ -498,7 +481,7 @@ impl DumpCommand {
cc.minimal_chatter = true;
}
fn execute(self, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
fn execute(self, config: PersistentConfig) -> Result<i32> {
let ws = Workspace::open_from_environment()?;
let doc = ws.first_document();
@ -522,13 +505,13 @@ impl DumpCommand {
.as_ref()
.unwrap_or_else(|| doc.outputs.keys().next().unwrap());
let mut builder = doc.setup_session(output_name, &setup_options, status)?;
let mut builder = doc.setup_session(output_name, &setup_options)?;
builder
.format_cache_path(config.format_cache_path()?)
.pass(PassSetting::Tex);
let sess = crate::compile::run_and_report(builder, status)?;
let sess = crate::compile::run_and_report(builder)?;
let files = sess.into_file_data();
if self.suffix_mode {
@ -545,10 +528,9 @@ impl DumpCommand {
}
if !found_any {
tt_error!(
status,
"found no intermediate files with names ending in `{}`",
self.filename
error!(
tectonic_log_source = "cli",
"found no intermediate files with names ending in `{}`", self.filename
);
return Ok(1);
}
@ -577,7 +559,7 @@ pub struct WatchCommand {
impl WatchCommand {
fn customize(&self, _cc: &mut CommandCustomizations) {}
async fn execute_inner(self, status: &mut dyn StatusBackend) -> Result<i32> {
async fn execute_inner(self) -> Result<i32> {
let exe_name = crate::watch::get_trimmed_exe_name()
.into_os_string()
.into_string()
@ -675,10 +657,9 @@ impl WatchCommand {
match exec_handler {
Err(e) => {
tt_error!(
status,
"failed to build arguments for watch ExecHandler";
e.into()
error!(
tectonic_log_source = "cli",
"failed to build arguments for watch ExecHandler: {}", e
);
Ok(1)
}
@ -689,12 +670,12 @@ impl WatchCommand {
}
}
fn execute(self, _config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
fn execute(self, _config: PersistentConfig) -> Result<i32> {
let rt = runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
rt.block_on(self.execute_inner(status))
rt.block_on(self.execute_inner())
}
}
@ -709,21 +690,16 @@ pub struct NewCommand {
impl NewCommand {
fn customize(&self, _cc: &mut CommandCustomizations) {}
fn execute(
self,
config: PersistentConfig,
status: &mut dyn StatusBackend,
web_bundle: Option<String>,
) -> Result<i32> {
tt_note!(
status,
fn execute(self, config: PersistentConfig, web_bundle: Option<String>) -> Result<i32> {
info!(
tectonic_log_source = "cli",
"creating new document in directory `{}`",
self.path.display()
);
let wc = WorkspaceCreator::new(self.path);
ctry!(
wc.create_defaulted(config, status, web_bundle);
wc.create_defaulted(config, web_bundle);
"failed to create the new Tectonic workspace"
);
Ok(0)
@ -737,22 +713,17 @@ pub struct InitCommand {}
impl InitCommand {
fn customize(&self, _cc: &mut CommandCustomizations) {}
fn execute(
self,
config: PersistentConfig,
status: &mut dyn StatusBackend,
web_bundle: Option<String>,
) -> Result<i32> {
fn execute(self, config: PersistentConfig, web_bundle: Option<String>) -> Result<i32> {
let path = env::current_dir()?;
tt_note!(
status,
info!(
tectonic_log_source = "cli",
"creating new document in this directory ({})",
path.display()
);
let wc = WorkspaceCreator::new(path);
ctry!(
wc.create_defaulted(config, status, web_bundle);
wc.create_defaulted(config, web_bundle);
"failed to create the new Tectonic workspace"
);
Ok(0)
@ -780,9 +751,9 @@ impl ShowCommand {
}
}
fn execute(self, config: PersistentConfig, status: &mut dyn StatusBackend) -> Result<i32> {
fn execute(self, config: PersistentConfig) -> Result<i32> {
match self.command {
ShowCommands::UserCacheDir(c) => c.execute(config, status),
ShowCommands::UserCacheDir(c) => c.execute(config),
}
}
}
@ -795,7 +766,7 @@ impl ShowUserCacheDirCommand {
cc.always_stderr = true;
}
fn execute(self, _config: PersistentConfig, _status: &mut dyn StatusBackend) -> Result<i32> {
fn execute(self, _config: PersistentConfig) -> Result<i32> {
use tectonic_bundles::cache::Cache;
let cache = Cache::get_user_default()?;
println!("{}", cache.root().display());

View File

@ -21,10 +21,7 @@ use tectonic_bundles::{
use tectonic_io_base::app_dirs;
use url::Url;
use crate::{
errors::{ErrorKind, Result},
status::StatusBackend,
};
use crate::errors::{ErrorKind, Result};
/// Awesome hack time!!!
///
@ -139,7 +136,6 @@ impl PersistentConfig {
url: &str,
only_cached: bool,
custom_cache_root: Option<&Path>,
status: &mut dyn StatusBackend,
) -> Result<Box<dyn Bundle>> {
if let Ok(test_bundle) = maybe_return_test_bundle(Some(url.to_owned())) {
return Ok(test_bundle);
@ -151,15 +147,11 @@ impl PersistentConfig {
Cache::get_user_default()?
};
let bundle = cache.open::<IndexedTarBackend>(url, only_cached, status)?;
let bundle = cache.open::<IndexedTarBackend>(url, only_cached)?;
Ok(Box::new(bundle) as _)
}
pub fn make_local_file_provider(
&self,
file_path: PathBuf,
_status: &mut dyn StatusBackend,
) -> Result<Box<dyn Bundle>> {
pub fn make_local_file_provider(&self, file_path: PathBuf) -> Result<Box<dyn Bundle>> {
let bundle: Box<dyn Bundle> = if file_path.is_dir() {
Box::new(DirBundle::new(file_path))
} else {
@ -172,11 +164,7 @@ impl PersistentConfig {
&self.default_bundles[0].url
}
pub fn default_bundle(
&self,
only_cached: bool,
status: &mut dyn StatusBackend,
) -> Result<Box<dyn Bundle>> {
pub fn default_bundle(&self, only_cached: bool) -> Result<Box<dyn Bundle>> {
use std::io;
if let Ok(test_bundle) = maybe_return_test_bundle(None) {
@ -197,10 +185,10 @@ impl PersistentConfig {
let file_path = url.to_file_path().map_err(|_| {
io::Error::new(io::ErrorKind::InvalidInput, "failed to parse local path")
})?;
return self.make_local_file_provider(file_path, status);
return self.make_local_file_provider(file_path);
}
let bundle =
self.make_cached_url_provider(&self.default_bundles[0].url, only_cached, None, status)?;
self.make_cached_url_provider(&self.default_bundles[0].url, only_cached, None)?;
Ok(Box::new(bundle) as _)
}