use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use xron::Error;
fn app() -> App<'static, 'static> {
App::new("xron")
.about("Converts XLSX files to RON")
.author("Thomas Schaller")
.setting(AppSettings::ArgsNegateSubcommands)
.setting(AppSettings::SubcommandsNegateReqs)
.arg(
Arg::with_name("INPUT_FILE")
.required(true)
.takes_value(true)
.value_name("INPUT_FILE")
.index(1),
)
.arg(
Arg::with_name("reverse")
.help("Converts RON to XLSX")
.short("r")
.long("reverse")
.requires("output-file"),
)
.arg(
Arg::with_name("skip-empty")
.help("Does not insert empty rows into XLSX")
.long("skip-empty")
.requires("reverse"),
)
.arg(
Arg::with_name("column-width")
.help("Sets column width for XLSX")
.long("column-width")
.requires("reverse")
.takes_value(true)
.value_name("COLUMN_WIDTH"),
)
.arg(
Arg::with_name("output-file")
.short("o")
.long("output-file")
.takes_value(true)
.value_name("OUTPUT_TO_FILE"),
)
.subcommand(
SubCommand::with_name("duplicates")
.about("Prints duplicated line numbers")
.arg(
Arg::with_name("INPUT_FILE")
.required(true)
.takes_value(true)
.value_name("INPUT_FILE")
.index(1),
)
.arg(
Arg::with_name("column")
.long("column")
.help("column number to search (zero-based)")
.default_value("0")
.takes_value(true)
.value_name("COLUMN_NUMBER"),
)
.arg(
Arg::with_name("sheet")
.long("sheet")
.help("sheet to search [default: first]")
.takes_value(true)
.value_name("SHEET_NAME"),
)
.arg(
Arg::with_name("write-unique-xlsx")
.long("write-unique-xlsx")
.help("Creates a copy without duplicates")
.takes_value(true)
.conflicts_with("sheet")
.value_name("NEW_UNIQUE_XLSX_FILE"),
),
)
.subcommand(
SubCommand::with_name("intersect")
.about("Only keep intersect rows")
.arg(
Arg::with_name("BASE_FILE")
.help("Base file to remove rows from")
.required(true)
.takes_value(true)
.value_name("BASE_FILE")
.index(1),
)
.arg(
Arg::with_name("CMP_FILE")
.help("File to compare rows to")
.required(true)
.takes_value(true)
.value_name("CMP_FILE")
.index(2),
)
.arg(
Arg::with_name("output-file")
.short("o")
.long("output-file")
.takes_value(true)
.value_name("OUTPUT_TO_FILE"),
),
)
}
fn core(matches: &ArgMatches<'_>) -> Result<(), Error> {
let file = matches.value_of("INPUT_FILE").unwrap();
if matches.is_present("reverse") {
let skip_empty = matches.is_present("skip-empty");
let column_width = matches.value_of("skip-empty").unwrap_or("60.0");
let column_width = column_width.parse().unwrap_or(60.0);
let output_file = matches.value_of("output-file").unwrap();
let ron_workbook = xron::RonWorkbook::read_ron(file)?;
ron_workbook.write_xlsx(output_file, column_width, skip_empty)?;
} else {
let ron_workbook = xron::RonWorkbook::read_xlsx(file)?;
let serialized = ron::ser::to_string_pretty(&ron_workbook, Default::default())?;
println!("{}", serialized);
if let Some(file) = matches.value_of("output-file") {
std::fs::write(file, serialized.as_bytes())?;
}
}
Ok(())
}
fn duplicates(matches: &ArgMatches<'_>) -> Result<(), Error> {
let file = matches.value_of("INPUT_FILE").unwrap();
let column = matches.value_of("column").unwrap_or("0");
let column = column.parse().unwrap_or(0usize);
let mut ron_workbook = xron::RonWorkbook::read_xlsx(file)?;
let sheet = {
matches
.value_of("sheet")
.and_then(|name| ron_workbook.sheets.get(name))
};
let sheet = match sheet {
Some(x) => x,
None => ron_workbook.sheets.values().next().expect("No sheets"),
};
if let Some(unique_xlsx) = matches.value_of("NEW_UNIQUE_XLSX_FILE") {
ron_workbook.retain_unique(column);
ron_workbook.write_xlsx(unique_xlsx, 60.0, false)?;
} else {
let lines = sheet.find_duplicates(column);
println!("Duplicated lines: {:?}", lines);
}
Ok(())
}
fn unique(matches: &ArgMatches<'_>) -> Result<(), Error> {
let base_file = matches.value_of("BASE_FILE").unwrap();
let cmp_file = matches.value_of("CMP_FILE").unwrap();
let mut base_workbook = xron::RonWorkbook::read_xlsx(base_file)?;
let cmp_workbook = xron::RonWorkbook::read_xlsx(cmp_file)?;
base_workbook.retain_intersecting(&cmp_workbook);
let serialized = ron::ser::to_string_pretty(&base_workbook, Default::default())?;
println!("{}", serialized);
if let Some(file) = matches.value_of("output-file") {
std::fs::write(file, serialized.as_bytes())?;
}
Ok(())
}
fn run() -> Result<(), Error> {
let app = app();
let matches = app.get_matches();
match matches.subcommand() {
("duplicates", Some(sm)) => duplicates(sm)?,
("intersect", Some(sm)) => unique(sm)?,
_ => core(&matches)?,
}
Ok(())
}
fn main() {
if let Err(e) = run() {
eprintln!("Error: {}", e);
}
}