Add initial support for the XDG Base Directory spec

Spec version 0.7 from https://standards.freedesktop.org/basedir-spec/basedir-spec-0.7.html
(latest as of this commit).

Three virtual methods are added to OS for the various XDG paths we will use:
- OS::get_data_path gives XDG_DATA_HOME, or if missing:
  ~/.local/share on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_config_path gives XDG_CONFIG_HOME, or if missing:
  ~/.config on X11, ~/Library/Application Support/ on macOS and %APPDATA% on Windows
- OS::get_cache_path gives XDG_CACHE_HOME, or if missing:
  ~/.cache on X11, ~/Library/Caches on macOS and %APPDATA% on Windows

So for Windows there are no changes, for Linux we follow the full split spec
and for macOS stuff will move from ~/.godot to ~/Library/Application Support/Godot.

Support for system-wide installation of templates on Unix was removed for now,
as it's a bit hackish and I don't think anyone uses it.

user:// will still be OS::get_data_path() + "/godot/app_userdata/$name" by
default, but when using the application/config/use_shared_user_dir option
it will now use XDG_DATA_HOME/$name, e.g. ~/.local/share/MyGame.

For now everything still goes in EditorSettings::get_settings_dir(), but
this will be changed in a later commit to make use of the new splitting
where relevant.

Part of #3513.
This commit is contained in:
Rémi Verschelde
2017-11-17 17:11:41 +01:00
parent ad199c3964
commit 32c12a92a5
17 changed files with 360 additions and 118 deletions

View File

