Skip to content

Commit 7935ac8

Browse files
authored
Merge pull request #5823 from ab9rf/config-path-api
make `getConfigPath` a public `Core` API
2 parents 2efa5d6 + 7c64a1b commit 7935ac8

22 files changed

Lines changed: 100 additions & 66 deletions

docs/changelog.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,10 @@ Template for new versions:
8686
## Documentation
8787

8888
## API
89+
- Core: added ``getConfigPath()`` API for obtaining the path to user-specific configuration files
8990

9091
## Lua
92+
- Added ``dfhack.getConfigPath()`` API, proxying ``Core::getConfigPath``
9193

9294
## Removed
9395

docs/dev/Lua API.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,17 @@ can be omitted.
938938

939939
* ``dfhack.getHackPath()``
940940

941-
Returns the dfhack directory path, i.e., ``".../df/hack/"``.
941+
Returns the DFHack installation directory path (the folder where DFHack is installed).
942+
This may be the ``hack`` folder within the DF installation, but you should not rely on this.
943+
Specifically, the installation folder is extremely likely to be somewhere else when DFHack is installed from Steam.
944+
Always use this function to get the DFHack installation directory path instead of hardcoding it.
945+
946+
* ``dfhack.getConfigPath()``
947+
948+
Returns the DFHack config directory path (the folder where user-specific configuration files are stored).
949+
This is currently the ``dfhack-config`` folder within the DF installation, but you should not rely on this as it is likely to change in the future.
950+
Always use this function to get the DFHack config directory path instead of hardcoding it.
951+
Avoid storing this value in a long-lived variable, as it's possible that in future versions of DFHack, it may be possible for the config directory to be changed at runtime.
942952

943953
* ``dfhack.getSavePath()``
944954

