mirror of
https://github.com/sharkdp/bat.git
synced 2025-01-14 01:28:18 +01:00
Change circle detection to use new more conservative method and run in main loop instead of before the loop
This commit is contained in:
parent
a98811b6d7
commit
694b31909a
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -98,6 +98,7 @@ dependencies = [
|
|||||||
"git2",
|
"git2",
|
||||||
"globset",
|
"globset",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"nix",
|
||||||
"path_abs",
|
"path_abs",
|
||||||
"predicates",
|
"predicates",
|
||||||
"semver",
|
"semver",
|
||||||
@ -213,12 +214,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clircle"
|
name = "clircle"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e27a01e782190a8314e65cc94274d9bbcd52e05a9d15b437fe2b31259b854b0d"
|
checksum = "e68bbd985a63de680ab4d1ad77b6306611a8f961b282c8b5ab513e6de934e396"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"nix",
|
"libc",
|
||||||
"serde",
|
"serde",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
@ -48,7 +48,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
semver = "0.11"
|
semver = "0.11"
|
||||||
path_abs = { version = "0.5", default-features = false }
|
path_abs = { version = "0.5", default-features = false }
|
||||||
clircle = "0.2.0"
|
clircle = "0.3"
|
||||||
bugreport = "0.3"
|
bugreport = "0.3"
|
||||||
dirs-next = { version = "2.0.0", optional = true }
|
dirs-next = { version = "2.0.0", optional = true }
|
||||||
|
|
||||||
|
@ -329,7 +329,7 @@ mod tests {
|
|||||||
|
|
||||||
let input = Input::ordinary_file(file_path.as_os_str());
|
let input = Input::ordinary_file(file_path.as_os_str());
|
||||||
let dummy_stdin: &[u8] = &[];
|
let dummy_stdin: &[u8] = &[];
|
||||||
let mut opened_input = input.open(dummy_stdin).unwrap();
|
let mut opened_input = input.open(dummy_stdin, None).unwrap();
|
||||||
|
|
||||||
self.assets
|
self.assets
|
||||||
.get_syntax(None, &mut opened_input, &self.syntax_mapping)
|
.get_syntax(None, &mut opened_input, &self.syntax_mapping)
|
||||||
@ -343,7 +343,7 @@ mod tests {
|
|||||||
let input = Input::from_reader(Box::new(BufReader::new(first_line.as_bytes())))
|
let input = Input::from_reader(Box::new(BufReader::new(first_line.as_bytes())))
|
||||||
.with_name(Some(file_path.as_os_str()));
|
.with_name(Some(file_path.as_os_str()));
|
||||||
let dummy_stdin: &[u8] = &[];
|
let dummy_stdin: &[u8] = &[];
|
||||||
let mut opened_input = input.open(dummy_stdin).unwrap();
|
let mut opened_input = input.open(dummy_stdin, None).unwrap();
|
||||||
|
|
||||||
self.assets
|
self.assets
|
||||||
.get_syntax(None, &mut opened_input, &self.syntax_mapping)
|
.get_syntax(None, &mut opened_input, &self.syntax_mapping)
|
||||||
@ -367,7 +367,7 @@ mod tests {
|
|||||||
|
|
||||||
fn syntax_for_stdin_with_content(&self, file_name: &str, content: &[u8]) -> String {
|
fn syntax_for_stdin_with_content(&self, file_name: &str, content: &[u8]) -> String {
|
||||||
let input = Input::stdin().with_name(Some(OsStr::new(file_name)));
|
let input = Input::stdin().with_name(Some(OsStr::new(file_name)));
|
||||||
let mut opened_input = input.open(content).unwrap();
|
let mut opened_input = input.open(content, None).unwrap();
|
||||||
|
|
||||||
self.assets
|
self.assets
|
||||||
.get_syntax(None, &mut opened_input, &self.syntax_mapping)
|
.get_syntax(None, &mut opened_input, &self.syntax_mapping)
|
||||||
@ -523,7 +523,7 @@ mod tests {
|
|||||||
|
|
||||||
let input = Input::ordinary_file(file_path_symlink.as_os_str());
|
let input = Input::ordinary_file(file_path_symlink.as_os_str());
|
||||||
let dummy_stdin: &[u8] = &[];
|
let dummy_stdin: &[u8] = &[];
|
||||||
let mut opened_input = input.open(dummy_stdin).unwrap();
|
let mut opened_input = input.open(dummy_stdin, None).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
test.assets
|
test.assets
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::convert::TryFrom;
|
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
use crate::assets::HighlightingAssets;
|
use crate::assets::HighlightingAssets;
|
||||||
@ -15,6 +14,8 @@ use crate::output::OutputType;
|
|||||||
use crate::paging::PagingMode;
|
use crate::paging::PagingMode;
|
||||||
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
|
use crate::printer::{InteractivePrinter, Printer, SimplePrinter};
|
||||||
|
|
||||||
|
use clircle::Clircle;
|
||||||
|
|
||||||
pub struct Controller<'a> {
|
pub struct Controller<'a> {
|
||||||
config: &'a Config<'a>,
|
config: &'a Config<'a>,
|
||||||
assets: &'a HighlightingAssets,
|
assets: &'a HighlightingAssets,
|
||||||
@ -67,12 +68,10 @@ impl<'b> Controller<'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let attached_to_pager = output_type.is_pager();
|
let attached_to_pager = output_type.is_pager();
|
||||||
let rw_cycle_detected = !attached_to_pager && {
|
let stdout_identifier = if cfg!(windows) || attached_to_pager {
|
||||||
let identifiers: Vec<_> = inputs
|
None
|
||||||
.iter()
|
} else {
|
||||||
.flat_map(clircle::Identifier::try_from)
|
clircle::Identifier::stdout()
|
||||||
.collect();
|
|
||||||
clircle::stdout_among_inputs(&identifiers)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let writer = output_type.handle()?;
|
let writer = output_type.handle()?;
|
||||||
@ -87,13 +86,8 @@ impl<'b> Controller<'b> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if rw_cycle_detected {
|
|
||||||
print_error(&"The output file is also an input!".into(), writer);
|
|
||||||
return Ok(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (index, input) in inputs.into_iter().enumerate() {
|
for (index, input) in inputs.into_iter().enumerate() {
|
||||||
match input.open(io::stdin().lock()) {
|
match input.open(io::stdin().lock(), stdout_identifier.as_ref()) {
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
print_error(&error, writer);
|
print_error(&error, writer);
|
||||||
no_errors = false;
|
no_errors = false;
|
||||||
|
60
src/input.rs
60
src/input.rs
@ -2,8 +2,8 @@ use std::convert::TryFrom;
|
|||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, BufRead, BufReader, Read};
|
use std::io::{self, BufRead, BufReader, Read};
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
|
use clircle::{Clircle, Identifier};
|
||||||
use content_inspector::{self, ContentType};
|
use content_inspector::{self, ContentType};
|
||||||
|
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
@ -157,25 +157,55 @@ impl<'a> Input<'a> {
|
|||||||
&mut self.description
|
&mut self.description
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn open<R: BufRead + 'a>(self, stdin: R) -> Result<OpenedInput<'a>> {
|
pub(crate) fn open<R: BufRead + 'a>(
|
||||||
|
self,
|
||||||
|
stdin: R,
|
||||||
|
stdout_identifier: Option<&Identifier>,
|
||||||
|
) -> Result<OpenedInput<'a>> {
|
||||||
let description = self.description().clone();
|
let description = self.description().clone();
|
||||||
match self.kind {
|
match self.kind {
|
||||||
InputKind::StdIn => Ok(OpenedInput {
|
InputKind::StdIn => {
|
||||||
kind: OpenedInputKind::StdIn,
|
if let Some(stdout) = stdout_identifier {
|
||||||
description,
|
let input_identifier = Identifier::try_from(clircle::Stdio::Stdin)
|
||||||
metadata: self.metadata,
|
.map_err(|e| format!("Stdin: Error identifying file: {}", e))?;
|
||||||
reader: InputReader::new(stdin),
|
if stdout.surely_conflicts_with(&input_identifier) {
|
||||||
}),
|
return Err("IO circle detected. The input from stdin is also an output. Aborting to avoid infinite loop.".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(OpenedInput {
|
||||||
|
kind: OpenedInputKind::StdIn,
|
||||||
|
description,
|
||||||
|
metadata: self.metadata,
|
||||||
|
reader: InputReader::new(stdin),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
InputKind::OrdinaryFile(path) => Ok(OpenedInput {
|
InputKind::OrdinaryFile(path) => Ok(OpenedInput {
|
||||||
kind: OpenedInputKind::OrdinaryFile(path.clone()),
|
kind: OpenedInputKind::OrdinaryFile(path.clone()),
|
||||||
description,
|
description,
|
||||||
metadata: self.metadata,
|
metadata: self.metadata,
|
||||||
reader: {
|
reader: {
|
||||||
let file = File::open(&path)
|
let mut file = File::open(&path)
|
||||||
.map_err(|e| format!("'{}': {}", path.to_string_lossy(), e))?;
|
.map_err(|e| format!("'{}': {}", path.to_string_lossy(), e))?;
|
||||||
if file.metadata()?.is_dir() {
|
if file.metadata()?.is_dir() {
|
||||||
return Err(format!("'{}' is a directory.", path.to_string_lossy()).into());
|
return Err(format!("'{}' is a directory.", path.to_string_lossy()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(stdout) = stdout_identifier {
|
||||||
|
let input_identifier = Identifier::try_from(file).map_err(|e| {
|
||||||
|
format!("{}: Error identifying file: {}", path.to_string_lossy(), e)
|
||||||
|
})?;
|
||||||
|
if stdout.surely_conflicts_with(&input_identifier) {
|
||||||
|
return Err(format!(
|
||||||
|
"IO circle detected. The input from '{}' is also an output. Aborting to avoid infinite loop.",
|
||||||
|
path.to_string_lossy()
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
file = input_identifier.into_inner().expect("The file was lost in the clircle::Identifier, this should not have happended...");
|
||||||
|
}
|
||||||
|
|
||||||
InputReader::new(BufReader::new(file))
|
InputReader::new(BufReader::new(file))
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -189,18 +219,6 @@ impl<'a> Input<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&'_ Input<'_>> for clircle::Identifier {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(input: &Input) -> std::result::Result<clircle::Identifier, ()> {
|
|
||||||
match input.kind {
|
|
||||||
InputKind::OrdinaryFile(ref path) => Self::try_from(Path::new(path)).map_err(|_| ()),
|
|
||||||
InputKind::StdIn => Self::try_from(clircle::Stdio::Stdin).map_err(|_| ()),
|
|
||||||
InputKind::CustomReader(_) => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct InputReader<'a> {
|
pub(crate) struct InputReader<'a> {
|
||||||
inner: Box<dyn BufRead + 'a>,
|
inner: Box<dyn BufRead + 'a>,
|
||||||
pub(crate) first_line: Vec<u8>,
|
pub(crate) first_line: Vec<u8>,
|
||||||
|
Loading…
Reference in New Issue
Block a user