Skip to content

Commit 599dd13

Browse files
committed
pr: uniformise dirs for state and config
1 parent f5c2fb9 commit 599dd13

File tree

3 files changed

+122
-47
lines changed

3 files changed

+122
-47
lines changed

Cargo.lock

Lines changed: 50 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

anyrun/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ wl-clipboard-rs = "0.9.1"
1717
nix = { version = "0.29", default-features = false, features = ["process"] }
1818
clap = { version = "4.2.7", features = ["derive"] }
1919
chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
20+
dirs = "5.0.1"

anyrun/src/main.rs

Lines changed: 71 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::{
1212
use abi_stable::std_types::{ROption, RVec};
1313
use anyrun_interface::{HandleResult, Match, PluginInfo, PluginRef, PollResult};
1414
use clap::{Parser, ValueEnum};
15+
use dirs;
1516
use gtk::{gdk, gdk_pixbuf, gio, glib, prelude::*};
1617
use nix::unistd;
1718
use serde::{Deserialize, Serialize};
@@ -182,11 +183,76 @@ struct RuntimeData {
182183
/// Used for displaying errors later on
183184
error_label: String,
184185
config_dir: String,
186+
state_dir: Option<String>,
185187
}
186188

187189
impl RuntimeData {
190+
fn new(config_dir_path: Option<String>, cli_config: ConfigArgs) -> Self {
191+
// Setup config directory
192+
let config_dir = config_dir_path.unwrap_or_else(|| {
193+
dirs::config_dir()
194+
.map(|dir| dir.join("anyrun"))
195+
.and_then(|path| path.to_str().map(String::from))
196+
.filter(|path| PathBuf::from(path).exists())
197+
.unwrap_or_else(|| DEFAULT_CONFIG_DIR.to_string())
198+
});
199+
200+
// Load config, if unable to then read default config
201+
let (mut config, error_label) = match fs::read_to_string(format!("{}/config.ron", config_dir)) {
202+
Ok(content) => ron::from_str(&content)
203+
.map(|config| (config, String::new()))
204+
.unwrap_or_else(|why| {
205+
(
206+
Config::default(),
207+
format!(
208+
"Failed to parse Anyrun config file, using default config: {}",
209+
why
210+
),
211+
)
212+
}),
213+
Err(why) => (
214+
Config::default(),
215+
format!(
216+
"Failed to read Anyrun config file, using default config: {}",
217+
why
218+
),
219+
),
220+
};
221+
222+
// Merge CLI config if provided
223+
config.merge_opt(cli_config);
224+
225+
// Setup state directory only if persistence is enabled
226+
let state_dir = if config.persist_state {
227+
let state_dir = dirs::state_dir()
228+
.unwrap_or_else(|| dirs::cache_dir().expect("Failed to get state or cache directory"))
229+
.join("anyrun");
230+
231+
// Ensure atomically that the directory exists
232+
if let Err(e) = fs::create_dir_all(&state_dir) {
233+
eprintln!("Failed to create state directory at {}: {}", state_dir.display(), e);
234+
std::process::exit(1);
235+
}
236+
237+
Some(state_dir.to_str().unwrap().to_string())
238+
} else {
239+
None
240+
};
241+
242+
Self {
243+
exclusive: None,
244+
plugins: Vec::new(),
245+
post_run_action: PostRunAction::None,
246+
config,
247+
error_label,
248+
config_dir,
249+
state_dir,
250+
}
251+
}
252+
188253
fn state_file(&self) -> String {
189-
format!("{}/state.txt", self.config_dir)
254+
let state_dir = self.state_dir.as_ref().expect("state operations called when persistence is disabled");
255+
PathBuf::from(state_dir).join("state.txt").to_str().unwrap().to_string()
190256
}
191257

192258
fn save_state(&self, text: &str) -> io::Result<()> {
@@ -281,51 +347,10 @@ fn main() {
281347

282348
let args = Args::parse();
283349

284-
// Figure out the config dir
285-
let user_dir = format!(
286-
"{}/.config/anyrun",
287-
env::var("HOME").expect("Could not determine home directory! Is $HOME set?")
288-
);
289-
let config_dir = args.config_dir.unwrap_or_else(|| {
290-
if PathBuf::from(&user_dir).exists() {
291-
user_dir
292-
} else {
293-
DEFAULT_CONFIG_DIR.to_string()
294-
}
295-
});
296-
297-
// Load config, if unable to then read default config. If an error occurs the message will be displayed.
298-
let (mut config, error_label) = match fs::read_to_string(format!("{}/config.ron", config_dir)) {
299-
Ok(content) => ron::from_str(&content)
300-
.map(|config| (config, String::new()))
301-
.unwrap_or_else(|why| {
302-
(
303-
Config::default(),
304-
format!(
305-
"Failed to parse Anyrun config file, using default config: {}",
306-
why
307-
),
308-
)
309-
}),
310-
Err(why) => (
311-
Config::default(),
312-
format!(
313-
"Failed to read Anyrun config file, using default config: {}",
314-
why
315-
),
316-
),
317-
};
318-
319-
config.merge_opt(args.config);
320-
321-
let runtime_data = Rc::new(RefCell::new(RuntimeData {
322-
exclusive: None,
323-
plugins: Vec::new(),
324-
post_run_action: PostRunAction::None,
325-
config,
326-
error_label,
327-
config_dir,
328-
}));
350+
let runtime_data = Rc::new(RefCell::new(RuntimeData::new(
351+
args.config_dir,
352+
args.config,
353+
)));
329354

330355
let runtime_data_clone = runtime_data.clone();
331356
app.connect_activate(move |app| activate(app, runtime_data_clone.clone()));

0 commit comments

Comments
 (0)