library/Core.cpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,6 @@ namespace DFHack {
135135
DBG_DECLARE(core, keybinding, DebugCategory::LINFO);
136136
DBG_DECLARE(core, script, DebugCategory::LINFO);
137137

138-
static const std::filesystem::path getConfigPath()
139-
{
140-
return Filesystem::getInstallDir() / "dfhack-config";
141-
};
142-
143-
static const std::filesystem::path getConfigDefaultsPath()
144-
{
145-
return Core::getInstance().getHackPath() / "data" / "dfhack-config-defaults";
146-
};
147-
148138
class MainThread {
149139
public:
150140
//! MainThread::suspend keeps the main DF thread suspended from Core::Init to
@@ -538,7 +528,7 @@ std::filesystem::path Core::findScript(std::string name)
538528
return {};
539529
}
540530

541-
bool loadScriptPaths(color_ostream &out, bool silent = false)
531+
bool Core::loadScriptPaths(color_ostream &out, bool silent)
542532
{
543533
std::filesystem::path filename{ getConfigPath() / "script-paths.txt" };
544534
std::ifstream file(filename);
@@ -563,7 +553,7 @@ bool loadScriptPaths(color_ostream &out, bool silent = false)
563553
getline(ss, path);
564554
if (ch == '+' || ch == '-')
565555
{
566-
if (!Core::getInstance().addScriptPath(path, ch == '+') && !silent)
556+
if (!addScriptPath(path, ch == '+') && !silent)
567557
out.printerr("{}:{}: Failed to add path: {}\n", filename, line, path);
568558
}
569559
else if (!silent)
@@ -935,12 +925,11 @@ static void run_dfhack_init(color_ostream &out, Core *core)
935925
}
936926

937927
// load baseline defaults
938-
core->loadScriptFile(out, getConfigPath() / "init" / "default.dfhack.init", false);
928+
core->loadScriptFile(out, core->getConfigPath() / "init" / "default.dfhack.init", false);
939929

940930
// load user overrides
941931
std::vector<std::string> prefixes(1, "dfhack");
942-
loadScriptFiles(core, out, prefixes, getConfigPath() / "init");
943-
932+
loadScriptFiles(core, out, prefixes, core->getConfigPath() / "init");
944933
// show the terminal if requested
945934
auto L = DFHack::Core::getInstance().getLuaState();
946935
Lua::CallLuaModuleFunction(out, L, "dfhack", "getHideConsoleOnStartup", 0, 1,
@@ -962,9 +951,9 @@ static void fInitthread(IODATA * iod)
962951
// A thread function... for the interactive console.
963952
static void fIOthread(IODATA * iod)
964953
{
965-
static const std::filesystem::path HISTORY_FILE = getConfigPath() / "dfhack.history";
966-
967954
Core * core = iod->core;
955+
std::filesystem::path HISTORY_FILE = core->getConfigPath() / "dfhack.history";
956+
968957
PluginManager * plug_mgr = iod->plug_mgr;
969958

970959
CommandHistory main_history;

library/LuaApi.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,6 +1359,7 @@ static uint32_t getTickCount() { return Core::getInstance().p->getTickCount(); }
13591359

13601360
static std::filesystem::path getDFPath() { return Core::getInstance().p->getPath(); }
13611361
static std::filesystem::path getHackPath() { return Core::getInstance().getHackPath(); }
1362+
static std::filesystem::path getConfigPath() { return Core::getInstance().getConfigPath(); }
13621363

13631364
static bool isWorldLoaded() { return Core::getInstance().isWorldLoaded(); }
13641365
static bool isMapLoaded() { return Core::getInstance().isMapLoaded(); }
@@ -1384,6 +1385,7 @@ static const LuaWrapper::FunctionReg dfhack_module[] = {
13841385
WRAP(getDFPath),
13851386
WRAP(getTickCount),
13861387
WRAP(getHackPath),
1388+
WRAP(getConfigPath),
13871389
WRAP(isWorldLoaded),
13881390
WRAP(isMapLoaded),
13891391
WRAP(isSiteLoaded),

library/LuaTools.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,29 +1281,30 @@ bool DFHack::Lua::RunCoreQueryLoop(color_ostream &out, lua_State *state, DFHack:
12811281
return (rv == LUA_OK);
12821282
}
12831283

1284-
static bool init_interpreter(color_ostream &out, lua_State *state, const char* prompt, const char* hfile)
1284+
static bool init_interpreter(color_ostream &out, lua_State *state, std::string_view prompt, const std::filesystem::path& hfile)
12851285
{
12861286
lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN);
12871287
lua_getfield(state, -1, "interpreter");
12881288
lua_remove(state, -2);
1289-
lua_pushstring(state, prompt);
1290-
lua_pushstring(state, hfile);
1289+
lua_pushlstring(state, prompt.data(), prompt.size());
1290+
lua_pushlstring(state, hfile.string().data(), hfile.string().size());
12911291
return true;
12921292
}
12931293

12941294
bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
1295-
const char *prompt, const char *hfile)
1295+
std::string_view prompt, std::filesystem::path hfile)
12961296
{
12971297
if (!out.is_console())
12981298
return false;
12991299

1300-
if (!hfile)
1301-
hfile = "dfhack-config/lua.history";
1302-
if (!prompt)
1300+
if (hfile.empty())
1301+
hfile = DFHack::Core::getInstance().getConfigPath() / "lua.history";
1302+
if (prompt.empty())
13031303
prompt = "lua";
13041304

1305-
using namespace std::placeholders;
1306-
auto init_fn = std::bind(init_interpreter, _1, _2, prompt, hfile);
1305+
auto init_fn = [&](color_ostream& out, lua_State* state) {
1306+
return init_interpreter(out, state, prompt, hfile);
1307+
};
13071308

13081309
return RunCoreQueryLoop(out, state, init_fn);
13091310
}

library/include/Core.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ distribution.
2929
#include "Export.h"
3030
#include "Hooks.h"
3131

32+
#include "modules/Filesystem.h"
33+
3234
#include <algorithm>
3335
#include <atomic>
3436
#include <chrono>
@@ -189,6 +191,8 @@ namespace DFHack
189191
std::map<std::string, std::vector<std::string>> ListAliases();
190192
std::string GetAliasCommand(const std::string &name, bool ignore_params = false);
191193

194+
// note that this isn't valid until after DFHack is initialized by DF calling `dfhooks_init`
195+
// that means that it's invalid during at-init static initialization
192196
std::filesystem::path getHackPath();
193197

194198
bool isWorldLoaded() { return (last_world_data_ptr != nullptr); }
@@ -251,6 +255,18 @@ namespace DFHack
251255
return false;
252256
}
253257

258+
// Note that this path should be treated as potentially changeable over the life of a Core instance
259+
// Consumers should not cache this path in long-lived local variables
260+
const std::filesystem::path getConfigPath()
261+
{
262+
return Filesystem::getInstallDir() / "dfhack-config";
263+
}
264+
265+
const std::filesystem::path getConfigDefaultsPath()
266+
{
267+
return getHackPath() / "data" / "dfhack-config-defaults";
268+
}
269+
254270
private:
255271
DFHack::Console con;
256272

@@ -275,6 +291,8 @@ namespace DFHack
275291
void onStateChange(color_ostream &out, state_change_event event);
276292
void handleLoadAndUnloadScripts(color_ostream &out, state_change_event event);
277293

294+
bool loadScriptPaths(color_ostream& out, bool silent = false);
295+
278296
Core(Core const&) = delete;
279297
void operator=(Core const&) = delete;
280298

library/include/LuaTools.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,16 @@ distribution.
2424

