desktop: Add log filename pattern (e.g. with timestamp) to preferences
This commit is contained in:
parent
6585ffdd28
commit
a5fe7e1c81
|
@ -13,3 +13,7 @@ language = Language
|
|||
|
||||
audio-output-device = Audio Output Device
|
||||
audio-output-device-default = System Default
|
||||
|
||||
log-filename-pattern = Log Filename
|
||||
log-filename-pattern-single-file = Single File (ruffle.log)
|
||||
log-filename-pattern-with-timestamp = With Timestamp
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::gui::{available_languages, optional_text, text};
|
||||
use crate::log::FilenamePattern;
|
||||
use crate::preferences::GlobalPreferences;
|
||||
use cpal::traits::{DeviceTrait, HostTrait};
|
||||
use egui::{Align2, Button, ComboBox, Grid, Ui, Widget, Window};
|
||||
|
@ -25,6 +26,9 @@ pub struct PreferencesDialog {
|
|||
output_device: Option<String>,
|
||||
available_output_devices: Vec<String>,
|
||||
output_device_changed: bool,
|
||||
|
||||
log_filename_pattern: FilenamePattern,
|
||||
log_filename_pattern_changed: bool,
|
||||
}
|
||||
|
||||
impl PreferencesDialog {
|
||||
|
@ -63,6 +67,9 @@ impl PreferencesDialog {
|
|||
available_output_devices,
|
||||
output_device_changed: false,
|
||||
|
||||
log_filename_pattern: preferences.log_filename_pattern(),
|
||||
log_filename_pattern_changed: false,
|
||||
|
||||
preferences,
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +95,8 @@ impl PreferencesDialog {
|
|||
self.show_language_preferences(locale, ui);
|
||||
|
||||
self.show_audio_preferences(locale, ui);
|
||||
|
||||
self.show_log_preferences(locale, ui);
|
||||
});
|
||||
|
||||
if self.restart_required() {
|
||||
|
@ -115,6 +124,7 @@ impl PreferencesDialog {
|
|||
self.graphics_backend != self.preferences.graphics_backends()
|
||||
|| self.power_preference != self.preferences.graphics_power_preference()
|
||||
|| self.output_device != self.preferences.output_device_name()
|
||||
|| self.log_filename_pattern != self.preferences.log_filename_pattern()
|
||||
}
|
||||
|
||||
fn show_graphics_preferences(
|
||||
|
@ -237,6 +247,30 @@ impl PreferencesDialog {
|
|||
ui.end_row();
|
||||
}
|
||||
|
||||
fn show_log_preferences(&mut self, locale: &LanguageIdentifier, ui: &mut Ui) {
|
||||
ui.label(text(locale, "log-filename-pattern"));
|
||||
|
||||
let previous = self.log_filename_pattern;
|
||||
ComboBox::from_id_source("log-filename-pattern")
|
||||
.selected_text(filename_pattern_name(locale, self.log_filename_pattern))
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(
|
||||
&mut self.log_filename_pattern,
|
||||
FilenamePattern::SingleFile,
|
||||
filename_pattern_name(locale, FilenamePattern::SingleFile),
|
||||
);
|
||||
ui.selectable_value(
|
||||
&mut self.log_filename_pattern,
|
||||
FilenamePattern::WithTimestamp,
|
||||
filename_pattern_name(locale, FilenamePattern::WithTimestamp),
|
||||
);
|
||||
});
|
||||
if self.log_filename_pattern != previous {
|
||||
self.log_filename_pattern_changed = true;
|
||||
}
|
||||
ui.end_row();
|
||||
}
|
||||
|
||||
fn save(&mut self) {
|
||||
if let Err(e) = self.preferences.write_preferences(|preferences| {
|
||||
if self.graphics_backend_changed {
|
||||
|
@ -252,6 +286,9 @@ impl PreferencesDialog {
|
|||
preferences.set_output_device(self.output_device.clone());
|
||||
// [NA] TODO: Inform the running player that the device changed
|
||||
}
|
||||
if self.log_filename_pattern_changed {
|
||||
preferences.set_log_filename_pattern(self.log_filename_pattern);
|
||||
}
|
||||
}) {
|
||||
// [NA] TODO: Better error handling... everywhere in desktop, really
|
||||
tracing::error!("Could not save preferences: {e}");
|
||||
|
@ -276,6 +313,13 @@ fn graphics_power_name(locale: &LanguageIdentifier, power_preference: PowerPrefe
|
|||
}
|
||||
}
|
||||
|
||||
fn filename_pattern_name(locale: &LanguageIdentifier, pattern: FilenamePattern) -> Cow<str> {
|
||||
match pattern {
|
||||
FilenamePattern::SingleFile => text(locale, "log-filename-pattern-single-file"),
|
||||
FilenamePattern::WithTimestamp => text(locale, "log-filename-pattern-with-timestamp"),
|
||||
}
|
||||
}
|
||||
|
||||
fn backend_availability(descriptors: &Descriptors, backend: wgpu::Backends) -> wgpu::Backends {
|
||||
if descriptors
|
||||
.wgpu_instance
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
use chrono::Utc;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug, Default)]
|
||||
pub enum FilenamePattern {
|
||||
#[default]
|
||||
SingleFile,
|
||||
WithTimestamp,
|
||||
}
|
||||
|
||||
impl FromStr for FilenamePattern {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"single_file" => Ok(FilenamePattern::SingleFile),
|
||||
"with_timestamp" => Ok(FilenamePattern::WithTimestamp),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FilenamePattern {
|
||||
pub fn create_path(&self, directory: &Path) -> PathBuf {
|
||||
match self {
|
||||
FilenamePattern::SingleFile => directory.join("ruffle.log"),
|
||||
FilenamePattern::WithTimestamp => {
|
||||
directory.join(Utc::now().format("ruffle_%F_%H-%M-%S.log").to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> &'static str {
|
||||
match self {
|
||||
FilenamePattern::SingleFile => "single_file",
|
||||
FilenamePattern::WithTimestamp => "with_timestamp",
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ mod cli;
|
|||
mod custom_event;
|
||||
mod executor;
|
||||
mod gui;
|
||||
mod log;
|
||||
mod player;
|
||||
mod preferences;
|
||||
mod task;
|
||||
|
@ -155,7 +156,9 @@ fn main() -> Result<(), Error> {
|
|||
|
||||
// [NA] `_guard` cannot be `_` or it'll immediately drop
|
||||
// https://docs.rs/tracing-appender/latest/tracing_appender/non_blocking/index.html
|
||||
let log_path = preferences.cli.config.join("ruffle.log");
|
||||
let log_path = preferences
|
||||
.log_filename_pattern()
|
||||
.create_path(&preferences.cli.config);
|
||||
let (non_blocking_file, _file_guard) = tracing_appender::non_blocking(File::create(log_path)?);
|
||||
let (non_blocking_stdout, _stdout_guard) = tracing_appender::non_blocking(std::io::stdout());
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ mod read;
|
|||
mod write;
|
||||
|
||||
use crate::cli::Opt;
|
||||
use crate::log::FilenamePattern;
|
||||
use crate::preferences::read::read_preferences;
|
||||
use crate::preferences::write::PreferencesWriter;
|
||||
use anyhow::{Context, Error};
|
||||
|
@ -117,6 +118,15 @@ impl GlobalPreferences {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn log_filename_pattern(&self) -> FilenamePattern {
|
||||
self.preferences
|
||||
.lock()
|
||||
.expect("Preferences is not reentrant")
|
||||
.values
|
||||
.log
|
||||
.filename_pattern
|
||||
}
|
||||
|
||||
pub fn write_preferences(&self, fun: impl FnOnce(&mut PreferencesWriter)) -> Result<(), Error> {
|
||||
let mut preferences = self
|
||||
.preferences
|
||||
|
@ -158,6 +168,7 @@ pub struct SavedGlobalPreferences {
|
|||
pub output_device: Option<String>,
|
||||
pub mute: bool,
|
||||
pub volume: f32,
|
||||
pub log: LogPreferences,
|
||||
}
|
||||
|
||||
impl Default for SavedGlobalPreferences {
|
||||
|
@ -173,6 +184,12 @@ impl Default for SavedGlobalPreferences {
|
|||
output_device: None,
|
||||
mute: false,
|
||||
volume: 1.0,
|
||||
log: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Default)]
|
||||
pub struct LogPreferences {
|
||||
pub filename_pattern: FilenamePattern,
|
||||
}
|
||||
|
|
|
@ -72,6 +72,21 @@ pub fn read_preferences(input: &str) -> (ParseResult, Document) {
|
|||
Err(e) => result.add_warning(format!("Invalid mute: {e}")),
|
||||
};
|
||||
|
||||
if let Some(log_item) = document.get("log") {
|
||||
if let Some(log) = log_item.as_table_like() {
|
||||
match parse_item_from_str(log.get("filename_pattern")) {
|
||||
Ok(Some(value)) => result.result.log.filename_pattern = value,
|
||||
Ok(None) => {}
|
||||
Err(e) => result.add_warning(format!("Invalid log.filename_pattern: {e}")),
|
||||
};
|
||||
} else {
|
||||
result.add_warning(format!(
|
||||
"Invalid log: expected table but found {}",
|
||||
log_item.type_name()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
(result, document)
|
||||
}
|
||||
|
||||
|
@ -118,6 +133,8 @@ fn parse_item_from_bool(item: Option<&Item>) -> Result<Option<bool>, String> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::log::FilenamePattern;
|
||||
use crate::preferences::LogPreferences;
|
||||
use fluent_templates::loader::langid;
|
||||
use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference};
|
||||
|
||||
|
@ -370,4 +387,63 @@ mod tests {
|
|||
read_preferences("volume = -1.0").0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log_filename() {
|
||||
assert_eq!(
|
||||
ParseResult {
|
||||
result: SavedGlobalPreferences {
|
||||
log: LogPreferences {
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
warnings: vec![
|
||||
"Invalid log.filename_pattern: expected string but found integer".to_string()
|
||||
]
|
||||
},
|
||||
read_preferences("log = {filename_pattern = 5}").0
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
ParseResult {
|
||||
result: SavedGlobalPreferences {
|
||||
log: LogPreferences {
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
warnings: vec![
|
||||
"Invalid log.filename_pattern: unsupported value \"???\"".to_string()
|
||||
]
|
||||
},
|
||||
read_preferences("log = {filename_pattern = \"???\"}").0
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
ParseResult {
|
||||
result: SavedGlobalPreferences {
|
||||
log: LogPreferences {
|
||||
filename_pattern: FilenamePattern::WithTimestamp,
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
warnings: vec![]
|
||||
},
|
||||
read_preferences("log = {filename_pattern = \"with_timestamp\"}").0
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log() {
|
||||
assert_eq!(
|
||||
ParseResult {
|
||||
result: SavedGlobalPreferences {
|
||||
..Default::default()
|
||||
},
|
||||
warnings: vec!["Invalid log: expected table but found string".to_string()]
|
||||
},
|
||||
read_preferences("log = \"yes\"").0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use crate::log::FilenamePattern;
|
||||
use crate::preferences::PreferencesAndDocument;
|
||||
use ruffle_render_wgpu::clap::{GraphicsBackend, PowerPreference};
|
||||
use toml_edit::value;
|
||||
|
@ -43,11 +44,17 @@ impl<'a> PreferencesWriter<'a> {
|
|||
self.0.toml_document["volume"] = value(volume as f64);
|
||||
self.0.values.volume = volume;
|
||||
}
|
||||
|
||||
pub fn set_log_filename_pattern(&mut self, pattern: FilenamePattern) {
|
||||
self.0.toml_document["log"]["filename_pattern"] = value(pattern.as_str());
|
||||
self.0.values.log.filename_pattern = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::log::FilenamePattern;
|
||||
use crate::preferences::read::read_preferences;
|
||||
use fluent_templates::loader::langid;
|
||||
|
||||
|
@ -149,4 +156,23 @@ mod tests {
|
|||
"mute = false\n",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_log_filename_pattern() {
|
||||
test(
|
||||
"",
|
||||
|writer| writer.set_log_filename_pattern(FilenamePattern::WithTimestamp),
|
||||
"log = { filename_pattern = \"with_timestamp\" }\n",
|
||||
);
|
||||
test(
|
||||
"log = { filename_pattern = \"with_timestamp\" }\n",
|
||||
|writer| writer.set_log_filename_pattern(FilenamePattern::SingleFile),
|
||||
"log = { filename_pattern = \"single_file\" }\n",
|
||||
);
|
||||
test(
|
||||
"[log]\nfilename_pattern = \"with_timestamp\"\n",
|
||||
|writer| writer.set_log_filename_pattern(FilenamePattern::SingleFile),
|
||||
"[log]\nfilename_pattern = \"single_file\"\n",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue