Applescript requiring a "repeat" loop won't quit

Hello,

First off I’d like to apologize if this specific problem has been tackled elsewhere. I’ve searched through the forums here and elsewhere (Apple Discussion Forums, etc.) and can’t quite seem to get exactly what I need.

Also, I am fairly new to Applescript. So… if my issue has a simple solution, I won’t be surprised. :slight_smile:

Allrighty… with that said, here’s what’s going on:

  • I’m manually scripting something that I should be able to do, but can’t, with Folder Actions. The reason I can’t do it with Folder Actions is because it involves files being copied over a network into a local folder, and Folder Actions doesn’t pick up on the fact that they’ve been copied in.
  • The intention of the script is to monitor the modification date of the folder in question (the “Drop” folder), and run a routine that sends all new files to a Compressor droplet when it detects that the modification date of the folder has changed (indicating the arrival of new files). I’ve also built in a routine to make sure that it doesn’t send partially-copied files to Compressor.

The simplified version of my script is as follows:


on run
	tell application "Finder"
		set the drop_folder to "Mac OS:Users:cvw:Compressor:ProRes422:Drop" as alias
		set x to drop_folder
		set modDate to modification date of x
		
		repeat
			
			try
				
				set dateCheck to modification date of x
				if modDate ≠ dateCheck then
					
					-- in the original code, this runs a routine that picks up every new file placed into my Drop folder and sends it to a Compressor droplet.
					
					set modDate to dateCheck
					
				end if
				delay 10
				
			on error
				delay 5
			end try
			
		end repeat
	end tell
end run

This script, as it stands, works perfectly. I can run it from the Script editor or I can save it out as an application, and it will successfully handle all files I throw at it.

However, as the title of my post would suggest, my problem is that the script simply refuses to quit. Whether I hit Cmd-Q, select Quit from the app menu, or attempt a shutdown/restart/log off, it just sits there and I have to force quit it from the force quit panel.

Now… in the research I’ve done, I keep seeing that this problem can frequently be fixed by using an idle handler, in a stay-open application, instead of a repeat loop. I gave that a shot but I could only get it to work when I enclosed all of my existing script in an idle handler (and turning off the repeat loop). Unfortunately, this disabled the functionality of my script because part of my script relies on a continuous update of the modification date checker (at the end of the script, the modDate is updated, then checked against an updated dateCheck, then updated again, then checked again, etc.). Inside the idle handler, the entire script would run once each time it was called, not being able to take advantage of the repeat loop to check the modification date on each repeat.

If there’s any way to stick an idle handler within the “tell” block, that might do it… basically just swap out the existing repeat loop for an idle handler. Or that might be impossible and I might be talking gibberish.

I’ve tried a number of “on quit” blocks, to no avail (which again I believe is the result of the CPU being hogged by the repeat loop… or something along those lines). For example, I’ve stuck the following code at the end of my script:


on quit
	beep
	return
end quit

… the beep just making sure that the script responds when I tell it to quit. And sure enough, every time I hit Cmd-Q, it beeped, so it was running my “on quit” block… it just didn’t quit. And I’ve replaced “return” with “error -128”, “error number -128”, and “continue quit”… none of them worked.

And again, this is meant to be a script that runs in the background. I can’t have it toss up a dialog during the normal operation of the script asking if it should quit. I suppose, if it would work, I could have it bring up a dialog asking “Are you sure you want to quit?” when the quit command was given… if that would somehow help things.

Well, I hope this all made enough sense. Sorry if I’m a bit long-winded. If you’ve got any questions to help clarify what my issue is, please let me know. I can also post the entirety of the script if that would help matters.

And thank you so much for taking time to read this and hopefully toss some insight my way. :slight_smile:

Focussing on just the core problem, the script won’t quit because it’s stuck in the repeat loop which doesn’t have an exit condition of any kind. You should be using an “on idle” script to accomplish this. In simplest terms, an on idle handler is a script application saved as stay open (to be quit from the Dock) with the following parts:


on run
-- do setup stuff if required. May be omitted
end run

on idle
-- this runs immediately after the run handler if an explicit one exists
-- Here you do whatever is supposed to happen periodically.
return X -- where X is in seconds and represents the delay before the next cycle.
end idle

on quit
-- not necessary but useful for cleanup or saving stuff
-- do cleanup
continue quit -- this MUST be the last line of a quit handler.
end quit

Here’s a recent example to study: Read Nigel Garvey’s contributions

Oh, wow. Thanks so much, Adam! That totally did the trick. I guess (among other things) I hadn’t gotten it clear exactly how the different handlers (run, idle) work, and how exactly I should structure them. At first I was getting a couple errors mid-script but that was only because I’d forgotten to make my variables global. I’ve fully implemented the new code based on your outline and it’s working perfectly. Here’s the adjusted (simplified) code that I’m using now:

(the dialogs, of course, are just for my reference; they don’t exist in the full version of this script)


global x
global modDate
global dateCheck

on run
	tell application "Finder"
		set the drop_folder to "Mac OS:Users:cvw:Compressor:ProRes422:Drop" as alias
		set x to drop_folder
		set modDate to modification date of x
		
		display dialog "Applet running."
	end tell
end run

on idle
	tell application "Finder"
		try
			
			set dateCheck to modification date of x
			if modDate ≠ dateCheck then
				
				display dialog "New file detected."
				-- in the original code, this runs a routine that picks up every new file placed into my Drop folder and sends it to a Compressor droplet.
				
			end if
			set modDate to dateCheck
		on error
			return 5
		end try
		
	end tell
	return 10
end idle

on quit
	continue quit
end quit

In the meantime, I’m going to go read up on some of the tutorials and such here, to learn more about efficiently programming in Applescript. Thanks again!!

Hi;

Since you don’t do anything in the quit handler, you can omit it entirely, and your globals can be inside the run handler as long as they precede their use anywhere.

I have mostly stopped using folder actions (because of the problems you mentioned) and use launchd instead. You can google for tutorials on launchd to learn more, but it can watch a folder for you and when something changes in that folder it can run an applescript.

Basically you create a plist file in your ~/Library/LaunchAgents folder. Here’s a copy of one I made to watch my downloads folder. It runs an applescript whenever I download a file so you can easily modify this to watch your folder and run your applescript.

Change “/Users/hmcshane/Downloads/” to the path to your folder. Change “/Users/hmcshane/Library/Scripts/moveFiles.scpt” to the path to your applescript. Change “com.hamsoft.moveFiles” to whatever you want to name this plist file and name your plist file “com.your.newname.plist”. You will need to logout of your user account after adding the plist to the LaunchAgents folder for it to start working.

I think you’ll find that launchd will properly work when files are added to your folder. The big advantage for you will be that you won’t need an applescript running constantly to find if files have been added to the folder. Good luck.

<?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>WatchPaths</key>
	<array>
		<string>/Users/hmcshane/Downloads/</string>
	</array>
	<key>ProgramArguments</key>
	<array>
		<string>osascript</string>
		<string>/Users/hmcshane/Library/Scripts/moveFiles.scpt</string>
	</array>
	<key>Label</key>
	<string>com.hamsoft.moveFiles</string>
</dict>
</plist>

I am a recent launchd convert as well.

Here are some shell commands that will be useful too:

To load regulus6633’s launch agent:

launchctl load -w "/Users/danbert/Library/LaunchAgents/com.hamsoft.moveFiles.plist"

to unload it:

launchctl unload -w "/Users/danbert/Library/LaunchAgents/com.hamsoft.moveFiles.plist"

to list loaded agents:

launchctl list