Suggestions for App Install script?

This script installs apps from disk images, ZIP files, and package installers (runs installer only). After it copies the app to the Applications folder, it unmounts the disk.

I’ve spent a good amount of time trying to get this right, but I feel there’s still something I can improve. If I test this on a disk image for a second time (consecutively), I get this error (notice the curly quotes):

Here is the script:

global diskInfo, diskName, diskPath, appDisk, action

on getTargetApp(fileExt)
	tell application "Finder"
		-- find app on disk image
		try
			get (first file of appDisk whose name extension is fileExt)
		on error
			get first file of (entire contents of appDisk) whose name extension is fileExt
		end try
	end tell
end getTargetApp

on getDiskName()
	set volOffset to offset of "/Volumes/" in diskInfo
	set diskPath to characters volOffset through end of diskInfo as text
	set appDisk to POSIX file diskPath as alias
end getDiskName

on diskAction(action, chosenDisk)
	do shell script ("hdiutil " & action & space & quoted form of chosenDisk)
end diskAction

tell application "Finder"
	set allDMGs to every file of folder (path to downloads folder as text) whose name extension is "dmg"
	repeat with eachDMG in allDMGs
		set dmgName to name of eachDMG
		set dmgPath to POSIX path of (eachDMG as alias)
		-- mount and find DMG disk
		set diskInfo to diskAction("mount", dmgPath) of me
		getDiskName() of me
		-- install app from DMG
		-- try
		installApp() of me
		(* on error
			-- install package from DMG
			try
				runInstaller() of me
			on error
				beep 2
				diskAction("unmount", diskPath) of me
			end try
		end try *)
	end repeat
	-- install app from ZIP, or run package installer
	extractZips() of me
	runPkgs() of me
end tell

-- DMG install handler
on installApp()
	tell application "Finder"
		set theApp to getTargetApp("app") of me
		duplicate theApp to folder (path to applications folder as text) with replacing
		diskAction("unmount", diskPath) of me
	end tell
end installApp

-- DMG installer handler
on runInstaller()
	tell application "Finder"
		set thePkg to getTargetApp("pkg") of me
		open thePkg
	end tell
end runInstaller

-- ZIP install handler
on extractZips()
	tell application "Finder"
		set allZips to every file of folder (path to downloads folder as text) whose name extension is "zip"
		if allZips = {} then return
		repeat with eachZip in allZips
			set zipPath to POSIX path of (eachZip as alias)
			do shell script ("unzip -u " & quoted form of zipPath & " -d ~/Downloads/")
		end repeat
		set newApps to every file of folder (path to downloads folder as text) whose name extension is "app"
		move newApps to folder (path to applications folder as text) with replacing
	end tell
end extractZips

on runPkgs()
	tell application "Finder"
		set allPkgs to every file of folder (path to downloads folder as text) whose name extension is "pkg"
		repeat with eachPkg in allPkgs
			open eachPkg
		end repeat
	end tell
end runPkgs

Any ideas?

I can’t see exactly what your problem is however I would do it differently. Here’s how I would do what you’re looking to do. First, I would not use hdiutil to mount a dmg. Many dmg files have license agreements that have to be “OK’d” before they mount and hdiutil will not work with them. So try this…

try
	tell application "Finder"
		set allDMGs to every file of (path to downloads folder) whose name extension is "dmg"
		if allDMGs is {} then error "No DMG files were found in the downloads folder"
	end tell
	
	set appsInstalled to ""
	repeat with i from 1 to count of allDMGs
		-- mount the dmg
		set mountedDisk to mountDMG(item i of allDMGs)
		if mountedDisk is missing value then error "Could not mount the disk: " & (item i of allDMGs) as text
		
		-- find the application file to install
		set theApp to getAppFileOnDisk(mountedDisk)
		if theApp is missing value then error "Could not find the application to install on disk: " & mountedDisk
		
		-- install the app file to Applications
		try
			tell application "Finder"
				move theApp to (path to applications folder) with replacing
				set appsInstalled to appsInstalled & (name of theApp) & return
			end tell
		end try
		
		-- eject the disk image
		ejectDisk(mountedDisk)
	end repeat
	display dialog "The following applications were installed:" & return & appsInstalled
on error theError number errorNumber
	display dialog "There was an error:" & return & theError & return & return & "Error Number: " & errorNumber as text buttons {"OK"} default button 1 with icon stop
end try


(*================= SUBROUTINES ====================*)
on getAppFileOnDisk(theDiskName)
	tell application "Finder"
		set theApp to missing value
		try
			set theApp to (first file of disk theDiskName whose name extension is "app")
		on error
			try
				set theApp to first file of (entire contents of disk theDiskName) whose name extension is "app"
			end try
		end try
	end tell
	return theApp
end getAppFileOnDisk

on ejectDisk(diskName)
	try
		tell application "Finder" to eject disk diskName
	end try
end ejectDisk

on mountDMG(dmgPath)
	set dmgPath to dmgPath as text
	
	-- get a pre-list of the mounted disks so we can compare it later to determine what was mounted
	set preDisks to list disks
	set preDisksCount to count of preDisks
	
	-- mount the dmg
	tell application "Finder" to open file dmgPath -- we do it this way because some dmg have license agreements
	
	-- delay while the dmg mounts... max 10 seconds
	set startTime to current date
	repeat
		set postDisks to list disks
		set postDisksCount to count of postDisks
		if postDisksCount is not preDisksCount then exit repeat
		if (current date) - startTime is greater than 10 then
			return missing value
			exit repeat
		end if
		delay 1
	end repeat
	
	-- determine the mounted disk
	set mountedDisk to missing value
	repeat with aDisk in postDisks
		if aDisk is not in preDisks then
			set mountedDisk to contents of aDisk
			exit repeat
		end if
	end repeat
	
	return mountedDisk
end mountDMG

Thanks! That script seems much better, and it clears up many issues.