Request for help optimizing a slow script that works well otherwise

Hello,

I have a script that I use to open up the application folder of whatever app I am working on in the iPhone Simulator, which it finds by locating the most recently modified app. It works perfectly as far as the minimal testing I’ve done has demonstrated but it is very, very slow (over a minute on a 2009 MBP):


set simulatorFolder to ((path to application support folder from user domain as text) & "iPhone Simulator:" as alias)
tell application "Finder"
	
	set allApps to every file of entire contents of simulatorFolder whose file type is "APPL"
	set newestApp to item 1 of (sort allApps by modification date)
	reveal newestApp
	
end tell

Would anyone be so kind as to help me optimize this script so it gives the identical result (reliably find the most recently modified app and display it in the finder in its containing folder) without the wait?

Information that might be useful here is that the app is always found in the following folder hierarchy, where “Applications” is the literal name of the folder and all the other folder names are dynamic:

Thank you!

XCode is scriptable so you can ask it directly…

tell application "Xcode"
	tell (first project) to set posixProductFolder to product directory
	-- you can use "real path" instead if you want to reveal the "xcodeproj" file
end tell

set productFolder to POSIX file posixProductFolder
tell application "Finder"
	activate
	reveal productFolder
end tell

Hello,

Thanks for the suggestion – your script opens up the build directory with the product before it is installed to the Simulator, but my script opens up the Simulator installed app directory which contains the app and its sandbox (the Documents folder, the temp folder, etc). This is very useful because that directory doesn’t always keep the same name over multiple build/runs, and the installed app directory name is a hash so it isn’t ever self-evident, and there is a new directory created for every targeted SDK version that is installed into the Simulator so it can be pretty hard to keep track of.

So, for instance, if your app saves documents to the Documents folder and you want to see if that is working, running the script while using the Simulator puts the documents folder right in front of you in the finder.

You can see what it does firsthand if you install an app in the Simulator and run it, and then run the script.

The issue in a nutshell is that the method of doing “every file of entire contents of simulatorFolder” is woefully inefficient but it also reliably detects the most-recently-installed app in the entire Simulator support folder (which is always the last build that was made, i.e. the app you’re currently testing in the Simulator), so I’m hoping that someone might have a suggestion of another way of scripting the identical functionality, perhaps with a shell script that is called from the Applescript or perhaps with a more efficient method that is pure Applescript that exploits the fact that the apps always have the same hierarchical position in the ~/Library/Application Support/iPhone Simulator folder.

Thanks!

Hi Halle,

I see what you’re saying… that Xcode doesn’t know the path you’re looking for because it’s the Simulator that’s putting files there. I checked and the Simulator isn’t scriptable so your approach is probably the only viable solution.

My best suggestion would be to try and reduce the number of folders the Finder has to search. So you need to find some attribute of the “some.version.number” folder that you can filter on. Is that folder the newest created folder in the iPhone Support folder? If so then something like this might help…

set simulatorFolder to ((path to application support folder from user domain as text) & "iPhone Simulator:" as alias)
tell application "Finder"
	set allFolders to folders of simulatorFolder
	set newestFolder to item 1 of (sort allFolders by creation date) -- maybe you need the last item here instead?
	set applicationsFolderPath to (newestFolder as text) & "Applications:"
	
	set allApps to every file of entire contents of folder applicationsFolderPath whose file type is "APPL"
	set newestApp to item 1 of (sort allApps by modification date)
	reveal newestApp
end tell

Hi Hank,

I think you’re right about reducing the folder search. Unfortunately, folder creation date is out because the decision factor for knowing if this is the app you are simulating can probably only be the modification date of the installed app file.

The reason is that the outer folders are only created/recreated intermittently (sometimes a folder will persist over many builds, sometimes not), and the folders do not reliably pick up the modification date of the most-recently-modified item they contain (which is odd – maybe a finder bug?). Suffice to say, searching for the install folder with the most recent modification date finds the wrong install folder every time for some reason (and not the oldest one, just a random one), while searching for the most-recently-modified APPL-type file always finds the build you are currently simulating.

Here is what I think would work as pseudocode that I don’t quite know how to do in Applescript:

For each folder in simulatorFolder that isn’t titled User
For each folder in this subfolder
for each folder titled Applications in this sub-sub-folder
add each file found here with the type APPL to a collection called applicationList
reveal in finder the most-recently-modified member of applicationList

I don’t have those folders so I didn’t test this, but it should at least be close to what you asked. You’ll have to test your original script versus this one and determine if this is an improvement.

set simulatorFolder to ((path to application support folder from user domain as text) & "iPhone Simulator:") as alias

