settings.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. use crate::{Result, TraceSrc};
  2. use serde::{Deserialize, Serialize};
  3. use std::{fs, path::PathBuf};
  4. use tracing::{error, trace, warn};
  5. const GLOBAL_SETTINGS_FILE_NAME: &str = "dioxus/settings.toml";
  6. /// Describes cli settings from project or global level.
  7. /// The order of priority goes:
  8. /// 1. CLI Flags/Arguments
  9. /// 2. Project-level Settings
  10. /// 3. Global-level settings.
  11. ///
  12. /// This allows users to control the cli settings with ease.
  13. #[derive(Debug, Clone, Serialize, Deserialize, Default)]
  14. pub(crate) struct CliSettings {
  15. /// Describes whether hot reload should always be on.
  16. pub(crate) always_hot_reload: Option<bool>,
  17. /// Describes whether the CLI should always open the browser for Web targets.
  18. pub(crate) always_open_browser: Option<bool>,
  19. /// Describes whether desktop apps in development will be pinned always-on-top.
  20. pub(crate) always_on_top: Option<bool>,
  21. /// Describes the interval in seconds that the CLI should poll for file changes on WSL.
  22. #[serde(default = "default_wsl_file_poll_interval")]
  23. pub(crate) wsl_file_poll_interval: Option<u16>,
  24. }
  25. impl CliSettings {
  26. /// Load the settings from the local, global, or default config in that order
  27. pub(crate) fn load() -> Self {
  28. Self::from_global().unwrap_or_default()
  29. }
  30. /// Get the current settings structure from global.
  31. pub(crate) fn from_global() -> Option<Self> {
  32. let Some(path) = dirs::data_local_dir() else {
  33. warn!("failed to get local data directory, some config keys may be missing");
  34. return None;
  35. };
  36. let path = path.join(GLOBAL_SETTINGS_FILE_NAME);
  37. let Some(data) = fs::read_to_string(path).ok() else {
  38. // We use a debug here because we expect the file to not exist.
  39. trace!("failed to read `{}` config file", GLOBAL_SETTINGS_FILE_NAME);
  40. return None;
  41. };
  42. let data = toml::from_str::<CliSettings>(&data).ok();
  43. if data.is_none() {
  44. warn!(
  45. "failed to parse `{}` config file",
  46. GLOBAL_SETTINGS_FILE_NAME
  47. );
  48. }
  49. data
  50. }
  51. /// Save the current structure to the global settings toml.
  52. /// This does not save to project-level settings.
  53. pub(crate) fn save(self) -> Result<Self> {
  54. let path = Self::get_settings_path().ok_or_else(|| {
  55. error!(dx_src = ?TraceSrc::Dev, "failed to get settings path");
  56. anyhow::anyhow!("failed to get settings path")
  57. })?;
  58. let data = toml::to_string_pretty(&self).map_err(|e| {
  59. error!(dx_src = ?TraceSrc::Dev, ?self, "failed to parse config into toml");
  60. anyhow::anyhow!("failed to parse config into toml: {e}")
  61. })?;
  62. // Create the directory structure if it doesn't exist.
  63. let parent_path = path.parent().unwrap();
  64. if let Err(e) = fs::create_dir_all(parent_path) {
  65. error!(
  66. dx_src = ?TraceSrc::Dev,
  67. ?data,
  68. ?path,
  69. "failed to create directories for settings file"
  70. );
  71. return Err(
  72. anyhow::anyhow!("failed to create directories for settings file: {e}").into(),
  73. );
  74. }
  75. // Write the data.
  76. let result = fs::write(&path, data.clone());
  77. if let Err(e) = result {
  78. error!(?data, ?path, "failed to save global cli settings");
  79. return Err(anyhow::anyhow!("failed to save global cli settings: {e}").into());
  80. }
  81. Ok(self)
  82. }
  83. /// Get the path to the settings toml file.
  84. pub(crate) fn get_settings_path() -> Option<PathBuf> {
  85. let Some(path) = dirs::data_local_dir() else {
  86. warn!("failed to get local data directory, some config keys may be missing");
  87. return None;
  88. };
  89. Some(path.join(GLOBAL_SETTINGS_FILE_NAME))
  90. }
  91. /// Modify the settings toml file
  92. pub(crate) fn modify_settings(with: impl FnOnce(&mut CliSettings)) -> Result<()> {
  93. let mut settings = Self::load();
  94. with(&mut settings);
  95. settings.save()?;
  96. Ok(())
  97. }
  98. }
  99. fn default_wsl_file_poll_interval() -> Option<u16> {
  100. Some(2)
  101. }