use std::error::Error;
use std::path::Path;
use crate::dictionary_builder::DictionaryBuilder;
pub struct FetchParams {
pub file_name: &'static str,
pub input_dir: &'static str,
pub output_dir: &'static str,
pub dummy_input: &'static str,
pub download_url: &'static str,
}
#[cfg(not(target_os = "windows"))]
fn empty_directory(dir: &Path) -> Result<(), Box<dyn Error>> {
if dir.is_dir() {
for entry in std::fs::read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
std::fs::remove_dir_all(&path)?;
} else {
std::fs::remove_file(&path)?;
}
}
}
Ok(())
}
#[cfg(target_os = "windows")]
fn copy_dir_all(src: &Path, dst: &Path) -> Result<(), Box<dyn Error>> {
if !dst.exists() {
std::fs::create_dir(dst)?;
}
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let entry_path = entry.path();
let dst_path = dst.join(entry.file_name());
if entry_path.is_dir() {
copy_dir_all(&entry_path, &dst_path)?;
} else {
std::fs::copy(&entry_path, &dst_path)?;
}
}
Ok(())
}
pub fn fetch(params: FetchParams, builder: impl DictionaryBuilder) -> Result<(), Box<dyn Error>> {
use std::env;
use std::fs::{create_dir, rename, File};
use std::io::{self, Cursor, Read, Write};
use std::path::{Path, PathBuf};
use encoding::all::UTF_8;
use encoding::{EncoderTrap, Encoding};
use flate2::read::GzDecoder;
use tar::Archive;
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.toml");
let (build_dir, is_cache) = if let Some(lindera_cache_dir) = env::var_os("LINDERA_CACHE") {
(
PathBuf::from(lindera_cache_dir).join(env::var_os("CARGO_PKG_VERSION").unwrap()),
true,
)
} else {
(
PathBuf::from(env::var_os("OUT_DIR").unwrap()),
false,
)
};
println!("cargo::rustc-env=LINDERA_WORKDIR={}", build_dir.display());
std::fs::create_dir_all(&build_dir)?;
let input_dir = build_dir.join(params.input_dir);
let output_dir = build_dir.join(params.output_dir);
if is_cache && output_dir.is_dir() {
return Ok(());
}
if std::env::var("DOCS_RS").is_ok() {
create_dir(&input_dir)?;
let mut dummy_char_def = File::create(input_dir.join("char.def"))?;
dummy_char_def.write_all(b"DEFAULT 0 1 0\n")?;
let mut dummy_dict_csv = File::create(input_dir.join("dummy_dict.csv"))?;
dummy_dict_csv.write_all(
&UTF_8
.encode(params.dummy_input, EncoderTrap::Ignore)
.unwrap(),
)?;
File::create(input_dir.join("unk.def"))?;
let mut dummy_matrix_def = File::create(input_dir.join("matrix.def"))?;
dummy_matrix_def.write_all(b"0 1 0\n")?;
} else {
let source_path_for_build = &build_dir.join(params.file_name);
let tmp_path = Path::new(&build_dir).join(params.file_name.to_owned() + ".download");
let resp = ureq::get(params.download_url).call()?;
let mut dest = File::create(&tmp_path)?;
io::copy(&mut resp.into_reader(), &mut dest)?;
dest.flush()?;
rename(tmp_path.clone(), source_path_for_build).expect("Failed to rename temporary file");
let tmp_extract_path =
Path::new(&build_dir).join(format!("tmp-archive-{}", params.input_dir));
let tmp_extracted_path = tmp_extract_path.join(params.input_dir);
let _ = std::fs::remove_dir_all(&tmp_extract_path);
std::fs::create_dir_all(&tmp_extract_path)?;
let mut tar_gz = File::open(source_path_for_build)?;
let mut buffer = Vec::new();
tar_gz.read_to_end(&mut buffer)?;
let cursor = Cursor::new(buffer);
let decoder = GzDecoder::new(cursor);
let mut archive = Archive::new(decoder);
archive.unpack(&tmp_extract_path)?;
#[cfg(target_os = "windows")]
{
if input_dir.exists() {
std::fs::remove_dir_all(&input_dir).expect("Failed to remove input directory");
std::fs::create_dir_all(&input_dir).expect("Failed to create input directory");
}
copy_dir_all(&tmp_extracted_path, &input_dir)
.expect("Failed to copy files from temporary directory to input directory");
std::fs::remove_dir_all(&tmp_extracted_path)
.expect("Failed to remove temporary directory");
}
#[cfg(not(target_os = "windows"))]
{
empty_directory(&input_dir).expect("Failed to empty input directory");
rename(tmp_extracted_path, &input_dir).expect("Failed to rename archive directory");
}
let _ = std::fs::remove_dir_all(&tmp_extract_path);
drop(dest);
let _ = std::fs::remove_file(source_path_for_build);
}
let tmp_path = build_dir.join(format!("tmp-output-{}", params.output_dir));
let _ = std::fs::remove_dir_all(&tmp_path);
builder.build_dictionary(&input_dir, &tmp_path)?;
#[cfg(target_os = "windows")]
{
if output_dir.exists() {
std::fs::remove_dir_all(&output_dir).expect("Failed to remove output directory");
std::fs::create_dir_all(&output_dir).expect("Failed to create output directory");
}
copy_dir_all(&tmp_path, &output_dir).expect("Failed to copy output directory");
std::fs::remove_dir_all(&tmp_path).expect("Failed to copy output directory");
}
#[cfg(not(target_os = "windows"))]
{
empty_directory(&output_dir).expect("Failed to empty output directory");
rename(tmp_path, &output_dir).expect("Failed to rename output directory");
}
let _ = std::fs::remove_dir_all(&input_dir);
Ok(())
}