Apologies for reopening this discussion. I’ve read Folder Distinctions for Development but it didn’t fully enlighten me. I’m looking for a somewhat correct way to map XDG base directories onto Haiku for this little app I’m working on. Far as I can tell, app data should go somewhere under $HOME/config, but where exactly?
the Python interpreter saves its history file under $HOME/config/var, which seems to be the correct place for state data
Midnight Commander saves its config and history under $HOME/config/non-packaged/data (despite being packaged, go figure)
What would be an acceptable place for my own Python script to save its data without having to ask the Haiku API?
Edit: never mind, I see that nowadays Haiku correctly sets $XDG_DATA_HOME and company. I’ll just look at that first, then fall back on OS defaults.
The recommended way to find the correct directory is using the FindDirectory API:
The documentation also explains which directory should be used for which things.
The data directory is primarily meant for read-only data that comes packaged with an app and doesn’t change. ~/config is a read-only directory managed by packagefs,you can’t directly create new folders there and ~/config/data only exists if you have a application installed that puts something there.
Of course it’s wrong that Midnight Commander uses ~/config/non-packaged/data,that technically works because non-packaged is a writable path,but that path is meant for app data of non-packaged applications.
Settings and user data is usually stored at ~/config/settings which is the B_USER_SETTINGS_DIRECTORY.
Almost all applications put their settings and data there,also Midnight Commander,don’t know why it stores stuff both in ~/config/settings (where is should be) and ~/config/non-packaged/data (where it shouldn’t).
Only some are set, and those that are are “just” set by finddir aswell in the startup stuff, finddir is the definitive truth and more granular than the xdg spec
I get it, but this is for a portable Python script that only needs to be mostly correct. At least more so than the average Linux app (see below). Here’s the code I arrived at:
def config_home() -> str:
"""Get storage dir for user config files as per the XDG spec."""
if os.getenv("XDG_CONFIG_HOME"):
return os.getenv("XDG_CONFIG_HOME")
elif sys.platform.startswith("haiku"):
return os.path.join(os.getenv("HOME"), "config", "settings")
else:
return os.path.join(os.getenv("HOME"), ".config")
What confused me at first: on Linux, the ~/.local/ hierarchy corresponds to /usr/local (hence why it has bin/ and share/ subdirectories). Both are for permanent data like help text and licenses, not transitory stuff like a scratchpad file or whatever. But a lot of developers see they can write to ~/.local/share/ and misuse it. Then their apps get ported to Haiku.
Now on Haiku, the equivalent locations are ~/config/non-packaged/ and /system/non-packaged, respectively; $XDG_DATA_DIR correctly points to the former, and should be used the same way as on Linux.
Thanks again for everyone’s patience. Here’s to more apps that follow OS conventions correctly.
If you have a path for Haiku please just use finddir, it will give you the correct location. Stuff with hardcoded $HOME is definetely wrong. The whole point of this system is that these locations can change
Edit: To be clear, finddir is a commanline app you can call, passing it the same constants you would the C/C++ classes. This seems badly documented sadly
finddir B_USER_SETTINGS_DIRECTORY (that’s the equivelant(?) of ~/config/settings, not sure how to pass this to python though, maybe @BiPolar has an idea there?
EDIT: plenty of examples on how this is used can be found at haikuports
Also, finddir -l will give you a full list of variables.
With subprocess.run() it’s easy enough. My script already makes heavy use of external programs:
def config_home() -> str:
"""Get storage dir for user config files as per the XDG spec."""
if os.getenv("XDG_CONFIG_HOME"):
return str(os.getenv("XDG_CONFIG_HOME"))
elif sys.platform.startswith("haiku"):
result = subprocess.run(
["finddir", "B_USER_SETTINGS_DIRECTORY"],
capture_output=True)
return result.stdout.decode()
else:
return os.path.join(str(os.getenv("HOME")), ".config")
And thanks for the finddir tip! That will come in handy when writing more Haiku-oriented code.