VSSに格納されたファイルの一覧を取得するベストプラクティス

# 概要らしきなにか

1. ソースシュレッダーとか馬鹿にされているし僕も極力使いたくないんだけど、使っているものはしょーがない。
2. ファイルレポート機能 ニア・イコール `Dir`コマンド によって出力できるが、固定長文字列で出力されてしまう。
3. 公式ドキュメント(オンラインは閉鎖してると思うけど付属のヘルプで)に下記記載があった
    > -O@<file name>
   指定したファイルにすべての出力を送信します。履歴レポートなどのレポートをファイルやプリンタにエクスポートする場合は、このオプショ ンを使用します。指定した名前のファイルが既に存在する場合、出力はそのファイルに追加されます。
    - `Dir`の項目には「使えるヨ」と案内がある(`ss Dir <project> ... [-O]`)だけで出方についてはノータッチ。上記はオプションの説明
4. `-O@<file name>`を指定すれば固定長じゃなくきちんと出力されてくれた。
    - ついでにプロンプトがない分高速で動いてくれている。ような気がする。

# 動くコードくれよ
はいよ

```bat:export.bat
rem 対象のVSS格納フォルダ指定
set SSDIR=VSSデータベースルートフォルダ
rem VSSアプリのパス。
set ssApp="C:\Program Files (x86)\Microsoft Visual SourceSafe\ss.exe"

rem 出力先ファイル。存在チェックとかは適当に組んでどうぞ。なお、追記される。
set outFile=出力先ファイル.txt

rem 時間がかかるので前後echo推奨
@echo 出力開始
%ssApp% Dir $/ -R -O@%outFile%
rem アプリパス Dirコマンド 出力対象プロジェクト指定 -Rで再帰出力指定 -O@で出力先ファイル名指定(同時にプロンプト出力がなくなる。)
@echo 完了
pause
```

# 変換

出力みたことあればわかるんですが正直クソインターフェースです。
`tree`の劣化版出力みたいな出力で、まあ多分ファイル毎の詳細情報を出力するための出力順なんだと思うんですけど、
その機能別でいいじゃんね。

てなわけで、powershellで上記出力を加工して読みやすいように組み替えるやつ作った。
ぼくがほしいやつしか作ってないのでこまけえところは各自で改造してくれ。
powershellのこまけえヘルプはネットの海を漂って探してくれ。

## ただのファイルフルパス一覧にするもの。

```powershell:exportToPlainTxt.ps1
$target = "input.txt" # VSSのDirの出力ファイル
$output = "output.txt" # 出力ファイル名(上書きするので注意)
Out-File $output default -InputObject (
  (Get-Content $target)| % {
    if ($_ -match '^\$.*[^:]$') { return }
    if ($_ -like "$*") {
      $pardir = ($_ -replace ":", "/")
      $pardir
    } elseif (!(($preLength -eq 0) -Or ($_.length -eq 0))) {
      $pardir + $_
    } else { "" }
    $preLength = $_.length
  }
)
```

## VSSのファイルリストを作成してEverythingでさくさく検索する

Everythingのファイルリスト形式に変換するモノ

下記では「プロジェクト」を「ディレクトリ」と読み替えている場合がある。
正直なんで読み替えにゃならんのかわからん。


```powershell:exportToefu.ps1
# Everything File List
$target = "input.txt" # VSSのDirの出力ファイル
$output = "output.efu" # 出力ファイル名(上書きするので注意)
$preLength = 0
"Filename,Size,Date Modified,Date Created,Attributes"|Out-File $output utf8
Out-File $output utf8 -Append -InputObject (
  (Get-Content $target)| % {
    if ($_ -match '^\$.*[^:]$') { return }
      # 「ディレクトリ内に存在するディレクトリ」または「$...:は空です」を指す。スキップ
    if ($_ -like "$*") {
      # 各ディレクトリのヘッダ的に出力されている、ルートディレクトリ。
      # ディレクトリとして出力し、次行以降では親ディレクトリとして文字列を使用
      $pardir = (($_ -replace "\`$(.*):`$", "`$:`$1") -replace "/","\")
      # Everything の仕様(?)で、「$:/」をドライブレターとして認識させるのにパス区切り「/」を「\」にしている。 
      # 最後に一括でやったほうが性能いいかも
      '"'+$pardir+'",,,,16'
      # Attribute で Directory(16) を指定。
    } elseif (!(($preLength -eq 0) -Or ($_.length -eq 0))) {
      '"'+$pardir + "\" + $_+'",1,,,1'
      # Attribute で Readonly(1)を指定。
      # Size (FileSize)を正確に取るには VSSでProperty とか投げればとれそう
      # だけど、当方環境はファイル数が膨大で重くなりそうなのでためしていない。
      # 上記例のように「1」とすると、「1バイト/ファイル」になり、"ディレクトリ毎に計上され"、各ディレクトリの子孫のファイル数が把握しやすい。
    } # else {  }
    $preLength = $_.length
  }
)
```

Everythingファイルリストは
ヘッダを`Filename,Size,Date Modified,Date Created,Attributes`とする
CSV形式(UTF-8)で、
型・書式は順番に"文字列"、バイト数(10進整数)、なんらかの10進整数、なんらかの10進整数、属性値を表すビットの10進整数

`1バイト/ファイル`にするのは最低限空のフォルダを検出したいから。
Dirの出力に出ていれば全部出るので、リンクとかも出る。

当然ながらファイル実態を示さないので、Everythingのファイル実態に対する操作(検索結果のファイル一覧に対する読み書き)は無効。
パスとかファイル名は取得できるので「`$:/`」を作業フォルダに置換するなどして取得したハズの場所に直接飛ぶとかはできる。
Everythingのコンテキストメニューのカスタマイズでどうにか作業フォルダに直接飛ぶのを試行するように変更とかはできそう(いらないのでやらないけど)

## 運用手順例

### 初回

1. 出力した`output.efu`を任意のパスに移動/コピー(以下「vssリスト」と呼ぶ)
1. Everythingのオプションで、「検索データ>ファイルリスト」にvssリストのパスを追加する
1. 一旦オプションを閉じて、ファイルリストが読み込まれるのを待つ
1. 検索でvssのファイルが検索できる感動を味わう
1. 再度オプションを開き、「変更を監視します」をuncheckする(自動更新バッチとか組む場合は残しても良い)

## 次回以降

1. 任意のタイミングで`output.efu`を更新する
    * きまぐれに更新するも、タスクスケジューラで定期的に実行してもよし。お好きに
1. vssリストを上書きする
1. Everythingのオプションで「変更を監視します」にチェックをつけて閉じる
1. 一旦オプションを閉じて、ファイルリストが読み込まれるのを待つ
1. 検索でvssのファイルが検索できる感動を味わう
1. 再度オプションを開き、「変更を監視します」をuncheckする


# 感想
そもそも僕の作業所でのVSS(曲がりなりにもバージョン管理システム)の使い方が変なので、
ファイル一覧があるとないとで利便性がかなり違うので作った。

作業コピーをフルで用意する場合とか、ツールが優秀な場合は不要な長物なんだけど、
作業コピーフルで用意したらストレージ死んじゃうし、
ツールはお世辞でなおゴミだし(しゃーないから使うが)
なので怒りとノリで作った。

Everything向けのファイルリスト出力は別のVCSでも作業コピーを部分的にとるなら需要あると思うので、
それぞれでコーディングするのがめんどいけど「ファイル一覧出力→efu形式」のバッチは作っても良さそう。
今の所僕が使わないから作らないけど。

以上。