Skip to content

Instantly share code, notes, and snippets.

@github0013
Last active November 6, 2016 13:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save github0013/62f05da7835275373e7eeff322d7dc64 to your computer and use it in GitHub Desktop.
Save github0013/62f05da7835275373e7eeff322d7dc64 to your computer and use it in GitHub Desktop.
how to auto-mount an osx time machine sparsebundle over a nas drive

installation

  1. save the .rb file in ~/bin
  2. save the .plist file in ~/Library/LaunchAgents
  3. run brew install terminal-notifier terminal-notifier
  4. change .plist parameters
  5. run launchctl load ~/Library/LaunchAgents/local.timemachine.drive.plist

It will show a notification when mount is completed.

notification

<?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">
<dict>
<key>Label</key>
<string>local.timemachine.drive</string>
<key>ProgramArguments</key>
<array>
<string>ruby</string>
<!-- change these parameters -->
<string>FULL_PATH_TO_THE_RUBY_FILE_|_YOU_CAN_SAVE_IN_HOME_BIN_DIR</string>
<string>FULL_PATH_TO_YOUR_NAS_SAMBA_DIRECTORY_|_EX_//guest:@192.168.1.1/NAS_DRIVE_MOUNT_NAME</string>
<string>NAS_DRIVE_MOUNT_NAME_|_EX_samba_drive</string>
<string>TIME_MACHINE_MOUNT_NAME_|_EX_tm_drive</string>
<string>/Volumes/NAS_DRIVE_MOUNT_NAME/PATH/TO/YOUR.sparsebundle</string>
<!-- change these parameters -->
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>60</integer>
</dict>
</plist>
require "pathname"
require "shellwords"
class AutoTimeMachineDrive
class << self
def mount!
new.mount_timemachine_drive
rescue => ex
notify(ex.message)
end
def notify(message)
options = {
group: self.to_s,
title: self.to_s,
message: message,
sound: :default
}
system "/usr/local/bin/terminal-notifier #{option_line options}"
end
def option_line(*options)
options.collect do |element|
case element
when Hash
element.collect{|k, v| "-#{k} #{Shellwords.escape v}"}.join " "
when String, Pathname
element.to_s
end
end.join " "
end
end
def initialize
@smb_url, @smb_mount_name,
@time_machine_mount_name, @time_machine_sparsebundle_file_path = ARGV
end
def mount_timemachine_drive
return if tm_mount_point.exist?
ensure_smb_mount_point do
ensure_tm_mount_point_is_missing do
mount_timemachine_sparsebundle_file
self.class.notify("#{time_machine_mount_name} mounted.") if tm_mount_point.exist?
end
end
end
private
attr_reader :smb_url, :smb_mount_name,
:time_machine_mount_name, :time_machine_sparsebundle_file_path
def smb_mount_point
Pathname "/Volumes/#{smb_mount_name}"
end
def tm_mount_point
Pathname "/Volumes/#{time_machine_mount_name}"
end
def ensure_smb_mount_point
prepare_smb_mount_point do
mount_samba
yield
end
end
def ensure_tm_mount_point_is_missing
yield unless tm_mount_point.exist?
end
def prepare_smb_mount_point
if smb_mount_point.exist?
if [smb_mount_point_not_network_drive?, smb_mount_point_not_empty?].all?
return self.class.notify "unempty smb_mount_point (#{smb_mount_point}) exists. make sure this directory is removed before running."
end
else
smb_mount_point.mkdir
end
yield
end
def smb_mount_point_not_network_drive?
`mount`.lines.select{|line| line.include? smb_mount_point.to_s }.count == 0
end
def smb_mount_point_is_network_drive?
not smb_mount_point_not_network_drive?
end
def smb_mount_point_not_empty?
smb_mount_point.children.count > 0
end
def mount_samba
return if smb_mount_point_is_network_drive?
system "mount_smbfs #{self.class.option_line(smb_url, smb_mount_point)}"
end
def mount_timemachine_sparsebundle_file
system "hdiutil attach #{self.class.option_line(
{mountpoint: tm_mount_point},
time_machine_sparsebundle_file_path
)}"
end
end
AutoTimeMachineDrive.mount!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment