仕組み
Rigoの動作を理解するための中核概念(Vaultのレイアウト・エントリと状態モデル・OS別レイヤー・マシンごとの選択)を説明します。日々の操作手順はチュートリアルを参照してください。
Vault
Vaultは,ホームディレクトリを鏡写しにしたただのディレクトリです。vault/.zshrc は ~/.zshrc に,vault/.config/git/config は ~/.config/git/config に対応します。
Vault/
├── .config/
│ └── rigo/
│ └── rigo.toml # Rigo自身の設定。他のエントリと同様に管理される
├── .zshrc # → ~/.zshrc
├── .gitconfig # → ~/.gitconfig
├── .os/ # OS別レイヤー(後述)
└── .trash/ # forgetの安全網(後述).os と .trash はRigoが特別扱いする構造用ディレクトリで,通常のスキャン対象から除外されます(名前は rigo.toml の os_dir / trash_dir / abs_dir で変更可能です)。
設定ファイルの位置とVaultの発見
設定ファイル rigo.toml はVault内の固定位置 <vault>/.config/rigo/rigo.toml に置き,他の管理対象ファイルと同様に ~/.config/rigo/rigo.toml へリンクされます。Rigoはこのsymlinkを逆にたどってVaultの場所を発見します。
$XDG_CONFIG_HOME/rigo/rigo.toml(未設定なら~/.config/rigo/rigo.toml)のsymlinkを読む- リンク先のパスから末尾の
.config/rigo/rigo.tomlを取り除いたものがVaultルート
つまり「設定ファイルがVault内のどこにあるか」が固定されているため,Vaultの場所を別途記録する必要がありません。新しいマシンではまだこのsymlinkが存在しないので,初回だけ -f でVault内の rigo.toml を直接指定します(実行するコマンドが apply なら,その場で rigo.toml 自身もリンクされ,以降の自動発見が機能するようになります)。
Vaultの切り替え
複数のVault(たとえば常用と検証用)を使い分ける場合も,仕組みは同じです。発見用symlinkが指す先を変えれば,環境が切り替わります。切り替え先の rigo.toml を -f で指定して,発見用symlink自身を link し直します。
# 発見用symlinkを別のVaultへ向け直す
rigo -f ~/Lab/Vault/.config/rigo/rigo.toml link .config/rigo/rigo.tomlreplacing symlink that pointed to /Users/ada/Sync/Vault/.config/rigo/rigo.toml以降の rigo コマンドは新しいVaultを参照します。発見用symlinkを ln -sf で手で張り替えても同じです。
切り替え後,旧Vaultへ張られていた他のエントリのsymlinkは,新Vaultにも同名エントリがあれば broken として status に現れるので,rigo link で張り替えます。旧Vaultにしかないエントリのリンクは新Vaultからは見えないため,残したくなければ切り替え前に旧Vault側で unlink(実体化)しておくのが安全です。
なお,ボリュームルート直下(/ や D:\ そのもの)をVaultにすることはできません。OSが生成するエントリに埋もれてしまうためです。
エントリ
管理の単位をエントリと呼びます。エントリには2種類あります。
- ファイルエントリ
Vault内の1ファイルが1本のsymlinkになる,基本の形。 - ディレクトリ単位エントリ
ディレクトリ全体が1本のsymlinkになる形。rigo.tomlのdirs(またはtags内で末尾/付き)で宣言します。ディレクトリ内に新しいファイルを作っても自動で管理下に入るのが利点です。
宣言されていないディレクトリは,それ自体は管理対象にならず,リンクもされません。Rigoはその中へ降りていき,中のファイルを個別のエントリとして管理します。たとえば .config/ は通常このかたちで,.config/git/config などの各ファイルが個別のエントリになります。
ディレクトリ単位エントリの内側のパスを dirs や tags で個別に宣言することはできません(ディレクトリ全体が1本のリンクなので,内側だけ別扱いできないため。スキャン時にエラーになります)。
状態モデル
各エントリは,そのマシン上で次の5状態のいずれかを取ります。判定はデプロイ先(ターゲット)の実際の状態の観察だけで行われ,別途の状態ファイルは持ちません。
| 状態 | 意味 |
|---|---|
linked | ターゲットがVault実体へのsymlink(収束済み) |
pending | ターゲットが存在しない(未展開) |
unlinked | ターゲットが実体ファイルで,内容はVaultと同一 |
conflict | ターゲットが実体ファイルで,内容がVaultと異なる |
broken | ターゲットがsymlinkだが,Vault実体を指していない(リンク切れ含む) |
status の表示にはこのほか,このマシンでは展開対象外であることを示す excluded が加わります(後述の「マシンごとの選択」を参照)。
ディレクトリ単位エントリの同一性比較は再帰的です(ファイル集合と各内容がすべて一致して初めて unlinked)。
安全設計
状態遷移には一貫した原則があります。
- conflictは黙って解決されない
applyはconflictを一覧表示するだけで触りません。解決はrigo linkの対話(diff表示 → Vault側を採るか,ローカル側をVaultに取り込むか選択),または--force(Vault側を採る)の明示だけです。 - ローカル実体は失われない
リンク作成時は既存内容を退避してから張り替え,失敗したら復元します。unlinkはコピーを準備してから入れ替えます。 forgetはトラッシュ経由
管理をやめてもVault側の実体は即削除されず,Vault内トラッシュへ移動します(後述)。
OS別レイヤーとオーバーレイ
Vaultは複数のレイヤーの重ね合わせとしてスキャンされます。同じ論理パスに複数のレイヤーがエントリを持つ場合,後のレイヤーが優先されます。
共通(Vaultルート直下) < .os/<goos>/ < .os/linux/<distro>/- 共通レイヤー
全OSに展開されます。 - OSレイヤー
.os/darwin/・.os/linux/・.os/windows/配下に,同じくホームの鏡写しとして置きます。そのOSのマシンにだけ展開されます。 - ディストリビューションオーバーレイ
.os/linux/<distro>/配下。rigo.tomlのdistrosに宣言されたディレクトリ名だけがオーバーレイとして扱われ,/etc/os-releaseのIDフィールドと一致するマシンにだけ展開されます。宣言のないディレクトリは通常のホーム内容と見なされます(ホストのディストリビューション名と偶然一致した場合は警告が出ます)。
たとえば .zshrc を共通に置きつつ,.os/darwin/.zshrc を置けば,macOSだけ別内容になります。
ホーム外の絶対パス(.abs)
ホームディレクトリの外のパスは,OSレイヤー内の .abs/ 配下にルートからの鏡写しとして置きます。ホーム外のパスはOS間で共有できないため,必然的にOS別です。
vault/.os/linux/.abs/etc/systemd/user/foo.service → /etc/systemd/user/foo.serviceWindows固有のマッピング
Windowsでは,さらに2つのマッピングが加わります。
- プロファイルセクション
.os/windows/.appdata/は%APPDATA%に,.os/windows/.local/は%LOCALAPPDATA%に対応します。 - 名前付きボリューム
ホーム外の絶対パスはドライブレターを直接は使わず,.abs/<ボリューム名>/を経由します。ボリューム名からドライブレターへの対応はrigo.tomlの[volumes]でホスト(またはグループ)ごとに宣言します。組み込みボリュームsystemは%SystemDrive%に解決され,宣言不要です。
vault/.os/windows/.abs/data/Tools/x.ini → D:\Tools\x.ini
(E:\Tools\x.ini on a host that maps "data" to e)同じ内容が,マシンによって違うドライブに置かれるケースを名前で吸収する仕組みです。
なお,.config/ 配下の論理パスは各OSで $XDG_CONFIG_HOME(未設定なら ~/.config)に解決されます。
マシンごとの選択
どのエントリをどのマシンに展開するかは,rigo.toml の [groups] / [include] / [exclude] で制御します。
- マシンの識別子(ホスト名)は,OSのホスト名の最初のドットまでを小文字化したものです。
rigo statusのヘッダで確認できます。 [groups]はホストをまとめる名前です(Ansibleのインベントリと同じ発想)。[include]/[exclude]のキーはホスト名またはグループ名,値はパスまたはタグ名のリストです。
選択は2つのモードのいずれかで動きます。
- excludeモード(既定)
すべて展開し,effective exclude(ホスト自身とその所属グループのexcludeの和)に該当するものだけ除外します。 - includeモード
そのホストにeffective includeが1つでもあると切り替わります。effective includeに該当するものだけを展開し,そこからさらにexcludeを除きます(allowlist)。
リストの各項目はタグ名(そのタグの全メンバーに展開される)またはパスです。パスはそのエントリ自身に一致し,ディレクトリを書いた場合はその配下のエントリすべてにも一致します。
選択から外れたエントリは status で excluded と表示され,apply や link の対象になりません。ただし forget はVaultレベルの操作なので,excludedなエントリにも実行できます(ローカルの実体化だけ行われません)。
ignore
次のものはスキャンから除外され,エントリになりません。
- 組み込みignore
OSのゴミ(.DS_Store・Thumbs.dbなど)と主要な同期サービスのアーティファクト(Syncthing・Dropbox・iCloud Drive・Google Drive・OneDrive・Nextcloud/ownCloud・Resilio・Synologyなど)。Rigoは同期手段を選ばないため,主要どころが最初からカバーされています。 - ユーザーパターン
rigo.tomlのignoreに書くgitignore風のグロブ(Vault相対パスに対して照合。/を含まないパターンは任意の深さのベース名に一致し,**はディレクトリをまたぎ,末尾/はディレクトリ限定)。
conflictコピーのファイル名がローカライズされるサービス(Dropbox・Nextcloud)は英語形のみ組み込みです。他言語環境ではユーザーパターンで補ってください。
トラッシュ
rigo forget でVaultから外れた実体は,即削除されずVault内の .trash/ に移動します。
- トラッシュはUTCタイムスタンプの世代ディレクトリ(例
.trash/20260716T093000Z/)で構成され,1世代に1エントリが入ります。 - 各世代には元のVault相対パスを記録したメタデータファイル(
.rigo-entry)が置かれ,trash ls/trash restoreがこれを使います。 - トラッシュもVaultの一部なので同期ツールに乗ります。あるマシンでの
forgetのやり直し(trash restore)を別のマシンからでも行える半面,trash emptyは全マシン共通の安全網を消す操作になります(実行時に確認が入ります)。
他マシンでの forget が同期されてくると,手元にはリンク切れのsymlinkが残ります。これを対話的に片付けるのが rigo clean で,トラッシュにコピーが残っていれば「実体ファイルとして復元」も選べます。
次はチュートリアルで,これらの概念を実際の手順として通しで体験します。