How to wait for osascript to produce a result

346 Views Asked by At

sometimes my AppleScript code seems to fail, on other machines is works.

I run this AppleScript code as heredoc from inside a shell script. The shell script is a postinstall script run by a pkg installer and runs as root:

#!/bin/sh
set -x
logfile="/Library/Logs/EZEEP Connector Installer.log"

LogMessage()
{
  echo $(date) $1 >> "${logfile}"
}

LogMessage "................................."
LogMessage "Installer postinstall started ..."
LogMessage "................................."

# set file system tag 'Printing' on app bundle:
/usr/bin/osascript <<'EOD'
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

on addTags:tagList forPath:posixPath -- add to existing tags
    set aURL to current application's |NSURL|'s fileURLWithPath:posixPath -- make URL
    #display dialog aURL as string
    -- get existing tags
    
    set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
    if theTags is not missing value then -- add new tags
        set tagList to (theTags as list) & tagList
        set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
    end if
    aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
    
end addTags:forPath:

tell application "Finder"
    set thePath to (POSIX path of (application file id "com.thinprint.ezeep.Connector" as alias))
    
    my addTags:{"Printing"} forPath:thePath
end tell
EOD

#sleep 10


sudo -u ${USER} /usr/bin/osascript -e 'tell application "/Applications/ezeep Connector.app" to launch'

LogMessage "................................."
LogMessage " Installer postinstall finished ."
LogMessage "................................."

Sometimes the targeted app bundle gets a tag, sometimes not. If I uncomment the last sleep in my code sample, then everything works as expected.

Even on 2 different VMs we have the tag always created on one VM and failing to create on the other.

Is there a proper way to wait for the result of the add tag operation and then proceed with the script? Or is the sleep 10 command a reliable solution to have it run on dozens or event hundreds of Macs without failing on even a few?

kind regards,

Robert

1

There are 1 best solutions below

0
On

First, it's always good idea to avoid scripting the Finder (a busy app that can produce odd delays and errors in scripts). Since you're using AppleScriptObjC anyway, you can get the URL you need from NSWorkspace. Then all you need to do is add a repeat/check/delay loop that looks to see if the tag has been added.

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"

set theURL to my findAppURLFromID:"com.thinprint.ezeep.Connector"
my addTags:{"Printing"} forURL:theURL
my checkTag:"Printing" forURL:theURL

(* get app package URL from NSWorkspace *)
on findAppURLFromID:appID
    set sharedWorkspace to (current application's NSWorkspace's sharedWorkspace)
    set appURL to sharedWorkspace's URLForApplicationWithBundleIdentifier:appID
    return appURL
end findAppURLFromID:

(* altered to accept URL directly *)
on addTags:tagList forURL:aURL
    set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
    if theTags is not missing value then
        set tagList to (theTags as list) & tagList
    end if
    (*
        I moved the following statement out of the 'if' block. This would not be
        called if the package file has no tags, so the script would feed an unaltered
        AppleScript list to 'setResourceValue:forKey:error'. That may work, dunno
        but better to put everything into the correct object format
    *)
    set tagList to (current application's NSOrderedSet's orderedSetWithArray:tagList)'s allObjects() -- delete any duplicates
    aURL's setResourceValue:tagList forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
end addTags:forURL:

(* checks every half second to see if the list of tags contains "Printing" *)
on checkTag:tagName forURL:aURL
    repeat 120 times
        set {theResult, theTags} to aURL's getResourceValue:(reference) forKey:(current application's NSURLTagNamesKey) |error|:(missing value)
        set tagList to (theTags as list)
        if tagList contains "Printing" then return
        delay 0.5
    end repeat
    display alert "tagging timed out after 1 minute"
end checkTag:forURL:

I fixed one (potential) error in your script; see the text comment inline.

This assumes that you are only adding a single tag. If you want to add (and check) for multiple tags, you'll need to complexity checkTag:forURL. Also, I haven't done much with error handling (any case where for some reason adding the tag fails) except toss up an alert. I used a contingent repeat loop to keep it from going on infinitely on failure, but you may want it to fail silently, or do something else at that point.