Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 49 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,13 @@ cargo install ferium

### Program Configuration

Ferium stores profile and modpack information in its config file. By default, this is located at `~/.config/ferium/config.json`.
You can change this in 2 ways, setting the `FERIUM_CONFIG_FILE` environment variable, or setting the `--config-file` global flag.
The flag always takes precedence.
Ferium stores profile and modpack information in its config file. By default, this is located at
- `$XDG_CONFIG_HOME/ferium/config.json` or `~/.config/ferium/config.json` on Linux.
- `%APPDATA%/ferium/config/config.json` on Windows.
- `~/.config/ferium/config.json` on macOS.

You can change this in 2 ways; by setting the `FERIUM_CONFIG_FILE` environment variable,
or the `--config-file` global flag. The flag takes precedence.

> [!CAUTION]
> Be mindful of syntax when manually editing the config file
Expand Down
2 changes: 1 addition & 1 deletion libium/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ serde = { version = "1.0", features = ["derive"] }
url = { version = "2.5", features = ["serde"] }
zip-extensions = "0.8"
futures-util = "0.3"
directories = "6.0"
thiserror = "2.0"
regex = "1.11"
sha1 = "0.10"
home = "0.5"
zip = "2.5"

[patch.crates-io]
Expand Down
11 changes: 1 addition & 10 deletions libium/src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
pub mod filters;
pub mod structs;

use std::{
fs::{create_dir_all, File},
io::{BufReader, Result},
path::{Path, PathBuf},
sync::LazyLock,
path::Path,
};

pub static DEFAULT_CONFIG_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
crate::HOME
.join(".config")
.join("ferium")
.join("config.json")
});

