###############################################################################
#
# pkgt.eagle --
#
# Extensible Adaptable Generalized Logic Engine (Eagle)
# Eagle Package Toolset Package File
#
# Copyright (c) 2007-2012 by Joe Mistachkin. All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: $
#
###############################################################################
#
# NOTE: Use our own namespace here because even though we do not directly
# support namespaces ourselves, we do not want to pollute the global
# namespace if this script actually ends up being evaluated in Tcl.
#
namespace eval ::Eagle {
#
# NOTE: This procedure sets up the default values for all configuration
# parameters used by this package. If the force argument is non-zero,
# any existing values will be overwritten and set back to their
# default values.
#
proc setupPackageToolsetVars { force } {
#
# NOTE: Using the [getAuxiliaryBaseUri] procedure requires the update
# package.
#
# NOTE: The base URI used to build the URIs for the Package Client
# Toolset downloads.
#
variable baseUri; # DEFAULT: [getAuxiliaryBaseUri] -OR- https://urn.to/r
if {$force || ![info exists baseUri]} then {
if {[isEagle]} then {
package require Eagle.Update
set baseUri [getAuxiliaryBaseUri]
} else {
set baseUri https://urn.to/r
}
}
#
# NOTE: The URN, relative to the base URI, where the Package Client
# Toolset may be downloaded.
#
variable packageToolsetUrn; # DEFAULT: pkg_client_only
if {$force || ![info exists packageToolsetUrn]} then {
set packageToolsetUrn pkg_client_only
}
#
# NOTE: The URI where the Package Client Toolset may be downloaded.
#
variable packageToolsetUri; # DEFAULT: ${baseUri}/${packageToolsetUrn}
if {$force || ![info exists packageToolsetUri]} then {
set packageToolsetUri {${baseUri}/${packageToolsetUrn}}
}
#
# NOTE: The URN, relative to the base URI, where the TclKit DLL for
# a particular platform may be downloaded.
#
variable tclKitDllUrn; # DEFAULT: tclkit_dll_${platform}
if {$force || ![info exists tclKitDllUrn]} then {
set tclKitDllUrn {tclkit_dll_${platform}}
}
#
# NOTE: The URI where the TclKit DLL for a particular platform may
# be downloaded.
#
variable tclKitDllUri; # DEFAULT: ${baseUri}/${urn}
if {$force || ![info exists tclKitDllUri]} then {
set tclKitDllUri {${baseUri}/${urn}}
}
#
# NOTE: The URN, relative to the base URI, where the Harpy and Badge
# plugins for a particular build may be downloaded.
#
variable securityToolsetUrn; # DEFAULT: security_toolset_${platform}
if {$force || ![info exists securityToolsetUrn]} then {
set securityToolsetUrn {security_toolset_${platform}}
}
#
# NOTE: The URI where the Harpy and Badge plugins for a particular
# build may be downloaded.
#
variable securityToolsetUri; # DEFAULT: ${baseUri}/${urn}
if {$force || ![info exists securityToolsetUri]} then {
set securityToolsetUri {${baseUri}/${urn}}
}
#
# NOTE: The URN, relative to the base URI, where license certificate
# requests should be sent.
#
variable licenseUrn; # DEFAULT: get_license_01
if {$force || ![info exists licenseUrn]} then {
set licenseUrn get_license_01
}
#
# NOTE: The URI where license certificate requests should be sent.
#
variable licenseUri; # DEFAULT: ${baseUri}/${urn}
if {$force || ![info exists licenseUri]} then {
set licenseUri {${baseUri}/${urn}}
}
}
#
# NOTE: This procedure attempts to download and extract the Package Client
# Toolset. The optional channel argument is the output channel where
# diagnostic information is sent. The optional quiet argument should
# be non-zero to prevent diagnostic information from being emitted.
# This procedure may raise script errors. The return value is the
# full path to the directory that should be added to the auto-path.
#
proc downloadAndExtractPackageClientToolset {
{channel stdout} {quiet false} } {
setupPackageToolsetVars false
variable baseUri
variable packageToolsetUri
variable packageToolsetUrn
package require Eagle.Test
package require Eagle.Unzip
set extractRootDirectory [getTemporaryPath]
set directory [file join $extractRootDirectory [appendArgs \
ea-pt-di- [pid] - [string trim [clock seconds] -]]]
set uri [subst $packageToolsetUri]
set fileName [getTemporaryFileName]
if {[isEagle]} then {
uri download $uri $fileName
} else {
package require Eagle.Tools.Common
namespace import \
::Eagle::Tools::Common::getFileViaHttp \
::Eagle::Tools::Common::writeFile
set data [getFileViaHttp $uri 20 $channel $quiet -binary true]
writeFile $fileName $data
}
set extractDirectory [extractZipArchive $fileName $extractRootDirectory]
return [file join $extractDirectory pkgr_an_d client 1.0 neutral]
}
#
# NOTE: This procedure attempts to download and extract a native TclKit DLL
# for the current platform. The optional channel argument is the
# output channel where diagnostic information is sent. The optional
# quiet argument should be non-zero to prevent diagnostic information
# from being emitted. This procedure may raise script errors. The
# return value is the full path to the native TclKit DLL file.
#
proc downloadAndExtractNativeTclKitDll {
{channel stdout} {quiet false} } {
setupPackageToolsetVars false
variable baseUri
variable tclKitDllUri
variable tclKitDllUrn
package require Eagle.Test
package require Eagle.Unzip
set extractRootDirectory [getTemporaryPath]
set directory [file join $extractRootDirectory [appendArgs \
ea-td-di- [pid] - [string trim [clock seconds] -]]]
set platform [machineToPlatform $::tcl_platform(machine) true]
set urn [subst $tclKitDllUrn]; set uri [subst $tclKitDllUri]
set fileName [getTemporaryFileName]
if {[isEagle]} then {
uri download $uri $fileName
} else {
package require Eagle.Tools.Common
namespace import \
::Eagle::Tools::Common::getFileViaHttp \
::Eagle::Tools::Common::writeFile
set data [getFileViaHttp $uri 20 $channel $quiet -binary true]
writeFile $fileName $data
}
set extractDirectory [extractZipArchive $fileName $extractRootDirectory]
return [lindex [glob -nocomplain \
[file join $extractDirectory lib *[info sharedlibextension]]] 0]
}
#
# NOTE: This procedure attempts to download and extract the Security Toolset,
# which includes the Harpy and Badge plugins. The optional channel
# argument is the output channel where diagnostic information is sent.
# The optional quiet argument should be non-zero to prevent diagnostic
# information from being emitted. This procedure may raise script
# errors. The return value is the full path to a directory that should
# contain the "Harpy1.0" and "Badge1.0" plugin directories.
#
proc downloadAndExtractSecurityToolset {
{channel stdout} {quiet false} } {
setupPackageToolsetVars false
variable baseUri
variable securityToolsetUri
variable securityToolsetUrn
package require Eagle.Test
package require Eagle.Unzip
set extractRootDirectory [getTemporaryPath]
set directory [file join $extractRootDirectory [appendArgs \
ea-st-di- [pid] - [string trim [clock seconds] -]]]
if {[info exists ::eagle_platform(text)]} then {
set platform [string tolower $::eagle_platform(text)]
} else {
set platform [string tolower netFx20]; # TODO: Good default?
}
set dir [string map [list fx ""] $platform]; # netfx20 -> net20
set urn [subst $securityToolsetUrn]; set uri [subst $securityToolsetUri]
set fileName [getTemporaryFileName]
if {[isEagle]} then {
uri download $uri $fileName
} else {
package require Eagle.Tools.Common
namespace import \
::Eagle::Tools::Common::getFileViaHttp \
::Eagle::Tools::Common::writeFile
set data [getFileViaHttp $uri 20 $channel $quiet -binary true]
writeFile $fileName $data
}
set extractDirectory [extractZipArchive $fileName $extractRootDirectory]
return [file join $extractDirectory build $dir lib]
}
#
# NOTE: This procedure attempts to request a license certificate for Eagle,
# which includes the Harpy and Badge plugins. The optional channel
# argument is the output channel where diagnostic information is sent.
# The optional quiet argument should be non-zero to prevent diagnostic
# information from being emitted. This procedure may raise script
# errors. The return value is the fully qualified file name for the
# resulting license certificate.
#
# WARNING: This procedure will send the short name and display name of the
# currently logged on user to the Eagle license server as they are
# required for a new license certificate to be issued. Abuse of
# this service may result in a permanent ban from the service and
# revocation of any previously issued license certificates.
#
proc requestLicenseCertificate {
{channel stdout} {quiet false} } {
setupPackageToolsetVars false
variable baseUri
variable licenseUri
variable licenseUrn
package require Eagle.Test
set certificateRootDirectory [getTemporaryPath]
set processDirectoryPrefix [file join $certificateRootDirectory \
[appendArgs ea-lc-di- [pid] -]]
#
# NOTE: Issue a warning to the user if it appears there is already a
# license certificate in a temporary directory that was created
# by this process. Hopefully, this should reduce the number of
# duplicate requests.
#
set varName1 YES_PLEASE_FORCE_A_LICENSE_CERTIFICATE_REQUEST
if {![info exists ::env($varName1)] && [isWindows]} then {
set processFileNames [list]
foreach processDirectory [findDirectories \
[appendArgs $processDirectoryPrefix *]] {
eval lappend processFileNames [findFiles \
[file join $processDirectory *]]
}
if {[llength $processFileNames] > 0} then {
set warningCommand [list]
if {[isEagle]} then {
lappend warningCommand host result Error
} else {
lappend warningCommand puts stderr
}
set varName2 Master_Certificate
lappend warningCommand [appendArgs \
"One or more temporary license certificate files " \
"apparently belonging to this process were found. " \
"If you wish to override this warning and force a " \
"new license certificate request to be submitted, " \
"set the \"" $varName1 "\" environment variable " \
"(to anything); however, please keep in mind that " \
"requesting too many license certificates and/or " \
"requesting license certificates too fast MAY be " \
"considered abusive behavior. Upon success, the " \
"resulting temporary license certificate file " \
"SHOULD be saved to a secure location on the local " \
"file system, e.g. the home directory associated " \
"with the user submitting the license certificate " \
"request. The fully qualified file name for the " \
"temporary license certificate MUST used as the " \
"value for the \"" $varName2 "\" environment " \
"variable; otherwise, it MAY NOT be found when one " \
"of its associated plugins attempts to load.\n"]
#
# NOTE: Emit our carefully worded license warning message.
#
eval $warningCommand
#
# NOTE: Return the first pre-existing license certificate file
# name that was found.
#
return [lindex $processFileNames 0]
}
}
set directory [appendArgs \
$processDirectoryPrefix [string trim [clock seconds] -]]
set urn [subst $licenseUrn]; set uri [subst $licenseUri]
if {![isEagle] || [catch {
object invoke System.Security.Principal.WindowsIdentity \
GetCurrent.Name
} userName]} then {
#
# HACK: Fallback to using a value from the "tcl_platform" array.
# For native Tcl, this is the only choice. For Eagle, it
# is used as a fallback.
#
if {[info exists ::tcl_platform(user)]} then {
set userName $::tcl_platform(user)
} else {
set userName "NO USER NAME"
}
}
if {![isEagle] || [catch {
object load System.DirectoryServices.AccountManagement
object invoke \
System.DirectoryServices.AccountManagement.UserPrincipal \
Current.DisplayName
} displayName]} then {
#
# HACK: Fallback to using a value from the "tcl_platform" array.
# This value is not set by native Tcl or Eagle; therefore,
# the user would have to set it manually prior to calling
# this procedure.
#
if {[info exists ::tcl_platform(userDisplayName)]} then {
set displayName $::tcl_platform(userDisplayName)
} else {
set displayName "NO DISPLAY NAME"
}
}
#
# NOTE: Add the necessary query parameters to the license request
# URI, making sure to properly escape their values.
#
if {[isEagle]} then {
append uri ?userName= [uri escape data $userName]
append uri &displayName= [uri escape data $displayName]
} else {
package require http 2.0
append uri ? [::http::formatQuery \
userName $userName displayName $displayName]
}
if {[isEagle]} then {
set data [uri download -inline $uri]
} else {
package require Eagle.Tools.Common
namespace import \
::Eagle::Tools::Common::getFileViaHttp \
::Eagle::Tools::Common::writeFile
set data [getFileViaHttp $uri 20 $channel $quiet -binary true]
package require Eagle.Auxiliary
}
if {[getDictionaryValue $data returnCode] ne "Ok"} then {
if {[string length $data] > 0} then {
error [appendArgs \
"request failed with error information: " $data]
} else {
error "request failed without providing error information"
}
}
set fileName [getTemporaryFileName]
writeFile $fileName [getDictionaryValue $data result]
set newFileName [file join $directory [file tail $fileName]]
file mkdir $directory; file copy $fileName $newFileName
file delete $fileName
return $newFileName
}
#
# NOTE: Provide the Eagle "package toolset" package to the interpreter.
#
package provide Eagle.Package.Toolset \
[expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
}