Skip to content

Commit 13d8235

Browse files
committed
Merge branch 'more-XDG' of github.com:tmzullinger/MPD
2 parents 7d81cd4 + 4208825 commit 13d8235

7 files changed

Lines changed: 155 additions & 1 deletion

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ ver 0.25 (not yet released)
1212
* player
1313
- support replay gain parameter in stream URI
1414
- preallocate physical RAM for audio buffer when playback starts
15+
* configuration
16+
- support $XDG_DATA_HOME, $XDG_STATE_HOME
1517
* switch to C++23
1618
* require Meson 1.2
1719

doc/mpd.conf.5.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ supported:
3333
- ``$XDG_CONFIG_HOME``
3434
- ``$XDG_MUSIC_DIR``
3535
- ``$XDG_CACHE_HOME``
36+
- ``$XDG_DATA_HOME``
3637
- ``$XDG_RUNTIME_DIR``
38+
- ``$XDG_STATE_HOME``
3739

3840
Example:
3941

doc/mpdconf.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
# it was brought down. This setting is disabled by default and the server
5656
# state will be reset on server start up.
5757
#
58-
#state_file "$XDG_RUNTIME_DIR/mpd/state"
58+
#state_file "$XDG_STATE_HOME/mpd/state"
5959
#state_file "~/.mpd/state"
6060
#
6161
# The location of the sticker database. This is a database which

src/config/Path.cxx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,14 @@ GetVariable(std::string_view name)
8181
return GetUserConfigDir();
8282
else if (name == "XDG_MUSIC_DIR"sv)
8383
return GetUserMusicDir();
84+
else if (name == "XDG_DATA_HOME"sv)
85+
return GetUserDataDir();
8486
else if (name == "XDG_CACHE_HOME"sv)
8587
return GetUserCacheDir();
8688
else if (name == "XDG_RUNTIME_DIR"sv)
8789
return GetUserRuntimeDir();
90+
else if (name == "XDG_STATE_HOME"sv)
91+
return GetUserStateDir();
8892
else
8993
throw FmtRuntimeError("Unknown variable: {:?}", name);
9094
}

src/fs/glue/StandardDirectory.cxx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,39 @@ GetAppCacheDir() noexcept
345345
#endif
346346
}
347347

348+
AllocatedPath
349+
GetUserDataDir() noexcept
350+
{
351+
#ifdef USE_XDG
352+
// Check for $XDG_DATA_HOME
353+
if (const auto path = GetExistingEnvDirectory("XDG_DATA_HOME");
354+
path != nullptr)
355+
return AllocatedPath{path};
356+
357+
// Check for $HOME/.local/share
358+
if (const auto home = GetHomeDir(); !home.IsNull())
359+
if (auto fallback = home / Path::FromFS(".local/share");
360+
IsValidDir(fallback))
361+
return fallback;
362+
363+
#endif
364+
return nullptr;
365+
}
366+
367+
AllocatedPath
368+
GetAppDataDir() noexcept
369+
{
370+
#if defined(USE_XDG)
371+
if (const auto user_dir = GetUserDataDir(); !user_dir.IsNull()) {
372+
auto dir = user_dir / app_filename;
373+
CreateDirectoryNoThrow(dir);
374+
return dir;
375+
}
376+
377+
#endif
378+
return nullptr;
379+
}
380+
348381
AllocatedPath
349382
GetUserRuntimeDir() noexcept
350383
{
@@ -386,6 +419,47 @@ GetAppRuntimeDir() noexcept
386419
return nullptr;
387420
}
388421

422+
AllocatedPath
423+
GetUserStateDir() noexcept
424+
{
425+
#ifdef USE_XDG
426+
// Check for $XDG_STATE_HOME
427+
if (const auto path = GetExistingEnvDirectory("XDG_STATE_HOME");
428+
path != nullptr)
429+
return AllocatedPath{path};
430+
431+
// Check for $HOME/.local/state
432+
if (const auto home = GetHomeDir(); !home.IsNull())
433+
if (auto fallback = home / Path::FromFS(".local/state");
434+
IsValidDir(fallback))
435+
return fallback;
436+
#endif
437+
438+
return nullptr;
439+
}
440+
441+
AllocatedPath
442+
GetAppStateDir() noexcept
443+
{
444+
#if defined(__linux__) && !defined(ANDROID)
445+
/* systemd specific; see systemd.exec(5) */
446+
if (const char *state_directory = getenv("STATE_DIRECTORY"))
447+
if (auto dir = Split(std::string_view{state_directory}, ':').first;
448+
!dir.empty())
449+
return AllocatedPath::FromFS(dir);
450+
#endif
451+
452+
#if defined(USE_XDG)
453+
if (const auto user_dir = GetUserStateDir(); !user_dir.IsNull()) {
454+
auto dir = user_dir / app_filename;
455+
CreateDirectoryNoThrow(dir);
456+
return dir;
457+
}
458+
#endif
459+
460+
return nullptr;
461+
}
462+
389463
#ifdef _WIN32
390464

