Etcetera
repository·master·Indexed 41 days ago
https://github.com/lunacookies/etceteraAn unopinionated Rust library for determining cross-platform filesystem locations for configuration, data, and cache files. It supports XDG base directory, Apple's Standard Directories, Windows' Known Folder Locations, and the Unix Single-folder Convention, providing both BaseStrategy and AppStrategy modes to resolve paths based on application metadata and target operating systems.
What's inside Etcetera
- Etcetera is a Rust library designed to help developers determine the correct filesystem locations for application-specific files, such as configuration, data, and cache. Unlike other libraries that enforce a single standard, Etcetera allows you to choose between different directory conventions based on your application's needs (e.g., CLI vs. GUI) and the target operating system.
How BaseStrategy and AppStrategy work
masterEtcetera operates using two distinct modes of operation:
BaseStrategy
Returns the root location of a specific directory type without application-specific subdirectories.
- Example (
config_dir()):- XDG:
~/.config - Apple:
~/Library/Preferences - Windows:
~\AppData\Roaming
- XDG:
AppStrategy
Returns a path specific to your application by combining the base directory with application metadata. You must provide details like
top_level_domain,author, andapp_name.- Example (with
{ top_level_domain: "org", author: "Acme Corp", app_name: "Frobnicator Plus" }):- XDG:
~/.config/frobnicator-plus - Unix:
~/.frobnicator-plus - Apple:
~/Library/Preferences/org.acme-corp.Frobnicator-Plus - Windows:
~\AppData\Roaming\Acme Corp\Frobnicator Plus
- XDG:
Note: The home directory (
~) is determined usingstd::env::home_dir.- Example (
Supported directory conventions in Etcetera
masterEtcetera supports four primary directory conventions to ensure cross-platform compatibility:
- XDG base directory: The standard for Linux/Unix systems.
- Apple's Standard Directories: Used on macOS and iOS.
- Windows' Known Folder Locations: The standard for Windows applications.
- Unix Single-folder Convention: A pattern where all application files are stored in a single hidden directory in the home folder (e.g.,
~/.myapp).
Use convenience functions to select strategies
masterEtcetera provides helper functions to automatically select the most appropriate strategy for your application type based on the host platform:
For CLI Tools
Use these functions if you want to follow the standard for CLI tools (Windows uses Windows conventions, while all other platforms use XDG):
base_strategy::choose_base_strategyapp_strategy::choose_app_strategy
For GUI Applications
Use these functions if you want to follow native platform standards (Windows uses Windows, macOS/iOS uses Apple, and all other platforms use XDG):
base_strategy::choose_native_strategyapp_strategy::choose_native_strategy
How AppStrategy and BaseStrategy work together
masterEtcetera provides two main ways to resolve paths depending on your application type:
- BaseStrategy: Best for general-purpose tools or when you want to follow the OS's default directory structure without specific application subfolders. It uses
XDGon Linux/macOS andWindowson Windows. - AppStrategy: Best for specific applications. It uses the application's metadata (name, author, TLD) to create a unique directory structure following platform conventions.
Choosing a strategy for macOS GUI apps: While
choose_app_strategy()uses theXDGconvention on macOS (which is often preferred if users need to manually edit config files), you can usechoose_native_strategy()if you want to follow Apple's 'Standard Directories' specifically for a GUI application.- BaseStrategy: Best for general-purpose tools or when you want to follow the OS's default directory structure without specific application subfolders. It uses
Choose a strategy based on application type
masterThe library provides two helper functions to select a strategy based on whether you are building a GUI or a CLI application. This ensures your application follows the correct OS conventions.
For GUI Applications
Use
choose_native_strategy()to get the OS-specific strategy:- Windows: Uses
Windowsstrategy. - macOS & iOS: Uses
Applestrategy. - Other (Linux/Unix): Uses
Xdgstrategy.
For CLI Applications
Use
choose_base_strategy()to get the default strategy for CLI tools:- Windows: Uses
Windowsstrategy. - Other (macOS, iOS, Linux/Unix): Uses
Xdgstrategy.
use etcetera::{choose_native_strategy, choose_base_strategy}; // For a GUI app let strategy = choose_native_strategy().expect("Failed to resolve strategy"); let config = strategy.config_dir(); // For a CLI app let strategy = choose_base_strategy().expect("Failed to resolve strategy"); let data = strategy.data_dir();- Windows: Uses
Choose a strategy for GUI or CLI applications
masterDepending on whether you are building a GUI application or a CLI application, you should choose a different strategy to ensure your application follows OS-specific conventions.
For GUI Applications
Use
choose_native_strategy(args)to select the strategy most appropriate for the current operating system:- Windows: Uses the
Windowsstrategy. - macOS/iOS: Uses the
Applestrategy. - Linux/Other: Uses the
Xdgstrategy.
For CLI Applications
Use
choose_app_strategy(args)to select a more standard strategy for command-line tools:- Windows: Uses the
Windowsstrategy. - macOS/iOS/Linux/Other: Uses the
Xdgstrategy.
Both functions return a
Result<T, HomeDirError>.use etcetera::app_strategy::{AppStrategyArgs, choose_native_strategy}; let args = AppStrategyArgs { top_level_domain: "com".to_string(), author: "Example".to_string(), app_name: "MyApp".to_string(), }; // For a GUI app let strategy = choose_native_strategy(args).expect("Failed to resolve strategy"); let config = strategy.config_dir();- Windows: Uses the
Configure application identity with AppStrategyArgs
masterTo use an
AppStrategy, you must first define your application's identity usingAppStrategyArgs. This struct provides the metadata used to resolve platform-specific paths for configuration, data, and cache.Key fields:
top_level_domain: The TLD of your application (e.g.,com,org, orio.github).author: The name of the application's author.app_name: The name of the application.
AppStrategyArgsprovides two helper methods for generating identifiers:bundle_id(): Returns a reverse-DNS style string (e.g.,org.acme-corp.Frobnicator-Plus). It converts the author to lowercase and replaces spaces with hyphens, and replaces spaces in the app name with hyphens.unixy_name(): Returns a lowercase, hyphenated version of the app name, suitable for binary names (e.g.,frobnicator-plus).
use etcetera::app_strategy::AppStrategyArgs; let strategy_args = AppStrategyArgs { top_level_domain: "org".to_string(), author: "Acme Corp".to_string(), app_name: "Frobnicator Plus".to_string(), }; // bundle_id() -> "org.acme-corp.Frobnicator-Plus" // unixy_name() -> "frobnicator-plus"MSRV requirements for Etcetera
masterThe Minimum Supported Rust Version (MSRV) depends on the version of Etcetera you are using:
- v0.11.0 (Current): MSRV 1.87.0
- v0.10: MSRV 1.81.0
- v0.9: MSRV 1.70.0
Note: v0.12 raised the MSRV to 1.95.0 to utilize the
cfg_select!macro and remove thecfg-ifdependency.Use the AppStrategy trait to resolve application paths
masterThe
AppStrategytrait allows your application to retrieve standard platform-specific directories. This ensures your app follows the correct conventions for where to store configuration, data, and cache files.Core Directory Methods
home_dir(): Returns the current user's home directory.config_dir(): Returns the directory for application configuration.data_dir(): Returns the directory for application data.cache_dir(): Returns the directory for application cache.state_dir(): Returns anOption<PathBuf>for the state directory. Supported byXdgandUnixstrategies.runtime_dir(): Returns anOption<PathBuf>for the runtime directory. Supported byXdgandUnixstrategies.
Path Helper Methods
Instead of manually joining paths, use these helpers to construct paths inside specific directories:
in_config_dir(path)in_data_dir(path)in_cache_dir(path)in_state_dir(path)(ReturnsOption)in_runtime_dir(path)(ReturnsOption)
Note: For
runtime_dir, this library does not enforce the ownership or persistence requirements specified by the XDG Base Directory Specification.Use the Windows AppStrategy for path resolution
masterThe
Windowsstrategy implements path resolution following Windows conventions (based on theSHGetKnownFolderPathAPI). It organizes application files under anauthor/app_namehierarchy within standard Windows directories.Directory Mapping
When initialized with
AppStrategyArgs, the following paths are resolved:- Config Directory:
{APPDATA}/{author}/{app_name}/config - Data Directory:
{APPDATA}/{author}/{app_name}/data - Cache Directory:
{LOCALAPPDATA}/{author}/{app_name}/cache - Home Directory: Resolved via Windows system APIs (e.g.,
USERPROFILE).
Note that
state_dir()andruntime_dir()currently returnNonefor this strategy.Implementation Details
On Windows, this strategy uses the
SHGetKnownFolderPathAPI. On non-Windows platforms, it falls back to Windows default directory patterns. The strategy reads from the following environment variables:USERPROFILEAPPDATALOCALAPPDATA
use etcetera::app_strategy::{AppStrategy, AppStrategyArgs, Windows}; let app_strategy = Windows::new(AppStrategyArgs { top_level_domain: "org".to_string(), author: "Acme Corp".to_string(), app_name: "Frobnicator Plus".to_string(), }).unwrap(); let config = app_strategy.config_dir(); // e.g., AppData/Roaming/Acme Corp/Frobnicator Plus/config let cache = app_strategy.cache_dir(); // e.g., AppData/Local/Acme Corp/Frobnicator Plus/cache- Config Directory:
Use the Windows base directory strategy
masterThe
Windowsstrategy implements directory resolution following Windows conventions. It prioritizes environment variables (USERPROFILE,APPDATA,LOCALAPPDATA) and falls back to the WindowsSHGetKnownFolderPathAPI. If environment variables are missing, it uses default Windows directory paths.Key directory mappings:
home_dir(): Returns the user profile directory.config_dir(): Maps todata_dir()(typicallyAPPDATA).data_dir(): UsesAPPDATAenvironment variable or falls back toAppData/Roamingwithin the home directory.cache_dir(): UsesLOCALAPPDATAenvironment variable or falls back toAppData/Localwithin the home directory.state_dir(): Always returnsNone.runtime_dir(): Always returnsNone.
use etcetera::base_strategy::BaseStrategy; use etcetera::base_strategy::Windows; let base_strategy = Windows::new().unwrap(); let home = base_strategy.home_dir(); let config = base_strategy.config_dir(); let cache = base_strategy.cache_dir();