My script (with all ASObjC) runs very fast from anywhere.
I think you may have over-complicated things by trying to integrate with SD.
Why not just have the script show a dialog with the version info, and buttons to “Copy”, “Paste”, and “OK” ?
Then you can run the script from anywhere. It could get the name of the frontmost app, and show a dialog with that as default, but allowing the user to enter a different app.
I think I was referring to the last one Bill posted that had a Tell application Script Debugger.
My script doesn’t integrate with SD. My script lives in the user’s script menu. When I want to run it, from any application, I just pull down the menu and run it. No need for a dialog, because it sets the clipboard and I just paste. With the versions I posted, the name of the script changes to show the info in the menu, so if I just want to double check what I’ve got installed, I just pull down the menu and see.
I suppose it could be useful to do get the info for other apps, but that sounds like overcomplicating things.
OK, this version integrates your methods for getting SD version and build
use scripting additions
use framework "Foundation"
--> SD 6.0.4 (6A198) OSX 10.11.6 (15G1217)
set appID to "com.latenightsw.ScriptDebugger6"
set fileNameFormat to {"Copy SD ", "version and", " OSX ", "version"}
set SDBundle to current application's NSBundle's bundleWithIdentifier:appID
set SDVersion to SDBundle's infoDictionary()'s objectForKey:"CFBundleShortVersionString"
set BundleVersion to SDBundle's infoDictionary()'s objectForKey:"CFBundleVersion"
set SystemInfo to do shell script "sw_vers"
set AppleScript's text item delimiters to {": ", return}
set SystemInfo to text items of SystemInfo
set AppleScript's text item delimiters to {""}
set SystemVersion to item 4 of SystemInfo
set SystemBuildNum to the last text item of SystemInfo
set infoString to " SD " & SDVersion & " (" & BundleVersion & ") OSX " & SystemVersion & " (" & SystemBuildNum & ")"
set the clipboard to "-->" & infoString
set newFileName to "Copy" & infoString
set thisScript to path to me as alias
--Unnote next line and run script to set script name back to default
--set newFileName to fileNameFormat as text
tell application "Finder"
set oldFileName to the name of thisScript
if "Unsaved Script Debugger Document" is in oldFileName then return
if "Untitled" is in oldFileName then return
set nameExt to the name extension of thisScript
set newFileName to newFileName & "." & nameExt
if oldFileName is not newFileName then set the name of thisScript to newFileName
end tell
return the clipboard
Let me try to clarify. My general preference for ASObjC is based on a few factors.
First, do shell script is often slower. I admit, I’m a speed freak.
Second, I prefer a command or method that says it returns what I want, rather than a hack, and many uses of do shell script are hacks doing things like reading implementation files. That’s not the case with PlistBuddy, but I’m talking more generally.
Third, because they’re at a lower level, some commands are traps. So sort can have trouble with Unicode, ls doesn’t know a package from a folder, and so on. These things often work fine in tests and end up in code as bugs waiting to happen.
And finally an awful lot of examples I see also include code using TIDs/awk/sed/whatever to extract the required info from the result, and that’s just another layer of fragile code. It’s hard to test, and if the tool is modified – and in some cases if the environment changes – stuff can fall apart apart in hard-to-debug ways.
Now there are plenty of cases that avoid all these, and there are also ASObjC methods that are unusable or impractical. But I like to play the percentages, and I reckon they’re strongly on the side of ASObjC.
For example, in this very thread: bundleWithIdentifier:. Chris has pointed out to me off-forum that it fails when passed other apps’ IDs in Script Debugger 5, and from FastScripts. I have know idea why. But FWIW, here’s an alternative:
set theURL to current application's NSWorkspace's sharedWorkspace()'s URLForApplicationWithBundleIdentifier:appID
set SDBundle to current application's NSBundle's bundleWithURL:theURL
Note that this should also include:
use framework "AppKit"
for NSWorkspace.
And for JM’s info, the documentation for URLForApplicationWithBundleIdentifier: is a little more forthcoming, if not much more enlightening:
This uses various (currently unspecified) heuristics in case multiple apps have the same bundle ID.
I guess I missed a key factor that your script ONLY gets the version info for SD. That’s useful, but I very often need to know (and post) the version info for other apps.
Here’s a script that does that, and does NOT use shell scripts, only ASObjC statements.
###AppleScript Using Only ASObjC
NOTE: TextWrangler was the FrontMost app.
Executed script from Apple script menu.
####Example Output
(*
VER: 1.1 Date: 2017-02-22
Revised per Shane Stanley's fix using app URL to get Bundle.
*)
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"
use scripting additions
tell application "System Events" to ¬
set appName to item 1 of (get name of processes whose frontmost is true)
set currentApp to appName
set msgStr to "Confirm or Change App Name"
set titleStr to "Get Version Info for App and macOS"
set ansStr to appName
display dialog msgStr ¬
with title titleStr ¬
with icon caution ¬
default answer ansStr
set ansRec to result
set buttonStr to button returned of ansRec
set appName to text returned of ansRec
set macOS to system version of (system info)
try
set appID to get id of application appName
set appURL to current application's NSWorkspace's sharedWorkspace()'s URLForApplicationWithBundleIdentifier:appID
set appBundle to current application's NSBundle's bundleWithURL:appURL
set appVer to appBundle's infoDictionary()'s objectForKey:"CFBundleShortVersionString"
set appBuild to appBundle's infoDictionary()'s objectForKey:"CFBundleVersion"
set aName to appBundle's infoDictionary()'s objectForKey:"CFBundleExecutable"
set appName to (aName as text)
on error errStr number errorNumber
display dialog "ERROR: " & errStr with title titleStr
return
end try
set verStr to appName & " " & (appVer as text) & ¬
" (" & (appBuild as text) & ¬
")" & " on macOS " & macOS
set ansRec to display dialog verStr ¬
with title ¬
titleStr buttons {"Copy", "Paste", "OK"} ¬
default button ¬
"OK" with icon note
set buttonStr to button returned of ansRec
if (buttonStr = "Copy") then
set the clipboard to verStr
display notification verStr with title "Copied to Clipboard"
else if (buttonStr = "Paste") then
set the clipboard to verStr
delay 0.2
tell application currentApp
activate
tell application "System Events"
keystroke "v" using command down
end tell
end tell -- App
end if
--- EXAMPLE RESULTS ---
-->Adobe Acrobat Pro 11.0.19 (11.0.19) on macOS 10.11.6
OK, here’s a full version of the script I want (SD and OS versions and builds; sets clipboard; changes script’s file name) without any shell scripting or UI scripting. (it should be pretty easy to repurpose to other apps for Michael’s needs).
use scripting additions
use framework "Foundation"
set fileNameFormat to {"Copy SD ", "version and", " OSX ", "version"}
set appName to "SD"
set appId to "com.latenightsw.ScriptDebugger6"
set appBundle to current application's NSBundle's bundleWithIdentifier:appId
set appVersion to appBundle's infoDictionary()'s objectForKey:"CFBundleShortVersionString"
set appBundleVersion to appBundle's infoDictionary()'s objectForKey:"CFBundleVersion"
set SystemInfo to current application's NSProcessInfo's processInfo()'s operatingSystemVersionString()
set AppleScript's text item delimiters to {" ", ")"}
set SystemInfo to text items of (SystemInfo as text)
set AppleScript's text item delimiters to {""}
set SystemVersion to item 2 of SystemInfo
set SystemBuildNum to item 4 of SystemInfo
set infoString to appName & appVersion & " (" & appBundleVersion & ") OSX " & SystemVersion & " (" & SystemBuildNum & ")"
set the clipboard to "-->" & infoString
set newFileName to "Copy" & infoString
set thisScript to path to me as alias
--Unnote next line and run script to set script name back to default
--set newFileName to fileNameFormat as text
tell application "Finder"
set oldFileName to the name of thisScript
if "Unsaved Script Debugger Document" is in oldFileName then return
if "Untitled" is in oldFileName then return
set nameExt to the name extension of thisScript
set newFileName to newFileName & "." & nameExt
if oldFileName is not newFileName then set the name of thisScript to newFileName
end tell
return the clipboard
If you have multiple copies of an app, it’s always a bit of a crap-shoot. Launch Services is ultimately responsible, and it often moves in mysterious ways.
An alternative is to use a path:
set SDBundle to current application's NSBundle's bundleWithPath:"/Applications/Script Debugger"
As JM pointed out Shane thoughtfully provided some ASObjC for that.
I don’t happen to like the output though, so I changed it a bit.
use framework "Foundation"
set sysVerStr to ((current application's NSProcessInfo's processInfo()'s ¬
operatingSystemVersionString())'s stringByReplacingOccurrencesOfString:("Version") ¬
withString:"macOS") as text
Let’s incorporate Shane’s bug-fix and let ASObjC do a little more of the work for us.
Only the app-id is needed now.
------------------------------------------------------------------------------
use framework "Foundation"
use framework "AppKit"
------------------------------------------------------------------------------
set appID to "com.latenightsw.ScriptDebugger6"
------------------------------------------------------------------------------
set appNSURL to current application's NSWorkspace's sharedWorkspace()'s URLForApplicationWithBundleIdentifier:appID
set appBundle to current application's NSBundle's bundleWithURL:appNSURL
set appName to (appBundle's infoDictionary()'s objectForKey:"CFBundleName") as text
set appVer to (appBundle's infoDictionary()'s objectForKey:"CFBundleShortVersionString") as text
set appBundleVer to (appBundle's infoDictionary()'s objectForKey:"CFBundleVersion") as text
set sysVer to (current application's NSProcessInfo's processInfo()'s operatingSystemVersionString())
set sysVer to (sysVer's stringByReplacingOccurrencesOfString:("Version") withString:"macOS")
set sysVer to (sysVer's stringByReplacingOccurrencesOfString:("Build ") withString:"") as text
set infoString to appName & space & appVer & " (" & appBundleVer & ") on " & sysVer
return infoString
--> "Script Debugger 6.0.4 (6A198) on macOS 10.12.3 (16D32)"
------------------------------------------------------------------------------
What do you think of this version. This version seems more straight forward. I also removed the second use framework “Foundation” line as well as the use framework “AppKit” and use scripting additions since they weren’t needed. I put a line between the first and second set of 3 lines because the middle lines are calculating the actual values that will be used while the first 3 lines are determining the the appBundle so those values can be calculated. The last 3 lines calculate the system info and create the output string.
use framework "Foundation"
------------------------------------------------------------------------------
set appID to "com.latenightsw.ScriptDebugger6"
------------------------------------------------------------------------------
-- Determine the application bundle
set appNSURL to current application's NSWorkspace's sharedWorkspace()'s URLForApplicationWithBundleIdentifier:appID
set appBundle to current application's NSBundle's bundleWithURL:appNSURL
-- Calculate the App's name, version and bundle version
set appName to (appBundle's infoDictionary()'s objectForKey:"CFBundleName") as text
set appVer to (appBundle's infoDictionary()'s objectForKey:"CFBundleShortVersionString") as text
set appBundleVer to (appBundle's infoDictionary()'s objectForKey:"CFBundleVersion") as text
-- Calculate the OSX information & create the output string
set procInfo to current application's NSProcessInfo's processInfo()
set sysVer to strings 9 thru -1 of ((procInfo's operatingSystemVersionString()) as text)
set infoString to appName & space & appVer & " (" & appBundleVer & ") on macOS " & sysVer
return infoString
Thanks for pointing out the redundant “use” line. (Removed.)
The AppKit line is necessary according to Shane.
I prefer explicit string replacement to gathering position-based strings – it’s more robust and easier to read.
You missed the “Build ” string removal, which I included to match Ed’s last script above.
On my own system I’d use RegEx find/replace via the Satimage.osax, but this was a good case for simple string-replacement (which is easier for most people to grok).