started v2

This commit is contained in:
FantasyPvP
2024-03-18 10:53:38 +00:00
parent 403e6ba087
commit 9b72d23779
12 changed files with 681 additions and 185 deletions
+354
View File
@@ -0,0 +1,354 @@
use num_cpus;
use std::{
fs::{self, OpenOptions},
io::{self, Error, ErrorKind, Write},
path::{Path, PathBuf},
};
use std::collections::HashMap;
use std::slice::SliceIndex;
use tracing::{event, info, span, Level, warn, error};
use tracing_subscriber::{
filter::{EnvFilter, LevelFilter},
fmt::{self, fmt},
prelude::*,
};
use toml;
use walkdir::WalkDir;
use zip::write::{FileOptions, ZipWriter};
use zip::CompressionMethod;
use zip_archive::{get_dir_list, Archiver};
fn main() {
tracing_subscriber::registry()
.with(
fmt::layer()
.pretty()
.with_target(false)
.with_thread_ids(false)
.with_thread_names(false)
.with_file(false)
.with_line_number(false),
)
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::DEBUG.into())
.from_env_lossy(),
)
.init();
let config = Config::load().expect("failed to load config");
let pack_repo = PathBuf::from(&config.repository);
match clear_resourcepacks(&config) {
Ok(_) => {},
Err(e) => return,
};
search_dir(&pack_repo, &config).unwrap();
}
fn clear_resourcepacks(conf: &Config) -> io::Result<()> {
let span = span!(Level::INFO, "clear_packs");
let _guard = span.enter();
info!("Clearing existing resourcepacks folder");
match fs::remove_dir_all(&conf.resourcepacks) {
Ok(_) => {}
Err(e) => warn!("No existing packs folder detected. Creating new folder."),
};
match fs::create_dir(&conf.resourcepacks) {
Ok(_) => {}
Err(e) => {
error!("{}", e);
return Err(e);
}
};
info!("Successfully reset resourcepacks folder");
Ok(())
}
fn search_dir(path: &PathBuf, config: &Config) -> io::Result<()> {
let span = span!(Level::INFO, "Searching for packs");
let _guard = span.enter();
// info!("Searching for packs in {}", path.display());
// check if file is a valid pack
if path.clone().join("pack.toml").exists() {
println!("Found pack {}", path.display());
Pack::load(&path).unwrap().archive(&path, config).unwrap();
return Ok(());
} else {
println!("1c| {}", path.display());
for entry in WalkDir::new(path.clone())
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_dir() && e.file_name() != path)
.filter(|e| !e.file_name().to_str().unwrap().to_string().contains("/_"))
{
println!("PATH {}", entry.path().join(entry.file_name()).to_str().unwrap());
// search_dir(&entry.path().join(entry.file_name()).to_path_buf(), config).unwrap();
}
}
Ok(())
}
#[derive(Debug, Clone, Deserialize)]
struct Pack {
release: bool,
name: String,
version: String,
description: String,
packs: HashMap<String, PackComponent>,
}
impl Pack {
fn load(path: &PathBuf) -> io::Result<Pack> {
let span = span!(Level::INFO, "Loading Pack Config file");
let _guard = span.enter();
let contents = fs::read_to_string(path.join("pack.toml"))?;
let pack = toml::from_str::<Pack>(&contents).map_err(|e| Error::new(ErrorKind::Other, e))?;
Ok(pack)
}
fn archive(&self, path: &PathBuf, config: &Config) -> Result<(), Box<dyn std::error::Error>> {
let span = span!(Level::INFO, "Archiving Pack");
let _guard = span.enter();
let resourcepacks = if config.versions.contains_key(&self.version) {
match config.versions.get(&self.version).unwrap().resourcepacks.clone() {
Some(folder) => folder,
None => config.resourcepacks.clone()
}
} else {
config.resourcepacks.clone()
};
let zip_file = fs::File::create(format!("{}/{}.zip", resourcepacks, self.name))?;
let mut zip_writer = ZipWriter::new(zip_file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated)
.unix_permissions(0o755);
for entry in WalkDir::new(path.clone())
.into_iter()
.filter_map(|e| e.ok())
{
let file_path = entry.path();
if file_path.is_file() {
let mut file = fs::File::open(file_path)?;
let relpath = file_path.strip_prefix(path.clone())?;
let mut zip_path = PathBuf::new();
zip_path.push(relpath);
zip_writer.start_file(zip_path.to_string_lossy().into_owned(), options)?;
std::io::copy(&mut file, &mut zip_writer)?;
}
}
zip_writer.finish()?;
Ok(())
}
}
#[derive(Debug, Clone, Deserialize)]
struct PackComponent {
prefix: String,
release: bool,
}
//
// fn scan_directory(path: PathBuf, config: &Config) -> io::Result<()> {
// let mut pack_mcmeta = path.clone();
// pack_mcmeta.push("pack.mcmeta");
// if pack_mcmeta.exists() {
// // if pack metadata exists, put the pack into a zip folder.
// get_archive(path, config).map_err(|_| Error::new(ErrorKind::Other, "failed to archive zip"))?;
// return Ok(());
// } else {
// // recursively scans subdirectories for other packs
// for entry in fs::read_dir(path)? {
// let entry = entry?;
//
// if entry
// .path()
// .file_name()
// .unwrap()
// .to_os_string()
// .into_string()
// .map_err(|_| Error::new(ErrorKind::Other, "failed to convert os_str to string"))?
// .starts_with("_")
// {
// println!("found _");
// continue;
// }
// if let Some(zip_str) = entry.path().extension() {
// if zip_str == "zip" {
// fs::copy(
// entry.path(),
// format!(
// "{}/{}",
// config.resourcepacks,
// entry
// .path()
// .file_name()
// .unwrap()
// .to_os_string()
// .into_string()
// .map_err(|_| Error::new(
// ErrorKind::Other,
// "failed to convert os_str to string"
// ))?
// ),
// )?;
// }
// }
//
// if let Ok(file_type) = entry.file_type() {
// if file_type.is_dir() {
// scan_directory(entry.path(), &config)?;
// }
// }
// }
// }
// Ok(())
// }
//
// fn get_archive(path: PathBuf, config: &Config) -> Result<(), Box<dyn std::error::Error>> {
// println!("CREATING ARCHIVE: {}", &path.display());
// if let Some(f) = path.file_stem() {
// let mut filename = f
// .to_os_string()
// .into_string()
// .map_err(|_| Error::new(ErrorKind::Other, "failed to convert os_str to string"))?;
// filename.push_str("_0");
// loop {
// if !Path::new(&format!("{}/{}.zip", config.resourcepacks, filename.to_string())).exists() {
// // checks if zip file already exists
// let zip_file = fs::File::create(format!("{}/{}.zip", config.resourcepacks, filename))?;
// let mut zip_writer = ZipWriter::new(zip_file);
//
// let options = FileOptions::default()
// .compression_method(CompressionMethod::Deflated)
// .unix_permissions(0o755);
//
// for entry in WalkDir::new(path.clone())
// .into_iter()
// .filter_map(|e| e.ok())
// {
// let file_path = entry.path();
// if file_path.is_file() {
// let mut file = fs::File::open(file_path)?;
// let relpath = file_path.strip_prefix(path.clone())?;
// let mut zip_path = PathBuf::new();
// zip_path.push(relpath);
//
// zip_writer.start_file(zip_path.to_string_lossy().into_owned(), options)?;
// std::io::copy(&mut file, &mut zip_writer)?;
// }
// }
// zip_writer.finish()?;
// break;
// } else {
// // 10 increments the last digit of the filename by 1
// // TODO: add support for more than one digit
// let i: u32 = filename.pop().unwrap().to_digit(10).unwrap();
// filename.push(char::from_digit(i + 1, 10).unwrap());
// }
// }
// }
// Ok(())
// }
#[derive(Debug, Deserialize, Serialize)]
pub struct VersionConfig {
pub pack_repo: Option<String>,
pub resourcepacks: Option<String>,
pub ignore_folder_prefix: Option<String>,
}
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
pub repository: String,
pub resourcepacks: String,
pub ignore_folder_prefix: String,
pub versions: HashMap<String, VersionConfig>
}
impl Config {
pub fn default() -> Config {
Config {
repository: ".".to_string(),
resourcepacks: "_resourcepacks".to_string(),
ignore_folder_prefix: "_".to_string(),
versions: HashMap::new()
}
}
pub fn load() -> Result<Config, Error> {
let span = span!(Level::INFO, "Loading Configuration File");
let _guard = span.enter();
let mut conf_path = Config::path().ok_or(Error::new(ErrorKind::Other, "error getting config path"))?;
if conf_path.exists() {
let config: Config = toml::from_str(fs::read_to_string(&conf_path)?.as_str())
.map_err(|_| Error::new(ErrorKind::Other, "failed to deserialise"))?;
info!(
"Loaded Config File: \n\trepo: {}\n\tpacks folder: {}\n\tignore with prefix: {}",
config.repository, config.resourcepacks, config.ignore_folder_prefix
);
Ok(config)
} else {
warn!(
"No config file detected. Creating config file with default values at:\n\t{}",
conf_path.display()
);
create_config_file(&conf_path)?;
Ok(Config::default())
}
}
#[cfg(debug_assertions)]
fn path() -> Option<PathBuf> {
Some(PathBuf::from(".").join("config.toml"))
}
#[cfg(not(debug_assertions))]
fn path() -> Option<PathBuf> {
dirs::config_dir()?.join("pack_sync").join("config.toml")
}
}
fn create_config_file(path: &PathBuf) -> Result<(), Error> {
println!("{}", path.display());
fs::create_dir_all(path.parent().unwrap())?;
fs::File::create(path)?;
let yaml = serde_yaml::to_string(&Config::default())
.map_err(|_| Error::new(ErrorKind::Other, "failed to serialise"))?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)?
.write_all(yaml.as_bytes())?;
Ok(())
}
-106
View File
@@ -1,106 +0,0 @@
use std::{fs, io::{self, Error, ErrorKind}, path::{Path, PathBuf}};
use zip::write::{FileOptions, ZipWriter};
use zip::CompressionMethod;
use walkdir::WalkDir;
use zip_archive::{Archiver, get_dir_list};
use num_cpus;
pub mod utils;
const PACK_REPO: &str = "./";
const RESOURCEPACKS: &str = "./_resourcepacks";
const IGNORE_FOLDERS_PREFIX: &str = "_";
fn main() {
let conf = utils::load_config().unwrap();
let pack_repo = PathBuf::from(PACK_REPO);
clear_resourcepacks().unwrap();
scan_directory(pack_repo).unwrap();
}
fn clear_resourcepacks() -> io::Result<()> {
println!("[removing existing packs]");
fs::remove_dir_all(RESOURCEPACKS)?;
fs::create_dir(RESOURCEPACKS)?;
println!(" => cleared resourcepacks folder");
Ok(())
}
fn scan_directory(path: PathBuf) -> io::Result<()> {
let mut pack_mcmeta = path.clone();
pack_mcmeta.push("pack.mcmeta");
if pack_mcmeta.exists() {
// if pack metadata exists, put the pack into a zip folder.
get_archive(path).map_err(|_| Error::new(ErrorKind::Other, "failed to archive zip"))?;
return Ok(())
} else {
// recursively scans subdirectories for other packs
for entry in fs::read_dir(path)? {
let entry = entry?;
if entry.path()
.file_name()
.unwrap()
.to_os_string()
.into_string()
.map_err(|_| Error::new(ErrorKind::Other, "failed to convert os_str to string"))?
.starts_with("_") {
println!("found _");
continue;
}
if let Some(zip_str) = entry.path().extension() {
if zip_str == "zip" {
fs::copy(entry.path(), format!("{}/{}", RESOURCEPACKS, entry.path().file_name().unwrap().to_os_string().into_string().map_err(|_| Error::new(ErrorKind::Other, "failed to convert os_str to string"))?))?;
}
}
if let Ok(file_type) = entry.file_type() {
if file_type.is_dir() {
scan_directory(entry.path())?;
}
}
}
}
Ok(())
}
fn get_archive(path: PathBuf) -> Result<(), Box<dyn std::error::Error>> {
println!("CREATING ARCHIVE: {}", &path.display());
if let Some(f) = path.file_stem() {
let mut filename = f.to_os_string().into_string().map_err(|_| Error::new(ErrorKind::Other, "failed to convert os_str to string"))?;
filename.push_str("_0");
loop {
if !Path::new(&format!("{}/{}.zip", RESOURCEPACKS, filename.to_string())).exists() { // checks if zip file already exists
let zip_file = fs::File::create(format!("{}/{}.zip", RESOURCEPACKS, filename))?;
let mut zip_writer = ZipWriter::new(zip_file);
let options = FileOptions::default()
.compression_method(CompressionMethod::Deflated)
.unix_permissions(0o755);
for entry in WalkDir::new(path.clone()).into_iter().filter_map(|e| e.ok()) {
let fpath = entry.path();
if fpath.is_file() {
let mut file = fs::File::open(fpath)?;
let relpath = fpath.strip_prefix(path.clone())?;
let mut zip_path = PathBuf::new();
zip_path.push(relpath);
zip_writer.start_file(zip_path.to_string_lossy().into_owned(), options)?;
std::io::copy(&mut file, &mut zip_writer)?;
}
}
zip_writer.finish()?;
break;
} else {
// 10 increments the last digit of the filename by 1
// TODO: add support for more than one digit
let i: u32 = filename.pop().unwrap().to_digit(10).unwrap();
filename.push(char::from_digit(i+1, 10).unwrap());
}
}
}
Ok(())
}
+3
View File
@@ -0,0 +1,3 @@
fn main() {
println!("hello world");
}
-74
View File
@@ -1,74 +0,0 @@
use std::{fs::{self, OpenOptions}, io::{self, Error, ErrorKind, Write}, path::{Path, PathBuf}};
use crate::IGNORE_FOLDERS_PREFIX;
use serde::{Serialize, Deserialize};
#[derive(Debug, Deserialize, Serialize)]
pub struct Config {
pack_repo: String,
resourcepacks: String,
ignore_folder_prefix: String,
}
fn config_path() -> Option<PathBuf> {
dirs::config_dir()
}
fn create_config_dir(path: &PathBuf) -> Result<(), Error> {
fs::create_dir_all(path)?;
create_config_file(&path.join("config.yml"))?;
Ok(())
}
fn write_config(path: &PathBuf, config: Config) -> Result<(), Error> {
fs::File::create(path)?;
Ok(())
}
fn create_config_file(path: &PathBuf) -> Result<(), Error> {
fs::File::create(path)?;
let conf_file = Config {
pack_repo: ".".to_string(),
resourcepacks: "./_resourcepacks".to_string(),
ignore_folder_prefix: "_".to_string(),
};
let yaml = serde_yaml::to_string(&conf_file).map_err(|_| Error::new(ErrorKind::Other, "failed to serialise"))?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)?;
file.write_all(yaml.as_bytes())?;
Ok(())
}
pub fn load_config() -> Result<Config, Error> {
let mut conf_path = config_path().ok_or(Error::new(ErrorKind::Other, "error getting config path"))?;
if !conf_path.exists() {
return Err(Error::new(ErrorKind::Other, "No config directory found"));
};
conf_path.push("fqntqpacks");
if !conf_path.exists() {
create_config_dir(&conf_path)?;
};
conf_path.push("config.yml");
if !conf_path.exists() {
create_config_file(&conf_path)?;
};
let config: Config = serde_yaml::from_reader(fs::File::open(&conf_path)?)
.map_err(|_| Error::new(ErrorKind::Other, "failed to deserialise"))?;
println!(
"-----------------------------------------------------------------
WARNING: no previous config file detected, created config file at
{}
-----------------------------------------------------------------", conf_path.display());
Ok(config)
}