tell application "Finder"
	-- get all the folders from simulator folder that isn't tiled "User"
	set nonUserFolders to folders of simulatorFolder whose name is not "User"
	
	-- get all the "Application" folders found in the above
	set applicationFolders to {}
	repeat with aNonUserFolder in nonUserFolders
		set appFolders to (folders of aNonUserFolder whose name is "Application")
		set applicationFolders to applicationFolders & appFolders
	end repeat
	
	-- get all the files from the above with type "AAPL"
	set aaplFiles to {}
	repeat with anAppFolder in applicationFolders
		set allAaplFiles to (files of anAppFolder whose file type is "APPL")
		set aaplFiles to aaplFiles & allAaplFiles
	end repeat
	
	-- sort the AAPL files and get the newest
	set newestAaplFile to item 1 of (sort aaplFiles by modification date)
	
	-- reveal the first listing
	reveal newestAaplFile
end tell

Thank you Hank, that’s ideal. With some very minor changes (there’s one more folder depth):



set simulatorFolder to ((path to application support folder from user domain as text) & "iPhone Simulator:") as alias

tell application "Finder"
	-- get all the folders from simulator folder that isn't titled "User"
	set nonUserFolders to folders of simulatorFolder whose name is not "User"
	
	-- get all the "Application" folders found in the above
	set applicationFolders to {}
	repeat with aNonUserFolder in nonUserFolders
		set appFolders to (folders of aNonUserFolder whose name is "Applications")
		set applicationFolders to applicationFolders & appFolders
	end repeat
	
	-- get all the install folders named with a hash found in the above
	set installFolders to {}
	repeat with anApplicationFolder in applicationFolders
		set instFolders to (folders of anApplicationFolder)
		set installFolders to installFolders & instFolders
	end repeat
	
	-- get all the files from the above with type "AAPL"
	set applFiles to {}
	repeat with anAppFolder in installFolders
		set allApplFiles to (files of anAppFolder whose file type is "APPL")
		set applFiles to applFiles & allApplFiles
	end repeat
	
	-- sort the AAPL files and get the newest
	set newestApplFile to item 1 of (sort applFiles by modification date)
	
	-- reveal the first listing
	reveal newestApplFile
	
end tell

Thank you very much, this takes 3 seconds versus 42 seconds for the other one at today’s timing.

That’s a great speed gain… glad to help. :smiley:

NOTE: you forgot to add the “whose” filter to filter for the hash, so change the line to this…
set instFolders to (folders of anApplicationFolder whose name contains “-”)

Hi Hank,

the application bundles are not directly in the “Applications” folder but in a subfolder with the project (or whatever) UUID


set simulatorFolder to ((path to application support folder from user domain as text) & "iPhone Simulator:") as alias

tell application "Finder"
	-- get all the folders from simulator folder that isn't tiled "User"
	set nonUserFolders to folders of simulatorFolder whose name is not "User"
	
	-- get all the "Application" folders found in the above
	set applicationFolders to {}
	repeat with aNonUserFolder in nonUserFolders
		set appFolders to (folders of aNonUserFolder whose name is "Applications")
		set applicationFolders to applicationFolders & appFolders
	end repeat
	
	-- get all the files from the above with type "AAPL"
	set aaplFiles to {}
	repeat with anAppFolder in applicationFolders
		repeat with singleAppFolder in (get folders of anAppFolder)
			set allAaplFiles to (files of singleAppFolder whose file type is "APPL")
			set aaplFiles to aaplFiles & allAaplFiles
		end repeat
	end repeat
	
	-- sort the AAPL files and get the newest
	set newestAaplFile to item 1 of (sort aaplFiles by modification date)
	
	-- reveal the first listing
	reveal newestAaplFile
end tell


this shell solution using Spotlight should do it too


property findtype : quoted form of "kMDItemContentType = \"com.apple.application-bundle\""

set simulatorFolder to POSIX path of (path to application support folder from user domain) & "iPhone Simulator/"
set appFiles to paragraphs of (do shell script "mdfind -onlyin " & quoted form of simulatorFolder & " " & findtype)
if appFiles is not {} then
	set mostRecentApp to item 1 of appFiles
	tell application "Finder" to reveal ((POSIX file mostRecentApp) as alias)
end if


Ah, the hash folders are the only kind of folders in there so they don’t need to/can’t be filtered.

It is a great speed gain! What’s funny is that both the original and final scripts vary immensely in their times to complete and I wonder what it’s based on. The original takes from around 40 to around 70 seconds and the final version takes from around 2 to around 7 (both of which are entirely acceptable versus browsing through the filesystem).

Whoops, StephanK slipped ahead. That one is also very fast, thank you both for your assistance.

Hi StefanK, based on this line…

set mostRecentApp to item 1 of appFiles

I would conclude that the spotlight results are returned based on the order they’re added to the spotlight database. Meaning since the newest app went into the database last then it is returned first from the spotlight query. If that’s true then definitely that will be the fastest way to get at the newest app file and I learned something new about how spotlight works. :slight_smile: