Ablageort für die anwendungsweite Konfiguration #3

Closed
opened 2026-08-27 12:32:19 +00:00 by RDietermann · 1 comment
Owner

Part of #1

Question

Wo legt eine Desktop-App unter Windows (und, falls billig zu beantworten, macOS/Linux) ihre anwendungsweiten Konfigurationsdaten ab — und wie ermittelt man diesen Pfad in Rust?

Hintergrund: Die Liste zuletzt benutzter Workspaces muss außerhalb jedes Workspace liegen, sonst kann man sie nicht lesen, bevor ein Workspace geöffnet ist.

Konkret zu klären:

  • Welche Crate ist der übliche Weg (dirs, directories, etwas anderes)? Welche wird gepflegt?
  • Welcher der zurückgegebenen Pfade ist der richtige für Konfiguration — nicht Cache, nicht Daten? Unter Windows: %APPDATA% (Roaming) oder %LOCALAPPDATA%?
  • Gibt es in Dioxus 0.7 bereits eine eigene Abstraktion dafür, die man statt einer Extra-Crate nutzen würde?
  • Muss die App das Verzeichnis selbst anlegen, oder existiert es?

Zielgröße: ein konkreter Pfad für DioNotes unter Windows, plus der Rust-Aufruf, der ihn liefert.

Part of #1 ## Question Wo legt eine Desktop-App unter Windows (und, falls billig zu beantworten, macOS/Linux) ihre anwendungsweiten Konfigurationsdaten ab — und wie ermittelt man diesen Pfad in Rust? Hintergrund: Die Liste zuletzt benutzter Workspaces muss außerhalb jedes Workspace liegen, sonst kann man sie nicht lesen, bevor ein Workspace geöffnet ist. Konkret zu klären: - Welche Crate ist der übliche Weg (`dirs`, `directories`, etwas anderes)? Welche wird gepflegt? - Welcher der zurückgegebenen Pfade ist der richtige für Konfiguration — nicht Cache, nicht Daten? Unter Windows: `%APPDATA%` (Roaming) oder `%LOCALAPPDATA%`? - Gibt es in Dioxus 0.7 bereits eine eigene Abstraktion dafür, die man statt einer Extra-Crate nutzen würde? - Muss die App das Verzeichnis selbst anlegen, oder existiert es? Zielgröße: ein konkreter Pfad für DioNotes unter Windows, plus der Rust-Aufruf, der ihn liefert.
RDietermann added the wayfinder:research label 2026-08-27 12:32:19 +00:00
RDietermann added a new dependency 2026-08-27 12:35:51 +00:00
RDietermann self-assigned this 2026-08-27 12:39:00 +00:00
Author
Owner

Antwort

Crate: directories 6.0.0 (Release 2025-01-12). Zusammen mit dem Geschwister-Crate dirs 6.0.0 der De-facto-Standard (dirs: ~308 Mio. Downloads, ~72 Mio. in 90 Tagen). Wartungslage ehrlich: Die GitHub-Repos sind seit 2025-02-18 archiviert und nach https://codeberg.org/dirs/directories-rs umgezogen; dort nicht archiviert, aber seit dem 6.0.0-Release nur noch README-/Metadaten-Commits. Also: gepflegt-aber-fertig, kein Risiko für "gib mir einen Pfad". Aktive Alternative wäre etcetera 0.11.0 (2025-10-28) — bringt uns aber nichts.

Nebenbefund: dirs 6.0.0 liegt bereits transitiv in unserer Cargo.lock (über wry und tray-icon). directories hängt nur an dirs-sys ^0.5.0 — kostet also genau eine zusätzlich kompilierte Crate.

Konkrete Pfade

Windows:

C:\Users\<Benutzername>\AppData\Local\DioNotes\config\recent-workspaces.json

Linux:

/home/<benutzername>/.local/state/dionotes/recent-workspaces.json

macOS: ~/Library/Application Support/DioNotes/recent-workspaces.json

Rust-Aufruf — ein Ausdruck, alle drei Plattformen:

use directories::ProjectDirs;

let dirs = ProjectDirs::from("", "", "DioNotes")
    .ok_or("Home-Verzeichnis nicht ermittelbar")?;

// state_dir() gibt es nur unter Linux (XDG_STATE_HOME); Windows/macOS liefern None.
let dir = dirs.state_dir().unwrap_or_else(|| dirs.config_local_dir());

std::fs::create_dir_all(dir)?;
let file = dir.join("recent-workspaces.json");

Bewusst kein #[cfg(target_os = ...)] — die Fallunterscheidung steckt schon im Option, das directories zurückgibt. Windows-Werte auf diesem Rechner ausgeführt und verifiziert (state_dir() = None, Fallback greift); Linux/macOS aus dem Quelltext von directories 6.0.0 abgeleitet.

Linux: es ist nicht ~/.config

Der Punkt, der mich beim Nachrecherchieren die Empfehlung hat ändern lassen. XDG kennt neben config und data noch $XDG_STATE_HOME (Default ~/.local/state). Spec 0.8, wörtlich:

"The $XDG_STATE_HOME contains state data that should persist between (application) restarts, but that is not important or portable enough to the user that it should be stored in $XDG_DATA_HOME. It may contain:

  • actions history (logs, history, recently used files, …)
  • current state of the application that can be reused on a restart (view, layout, open files, undo history, …)"

— https://specifications.freedesktop.org/basedir/latest/

Das ist keine Auslegung: Die Spec nennt "recently used files" und "open files" namentlich. Unsere Workspace-Liste ist unter Linux State, nicht Config.

directories bildet das ab und liefert state_dir() nur dort, wo es das Konzept gibt — Some("~/.local/state/dionotes") unter Linux, None unter Windows (src/win.rs Z. 89) und macOS (src/mac.rs Z. 83).

Zwei weitere Linux-Punkte:

  • Kleinschreibung erledigt directories automatisch (trim_and_lowercase_then_replace_spaces in src/lin.rs): aus "DioNotes" wird dionotes. Mit dirs allein bekäme man ~/.config/DioNotes — unschön. Das ist das stärkste Einzelargument für directories statt dirs.
  • Flatpak/Snap brauchen keine Sonderbehandlung: directories liest die XDG-Variablen zur Laufzeit, eine Sandbox, die sie umbiegt, wird automatisch respektiert. (Ob die gespeicherten absoluten Workspace-Pfade aus einer Sandbox erreichbar sind, ist ein separates Thema.)

Windows: %LOCALAPPDATA%, nicht %APPDATA%

Die Windows-Konvention fragt nicht "Konfiguration oder Daten?", sondern "maschinenunabhängig oder maschinenspezifisch?". Microsoft wörtlich:

"Windows uses the Local and LocalLow folders for application data that does not roam with the user. Usually this data is either machine specific or too large to roam."
"Windows uses the Roaming folder for application specific data … which are machine independent and should roam with the user profile."
— https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc766489(v=ws.10)

Bestätigt in der aktuell gepflegten .NET-Doku: ApplicationData = "for the current roaming user", LocalApplicationData = "used by the current, non-roaming user" (https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder).

Die Workspace-Liste besteht aus absoluten Dateisystempfaden. Ein D:\Notizen\Privat existiert auf einem zweiten Rechner nicht — maschinenspezifisch, also Local. Dazu der Fehlermodus von Roaming: Synchronisiert wird beim Ab-/Anmelden, bei paralleler Nutzung gewinnt die letzte Abmeldung und überschreibt die andere Sitzung.

Wichtig: Diese Entscheidung ist rein Windows-spezifisch und kostet anderswo nichts — unter Linux und macOS ist config_local_dir im Quelltext ein config_dir.clone(), also derselbe Pfad.

Nicht zu benutzen: cache_dir() (löschbar), data_dir()/data_local_dir() (Nutzdaten), preference_dir() (zeigt auf macOS nach ~/Library/Preferences, und dorthin darf man laut Apple nicht selbst schreiben).

Dioxus 0.7: keine eigene Abstraktion

dioxus_desktop::Config::with_data_directory klingt richtig, ist es aber nicht. Der Wert landet in WebContext::new(cfg.data_dir.clone()) (packages/desktop/src/webview.rs @ v0.7.1), und wry::WebContext ist das Browser-Profil der WebView — WebView2-Cookies, LocalStorage, Cache. Nicht die Anwendungskonfiguration.

Ansonsten: nichts Passendes in der Item-Liste von dioxus 0.7.1, kein Treffer in zwei unabhängigen Doku-Korpora, nichts in unserer AGENTS.md. Und das offizielle Dioxus-SDK greift für seinen use_persistent-Storage selbst zu directories::BaseDirs::new().unwrap().data_local_dir() — gäbe es etwas Eingebautes, hätte es das benutzt.

