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
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
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
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.
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.
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?
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.
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.
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