rcmdnk's blog
Last update

XDG Gear and Gear Wall Clock Gear Science Art Artificial Intelligence Steampunk Neuroscience Art Vinyl Record Wall Clock (Size: 12 Inch with LED)

Pythonでコマンドラインツールなどを作る際に 設定ファイルをいい感じに探し出すツールを作ってみました。

コマンドラインツールの設定ファイル

最近は XDG (X Desktop Group) Base のディレクトリを使うツールが増えています。

XDG Baseな環境では $XDG_CONFIG_HOMEという値が定められていればその下に設定ファイルを各種ツールの名前ごとに ディレクトリを作って置きます。 (ツール名の設定ファイルを直接置く場合もある。)

$XDG_CONFIG_HOMEは通常は~/.configで、$XDG_CONFIG_HOMEが設定されてなければ ~/.configを使う、ということもよくあるかと思います。

だいぶ前はHOMEにdotfileな形で置くものの方が多かったと思います。

例えばVimは~/.vimrcを使いますが、Neovimは~/.config/nvimというディレクトリの下のinit.vimという設定ファイルを使います。

途中で移行したものもあり、そういった場合は古い場所にしかなければそちらを使う、という状態になってたりします。

~/.configを探してなければHOMEのdotfileを探す、と。

さらに、個別のプロジェクトごとなどでも設定できるよう、 現在のディレクトリにdotfileの形で置いてあるとそれを優先して使うものもあります。

また、Gitのレポジトリの中で作業しているときにはそのrootディレクトリを探したりすることもあります。

さらにこれらのディレクトリの位置とともに、 直接.<tool_name>.ymlのような感じでdotfileとして置く場合と、 .<tool_name>というディレクトリの下に .<tool_name>/conf.ymlのようにファイルを置く場合もあります。

conf-finder

上記のようなディレクトリやファイルの可能性を考慮に入れて 設定ファイルを探すためのPythonライブラリ。

PyPIに公開 してあるのでpip

1
$ pip install conf-finder

で入れられます。 (似たような名前のconfig-finderというものもあるので注意。というかこれがあったのでconf-finderにしました。)

デフォルトでは探すディレクトリとして

  • 現在のディレクトリ
  • Gitのrootディレクトリ(Gitのレポジトリ内にいる場合)
  • XDG config home ($XDG_CONFIG_HOME。設定されてない場合は~/.config。)
  • HOMEディレクトリ

を探します。

簡単な使い方は

conf_check.py
1
2
3
4
5
from conf_finder import ConfFinder


cf = ConfFinder('mytool')
print(cf.conf(ext='yml'))

のような感じ。 mytoolはツールの名前、cf.confextは設定ファイルの拡張子(もし指定しなければ拡張子なし)。

ファイル検索をする際にはまず上記のディレクトリの順に、 .<tool_name>.ymlのような名前のファイルを探します。 ただし、XDG config homeの下ではdotを外して<tool_name>.ymlを探します。

すべての場所になかった場合、次は.<tool_name>というディレクトリを探します。 ファイルの場合と同様、 XDG config homeの下ではdotを外して<tool_name>を探します。 これらのディレクトリがあり、その中にconf.ymlというファイルがあればそれを返します。

もし見つからなかった場合、デフォルトのファイル場所として、XDG config homeの場所(~/.config/<tool_name>/conf.yml)を返します。

なので、以下のような順番で探すことになります。

  1. ./.mytool.yml
  2. <git root>/.mytool.yml
  3. ~/.config/mytool.yml
  4. ~/.mytool.yml
  5. ./.mytool/conf.yml
  6. <git root>/.mytool/conf.yml
  7. ~/.config/mytool/conf.yml
  8. ~/.mytool/conf.yml

もしどれもなかった場合には

  • ~/.config/mytool/conf.yml

が返されます。

直接ファイルベースにするのかディレクトリベースにするのか分けた方が良い気もしてきましたが、 とりあえず一旦こういう感じで。

追記: 2023/09/24

ConfFinderにconf_typeという引数を渡せるようにして、これが

  • both: ファイル、ディレクトリ両方 (デフォルト)
  • file: 直接ファイルベースのみ
  • dir: ディレクトリベースのみ

を探すようにしました。

conf_check.py
1
2
3
4
5
from conf_finder import ConfFinder


cf = ConfFinder('mytool', conf_type='file')
print(cf.conf(ext='yml'))

なら

  1. ./.mytool.yml
  2. <git root>/.mytool.yml
  3. ~/.config/mytool.yml
  4. ~/.mytool.yml

を探して見つからなければ ~/.config/mytool.ymlを返します。

追記ここまで

conf-finderのその他オプション

ファイルは無視してディレクトリを検索

conf_check.py
1
print(cf.directory())

とすると

  1. ./.mytool
  2. <git root>/.mytool
  3. ~/.config/mytool
  4. ~/.mytool

を探して見つかったディレクトリを返します。どれもなければ ~/.config/mytool

設定ファイル名の変更

conf_check.py
1
print(cf.conf(ext='yml', file_name='my_conf'))

のような形でfile_nameを指定すると、

  1. ./.my_conf.yml
  2. <git root>/.my_conf.yml
  3. ~/.config/my_conf.yml
  4. ~/.my_conf.yml
  5. ./.mytool/my_conf.yml
  6. <git root>/.mytool/my_conf.yml
  7. ~/.config/mytool/my_conf.yml
  8. ~/.mytool/my_conf.yml

といった感じに、直接ファイルを探す際にはfile_nameを、 ディレクトリを探す場合にはmytoolのディレクトリを探しその中にfile_nameのファイルを探します。

探索ディレクトリの変更

ConfFinderへの引数で search_dir_listへディレクトリのリストを渡すとそのディレクトリを探すようになります。

conf_check.py
1
cf = ConfFinder('mytool', search_dir_list=['cwd', 'git', 'xdg', 'home', '/etc'])

とすると、リストの順に探索し、/etc/.mytool.yml/etc/.mytool/conf.ymlも探します。

基本的に渡したものはそのままディレクトリパスとして解釈されますが、上にもあるような 一部の単語は中で変換されます。

  • cwd: 現在のディレクトリ
  • git, git_root: Gitのrootディレクトリ
  • xdg, xdg_config_home: XDG config home
  • home: HOMEディレクトリ

dotをつけないディレクトリの指定

上にもあるようにXDG config homeの下の場合のみdotをつけない形にします。 これを変更するには

conf_check.py
1
cf = ConfFinder('mytool', non_dot_dir=['cwd', 'xdg_config_home'])

のようにConfFinderのnon_dot_dirにリストを渡します。 初期値はxdg_config_homeのみです。

デフォルトファイルの変更

すべて見つからなかった場合に使うファイルの位置を変更するには

conf_check.py
1
cf = ConfFinder('mytool', default_dir='cwd')

のようにdefault_dirに指定します。 初期値はxdg_config_homeになっています。

Sponsored Links
Sponsored Links

« Google AnalyticsのUAからGA4への移行 Oura Ring(第3世代)のバッテリーがだめになったので交換してもらった »

}