概要
最近は、いろんなアプリが XDG Base Directory の仕様に則った動きをするようになってますね。
XDGってなんぞや?って方もいらっしゃると思いますが、
specifications.freedesktop.org
簡単にいうと、デスクトップ環境で使う標準的なディレクトリ構造を規定している仕様です。
アプリケーションのデータファイルはここに置くべきとか、設定ファイルはここに置くべきとかが決まっています。
基本的には、環境変数で設定しておくものらしいんですが、設定していない場合のデフォルト値が決まっているので
ほとんどの人は設定しないんじゃないですかね。
例えば、Linux系のOSの場合は、$XDG_CONFIG_HOME
の値が ~/.config
になります。このディレクトリ、いつの間にか出来てて、なにこれ?ってなる人多いんじゃないでしょうか。
で、Goからこれらの値を利用してみたいってときに、以下の便利なライブラリがありました。
こういうライブラリ、すごく助かります。
てことで、ちょっと試してみました。
サンプル
XDG Base Directory のサンプル
package xdgspec import ( "github.com/adrg/xdg" "github.com/devlights/try-golang/lib/output" "runtime" ) // XdgBaseDirectory は、XDG Base Directory についてのサンプルです. // [xdg](https://github.com/adrg/xdg) を利用して各値を取得しています. // // REFEFENCES:: // - https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html // - https://kledgeb.blogspot.com/2013/04/ubuntu-10-xdg-base-directory.html func XdgBaseDirectory() error { // ------------------------------------------------------------ // XDG Base Directory について // XDG の各値は、xdg パッケージを利用すると簡単に利用できる // このパッケージは、Windows/MacOS/Unix に対応している // // xdg パッケージは、対象となる環境変数が設定されていれば、その値を返し // 設定されていない場合は、デフォルトの値を返すようになっている。 // ------------------------------------------------------------ output.Stdoutl("[OS]", runtime.GOOS) // XDG_DATA_HOME // ユーザ個別のデータファイルが書き込まれる場所 (ユーザディレクトリ) output.Stdoutl("XDG_DATA_HOME", xdg.DataHome) // XDG_CONFIG_HOME // ユーザ個別の設定が書き込まれる場所 (ユーザディレクトリ) output.Stdoutl("XDG_CONFIG_HOME", xdg.ConfigHome) // XDG_CACHE_HOME // ユーザ毎のキャッシュデータの置き場 (ユーザディレクトリ) output.Stdoutl("XDG_CACHE_HOME", xdg.CacheHome) // XDG_RUNTIME_DIR // ユーザ毎の実行時ファイルやその他のファイルを置くべき場所 (ユーザディレクトリ) output.Stdoutl("XDG_RUNTIME_DIR", xdg.RuntimeDir) // XDG_DATA_DIRS // データファイルを検索する際のサーチパス (システムディレクトリ) // // (補足) アプリのデータを検索する場合は $XDG_DATA_HOME:$XDG_DATA_DIRS の順で行い // ユーザ毎のデータを優先させる output.Stdoutl("XDG_DATA_DIRS", xdg.DataDirs) // XDG_CONFIG_DIRS // 設定ファイルを検索する際のサーチパス (システムディレクトリ) // // (補足) アプリの設定を検索する場合は $XDG_CONFIG_HOME:$XDG_CONFIG_DIRS の順で行い // ユーザ毎の設定を優先させる output.Stdoutl("XDG_CONFIG_DIRS", xdg.ConfigDirs) return nil }
try-golang/xdg_base_directory.go at master · devlights/try-golang · GitHub
実行すると以下のようになります。
ENTER EXAMPLE NAME: xdg_base_directory [Name] "xdg_base_directory" [OS] darwin XDG_DATA_HOME /Users/xxxx/Library/Application Support XDG_CONFIG_HOME /Users/xxxx/Library/Preferences XDG_CACHE_HOME /Users/xxxx/Library/Caches XDG_RUNTIME_DIR /Users/xxxx/Library/Application Support XDG_DATA_DIRS [/Library/Application Support] XDG_CONFIG_DIRS [/Library/Preferences]
MacOSだと、$XDG_CONFIG_HOME
の値が ~/.config
じゃないんですね。
~/Library/Preferences
の下は plist ファイルばっかりなので、ここは ~/.config
が良かったけどXDG自体がデスクトップ環境のためのディレクトリ仕様なので、こうなるのは納得。
ついでに、Linuxでも実行してみた。
ENTER EXAMPLE NAME: xdg_base_directory [Name] "xdg_base_directory" [OS] linux XDG_DATA_HOME /home/gitpod/.local/share XDG_CONFIG_HOME /home/gitpod/.config XDG_CACHE_HOME /home/gitpod/.cache XDG_RUNTIME_DIR /run/user/33333 XDG_DATA_DIRS [/usr/local/share /usr/share] XDG_CONFIG_DIRS [/etc/xdg]
XDG User Directory のサンプル
package xdgspec import ( "github.com/adrg/xdg" "github.com/devlights/try-golang/lib/output" "runtime" ) // XdgUserDirectory は、XDG User Directory についてのサンプルです. // [xdg](https://github.com/adrg/xdg) を利用して各値を取得しています. // // REFEFENCES:: // - https://www.freedesktop.org/wiki/Software/xdg-user-dirs/ func XdgUserDirectory() error { // ------------------------------------------------------------ // XDG User Directory について // XDG の各値は、xdg パッケージを利用すると簡単に利用できる // このパッケージは、Windows/MacOS/Unix に対応している // // XDG User Directory は、Documents,Downloads,Music,Desktopなどの // $HOME に配置されるユーザ共通のディレクトリのセットのこと // // xdg パッケージは、対象となる環境変数が設定されていれば、その値を返し // 設定されていない場合は、デフォルトの値を返すようになっている。 // ------------------------------------------------------------ output.Stdoutl("[OS]", runtime.GOOS) // XDG_DESKTOP_DIR // デスクトップの場所 output.Stdoutl("XDG_DESKTOP_DIR", xdg.UserDirs.Desktop) // XDG_DOWNLOAD_DIR // ダウンロードの場所 output.Stdoutl("XDG_DOWNLOAD_DIR", xdg.UserDirs.Download) // XDG_DOCUMENTS_DIR // ドキュメントの場所 output.Stdoutl("XDG_DOCUMENTS_DIR", xdg.UserDirs.Documents) // XDGの標準規定にはないもの output.Stdoutl("Application dirs", xdg.ApplicationDirs) output.Stdoutl("Font dirs", xdg.FontDirs) return nil }
try-golang/xdg_user_directory.go at master · devlights/try-golang · GitHub
実行すると以下のようになります。
ENTER EXAMPLE NAME: xdg_user_directory [Name] "xdg_user_directory" [OS] darwin XDG_DESKTOP_DIR /Users/xxxx/Desktop XDG_DOWNLOAD_DIR /Users/xxxx/Downloads XDG_DOCUMENTS_DIR /Users/xxxx/Documents Application dirs [/Applications] Font dirs [/Users/xxxx/Library/Fonts /Library/Fonts /System/Library/Fonts /Network/Library/Fonts]
ついでに Linux で実行してみた
ENTER EXAMPLE NAME: xdg_user_directory [Name] "xdg_user_directory" [OS] linux XDG_DESKTOP_DIR /home/gitpod/Desktop XDG_DOWNLOAD_DIR /home/gitpod/Downloads XDG_DOCUMENTS_DIR /home/gitpod/Documents Application dirs [/home/gitpod/.local/share/applications /usr/local/share/applications /usr/share/applications] Font dirs [/home/gitpod/.local/share/fonts /home/gitpod/.fonts /usr/local/share/fonts /usr/share/fonts]
xdgパッケージの便利な関数のサンプル
package xdgspec import ( "github.com/adrg/xdg" "github.com/devlights/try-golang/lib/output" "io/ioutil" "os" "path/filepath" "runtime" ) // XdgFileOperation は、[xdg](https://github.com/adrg/xdg) を利用して // XDGの規定に従った場所にファイルを配置したり検索したりしています. func XdgFileOperation() error { var ( dataDir = filepath.Join(xdg.DataHome, "try-golang") ) output.Stdoutl("[OS]", runtime.GOOS) output.Stdoutl("[dataDir]", dataDir) // 処理する前に既にファイルが存在してたら消す if _, err := os.Stat(dataDir); err == nil { output.Stdoutl("[exists?]", "存在する --> 削除") if err = os.RemoveAll(dataDir); err != nil { output.Stderrl("[os.Remove]", err) return err } } else { output.Stdoutl("[exists?]", "存在しない") } // xdg.DataFile() に アプリ名/ファイル名 で渡すとXDGの規定に従ったパスを // 生成して返してくれる. xdg.DataFile() にすると $XDG_DATA_HOME // xdg.ConfigFile() にすると $XDG_CONFIG_HOME がベースとなる // // このとき、ファイルの親ディレクトリ(つまりアプリ名の部分)が // 存在しない場合は、ディレクトリを作成してくれる dataFile, err := xdg.DataFile("try-golang/mydata.txt") if err != nil { output.Stderrl("[xdg.DataFile]", err) return err } output.Stdoutl("[xdg.DataFile]", dataFile) if _, err = os.Stat(dataDir); err == nil { output.Stdoutl("[exists?]", "存在する") } else { output.Stdoutl("[exists?]", "存在しない") } if err = ioutil.WriteFile(dataFile, []byte("helloworld\n"), 0644); err != nil { output.Stderrl("[ioutil.WriteFile]", err) return err } if bytes, err := ioutil.ReadFile(dataFile); err == nil { output.Stdoutl("[ioutil.ReadFile]", string(bytes)) } // xdg.SearchDataFile() を利用すると、指定した アプリ名/ファイル名 を探してくれる. // 存在しない場合は、err に値が入る. // xdg.DataFile() と違い、こちらは親ディレクトリを作ったりはしてくれない. // 既にファイルが存在する場合に利用する. dataFile2, err := xdg.SearchDataFile("try-golang/mydata.txt") if err != nil { output.Stderrl("[xdg.SearchDataFile]", err) return err } output.Stdoutl("[xdg.SearchDataFile]", dataFile2) // 後始末 _ = os.RemoveAll(dataDir) return nil }
try-golang/xdg_file_operation.go at master · devlights/try-golang · GitHub
実行すると以下のようになります。
ENTER EXAMPLE NAME: xdg_file_operation [Name] "xdg_file_operation" [OS] darwin [dataDir] /Users/xxxx/Library/Application Support/try-golang [exists?] 存在しない [xdg.DataFile] /Users/xxxx/Library/Application Support/try-golang/mydata.txt [exists?] 存在する [ioutil.ReadFile] helloworld [xdg.SearchDataFile] /Users/xxxx/Library/Application Support/try-golang/mydata.txt
ついでに Linux で実行してみた
ENTER EXAMPLE NAME: xdg_file_operation [Name] "xdg_file_operation" [OS] linux [dataDir] /home/gitpod/.local/share/try-golang [exists?] 存在しない [xdg.DataFile] /home/gitpod/.local/share/try-golang/mydata.txt [exists?] 存在する [ioutil.ReadFile] helloworld [xdg.SearchDataFile] /home/gitpod/.local/share/try-golang/mydata.txt
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場