mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'juliancoffee/asset_tweak' into 'master'
tweak_expect function to tweak values from .ron See merge request veloren/veloren!2391
This commit is contained in:
commit
dc4bd0de75
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,6 +26,7 @@ target
|
|||||||
# Veloren
|
# Veloren
|
||||||
*.rar
|
*.rar
|
||||||
*.log
|
*.log
|
||||||
|
assets/tweak/
|
||||||
settings.ron
|
settings.ron
|
||||||
server_settings.ron
|
server_settings.ron
|
||||||
run.sh
|
run.sh
|
||||||
|
@ -6,7 +6,7 @@ code-quality:
|
|||||||
script:
|
script:
|
||||||
- ln -s /dockercache/target target
|
- ln -s /dockercache/target target
|
||||||
- rm -r target/debug/incremental/* || echo "all good" # TMP FIX FOR 2021-03-22-nightly
|
- rm -r target/debug/incremental/* || echo "all good" # TMP FIX FOR 2021-03-22-nightly
|
||||||
- cargo clippy --all-targets --locked --features="bin_csv,bin_bot" -- -D warnings
|
- cargo clippy --all-targets --locked --features="bin_csv,bin_bot,asset_tweak" -- -D warnings
|
||||||
- cargo fmt --all -- --check
|
- cargo fmt --all -- --check
|
||||||
|
|
||||||
security:
|
security:
|
||||||
|
24
Cargo.lock
generated
24
Cargo.lock
generated
@ -4764,6 +4764,28 @@ dependencies = [
|
|||||||
"syn 1.0.72",
|
"syn 1.0.72",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"parking_lot 0.11.1",
|
||||||
|
"serial_test_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serial_test_derive"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.27",
|
||||||
|
"quote 1.0.9",
|
||||||
|
"syn 1.0.72",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -5805,6 +5827,8 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"ron",
|
"ron",
|
||||||
|
"serde",
|
||||||
|
"serial_test",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -12,3 +12,10 @@ ron = { version = "0.6", default-features = false }
|
|||||||
dot_vox = "4.0"
|
dot_vox = "4.0"
|
||||||
image = { version = "0.23.12", default-features = false, features = ["png"] }
|
image = { version = "0.23.12", default-features = false, features = ["png"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|
||||||
|
# asset tweak
|
||||||
|
serde = {version = "1.0", features = ["derive"], optional = true}
|
||||||
|
serial_test = {version = "0.5", optional = true}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
asset_tweak = ["serial_test", "serde"]
|
||||||
|
@ -128,6 +128,23 @@ impl Asset for DotVoxAsset {
|
|||||||
const EXTENSION: &'static str = "vox";
|
const EXTENSION: &'static str = "vox";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return path to repository root by searching 10 directories back
|
||||||
|
pub fn find_root() -> Option<PathBuf> {
|
||||||
|
std::env::current_dir().map_or(None, |path| {
|
||||||
|
// If we are in the root, push path
|
||||||
|
if path.join(".git").exists() {
|
||||||
|
return Some(path);
|
||||||
|
}
|
||||||
|
// Search .git directory in parent directries
|
||||||
|
for ancestor in path.ancestors().take(10) {
|
||||||
|
if ancestor.join(".git").exists() {
|
||||||
|
return Some(ancestor.to_path_buf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Lazy static to find and cache where the asset directory is.
|
/// Lazy static to find and cache where the asset directory is.
|
||||||
/// Cases we need to account for:
|
/// Cases we need to account for:
|
||||||
@ -154,19 +171,8 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. Root of the repository
|
// 3. Root of the repository
|
||||||
if let Ok(path) = std::env::current_dir() {
|
if let Some(path) = find_root() {
|
||||||
// If we are in the root, push path
|
|
||||||
if path.join(".git").is_dir() {
|
|
||||||
paths.push(path);
|
paths.push(path);
|
||||||
} else {
|
|
||||||
// Search .git directory in parent directries
|
|
||||||
for ancestor in path.ancestors().take(10) {
|
|
||||||
if ancestor.join(".git").is_dir() {
|
|
||||||
paths.push(ancestor.to_path_buf());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. System paths
|
// 4. System paths
|
||||||
@ -254,3 +260,244 @@ impl Compound for Directory {
|
|||||||
Ok(Directory(files))
|
Ok(Directory(files))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[warn(clippy::pedantic)]
|
||||||
|
#[cfg(feature = "asset_tweak")]
|
||||||
|
pub mod asset_tweak {
|
||||||
|
// Return path to repository by searching 10 directories back
|
||||||
|
use super::{find_root, fs, Asset, AssetExt, Path, RonLoader};
|
||||||
|
use ron::ser::{to_writer_pretty, PrettyConfig};
|
||||||
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize)]
|
||||||
|
struct AssetTweakWrapper<T>(T);
|
||||||
|
|
||||||
|
impl<T> Asset for AssetTweakWrapper<T>
|
||||||
|
where
|
||||||
|
T: Clone + Sized + Send + Sync + 'static + DeserializeOwned,
|
||||||
|
{
|
||||||
|
type Loader = RonLoader;
|
||||||
|
|
||||||
|
const EXTENSION: &'static str = "ron";
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
/// # Usage
|
||||||
|
/// Create file with content which represent tweaked value
|
||||||
|
///
|
||||||
|
/// Example if you want to tweak integer value
|
||||||
|
/// ```no_run
|
||||||
|
/// use veloren_common_assets::asset_tweak;
|
||||||
|
/// let x: i32 = asset_tweak::tweak_expect("x");
|
||||||
|
/// ```
|
||||||
|
/// File needs to look like that
|
||||||
|
/// ```text
|
||||||
|
/// assets/tweak/x.ron
|
||||||
|
/// (5)
|
||||||
|
/// ```
|
||||||
|
/// Note the parentheses.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// 1) If given `asset_specifier` does not exists
|
||||||
|
/// 2) If asseet is broken
|
||||||
|
pub fn tweak_expect<T>(specifier: &str) -> T
|
||||||
|
where
|
||||||
|
T: Clone + Sized + Send + Sync + 'static + DeserializeOwned,
|
||||||
|
{
|
||||||
|
let asset_specifier: &str = &format!("tweak.{}", specifier);
|
||||||
|
let handle = <AssetTweakWrapper<T> as AssetExt>::load_expect(asset_specifier);
|
||||||
|
let AssetTweakWrapper(value) = handle.read().clone();
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
/// # Usage
|
||||||
|
/// Will create file "assets/tweak/{specifier}.ron" if not exists
|
||||||
|
/// and return passed `value`.
|
||||||
|
/// If file exists will read a value from such file.
|
||||||
|
///
|
||||||
|
/// In release builds (if `debug_assertions` == false) just returns passed
|
||||||
|
/// `value`
|
||||||
|
///
|
||||||
|
/// Example if you want to tweak integer value
|
||||||
|
/// ```no_run
|
||||||
|
/// use veloren_common_assets::asset_tweak;
|
||||||
|
/// let x: i32 = asset_tweak::tweak_expect_or_create("x", 5);
|
||||||
|
/// ```
|
||||||
|
/// File needs to look like that
|
||||||
|
/// ```text
|
||||||
|
/// assets/tweak/x.ron
|
||||||
|
/// (5)
|
||||||
|
/// ```
|
||||||
|
/// Note the parentheses.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
/// 1) If asset is broken
|
||||||
|
/// 2) filesystem errors
|
||||||
|
pub fn tweak_expect_or_create<T>(specifier: &str, value: T) -> T
|
||||||
|
where
|
||||||
|
T: Clone + Sized + Send + Sync + 'static + DeserializeOwned + Serialize,
|
||||||
|
{
|
||||||
|
if cfg!(not(debug_assertions)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = find_root().expect("failed to discover repository_root");
|
||||||
|
let tweak_dir = root.join("assets/tweak/");
|
||||||
|
let filename = format!("{}.ron", specifier);
|
||||||
|
|
||||||
|
if Path::new(&tweak_dir.join(&filename)).is_file() {
|
||||||
|
let asset_specifier: &str = &format!("tweak.{}", specifier);
|
||||||
|
let handle = <AssetTweakWrapper<T> as AssetExt>::load_expect(asset_specifier);
|
||||||
|
let AssetTweakWrapper(new_value) = handle.read().clone();
|
||||||
|
|
||||||
|
new_value
|
||||||
|
} else {
|
||||||
|
fs::create_dir_all(&tweak_dir).expect("failed to create directory for tweak files");
|
||||||
|
let f = fs::File::create(tweak_dir.join(&filename)).unwrap_or_else(|err| {
|
||||||
|
panic!("failed to create file {:?}. Error: {:?}", &filename, err)
|
||||||
|
});
|
||||||
|
to_writer_pretty(f, &value, PrettyConfig::new()).unwrap_or_else(|err| {
|
||||||
|
panic!("failed to write to file {:?}. Error: {:?}", &filename, err)
|
||||||
|
});
|
||||||
|
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{find_root, tweak_expect, tweak_expect_or_create};
|
||||||
|
use serial_test::serial;
|
||||||
|
use std::{
|
||||||
|
convert::AsRef,
|
||||||
|
fmt::Debug,
|
||||||
|
fs::{self, File},
|
||||||
|
io::Write,
|
||||||
|
path::Path,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DirectoryGuard<P>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
dir: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> DirectoryGuard<P>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
fn create(dir: P) -> Self {
|
||||||
|
fs::create_dir_all(&dir).expect("failed to create directory");
|
||||||
|
Self { dir }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> Drop for DirectoryGuard<P>
|
||||||
|
where
|
||||||
|
P: AsRef<Path>,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) { fs::remove_dir(&self.dir).expect("failed to remove directory"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FileGuard<P>
|
||||||
|
where
|
||||||
|
P: AsRef<Path> + Debug,
|
||||||
|
{
|
||||||
|
file: P,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> FileGuard<P>
|
||||||
|
where
|
||||||
|
P: AsRef<Path> + Debug,
|
||||||
|
{
|
||||||
|
fn create(file: P) -> (Self, File) {
|
||||||
|
let f = File::create(&file)
|
||||||
|
.unwrap_or_else(|_| panic!("failed to create file {:?}", &file));
|
||||||
|
(Self { file }, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hold(file: P) -> Self { Self { file } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P> Drop for FileGuard<P>
|
||||||
|
where
|
||||||
|
P: AsRef<Path> + Debug,
|
||||||
|
{
|
||||||
|
fn drop(&mut self) {
|
||||||
|
fs::remove_file(&self.file)
|
||||||
|
.unwrap_or_else(|_| panic!("failed to create file {:?}", &self.file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_tweaked_string() {
|
||||||
|
let root = find_root().expect("failed to discover repository_root");
|
||||||
|
let tweak_dir = root.join("assets/tweak/");
|
||||||
|
let _dir_guard = DirectoryGuard::create(tweak_dir.clone());
|
||||||
|
|
||||||
|
// define test files
|
||||||
|
let from_int = tweak_dir.join("__test_int_tweak.ron");
|
||||||
|
let from_string = tweak_dir.join("__test_string_tweak.ron");
|
||||||
|
let from_map = tweak_dir.join("__test_map_tweak.ron");
|
||||||
|
|
||||||
|
// setup fs guards
|
||||||
|
let (_file_guard1, mut file1) = FileGuard::create(from_int);
|
||||||
|
let (_file_guard2, mut file2) = FileGuard::create(from_string);
|
||||||
|
let (_file_guard3, mut file3) = FileGuard::create(from_map);
|
||||||
|
|
||||||
|
// write to file and check result
|
||||||
|
file1
|
||||||
|
.write_all(b"(5)")
|
||||||
|
.expect("failed to write to the file");
|
||||||
|
let x = tweak_expect::<i32>("__test_int_tweak");
|
||||||
|
assert_eq!(x, 5);
|
||||||
|
|
||||||
|
// write to file and check result
|
||||||
|
file2
|
||||||
|
.write_all(br#"("Hello Zest")"#)
|
||||||
|
.expect("failed to write to the file");
|
||||||
|
let x = tweak_expect::<String>("__test_string_tweak");
|
||||||
|
assert_eq!(x, "Hello Zest".to_owned());
|
||||||
|
|
||||||
|
// write to file and check result
|
||||||
|
file3
|
||||||
|
.write_all(
|
||||||
|
br#"
|
||||||
|
({
|
||||||
|
"wow": 4,
|
||||||
|
"such": 5,
|
||||||
|
})
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.expect("failed to write to the file");
|
||||||
|
let x: std::collections::HashMap<String, i32> = tweak_expect("__test_map_tweak");
|
||||||
|
let mut map = std::collections::HashMap::new();
|
||||||
|
map.insert("wow".to_owned(), 4);
|
||||||
|
map.insert("such".to_owned(), 5);
|
||||||
|
assert_eq!(x, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[serial]
|
||||||
|
fn test_tweaked_create() {
|
||||||
|
let root = find_root().expect("failed to discover repository_root");
|
||||||
|
let tweak_dir = root.join("assets/tweak/");
|
||||||
|
let test_path1 = tweak_dir.join("__test_int_create.ron");
|
||||||
|
let _file_guard1 = FileGuard::hold(&test_path1);
|
||||||
|
let x = tweak_expect_or_create("__test_int_create", 5);
|
||||||
|
assert_eq!(x, 5);
|
||||||
|
assert!(test_path1.is_file());
|
||||||
|
|
||||||
|
// Test that file has stronger priority
|
||||||
|
let test_path2 = tweak_dir.join("__test_priority.ron");
|
||||||
|
let (_file_guard2, mut file) = FileGuard::create(&test_path2);
|
||||||
|
file.write_all(b"(10)")
|
||||||
|
.expect("failed to write to the file");
|
||||||
|
let x = tweak_expect_or_create("__test_priority", 6);
|
||||||
|
assert_eq!(x, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -31,7 +31,7 @@ fn main() {
|
|||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
// Generate paths
|
// Generate paths
|
||||||
let root = veloren_i18n::find_root().expect("Failed to find root of repository");
|
let root = common_assets::find_root().expect("Failed to find root of repository");
|
||||||
let asset_path = Path::new("assets/voxygen/i18n/");
|
let asset_path = Path::new("assets/voxygen/i18n/");
|
||||||
|
|
||||||
if let Some(code) = matches.value_of("CODE") {
|
if let Some(code) = matches.value_of("CODE") {
|
||||||
|
@ -388,23 +388,6 @@ pub fn list_localizations() -> Vec<LanguageMetadata> {
|
|||||||
/// Start hot reloading of i18n assets
|
/// Start hot reloading of i18n assets
|
||||||
pub fn start_hot_reloading() { assets::start_hot_reloading(); }
|
pub fn start_hot_reloading() { assets::start_hot_reloading(); }
|
||||||
|
|
||||||
/// Return path to repository by searching 10 directories back
|
|
||||||
pub fn find_root() -> Option<PathBuf> {
|
|
||||||
std::env::current_dir().map_or(None, |path| {
|
|
||||||
// If we are in the root, push path
|
|
||||||
if path.join(".git").is_dir() {
|
|
||||||
return Some(path);
|
|
||||||
}
|
|
||||||
// Search .git directory in parent directries
|
|
||||||
for ancestor in path.ancestors().take(10) {
|
|
||||||
if ancestor.join(".git").is_dir() {
|
|
||||||
return Some(ancestor.to_path_buf());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List localization directories as a `PathBuf` vector
|
/// List localization directories as a `PathBuf` vector
|
||||||
pub fn i18n_directories(i18n_dir: &Path) -> Vec<PathBuf> {
|
pub fn i18n_directories(i18n_dir: &Path) -> Vec<PathBuf> {
|
||||||
fs::read_dir(i18n_dir)
|
fs::read_dir(i18n_dir)
|
||||||
@ -416,6 +399,7 @@ pub fn i18n_directories(i18n_dir: &Path) -> Vec<PathBuf> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::assets;
|
||||||
// Test that localization list is loaded (not empty)
|
// Test that localization list is loaded (not empty)
|
||||||
#[test]
|
#[test]
|
||||||
fn test_localization_list() {
|
fn test_localization_list() {
|
||||||
@ -435,7 +419,7 @@ mod tests {
|
|||||||
fn verify_all_localizations() {
|
fn verify_all_localizations() {
|
||||||
// Generate paths
|
// Generate paths
|
||||||
let i18n_asset_path = std::path::Path::new("assets/voxygen/i18n/");
|
let i18n_asset_path = std::path::Path::new("assets/voxygen/i18n/");
|
||||||
let root_dir = super::find_root().expect("Failed to discover repository root");
|
let root_dir = assets::find_root().expect("Failed to discover repository root");
|
||||||
crate::verification::verify_all_localizations(&root_dir, &i18n_asset_path);
|
crate::verification::verify_all_localizations(&root_dir, &i18n_asset_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,7 +431,7 @@ mod tests {
|
|||||||
let be_verbose = true;
|
let be_verbose = true;
|
||||||
// Generate paths
|
// Generate paths
|
||||||
let i18n_asset_path = std::path::Path::new("assets/voxygen/i18n/");
|
let i18n_asset_path = std::path::Path::new("assets/voxygen/i18n/");
|
||||||
let root_dir = super::find_root().expect("Failed to discover repository root");
|
let root_dir = assets::find_root().expect("Failed to discover repository root");
|
||||||
crate::analysis::test_all_localizations(&root_dir, &i18n_asset_path, be_verbose);
|
crate::analysis::test_all_localizations(&root_dir, &i18n_asset_path, be_verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user