Skip to content

Commit

Permalink
configurable config,cache,data dirs
Browse files Browse the repository at this point in the history
Remove config/data dir config as its not necessary

fmt

idk
  • Loading branch information
Buckminsterfullerene02 committed Feb 25, 2024
1 parent d91b633 commit d137ad0
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 42 deletions.
112 changes: 77 additions & 35 deletions src/gui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ use std::collections::{BTreeMap, BTreeSet};
use std::time::{Duration, SystemTime};
use std::{
collections::{HashMap, HashSet},
fs,
ops::DerefMut,
path::PathBuf,
};

use anyhow::{anyhow, Context, Result};
use anyhow::{anyhow, Result};
use eframe::egui::{Button, CollapsingHeader, RichText, Visuals};
use eframe::epaint::{Pos2, Vec2};
use eframe::{
Expand All @@ -32,8 +33,9 @@ use tracing::{debug, trace};
use crate::mod_lints::{LintId, LintReport, SplitAssetPair};
use crate::Dirs;
use crate::{
clear_directory,
integrate::uninstall,
is_drg_pak,
is_drg_pak, is_valid_directory,
providers::{
ApprovalStatus, FetchProgress, ModInfo, ModSpecification, ModStore, ModioTags,
ProviderFactory, RequiredStatus,
Expand Down Expand Up @@ -928,26 +930,26 @@ impl App {
});
ui.end_row();

let config_dir = &self.state.dirs.config_dir;
ui.label("Config directory:");
if ui.link(config_dir.display().to_string()).clicked() {
opener::open(config_dir).ok();
}
ui.end_row();
let edit_directory_field = |ui: &mut egui::Ui, label: &str, path: &mut String, err: &mut Option<String>| {
ui.horizontal(|ui| {
ui.label(label);
ui.text_edit_singleline(path);

let cache_dir = &self.state.dirs.cache_dir;
ui.label("Cache directory:");
if ui.link(cache_dir.display().to_string()).clicked() {
opener::open(cache_dir).ok();
}
ui.end_row();
if ui.button("Browse").clicked() {
if let Some(selected_path) = rfd::FileDialog::new().pick_folder() {
*path = selected_path.to_string_lossy().to_string();
*err = None;
}
}

let data_dir = &self.state.dirs.data_dir;
ui.label("Data directory:");
if ui.link(data_dir.display().to_string()).clicked() {
opener::open(data_dir).ok();
}
ui.end_row();
if let Some(err_msg) = err {
ui.label(&*err_msg);
}
ui.end_row();
});
};

edit_directory_field(ui, "Cache Directory:", &mut window.cache_dir, &mut window.cache_dir_err);

ui.label("GUI theme:");
ui.horizontal(|ui| {
Expand Down Expand Up @@ -980,24 +982,56 @@ impl App {
}
});

ui.with_layout(egui::Layout::right_to_left(Align::TOP), |ui| {
if ui.add_enabled(window.drg_pak_path_err.is_none(), egui::Button::new("save")).clicked() {
ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| {
let can_save = window.drg_pak_path_err.is_none()
&& window.cache_dir_err.is_none();

if ui.add_enabled(can_save, egui::Button::new("save")).clicked() {
try_save = true;
}

if let Some(error) = &window.drg_pak_path_err {
ui.colored_label(ui.visuals().error_fg_color, error);
}
if let Some(error) = &window.cache_dir_err {
ui.colored_label(ui.visuals().error_fg_color, error);
}
});

});
if try_save {
if let Err(e) = is_drg_pak(&window.drg_pak_path).context("Is not valid DRG pak") {
let mut has_error = false;

if let Err(e) = is_drg_pak(&window.drg_pak_path) {
window.drg_pak_path_err = Some(e.to_string());
} else {
self.state.config.drg_pak_path = Some(PathBuf::from(
self.settings_window.take().unwrap().drg_pak_path,
));
self.state.config.save().unwrap();
has_error = true;
}
if let Err(e) = is_valid_directory(&window.cache_dir) {
window.cache_dir_err = Some(e);
has_error = true;
}

if !has_error {
if let Some(old_cache_dir) = &self.state.config.cache_dir {
if old_cache_dir.to_string_lossy() != window.cache_dir {
if let Err(e) = fs::create_dir_all(&window.cache_dir) {
window.cache_dir_err =
Some(format!("Failed to create new cache directory: {}", e));
has_error = true;
} else if let Err(e) = clear_directory(old_cache_dir) {
window.cache_dir_err =
Some(format!("Failed to clear cache directory: {}", e));
has_error = true;
}
}
}

if !has_error {
self.state.config.drg_pak_path = Some(PathBuf::from(&window.drg_pak_path));
self.state.config.cache_dir = Some(PathBuf::from(&window.cache_dir));

self.state.config.save().unwrap();
}
}
} else if !open {
self.settings_window = None;
Expand Down Expand Up @@ -1483,19 +1517,27 @@ impl WindowProviderParameters {
struct WindowSettings {
drg_pak_path: String,
drg_pak_path_err: Option<String>,
cache_dir: String,
cache_dir_err: Option<String>,
}

impl WindowSettings {
fn new(state: &State) -> Self {
let path = state
.config
.drg_pak_path
.as_ref()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default();
Self {
drg_pak_path: path,
drg_pak_path: state
.config
.drg_pak_path
.as_ref()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default(),
drg_pak_path_err: None,
cache_dir: state
.config
.cache_dir
.as_ref()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_default(),
cache_dir_err: None,
}
}
}
Expand Down
60 changes: 59 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pub mod mod_lints;
pub mod providers;
pub mod state;

use std::io::{Cursor, Read};
use std::fs::{self, copy, create_dir_all};
use std::io::{self, Cursor, Read};
use std::str::FromStr;
use std::{
collections::HashSet,
Expand Down Expand Up @@ -87,6 +88,63 @@ pub fn write_file<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, data: C) -> Result<()
.with_context(|| format!("Could not write to file {}", path.as_ref().display()))
}

pub fn is_valid_directory(path: &str) -> Result<(), String> {
let path = Path::new(path);

if !path.exists() {
return Err("Path does not exist.".to_string());
}
if !path.is_dir() {
return Err("Path is not a directory.".to_string());
}

match fs::metadata(path) {
Ok(metadata) => {
if !metadata.permissions().readonly() {
Ok(())
} else {
Err("Directory is not writable.".to_string())
}
}
Err(_) => Err("Unable to access directory metadata.".to_string()),
}
}

pub fn copy_directory_contents(src: &Path, dest: &Path) -> io::Result<()> {
if src.is_dir() {
create_dir_all(dest)?;

for entry in fs::read_dir(src)? {
let entry = entry?;
let path = entry.path();
let dest_path = dest.join(entry.file_name());

if path.is_dir() {
copy_directory_contents(&path, &dest_path)?;
} else {
copy(&path, &dest_path)?;
}
}
}
Ok(())
}

pub fn clear_directory(path: &Path) -> io::Result<()> {
if path.is_dir() {
for entry in fs::read_dir(path)? {
let entry = entry?;
let path = entry.path();

if path.is_dir() {
fs::remove_dir_all(&path)?;
} else {
fs::remove_file(&path)?;
}
}
}
Ok(())
}

pub fn is_drg_pak<P: AsRef<Path>>(path: P) -> Result<()> {
let mut reader = std::io::BufReader::new(open_file(path)?);
let pak = repak::PakBuilder::new().reader(&mut reader)?;
Expand Down
45 changes: 39 additions & 6 deletions src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,18 +326,30 @@ impl ModData!["0.1.0"] {

#[obake::versioned]
#[obake(version("0.0.0"))]
#[obake(version("0.1.0"))]
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
#[obake(cfg("0.0.0"))]
#[obake(cfg("0.1.0"))]
pub provider_parameters: HashMap<String, HashMap<String, String>>,
#[obake(cfg("0.0.0"))]
#[obake(cfg("0.1.0"))]
pub drg_pak_path: Option<PathBuf>,
#[obake(cfg("0.0.0"))]
#[obake(cfg("0.1.0"))]
pub gui_theme: Option<GuiTheme>,

#[obake(cfg("0.1.0"))]
pub cache_dir: Option<PathBuf>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "version")]
pub enum VersionAnnotatedConfig {
#[serde(rename = "0.0.0")]
V0_0_0(Config!["0.0.0"]),
#[serde(rename = "0.1.0")]
V0_1_0(Config!["0.1.0"]),
#[serde(other)]
Unsupported,
}
Expand All @@ -357,38 +369,58 @@ impl Default for MaybeVersionedConfig {

impl Default for VersionAnnotatedConfig {
fn default() -> Self {
VersionAnnotatedConfig::V0_0_0(Default::default())
VersionAnnotatedConfig::V0_1_0(Default::default())
}
}

impl Deref for VersionAnnotatedConfig {
type Target = Config!["0.0.0"];
type Target = Config_v0_1_0;

fn deref(&self) -> &Self::Target {
match self {
VersionAnnotatedConfig::V0_0_0(cfg) => cfg,
VersionAnnotatedConfig::Unsupported => unreachable!(),
VersionAnnotatedConfig::V0_0_0(_) => unreachable!("Attempted to deref a legacy config"),
VersionAnnotatedConfig::V0_1_0(ref cfg) => cfg,
VersionAnnotatedConfig::Unsupported => {
unreachable!("Attempted to deref an unsupported config")
}
}
}
}

impl DerefMut for VersionAnnotatedConfig {
fn deref_mut(&mut self) -> &mut Self::Target {
match self {
VersionAnnotatedConfig::V0_0_0(cfg) => cfg,
VersionAnnotatedConfig::V0_0_0(_) => unreachable!(),
VersionAnnotatedConfig::V0_1_0(cfg) => cfg,
VersionAnnotatedConfig::Unsupported => unreachable!(),
}
}
}

impl Default for Config!["0.0.0"] {
impl Default for Config!["0.1.0"] {
fn default() -> Self {
let default_dirs = Dirs::default_xdg().expect("Failed to get default directories");

Self {
provider_parameters: Default::default(),
drg_pak_path: DRGInstallation::find()
.as_ref()
.map(DRGInstallation::main_pak),
gui_theme: None,
cache_dir: Some(default_dirs.cache_dir),
}
}
}

impl From<Config!["0.0.0"]> for Config!["0.1.0"] {
fn from(legacy: Config!("0.0.0")) -> Self {
let default_dirs = Dirs::default_xdg().expect("Failed to get default directories");

Self {
provider_parameters: legacy.provider_parameters,
drg_pak_path: legacy.drg_pak_path,
gui_theme: legacy.gui_theme,
cache_dir: Some(default_dirs.cache_dir),
}
}
}
Expand Down Expand Up @@ -432,6 +464,7 @@ fn read_config_or_default(config_path: &PathBuf) -> Result<VersionAnnotatedConfi
.context("failed to deserialize user config into maybe versioned config")?;
match config {
MaybeVersionedConfig::Versioned(v) => match v {
VersionAnnotatedConfig::V0_1_0(v) => VersionAnnotatedConfig::V0_1_0(v),
VersionAnnotatedConfig::V0_0_0(v) => VersionAnnotatedConfig::V0_0_0(v),
VersionAnnotatedConfig::Unsupported => bail!("unsupported config version"),
},
Expand Down

0 comments on commit d137ad0

Please sign in to comment.