コメント付きのTime Machineにしてみる
Time Machineは、絶大な安心感を与えてくれる。過去1年半の間に、幾度かの復元作業を経験して、確実に過去を復元できることを実感した。ちなみに、Time Machineを利用した復元には3つの方法があって、目的に応じて使い分ける必要がある。
- ファイルの復元
- OS環境全体の復元
- インストールDVD >> ユーティリティ >> システムの復元から実行する。
- 日時とOSXのバージョン番号がリストされ、過去の任意の時点に、OS環境をまるごと復元する。
- OS以外の環境の移行
- /Applications/Utilities/移行アシスタント.app を起動して、現在のユーザ、アプリケーション、各種設定 等をコピーする。
ところで、ファイルの復元をするのでTime Machineに入ると、あの神秘的な宇宙空間に、延々と過去に連なるウィンドウの羅列が表示される。どこでも好きな過去に戻ってくれと言わんばかりに!しかーし、一体、自分はいつの過去に戻りたいのか?
日付と時間は表示される。クイックルックでファイルの内容も確認できる。でも、何らかの設定ファイルだったりすると、すぐに内容を確認できず、日付と時間に頼るしかない。あのセキュリティアップデートはいつだったか、あのアプリケーションのバージョンアップしたのはいつだったか、調べる必要があるかもしれない。そのためにTime Machineを出たり、入ったり、別のファイルを選択して、過去と未来に行ったり来たりしながら、戻りたい日時を特定する。
(まあ、あまり上記のような状況に陥ることはないのだけど)もし、バックアップした時のOSやアプリケーションの状況や、自分のコメントが簡単に確認できれば、より安心・確実にTime Machineを使いこなすことができるはずだ。きっと、それらの情報をテキストファイルに書いて、クイックルックできるようにしておけば、Time Machineの中で的確に戻りたい過去を判断できるだろう。
何を表示するべきか?
インストールされたソフトウェアの一覧
ソフトウェア・アップデートでは、インストールされたソフトウェアの一覧を表示できる。
それが記録されているファイルは、/Library/Receipts/InstallHistory.plist だ。内容を確認して初めて知ったが、ここにはインストーラー.app(/System/Library/CoreServices/Installer.app)がインストールした履歴が保存されているようだ。つまり、インストールパッケージをダブルクリックしてインストールしたソフトウェアは、随時このファイルにインストール履歴が記録されているのだ。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <dict> <key>date</key> <date>2009-09-29T23:49:17Z</date> <key>displayName</key> <string>Sun VirtualBox</string> <key>displayVersion</key> <string></string> <key>packageIdentifiers</key> <array> <string>org.virtualbox.pkg.vboxkexts</string> <string>org.virtualbox.pkg.vboxstartupitems</string> <string>org.virtualbox.pkg.virtualbox</string> <string>org.virtualbox.pkg.virtualboxcli</string> </array> <key>processName</key> <string>Installer</string> </dict> <dict> <key>date</key> <date>2009-10-02T03:57:18Z</date> <key>displayName</key> <string>キヤノン・プリンタドライバ・アップデート</string> <key>displayVersion</key> <string>2.1</string> <key>packageIdentifiers</key> <array> <string>com.apple.pkg.Canon_Frameworks</string> <string>com.apple.pkg.Canon_PDEs</string> <string>com.apple.pkg.MakeQueuesScript</string> </array> <key>processName</key> <string>Software Update</string> </dict> </array> </plist>
AppFresh.appがインストールした履歴
AppFreshという、ソフトウェアのアップデートを管理するアプリケーションを利用している。仕組みは、CDの曲のタイトルを表示するCDDBと似た感じだ。
- i use thisというサイトがある。
- そこにユーザーは、自分がどんなソフトウェアを利用しているか投稿する。
- 投稿する情報には、最新バージョンや、ダウンロードのURL情報も含まれている。
- AppFreshは、i use thisに蓄積されたそれらの情報を利用して、最新のアップデート情報を通知して、インストールもしてくれる。
- そして、AppFresh経由でインストールした履歴は、/Library/Logs/Software Update.log に記録されるのだ。
2009-09-20 21:32:21 +0900: Installed "RightZoom" (1.6) 2009-09-20 21:35:39 +0900: Installed "The Unarchiver" (2.0.2) 2009-09-20 21:37:14 +0900: Installed "AllBookmarks" (3.1.4) 2009-09-20 21:37:26 +0900: Installed "CotEditor" (1.0.1) 2009-09-20 21:39:40 +0900: Installed "VLC" (1.0.1) 2009-09-20 21:42:24 +0900: Installed "Xmarks for Safari" (1.2.1) 2009-09-20 21:43:03 +0900: Installed "Xmarks" (1.0)
AppleScriptとシェルコマンド
以上の情報を一つのファイルにまとめておくと便利だ。テキスト情報として表示するには、AppFreshが生成する Software Update.log のような書式が見易いと思う。その書式に統一したいのだが、悩みどころは InstallHistory.plist を同じ書式に変換する方法。PropertyListというxmlなのだが、各dictのkeyであるdate・displayName・displayVersionに対する値を日付情報と並べて1行で表示したい。
調べてみると、AppleScriptがxmlのパース(構文解析)にも軽く対応しているようなので、利用することにしてみた。AppleScriptでSoftware Update.log書式に変換して、その後、do shell scriptからシェルのsortコマンドで、3つのファイルをまとめて、日時をキーに並べ替える。以下のようにしてみた。
- 下記コードをAppleScriptエディタで開く...
-
- コピー&ペースでAppleScriptエディタに貼付けた場合は、コード中の半角¥を、半角\に置き換える必要あり。
-
----comment_on_TimeMachine----
add_comment() merge_comment_and_install_history()
on add_comment() set datetime to do shell script "date"
set localtime to do_ruby_script({"require 'time'", "Time.parse('" & datetime & "').strftime('%Y-%m-%d %H:%M:%S +0900:')"}) set msg to "コメントを入力してください。"
set res_text to text returned of (display dialog msg default answer "" with icon note) if res_text ≠ "" then
set comment to localtime & space & res_text
do shell script "echo " & quoted form of (comment) & " >> ~/_time_machine_comment.txt"
my message("", quoted form of comment) end if
end add_comment
on merge_comment_and_install_history() try
set merge_file_list to {¬ "/tmp/install_history.txt", ¬ "/Library/Logs/Software\\ Update.log", ¬ "~/_time_machine_comment.txt"} do shell script "echo " & quoted form of my plist_to_text("/Library/Receipts/InstallHistory.plist") & " > /tmp/install_history.txt"
do shell script "sort -r -k1,2 " & join(merge_file_list, space) & " > /tmp/_time_machine_comment_and_install_history.txt"
--UTF-8のままではクイックルックで表示できなかったので、仕方なくUTF-16に変換した
do shell script "iconv -f UTF-8 -t UTF-16 < /tmp/_time_machine_comment_and_install_history.txt > ~/_time_machine_comment_and_install_history.txt"
on error
do shell script "touch " & join(merge_file_list, space) my message("", "エラーが発生しました。もう一度、実行してみてください。") error -128 --処理を中止するためのエラー
end try
quick_look((path to home folder as text) & "_time_machine_comment_and_install_history.txt") end merge_comment_and_install_history
on plist_to_text(plist_path) tell application "System Events"
tell contents of XML file plist_path
set dictArray to (XML element "plist"'s XML element "array"'s XML elements) end tell
set install_history to {} repeat with dict in dictArray
set dictValue to (dict's XML elements whose name is not "key")'s value
set datetime to dictValue's item 1
set localtime to my do_ruby_script({"require 'time'", "(Time.parse('" & datetime & "') + 9*3600).strftime('%Y-%m-%d %H:%M:%S +0900:')"}) set dictValue's item 1 to localtime
set dictValue to my join(dictValue, space) set dictValue to my replace(dictValue, "missing value", "-") set install_history's end to dictValue
end repeat
--改行コードによるsortコマンドの動作状況: \n...sort_OK, return...sort_NG, \r...sort_NG
my join(install_history, "\n") end tell
end plist_to_text
on quick_look(file_path) tell application "Finder" to activate
tell application "Finder" to select file file_path
tell application "System Events" to keystroke space
end quick_look
--rubyコードを実行して結果を返す
--do_ruby_script({"require 'uri'", "URI.escape(%q|" & "tell application \"System Events\" --ショートカット操作をする限り" & "|)"})
--バックスラッシュのみ,エスケープ\\が必要、それ以外はRubyコードの書き方と同じ
on do_ruby_script(ruby_code) set ruby_code to ruby_code as list
set last_code to ruby_code's last item
set puts_last_code to "puts(" & last_code & ")"
if (count of ruby_code) ≥ 2 then
set pre_code to join(ruby_code's items 1 thru -2, ";") & ";"
else
set pre_code to ""
end if
set shell_code to "ruby -e " & quoted form of (pre_code & puts_last_code) log shell_code
do shell script shell_code
end do_ruby_script
--rubyコードを require 'jcode'; $KCODE='u'; な日本語環境で実行して結果を返す
on do_ruby_jcode_u(ruby_code) do_ruby_script({"require 'jcode'", "$KCODE='u'"} & ruby_code) end do_ruby_jcode_u
--sourceTextをdelimiterでリストに変換する
--split("1,2,3,4", ",")
-- 結果:{"1", "2", "3", "4"}
--AppleScript2.0では、«constant conszkhk»などの拡張属性はサポートしない。
--http://www.seuzo.jp/st/Other/AS2.0.html
on split(sourceText, delimiter) --considering «constant conszkhk»
if sourceText = "" then return {} set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to {delimiter} set theList to text items of sourceText
set AppleScript's text item delimiters to oldDelimiters
return theList
--end considering
end split
--sourceListをdelimiterで区切ったテキストに変換する
--join({"1", "2", "3", "4"}, ",")
-- 結果:"1,2,3,4"
--join({{1, 2}, {3, 4}}, ",")
-- 結果:"1,2,3,4"
--AppleScript2.0では、«constant conszkhk»などの拡張属性はサポートしない。
--http://www.seuzo.jp/st/Other/AS2.0.html
on join(sourceList, delimiter) --considering «constant conszkhk»
set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to {delimiter} set theText to sourceList as text
set AppleScript's text item delimiters to oldDelimiters
return theText
--end considering
end join
--sourceText中の全てのtext1をtext2に置き換える
--replace("abcdefg", "bc", "_bc_")
-- 結果:"a_bc_defg"
on replace(sourceText, text1, text2) join(split(sourceText, text1), text2) end replace
--growlまたはdisplay dialogでメッセージを表示する。
on message(title, msg) try
do shell script "/usr/local/bin/growlnotify " & title & " -m " & quoted form of msg
on error
activate
display alert msg giving up after 1
end try
end message
運用
- コメントは入力しなくてもOK。入力すれば、~/_time_machine_comment.txt に追記される。
- 処理が完了すれば、_time_machine_comment_and_install_history.txt の内容がクイックルックで表示される。
以上で、ホームフォルダ直下には、二つのファイルが生成されている。
- _time_machine_comment_and_install_history.txt
- 以下3つのファイルをまとめたインストール履歴。Time Machineでクイックルックして活用する。
- /Library/Receipts/InstallHistory.plist
- /Library/Logs/Software Update.log
- ~/_time_machine_comment.txt
- _time_machine_comment.txt
- 自分のコメント。テキストエディタで開いて編集することも可能。
これで、Time Machineのコメントもどきファイル、一応完成!ソフトウェアをインストールした時、あるいはTime Machineのバックアップの前に、コメント入力を心掛ける。そうすれば、ソフトウェアのインストール状態を把握するコメント履歴となるのだ。