Folder Action across a network

Hello,

I have a Folder Action script that opens every file dropped into a folder file in Photoshop, modifies it and saves it to a new location and moves the origianl file out of the way.

I based this script on the example script called “convert - PostScript to PDF.scpt”.

it works fine as long as the files dropped into the folder are copied to the folder from the same machine. If they are copied from the network the the script is triggered before the file is copied completely. then the script grinds with a photoshop error because the file is corrupt. :frowning:

what’s the best way to make sure the file is complete?

watch that the modification date of the file has at least a certain agemay be?

I remeber that folder actions in mac os 9 had a built in mechanism to avoid this situation ( file-in-use-flag ). But i suppose that osx doesn’t have the file-in-use-flag anymore.

Thank you for your suggestions.

jc

Here’s what I use in a folder action that’s attached to my download folder.

repeat
	set size_check1 to size of (info for file_)
	do shell script "sleep 10"
	set size_check2 to size of (info for file_)
	if size_check1 is equal to size_check2 then exit repeat
end repeat

– Rob

This seems to work for me (although it’s a bit more CPU intensive):

set the_file to "path:to:file"
my check_busy(the_file)

on check_busy(the_file)
	repeat
		if file type of (get info for (the_file as alias)) is not "brok" then return
	end repeat
end check_busy

Jon

thank you jon and rob.

these are very fine solutions. actually jons is faster i think

now i have a problem with photoshop. it needs to be frontmost all the time (??? i believe) in order to sucessfully process pictures using

do scrtipt “my Action” from “default actions”

is there a good solution for that?

sheerz

jc

Jon,
Your code doesn’t appear to work for me on OS X 10.2.8 when downloading files (via Safari). What does file type “brok” relate to?

couzteau,
I’m glad Jon’s code works for you. One reason that it’s faster is because it goes into a continuous loop. My code uses 10 second delays to reduce demands on the CPU. :slight_smile:

– Rob

Rob is correct on this, but I like the file type check better than the size check because if there is network congestion, it may take more than 10 seconds for data to download and, as such, your code would return a false positive. If you wanted to reduce cycle times in my script, you could also add a delay in the repeat loop.

Hmm, I didn’t test with a download, I tested with a Finder copy. (Going back and testing with a Safari download, while downloading, the file type was “”. This would break my code if you were testing on a download as opposed to a Finder copy.) I’m not sure when Apple changed this but what I did was to write a script that grabbed a file’s attributes while it was being copied (I did this locally with a large file). Then, when the file was finished, I did it again. During the copy, the file type was “brok” and then, when the copy was done, it reverted back to its proper code. I’m using 10.3.2 and that’s all I tested on. In the “get info” record, there is a “busy status” property but this was always false, even during the copy.

In TechNote 1142, Apple writes:

I think maybe “brok” (broken?) is the new code for "bzy ", but I’m not sure.

Jon

Actually, I’m getting some strange results from the “get info” record. Often times I get a lone open quote for both file type and file creator (file type:“file creator:”) with no commas. (Mac OS X 10.3.2/AS 1.9.3) Does anyone else see this?

Jon

Thanks for the explanation. When I wrote the folder action that monitors my download folder, I spent a considerable amount of time trying to pin down a good way to determine if a file is busy/open (in OS X). Unfortunately, I’ve been unable to come up with anything reliable. Even the shell doesn’t appear to offer any solutions and I’ve come to the conclusion that either it isn’t possible or applications “must” flag a file as busy or open in order for us to use the info. I suspect that few apps, if any, do so.

– Rob

So far, I’ve had the same problem. Jon’s got something that handles Finder copies, and I suppose including file type “” would help too, but it seems there is no way to be SURE a file is not busy. That is something that leads to all kinds of problems in OS X. I really wish that Apple would find an OS-level solution…

I think part of the problem is that multiple processes NEED to be able to modify the same file in OS X, so there would have to be a flag that let that happen. It would be helpful to perhaps have a flag that says what processes have a given file opened, so a script could see whether an uninterruptible process was occurring.

thanks for your comments. i think that the best solution is to use the cunjunction of all of the criteria that you suggested. her is my implementation

i also added a max value for the to to wait for the completion of the file. at some point i’d rather see an error, instead of an infinite loop

