SSブログ

ドラッグ&ドロップでフォルダを同期するフォルダアクション [プログラミング]

ちょっと時間があいてしまった。

いきさつ、なにがやりたいか、技術的な問題は何か、といったことは前回説明したけど、今日は実際に動作するApple Scriptを示して、その使い方を説明する。

こういうのってどうだろ?面白いかな?

これはなにか?

ドラッグ&ドロップでフォルダの内容を同期するフォルダアクション。

バックアップしたいフォルダを、バックアップ先のフォルダのコマンド+オプションキーを同時に押しながらドラッグ&ドロップする。

1029dragAndDropping.png

しばらくすると「同期が完了しました」というダイアログ

1029synced.png

が現れて、
  • バックアップ先のフォルダにないものはコピーする
  • 古いファイルは置き換える
ということを行う。
ただし、バックアップ元とバックアップ先のフォルダの名前は、かならず同じにしておくことが必要。

やりかた

まず、ユーティリティフォルダにある「Apple Scriptエディタ」を起動する。

1029ased.png

新規ファイルを作ってこのページの下の方にあるスクリプトをコピペする。
下の図に示したフォルダ(自分の「ライブラリ」のなかの「Scripts」の「Folder Action Scripts」)に適当な名前(ここではrsyncFolder)をつけて保存する。

1029script.png

フォルダがない場合はこの通りの正確な名前で作っておく。

バックアップ元ではなく、バックアップ先のフォルダアクションを設定する。

1029contextMenu.png

さっき保存したスクリプトが表示されるはずなので、それを選んで「関連付ける」ボタンを押す。

1029folderAction.png

これで完了。

もちろん、ローカルHDD内の別の場所にあるフォルダだけでなく、ローカルとUSBメモリのあいだや、ネットワーク上のフォルダでも動作する。ただし、ローカル以外のドライブがHFS+でフォーマットされていないと、フォルダアクションの設定はドライブを取り出すと忘れられてしまうので要注意。

うごかないとき

 1.コマンド+オプションキーを押しながらバックアップ先のフォルダの中にドロップしているか?

このとき、ポインタが「エイリアスを作る」場合の形(曲がった矢印)になっているか確認。

 2.スクリプトを保存したフォルダの名前があっているか?

正確でないと、「フォルダアクション設定」でスクリプトが表示されない。

 3.rsyncがインストールされているか?

実際の同期作業はrsyncというunixコマンドを使っている。ターミナルから
% ls /usr/bin/rsync
と入力して(%はプロンプトで入力は「ls」以降)、なにも表示されなければ、rsyncは存在しない。Mac OS Xでは標準でインストールされているはずなので、あとから消されたと考えられる。rsyncだけインストールするか、OS再インストール。

なにをしているか

フォルダにファイルを追加したときに実行されるon adding folder itemsフォルダアクションを使っている。オプションキーとコマンドキーを押しながらドロップすると、エイリアスファイルがそのフォルダの中に作られる。

スクリプトからFinderを呼んで
  • ドロップされたのはエイリアスファイルか?
  • そのエイリアスファイルの実体はフォルダか?
  • その名前がフォルダアクションの設定されているフォルダと同じか?
を調べている。そうでなかったらなにもせずに終わる(通常のFinder操作と見なす)。その通りだったら、ドロップされたエイリアスの実体からフォルダアクションが設定されたフォルダへrsyncコマンドを使ってバックアップする。終わったらエイリアスファイルを削除する。これだけで、あとはエラー処理をやってるだけ。

フォルダアクションはFinderの動作のあとに起動されるので、エイリアスファイルをドロップするのがミソ。また、rsyncは正常に終わったら何も出力しないので、それでエラーがあったかどうか判断をしている。

スクリプト

コンパイル済みのApple Scriptをダウンロードしてもらってもいいんだけど、バイトコードが含まれてしまうので、スクリプトだけをここに示す。ひとつのスクリプトにせずに、いくつかに分割した方が読みやすかった。けどもういいや。

