Keeping a "on adding folder items" script from calling itself

Hi guys,

I’m working on a folder action script that moves items dropped in a folder after making sure their names are 31 characters or less.

It all works well, prompting a user for a new name if the current one is too long then renaming files, but once it does the rename it immediately triggers itself again (i.e. the folder sees it as a new item and starts the script over).

Is there a way to not let the script trigger a new “on adding folder items” event?

Thanks!

Here are the offending parts of the script:

on adding folder items to thefolder after receiving theaddeditems

	repeat with eachItem in theaddeditems
		-- check name length. Over 31 characters (with extension) and system barfs
		set theFileInfo to info for eachItem -- get info for the incoming file
		set currentName to the name of theFileInfo
		set n to the number of characters of the currentName
		if n > 31 then
			try
				set the ext to text ((offset of "." in currentName)) thru -1 of currentName
				set the new_name to ((characters 1 thru 26 of currentName) as string) & ext
			on error the error_message number the error_number
				display dialog "Error: " & error_message
			end try
			tell me to display dialog "File name too long." & return & "It can only be 31 characters in length. Please rename:" default answer new_name buttons {"Cancel", "OK"} default button 2
			copy the result as list to {new_name, button_pressed}
			if the button_pressed is "Cancel" then return 0
			set_item_name(eachItem, new_name)
		end if
		-- do actual useful work with the files here
end adding folder items to

on set_item_name(this_item, new_item_name)
	tell application "Finder"
		set the parent_container_path to (the container of this_item) as text
		if not (exists item (the parent_container_path & new_item_name)) then
			try
				set the name of this_item to new_item_name
			on error the error_message number the error_number
				if the error_number is -59 then
					set the error_message to "This name contains improper characters, such as a colon (:)."
				else --the suggested name is too long
					set the error_message to error_message -- "The name is more than 31 characters long."
				end if
				tell me to display dialog the error_message default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
				copy the result as list to {new_item_name, button_pressed}
				if the button_pressed is "Skip" then return 0
				my set_item_name(this_item, new_item_name)
			end try
		else --the name already exists
			tell me to display dialog "This name is already taken, please rename." default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
			copy the result as list to {new_item_name, button_pressed}
			if the button_pressed is "Skip" then return 0
			my set_item_name(this_item, new_item_name)
		end if
	end tell
end set_item_name

You need to move the file before you change the name in any way, or the script will be called again because it’s a folder action and changing the name makes the folder see the file as a new file.

Hi CWT,

Thanks for the reply. I was hoping to avoid another copy of the file, but I see the simple logic in this.

Cheers!

Sometimes you can check to see if your script has already altered the file name, and skip it in that case. I don’t see how you’d do that in this case though.

Forgive a noob, but I’m floundering in my file copying skills…

The following code gives me an Error: Can’t make container of file “:‘:Users:joeuser:tmp:filename.txt’” into type string

set newPath to the quoted form of ("/Users/joeuser/tmp/" & currentName)
do shell script ("ditto " & item_path & " " & newPath) -- copy the file into a temp directory before renaming
set theFile to POSIX file newPath -- create an object pointing to the new file
set the parent_container_path to (the container of theFile) as text

The “container” line is just to proof that the theFile object is okay (which it obviously isn’t). In actuallity I then pass theFile to set_item_name.

I know I’m make a beginner’s mistake here somewhere. Any insight appreciated.

BTW, is there a better language reference than http://developer.apple.com/documentation/applescript/conceptual/applescriptlangguide?

Thanks!

New path is already a POSIX path. You don’t need to set theFile or parent_container_path.

Assuming you’re doing this as part of the folder action script above, I think you’re looking for something like this:

set thefile to quoted form of POSIX path of eachitem

The variable: eachitem is already an alias of an existing file, so getting the POSIX path is no problem.

No, there are some guides (books), but there’s no better reference at all

Yes, this is still the same folder action. parent_container_path was just a test of the object (theFile is an object, not just the path, right?).

For some reason I thought I had to pass an object, not just a path to set_item_name…? Will try it now.

Thanks, CWT & Stefan!

No luck. Thanks for your patience, guys…

set_item_name generates the following error:
Can’t make «class ctnr» of “Users/admin/tmp/filename.txt” into type string

Here’s the script as it stands now (note the non-op section is triggered when a file name is over 31 characters long, everything else seems to work well):


