I have an AppleScript, that executes every night. It mounts a remote volume, moves a set of files to a specific location on that remote volume, and unmounts the remote volume. Works great. It even writes script status out to an event log, and has an idle handler to wait for large file copies to complete. All of this works perfectly, every night.
In the middle of the script, there’s a statement that uses GUI Scripting (which is turned on on that machine)… and there’s where the problem comes in. This single line (well, three lines with the tell statement) works perfectly if I trigger the script manually, and often will work the night after I make some sort of change or tweak to try to get it to work. But other than that, that line just quietly fails, and I can’t figure out why. Here’s the line, in context:
[scripting elements up here that, among other things, selects the correct folder so that it's selected and visible in the Finder]
tell application "System Events"
tell process "Finder" to click (first menu item of menu 1 of menu bar item 3 of menu bar 1 whose name contains DaySpecificFolder)
end tell
That should trigger the “Create Archive of ‘DaySpecificFolder’” menu item every time. Yet it only does sometimes.
Does anyone have any experience with this? Is there anythign to GUI scripting that I need to do to tweak this to work all the time? Is there a better way to get this archive made within this script? Any help or suggestions are appreciated!
maybe you should activate the Finder before choosing a menu item
activate application "Finder"
tell application "System Events"
tell process "Finder" to click (first menu item of menu 1 of menu bar item 3 of menu bar 1 whose name contains DaySpecificFolder)
end tell
Maybe I’m not being clear; I have a whole bunch of scripting before and after this line, and yes, at the moment at which this line occurs, the Finder is activated, the enclosing folder is open, the correct folder is selected - all of this happens every time, quite reliably. It’s just that the GUI scripting line is most often (but not always!) ignored.
I could post the entire script here, if that’s appropriate. It’s not small. Please advise.
OK, I’ve pared this down a little - I’ve removed the error logging and replaced some of the specific variables (like file paths and passwords and such) with [filepath here] kinds of things.
on check_progress()
tell application "Finder"
repeat while ((first window whose class is «class prwd») exists)
delay 5 -- change to higher increment if we need this to be longer
end repeat
end tell
delay 5 -- juuuust in case
end check_progress
----
on run
-- [stuff here to get the date and time]
set DaySpecificFolder to "FMS_Daily_Backup_" & DayNumberOfWeek & "_" & DayOfWeek
ignoring application responses
tell application "ScreenSaverEngine" to quit
end ignoring
-- should kill the screensaver, if it's running
tell application "Finder"
activate
make new Finder window -- just to make debugging a little more visible
mount volume "[IP and name]" as user name "[username]" with password "[password]"
set LocalBackupFolder to folder [filepath_here]
set SourceFolder to folder DaySpecificFolder of LocalBackupFolder
set DestinationParentFolder to folder [filepath_here]
activate
select folder DaySpecificFolder of LocalBackupFolder
end tell
tell application "System Events"
tell process "Finder" to click (first menu item of menu 1 of menu bar item 3 of menu bar 1 whose name contains DaySpecificFolder)
end tell
check_progress() -- Wait for any progress bar to disappear.
tell application "Finder"
-- [stuff here that moves the zip file to the remote volume and trashes the original]
end tell
check_progress() -- Wait for any progress bar to disappear.
tell application "Finder"
duplicate SourceFolder to DestinationParentFolder replacing yes
end tell
check_progress() -- Wait for any progress bar to disappear.
tell application "Finder"
eject "[remote volume here]"
repeat while window 1 exists
close window 1
end repeat
end tell
end run
All of that works, except the “System Events” portion; most often, that part simply fails to execute, though the remainder of the script still executes just fine like clockwork. Sometimes - sometimes - we get a zip file out of it, like we’re supposed to. And if I manually trigger this AppleScript, I’ll get a zip file 100% of the time.
forget this annoying GUI scripting and use a shell command to create the zip file
...
tell application "Finder"
set LocalBackupFolder to [filepath_here]
set SourceFolder to folder DaySpecificFolder of LocalBackupFolder
set fName to name of SourceFolder
end tell
set item_path to quoted form of POSIX path of (SourceFolder as alias)
set destination_path to quoted form of (POSIX path of (LocalBackupFolder as Unicode text) & fName & ".zip")
do shell script ("/usr/bin/ditto -c -k -rsrc --keepParent " & item_path & " " & destination_path)
...
What I can imagine is that you call (the old bugger, ready to retire ;)) Finder too fast again in:
....
select folder DaySpecificFolder of LocalBackupFolder
end tell
tell application "System Events"
tell process "Finder" to click (first menu item of menu 1 of menu bar item 3 of menu bar 1 whose name contains DaySpecificFolder)
end tell
After selecting “select folder DaySpecific…”, the old beast needs some time to get its menu’s updated, otherwise there is no “first menu item… … …”
I suggest to pause a couple of seconds after “select” (don’t pause Finder, but pause your script with tell me to do shell script “Sleep 2” or alike)
Ah - excellent! I was hoping there was a more robust way to go about making the zip archive. The GUI scripting is so very brittle (as I’ve seen).
Question, though: when I use the GUI scripting, I have a progress bar that pops up while the zip is happening, and my idle handler waits based on the presence of that progress window. I’m zipping a couple of gigs of stuff, and that can take longer than AppleScript’s timeout; does OS X tell the AppleScript when the shell script is complete? How does my script know when to continue?