Tackling a Club MacStories DMG Workflow Request22 Mar 2016
Club MacStories is a membership value add option provided by the rather popular MacStories.net web site. I’m a Club MacStories member and as such receive the weekly newsletter which contains lots of additional Apple related material and articles. In last week’s newsletter (issue 24) one of the user questions was around automatically attaching and detaching DMGs and whilst a partial solution was provided, the response also invited readers to round it out to complete the last part. I figured I’d give it a go and share what I came up with.
This solution was featured as a response in issue 25 of the Club MacStories newsletter. In the details it stated the following.
Note that Stephen Millard’s solution involves generating a script that sits alongside the DMG that the first Hazel rule mounts. The second script runs 24 hours after the DMG is mounted. If the DMG is ejected before the 24 hours expires, either manually or because you shut down your Mac, you will be left with a stray script file on your Mac’s drive.
I did write back to them to highlight that this is not the case and that the solution actually explicitly takes care of that situation because when it runs the script the Hazel rule moves the script to the trash.
The Details of the Question
The original question was posted by Lucius and was as follows.
Hi, can you create a workflow that will monitor my Downloads folder and will mount any new DMG files, and meanwhile it will eject old DMG files, say older than 24 hours. Thanks. (Lucius)
Noodlesoft’s Hazel is an incredibly useful Mac utility that has a few features, but whose primary purpose is to monitor folders for file changes and carry out actions on those files. This is often used for automated filing (based on file name, file attributes or even content) but the actions engine that powers Hazel is wonderfully wide in scope and with the extensibility of scripting is even more so.
One of the file actions that Hazel offers is to open a file in it’s default application. John’s response to Lucius was to use Hazel to monitor the Downloads folder for files with a DMG file extension and then have it open matching files using this open action to automatically attach the DMG. Unfortunately Hazel did not offer such a simple solution to unattaching and this was where John opened it up to readers.
To my mind Hazel is the perfect choice to tackle this workflow challenge. It can easily be set to monitor the folder and in addition it can also operate on files based upon when they were added to a folder (very handy for automated archival actions). As a result I needed two rules - one to attach the DMG and one to unattach the DMG.
The key for my solution was in noting that when attaching a DMG I wanted to make a note of what mount was added so that I could remove it later. To do this I turned to a little bit of (BASH) shell scripting.
When attaching the DMG rather than using the open in action I used the
hdiutil utility and captured its output to a temporary file. I then
processed the temporary file by dropping lines, removing white space and
finally stripping it down to leave just the name of the volume that was
mounted when the DMG file was attached.
With the name known I then used the script to create a new shell script to unmount that particular volume (if it exists - i.e. hasn’t already been unmounted) in effect unattaching the DMG.
Finally I remove any temporary files that may have been generated.
The script content is shown below.
#Mount the DMG hdiutil attach "$*" > "$*.tmp1" # Grab the name of the volume so we can build an unmount script # Get the last line of the output from the mounting operation tail -1 "$*.tmp1" > "$*.tmp2" # Change all spaces into tabs with multiple spaces being squeezed down to a single tab tr -s ' ' '\t' < "$*.tmp2" > "$*.tmp1" # With a tab separated line remove the first two columns cut -d' ' -f3- "$*.tmp1" > "$*.tmp2" # In case we have any tabs in our final volume name we need to convert them back to spaces sed -i -e 's/ / /g' "$*.tmp2" #Create a shell script to unmount the DMG volume_to_unmount=`cat "$*.tmp2"` shell_script="/Users/stephen/Downloads/DMG_Test/$(date "+%Y-%m-%d-%H.%M.%S")_unmount.sh" shell_script_content="hdiutil detach \"$volume_to_unmount\"" echo "#!/bin/bash" > "$shell_script" echo "if mount | grep \"on $volume_to_unmount\" > /dev/null" >> "$shell_script" echo "then" >> "$shell_script" echo "$shell_script_content" >> "$shell_script" echo "fi" >> "$shell_script" chmod +x "$shell_script" # Clean up rm "$*.tmp1" rm "$*.tmp2" rm "$*.tmp2-e"
In my testing (and as you may have noted from the two rule screen shot
above) I actually set-up Hazel to use a sub-folder of my Downloads
folder. If you use this script you will want to modify it to match your
Downloads folder. Simply replace ‘
with the UNIX file path to the folder you are monitoring (e.g.
/Users/Lucius/Downloads/’) - or you could monitor an entirely
different folder if you wished.
This should then be added into a Hazel rule. Note that when embedding the script you don’t need to include a #! as the type of script is specified in Hazel.
When this rule is activated the DMG gets mounted and an unmount script is generated. I also set the colour attribute on the DMG file to grey as a visual cue that Hazel had run the auto-attach processing on it.
Here’s an example case where I downloaded a DMG into my test folder and it was processed by the attach Hazel rule. The DMG file is coloured grey and a script file is created alongside it.
The content of the script file generated is as follows.
The second Hazel rule is used to monitor the appropriate folder for the unmount script and when it identifies that a script was added over 24 hours ago it will run the script and then remove it.
For testing this I didn’t actually want to wait 24 hours each time so I decided that if I tagged a script with the red colour attribute that I’d also like it to be picked up.
The second rule for me therefore looked like this.
The script attached to this rule simply needs to run the script file it has identified. I use a simple bash script to do this.
In my testing this set-up worked without issue. It coped with DMGs where the volume mounted was a different name to the DMG file, had spaces in it, didn’t try to dismount mounts that had been ejected and where a DMG was attached multiple times it unmounted the correctly named volume. It hasn’t been tested to destruction but I think it is in a relatively stable state and is ready for practical use.
I’m dropping a note to the MacStories folks to let them know I’ve posted what I think is a solution to Lucius’ issue; but hopefully you and others will find this useful either as a workflow or as an idea for how to do something of your own. If you do find it useful or create something derivative from it please leave a comment and let me and everyone else know exactly how you’ve made use of it.