Windowsでdotfilesの世界をパクリんぐする

· Read in about 7 min · (3190 words) ·

アドベントカレンダーに参加しています。

Windowsでdotfilesの世界をパクリんぐする話をします。

Windowsにおける設定情報

Windowsにおいては昨今、設定情報はかなり混沌と設定している、今となってはレガシー化しつつある、レジストリ情報に加えて、*NIX風のdotfilesをUser Profileの直下に置くパターンなどいくつものパターンがある。一旦、整理してから話を進めたい。

レジストリ情報

dotfilesの方向性としては異なるが整理のため、触れることにする。レジストリ情報はHKEY_LOCAL_MACHINEなど各種の階層で格納されているが一般にユーザごとの情報はHKEY_USERSの下にあり、実際にはそれがHKEY_CURRENT_USERにリンクされているものと考えられる。ただ、これは知っての通りバイナリデータとしてユーザにはコントロールしにくい形で存在していること、また、dotfilesの形とは言い難いため議論はここまでとする。

User Profilesの下に置かれるdotfiles

User ProfileはデフォルトのインストールではUsers\<ユーザ名>に置かれるファイル群である。この中にはHKEY_USERSに置かれているレジストリも含まれている。昨今では特に*NIXからポーティングされたツールを中心にここに.で始まるファイルや_などで始まるファイル群を展開するものが散見される。例えば、scoopでvimをインストールした場合、_vimrcはUser Profileの直下に格納される。

User ProfileのAppData以下

User Profileには一般にAppDataとDocumentsが格納されている。標準的なデザインとしてはユーザにその存在を認識させるファイルはDocumentsにその存在を認識させなくてもいいファイルをAppDataに格納し、さらにAppDataの中で移動プロファイルでローミングするファイルはRoamingにマシン固有のファイルはLocalに置かれることになっている。例えば、ConsoleZの設定情報はAppData内のRoamingにConsole\console.xmlという形で格納されている。また、Visual Studio Codeの設定情報はRoamingのcode以下に格納されている。

UWPのLocalState

狭義のUWP (U先のniversal Windows Platform)アプリケーションにおいては、先のAppDataのLocalの下にあるPackagesディレクトリの下にアプリケーションごとにディレクトリを作成しその中にある、LocalStateディレクトリ内に格納されることが多い。たとえば、WindowsTerminalにおいては、少なくとも現時点においてはPackages内のMicrosoft.WindowsTerminal_8wekyb3d8bbweディレクトリにLocalStateが存在している。

WSL

WSL1の場合は、ファイル群はdevfsとdrvfsと考えられるが、一般にdevfsの構造はWindowsから見ると深いディレクトリに置かれていること、また、Windows側からdevfsのファイルを操作すると、metadataを損壊することになるため、注意を要する。従って、WSLの設定情報については現状、Windowsのdrvfsにレポジトリをおいて、適時シンボリックリンクを張っているが、後述する、Windows上でのgitの特性から、WSL上で独自にdotfilesをコントロールしたほうがいいかもしれない。

dotfilesによる設定情報のコントロール

dotfilesでコントロールしやすいもの

先までに上げたものの中で、dotfilesによるコントロールに適するのは基本的にはレジストリを除いたものであると考えられる。レジストリはバイナリデータとして格納されているため、*NIX的な管理はし辛い。

dotfilesによるコントロールのサンプル

dotfiles風にコントロールの容易なものとして、以下に例をあげる。

  • vimrc
  • Windows Terminal
  • git
  • nyagos
  • ConsoleZ
  • WSLのdotfiles

これらを分類すると以下のようになる。

名前 種類
vimrc User Profile
Windows Terminal UWP LocalState
git User Profile
nyagos User Profile
ConsoleZ AppData
WSL dotfiles WSL

シンボリックリンクの活用

レポジトリから各ファイルへはシンボリックリンクを用いる。シンボリックリンクは開発者モードでは一般ユーザでも作成できる。ただし、開発者モード以外ではシンボリックリンクの作成には管理者特権が必要であるため、シンボリックリンクの構築スクリプトをPowerShellで作る場合、以下のような構造になるであろう。

$userProfile = $env:USERPROFILE

if($PSVersionTable.PSVersion.Major -gt 4) {
    if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
            [Security.Principal.WindowsBuiltInRole] "Administrator")) {
 

 
    }

    else {
        Write-Warning "管理者権限が付与されていません"
        exit 1
    }
}
else {
    Write-Warning "PowerShellのバージョンが条件を満たしていません"
}

PowerShellのバージョンを確認するのはPowerShellでシンボリックリンクが作成できるようになったのは、Windows PowerShell 5.xからであり、それ以下の場合には構築できないだけでなく、削除をした場合にリンクが削除されるだけでなく元のファイルまで消えてしまうためである。したがって、バージョンを確認する必要がある。

当初はインストール用のスクリプトをCMD Batchを使って作成していたが、管理者権限の有無に関して、openfilesコマンドの実行に管理者権限が必須なことを利用して判定を行っていたりしたが、この部分の挙動に不安が残ること、また、環境変数の展開などコードの作成負荷が高いことを考慮して、全面的にPowerShellに移行した。ただ、PowerShellのバージョンを考慮して、一応、セーフティネットを張っている。