ところで、Apple Scriptってローカライズはどうやってやるんだろう。スクリプトに日本語の文字列が埋まってしまう。Cocoaみたいな方法ってあるのかしら。
property nameOfTheAuther : "decafish"
property rsyncFolderLogName : "rsyncFolder"

on adding folder items to thisFolder after receiving aliasList
    try
        set droppedItem to the first item of aliasList
        
        -- Finderからファイルの情報を得る
        tell application "Finder"
            set nameOfThisFolder to name of thisFolder
            set droppedKind to kind of droppedItem
            set isAliasOfFolder to false
            set nameOfOriginal to ""
            if droppedKind is equal to "エイリアス" then
                set droppedOriginal to original item of droppedItem
                set nameOfOriginal to name of droppedOriginal
                if class of droppedOriginal is equal to folder then
                    set droppedOriginalFile to droppedOriginal as alias
                    set isAliasOfFolder to true
                end if
            end if
        end tell
        
        if isAliasOfFolder and (nameOfOriginal is equal to nameOfThisFolder) then
            set thisPath to POSIX path of thisFolder
            set droppedPath to POSIX path of droppedOriginalFile
            set rsyncLogPath to ("/tmp/" & rsyncFolderLogName & ".log")
            set rsyncCommand to ("/usr/bin/rsync -a " & droppedPath & " " & thisPath & " > " & rsyncLogPath)
            
            -- rsyncコマンド発行
            do shell script rsyncCommand
            set rsyncLogFile to (POSIX file rsyncLogPath) as alias
            tell application "Finder"
                if (size of rsyncLogFile) is not equal to 0 then
                    set moveLogDestination to ("~/Library/Logs/" & rsyncFolderLogName & ".log")
                    do shell script ("mv " & rsyncLogPath & " " & moveLogDestination)
                    error ("同期に失敗しました。詳細はコンソールから" & rsyncFolderLogName & "を確認して下さい。")
                else
                    do shell script ("rm " & rsyncLogPath)
                end if
                delete droppedItem
            end tell
            display dialog ("\"" & nameOfThisFolder & "\"フォルダを同期しました。")
        (*
        else
            display dialog "do nothing"
        *)
        end if
    on error errStr number errorNumber
        if isAliasOfFolder then
            tell application "Finder"
                delete droppedItem
            end tell
        end if
        display dialog errStr
        error errStr number errorNumber
    end try
end adding folder items to

nice!(0)  コメント(4)  トラックバック(0) 

nice! 0

コメント 4

モリヤン

こんばんは。
エイリアスかどうかの判定は、alias of (info for (item 1 of aliasList)) の真偽値を見るようにすれば、Finder の言語設定に依存しないでいけるんじゃないかと思います。
AppleScript 久しぶり過ぎ…。いまは他にも方法あるのかもしれませんが、とりあえず。
by モリヤン (2012-11-01 22:52) 

decafish

コメントありがとうございます。
Apple Script初心者なので助かりました。そう言う言い回しがあるんですね。
ダイアログの中の文字列には、なにかいいローカライズの方法があるんでしょうか?
by decafish (2012-11-05 20:50) 

モリヤン

info for は標準附属の拡張関数みたいなもので、スクリプト編集プログラム…じゃなかった AppleScriptエディタでは、ファイル>用語説明を開く...で、StandardAdditions.osax を開くとドキュメントが確認できます。
display dialog で表示する文字列のローカライズについては、AppleScriptエディタで書くようなスクリプトでは僕は聞いたことありません。Xcode で AppleScript を使ってスタンドアロンアプリを作るときには、他言語同様の方法があるんじゃないかと思いますが、詳しくは知りません。お役に立てませんー。すみませんー。
by モリヤン (2012-11-06 23:33) 

decafish

詳しい解説までしていただいてお手数をおかけしました。理解しました。ありがとうございます。
やっぱりApple Scriptは古いMac OSのスタイルを引き継いでいるんでしょうか。
OS Xのバンドルによるローカライズのしくみは使う上では簡単でいいんですが、リソースフォークよりは少なくともシステムは難しいことをしているので、古いApple Scriptと馴染みがわるいということなのかしら。
by decafish (2012-11-07 21:01) 

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

献立10/29献立10/30 ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。