Script stops unexpectedly after 'delete' command

Hi there,

with the kind help of some of the members here I managed to ‘bake’ a folder action that does the following:

It analyses the name of each file that is added to the folder.
Based on some part of the file name it identifies a certain folder an a server.
And within this folder it looks for a matching flag file in the folder substructure.
Then it moves the original file to the folder that contains the flag file.

It works like a charm, but:
If no matching flag file is found the script is supposed to move the original file to a special folder called ‘orphans’.

This works as well. But each time this happens the script stops unexpectedly and does not continue to work on the remaining files in the watched folder.

I have no clue why the script stops. If there is no orphan in the queue the script manages to move every file of the watched folder without stopping.

Has anybody an idea?

Please see the script below…:

Thank you very much for any help
traegheitsmoment


use scripting additions
use framework "Foundation"

on adding folder items to this_folder after receiving these_items
	repeat with i from 1 to number of items in these_items
		set sourceFile to item i of these_items
		set searchPath to "/Volumes/space/data/projects/" -- this should be path to folder on server
		set ATID to AppleScript's text item delimiters
		set AppleScript's text item delimiters to {":"}
		set sourceFileName to text item -1 of (sourceFile as text)
		set AppleScript's text item delimiters to {"-"}
		set theProjektPrefix to text item 1 of sourceFileName
		set theCompanyName to text item 2 of sourceFileName
		set AppleScript's text item delimiters to ATID
		set targetProjektFolder to getProjektfolder(searchPath, theProjektPrefix)
		set targetProjektFolder to (targetProjektFolder as string) & theProjektPrefix & "-team:"
		set locationFileName to theProjektPrefix & "-" & theCompanyName & "-huhu.txt"
		set theCheckFile to (getFlag(targetProjektFolder, locationFileName) & sourceFileName) as string
		set targetFolder to getFlag(targetProjektFolder, locationFileName)

		tell application "System Events"

			if exists file (theCheckFile) then
				set targetFolder to alias "Macintosh HD:Users:me:Documents:deposit:double:"
				tell application "Finder"
					move sourceFile to targetFolder with replacing
				end tell
			else
				tell application "Finder"
					move sourceFile to targetFolder without replacing
					delete sourceFile

-- This is where the script stops if the file was moved to the orphans folder.

				end tell
			end if
		end tell
		
	end repeat
	
	display dialog "Es wurden " & (number of items in these_items) & " Files moved."
end adding folder items to