Verzeichnis anlegen: ja

Die Crate legt nichts an. README wörtlich: "This library does not create directories or check for their existence. The library only provides information on what the path to a certain directory should be."

Verifiziert: %LOCALAPPDATA%\DioNotes existiert auf meinem Rechner nicht. Die Basis-Ordner %APPDATA%/%LOCALAPPDATA% dagegen schon — PERUSER-Known-Folders, kommen mit dem Benutzerprofil. Anzulegen ist nur der App-Teil, per std::fs::create_dir_all (idempotent). Unter Linux erwartet die XDG-Spec dasselbe ausdrücklich: "When attempting to write a file, if the destination directory is non-existent an attempt should be made to create it with permission 0700."


Langfassung mit allen Quellenangaben und der Trennung belegt/Vermutung: Branch research/config-ablageort, Datei docs/research/konfigurations-ablageort.md (nicht gepusht).

## Antwort **Crate:** `directories` **6.0.0** (Release 2025-01-12). Zusammen mit dem Geschwister-Crate `dirs` 6.0.0 der De-facto-Standard (`dirs`: ~308 Mio. Downloads, ~72 Mio. in 90 Tagen). Wartungslage ehrlich: Die GitHub-Repos sind seit 2025-02-18 **archiviert** und nach <https://codeberg.org/dirs/directories-rs> umgezogen; dort nicht archiviert, aber seit dem 6.0.0-Release nur noch README-/Metadaten-Commits. Also: gepflegt-aber-fertig, kein Risiko für "gib mir einen Pfad". Aktive Alternative wäre `etcetera` 0.11.0 (2025-10-28) — bringt uns aber nichts. Nebenbefund: `dirs 6.0.0` liegt bereits transitiv in unserer `Cargo.lock` (über `wry` und `tray-icon`). `directories` hängt nur an `dirs-sys ^0.5.0` — kostet also genau eine zusätzlich kompilierte Crate. ### Konkrete Pfade **Windows:** ``` C:\Users\<Benutzername>\AppData\Local\DioNotes\config\recent-workspaces.json ``` **Linux:** ``` /home/<benutzername>/.local/state/dionotes/recent-workspaces.json ``` **macOS:** `~/Library/Application Support/DioNotes/recent-workspaces.json` **Rust-Aufruf — ein Ausdruck, alle drei Plattformen:** ```rust use directories::ProjectDirs; let dirs = ProjectDirs::from("", "", "DioNotes") .ok_or("Home-Verzeichnis nicht ermittelbar")?; // state_dir() gibt es nur unter Linux (XDG_STATE_HOME); Windows/macOS liefern None. let dir = dirs.state_dir().unwrap_or_else(|| dirs.config_local_dir()); std::fs::create_dir_all(dir)?; let file = dir.join("recent-workspaces.json"); ``` Bewusst **kein** `#[cfg(target_os = ...)]` — die Fallunterscheidung steckt schon im `Option`, das `directories` zurückgibt. Windows-Werte auf diesem Rechner ausgeführt und verifiziert (`state_dir() = None`, Fallback greift); Linux/macOS aus dem Quelltext von `directories` 6.0.0 abgeleitet. ### Linux: es ist *nicht* `~/.config` Der Punkt, der mich beim Nachrecherchieren die Empfehlung hat ändern lassen. XDG kennt neben `config` und `data` noch `$XDG_STATE_HOME` (Default `~/.local/state`). Spec 0.8, wörtlich: > "The `$XDG_STATE_HOME` contains state data that should persist between (application) restarts, but that is not important or portable enough to the user that it should be stored in `$XDG_DATA_HOME`. It may contain: > - actions history (logs, history, **recently used files**, …) > - current state of the application that can be reused on a restart (view, layout, **open files**, undo history, …)" > > — <https://specifications.freedesktop.org/basedir/latest/> Das ist keine Auslegung: Die Spec nennt "recently used files" und "open files" namentlich. Unsere Workspace-Liste ist unter Linux **State, nicht Config**. `directories` bildet das ab und liefert `state_dir()` nur dort, wo es das Konzept gibt — `Some("~/.local/state/dionotes")` unter Linux, `None` unter Windows (`src/win.rs` Z. 89) und macOS (`src/mac.rs` Z. 83). Zwei weitere Linux-Punkte: - **Kleinschreibung erledigt `directories` automatisch** (`trim_and_lowercase_then_replace_spaces` in `src/lin.rs`): aus `"DioNotes"` wird `dionotes`. Mit `dirs` allein bekäme man `~/.config/DioNotes` — unschön. Das ist das stärkste Einzelargument für `directories` statt `dirs`. - **Flatpak/Snap** brauchen keine Sonderbehandlung: `directories` liest die XDG-Variablen zur Laufzeit, eine Sandbox, die sie umbiegt, wird automatisch respektiert. (Ob die *gespeicherten absoluten Workspace-Pfade* aus einer Sandbox erreichbar sind, ist ein separates Thema.) ### Windows: `%LOCALAPPDATA%`, nicht `%APPDATA%` Die Windows-Konvention fragt nicht "Konfiguration oder Daten?", sondern "maschinenunabhängig oder maschinenspezifisch?". Microsoft wörtlich: > "Windows uses the Local and LocalLow folders for application data that does not roam with the user. Usually this data is either **machine specific** or too large to roam." > "Windows uses the Roaming folder for application specific data … which are **machine independent** and should roam with the user profile." > — <https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-vista/cc766489(v=ws.10)> Bestätigt in der aktuell gepflegten .NET-Doku: `ApplicationData` = "for the current **roaming** user", `LocalApplicationData` = "used by the current, **non-roaming** user" (<https://learn.microsoft.com/en-us/dotnet/api/system.environment.specialfolder>). Die Workspace-Liste besteht aus **absoluten Dateisystempfaden**. Ein `D:\Notizen\Privat` existiert auf einem zweiten Rechner nicht — maschinenspezifisch, also Local. Dazu der Fehlermodus von Roaming: Synchronisiert wird beim Ab-/Anmelden, bei paralleler Nutzung gewinnt die letzte Abmeldung und überschreibt die andere Sitzung. Wichtig: Diese Entscheidung ist **rein Windows-spezifisch und kostet anderswo nichts** — unter Linux und macOS ist `config_local_dir` im Quelltext ein `config_dir.clone()`, also derselbe Pfad. Nicht zu benutzen: `cache_dir()` (löschbar), `data_dir()`/`data_local_dir()` (Nutzdaten), `preference_dir()` (zeigt auf macOS nach `~/Library/Preferences`, und dorthin darf man laut Apple nicht selbst schreiben). ### Dioxus 0.7: keine eigene Abstraktion `dioxus_desktop::Config::with_data_directory` klingt richtig, ist es aber nicht. Der Wert landet in `WebContext::new(cfg.data_dir.clone())` (`packages/desktop/src/webview.rs` @ v0.7.1), und `wry::WebContext` ist das **Browser-Profil der WebView** — WebView2-Cookies, LocalStorage, Cache. Nicht die Anwendungskonfiguration. Ansonsten: nichts Passendes in der Item-Liste von `dioxus` 0.7.1, kein Treffer in zwei unabhängigen Doku-Korpora, nichts in unserer `AGENTS.md`. Und das offizielle **Dioxus-SDK** greift für seinen `use_persistent`-Storage selbst zu `directories::BaseDirs::new().unwrap().data_local_dir()` — gäbe es etwas Eingebautes, hätte es das benutzt. ### Verzeichnis anlegen: ja Die Crate legt nichts an. README wörtlich: "This library does not create directories or check for their existence. The library only provides information on what the path to a certain directory **should** be." Verifiziert: `%LOCALAPPDATA%\DioNotes` existiert auf meinem Rechner nicht. Die Basis-Ordner `%APPDATA%`/`%LOCALAPPDATA%` dagegen schon — `PERUSER`-Known-Folders, kommen mit dem Benutzerprofil. Anzulegen ist nur der App-Teil, per `std::fs::create_dir_all` (idempotent). Unter Linux erwartet die XDG-Spec dasselbe ausdrücklich: "When attempting to write a file, if the destination directory is non-existent an attempt should be made to create it with permission `0700`." --- Langfassung mit allen Quellenangaben und der Trennung belegt/Vermutung: Branch **`research/config-ablageort`**, Datei `docs/research/konfigurations-ablageort.md` (nicht gepusht).
Sign in to join this conversation.