/// Open the config file at `path` and deserialise it into a config struct
pub fn read_config(path: impl AsRef<Path>) -> Result<structs::Config> {
if !path.as_ref().exists() {
Expand Down
32 changes: 18 additions & 14 deletions libium/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod version_ext;
pub use add::add;
pub use scan::scan;

use directories::{BaseDirs, ProjectDirs};
use std::{path::PathBuf, sync::LazyLock};

pub static GITHUB_API: LazyLock<octocrab::Octocrab> = LazyLock::new(|| {
Expand Down Expand Up @@ -36,24 +37,27 @@ pub static MODRINTH_API: LazyLock<ferinth::Ferinth> = LazyLock::new(|| {
.expect("Could not build Modrinth client") // This should never fail since no `authorisation` token was provided
});

pub static HOME: LazyLock<PathBuf> =
LazyLock::new(|| home::home_dir().expect("Could not get user's home directory"));
pub static BASE_DIRS: LazyLock<BaseDirs> =
LazyLock::new(|| BaseDirs::new().expect("Could not get OS specific directories"));

pub static PROJECT_DIRS: LazyLock<ProjectDirs> = LazyLock::new(|| {
ProjectDirs::from("", "", "ferium").expect("Could not get OS specific directories")
});

/// Gets the default Minecraft instance directory based on the current compilation `target_os`
///
/// If the `target_os` doesn't match `"macos"`, `"linux"`, or `"windows"`, this function will not compile.
pub fn get_minecraft_dir() -> PathBuf {
#[cfg(target_os = "windows")]
return HOME.join("AppData").join("Roaming").join(".minecraft");

#[cfg(target_os = "macos")]
return HOME
.join("Library")
.join("Application Support")
.join("minecraft");

#[cfg(target_os = "linux")]
return HOME.join(".minecraft");
{
BASE_DIRS.data_dir().join("minecraft")
}
#[cfg(target_os = "windows")]
{
BASE_DIRS.data_dir().join(".minecraft")
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
{
BASE_DIRS.home_dir().join(".minecraft")
}
}

/// Read `source` and return the data as a string
Expand Down
12 changes: 9 additions & 3 deletions libium/src/upgrade/modpack_downloadable.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
use super::{from_mr_version, try_from_cf_file, DistributionDeniedError};
use crate::{config::structs::ModpackIdentifier, CURSEFORGE_API, HOME, MODRINTH_API};
use crate::{config::structs::ModpackIdentifier, CURSEFORGE_API, MODRINTH_API, PROJECT_DIRS};
use reqwest::Client;
use std::{fs::create_dir_all, path::PathBuf};

#[derive(Debug, thiserror::Error)]
#[error(transparent)]
pub enum Error {
/// The user can manually download the modpack zip file and place it in `~/.config/ferium/.cache/` to mitigate this.
/// The user can manually download the modpack zip file and place it in
/// `<ferium cache path>/downloaded` to mitigate this.
/// However, they will have to manually update the modpack file.
///
/// Ferium cache path:
/// - Windows: `%LOCALAPPDATA%/ferium/cache`
/// - Linux: `${XDG_CACHE_HOME}/ferium` or `~/.cache/ferium`
/// - MacOS: `~/Library/Caches/ferium`
DistributionDenied(#[from] DistributionDeniedError),
ModrinthError(#[from] ferinth::Error),
CurseForgeError(#[from] furse::Error),
Expand All @@ -32,7 +38,7 @@ impl ModpackIdentifier {
}
};

let cache_dir = HOME.join(".config").join("ferium").join(".cache");
let cache_dir = PROJECT_DIRS.cache_dir().join("downloaded");
let modpack_path = cache_dir.join(&download_data.output);
if !modpack_path.exists() {
create_dir_all(&cache_dir)?;
Expand Down
4 changes: 2 additions & 2 deletions src/file_picker.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use libium::HOME;
use libium::BASE_DIRS;
use std::{
io::Result,
path::{Path, PathBuf},
Expand Down Expand Up @@ -38,7 +38,7 @@ pub fn pick_folder(
.components()
.map(|c| {
if c.as_os_str() == "~" {
HOME.as_os_str()
BASE_DIRS.home_dir().as_os_str()
} else {
c.as_os_str()
}
Expand Down
24 changes: 22 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ use libium::{
self,
filters::ProfileParameters as _,
structs::{Config, ModIdentifier, Modpack, Profile},
DEFAULT_CONFIG_PATH,
},
iter_ext::IterExt as _,
};
Expand Down Expand Up @@ -157,10 +156,31 @@ async fn actual_main(mut cli_app: Ferium) -> Result<()> {

let _ = SEMAPHORE.set(Semaphore::new(cli_app.parallel_tasks));

let old_default_config_path = libium::BASE_DIRS
.home_dir()
.join(".config")
.join("ferium")
.join("config.json");
let config_path = &cli_app
.config_file
.or_else(|| var_os("FERIUM_CONFIG_FILE").map(Into::into))
.unwrap_or(DEFAULT_CONFIG_PATH.clone());
.unwrap_or({
#[cfg(target_os = "macos")]
{
old_default_config_path
}
#[cfg(not(target_os = "macos"))]
{
libium::PROJECT_DIRS.config_dir().join("config.json")
}
});

// Handle old configs which may be in a different path
if !config_path.exists() && old_default_config_path.exists() {
std::fs::rename(old_default_config_path, config_path)
.context("Failed to relocate config file to the new path, try doing so manually.")?;
}

let mut config = config::read_config(config_path)?;

let mut did_add_fail = false;
Expand Down
4 changes: 2 additions & 2 deletions src/subcommands/modpack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::file_picker::pick_folder;
use anyhow::{ensure, Context as _, Result};
use fs_extra::dir::{copy, CopyOptions};
use inquire::Confirm;
use libium::HOME;
use libium::BASE_DIRS;
use std::{fs::read_dir, path::Path};

pub fn check_output_directory(output_dir: &Path) -> Result<()> {
Expand Down Expand Up @@ -44,7 +44,7 @@ pub fn check_output_directory(output_dir: &Path) -> Result<()> {
.unwrap_or_default()
{
let backup_dir = pick_folder(
&*HOME,
BASE_DIRS.home_dir(),
"Where should the backup be made?",
"Output Directory",
)?
Expand Down
16 changes: 7 additions & 9 deletions src/subcommands/modpack/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use libium::{
read_file_from_zip, zip_extract,
},
upgrade::{from_modpack_file, try_from_cf_file, DistributionDeniedError, DownloadData},
CURSEFORGE_API, HOME,
CURSEFORGE_API,
};
use std::{
fs::File,
Expand Down Expand Up @@ -113,10 +113,9 @@ pub async fn upgrade(modpack: &'_ Modpack) -> Result<()> {
);

if modpack.install_overrides {
let tmp_dir = HOME
.join(".config")
.join("ferium")
.join(".tmp")
let tmp_dir = libium::PROJECT_DIRS
.cache_dir()
.join("extracted")
.join(manifest.name);
zip_extract(&modpack_filepath, &tmp_dir)?;
to_install = read_overrides(&tmp_dir.join(manifest.overrides))?;
Expand All @@ -142,10 +141,9 @@ pub async fn upgrade(modpack: &'_ Modpack) -> Result<()> {
);

if modpack.install_overrides {
let tmp_dir = HOME
.join(".config")
.join("ferium")
.join(".tmp")
let tmp_dir = libium::PROJECT_DIRS
.cache_dir()
.join("extracted")
.join(metadata.name);
zip_extract(&modpack_filepath, &tmp_dir)?;
to_install = read_overrides(&tmp_dir.join("overrides"))?;
Expand Down
4 changes: 2 additions & 2 deletions src/subcommands/profile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use colored::Colorize as _;
use ferinth::Ferinth;
use fs_extra::dir::{copy, CopyOptions};
use inquire::{Confirm, MultiSelect, Select};
use libium::{config::structs::ModLoader, iter_ext::IterExt as _, HOME};
use libium::{config::structs::ModLoader, iter_ext::IterExt as _, BASE_DIRS};
use std::{
fs::{create_dir_all, read_dir},
path::PathBuf,
Expand Down Expand Up @@ -109,7 +109,7 @@ pub async fn check_output_directory(output_dir: &PathBuf) -> Result<()> {
.unwrap_or_default()
{
let backup_dir = pick_folder(
&*HOME,
BASE_DIRS.home_dir(),
"Where should the backup be made?",
"Output Directory",
)?
Expand Down
2 changes: 1 addition & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn get_args(subcommand: SubCommands, config_file: Option<&str>) -> Ferium {
}
Ferium {
subcommand,
config_file: Some(running.into()),
config_file: Some(running),
..DEFAULT
}
}
Expand Down