Refactor command line format enumerator (#1045)
This commit is contained in:
Родитель
25212e8a59
Коммит
cf53c6a7a8
|
@ -1,6 +1,5 @@
|
|||
use std::fs::{create_dir_all, File};
|
||||
use std::io::Write;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
|
@ -21,97 +20,24 @@ impl Format {
|
|||
|
||||
pub fn dump_formats<T: Serialize>(
|
||||
&self,
|
||||
space: &T,
|
||||
path: &Path,
|
||||
output_path: &Option<PathBuf>,
|
||||
space: T,
|
||||
path: PathBuf,
|
||||
output_path: Option<&PathBuf>,
|
||||
pretty: bool,
|
||||
) -> std::io::Result<()> {
|
||||
if output_path.is_none() {
|
||||
let stdout = std::io::stdout();
|
||||
let mut stdout = stdout.lock();
|
||||
|
||||
) {
|
||||
if let Some(output_path) = output_path {
|
||||
match self {
|
||||
Format::Cbor => Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Cbor format cannot be printed to stdout",
|
||||
)),
|
||||
Format::Json => {
|
||||
let json_data = if pretty {
|
||||
serde_json::to_string_pretty(&space).unwrap()
|
||||
} else {
|
||||
serde_json::to_string(&space).unwrap()
|
||||
};
|
||||
writeln!(stdout, "{json_data}")
|
||||
}
|
||||
Format::Toml => {
|
||||
let toml_data = if pretty {
|
||||
toml::to_string_pretty(&space).unwrap()
|
||||
} else {
|
||||
toml::to_string(&space).unwrap()
|
||||
};
|
||||
writeln!(stdout, "{toml_data}")
|
||||
}
|
||||
Format::Yaml => writeln!(stdout, "{}", serde_yaml::to_string(&space).unwrap()),
|
||||
Self::Cbor => Cbor::with_writer(space, path, output_path),
|
||||
Self::Json => Json::with_pretty_writer(space, path, output_path, pretty),
|
||||
Self::Toml => Toml::with_pretty_writer(space, path, output_path, pretty),
|
||||
Self::Yaml => Yaml::with_writer(space, path, output_path),
|
||||
}
|
||||
} else {
|
||||
let format_ext = match self {
|
||||
Format::Cbor => ".cbor",
|
||||
Format::Json => ".json",
|
||||
Format::Toml => ".toml",
|
||||
Format::Yaml => ".yml",
|
||||
};
|
||||
|
||||
// Remove root /
|
||||
let path = path.strip_prefix("/").unwrap_or(path);
|
||||
|
||||
// Remove root ./
|
||||
let path = path.strip_prefix("./").unwrap_or(path);
|
||||
|
||||
// Replace .. with . to keep files inside the output folder
|
||||
let cleaned_path: Vec<&str> = path
|
||||
.iter()
|
||||
.map(|os_str| {
|
||||
let s_str = os_str.to_str().unwrap();
|
||||
if s_str == ".." {
|
||||
"."
|
||||
} else {
|
||||
s_str
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Create the filename
|
||||
let filename = cleaned_path.join("/") + format_ext;
|
||||
|
||||
// Build the file path
|
||||
let format_path = output_path.as_ref().unwrap().join(filename);
|
||||
|
||||
// Create directories
|
||||
create_dir_all(format_path.parent().unwrap()).unwrap();
|
||||
|
||||
let mut format_file = File::create(format_path)?;
|
||||
match self {
|
||||
Format::Cbor => serde_cbor::to_writer(format_file, &space)
|
||||
.map_err(|e| Error::new(ErrorKind::Other, e.to_string())),
|
||||
Format::Json => {
|
||||
if pretty {
|
||||
serde_json::to_writer_pretty(format_file, &space)
|
||||
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
|
||||
} else {
|
||||
serde_json::to_writer(format_file, &space)
|
||||
.map_err(|e| Error::new(ErrorKind::Other, e.to_string()))
|
||||
}
|
||||
}
|
||||
Format::Toml => {
|
||||
let toml_data = if pretty {
|
||||
toml::to_string_pretty(&space).unwrap()
|
||||
} else {
|
||||
toml::to_string(&space).unwrap()
|
||||
};
|
||||
format_file.write_all(toml_data.as_bytes())
|
||||
}
|
||||
Format::Yaml => serde_yaml::to_writer(format_file, &space)
|
||||
.map_err(|e| Error::new(ErrorKind::Other, e.to_string())),
|
||||
Self::Json => Json::write_on_stdout_pretty(space, pretty),
|
||||
Self::Toml => Toml::write_on_stdout_pretty(space, pretty),
|
||||
Self::Yaml => Yaml::write_on_stdout(space),
|
||||
Self::Cbor => panic!("Cbor format cannot be printed to stdout"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -130,3 +56,184 @@ impl FromStr for Format {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn print_on_stdout(content: String) {
|
||||
writeln!(std::io::stdout().lock(), "{content}").unwrap();
|
||||
}
|
||||
|
||||
trait WriteOnStdout {
|
||||
#[inline(always)]
|
||||
fn write_on_stdout<T: Serialize>(content: T) {
|
||||
print_on_stdout(Self::format(content));
|
||||
}
|
||||
|
||||
fn format<T: Serialize>(content: T) -> String;
|
||||
}
|
||||
|
||||
trait WritePrettyOnStdout: WriteOnStdout {
|
||||
fn write_on_stdout_pretty<T: Serialize>(content: T, pretty: bool) {
|
||||
print_on_stdout(if pretty {
|
||||
Self::format_pretty(content)
|
||||
} else {
|
||||
Self::format(content)
|
||||
});
|
||||
}
|
||||
fn format_pretty<T: Serialize>(content: T) -> String;
|
||||
}
|
||||
|
||||
fn handle_path(path: PathBuf, output_path: &Path, extension: &str) -> PathBuf {
|
||||
// Remove root /
|
||||
let path = path.as_path().strip_prefix("/").unwrap_or(path.as_path());
|
||||
|
||||
// Remove root ./
|
||||
let path = path.strip_prefix("./").unwrap_or(path);
|
||||
|
||||
// Replace .. with . to keep files inside the output folder
|
||||
let cleaned_path: Vec<&str> = path
|
||||
.iter()
|
||||
.map(|os_str| {
|
||||
let s_str = os_str.to_str().unwrap();
|
||||
if s_str == ".." {
|
||||
"."
|
||||
} else {
|
||||
s_str
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Create the filename
|
||||
let filename = cleaned_path.join("/") + extension;
|
||||
|
||||
// Build the file path
|
||||
output_path.join(filename)
|
||||
}
|
||||
|
||||
trait WriteFile {
|
||||
const EXTENSION: &'static str;
|
||||
|
||||
fn open_file(path: PathBuf, output_path: &Path) -> File {
|
||||
// Handle output path
|
||||
let format_path = handle_path(path, output_path, Self::EXTENSION);
|
||||
|
||||
// Create directories
|
||||
create_dir_all(format_path.parent().unwrap()).unwrap();
|
||||
|
||||
File::create(format_path).unwrap()
|
||||
}
|
||||
|
||||
fn with_writer<T: Serialize>(content: T, path: PathBuf, output_path: &Path);
|
||||
}
|
||||
|
||||
trait WritePrettyFile: WriteFile {
|
||||
fn with_pretty_writer<T: Serialize>(
|
||||
content: T,
|
||||
path: PathBuf,
|
||||
output_path: &Path,
|
||||
pretty: bool,
|
||||
);
|
||||
}
|
||||
|
||||
struct Json;
|
||||
|
||||
impl WriteOnStdout for Json {
|
||||
fn format<T: Serialize>(content: T) -> String {
|
||||
serde_json::to_string(&content).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl WritePrettyOnStdout for Json {
|
||||
fn format_pretty<T: Serialize>(content: T) -> String {
|
||||
serde_json::to_string_pretty(&content).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteFile for Json {
|
||||
const EXTENSION: &'static str = ".json";
|
||||
|
||||
fn with_writer<T: Serialize>(content: T, path: PathBuf, output_path: &Path) {
|
||||
serde_json::to_writer(Self::open_file(path, output_path), &content).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl WritePrettyFile for Json {
|
||||
fn with_pretty_writer<T: Serialize>(
|
||||
content: T,
|
||||
path: PathBuf,
|
||||
output_path: &Path,
|
||||
pretty: bool,
|
||||
) {
|
||||
if pretty {
|
||||
serde_json::to_writer_pretty(Self::open_file(path, output_path), &content).unwrap();
|
||||
} else {
|
||||
Self::with_writer(content, path, output_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Toml;
|
||||
|
||||
impl WriteOnStdout for Toml {
|
||||
fn format<T: Serialize>(content: T) -> String {
|
||||
toml::to_string(&content).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl WritePrettyOnStdout for Toml {
|
||||
fn format_pretty<T: Serialize>(content: T) -> String {
|
||||
toml::to_string_pretty(&content).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteFile for Toml {
|
||||
const EXTENSION: &'static str = ".toml";
|
||||
|
||||
fn with_writer<T: Serialize>(content: T, path: PathBuf, output_path: &Path) {
|
||||
Self::open_file(path, output_path)
|
||||
.write_all(Self::format(content).as_bytes())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl WritePrettyFile for Toml {
|
||||
fn with_pretty_writer<T: Serialize>(
|
||||
content: T,
|
||||
path: PathBuf,
|
||||
output_path: &Path,
|
||||
pretty: bool,
|
||||
) {
|
||||
if pretty {
|
||||
Self::open_file(path, output_path)
|
||||
.write_all(Self::format_pretty(&content).as_bytes())
|
||||
.unwrap();
|
||||
} else {
|
||||
Self::with_writer(content, path, output_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Yaml;
|
||||
|
||||
impl WriteOnStdout for Yaml {
|
||||
fn format<T: Serialize>(content: T) -> String {
|
||||
serde_yaml::to_string(&content).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl WriteFile for Yaml {
|
||||
const EXTENSION: &'static str = ".yml";
|
||||
|
||||
fn with_writer<T: Serialize>(content: T, path: PathBuf, output_path: &Path) {
|
||||
serde_yaml::to_writer(Self::open_file(path, output_path), &content).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
struct Cbor;
|
||||
|
||||
impl WriteFile for Cbor {
|
||||
const EXTENSION: &'static str = ".cbor";
|
||||
|
||||
fn with_writer<T: Serialize>(content: T, path: PathBuf, output_path: &Path) {
|
||||
serde_cbor::to_writer(Self::open_file(path, output_path), &content).unwrap()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,10 +92,9 @@ fn act_on_file(path: PathBuf, cfg: &Config) -> std::io::Result<()> {
|
|||
} else if cfg.metrics {
|
||||
if let Some(output_format) = &cfg.output_format {
|
||||
if let Some(space) = get_function_spaces(&language, source, &path, pr) {
|
||||
output_format.dump_formats(&space, &path, &cfg.output, cfg.pretty)
|
||||
} else {
|
||||
Ok(())
|
||||
output_format.dump_formats(space, path, cfg.output.as_ref(), cfg.pretty);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
let cfg = MetricsCfg { path };
|
||||
let path = cfg.path.clone();
|
||||
|
@ -104,7 +103,8 @@ fn act_on_file(path: PathBuf, cfg: &Config) -> std::io::Result<()> {
|
|||
} else if cfg.ops {
|
||||
if let Some(output_format) = &cfg.output_format {
|
||||
let ops = get_ops(&language, source, &path, pr).unwrap();
|
||||
output_format.dump_formats(&ops, &path, &cfg.output, cfg.pretty)
|
||||
output_format.dump_formats(ops, path, cfg.output.as_ref(), cfg.pretty);
|
||||
Ok(())
|
||||
} else {
|
||||
let cfg = OpsCfg { path };
|
||||
let path = cfg.path.clone();
|
||||
|
|
Загрузка…
Ссылка в новой задаче