Hello,
I have an AppleScript that needs to have a customized version to be run on hundreds of machines, each machine having a different version of the script. My thought was to separate the customized details into one file, and then have a “codebase script” (CodeBaseTest.scpt) file that would be included on them. That way, I could maintain one codebase file more easily.
Because I don’t know the version of macOS running (and it may be as far back as 10.13), I need to keep things super simple. Furthermore, because they won’t have script libraries installed, I can’t use that mechanism for a codebase lib. That also rules out the third party tools, I believe, that make it easier to produce scripts with includes (whether a library, or something like Script Debugger).
So, I’ve gone ahead and split it to 2 scripts:
first.last.scpt << customized for each machine
CodeBaseTest.scpt << is copied to the same folder as first.last.scpt so it’s in the same folder
To make this work, and to make it easy to test new versions of code in the code base, I wanted to make the “on run” handler the same in both files – but this isn’t a must, just made it easier to do things.
Also to make it work, I had to remove all the properties and move to globals with declarations and then a set to make the defaults work.
The problem is that the scripts are not seeing variables that are clearly defined as globals.
There are two sets of these two files below – a short set, and a set that has a ton of debug code in the two files here (which will make the errors very obvious if you run them).
Short set first
first.last-test.scpt here:
on run
global myPath, myName, scriptFileExtension, myLibFilename, myLib
set myPath to (path to me) as text
set myName to ((name of me) as text)
set scriptFileExtension to ".scpt"
set myLibFilename to "CodeBaseTest" & scriptFileExtension
if (myName & scriptFileExtension) is not myLibFilename then
set myLib to load script (text 1 through ((length of myPath) - (length of (myName & scriptFileExtension))) of myPath & myLibFilename) as alias
else if (myName & scriptFileExtension) is myLibFilename then
set myLib to me
else
set fullErrorMsg to "Critical error assigning myLib or loading script. Script terminating. (main on run handler)" & return
log fullErrorMsg
display dialog fullErrorMsg
end if
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Assumptions that need to be defined early on… and are done so in initializeGlobals()
So that they can be used from either the user script (e.g., first.last.scpt) or test data
within code base script (i.e., OutlookCodeBase.scpt). First a check which file we're in.
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
initializeGlobals() of myLib
-- Account to copy to. If empty, defaults to first account in AcctsToAddList.
global theDestAcctParams, theDestAcctParamNames
set theDestAcctParams to {}
set theDestAcctParamNames to {}
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Accounts to Add: Custom User Account Parameters -- defined for each user
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
global AcctsToAddList
set AcctsToAddList to {¬
{"Field1", "Field2", "Field3"}, ¬
{"A", "B", "C"}, ¬
{"D", "E", "F"}, ¬
{EndOfListMarker}}
-- Main Script, and supporting routines, are executed by a routine in the OutlookCodeBase.scpt file
if (myName & scriptFileExtension) is not myLibFilename then
mainScript() of myLib
else
mainScript()
end if
end run
and CodeBaseTest.scpt (with debug code) here:
on initializeGlobals()
-- Additional logging takes place with the debugFlag set to true
global debugFlag
set debugFlag to true as boolean
global BlankUserPassword, EndOfListMarker
set BlankUserPassword to "" -- should remain blank and not seen
set EndOfListMarker to "ENDOFLIST"
end initializeGlobals
on mainScript()
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Log the time, so we know which run this is...
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
--if debugFlag then log "This run started at: " & (time string of (current date))
-- if theDestAcctParams is empty, copy first account from AcctsToAddList
if number of items in theDestAcctParams is 0 then
if number of items in AcctsToAddList is greater than 1 then
if debugFlag is true then log "theDestAcctParams is empty. copying 2nd item from AcctsToAddList"
set theDestAcctParams to item 2 of AcctsToAddList
else
log "!!! ERROR: not enough items in AcctsToAddList to copy"
end if
if debugFlag is true then log "theDestAcctParams is not empty."
end if
end mainScript
on run
global myPath, myName, scriptFileExtension, myLibFilename, myLib
set myPath to (path to me) as text
set myName to ((name of me) as text)
set scriptFileExtension to ".scpt"
set myLibFilename to "CodeBaseTest" & scriptFileExtension
if (myName & scriptFileExtension) is not myLibFilename then
set myLib to load script (text 1 through ((length of myPath) - (length of (myName & scriptFileExtension))) of myPath & myLibFilename) as alias
else if (myName & scriptFileExtension) is myLibFilename then
set myLib to me
else
set fullErrorMsg to "Critical error assigning myLib or loading script. Script terminating. (main on run handler)" & return
log fullErrorMsg
display dialog fullErrorMsg
end if
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Assumptions that need to be defined early on… and are done so in initializeGlobals()
So that they can be used from either the user script (e.g., first.last.scpt) or test data
within code base script (i.e., OutlookCodeBase.scpt). First a check which file we're in.
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
initializeGlobals() of myLib
-- Account to copy to. If empty, defaults to first account in AcctsToAddList.
global theDestAcctParams, theDestAcctParamNames
set theDestAcctParams to {}
set theDestAcctParamNames to {}
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Accounts to Add: Custom User Account Parameters -- defined for each user
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
global AcctsToAddList
set AcctsToAddList to {¬
{"Field1", "Field2", "Field3"}, ¬
{"A", "B", "C"}, ¬
{"D", "E", "F"}, ¬
{EndOfListMarker}}
-- Main Script, and supporting routines, are executed by a routine in the OutlookCodeBase.scpt file
if (myName & scriptFileExtension) is not myLibFilename then
mainScript() of myLib
else
mainScript()
end if
end run
Anyone have any idea why this isn’t working? I’m sure (and hopeful) that I’m doing something stupid … after all, I am coding during a migraine … but I have to get this done today!
Thanks for reading (and even more if you can help)!
Neil
============================================================================
The below is just the same scripts, but the set with all the extra debug code:
============================================================================
first.last-test.scpt here:
on run
global actionsHistory
set actionsHistory to ""
global myPath, myName, scriptFileExtension, myLibFilename, myLib
set myPath to (path to me) as text
set myName to ((name of me) as text)
set scriptFileExtension to ".scpt"
set myLibFilename to "CodeBaseTest" & scriptFileExtension
set actionsHistory to actionsHistory & return & return & ¬
"• " & ("hello world from " & myName)
display dialog ("hello world from " & myName)
if (myName & scriptFileExtension) is not myLibFilename then
set myLib to load script (text 1 through ((length of myPath) - (length of (myName & scriptFileExtension))) of myPath & myLibFilename) as alias
else if (myName & scriptFileExtension) is myLibFilename then
set myLib to me
else
set fullErrorMsg to "Critical error assigning myLib or loading script. Script terminating. (main on run handler)" & return
log fullErrorMsg
display dialog fullErrorMsg
set actionsHistory to actionsHistory & return & return & ¬
"• " & fullErrorMsg
end if
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Assumptions that need to be defined early on… and are done so in initializeGlobals()
So that they can be used from either the user script (e.g., first.last.scpt) or test data
within code base script (i.e., OutlookCodeBase.scpt). First a check which file we're in.
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
try
initializeGlobals() of myLib
(*
if (myName & scriptFileExtension) is not myLibFilename then
initializeGlobals() of myLib
else
initializeGlobals()
end if
*)
on error errorStr number errorNum partial result resultList
set fullErrorMsg to ("Error is: " & errorStr & return & "Error number: " & errorNum & return & "Result List: " & resultList as text) ¬
& return & "Critical error initializing globals. Script terminating. (attempt to call initializeGlobals() in " & myName & ")"
log fullErrorMsg
display dialog fullErrorMsg
set actionsHistory to actionsHistory & return & return & ¬
"• " & fullErrorMsg
end try
-- Account to copy to. If empty, defaults to first account in AcctsToAddList.
global theDestAcctParams, theDestAcctParamNames
set theDestAcctParams to {}
set theDestAcctParamNames to {}
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Accounts to Add: Custom User Account Parameters -- defined for each user
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
global AcctsToAddList
set AcctsToAddList to {¬
{"Field1", "Field2", "Field3"}, ¬
{"A", "B", "C"}, ¬
{"D", "E", "F"}, ¬
{EndOfListMarker}}
-- Main Script, and supporting routines, are executed by a routine in the CodeBaseTest.scpt file
if (myName & scriptFileExtension) is not myLibFilename then
mainScript() of myLib
else
mainScript()
end if
display dialog "Action history is: " & return & return & actionsHistory
end run
and CodeBaseTest.scpt (with debug code) here:
on initializeGlobals()
display dialog ("hello world from initializeGlobals() in CodeBaseTest.scpt")
try
-- Additional logging takes place with the debugFlag set to true
global debugFlag
set debugFlag to true as boolean
global BlankUserPassword, EndOfListMarker
set BlankUserPassword to "" -- should remain blank and not seen
set EndOfListMarker to "ENDOFLIST"
on error errorStr number errorNum partial result resultList from badObject to expectedType
set fullErrorMsg to (("Error is: " & errorStr & return * " Error number: " & errorNum & return ¬
& "in script: " & myName & return ¬
& "Result List: " & resultList as text) & return ¬
& "badObject: " & badObject as text) & return ¬
& "Coercion failure: " & expectedType
log fullErrorMsg
display dialog fullErrorMsg
set actionsHistory to actionsHistory & return & return & ¬
"• " & fullErrorMsg
end try
display dialog ("In routine " & "initializeGlobals" & " (end)" & " in " & myName & " with debugFlag = " & debugFlag)
end initializeGlobals
on mainScript()
display dialog ("hello world from mainScript() in CodeBaseTest.scpt")
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Log the time, so we know which run this is...
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
try
display dialog ("In routine " & "mainScript" & " (start)" & " with debugFlag = " & debugFlag)
if debugFlag then log "This run started at: " & (time string of (current date))
on error errorStr number errorNum partial result resultList from badObject to expectedType
set fullErrorMsg to ("Error is: " & errorStr & return & " Error number: " & errorNum & return ¬
& "Result List: " & (resultList as text) & return ¬
& "badObject: " & (badObject as text) & return ¬
& "Coercion failure: " & expectedType)
log fullErrorMsg
display dialog fullErrorMsg
set actionsHistory to actionsHistory & return & return & ¬
"• " & fullErrorMsg
end try
-- if theDestAcctParams is empty, copy first account from AcctsToAddList
try
if number of items in theDestAcctParams is 0 then
if number of items in AcctsToAddList is greater than 1 then
if debugFlag is true then log "theDestAcctParams is empty. copying 2nd item from AcctsToAddList"
set theDestAcctParams to item 2 of AcctsToAddList
else
log "!!! ERROR: not enough items in AcctsToAddList to copy"
end if
if debugFlag is true then log "theDestAcctParams is not empty."
end if
on error errorStr number errorNum partial result resultList from badObject to expectedType
set fullErrorMsg to ("Error is: " & errorStr & return & " Error number: " & errorNum & return ¬
& "Result List: " & (resultList as text) & return ¬
& "badObject: " & (badObject as text) & return ¬
& "Coercion failure: " & expectedType)
log fullErrorMsg
display dialog fullErrorMsg
set actionsHistory to actionsHistory & return & return & ¬
"• " & fullErrorMsg
end try
end mainScript
on run
global actionsHistory
set actionsHistory to ""
global myPath, myName, scriptFileExtension, myLibFilename, myLib
set myPath to (path to me) as text
set myName to ((name of me) as text)
set scriptFileExtension to ".scpt"
set myLibFilename to "CodeBaseTest" & scriptFileExtension
set actionsHistory to actionsHistory & return & return & ¬
"• " & ("hello world from " & myName)
display dialog ("hello world from " & myName)
if (myName & scriptFileExtension) is not myLibFilename then
set myLib to load script (text 1 through ((length of myPath) - (length of (myName & scriptFileExtension))) of myPath & myLibFilename) as alias
else if (myName & scriptFileExtension) is myLibFilename then
set myLib to me
else
set fullErrorMsg to "Critical error assigning myLib or loading script. Script terminating. (main on run handler)" & return
log fullErrorMsg
display dialog fullErrorMsg
set actionsHistory to actionsHistory & return & return & ¬
"• " & fullErrorMsg
end if
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Assumptions that need to be defined early on… and are done so in initializeGlobals()
So that they can be used from either the user script (e.g., first.last.scpt) or test data
within code base script (i.e., OutlookCodeBase.scpt). First a check which file we're in.
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
try
initializeGlobals() of myLib
(*
if (myName & scriptFileExtension) is not myLibFilename then
initializeGlobals() of myLib
else
initializeGlobals()
end if
*)
on error errorStr number errorNum partial result resultList
set fullErrorMsg to ("Error is: " & errorStr & return & "Error number: " & errorNum & return & "Result List: " & resultList as text) ¬
& return & "Critical error initializing globals. Script terminating. (attempt to call initializeGlobals() in " & myName & ")"
log fullErrorMsg
display dialog fullErrorMsg
set actionsHistory to actionsHistory & return & return & ¬
"• " & fullErrorMsg
end try
-- Account to copy to. If empty, defaults to first account in AcctsToAddList.
global theDestAcctParams, theDestAcctParamNames
set theDestAcctParams to {}
set theDestAcctParamNames to {}
(* —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
Accounts to Add: Custom User Account Parameters -- defined for each user
—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
*)
global AcctsToAddList
set AcctsToAddList to {¬
{"Field1", "Field2", "Field3"}, ¬
{"A", "B", "C"}, ¬
{"D", "E", "F"}, ¬
{EndOfListMarker}}
-- Main Script, and supporting routines, are executed by a routine in the CodeBaseTest.scpt file
if (myName & scriptFileExtension) is not myLibFilename then
mainScript() of myLib
else
mainScript()
end if
display dialog "Action history is: " & return & return & actionsHistory
end run