闇雲にまずは探すなら (Re: Windows では何種類にも派生しちゃう HOME、やぁねぇ)

これの少しだけ続き。

「管理」よりも前に、そもそも「まずは闇雲に探さねばならぬ」というシチュエーションにいるとして。

実は「究極」はデバッガ「的な」ものを使うことだったりもして、SysInternals の「filemon.exe」というかつて配布されていたものを使うと、「アプリケーションがファイル(的なもの)にアクセスするや報告してくれる」。Process Explorer にこの機能は統合されちゃったので、今は単独では手に入らない(入りにくい、かな)。てわけで、今だと Process Explorer を使ってそれをすることが出来る。無論これは「究極」にして「最後の手段」なのであって、まさに「Needle in a haystack」そのもの。あまりのアクセスの多さにビビること請け合い。

ひとまず「標準的な場所から探そうと試みる」としたら:

try_finding_confs.py
 1 # -*- coding: utf-8 -*-
 2 from __future__ import unicode_literals
 3 
 4 import sys
 5 import os
 6 
 7 
 8 def _root_cands():
 9     # レジストリ
10     #   "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
11     # にかつては欲しいものがあり、今でもあるが非推奨というか「don't use」
12     # とまで言われてる、ことが regedit で覗きにいってみればわかったりする。
13     # そこでは「正規の API 使いやがれ」というがこれを「Windows 正規の」もので
14     # ない手段から使うのは難儀。なおかつ Shell Folders 流儀は既に Vista で
15     #   https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457(v=vs.85).aspx
16     # にリプレイスされてたりもする。
17     #
18     # Win 8 からどうなのかワタシはわからんが、とりあえず Win7 では今でも
19     # 環境変数から以下にはアクセス出来る:
20     #     USERPROFILE
21     #     APPDATA
22     #     LOCALAPPDATA
23     #     PUBLIC
24     #     ALLUSERSPROFILE
25     # このうち USERPROFILE が unix で言うところの /home/user に相当し、
26     # c:/Users/hhsprings てな具合の値を取るが、この概念自体が Vista から。
27     # また、USERPROFILE は先の Shell Folders のテリトリー外。
28     #
29     # 結局「候補を知りたいだけ」の目的としては、まぁ環境変数だけ見るのが
30     # マシなのかも。てわけなので:
31     for ek in (
32         "APPDATA",
33         "LOCALAPPDATA",
34         "USERPROFILE",
35         "PUBLIC",
36         "ALLUSERSPROFILE",
37         ):
38         yield os.environ[ek]  # KeyError は知らん。
39 
40 if __name__ == "__main__":
41     import argparse
42     parser = argparse.ArgumentParser()
43     parser.add_argument("find_what")
44     args = parser.parse_args()
45 
46     for rc in _root_cands():
47         for root, dirs, files in os.walk(os.path.normpath(rc)):
48             for fn in files:
49                 # file じゃなく directory を探したい場合もあるであろう
50                 if args.find_what == fn:
51                     print(os.path.join(root, fn).replace("\\", "/"))
52                     # break したい場合もあるでしょーね。

性能的にはこれはエラいことになっていて、探索順を間違えると一向に返ってこない。おーい、そんなことがしたいんじゃないぞー、て言いたくなるが、「候補がわからない中から探そうと試みてみる」ためにはまさに「無限に潜り続ける」しかなかろ。まぁもちっと工夫は出来るけれどもね。

それでもまぁこれで「.pypirc はどこ?」という問いにはすぐに答えを出す。

けど本当の問題はそこじゃなくてな。まさに .pypirc がそうなんだけれど、「一旦起動がうまくいきさえすればこの設定ファイルが永続化される」という類のものであって、当然「初回起動」時にはんなもん「まだ」存在してない。だからこそ「このアプリケーションは設定ファイルをここに置く」という、「動かさないで知る方法」が必要なのだ。

ね、やでしょ? して上のスクリプトだが、「cygwin だぁ MSYS だぁ」と対応していくのかよ、って話である。なんであれ果てしないのだ、この問題。くっだらないんだよほんと。

なお、「開発者として、設定ファイル置き場をどうすれば?」問題への解は結構見つかる。例えば Python なら AppDirs なんてのがあった。ActiveStates 製、つまり PyWin32 からのニーズから発生した、のかな、多分。