on getProjektfolder(theFolder, theProjektPrefix)
	
	set theFolder to current application's |NSURL|'s fileURLWithPath:theFolder
	set fileManager to current application's NSFileManager's defaultManager()
	set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsSubdirectoryDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
	set thePred to current application's NSPredicate's predicateWithFormat_("(path MATCHES[c] %@)", (".*?/" & theProjektPrefix & ".*"))
	set theFiles to (folderContents's filteredArrayUsingPredicate:thePred)

	if (count theFiles) = 0 then errorDialog("No location files were found")
	return theFiles
end getProjektfolder

on getFlag(theFlagFolder, theName)
	set theFlagFolder to POSIX path of theFlagFolder
	set theFlagFolder to current application's |NSURL|'s fileURLWithPath:theFlagFolder
	set fileManager to current application's NSFileManager's defaultManager()
	set folderContents to (fileManager's enumeratorAtURL:theFlagFolder includingPropertiesForKeys:{} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects()
	
	set thePred to current application's NSPredicate's predicateWithFormat_("(lastPathComponent ==[c] %@)", theName)
	set theFiles to (folderContents's filteredArrayUsingPredicate:thePred)

	if (count theFiles) = 0 then

-- This is where the script checks for the orphans and returns the path to the orphans folder.	

		return ("Macintosh HD:Users:me:Documents:deposit:orphans:")
	else
		return ((theFiles's URLByDeletingLastPathComponent) as alias)
	end if
	
	
end getFlag

on errorDialog(dialogText)
	display dialog dialogText buttons {"OK"} default button 1 cancel button 1 with title "" with icon stop
end errorDialog



Rubbish reply withdrawn with apologies. :confused:

Instead of using this…

tell application "System Events"

			if exists file (theCheckFile) then
				set targetFolder to alias "Macintosh HD:Users:me:Documents:deposit:double:"
				tell application "Finder"
					move sourceFile to targetFolder with replacing
				end tell
			else
				tell application "Finder"
					move sourceFile to targetFolder without replacing
					delete sourceFile

-- This is where the script stops if the file was moved to the orphans folder.

				end tell
			end if
		end tell
		
	end repeat

Try using this instead…

tell application "System Events" to set fileExists to file (theCheckFile) exists
tell application "Finder"
	if fileExists then
		set targetFolder to alias "Macintosh HD:Users:me:Documents:deposit:double:"
		set theSourceFile to move sourceFile to targetFolder with replacing
	else
		set targetFolder to alias "Macintosh HD:Users:me:Documents:deposit:orphans:"
		set theSourceFile to move sourceFile to targetFolder without replacing
		delete sourceFile
	end if
end tell

@ Nigel
Thank you for the hint. I haven’t tested this yet, but I will try tomorrow, when I’m back in the office.

@ wch1zpink
Thank you very much as well. I also haven’t tested it, but as far as I understand it, the result of the script might not match the purpose…

The purpose of the original script is to…

copy the respective file to a certain folder in the substructure of an external server.

To find the destination folder the script analyses the file name and based on the file name searches for a matching flag file.

If…
no flag file is found… then the file should be moved in a local folder called orphans.

If…
there already exists a file with the same file name, the respective file should be moved in local folder called ‘double’.

It seems to me, that your code wouldn’t copy the file to the destination folder on the external server in any case.

@ KniazidisR
Thank you very much as well.
I tried your code. Maybe I’ve done something wrong. It moves the first file in the queue to the ‘double’ folder even if it doesn’t exist in the destination folder on the server and then stops.
I will do some more testing tomorrow…

Thank you all again for your time,
traegheitsmoment

That’s a common mistake. If you modify the size of a list while being enumerated the indexes change and you could run out of index.

An alternative is the repeat with … in loop. In conjunction with the get keyword the references to the items don’t change

on adding folder items to this_folder after receiving these_items
	repeat with sourceFile in (get these_items)
        ...

My script contained an error again. So I decided to remove it too.

But it seemed strange to me that according to Nigel Garvey and StefanK, after the Finder deletes a certain file/folder, the list of AppleScript aliases changes. That would be a bad surprise for me. After all, the list of aliases belongs to AppleScript, not Finder, so it shouldn’t change.

Perhaps my next test is wrong - it does not confirm that the list has changed. I even added 10 seconds delay to let Finder finish its deleting:


tell application "Finder"
	set thisItems to items of home as alias list --> 57 aliases
	log (count of thisItems) --> (*57*)
	delete (item 51 of thisItems) -- "OneDrive" folder on my Mac
end tell
delay 10
log (count of thisItems) --> --> (*57*)

Warning: put deleted item back from Trash, when finish the test.

Tip: to understand the reason for the failure of original script, the OP should test it as a script, not a hot folder. I cannot do this instead of OP, as I do not know the exact structure of OP folders.


tell application "Finder" to set these_items to items of (choose folder) as alias list
set hotFolder to choose folder with prompt "Choose Hot folder"

adding folder items to this_folder after receiving these_items


on adding folder items to this_folder after receiving these_items
    -- do something
end adding folder items to

You’re right! My apologies to all. ‘theseItems’ is a list, not the contents of a folder. I’ve now zapped my response in post #2.

I must be getting old. :confused:

Thank you KniazidisR,
I’m not sure if I did it correctly because when I start the modified script and choose two folders I stops and tells me ‘the variable “this folder” is not defined’

Maybe I didn’t modify the script correctly. I changed it like that…


use scripting additions
use framework "Foundation"

tell application "Finder" to set these_items to items of (choose folder) as alias list
set hotFolder to choose folder with prompt "Choose Hot folder"

adding folder items to this_folder after receiving these_items


on adding folder items to this_folder after receiving these_items
	
	
	repeat with sourceFile in (get these_items)
.
.
.
.
end repeat
end adding folder items to


Can you tell me a little bit about how it should work and how we can find the reason of the failure of the original script? I’m not sure what the first folder I need to choose is for and what the second folder (hot filder) is meant for.

Thanks again,
traegheitsmoment

Thank you Stefan,

I tried that and it works as good as the original script but still shows the same error. It stops every time if there is an orphan found after it moves the orphan correctly to the orphans folder.

If there is no orphan found, than the whole queue is being worked off.

My fault. Replace


set hotFolder to choose folder with prompt "Choose Hot folder"

with


set this_folder to choose folder with prompt "Choose Hot folder"

Hot folder is folder were arrive the files. Other folder provides files itself, which arrive to hot folder.

Thanks again,

I tried this as a script like you described it.
When I start it, it works for a while and then it renders the following error:

error “URLByDeletingLastPathComponent of «class ocid» id «data optr0000000060D8680000600000» kann nicht in Typ alias umgewandelt werden.” number -1700 from URLByDeletingLastPathComponent of «class ocid» id «data optr0000000060D8680000600000» to alias

The error refers to the getFlag subroutine, particularly to the 5th line of the following part:


set theFiles to (folderContents's filteredArrayUsingPredicate:thePred)
	if (count theFiles) = 0 then
		return ("Macintosh HD:Users:cm:Documents:Donath Bickel:db orphans:")
	else
		return ((theFiles's URLByDeletingLastPathComponent) as alias)
	end if


Does this help in any way to check out the underlying problem?

Hi. Again.

Try to replace this:


return ((theFiles's URLByDeletingLastPathComponent) as alias)

with this:


return ((item 1 of theFiles)'s URLByDeletingLastPathComponent()) as alias

NOTE: basically, I can’t understand what you try return in the else case: 1) list of aliases, 2) 1 alias, 3) list of HFS paths, 4) 1 HFS path (like in the case count theFiles = 0.

My last snippet returns 1 alias (case 2). If you try return 1 HFS path (case 4) then replace as alias with as text. If you want 1) or 3) then you should create empty list, and use repeat loop to add to it aliases or HFS paths, one by one.

Hi.

Looking at the original script more carefully and at more leisure today, I see a number of potential snagging points:

set AppleScript's text item delimiters to {":"}
set sourceFileName to text item -1 of (sourceFile as text)

sourceFileName will be set to an empty string if the “file” is in fact a folder or a package. It’s safer to use an application to extract the file name or else add a check to the TIDs process which gets the penultimate text item instead if the path ends with a colon.

set targetProjektFolder to getProjektfolder(searchPath, theProjektPrefix)
set targetProjektFolder to (targetProjektFolder as string) & theProjektPrefix & "-team:"

The getProjektfolder() handler returns an NSArray containing either an NSURL or nothing. Coercing such a result to ‘string’ isn’t a good idea.

 tell application "Finder"
	move sourceFile to targetFolder without replacing
	delete sourceFile
	
	-- This is where the script stops if the file was moved to the orphans folder.
	
end tell


	-- Skip ahead to :

if (count theFiles) = 0 then
	
	-- This is where the script checks for the orphans and returns the path to the orphans folder.	
	
	return ("Macintosh HD:Users:me:Documents:deposit:orphans:")
else
	return ((theFiles's URLByDeletingLastPathComponent) as alias)
end if

The “orphans” result returned at the end is text. It should be an alias like the other result so that the Finder doesn’t try to move the file to text instead of to a folder!

If the “orphans” folder’s on the same computer as the drop folder, and sourceFile is successfully moved to it, the file will be relocated from the drop folder to the “orphans” folder and the alias in the sourceFile variable will change to track it. So 1) there’ll be no need to delete the file from the drop folder (since it will no longer be there) and 2) deleting sourceFile will delete the file from its new location in the the “orphans” folder.

@all
Thank you all for your input. I appreciate very much. Based on your feedback I decided to restructure the loops and conditions to make debugging more easy. I haven’t finished yet but I’m sure it will help.

@KniazidisR

Thank you very much. I think you are right. The last thing you found in the script might be one of the things that may cause trouble.

@Nigel
Thank you very much as well for your insight. I think this will help and I learned alot thanks to your explanation.

Cheers
traegheitsmoment

Here’s an attempt to revamp the code, with a few comments to explain things. I haven’t been able to test it in context though, so there are no guarantees that it’ll actually do the job.

use AppleScript version "2.5" -- Mac OS X 10.11 (El Capitan) or later. (For NSURL to alias coercion.)
use scripting additions
use framework "Foundation"

on adding folder items to this_folder after receiving these_items
	set searchPath to "/Volumes/space/data/projects/" -- this should be path to folder on server
	repeat with i from 1 to (count these_items)
		set sourceFile to item i of these_items
		tell application "System Events" to set sourceFileName to name of sourceFile
		set ATID to AppleScript's text item delimiters
		set AppleScript's text item delimiters to {"-"}
		set theProjektPrefix to text item 1 of sourceFileName
		set theCompanyName to text item 2 of sourceFileName
		set AppleScript's text item delimiters to ATID
		
		set targetProjektFolder to (getProjektfolder(searchPath, theProjektPrefix) as text) & theProjektPrefix & "-team:" -- HFS path.
		set locationFileName to theProjektPrefix & "-" & theCompanyName & "-huhu.txt"
		set targetFolder to getFlag(targetProjektFolder, locationFileName) -- Alias.
		set checkFilePath to (targetFolder as text) & sourceFileName -- HFS path.
		
		tell application "System Events"
			
			if (file checkFilePath exists) then
				set targetFolder to alias "Macintosh HD:Users:me:Documents:deposit:double:"
				-- System Events version of the Finder's 'move … with replacing':
				if (file sourceFileName of targetFolder exists) then delete file sourceFileName of targetFolder
				move sourceFile to targetFolder
			else
				-- The original Finder code here specified moving the file 'without replacing', which would
				-- throw an error if a file with the same name already existed at the destination, so …
				try
					move sourceFile to targetFolder
				end try
				(* Or:
				if not (file sourceFileName of targetFolder exists) then move sourceFile to targetFolder
				*)
				-- Delete the file from the drop folder if it couldn't be moved or was 'moved' to the server and still exists at this end too.
				if (file sourceFileName of this_folder exists) then delete file sourceFileName of this_folder
			end if
		end tell
		
	end repeat
	
	display dialog "Es wurden " & (number of items in these_items) & " Files moved."
end adding folder items to


on getProjektfolder(rootPath, theProjektPrefix)
	set theFolder to current application's |NSURL|'s fileURLWithPath:rootPath
	set fileManager to current application's NSFileManager's defaultManager()
	(* set folderContents to (fileManager's enumeratorAtURL:theFolder includingPropertiesForKeys:{} options:((current application's NSDirectoryEnumerationSkipsPackageDescendants) + (current application's NSDirectoryEnumerationSkipsSubdirectoryDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)) errorHandler:(missing value))'s allObjects() *)
	-- Since you're skipping both package and subfolder contents, you can shorten the commented-out line above to this:
	set folderContents to fileManager's contentsOfDirectoryAtURL:theFolder includingPropertiesForKeys:{} options:(current application's NSDirectoryEnumerationSkipsHiddenFiles) |error|:(missing value)
	
	set thePred to current application's NSPredicate's predicateWithFormat_("(path MATCHES[c] %@)", (".*?/" & theProjektPrefix & ".*"))
	set theFiles to (folderContents's filteredArrayUsingPredicate:thePred) as list -- 'as list' gives an AppleScript list of AppleScript 'file' ojects.
	
	if (count theFiles) = 0 then errorDialog("No location files were found") -- NB. The errorDialog() handler stops the script immediately when the dialog's dismissed.
	return item 1 of theFiles -- Otherwise return the first (and only) 'file' (hopefully actually a folder) in the list.
end getProjektfolder

on getFlag(theFlagFolder, theName)
	set theFlagFolder to POSIX path of theFlagFolder
	set theFlagFolder to current application's |NSURL|'s fileURLWithPath:theFlagFolder
	set fileManager to current application's NSFileManager's defaultManager()
	set searchOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants) ¬
		+ (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set folderContents to (fileManager's enumeratorAtURL:theFlagFolder includingPropertiesForKeys:{} options:(searchOptions) errorHandler:(missing value))'s allObjects()
	
	set thePred to current application's NSPredicate's predicateWithFormat_("(lastPathComponent ==[c] %@)", theName)
	set theFiles to (folderContents's filteredArrayUsingPredicate:thePred) -- This is an NSArray containing 0 or more NSURLs.
	
	if (count theFiles) = 0 then
		
		-- This is where the script checks for the orphans and returns the path to the orphans folder.	
		
		return ("Macintosh HD:Users:me:Documents:deposit:orphans:") as alias -- 'as alias' assumes this folder already exists.
	else
		-- NB. firstObject(), and the parentheses after 'URLByDeletingLastPathComponent'.
		return (theFiles's firstObject()'s URLByDeletingLastPathComponent()) as alias
	end if
end getFlag

on errorDialog(dialogText)
	display dialog dialogText buttons {"OK"} default button 1 cancel button 1 with title "" with icon stop
end errorDialog

Hi Nigel,

thank you very much for your time.
I’m looking forward and I’m going to test it as soon as I’m in the office tomorrow…

Cheers
traegheitsmoment

Just a short update…

The script seems to fail to move the file to the targetFolder.
I haven’t figured out why because it computes the targetFolder correctly.

I will let you know when I find out more…