on file_is_complete(source_file)
	set entry_time to current date
	activatePS()
	repeat
		set type_of_file to file type of (get info for (source_file as alias))
		set size_check1 to size of (info for source_file)
		delay 2
		set size_check2 to size of (info for source_file)
		if (((size_check1 is equal to size_check2) and ¬
			(type_of_file is not "brok") and ¬
			((offset of "bzy" in type_of_file) = 0)) or ¬
			(current date) > entry_time + max_wait_for_file_completion) then exit repeat
	end repeat

	return true
end file_is_complete

cheerz

jc

jc,

In regards to activating Photoshop (I don’t know if it’s necessary), just add an ‘activate’ command at the beginning of the Photoshop code.

tell application "Photoshop"
    activate
-- rest of script

– Rob

I should have disclaimed the 10 second delay and noted that network conditions may require a different value, as observed by Jon. With that said, I’ve never run into a problem with 10 seconds on my setup. :slight_smile:

– Rob

Hmm. Nice concept, but you may want to make that an optional parameter, rather than something that comes through a global variable (which is what it looks like you are doing).

How about this? It lets you send in a string, file, or alias (and it then uses its own default max wait time, or a record with more parameters specified). One thing I noticed is that this was giving me false completes when downloading a file. Perhaps a longer default wait_between_checks, since “info for” often lags behind actual file size changes. In OS X, I’ve found shell scripts to be more reliable in checking a file’s size at an exact moment in time:


on file_is_complete(prefs)
	-- version 1.1
	if class of prefs is record then
		-- just keep what was sent in, but coerce source_file to string
		try
			get source_file of prefs
		on error
			error "file_is_complete() FAILED: Missing required parameter: source_file."
		end try
		set source_file of prefs to ((source_file of prefs) as string)
	else
		set prefs to {source_file:prefs as string}
	end if
	
	set defaultPrefs to {max_wait_for_file_completion:90, wait_between_checks:2} -- time is in seconds
	set prefs to prefs & defaultPrefs -- tack on defaults if they were not specified
	
	set wait_between_checks to wait_between_checks of prefs
	set max_wait_for_file_completion to max_wait_for_file_completion of prefs
	set source_file to alias (source_file of prefs)
	
	try
		set entry_time to current date
		repeat
			set type_of_file to file type of (get info for source_file)
			set size_check1 to size of (info for source_file)
			delay wait_between_checks
			set size_check2 to size of (info for source_file)
			if ((size_check1 is equal to size_check2) and ¬
				(type_of_file is not "brok") and ¬
				((offset of "bzy" in type_of_file) = 0)) then
				return true -- it is complete
			end if
			if (current date) > entry_time + max_wait_for_file_completion then
				-- it took too long, throw an error
				error "Timeout: Not complete after " & max_wait_for_file_completion & " seconds." number 1024
			end if
		end repeat
		
		return true
	on error errMsg number errNum
		error "file_is_complete FAILED: " & errMsg number errNum
	end try
end file_is_complete

i’m using properties as globals. to use prefs is more elegant. thanks

My remaining problem with the current solution is that after the script sucessfully waits for the completion of the file but if the file comes from a diifferent machine over the network, the finder cannot make an alias of the moved file. Actually the file disappears !!! So that’s why the finder can’t mak an alias. but why does the file disappear???

here is my code:


set the source_file to (move this_item to the originals_folder with replacing) as alias

this is the same as in the example code provided by apple.

when a large (>10MB) file is copied over the network i get the following error:
„«class docf» “pic.jpg” of application “Finder”“ kann nicht in alias umgewandelt werden. Number:-1700
translation: can’t make alias of «class docf» “pic.jpg” of application “Finder”“

what is going wrong there?

I’m a bit frustrated now because this error don’t seem to make much sense.

I have serious problems now with reliabilty. The script i’m developing is supposed to run on a machine that does nothing but running this script attached to several folders. All scripts do the same (tell photoshop to convert pix to cmyk and save as tiff) It is supposed ta handle a couple hundred files a day.

Everything works fine as long as only one machine and small files (< 1MB) involved, but since i started testing with large files over a network new problems arise.

Another Problem is concurrency - several people might be dropping things into folders at the same time. which will lead to a situation where a file is opened by PS while another is processed. In that situation the front document changes and files don’t get closed or saved. Can i bind applescript variable to PS-Documents?

I’ve tried to solve that using a flag that is written to a file in the folder, which is read before anything is processed. But the open for access command seems to work very unreliable.
To avoid these problems alltogether i’m thinking about using something else then Photoshop to do the conversion. I’ll make a third thread for that.

