SD and OS X version script

I’m wondering if there a reason the script was getting OS build info and version from two different sources?

Here’s a tweaked version

use scripting additions
use framework "Foundation"

set fileNameFormat to {"Copy SD ", "version and", " OSX ", "version"}

set sdPath to POSIX path of (path to application id "com.latenightsw.ScriptDebugger6")
set sdPlist to quoted form of (sdPath & "Contents/Info.plist")
set plListCommand to "/usr/libexec/PlistBuddy -c Print:CFBundleShortVersionString -c Print:CFBundleVersion " & sdPlist
set {SDVersion, BundleVersion} to paragraphs of (do shell script plListCommand)
set SystemInfo to do shell script "sw_vers"
set AppleScript's text item delimiters to {":	"}
set SystemVersion to text item 2 of paragraph 2 of SystemInfo
set SystemBuildNum to the last text item of SystemInfo
set AppleScript's text item delimiters to {""}

set infoString to " SD " & SDVersion & " (" & BundleVersion & ") OSX " & SystemVersion & " (Build " & 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

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.

Just an idea . . .

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.

I

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.

And did I mention speed? :slight_smile:

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.

But it still has calls to shell script.

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.

EDIT: 2017-02-22 11:40 PM CT

###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

Is there a way to get the OS build number without using shell scripts?

Didn’t Shane post that above?

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

Hi Shane,

OMM this returns incorrect information. Any thoughts on this?

What I get:

SD 6.0.1 (6A170)

Versus, what I should get:

SD 6.0.4 (6A198)

Stan C.

Thanks, but as you may have not noticed, I already a great working script (posted above). No need for a repurpose. :wink:

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"

Yeah, so did I at the beginning of this thread! :wink:

Hey Ed,

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

-Chris

1 Like

Well done, Chris! I like it!

1 Like

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)"

------------------------------------------------------------------------------

-Chris

Chris,

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

Bill

Hey Bill,

Nothing wrong with that.

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

-Chris

Yep – NSWorkspace is part of AppKit.