mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Reapply "Support plugin and archive symlinks"
This reverts commit da0e35bb2b.
The minimum version of libloadorder has been increased because 18.5.0
included some changes to support symlinked plugins, without which
symlink support is incomplete.
This commit is contained in:
+1
-1
@@ -10,7 +10,7 @@ license.workspace = true
|
||||
[dependencies]
|
||||
crc32fast = "1"
|
||||
esplugin = "6.1"
|
||||
libloadorder = "18.4"
|
||||
libloadorder = "18.5"
|
||||
log = { version = "0.4.6", features = ["std"] }
|
||||
loot-condition-interpreter = "5"
|
||||
petgraph = ">= 0.6, < 0.9"
|
||||
|
||||
+70
-3
@@ -625,14 +625,15 @@ fn find_archives(
|
||||
data_path: &Path,
|
||||
) -> std::io::Result<Vec<PathBuf>> {
|
||||
let extension = archive_file_extension(game_type);
|
||||
let allow_symlinks = allow_archive_symlinks(game_type);
|
||||
|
||||
let mut archive_paths = Vec::new();
|
||||
for path in additional_data_paths {
|
||||
let paths = find_archives_in_path(path, extension)?;
|
||||
let paths = find_archives_in_path(path, extension, allow_symlinks)?;
|
||||
archive_paths.extend(paths);
|
||||
}
|
||||
|
||||
let paths = find_archives_in_path(data_path, extension)?;
|
||||
let paths = find_archives_in_path(data_path, extension, allow_symlinks)?;
|
||||
archive_paths.extend(paths);
|
||||
|
||||
Ok(archive_paths)
|
||||
@@ -645,18 +646,29 @@ fn archive_file_extension(game_type: GameType) -> &'static str {
|
||||
}
|
||||
}
|
||||
|
||||
fn allow_archive_symlinks(game_type: GameType) -> bool {
|
||||
// Assuming support for archive symlinks matches support for plugin symlinks.
|
||||
!cfg!(windows) || matches!(game_type, GameType::OblivionRemastered | GameType::OpenMW)
|
||||
}
|
||||
|
||||
fn find_archives_in_path(
|
||||
parent_path: &Path,
|
||||
archive_file_extension: &str,
|
||||
allow_symlinks: bool,
|
||||
) -> std::io::Result<Vec<PathBuf>> {
|
||||
if !parent_path.exists() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
#[expect(
|
||||
clippy::filetype_is_file,
|
||||
reason = "Only files are supported except in specific cases"
|
||||
)]
|
||||
let paths = std::fs::read_dir(parent_path)?
|
||||
.filter_map(Result::ok)
|
||||
.filter(|e| {
|
||||
e.file_type().map(|f| f.is_file()).unwrap_or(false)
|
||||
e.file_type()
|
||||
.is_ok_and(|f| f.is_file() || (allow_symlinks && f.is_symlink()))
|
||||
&& iends_with_ascii(&e.file_name().to_string_lossy(), archive_file_extension)
|
||||
})
|
||||
.map(|e| e.path())
|
||||
@@ -2051,6 +2063,61 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
mod find_archives {
|
||||
use tempfile::tempdir;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn symlink_file(original: &Path, link: &Path) {
|
||||
std::os::windows::fs::symlink_file(original, link).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub(crate) fn symlink_file(original: &Path, link: &Path) {
|
||||
std::os::unix::fs::symlink(original, link).unwrap();
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[parameterized_test(ALL_GAME_TYPES)]
|
||||
fn should_find_symlinked_archives_on_linux(game_type: GameType) {
|
||||
test_find_symlinked_archives(game_type, true);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[parameterized_test(ALL_GAME_TYPES)]
|
||||
fn should_find_symlinked_archives_for_only_openmw_and_oblivion_remastered_on_windows(
|
||||
game_type: GameType,
|
||||
) {
|
||||
test_find_symlinked_archives(
|
||||
game_type,
|
||||
matches!(game_type, GameType::OpenMW | GameType::OblivionRemastered),
|
||||
);
|
||||
}
|
||||
|
||||
fn test_find_symlinked_archives(game_type: GameType, should_include_symlinks: bool) {
|
||||
let tmp_dir = tempdir().unwrap();
|
||||
|
||||
let extension = archive_file_extension(game_type);
|
||||
let archive_path = tmp_dir.path().join(format!("archive{extension}"));
|
||||
let symlink_path = tmp_dir.path().join(format!("archive.symlink{extension}"));
|
||||
|
||||
std::fs::File::create(&archive_path).unwrap();
|
||||
|
||||
symlink_file(&archive_path, &symlink_path);
|
||||
|
||||
let archives = find_archives(game_type, &[], tmp_dir.path()).unwrap();
|
||||
|
||||
assert!(archives.contains(&archive_path));
|
||||
|
||||
if should_include_symlinks {
|
||||
assert!(archives.contains(&symlink_path));
|
||||
} else {
|
||||
assert!(!archives.contains(&symlink_path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_plugin_sorting_data_should_filter_out_files_with_false_constraints() {
|
||||
let game_type = GameType::Oblivion;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// Allow some lints that are denied at the workspace level.
|
||||
#![allow(
|
||||
clippy::filetype_is_file,
|
||||
clippy::must_use_candidate,
|
||||
clippy::missing_errors_doc,
|
||||
clippy::wildcard_enum_match_arm
|
||||
|
||||
Reference in New Issue
Block a user