Skip to content

Commit

Permalink
Allow customize standard path
Browse files Browse the repository at this point in the history
  • Loading branch information
wengxt committed Apr 20, 2024
1 parent f78dff1 commit 04ef14b
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 29 deletions.
87 changes: 58 additions & 29 deletions src/lib/fcitx-utils/standardpath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ bool isAbsolutePath(const std::string &path) {
}

std::string constructPath(const std::string &basepath,
const std::string &path) {
const std::string &subpath) {
if (basepath.empty()) {
return {};
}
return fs::cleanPath(stringutils::joinPath(basepath, path));
return fs::cleanPath(stringutils::joinPath(basepath, subpath));
}

} // namespace
Expand Down Expand Up @@ -76,40 +76,49 @@ void StandardPathTempFile::close() {

class StandardPathPrivate {
public:
StandardPathPrivate(bool skipFcitxPath, bool skipUserPath)
: skipUserPath_(skipUserPath) {
StandardPathPrivate(
const std::string &packageName,
const std::unordered_map<std::string, std::string> &builtInPathMap,
bool skipBuiltInPath, bool skipUserPath)
: skipBuiltInPath_(skipBuiltInPath), skipUserPath_(skipUserPath) {
// initialize user directory
configHome_ = defaultPath("XDG_CONFIG_HOME", ".config");
pkgconfigHome_ = defaultPath(
"FCITX_CONFIG_HOME", constructPath(configHome_, "fcitx5").c_str());
configDirs_ = defaultPaths("XDG_CONFIG_DIRS", "/etc/xdg", nullptr);
pkgconfigHome_ =
defaultPath("FCITX_CONFIG_HOME",
constructPath(configHome_, packageName).c_str());
configDirs_ = defaultPaths("XDG_CONFIG_DIRS", "/etc/xdg",
builtInPathMap, nullptr);
auto pkgconfigDirFallback = configDirs_;
for (auto &path : pkgconfigDirFallback) {
path = constructPath(path, "fcitx5");
path = constructPath(path, packageName);
}
pkgconfigDirs_ = defaultPaths(
"FCITX_CONFIG_DIRS",
stringutils::join(pkgconfigDirFallback, ":").c_str(), nullptr);
pkgconfigDirs_ =
defaultPaths("FCITX_CONFIG_DIRS",
stringutils::join(pkgconfigDirFallback, ":").c_str(),
builtInPathMap, nullptr);

dataHome_ = defaultPath("XDG_DATA_HOME", ".local/share");
pkgdataHome_ = defaultPath("FCITX_DATA_HOME",
constructPath(dataHome_, "fcitx5").c_str());
pkgdataHome_ = defaultPath(
"FCITX_DATA_HOME", constructPath(dataHome_, packageName).c_str());
dataDirs_ = defaultPaths("XDG_DATA_DIRS", "/usr/local/share:/usr/share",
skipFcitxPath ? nullptr : "datadir");
builtInPathMap,
skipBuiltInPath_ ? nullptr : "datadir");
auto pkgdataDirFallback = dataDirs_;
for (auto &path : pkgdataDirFallback) {
path = constructPath(path, "fcitx5");
path = constructPath(path, packageName);
}
pkgdataDirs_ =
defaultPaths("FCITX_DATA_DIRS",
stringutils::join(pkgdataDirFallback, ":").c_str(),
skipFcitxPath ? nullptr : "pkgdatadir");
pkgdataDirs_ = defaultPaths(
"FCITX_DATA_DIRS",
stringutils::join(pkgdataDirFallback, ":").c_str(), builtInPathMap,
skipBuiltInPath_ ? nullptr : "pkgdatadir");
cacheHome_ = defaultPath("XDG_CACHE_HOME", ".cache");
const char *tmpdir = getenv("TMPDIR");
runtimeDir_ = defaultPath("XDG_RUNTIME_DIR",
!tmpdir || !tmpdir[0] ? "/tmp" : tmpdir);
addonDirs_ =
defaultPaths("FCITX_ADDON_DIRS", FCITX_INSTALL_ADDONDIR, nullptr);
// Though theoratically, this is also fcitxPath, we just simply don't
// use it here.
addonDirs_ = defaultPaths("FCITX_ADDON_DIRS", FCITX_INSTALL_ADDONDIR,
builtInPathMap, nullptr);

syncUmask();
}
Expand Down Expand Up @@ -154,6 +163,7 @@ class StandardPathPrivate {
}

bool skipUser() const { return skipUserPath_; }
bool skipBuiltIn() const { return skipBuiltInPath_; }

void syncUmask() {
// read umask, use 022 which is likely the default value, so less likely
Expand Down Expand Up @@ -207,9 +217,10 @@ class StandardPathPrivate {
return dir;
}

static std::vector<std::string> defaultPaths(const char *env,
const char *defaultPath,
const char *fcitxPath) {
static std::vector<std::string> defaultPaths(
const char *env, const char *defaultPath,
const std::unordered_map<std::string, std::string> &builtInPathMap,
const char *builtInPathType) {
std::vector<std::string> dirs;

const char *dir = getenv(env);
Expand All @@ -231,9 +242,15 @@ class StandardPathPrivate {
dirs.push_back(s);
}
}
if (fcitxPath) {
std::string path =
fs::cleanPath(StandardPath::fcitxPath(fcitxPath));
if (builtInPathType) {
std::string builtInPath;
if (const auto *value =
findValue(builtInPathMap, builtInPathType)) {
builtInPath = *value;
} else {
builtInPath = StandardPath::fcitxPath(builtInPathType);
}
std::string path = fs::cleanPath(builtInPath);
if (!path.empty() &&
std::find(dirs.begin(), dirs.end(), path) == dirs.end()) {
dirs.push_back(path);
Expand All @@ -243,6 +260,7 @@ class StandardPathPrivate {
return dirs;
}

bool skipBuiltInPath_;
bool skipUserPath_;
std::string configHome_;
std::vector<std::string> configDirs_;
Expand All @@ -258,9 +276,15 @@ class StandardPathPrivate {
std::atomic<mode_t> umask_;
};

StandardPath::StandardPath(
const std::string &packageName,
const std::unordered_map<std::string, std::string> &builtInPath,
bool skipBuiltInPath, bool skipUserPath)
: d_ptr(std::make_unique<StandardPathPrivate>(
packageName, builtInPath, skipBuiltInPath, skipUserPath)) {}

StandardPath::StandardPath(bool skipFcitxPath, bool skipUserPath)
: d_ptr(
std::make_unique<StandardPathPrivate>(skipFcitxPath, skipUserPath)) {}
: StandardPath("fcitx5", {}, skipFcitxPath, skipUserPath) {}

StandardPath::StandardPath(bool skipFcitxPath)
: StandardPath(skipFcitxPath, false) {}
Expand Down Expand Up @@ -696,4 +720,9 @@ bool StandardPath::hasExecutable(const std::string &name) {

void StandardPath::syncUmask() const { d_ptr->syncUmask(); }

bool StandardPath::skipBuiltInPath() const {
FCITX_D();
return d->skipBuiltIn();
}

} // namespace fcitx
25 changes: 25 additions & 0 deletions src/lib/fcitx-utils/standardpath.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,20 @@ class FCITXUTILS_EXPORT StandardPath {
PkgData
};

/**
* Allow to construct a StandardPath with customized internal value.
*
* @param packageName the sub directory under other paths.
* @param builtInPath this will override the value from fcitxPath.
* @param skipBuiltInPath skip built-in path
* @param skipUserPath skip user path, useful when doing readonly-test.
* @since 5.1.8
*/
StandardPath(
const std::string &packageName,
const std::unordered_map<std::string, std::string> &builtInPath,
bool skipBuiltInPath, bool skipUserPath);

StandardPath(bool skipFcitxPath, bool skipUserPath);
StandardPath(bool skipFcitxPath = false);
virtual ~StandardPath();
Expand Down Expand Up @@ -349,6 +363,17 @@ class FCITXUTILS_EXPORT StandardPath {
*/
void syncUmask() const;

/**
* Whether this StandardPath is configured to Skip built-in path.
*
* Built-in path is usually configured at build time, hardcoded.
* In portable environment (Install prefix is not fixed), this should be
* set to false.
*
* @since 5.1.8
*/
bool skipBuiltInPath() const;

private:
std::unique_ptr<StandardPathPrivate> d_ptr;
FCITX_DECLARE_PRIVATE(StandardPath);
Expand Down
14 changes: 14 additions & 0 deletions test/teststandardpath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,22 @@ void test_nouser() {
FCITX_ASSERT(file2.fd() == -1);
}

void test_custom() {
FCITX_ASSERT(setenv("XDG_CONFIG_HOME", "/TEST/PATH", 1) == 0);
FCITX_ASSERT(setenv("XDG_CONFIG_DIRS", "/TEST/PATH1:/TEST/PATH2", 1) == 0);
FCITX_ASSERT(setenv("XDG_DATA_DIRS", TEST_ADDON_DIR, 1) == 0);
StandardPath path("mypackage", {{"datadir", "/TEST/PATH3"}}, false, false);
FCITX_ASSERT(path.directories(fcitx::StandardPath::Type::PkgConfig) ==
std::vector<std::string>{"/TEST/PATH1/mypackage",
"/TEST/PATH2/mypackage"});
FCITX_ASSERT(path.directories(fcitx::StandardPath::Type::Data) ==
std::vector<std::string>{TEST_ADDON_DIR, "/TEST/PATH3"})
<< path.directories(fcitx::StandardPath::Type::Data);
}

int main() {
test_basic();
test_nouser();
test_custom();
return 0;
}

0 comments on commit 04ef14b

Please sign in to comment.