Finderの「サーバへ接続」画面において,+
ボタンを押すと,「よく使うサーバ」にサーバのURLを追加できます。
ここに登録したいサーバがたくさんあるとき,コマンドで一括追加したくなります。
かつては,
$ /usr/bin/sfltool add-item -n "hoge" com.apple.LSSharedFileList.FavoriteServers "smb://hoge@192.168.0.100"
のようなコマンドで「よく使うサーバ」リストに追加ができました。これにより,~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.FavoriteServers.sfl2
にサーバのエントリが追記されたのです。
これをシェルスクリプトにしておけば,よく使うサーバを大量に一括登録できたのですが,なんと,macOS 10.13 以降,sfltool
コマンドに add-item
というサブコマンドは廃止され,復活の予定はないそうです。
そこで,com.apple.LSSharedFileList.FavoriteServers.sfl2
にエントリを追加するには,結構面倒なプログラミングが必要になりました。Swiftコードで書くとこのようになります(エラー処理はテキトーです)。
import Foundation
let error = NSError(domain: "error", code: -1, userInfo: nil)
let sflURL = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Library").appendingPathComponent("Application Support").appendingPathComponent("com.apple.sharedfilelist").appendingPathComponent("com.apple.LSSharedFileList.FavoriteServers.sfl2")
func readFavoriteServers() throws -> (items: NSArray, properties: NSDictionary, existingURLs: [URL]) {
guard let dict = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(Data(contentsOf: sflURL)) as? NSDictionary,
let items = dict["items"] as? NSArray,
let properties = dict["properties"] as? NSDictionary else { throw error }
// 型情報
// dict: NSDictionary<NSString*,id>*
// items: NSArray<NSDictionary<NSString*,id>*>*
// properties: NSDictionary<NSString*,id>*
let existingURLs: [URL] = items.compactMap { item in
var stale: Bool = false
guard let item = item as? NSDictionary,
let data = item["Bookmark"] as? Data,
let url = try? URL(resolvingBookmarkData: data, bookmarkDataIsStale: &stale) else { return nil }
return url
}
return (items: items, properties: properties, existingURLs: existingURLs)
}
func addFavoriteServer(_ paths: String...) throws {
guard let (oldItems, properties, existingURLs) = try? readFavoriteServers() else { throw error }
let uniqueURLs = Set(existingURLs)
print("Existing items: " + existingURLs.description)
let newItems = NSMutableArray(array: oldItems)
paths.forEach { path in
guard let encodedPath = path.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
let url = URL(string: encodedPath),
let bookmark = try? url.bookmarkData(options: [], includingResourceValuesForKeys: nil, relativeTo: nil) else { return }
let entry: [String:Any] = [
"Name": path,
"Bookmark": bookmark,
"uuid": UUID().uuidString,
"visibility": 0,
"CustomItemProperties": NSDictionary()
]
if uniqueURLs.contains(url) {
print("Skip: " + path)
} else {
newItems.add(entry)
print("Add: " + path)
}
}
let newDict: [String:Any] = [
"items": newItems,
"properties": properties
]
do {
try NSKeyedArchiver.archivedData(withRootObject: newDict, requiringSecureCoding: true).write(to: sflURL)
} catch let e {
throw e
}
}
// main routine
do {
try addFavoriteServer("smb://192.168.100.1","smb://192.168.100.2","smb://192.168.100.3","smb://192.168.100.4")
let (_, _, existingURLs) = try readFavoriteServers()
print("New items: " + existingURLs.description)
print("Restart your Mac for the changes to take effect!")
} catch let e {
print(e.localizedDescription)
}
このコードでは,最後のメインルーチンのところで
addFavoriteServer("smb://192.168.100.1","smb://192.168.100.2","smb://192.168.100.3","smb://192.168.100.4")
とすることで,サーバのURLを一括追加しています。addFavoriteServer
は,引数に与えられたURLたちを,既存のサーバURLと照合して,既存のURLはスキップして,新しいURLのみだけを順に追加していきます。
この変更をFinderのUI上に反映させるためには,macOSの再起動が必要でした。(Finderの再起動だけで済むという話もありましたが,自分の環境ではOS全体を再起動しないと変更が反映されませんでした。)