2525
#pragma once
2626

27+
#include <concepts>
2728
#include <functional>
28-
#include <string>
29-
#include <vector>
30-
#include <set>
3129
#include <map>
30+
#include <set>
31+
#include <string>
32+
#include <string_view>
3233
#include <type_traits>
3334
#include <unordered_map>
3435
#include <unordered_set>
35-
#include <concepts>
36+
#include <vector>
3637

3738
#include "Core.h"
3839
#include "ColorText.h"
@@ -287,7 +288,7 @@ namespace DFHack::Lua {
287288
* Uses RunCoreQueryLoop internally.
288289
*/
289290
DFHACK_EXPORT bool InterpreterLoop(color_ostream &out, lua_State *state,
290-
const char *prompt = NULL, const char *hfile = NULL);
291+
std::string_view prompt = {}, std::filesystem::path hfile = {});
291292

292293
/**
293294
* Run an interactive prompt loop. All access to the lua state

library/lua/script-manager.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ function getModSourcePath(mod_id)
246246
end
247247

248248
function getModStatePath(mod_id)
249-
local path = ('dfhack-config/mods/%s/'):format(mod_id)
249+
local path = (dfhack.getConfigPath() + ('/mods/%s/')):format(mod_id)
250250
if not dfhack.filesystem.mkdir_recursive(path) then
251251
error(('failed to create mod state directory: "%s"'):format(path))
252252
end

plugins/blueprint.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*/
77

88
#include "Console.h"
9+
#include "Core.h"
910
#include "DataDefs.h"
1011
#include "DataFuncs.h"
1112
#include "DataIdentity.h"
@@ -59,8 +60,6 @@ using namespace DFHack;
5960
DFHACK_PLUGIN("blueprint");
6061
REQUIRE_GLOBAL(world);
6162

62-
static const string BLUEPRINT_USER_DIR = "dfhack-config/blueprints/";
63-
6463
namespace DFHack {
6564
DBG_DECLARE(blueprint,log);
6665
}
@@ -1370,9 +1369,9 @@ static const char * get_tile_zone(color_ostream &out, const df::coord &pos, cons
13701369

13711370
static bool create_output_dir(color_ostream &out,
13721371
const blueprint_options &opts) {
1373-
string basename = BLUEPRINT_USER_DIR + opts.name;
1374-
size_t last_slash = basename.find_last_of("/");
1375-
string parent_path = basename.substr(0, last_slash);
1372+
std::filesystem::path BLUEPRINT_USER_DIR = Core::getInstance().getConfigPath() / "blueprints";
1373+
std::filesystem::path basename = BLUEPRINT_USER_DIR / opts.name;
1374+
std::filesystem::path parent_path = basename.parent_path();
13761375

13771376
// create output directory if it doesn't already exist
13781377
if (!Filesystem::mkdir_recursive(parent_path)) {

plugins/debug.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ redistribute it freely, subject to the following restrictions:
2121
distribution.
2222
*/
2323

24+
#include "Core.h"
2425
#include "PluginManager.h"
2526
#include "DebugManager.h"
2627
#include "Debug.h"
@@ -352,7 +353,9 @@ struct FilterManager : public std::map<size_t, Filter>
352353
//! Current configuration version implemented by the code
353354
constexpr static Json::UInt configVersion{1};
354355
//! Path to the configuration file
355-
constexpr static const char* configPath{"dfhack-config/runtime-debug.json"};
356+
const inline std::filesystem::path getConfigPath() const {
357+
return DFHack::Core::getInstance().getConfigPath() / "runtime-debug.json";
358+
}
356359

357360
//! Get reference to the singleton
358361
static FilterManager& getInstance() noexcept
@@ -434,15 +437,14 @@ struct FilterManager : public std::map<size_t, Filter>
434437
DebugManager::categorySignal_t::Connection connection_;
435438
};
436439

437-
constexpr const char* FilterManager::configPath;
438-
439440
FilterManager::~FilterManager()
440441
{
441442
}
442443

443444
command_result FilterManager::loadConfig(DFHack::color_ostream& out) noexcept
444445
{
445446
nextId_ = 1;
447+
auto configPath = getConfigPath();
446448
if (!Filesystem::isfile(configPath))
447449
return CR_OK;
448450
try {
@@ -463,6 +465,7 @@ command_result FilterManager::loadConfig(DFHack::color_ostream& out) noexcept
463465

464466
command_result FilterManager::saveConfig(DFHack::color_ostream& out) const noexcept
465467
{
468+
auto configPath = getConfigPath();
466469
try {
467470
DEBUG(command, out) << "Save config to '" << configPath << "'" << std::endl;
468471
JsonArchive archive;

0 commit comments

Comments
 (0)