property destination_foldername : "/Volumes/Internal/Test"
on adding folder items to thefolder after receiving theaddeditems
	repeat with eachItem in theaddeditems
		set theFileInfo to info for eachItem -- get info for the incoming file
		-- check name length. Over 31 characters (with extension) and system barfs
		set currentName to the name of theFileInfo
		set the item_path to the quoted form of the POSIX path of eachItem
		set the destination_directory to POSIX path of the destination_foldername
		set the destination_path to the quoted form of (destination_directory & "/" & (name of the theFileInfo))
		set n to the number of characters of the currentName
		if n > 31 then
			try
				set newPath to the quoted form of ("/Users/admin/tmp/" & currentName)
				do shell script ("ditto " & item_path & " " & newPath)
				-- build a truncated name to suggest
				set the ext to text ((offset of "." in currentName)) thru -1 of currentName
				set the new_name to ((characters 1 thru 27 of currentName) as string) & ext
			on error the error_message number the error_number
				display dialog "Error: " & error_message
			end try
			tell me to display dialog "File name too long." & return & "It can only be 31 characters in length. Please rename:" default answer new_name buttons {"Cancel", "OK"} default button 2
			copy the result as list to {new_name, button_pressed}
			if the button_pressed is "Cancel" then return 0
			
			try
				set_item_name(newPath, new_name) -- THIS IS WHERE THINGS STOP PLAYING NICE
			on error the error_message number the error_number
				display dialog "Error: " & error_message
			end try
		end if
		-- do the actual work with the file here
	end repeat
end adding folder items to

-- the following comes from Apple's own "Trim File Names.scpt"
on set_item_name(this_item, new_item_name)
	tell application "Finder"
		--activate
		set the parent_container_path to (the container of this_item) as text -- THIS LINE GENERATES THE ERROR
		if not (exists item (the parent_container_path & new_item_name)) then
			try
				set the name of this_item to new_item_name
			on error the error_message number the error_number
				if the error_number is -59 then
					set the error_message to "This name contains improper characters, such as a colon (:)."
				else --the suggested name is too long
					set the error_message to error_message -- "The name is more than 31 characters long."
				end if
				--beep
				tell me to display dialog the error_message default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
				copy the result as list to {new_item_name, button_pressed}
				if the button_pressed is "Skip" then return 0
				my set_item_name(this_item, new_item_name)
			end try
		else --the name already exists
			--beep
			tell me to display dialog "This name is already taken, please rename." default answer new_item_name buttons {"Cancel", "Skip", "OK"} default button 3
			copy the result as list to {new_item_name, button_pressed}
			if the button_pressed is "Skip" then return 0
			my set_item_name(this_item, new_item_name)
		end if
	end tell
end set_item_name

Thanks, again, for any insight!
Charlie

newPath (in the handler this_item) is a literal string (actually a quoted POSIX path).
First of all you can’t get the name of a string and AppleScript works with HFS paths (colon separated)

I ended up abandoning my call to Apple’s set_item_name and went with the following which works for me:


property destination_foldername : "/Volumes/Internal/Test"
on adding folder items to thefolder after receiving theaddeditems
	repeat with eachItem in theaddeditems
		set theFileInfo to info for eachItem -- get info for the incoming file
		-- check name length. Over 31 characters (with extension) and system barfs
		set currentName to the name of theFileInfo
		set the item_path to the quoted form of the POSIX path of eachItem
		set the destination_directory to POSIX path of the destination_foldername
		set the destination_path to the quoted form of (destination_directory & "/" & (name of the theFileInfo))
		set n to the number of characters of the currentName
		if n > 31 then
			try
				set the new_name to currentName
				repeat while the number of characters of the new_name > 31
					set the ext to text ((offset of "." in currentName)) thru -1 of currentName
					set the new_name to ((characters 1 thru 27 of currentName) as string) & ext
					tell me to display dialog "File name too long." & return & "It can only be 31 characters in length. Please rename:" default answer new_name buttons {"Cancel", "OK"} default button 2
					copy the result as list to {new_name, button_pressed}
					if the button_pressed is "Cancel" then return 0
				end repeat
				
				set newPath to the quoted form of ("/Users/admin/tmp/" & new_name)
				do shell script ("ditto " & item_path & " " & newPath)
				
				set item_path to newPath
				set destination_path to the quoted form of (destination_directory & "/" & new_name)
			on error the error_message number the error_number
				display dialog "Error: " & error_message
			end try
		end if
		
		-- copy the file to the share
		do shell script ("ditto " & item_path & " " & destination_path)
		
	end repeat

Thanks, guys!

Charlie