391465
AllocatedPath

src/fs/glue/StandardDirectory.hxx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,20 @@ GetUserMusicDir() noexcept;
2626
AllocatedPath
2727
GetUserCacheDir() noexcept;
2828

29+
/**
30+
* Obtains data directory for this application.
31+
*/
32+
[[gnu::const]]
33+
AllocatedPath
34+
GetAppDataDir() noexcept;
35+
36+
/**
37+
* Obtains data directory for the current user.
38+
*/
39+
[[gnu::const]]
40+
AllocatedPath
41+
GetUserDataDir() noexcept;
42+
2943
/**
3044
* Obtains cache directory for this application.
3145
*/
@@ -47,6 +61,20 @@ GetUserRuntimeDir() noexcept;
4761
AllocatedPath
4862
GetAppRuntimeDir() noexcept;
4963

64+
/**
65+
* Obtains the state directory for the current user.
66+
*/
67+
[[gnu::const]]
68+
AllocatedPath
69+
GetUserStateDir() noexcept;
70+
71+
/**
72+
* Obtains the state directory for this application.
73+
*/
74+
[[gnu::const]]
75+
AllocatedPath
76+
GetAppStateDir() noexcept;
77+
5078
#ifdef _WIN32
5179

5280
/**

test/fs/TestParsePath.cxx

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,26 @@ GetAppCacheDir() noexcept
6868
#endif
6969
}
7070

71+
AllocatedPath
72+
GetUserDataDir() noexcept
73+
{
74+
#ifdef _WIN32
75+
return nullptr;
76+
#else
77+
return AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.local/share"));
78+
#endif
79+
}
80+
81+
AllocatedPath
82+
GetAppDataDir() noexcept
83+
{
84+
#ifdef _WIN32
85+
return nullptr;
86+
#else
87+
return GetUserDataDir() / AllocatedPath::FromFS(PATH_LITERAL("mpd"));
88+
#endif
89+
}
90+
7191
AllocatedPath
7292
GetUserRuntimeDir() noexcept
7393
{
@@ -88,6 +108,26 @@ GetAppRuntimeDir() noexcept
88108
#endif
89109
}
90110

111+
AllocatedPath
112+
GetUserStateDir() noexcept
113+
{
114+
#ifdef _WIN32
115+
return nullptr;
116+
#else
117+
return AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.local/state"));
118+
#endif
119+
}
120+
121+
AllocatedPath
122+
GetAppStateDir() noexcept
123+
{
124+
#ifdef _WIN32
125+
return nullptr;
126+
#else
127+
return GetUserStateDir() / AllocatedPath::FromFS(PATH_LITERAL("mpd"));
128+
#endif
129+
}
130+
91131
const char *
92132
ConfigData::GetString([[maybe_unused]] ConfigOption option,
93133
const char *default_value) const noexcept
@@ -136,7 +176,11 @@ TEST(ParsePath, XDG)
136176
EXPECT_EQ(ParsePath("$XDG_CONFIG_HOME/abc"), AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.config/abc")));
137177
EXPECT_EQ(ParsePath("$XDG_MUSIC_DIR"), AllocatedPath::FromFS(PATH_LITERAL("/home/foo/Music")));
138178
EXPECT_EQ(ParsePath("$XDG_CACHE_HOME"), AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.cache")));
179+
EXPECT_EQ(ParsePath("$XDG_DATA_HOME"), AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.local/share")));
180+
EXPECT_EQ(ParsePath("$XDG_DATA_HOME/mpd"), AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.local/share/mpd")));
139181
EXPECT_EQ(ParsePath("$XDG_RUNTIME_DIR/mpd"), AllocatedPath::FromFS(PATH_LITERAL("/run/user/foo/mpd")));
182+
EXPECT_EQ(ParsePath("$XDG_STATE_HOME"), AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.local/state")));
183+
EXPECT_EQ(ParsePath("$XDG_STATE_HOME/mpd"), AllocatedPath::FromFS(PATH_LITERAL("/home/foo/.local/state/mpd")));
140184
}
141185

142186
#endif

0 commit comments

Comments
 (0)