@ -640,8 +640,13 @@ void EditorSettings::create() {
DirAccess *dir = NULL;
String data_path;
String data_dir;
String config_path;
String config_dir;
String cache_path;
String cache_dir;
Ref<ConfigFile> extra_config = memnew(ConfigFile);
String exe_path = OS::get_singleton()->get_executable_path().get_base_dir();
@ -658,28 +663,74 @@ void EditorSettings::create() {
memdelete(d);
if (self_contained) {
// editor is self contained
// editor is self contained, all in same folder
data_path = exe_path;
data_dir = data_path.plus_file("editor_data");
config_path = exe_path;
config_dir = "editor_data";
config_dir = data_dir;
cache_path = exe_path;
cache_dir = data_dir.plus_file("cache");
} else {
if (OS::get_singleton()->has_environment("APPDATA")) {
// Most likely under windows, save here
config_path = OS::get_singleton()->get_environment("APPDATA");
config_dir = String(_MKSTR(VERSION_SHORT_NAME)).capitalize();
} else if (OS::get_singleton()->has_environment("HOME")) {
config_path = OS::get_singleton()->get_environment("HOME");
config_dir = "." + String(_MKSTR(VERSION_SHORT_NAME)).to_lower();
// Typically XDG_DATA_HOME or %APPDATA%
data_path = OS::get_singleton()->get_data_path();
data_dir = data_path.plus_file(OS::get_singleton()->get_godot_dir_name());
// Can be different from data_path e.g. on Linux or macOS
config_path = OS::get_singleton()->get_config_path();
config_dir = config_path.plus_file(OS::get_singleton()->get_godot_dir_name());
// Can be different from above paths, otherwise a subfolder of data_dir
cache_path = OS::get_singleton()->get_cache_path();
if (cache_path == data_path) {
cache_dir = data_dir.plus_file("cache");
} else {
cache_dir = cache_path.plus_file(OS::get_singleton()->get_godot_dir_name());
}
};
}
ClassDB::register_class<EditorSettings>(); //otherwise it can't be unserialized
String config_file_path;
if (config_path != "") {
if (data_path != "" && config_path != "" && cache_path != "") {
// Validate/create data dir and subdirectories
dir = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (dir->change_dir(data_path) != OK) {
ERR_PRINT("Cannot find path for data directory!");
memdelete(dir);
goto fail;
}
if (dir->change_dir(data_dir) != OK) {
dir->make_dir(data_dir);
if (dir->change_dir(data_dir) != OK) {
ERR_PRINT("Cannot create data directory!");
memdelete(dir);
goto fail;
}
}
// Validate/create cache dir
if (dir->change_dir(cache_path) != OK) {
ERR_PRINT("Cannot find path for cache directory!");
memdelete(dir);
goto fail;
}
if (dir->change_dir(cache_dir) != OK) {
dir->make_dir(cache_dir);
if (dir->change_dir(cache_dir) != OK) {
ERR_PRINT("Cannot create cache directory!");
memdelete(dir);
goto fail;
}
}
// Validate/create config dir and subdirectories
if (dir->change_dir(config_path) != OK) {
ERR_PRINT("Cannot find path for config directory!");
memdelete(dir);
@ -695,10 +746,17 @@ void EditorSettings::create() {
}
}
// FIXME: Move to data dir
if (dir->change_dir("templates") != OK) {
dir->make_dir("templates");
} else {
dir->change_dir("..");
}
// FIXME: Move to cache dir
if (dir->change_dir("tmp") != OK) {
dir->make_dir("tmp");
} else {
dir->change_dir("..");
}
@ -715,42 +773,33 @@ void EditorSettings::create() {
}
_create_script_templates(dir->get_current_dir() + "/script_templates");
if (dir->change_dir("tmp") != OK) {
dir->make_dir("tmp");
} else {
dir->change_dir("..");
}
// FIXME: Rename to "projects"
if (dir->change_dir("config") != OK) {
dir->make_dir("config");
} else {
dir->change_dir("..");
}
dir->change_dir("config");
// Validate/create project-specific config dir
dir->change_dir("config");
String project_config_dir = ProjectSettings::get_singleton()->get_resource_path();
if (project_config_dir.ends_with("/"))
project_config_dir = config_path.substr(0, project_config_dir.size() - 1);
project_config_dir = project_config_dir.get_file() + "-" + project_config_dir.md5_text();
if (dir->change_dir(project_config_dir)) {
if (dir->change_dir(project_config_dir) != OK) {
dir->make_dir(project_config_dir);
} else {
dir->change_dir("..");
}
dir->change_dir("..");
// path at least is validated, so validate config file
String config_file_name = "editor_settings-" + String(_MKSTR(VERSION_MAJOR)) + ".tres";
config_file_path = config_path + "/" + config_dir + "/" + config_file_name;
// Validate editor config file
String config_file_name = "editor_settings.tres";
config_file_path = config_dir.plus_file(config_file_name);
if (!dir->file_exists(config_file_name)) {
goto fail;
}
@ -766,7 +815,9 @@ void EditorSettings::create() {
singleton->save_changed_setting = true;
singleton->config_file_path = config_file_path;
singleton->project_config_dir = project_config_dir;
singleton->settings_dir = config_path + "/" + config_dir;
singleton->settings_dir = config_dir;
singleton->data_dir = data_dir;
singleton->cache_dir = cache_dir;
if (OS::get_singleton()->is_stdout_verbose()) {
@ -796,7 +847,9 @@ fail:
singleton = Ref<EditorSettings>(memnew(EditorSettings));
singleton->save_changed_setting = true;
singleton->config_file_path = config_file_path;
singleton->settings_dir = config_path + "/" + config_dir;
singleton->settings_dir = config_dir;
singleton->data_dir = data_dir;
singleton->cache_dir = cache_dir;
singleton->_load_defaults(extra_config);
singleton->setup_language();
singleton->setup_network();
@ -966,7 +1019,19 @@ void EditorSettings::add_property_hint(const PropertyInfo &p_hint) {
hints[p_hint.name] = p_hint;
}
// Settings paths and saved metadata
// Data directories
String EditorSettings::get_data_dir() const {
return data_dir;
}
String EditorSettings::get_templates_dir() const {
return get_data_dir().plus_file("templates");
}
// Config directories
String EditorSettings::get_settings_dir() const {
@ -975,9 +1040,29 @@ String EditorSettings::get_settings_dir() const {
String EditorSettings::get_project_settings_dir() const {
// FIXME: Rename to "projects"
return get_settings_dir().plus_file("config").plus_file(project_config_dir);
}
String EditorSettings::get_text_editor_themes_dir() const {
return get_settings_dir().plus_file("text_editor_themes");
}
String EditorSettings::get_script_templates_dir() const {
return get_settings_dir().plus_file("script_templates");
}
// Cache directory
String EditorSettings::get_cache_dir() const {
return cache_dir;
}
// Metadata
void EditorSettings::set_project_metadata(const String &p_section, const String &p_key, Variant p_data) {
Ref<ConfigFile> cf = memnew(ConfigFile);
String path = get_project_settings_dir().plus_file("project_metadata.cfg");