現状のディレクトリ構造

  • ConsoleZ
    • ConsoleZの設定を格納
  • dot
    • .gitconfigなどのdotfiles
  • Scripts
    • リンクの配置用スクリプトなどを格納
  • vscode
    • vscodeの設定を格納
  • WindowsTerminal
    • Windows Terminalの設定を格納
  • wsl
    • WSL1のdotfiles群を格納 (試験運用)

リンクのインストール用スクリプト

$userProfile = $env:USERPROFILE

if($PSVersionTable.PSVersion.Major -gt 4) {
    if (([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
            [Security.Principal.WindowsBuiltInRole] "Administrator")) {
                Remove-Item (Join-Path $userProfile "AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\profiles.json")
                Remove-Item (Join-Path $userProfile "AppData\Roaming\Console\console.xml")
                Remove-Item (Join-Path $userProfile "AppData\Roaming\Code\User\settings.json")
                Remove-Item (Join-Path $userProfile ".nyagos")
                Remove-Item (Join-Path $userProfile ".gitconfig")
                Remove-Item (Join-Path $userProfile "_vimrc")

                $i = Get-Item ..\WindowsTerminal\profiles.json
                New-Item -Path (Join-Path $userProfile "AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\profiles.json") -Value $i.FullName -ItemType SymbolicLink
                $i = Get-Item ..\ConsoleZ\console.xml
                New-Item -Path (Join-Path $userProfile "AppData\Roaming\Console\console.xml") -Value $i.FullName -ItemType SymbolicLink
                $i = Get-Item ..\vscode\settings.json
                New-Item -Path (Join-Path $userProfile "AppData\Roaming\Code\User\settings.json") -Value $i.FullName -ItemType SymbolicLink
                $i = Get-Item ..\dot\.nyagos
                New-Item -Path (Join-Path $userProfile ".nyagos") -Value $i.FullName -ItemType SymbolicLink
                $i = Get-Item ..\dot\.gitconfig
                New-Item -Path (Join-Path $userProfile ".gitconfig") -Value $i.FullName -ItemType SymbolicLink
                $i = Get-Item ..\dot\_vimrc
                New-Item -Path (Join-Path $userProfile "_vimrc") -Value $i.FullName -ItemType SymbolicLink
    }

    else {
        Write-Warning "管理者権限が付与されていません"
        exit 1
    }
}
else {
    Write-Warning "PowerShellのバージョンが条件を満たしていません"
}

おすすめ設定

nyagos

nyagosでは現在、llに関しては既定で定義はされていない。したがって、.nyagosでllのエイリアスを定義すると良いと思われる。

alias "ll=ls -oFl"

vscode

現状の、vscodeの設定はSyncを使っていたこともあり、かなり雑然としている。ただ、現状は設定をgitレポジトリで回すようにしたのでSyncは既に使われていない。したがって、Syncは既にカビが生えている。

// Place your settings in this file to overwrite the default settings
{
    "editor.fontFamily": "'源ノ角ゴシック Code JP',Consolas, 'Courier New', monospace",
	"editor.fontSize": 14,
	"editor.tabSize": 4,
	"editor.detectIndentation": true,
    "editor.cursorStyle": "block",
    "sync.gist": "3d05261c97ade4d609853b017737a877",
    "sync.lastUpload": "2018-03-17T11:59:25.910Z",
    "sync.autoDownload": false,
    "sync.autoUpload": false,
    "sync.lastDownload": "",
    "sync.version": 262,
    "sync.showSummary": true,
    "sync.forceDownload": false,
    "sync.workspaceSync": false,
    "sync.anonymousGist": false,
    "sync.host": "",
    "sync.pathPrefix": "",
    // Path to Python, you can use a custom version of Python by modifying this setting to include the full path.
    "python.pythonPath": "c:/Anaconda3/python.exe",
    // Path to folder with a list of Virtual Environments (e.g. ~/.pyenv, ~/Envs, ~/.virtualenvs).
    "python.venvPath": "",
    // Absolute path to a file containing environment variable definitions.
    "python.envFile": "${workspaceRoot}/.env",
    "python.linting.enabled": true,
    "python.linting.pylintEnabled": true,
    "sync.quietSync": false,
    "sync.askGistName": false,
    "terminal.integrated.shell.windows": "C:\\Program Files\\PowerShell\\6\\pwsh.exe",
    "git.path": "C:\\Users\\gorn\\scoop\\apps\\git\\current\\bin\\git.exe",
    "workbench.colorTheme": "Kimbie Dark",
    "workbench.iconTheme": "vscode-icons",
    "editor.smoothScrolling": true,
    "terminal.integrated.rendererType": "experimentalWebgl"
}

検討中の課題

Windows上でのgitの挙動

Windows上ではgitは.gitconfigの[core]にautoCRLF = falseがない場合、既定で改行コードをLF -> CRLFの変換を行う。当然ながら、WSL上のLinux環境では改行コードは通常、CRのみのため、改行コードが変換されてしまうと不都合が生じる。