Script stopped working after Sierra update

Hi,

I have a folder action script which prompts the user to rename an added file and then open the newly named file. I use it all the time (numerous times per day) and have it attached to my screenshots folder (because I’m usually documenting bugs during GUI development and uploading them to bitbucket issue descriptions).

The script utilizes non-trivial renaming applescript code I found on the internet that works around the folder action triggering a new rename event when the folder thinks the newly renamed file is a new file which should trigger another folder action. It does this by first labeling the file with a color label (e.g. set the label index of this_item to the special_label_index).

My suspicion is that the bug has to do with the setting of the label index. The file’s label gets successfully updated, as does the name, but the file object thereafter becomes unable to be used to open the file. E.g. this line of code no longer works:

open this_item

I was able to get around this issue by executing a shell script:

`do shell script (“open '” & (POSIX path of this_folder) & “/” & newName & “'”)

Note, I had to use POSIX path of this_folder because POSIX path of this_item would not work either.

I suspect the file’s label change as the culprit because in my test code, I eliminated the label change and (while the script asked me to change the file name twice - and the second time I didn’t change the already changed file name) it renamed the file successfully and also successfully opened the file using open this_item.

I created a simplified version of the script (though I kept the more complex methods I obtained off the web. This version is the broken version which calls open this_item. The file gets renamed, but does not open. Note, if you try this, you should use a file that you know the open command will succeed on, like an image or a text document:

property item_check_delay_time : 2
property folder_check_delay_time : 3
property special_label_index : 7

on adding folder items to this_folder after receiving added_items
	set the added_items to my check_added_items(the added_items)
	repeat with i from 1 to number of items in added_items
		set this_item to item i of added_items as alias
		tell application "Finder"
			set theExtension to name extension of this_item
			set this_file_name to text 1 through -((count theExtension) + 2) of (get name of this_item)
			display dialog "Name Screenshot" default answer this_file_name buttons {"Cancel", "OK"} default button 2
			set the replacement_string to the text returned of the result
			set the name of this_item to (replacement_string & "." & theExtension as string)
			open this_item
		end tell
	end repeat
	return
end adding folder items to

on check_added_items(the added_items)
	-- check the transfer status of every added file to determine
	-- if each file has completed being moved into the attached folder
	set the notbusy_items to {}
	repeat with i from 1 to the number of items in the added_items
		set this_item to (item i of the added_items)
		if my check_busy_status(this_item) is false then
			set the end of the notbusy_items to this_item
		end if
	end repeat
	return the notbusy_items
end check_added_items

on check_busy_status(this_item)
	-- a folder can contain items partially transfered
	-- this routine will wait for all the folder contents to transfer
	if the last character of (this_item as text) is ":" then
		set the check_flag to false
		repeat
			-- look for any files within the folder that are still transferring
			tell application "Finder"
				try
					set the busy_items to the name of every file of the entire contents of this_item ¬
						whose file type begins with "bzy"
				on error
					set the busy_items to {}
				end try
			end tell
			if the check_flag is true and the busy_items is {} then return false
			-- pause for the indicated time
			delay the folder_check_delay_time
			-- set the flag and check again
			set the check_flag to true
		end repeat
	else -- the passed item is a single file, suitcase, clipping, etc.
		-- check the label of the item. If it is the marked label, then it's already been processed so ignore.
		tell application "Finder"
			if (the label index of this_item) as integer is the special_label_index then
				return "ignore"
			end if
		end tell
		set the check_flag to false
		repeat
			tell application "Finder"
				set the item_file_type to the file type of this_item
			end tell
			if the check_flag is true and ¬
				the item_file_type does not start with "bzy" then
				tell application "Finder"
					set the label index of this_item to the special_label_index
				end tell
				-- allow the Finder time to change the label
				delay the item_check_delay_time
				return false
			else if the item_file_type does not start with "bzy" then
				-- set the flag and check again
				set the check_flag to true
			end if
			-- pause for the indicated time
			delay the item_check_delay_time
		end repeat
	end if
end check_busy_status

I am guessing that Sierra changed something WRT labels in the finder that broke certain functions of the file object in applescript. Or maybe it works, but just differently.

Oh yeah, one more thing, I wrapped the code in a try block and displayed the error string. I didn’t save it, but I’m certain it said “Parameter error” and that there was not as associated error code in the error string.

I tested the behavior of labels with this simple script.

on adding folder items to this_folder after receiving added_items
	set this_item to added_items's item 1
	tell application "Finder"
		set name of this_item to "truc.jpg"
		set label index of this_item to 5
		delay 0.2
		open this_item
	end tell
end adding folder items to

I dropped a jpeg file on the folder to which the script is attached.

The renamed file correctly got the purple label and was open in Preview.

It seems that, as long as you don’t mix labels (old objects) and tags (new objects), there is no difference in the way labels are treated.

Are you sure that the dropped files continue to have a file type property ?
For instance, here, the file type of PDF files is missing value

I never saw file types starting with “bzy” so I can’t check if the newly created ones continue to have this attribute.

I used my good old tip to check folder action scripts.

I edited yours as :

property item_check_delay_time : 2
property folder_check_delay_time : 3
property special_label_index : 7

--on adding folder items to this_folder after receiving added_items
set this_folder to ((path to desktop as text) & "  dossier") as alias
tell application "Finder"
	set added_items to files of this_folder
end tell
set the added_items to my check_added_items(the added_items)
repeat with i from 1 to number of items in added_items
	set this_item to item i of added_items as alias
	tell application "Finder"
		set theExtension to name extension of this_item
		set this_file_name to text 1 through -((count theExtension) + 2) of (get name of this_item)
		display dialog "Name Screenshot" default answer this_file_name buttons {"Cancel", "OK"} default button 2
		set the replacement_string to the text returned of the result
		set the name of this_item to (replacement_string & "." & theExtension as string)
		open this_item
	end tell
end repeat
return
--end adding folder items to

on check_added_items(the added_items)
	-- check the transfer status of every added file to determine
	-- if each file has completed being moved into the attached folder
	set the notbusy_items to {}
	repeat with i from 1 to the number of items in the added_items
		set this_item to (item i of the added_items)
		if my check_busy_status(this_item) is false then
			set the end of the notbusy_items to this_item
		end if
	end repeat
	return the notbusy_items
end check_added_items

on check_busy_status(this_item)
	-- a folder can contain items partially transfered
	-- this routine will wait for all the folder contents to transfer
	if the last character of (this_item as text) is ":" then
		set the check_flag to false
		repeat
			-- look for any files within the folder that are still transferring
			tell application "Finder"
				try
					set the busy_items to the name of every file of the entire contents of this_item ¬
						whose file type begins with "bzy"
				on error
					set the busy_items to {}
				end try
			end tell
			if the check_flag is true and the busy_items is {} then return false
			-- pause for the indicated time
			delay the folder_check_delay_time
			-- set the flag and check again
			set the check_flag to true
		end repeat
	else -- the passed item is a single file, suitcase, clipping, etc.
		-- check the label of the item. If it is the marked label, then it's already been processed so ignore.
		tell application "Finder"
			if (the label index of this_item) as integer is the special_label_index then
				return "ignore"
			end if
		end tell
		set the check_flag to false
		repeat
			tell application "Finder"
				set the item_file_type to the file type of this_item
			end tell
			if the check_flag is true and ¬
				the item_file_type does not start with "bzy" then
				tell application "Finder"
					set the label index of this_item to the special_label_index
				end tell
				-- allow the Finder time to change the label
				delay the item_check_delay_time
				return false
			else if the item_file_type does not start with "bzy" then
				-- set the flag and check again
				set the check_flag to true
			end if
			-- pause for the indicated time
			delay the item_check_delay_time
		end repeat
	end if
end check_busy_status

So I was able to see the history.

I got :

tell application "Finder"
	get every file of alias "SSD 500:Users:yvankoenig:Desktop:  dossier:"
		--> {document file "candidat.jpg" of folder "  dossier" of folder "Desktop" of folder "yvankoenig" of folder "Users" of startup disk}
	get document file "candidat.jpg" of folder "  dossier" of folder "Desktop" of folder "yvankoenig" of folder "Users" of startup disk
		--> "SSD 500:Users:yvankoenig:Desktop:  dossier:candidat.jpg"
	get label index of document file "candidat.jpg" of folder "  dossier" of folder "Desktop" of folder "yvankoenig" of folder "Users" of startup disk
		--> 0
	get file type of document file "candidat.jpg" of folder "  dossier" of folder "Desktop" of folder "yvankoenig" of folder "Users" of startup disk
		--> missing value
	get file type of document file "candidat.jpg" of folder "  dossier" of folder "Desktop" of folder "yvankoenig" of folder "Users" of startup disk
		--> missing value
	set label index of document file "candidat.jpg" of folder "  dossier" of folder "Desktop" of folder "yvankoenig" of folder "Users" of startup disk to 7
		--> 7
	get document file "candidat.jpg" of folder "  dossier" of folder "Desktop" of folder "yvankoenig" of folder "Users" of startup disk
		--> alias "SSD 500:Users:yvankoenig:Desktop:  dossier:candidat.jpg"
	get name extension of alias "SSD 500:Users:yvankoenig:Desktop:  dossier:candidat.jpg"
		--> "jpg"
	get name of alias "SSD 500:Users:yvankoenig:Desktop:  dossier:candidat.jpg"
		--> "candidat.jpg"
	display dialog "Name Screenshot" default answer "khonnard" buttons {"Cancel", "OK"} default button 2
		--> {button returned:"OK", text returned:"trump"}
	set name of alias "SSD 500:Users:yvankoenig:Desktop:  dossier:candidat.jpg" to "president.jpg"
		--> "president.jpg"
	open alias "SSD 500:Users:yvankoenig:Desktop:  dossier:president.jpg"
end tell

The file got the grey label and opened flawlessly.

I can’t resist to edit scripts which pass in front of me.

Here is an edited version. You will be able to compare it with the preceding one.

property item_check_delay_time : 2
property folder_check_delay_time : 3
property special_label_index : 7

--on adding folder items to this_folder after receiving added_items
set this_folder to ((path to desktop as text) & "  dossier") as alias
tell application "Finder"
	set added_items to files of this_folder
end tell
set the added_items to my check_added_items(the added_items)
repeat with this_item in added_items
	set this_item to this_item as alias
	tell application "Finder"
		set theExtension to name extension of this_item
		set this_file_name to text 1 through -((count theExtension) + 2) of (get name of this_item)
		display dialog "Name Screenshot" default answer this_file_name buttons {"Cancel", "OK"} default button 2
		set replacement_string to text returned of result
		set name of this_item to (replacement_string & "." & theExtension)
		open this_item
	end tell
end repeat
return
--end adding folder items to

on check_added_items(added_items)
	-- check the transfer status of every added file to determine
	-- if each file has completed being moved into the attached folder
	set notbusy_items to {}
	repeat with this_item in added_items
		if my check_busy_status(this_item) is false then
			set the end of the notbusy_items to (contents of this_item)
		end if
	end repeat
	return the notbusy_items
end check_added_items

on check_busy_status(this_item)
	-- a folder can contain items partially transfered
	-- this routine will wait for all the folder contents to transfer
	if last character of (this_item as text) is ":" then
		set check_flag to false
		repeat
			-- look for any files within the folder that are still transferring
			tell application "Finder"
				try
					set busy_items to name of every file of entire contents of this_item ¬
						whose file type begins with "bzy"
				on error
					set busy_items to {}
				end try
			end tell
			if check_flag is true and busy_items is {} then return false
			-- pause for the indicated time
			delay folder_check_delay_time
			-- set the flag and check again
			set check_flag to true
		end repeat
	else -- the passed item is a single file, suitcase, clipping, etc.
		-- check the label of the item. If it is the marked label, then it's already been processed so ignore.
		tell application "Finder"
			if (label index of this_item) as integer is special_label_index then
				return "ignore"
			end if
		end tell
		set check_flag to false
		repeat
			tell application "Finder"
				set item_file_type to file type of this_item
			end tell
			if item_file_type does not start with "bzy" then
				if check_flag then
					tell application "Finder"
						set label index of this_item to special_label_index
					end tell
					-- allow the Finder time to change the label
					delay item_check_delay_time
					return false
				else
					-- set the flag and check again
					set check_flag to true
				end if
			end if
			-- pause for the indicated time
			delay item_check_delay_time
		end repeat
	end if
end check_busy_status

Yvan KOENIG running Sierra 10.12.1 in French (VALLAURIS, France) mercredi 16 novembre 2016 21:05:17

Well, that’s a good test to have done. There goes my theory.

And yeah, I never dug that deeply into the code I got which uses that ‘bzy’ (presumably short for “busy”) file type check. I saw that when I was debugging and assumed that the finder puts that as the type temporarily while a file is being copied and changes it to the actual file type upon finishing… like when a downloading file appears either greyed out and a little progress bar appears in its icon?

I don’t know about consistency of the file type property. Is that something I can explicitly set?

It’s interesting that there are 2 things that break here: POSIX path of this_item and open this_item. Changing the label and changing the name appear to happen successfully. We’ve demonstrated that changing only the name still allows the file to be opened (I didn’t provide that code, nor did I save it). We’ve also demonstrated that changing the label allows the file to be open successfully. So to rule out the combo, I wrote this test script:

on adding folder items to this_folder after receiving added_items
	set this_item to added_items's item 1
	tell application "Finder"
		set label index of this_item to 5
		set the name of this_item to "test.png"
		delay 0.2
		open this_item
	end tell
end adding folder items to

and dropped a PNG into it. It worked. So I’m more baffled as to the script problem.

I looked into ‘bzy’. Apparently it is (or was?) a file type setting to indicate that a file is “busy” (e.g. in the process of being copied). I found this quote: “The Finder will treat any file whose type is set to zero or to a type within the range 'bzy ', ‘bzy!’, …, ‘bzy?’ as a busy file…”. I assume that the bzy checks are working because the file gets labeled and the name changes (though I admittedly haven’t tried dropping a big file or folder in).

So now a new theory… perhaps it has something to do with the label check? I was playing around with the test script and I noticed that a file can now have multiple (color) labels. The script definitely treats the files as if they can only have one label…

OK, so I wrapped the test code in a try block and the error I get is definitely: “Finder got an error: Parameter error.”.

I ran a number of other tests and discovered that if you don’t rename the file, it opens just fine, which is really weird:

property item_check_delay_time : 2
property folder_check_delay_time : 3
property special_label_index : 7

on adding folder items to this_folder after receiving added_items
	set the added_items to my check_added_items(the added_items)
	repeat with i from 1 to number of items in added_items
		set this_item to item i of added_items as alias
		tell application "Finder"
			set theExtension to name extension of this_item
			set this_file_name to text 1 through -((count theExtension) + 2) of (get name of this_item)
			display dialog "Name Screenshot" default answer this_file_name buttons {"Cancel", "OK"} default button 2
			set the replacement_string to the text returned of the result
			--set the name of this_item to (replacement_string & "." & theExtension as string)
			open this_item
		end tell
	end repeat
	return
end adding folder items to

on check_added_items(the added_items)
	-- check the transfer status of every added file to determine
	-- if each file has completed being moved into the attached folder
	set the notbusy_items to {}
	repeat with i from 1 to the number of items in the added_items
		set this_item to (item i of the added_items)
		if my check_busy_status(this_item) is false then
			set the end of the notbusy_items to this_item
		end if
	end repeat
	return the notbusy_items
end check_added_items

on check_busy_status(this_item)
	-- a folder can contain items partially transfered
	-- this routine will wait for all the folder contents to transfer
	if the last character of (this_item as text) is ":" then
		set the check_flag to false
		repeat
			-- look for any files within the folder that are still transferring
			tell application "Finder"
				try
					set the busy_items to the name of every file of the entire contents of this_item ¬
						whose file type begins with "bzy"
				on error
					set the busy_items to {}
				end try
			end tell
			if the check_flag is true and the busy_items is {} then return false
			-- pause for the indicated time
			delay the folder_check_delay_time
			-- set the flag and check again
			set the check_flag to true
		end repeat
	else -- the passed item is a single file, suitcase, clipping, etc.
		-- check the label of the item. If it is the marked label, then it's already been processed so ignore.
		tell application "Finder"
			if (the label index of this_item) as integer is the special_label_index then
				return "ignore"
			end if
		end tell
		set the check_flag to false
		repeat
			tell application "Finder"
				set the item_file_type to the file type of this_item
			end tell
			if the check_flag is true and ¬
				the item_file_type does not start with "bzy" then
				tell application "Finder"
					set the label index of this_item to the special_label_index
				end tell
				-- allow the Finder time to change the label
				delay the item_check_delay_time
				return false
			else if the item_file_type does not start with "bzy" then
				-- set the flag and check again
				set the check_flag to true
			end if
			-- pause for the indicated time
			delay the item_check_delay_time
		end repeat
	end if
end check_busy_status

I wonder if this could be some sort of security update issue? I’m at a loss.

I see you responded again (or edited, rather) while I was composing. Let me look it over and get back to you.

I don’t think so. My guess is that they no longer use the “bzy*” file type. They may be using “brok” instead. But file types are finally dying, so I suggest you move away from them entirely.

Well it appears that your edits work, but only when run as a script from the editor. When you change it back to a folder action, it doesn’t work again.

If you think it has to do with “bzy”, then why does the file get opened when all you do is not rename the file in the original example I posted? Even if they stopped using “bzy”, the code only checks that the type is not (or doesn’t start with) “bzy”. I added a 2 second delay to test if it was an issue with them changing from bzy to something else. 2 seconds should have been more than sufficient to wait for the copy to finish, yet I still got the parameter error.

I’ll try adding a check for “brok” tomorrow and see if that fixes it. I still feel though like something more is amiss and that we haven’t quite nailed it down.

Thanks for the assistance.

I said it was my guess – I didn’t really test the code. You were thinking it was to do with labels, and I thought you were on the wrong track. When that bzy code was written, every file had a file type; today many do not.

Whatever, a test here suggests bzy is no longer used. I suggest you use a test for when file size has stabilized instead – that’s what folder actions themselves use.

Here is a sample code showing how you may check that the file is really available.
Once again, the ASObjC code is borrowed from Shane Stanley.

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

on adding folder items to this_folder after receiving added_items
	say "point 1"
	set this_item to added_items's item 1
	
	say "point 2"
	set startDate to current application's NSDate's |date|() -- do stuff you want to time in here, eg
	say "point 3"
	set oldSize to {-20}
	say "point 4"
	set itsPosixPath to POSIX path of this_item
	say itsPosixPath
	repeat
		say "point 6"
		set newSize to my returnSizeFor:itsPosixPath
		if newSize = oldSize then exit repeat
		copy newSize to oldSize
	end repeat
	say "point 7"
	set timeDiff to startDate's timeIntervalSinceNow()
	set the clipboard to "That took " & (-timeDiff as real) & " seconds."
	tell application "Finder"
		set theExtension to name extension of this_item
		set this_file_name to text 1 through -((count theExtension) + 2) of (get name of this_item)
		set label index of this_item to 5
		set the name of this_item to "beurk." & theExtension
		open this_item
	end tell
end adding folder items to


on returnSizeFor:POSIXPath # get the size
	set aURL to current application's |NSURL|'s fileURLWithPath:POSIXPath -- make URL
	set {theResult, theSize} to aURL's getResourceValue:(reference) forKey:(current application's NSURLFileSizeKey) |error|:(missing value)
	if theSize = missing value then return {} -- because when there are none, it returns missing value
	return theSize as list
end returnSizeFor:

Oops, I missed a detail.

As it behaves since the beginning of folder action scripts, renaming an item in the targeted folder is interpreted by the process as the dropping of a new item. It’s why - exactly as Apple engineers did in samples delivered with the system in old times, for my own needs, I move the dropped files in an auxiliary folder with the new name. This way the folder action script is not triggered twice as it is with the script posted here.

Yvan KOENIG running Sierra 10.12.1 in French (VALLAURIS, France) jeudi 17 novembre 2016 10:54:19