How come you can move a file with the gui while its downloading and not corrupt it?

Apparently the Finder (or Mac OS) is intelligent enough to follow the file even during a download. As a test, I just downloaded (via Safari) a large file and moved it during the download. The download continued. Now, if I had tried to do something to the file (open, read, decompress, etc.) before the download was complete, it wouldn’t work but it wouldn’t necessarily be corrupt either - just incomplete.

Tested on OS X 10.2.8.

– Rob

I’m not sure if this was the case in earlier version but as of Safari 1.2 (v125), when you download a file via Safari, you now get icons with progress bars, the filename has a .download extension, and the kind = “Safari download”. Further, using this script:

set the_file to "Path:to:DownloadingFile.download" as alias
set the_info_1 to (get info for the_file)
tell application "Finder" to set the_info_2 to (properties of the_file)
return {the_info_1, the_info_2}

This returns:

{{name:"DownloadingFile.download", creation date:date "Wednesday, February 4, 2004 12:30:55 PM", modification date:date "Wednesday, February 4, 2004 12:30:55 PM", icon position:{0, 0}, size:2.409145E+6, folder:true, alias:false, name extension:"download", extension hidden:false, visible:true, package folder:true, file type:"", file creator:"", displayed name:"DownloadingFile.download", default application:alias "Macintosh HD:Applications:Safari.app:", kind:"Safari download", short version:missing value, long version:missing value, bundle identifier:missing value}, {class:document file, name:"DownloadingFile.download", index:3, displayed name:"DownloadingFile.download", name extension:"download", extension hidden:false, container:folder "Desktop" of folder "jon" of folder "Users" of startup disk of application "Finder", disk:startup disk of application "Finder", position:{-1, -1}, bounds:{-33, -33, 31, 31}, kind:"Safari download", label index:0, locked:false, description:missing value, comment:"", size:missing value, physical size:missing value, creation date:date "Wednesday, February 4, 2004 12:30:55 PM", modification date:date "Wednesday, February 4, 2004 12:30:55 PM", icon:missing value, URL:"file://localhost/Users/jon/Desktop/DownloadingFile.download/", owner:"jon", group:"staff", owner privileges:read write, group privileges:read only, everyones privileges:read only, file type:missing value, creator type:missing value, stationery:false, product version:"", version:""}}

The size from the “get info” call returns a real while the Finder returns “missing value” (for physical size as well). There are also discrepancies in the file type and creator between the two records. Finally, the get info record sees the download file as a package folder. Perhaps this new info (especially the extension) could be used to wait for the file to finish downloading before proceeding with the script.

Jon

This sounds promising, Jon.

I was somewhat disappointed, but understanding, when the latest version of Safari wasn’t made available to Jaguar users. I’ve since read many reports that indicate that it might be somewhat buggy, so maybe it’s good that I couldn’t obtain the update. :wink:

– Rob

Hello,

i just wanted to let you know that i no longer use folder actions for the kind of automation (watching a folder, moving and converting files). Despite your great help and good ideas some unsolvable problems remained.

The two main Problems are:

  1. Folder actions throws dialogs requesting authorisation to move files even though it runs as root user.
  2. When processing large files that came from some machine on the network the move or duplicate events error and either turn folder actions off alltogether or lead to files that are not processed. The problem persists despite the sucessful implementation of a function that watches file size and file types and makes the finder wait with its move or duplicate events.

I’m now doing everything with Perl and cron except for the Photoshop Part which still uses an AppleScript. I run the AppleScript from Perl using Mac::AppleScript

The great news is that it works pefectly well. The efforts to get a reliable AppleScript running remain a nightmare. I’m now into running AppleEvents directly from Perl with Mac::Glue. This is a bit of a challenge though too, but it doesn’t need AppleScript at all.

Thank you for your support and your suggestions

Although I don’t know if it would have helped you, I ran into a similar problem when running folder actions on 10.3 Server. My solution was that when people drop files on to a folder they shouldn’t be viewing the contents of the folder. This somehow seems to delay the launch of the script. My best guess as to why this is the case is that if someone isn’t viewing the contents of the destination folder, the remote machine doesn’t have to update information for that folder as quickly, allowing the files to finish copying before the script is launched. I don’t know if this would work for VERY large files or very large numbers, but so far it works for me.