ADDED client/1.0/pkgIndex.eagle
Index: client/1.0/pkgIndex.eagle
==================================================================
--- client/1.0/pkgIndex.eagle
+++ client/1.0/pkgIndex.eagle
@@ -0,0 +1,24 @@
+###############################################################################
+#
+# pkgIndex.eagle --
+#
+# Extensible Adaptable Generalized Logic Engine (Eagle)
+# Package Index 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: $
+#
+###############################################################################
+
+if {![package vsatisfies [package provide Tcl] 8.4]} {return}
+if {![package vsatisfies [package provide Eagle] 1.0]} {return}
+
+package ifneeded Eagle.Package.Repository 1.0 \
+ [list source [file join $dir pkgr.eagle]]
+
+package ifneeded Eagle.Package.Downloader 1.0 \
+ [list source [file join $dir pkgd.eagle]]
ADDED client/1.0/pkgIndex.eagle.harpy
Index: client/1.0/pkgIndex.eagle.harpy
==================================================================
--- client/1.0/pkgIndex.eagle.harpy
+++ client/1.0/pkgIndex.eagle.harpy
@@ -0,0 +1,50 @@
+
+
+
+ None
+ Mistachkin Systems
+ b0129e44-3b2c-42b0-a71f-1c07aa16afd2
+ SHA512
+ Script
+ 2016-08-16T02:51:50.7605000Z
+ -1.00:00:00
+ 0x2c322765603b5278
+
+ nF615q+lJascFI+duD9pIrNyquMbrsLaX1Za3HFLitpOmFxsTcj+cKQ6d5y48SHsN6OlU4DMbyJX
+ egCciqoZqk8SEnkD6WgFjD+oKWQRsaRMnbmI3MmZOP/z1jSff6FeLwQQkDlkV9hhJRTo/rBBS6Vu
+ hfTmX7eVy4Uy+ifV8/i9T+/9dfS8DTifSWq1+6YSJuhETNDCmjnBxT+SrHeOdSZE0n65SPlb6Fde
+ yzVVPp/DfsA3cP3q9pMHDENyueXKAz0yXjunKJAXiGM1NNDLKkJ9YKpIxb4yV/uGMduK9KIy9hkQ
+ PlQQpn0Eh+fWst+DZlTl1PTL6sc9WJf9GSoAnNERIYvwA6z8eqRgRfXRhAsTEa+Om76Nt5so2Prz
+ jtUP39UldpoXhq87H2I4NkJfngcx0x3Jybv25nwMygQv0paXWAlaEFN49atMLXYO6F85ghi8dmps
+ zCY6O06FjnyI43RkBUYIvuDyU1q9HjVZbKiHr0YoFVhBCZDZp/lcxucIYG2sXpX5YKDT09WPMiUz
+ 1r/TO286Y2kJyzmgJMMjRmqTmOID6nTRSjvPSQCyFikJ8tCIWA78IiI2+/539J99VYfNmJoPRq3j
+ sBJ0IERsQCrp7baZkPiF/vzGEIScXtqAsxOKbep4oLEMt8mBmLOONkAwfo+mjjvtUy5s2ZYdnqQJ
+ 8EUbAKF7pRcgu7+w8LVMnGJr+dh5iJG0U8J6P2yrSeu+PRKr+aiX41/w1vJLRXZEljdqQ7PoIdPt
+ vsgFY+HoWs0pydJDcReMQDQtNczgn+88gv0IH5YL+7bp91yMqABR4RL7wekVv9IHSt2Da3l884Zn
+ WWb7Xso51BdH79a4zlSwHbbetu297ScvsmiNzCnyNYVa22Dx6UrVTl5OMao8219HJkjYlsXSkmQq
+ IZQwQXcutbp+alQ3v/uZMytujpL4+2wldzAFCuKWEzTOoBcroxnWfrFY80XyLmGODWU0j1Np+iJC
+ TAnErZYhU74BXFFHuRTLjjWhOqADSdCHk1K1zgs27k1uL6maIYU0wyYc4r/KuI+zKQ13JPYcauND
+ L1fTB6DTropeAZIZxlJAhZGadgs3UX8yx7JHIHgJQz4LjxCcRpxwvbz+o2PVcHoav9YJOLOzhfHK
+ 2+/XSxTalaF+XetBz2fDBYosj/JY61zy3YJPnaq/pc5r7TCDwF/hHPrAUZh84aMjsDNcOkU6DJSU
+ 0ykiZeFDm/A7XxVWANeBbfgci1UgK5VCdJr4A8kFDzwBWj+u1Q3bxmYxTJurpXBC/LRNh5s1/30B
+ KrG8eRNO4JlCGJbCqrgdVVF8gGa/MvuVKvsC2BWLtNsmVf2BUt3wkQEXxLtQdjv3yDMzxtBtTQ==
+
+
ADDED client/1.0/pkgIndex.tcl
Index: client/1.0/pkgIndex.tcl
==================================================================
--- client/1.0/pkgIndex.tcl
+++ client/1.0/pkgIndex.tcl
@@ -0,0 +1,24 @@
+###############################################################################
+#
+# pkgIndex.tcl --
+#
+# Extensible Adaptable Generalized Logic Engine (Eagle)
+# Package Index 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: $
+#
+###############################################################################
+
+if {![package vsatisfies [package provide Tcl] 8.4]} {return}
+if {[string length [package provide Eagle]] > 0} then {return}
+
+package ifneeded Eagle.Package.Repository 1.0 \
+ [list source [file join $dir pkgr.eagle]]
+
+package ifneeded Eagle.Package.Downloader 1.0 \
+ [list source [file join $dir pkgd.eagle]]
ADDED client/1.0/pkgIndex.tcl.harpy
Index: client/1.0/pkgIndex.tcl.harpy
==================================================================
--- client/1.0/pkgIndex.tcl.harpy
+++ client/1.0/pkgIndex.tcl.harpy
@@ -0,0 +1,50 @@
+
+
+
+ None
+ Mistachkin Systems
+ 69ca970a-0c3d-447a-91cf-44fed99731ee
+ SHA512
+ Script
+ 2016-08-16T02:54:51.9323750Z
+ -1.00:00:00
+ 0x2c322765603b5278
+
+ HjolMDm2KhyxiFYnQ7OlS81iIPJnyriCCNo4ATggqUhZP1ag2J7e7j4EHbit8RSgAYuPUnT3SFQH
+ yOxLq410LfAGS0p+jTfua7JwfeXIBOGf5zbOADM79TS9iTI0qSyqHBrvSmHBhsyoPxrGs07wcrpe
+ hKYneaf+j9rjJpVL0bUasIEsBtoVhXUXEubuLuiLclcCT5w/VoHHa5IP6ogNdch2zPYv1wT0Vmo4
+ RO3wHzvcMwCmyj0cV9z6QxoSVgmlHDRnODXRJP4kY+nzWsEkGlNy+Gy21qjL8h8fk+CWWU/AnqhC
+ M4VR4fJJYlfKBXFipq6SKCWe3dQV3skkE/ETVqPoTNW3I1/UcrH7CGZiWgCPoPGKFT1uVZt0aw5y
+ 9J9B1nuzNTxrPlyr3IM1UY91MBxyVO4sPUhvBYkhv36/CuWj7Nixlh9Mu7MyTGquj99l7K5/gThH
+ VkThdOn/Vn3+7X+8OfB6aDJmQotZzu1bqvywCqrtu/DbwE0QNRI/4VbVunZilAE0ULwwAEsCVqOQ
+ itILH2X2XVvNLFfRjK9BCVovyrzzmAj7bzj+furph1YY4XZmEDn/Sk+xbnHQencqAFjracL4kpOs
+ gZ7FaGgXcAuk8LmCfVD0HWGLiVVGMVMON35lu6FUfjiFkEZTuE104/ijZUce2KxWYQfbSwrv/Ywu
+ hUPSDRXnmaZwwYNSYVkR6zGinmWibVRWLWP6hLy0rf2xxU5bbRDhLddHoOVLdIV0s6SRMS87z1y4
+ I7mNnql6OVVl55O/Ro/GQgIkp2+gaMkef9/FDGS6jMufZA6EuCEJD0yraARofd100tjnln3EVa/r
+ tn0ggpaqEXyXlqv9plG9PONcjPbBp+/zPnfihOuzUEsxgi+mkoxmSQh9UWQ9ELdgrL0m9zoVr5IV
+ jdyHqWkAIoVM4ILN7ORsRTIKGqxqHxSiier0ySvgjaPFxd7M1uzaAuvFeCjMx74XCmsDFGEHbI49
+ jc++8u+rA+ZvCVL6nhv64QgP3ce4PYznUDhSDHkLGstaw5JOibPTgiUGvyPTFVJE1cwSmYUe6KuQ
+ 2oeD1DKFs4/U0n902tq2aly5H7plz4NLuV5kUy1EWCANQFi2A1LX0xMoztHdSagmdmvykIronkbP
+ kAawsH99A9ukY1Er09bw6WDMUX6aACZQw++/e0eQs/0hkWX7o+rFFQMgEbRz5g5q7+pXVkDd1T9x
+ WTHAMsXWaaDeB0hcA53HkB92APDnrUi04+YOu5F1Eh0+lIi7GA+Y5fFcItVaXzuog9bUIzUAvuPh
+ FJGnCHXQ+gKP2/Y6c2Kd/3+O8vHPUNwbQfH4vONk4j4WANYU7oqYczSkxejI7/FJ0qGO2pueoA==
+
+
ADDED client/1.0/pkgd.eagle
Index: client/1.0/pkgd.eagle
==================================================================
--- client/1.0/pkgd.eagle
+++ client/1.0/pkgd.eagle
@@ -0,0 +1,291 @@
+###############################################################################
+#
+# pkgd.eagle --
+#
+# Extensible Adaptable Generalized Logic Engine (Eagle)
+# Package Downloader Client
+#
+# 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 ::PackageDownloader {
+ #
+ # NOTE: This procedure sets up the default values for all configuration
+ # parameters used by the package downloader client. There are no
+ # arguments.
+ #
+ proc setupDownloadVars {} {
+ #
+ # NOTE: Prevent progress messages from being displayed while downloading
+ # from the repository, etc? By default, this is enabled.
+ #
+ variable quiet; # DEFAULT: true
+
+ if {![info exists quiet]} then {
+ set quiet true
+ }
+
+ #
+ # NOTE: The base URI for the package distribution web site.
+ #
+ variable baseUri; # DEFAULT: https://urn.to/r/pkgd
+
+ if {![info exists baseUri]} then {
+ set baseUri https://urn.to/r/pkgd
+ }
+
+ #
+ # NOTE: The URI where a single package file may be found. This file will
+ # belong to a specific version of one package.
+ #
+ variable downloadUri; # DEFAULT: ${baseUri}?...&filename=${fileName}
+
+ if {![info exists downloadUri]} then {
+ set downloadUri {${baseUri}?download&ci=trunk&filename=${fileName}}
+ }
+
+ #
+ # NOTE: The root directory where any persistent packages will be saved.
+ #
+ variable persistentDirectory; # DEFAULT: [getPersistentRootDirectory]
+
+ if {![info exists persistentDirectory]} then {
+ set persistentDirectory [getPersistentRootDirectory]
+ }
+ }
+
+ #
+ # NOTE: This procedure returns the root directory where any packages that
+ # are downloaded should be saved to permanent storage for subsequent
+ # use. There are no arguments.
+ #
+ proc getPersistentRootDirectory {} {
+ #
+ # NOTE: Return a directory parallel to the one containing the library
+ # directory.
+ #
+ return [file join [file dirname [info library]] pkgd]
+ }
+
+ #
+ # NOTE: This procedure adds a directory to the auto-path of the specified
+ # language (i.e. native Tcl or Eagle). The directory will not be
+ # added if it is already present. The language argument must be the
+ # literal string "eagle" or the literal string "tcl". The directory
+ # argument is the fully qualified path for the directory to add to
+ # the auto-path.
+ #
+ #
+ proc addToAutoPath { language directory } {
+ #
+ # NOTE: Add the specified directory to the auto-path if not already
+ # present.
+ #
+ if {[string length $language] == 0 || $language eq "eagle"} then {
+ if {[isEagle]} then {
+ if {![info exists ::auto_path] || \
+ [lsearch -exact $::auto_path $directory] == -1} then {
+ lappend ::auto_path $directory
+ }
+ } else {
+ ::PackageRepository::eagleMustBeReady
+
+ eagle [string map [list %directory% $directory] {
+ if {![info exists ::auto_path] || \
+ [lsearch -exact $::auto_path {%directory%}] == -1} then {
+ lappend ::auto_path {%directory%}
+ }
+ }]
+ }
+ } elseif {$language eq "tcl"} then {
+ if {[isEagle]} then {
+ tcl eval [tcl master] [string map [list %directory% $directory] {
+ if {![info exists ::auto_path] || \
+ [lsearch -exact $::auto_path {%directory%}] == -1} then {
+ lappend ::auto_path {%directory%}
+ }
+ }]
+ } else {
+ if {![info exists ::auto_path] || \
+ [lsearch -exact $::auto_path $directory] == -1} then {
+ lappend ::auto_path $directory
+ }
+ }
+ } else {
+ error "unsupported language, no idea how to modify auto-path"
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to download a list of files, optionally
+ # persistening them for subsequent uses by the target language.
+ # The language argument must be the literal string "eagle" or the
+ # literal string "tcl". The version argument must be the literal
+ # string "8.4", "8.5", or "8.6" when the language is "tcl" -OR-
+ # the literal string "1.0" when the language is "eagle". The
+ # fileNames argument must be a well-formed list of file names to
+ # download, each one relative to the language/version-specific
+ # directory on the package file server. The persistent argument
+ # should be non-zero if the downloaded files should be saved to
+ # permanent storage for subsequent use. The usePgp argument
+ # should be non-zero when an OpenPGP signature file needs to be
+ # downloaded and verified for each downloaded file. The
+ # useAutoPath argument should be non-zero to modify the auto-path
+ # to include the temporary or persistent directories containing
+ # the downloaded files.
+ #
+ #
+ proc downloadFiles {
+ language version fileNames persistent usePgp useAutoPath } {
+ variable baseUri
+ variable downloadUri
+ variable persistentDirectory
+ variable quiet
+
+ if {[string length $language] == 0 || $language eq "eagle"} then {
+ if {$version ne "1.0"} then {
+ error "unsupported Eagle version"
+ }
+ } elseif {$language eq "tcl"} then {
+ if {$version ne "8.4" && $version ne "8.5" && $version ne "8.6"} then {
+ error "unsupported Tcl version"
+ }
+ } else {
+ error "unsupported language"
+ }
+
+ if {$persistent} then {
+ set downloadRootDirectory $persistentDirectory
+ } else {
+ set directoryNameOnly [appendArgs \
+ pkgd_ [string trim [pid] -] _ [string trim [clock seconds] -]]
+
+ global env
+
+ if {[info exists env(PKGD_TEMP)]} then {
+ set downloadRootDirectory $env(PKGD_TEMP)
+ } elseif {[info exists env(TEMP)]} then {
+ set downloadRootDirectory $env(TEMP)
+ } elseif {[info exists env(TMP)]} then {
+ set downloadRootDirectory $env(TMP)
+ } else {
+ error "please set PKGD_TEMP (via environment) to temporary directory"
+ }
+
+ set downloadRootDirectory [file join \
+ $downloadRootDirectory $directoryNameOnly]
+ }
+
+ set downloadDirectories [list]
+
+ foreach fileName $fileNames {
+ if {[string length $fileName] == 0 || \
+ [file pathtype $fileName] ne "relative"} then {
+ error [appendArgs \
+ "bad file name \"" $fileName "\", not relative"]
+ }
+
+ set directoryParts [file split [file dirname $fileName]]
+
+ if {[llength $directoryParts] == 0} then {
+ error [appendArgs \
+ "bad file name \"" $fileName "\", no directory parts"]
+ }
+
+ set downloadDirectory [file normalize [eval file join \
+ [list $downloadRootDirectory] $directoryParts]]
+
+ set downloadFileName [file normalize [file join \
+ $downloadDirectory [file tail $fileName]]]
+
+ if {!$persistent} then {
+ catch {file delete $downloadFileName}
+ }
+
+ file mkdir [file dirname $downloadFileName]
+
+ set savedFileName $fileName
+ set fileName [file join $language $version $fileName]
+ set uri [subst $downloadUri]
+ set fileName $savedFileName
+
+ if {[isEagle]} then {
+ writeFile $downloadFileName \
+ [interp readorgetscriptfile -- "" $uri]
+ } else {
+ writeFile $downloadFileName \
+ [::PackageRepository::getFileViaHttp $uri 10 stdout $quiet]
+ }
+
+ if {$usePgp} then {
+ set downloadSignatureFileName [appendArgs $downloadFileName .asc]
+
+ set savedFileName $fileName
+ set fileName [file join \
+ $language $version [appendArgs $fileName .asc]]
+
+ set uri [subst $downloadUri]
+ set fileName $savedFileName
+
+ if {[isEagle]} then {
+ writeFile $downloadSignatureFileName \
+ [interp readorgetscriptfile -- "" $uri]
+ } else {
+ writeFile $downloadSignatureFileName \
+ [::PackageRepository::getFileViaHttp $uri 10 stdout $quiet]
+ }
+
+ if {![::PackageRepository::verifyPgpSignature \
+ $downloadSignatureFileName]} then {
+ error [appendArgs \
+ "bad PGP signature \"" $downloadSignatureFileName \"]
+ }
+ }
+
+ lappend downloadDirectories $downloadDirectory
+ }
+
+ set downloadDirectories [lsort -unique $downloadDirectories]
+
+ if {$useAutoPath} then {
+ foreach downloadDirectory $downloadDirectories {
+ addToAutoPath $language $downloadDirectory
+ }
+ }
+
+ return $downloadDirectories
+ }
+
+ #
+ # NOTE: This package requires the package repository client package.
+ #
+ package require Eagle.Package.Repository
+
+ #
+ # NOTE: Attempt to read optional settings file now. This may override
+ # one or more of the variable setup in the next step.
+ #
+ ::PackageRepository::maybeReadSettingsFile [info script]
+
+ #
+ # NOTE: Setup the variables, within this namespace, used by this script.
+ #
+ setupDownloadVars
+
+ #
+ # NOTE: Provide the package to the interpreter.
+ #
+ package provide Eagle.Package.Downloader \
+ [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
+}
ADDED client/1.0/pkgd.eagle.harpy
Index: client/1.0/pkgd.eagle.harpy
==================================================================
--- client/1.0/pkgd.eagle.harpy
+++ client/1.0/pkgd.eagle.harpy
@@ -0,0 +1,50 @@
+
+
+
+ None
+ Mistachkin Systems
+ 53a7ee35-d269-407b-9849-062af5a64876
+ SHA512
+ Script
+ 2016-08-19T02:47:10.2744609Z
+ -1.00:00:00
+ 0x2c322765603b5278
+
+ Yp/5NPzblsNKAItBjTMKYni6R3tyMPN2ZEGrwDcSZNi4/Y1QlXWD9BF/MdF0Glc93u7UpJw3Itwt
+ dYziRGX2yMsaddIx7gUawg5L7vc1eCz0BTohnSctzR1wU8My0BV5wCqDvAgJICtHWJM53H6XTLW3
+ CgtsZjXN0GRbDVEos3D77uK1BmPdSWLyi2L0SMA/QiGtlVY1lnP5/X6hpvBfbEX0YmDK45mEO1VR
+ lh2Y+aN+Jf05jiKjJwdOR4ZK1wDuW313FByM9FgDlRDpCXlnZfAeSnTPmCIafwOILlK3EZdHDJCy
+ 0gvFySMslL0m177+Sfpr7QW0F1ZZ4ENlse5i3ac33sF6RkAVvkmP9ZbjEq+N8+2G4v68+Yed7dET
+ 5Rwo//rU4QJE+To2oqJJpgv1ZsWcdqASUuof3o73gn8fRCZo95ctYvQHURzK7mFT/tTndsl/nlUq
+ PFeoltj0amd3sI86eHRR99rybruihdt6rETXCbhnh7+nJF6YL9SD73TX5O0+RBzOTRxkYKvdgGyX
+ pJ83iJtZC5N6SEySjiZlTAaLe4YTuJyaIkYDn/HWKMme7k8A7gK/Ig2iPTRUJiXm31hIn6VLfJXt
+ XFgoW9Ln0PAZlm4tNbeJraEeArU3YJ3vQ2FzNT7QgU1ruNiHbObOGhs76/a1XOSaoAXBRR8PgUIF
+ l+GWC77nJVGGeFwdUsDaJf6seEfnEV1Srp2mMFKT3Zo34Z3PMOZrcUxjGVj4tylewlq6zOWLis41
+ cKE450S7P/WZZ8I3Ab14uKUYfkwR0yI+DGo/Zp9rHvYcY7eadxMByFc0BjBoWv/kaGjjtnHmLaap
+ e53Xm1u3oFiecYh/0+74gKZB3XcMWLJNXR/wSQR55NdOXGADoqnWBEGdlC8EHFObbE4K+v9mVmag
+ F2nmPPk+mbqOl2hRA5ZLutV2iR49bRghbVNPD0Me/lhoiqT9FrSTZWbggLy8ZanTn/CcaWORMJJi
+ gzDNED9UU/YAsXg4NYE376zKDuZWhUUwAmsjOlMksILIhiSCU0oH59AcXgLjKs9dtpCZP/t/IClr
+ wKfnm6CgHO2KjnB5kvCsSEmBFiciPkzzLJYGn1PYON/8/9bLXqeu65NjEl/Z+mNRP65565DWVYiN
+ QFcQbXbYZxDDgmjfYm85w4bOKkesGKkenT/o9jMnUksrbO85MVL1f77riYTvmK6w0mWuwmBxPxaD
+ nPZc2+D6uB2GHhh4bkYdgtQtaiKOSbdKjGVba1eLLzODYlrxwOZ6I1bJNvP0HoxHkpVoLacF8MgV
+ CODZzXo/MdVbDDT/5KHgBrXCvRUquhbpNNC7Ut5kvb5O9svvWrr6x0/S0oq8E3JYGD3/tZrErA==
+
+
ADDED client/1.0/pkgd.settings.eagle
Index: client/1.0/pkgd.settings.eagle
==================================================================
--- client/1.0/pkgd.settings.eagle
+++ client/1.0/pkgd.settings.eagle
@@ -0,0 +1,17 @@
+###############################################################################
+#
+# pkgd.settings.eagle --
+#
+# Extensible Adaptable Generalized Logic Engine (Eagle)
+# Package Downloader Client Settings
+#
+# 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: $
+#
+###############################################################################
+
+variable quiet false
ADDED client/1.0/pkgd.settings.eagle.harpy
Index: client/1.0/pkgd.settings.eagle.harpy
==================================================================
--- client/1.0/pkgd.settings.eagle.harpy
+++ client/1.0/pkgd.settings.eagle.harpy
@@ -0,0 +1,50 @@
+
+
+
+ None
+ Mistachkin Systems
+ 88bd4979-4392-42f3-a0e6-a6d2bb881e55
+ SHA512
+ Script
+ 2016-08-19T02:27:08.9736797Z
+ -1.00:00:00
+ 0x2c322765603b5278
+
+ P36p/qj9tAsoQPeWuc9Pk3g0O51CX9d/AIsxoMlrjtIreeCFn1Ki3x2KA3Jp7CKuShzSd7ZVbtGD
+ 4X7uNtPyoiRS3NitWI/hyR0wEN+tWqK+ImLatg4ZUjYCgbqJcGgTWsQZuJqj9X6a7nRhMrH4rJAB
+ uu92jWB/AHIcGTyMY/1Uw1u5/M3K2kePYnKIkZTmuNndrLBJa525osq3OeiowCshJE2ao+Yjx1RW
+ whTgplY5hBrgZVLnsSF/hXEXFCamsr7ZCHRjj99pX+7ycMUyyIIm+kVWY/OS9VjO+Mhu2Adq+JBu
+ 266BF7hDvDReEk5musXDPhZJD//ZS8blH+x+YxGHGfjw88ij9ISudRLkuv53UaGyXRLEyWvaCAHq
+ WSfiuaHgHSGTGPlXYWJBeQJO4r4NMs8kp/+cTL9HLwGN5UQpQ+CabnKnuGALrZdKwdojr/cS/QPK
+ znw85PdV2v0cGsHcGy/1qPo84pvtCX1D9aq5djmwhh4Wkg0saXAdJyr0XyNH8xniJ97hHO621QfD
+ BJpEtI5hOn9F74887mWsRb81zDpi66CgkFNQwgLY4tsJMulGc2inNC8Z4ZcPZHWUfSC9M1RfwlvL
+ 8eZ4HVK+IlGJPZpWS4qbca+ph25Uu3EPnzHLzqHiEHXd/ybWeTvQyorqvBCsjVOQ0HOv7GC11+6+
+ RrO92mnX0+u69guvosE/H+G59pXsTPTW8/mGHSvsRV0lihILje3bBUCpWZk8Vaa0HmH9i/hkDicY
+ bs1LoTyfVRabBUIfLOujSnszlqVfc2EGZXdccVuBolsonVddzr+czcL+1SzSLtE2m7lsTgE/1mUj
+ oGlFhUekWPtfHw/nHEHQ09XZHPsQ5E6uCw2sI0mYDtTa6sGTk1H3eWVEwOTFheqrAx+kyAAk6Rcp
+ 18mg6QBaieARwUFXwdA7KT7tq7yDlB9x3yjem3aFLKWAszwqxA9RT+6WrdgcCKucWrE3gu3EZz+M
+ GzZ9s87hsvah/6lATnPia11vfGJKiEkTS5WI7uTDwAY1Iru9+qyTxFqQLQzhxtz+p186VOvYbotU
+ lZHXnl+bs1gzaUHnOSrSCiuMURaEjLfKBeySuHdzbBe8g5H6SISCujx2t7D7g/ZyBH0Lcfs1i1Wf
+ awwzORvocDdoQbKV8rO/U+CPxLkvqyuhmDi/LJi0os3k9iTKYN5M7WS0hKitxKGslRf0eiV6pzFB
+ yEDRUy5NlKwgz2Yi8dAJS2cr6O54NWCI7adW4L3PRL/La/2lISMS6oQgKe1NR6qmAiAECkqXDlHb
+ uESRIJ0JRYNHgLwYPqGS0ZWTZ5yQGAitOcO2GXvbL8O3hXpLalLF8ePvGzCZZMuWxspMCk8D2g==
+
+
ADDED client/1.0/pkgr.eagle
Index: client/1.0/pkgr.eagle
==================================================================
--- client/1.0/pkgr.eagle
+++ client/1.0/pkgr.eagle
@@ -0,0 +1,1567 @@
+###############################################################################
+#
+# pkgr.eagle --
+#
+# Extensible Adaptable Generalized Logic Engine (Eagle)
+# Package Repository Client
+#
+# 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 ::PackageRepository {
+ #
+ # NOTE: This package absolutely requires the Eagle core script library
+ # package, even when it is being used by native Tcl. If needed,
+ # prior to loading this package, the native Tcl auto-path should
+ # be modified to include the "Eagle1.0" directory (i.e. the one
+ # containing the Eagle core script library file "init.eagle").
+ #
+ package require Eagle.Library
+
+ #
+ # NOTE: This procedure returns a formatted, possibly version-specific,
+ # package name, for use in logging.
+ #
+ proc formatPackageName { package version } {
+ return [string trim [appendArgs $package " " $version]]
+ }
+
+ #
+ # NOTE: This procedure returns a formatted script result. If the string
+ # result is empty, only the return code is used. The code argument
+ # must be an integer Tcl return code (e.g. from [catch]) and the
+ # result argument is the script result or error message.
+ #
+ proc formatResult { code result } {
+ switch -exact -- $code {
+ 0 {set codeString ok}
+ 1 {set codeString error}
+ 2 {set codeString return}
+ 3 {set codeString break}
+ 4 {set codeString continue}
+ default {set codeString [appendArgs unknown( $code )]}
+ }
+
+ if {[string length $result] > 0} then {
+ return [appendArgs $codeString ": " [list $result]]
+ } else {
+ return $codeString
+ }
+ }
+
+ #
+ # NOTE: This procedure emits a message to the package repository client
+ # log. The string argument is the content of the message to emit.
+ #
+ #
+ proc pkgLog { string } {
+ catch {
+ tclLog [appendArgs [pid] " : " [clock seconds] " : pkgr : " $string]
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to determine if a string is a valid list
+ # and returns non-zero when that is true. The value argument is
+ # the string to check.
+ #
+ proc stringIsList { value } {
+ if {[isEagle]} then {
+ return [string is list $value]
+ } else {
+ global tcl_version
+
+ if {[info exists tcl_version] && $tcl_version >= 8.5} then {
+ return [string is list $value]
+ } elseif {[catch {llength $value}] == 0} then {
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+
+ #
+ # NOTE: This procedure returns non-zero if the specified string value
+ # looks like a Harpy (script) certificate. The value argument
+ # is the string to check.
+ #
+ #
+ proc isHarpyCertificate { value } {
+ if {[string length $value] == 0 || [string first [string trim {
+
+ proc isPgpSignature { value } {
+ if {[string length $value] == 0 || [string first [string trim {
+ -----BEGIN PGP SIGNATURE-----
+ }] $value] != -1} then {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ #
+ # NOTE: This procedure returns a unique temporary file name. A script
+ # error is raised if this task cannot be accomplished. There are
+ # no arguments.
+ #
+ proc getFileTempName {} {
+ if {[isEagle]} then {
+ return [file tempname]
+ } else {
+ global env
+
+ if {[info exists env(PKGR_TEMP)]} then {
+ set directory $env(PKGD_TEMP)
+ } elseif {[info exists env(TEMP)]} then {
+ set directory $env(TEMP)
+ } elseif {[info exists env(TMP)]} then {
+ set directory $env(TMP)
+ } else {
+ error "please set PKGR_TEMP (via environment) to temporary directory"
+ }
+
+ set counter [expr {[pid] ^ int(rand() * 0xFFFF)}]
+
+ while {1} {
+ set fileNameOnly [format tcl%04X.tmp $counter]
+ set fileName [file join $directory $fileNameOnly]
+
+ if {![file exists $fileName]} then {
+ return $fileName
+ }
+
+ incr counter
+ }
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to verify the PGP signature contained in
+ # the specified (named) file. Non-zero is only returned if the PGP
+ # signature is verified successfully. A script error should not be
+ # raised by this procedure. The fileName argument must be the fully
+ # qualified path and file name of the PGP signature file to verify.
+ #
+ #
+ proc verifyPgpSignature { fileName } {
+ variable pgpCommand
+
+ if {[isEagle]} then {
+ set fileName [appendArgs \" $fileName \"]
+
+ if {[catch {
+ eval exec -success Success [subst $pgpCommand]
+ }] == 0} then {
+ return true
+ }
+ } else {
+ if {[catch {
+ eval exec [subst $pgpCommand] 2>@1
+ }] == 0} then {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ #
+ # NOTE: This procedure returns the prefix for fully qualified variable
+ # names that MAY be present in the global namespace. There are
+ # no arguments.
+ #
+ proc getLookupVarNamePrefix {} {
+ return ::pkgr_; # TODO: Make non-global?
+ }
+
+ #
+ # NOTE: This procedure returns a unique suffix for a fully qualified
+ # variable name that MAY be present in the global namespace.
+ # It is used (internally) to avoid any name collisions with
+ # variables and commands in the global namespace. There are
+ # no arguments.
+ #
+ proc getLookupVarNameSuffix {} {
+ return [appendArgs \
+ [string trim [pid] -] _ [string trim [clock seconds] -] _ \
+ [string trim [clock clicks -milliseconds] -]]; # TODO: Bad?
+ }
+
+ #
+ # NOTE: This procedure returns the list of API keys to use when looking
+ # up packages via the package repository server. An empty list
+ # is returned if no API keys are currently configured. There are
+ # no arguments.
+ #
+ proc getLookupApiKeys {} {
+ set varName [appendArgs [getLookupVarNamePrefix] api_keys]
+
+ if {[info exists $varName]} then {
+ return [set $varName]
+ }
+
+ global env
+ set varName [string trim $varName :]
+
+ if {[info exists env($varName)]} then {
+ return $env($varName)
+ }
+
+ return [list]; # NOTE: System default, which is "public-only".
+ }
+
+ proc getLookupBaseUri {} {
+ set varName [appendArgs [getLookupVarNamePrefix] base_uri]
+
+ if {[info exists $varName]} then {
+ return [set $varName]
+ }
+
+ global env
+ set varName [string trim $varName :]
+
+ if {[info exists env($varName)]} then {
+ return $env($varName)
+ }
+
+ return https://urn.to/r/pkg; # NOTE: System default.
+ }
+
+ #
+ # NOTE: This procedure returns the full URI to use when looking up a
+ # specific package via the package repository server. The apiKey
+ # argument is the API key to use -OR- an empty string if a public
+ # package is being looked up. The package argument is the name
+ # of the package being looked up, it cannot be an empty string.
+ # The version argument is the specific version being looked up
+ # -OR- an empty string for any available version. No HTTP request
+ # is issued by this procedure; it just returns the URI to use.
+ #
+ proc getLookupUri { apiKey package version } {
+ set baseUri [getLookupBaseUri]
+
+ if {[string length $baseUri] == 0} then {
+ return ""
+ }
+
+ #
+ # NOTE: Build the HTTP request URI using the specified query parameter
+ # values, escaping them as necessary. Also, include the standard
+ # query parameters with constant values for this request type.
+ #
+ if {[isEagle]} then {
+ return [appendArgs \
+ $baseUri ?raw=1&method=lookup&apiKey= [uri escape uri $apiKey] \
+ &package= [uri escape uri $package] &version= [uri escape uri \
+ $version]]
+ } else {
+ package require http 2.0
+
+ return [appendArgs \
+ $baseUri ? [http::formatQuery raw 1 method lookup apiKey $apiKey \
+ package $package version $version]]
+ }
+ }
+
+ #
+ # NOTE: This procedure returns the version of the package that should be
+ # used to lookup the associated [package ifneeded] script -OR- an
+ # empty string if no such version exists. The package argument is
+ # the name of the package, it cannot be an empty string. The
+ # version argument is the specific version being looked up -OR- an
+ # empty string for any available version.
+ #
+ proc getIfNeededVersion { package version } {
+ if {[string length $version] > 0} then {
+ return $version
+ }
+
+ return [lindex [package versions $package] 0]
+ }
+
+ #
+ # NOTE: This procedure accepts a package requirement (spec) and returns
+ # a simple package version, if possible. An empty string will be
+ # returned, if appropriate (i.e. any version should be allowed).
+ # The requirement argument must be a package specification that
+ # conforms to TIP #268.
+ #
+ proc packageRequirementToVersion { requirement } {
+ set result $requirement
+
+ if {[set index [string first - $result]] != -1} then {
+ incr index -1; set result [string range $result 0 $index]
+ }
+
+ if {[set index [string first a $result]] != -1 || \
+ [set index [string first b $result]] != -1} then {
+ incr index -1; set result [string range $result 0 $index]
+ }
+
+ if {$result eq "0"} then {
+ set result ""
+ } elseif {[regexp -- {^\d+$} $result]} then {
+ append result .0
+ }
+
+ return $result
+ }
+
+ #
+ # NOTE: This procedure issues an HTTP request that should return metadata
+ # that can be used to load and/or provide the specified package.
+ # The apiKey argument is the API key to use -OR- an empty string if
+ # a public package is being looked up. The package argument is the
+ # name of the package, it cannot be an empty string. The version
+ # argument is the specific version being looked up -OR- an empty
+ # string for any available version. This procedure may raise script
+ # errors. All line-endings are normalized to Unix-style; therefore,
+ # all script signatures must assume this.
+ #
+ proc getLookupData { apiKey package version } {
+ variable verboseUriDownload
+
+ set uri [getLookupUri $apiKey $package $version]
+
+ if {[string length $uri] == 0} then {
+ return ""
+ }
+
+ if {$verboseUriDownload} then {
+ pkgLog [appendArgs \
+ "attempting to download URI \"" $uri \"...]
+ }
+
+ if {[isEagle]} then {
+ set data [uri download -inline $uri]
+ } else {
+ set quiet [expr {!$verboseUriDownload}]
+ set data [getFileViaHttp $uri 10 stdout $quiet]
+ }
+
+ if {$verboseUriDownload} then {
+ pkgLog [appendArgs \
+ "raw response data is: " $data]
+ }
+
+ set data [string map [list <\; < >\; > "\; \" &\; &] $data]
+ set data [string map [list \r\n \n \r \n] $data]
+ set data [string trim $data]
+
+ return $data
+ }
+
+ #
+ # NOTE: This procedure attempts to extract the lookup code from the raw
+ # HTTP response data. The data argument is the raw HTTP response
+ # data. An empty string is returned if no lookup code is available.
+ #
+ proc getLookupCodeFromData { data } {
+ if {![stringIsList $data] || [llength $data] < 1} then {
+ return ""
+ }
+
+ return [lindex $data 0]
+ }
+
+ #
+ # NOTE: This procedure attempts to extract the lookup result from the raw
+ # HTTP response data. The data argument is the raw HTTP response
+ # data. An empty string is returned if no lookup result is available.
+ #
+ proc getLookupResultFromData { data } {
+ if {![stringIsList $data] || [llength $data] < 2} then {
+ return ""
+ }
+
+ return [lindex $data 1]
+ }
+
+ #
+ # NOTE: This procedure returns non-zero if the specified lookup response
+ # code indicates success. The code argument is the extracted HTTP
+ # lookup response code.
+ #
+ proc isLookupCodeOk { code } {
+ #
+ # NOTE: The code must be the literal string "OK" for the package lookup
+ # request to be considered successful.
+ #
+ return [expr {$code eq "OK"}]
+ }
+
+ #
+ # NOTE: This procedure was stolen from the "common.tcl" script used by the
+ # package repository server. It has been modified to support both
+ # native Tcl and Eagle. It should be noted here that TIP #268 syntax
+ # is not supported by Eagle. For native Tcl, the requirement argument
+ # must be a package version or requirement conforming to the TIP #268
+ # syntax. For Eagle, the requirement argument must be a simple dotted
+ # package version, with up to four components, without any 'a' or 'b'.
+ # The emptyOk argument should be non-zero if an empty string should be
+ # considered to be valid by the caller. The rangeOk argument should
+ # be non-zero if the version range syntax is allowed; this argument is
+ # ignored for Eagle because it requires TIP #268 support.
+ #
+ proc isValidPackageRequirement { requirement rangeOk {emptyOk false} } {
+ if {$emptyOk && [string length $requirement] == 0} then {
+ return true
+ }
+
+ if {[isEagle]} then {
+ #
+ # NOTE: Eagle does not support TIP #268. Use the built-in sub-command
+ # that checks a version number.
+ #
+ return [string is version -strict $requirement]
+ } else {
+ #
+ # HACK: If a version range is not allowed, make sure that the dash
+ # character is not present.
+ #
+ if {!$rangeOk && [string first - $requirement] != -1} then {
+ return false
+ }
+
+ #
+ # HACK: There is no direct way to check if a package requirement
+ # that uses the TIP #268 syntax is valid; however, we can
+ # purposely "misuse" the [package present] command for this
+ # purpose. We know the "Tcl" package is always present;
+ # therefore, if an error is raised here, then the package
+ # requirement is probably invalid. Unfortunately, the error
+ # message text has to be checked as well; otherwise, there
+ # is no way to verify version numbers that happen to be less
+ # than the running patch level of Tcl.
+ #
+ if {[catch {package present Tcl $requirement} error] == 0} then {
+ return true
+ } else {
+ #
+ # TODO: Maybe this will require updates in the future?
+ #
+ set pattern(1) "expected version number but got *"
+ set pattern(2) "expected versionMin-versionMax but got *"
+
+ if {![string match $pattern(1) $error] && \
+ ![string match $pattern(2) $error]} then {
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to extract the package lookup metadata from
+ # the lookup result. The result argument is the lookup result. The
+ # varName argument is the name of an array variable, in the call frame
+ # of the immediate caller, that should receive the extracted package
+ # lookup metadata. The caller argument must be an empty string -OR-
+ # the literal string "handler".
+ #
+ proc extractAndVerifyLookupMetadata { result varName caller } {
+ variable strictUnknownLanguage
+
+ #
+ # NOTE: Grab the returned patch level. It cannot be an empty string
+ # and it must conform to the TIP #268 requirements for a single
+ # package version.
+ #
+ set patchLevel [getDictionaryValue $result PatchLevel]
+
+ if {[string length $patchLevel] == 0} then {
+ error "missing patch level"
+ }
+
+ if {![isValidPackageRequirement $patchLevel false]} then {
+ error "bad patch level"
+ }
+
+ #
+ # NOTE: Grab the language for the package script. It must be an empty
+ # string, "Tcl", or "Eagle". If it is an empty string, "Eagle"
+ # will be assumed.
+ #
+ set language [getDictionaryValue $result Language]
+
+ if {[lsearch -exact [list "" Tcl Eagle] $language] == -1} then {
+ error "unsupported language"
+ }
+
+ #
+ # NOTE: Grab the package script. If it is an empty string, then the
+ # package cannot be loaded and there is nothing to do. In that
+ # case, just raise an error.
+ #
+ set script [getDictionaryValue $result Script]
+
+ if {[string length $script] == 0} then {
+ error "missing script"
+ }
+
+ #
+ # NOTE: Grab the package script certificate. If it is an empty string
+ # then the package script is unsigned, which is not allowed by
+ # this client. In that case, just raise an error.
+ #
+ set certificate [getDictionaryValue $result Certificate]
+
+ if {[string length $certificate] == 0} then {
+ error "missing script certificate"
+ }
+
+ #
+ # NOTE: Are we being called from the [package unknown] handler
+ # in "strict" mode?
+ #
+ if {$strictUnknownLanguage && $caller eq "handler"} then {
+ #
+ # NOTE: If so, the package script must be targeted at the this
+ # language; otherwise, there exists the possibility that
+ # the package may not be provided to this language.
+ #
+ if {[isEagle]} then {
+ if {$language ne "Eagle"} then {
+ error "repository package is not for Eagle"
+ }
+ } else {
+ if {$language ne "Tcl"} then {
+ error "repository package is not for Tcl"
+ }
+ }
+ }
+
+ #
+ # NOTE: If the caller wants the package lookup metadata, use their
+ # array variable name.
+ #
+ if {[string length $varName] > 0} then {
+ upvar 1 $varName metadata
+
+ set metadata(patchLevel) $patchLevel
+ set metadata(language) $language
+ set metadata(script) $script
+ set metadata(certificate) $certificate
+ }
+ }
+
+ #
+ # NOTE: This procedure, which may only be used from an Eagle script, checks
+ # if a native Tcl library is loaded and ready. If not, a script error
+ # is raised.
+ #
+ proc tclMustBeReady {} {
+ #
+ # NOTE: This procedure is not allowed to actually load a native Tcl
+ # library; therefore, one must already be loaded.
+ #
+ if {![isEagle]} then {
+ error "already running in Tcl language"
+ }
+
+ if {![tcl ready]} then {
+ error "cannot use Tcl language, supporting library is not loaded"
+ }
+ }
+
+ #
+ # NOTE: This procedure, which may only be used from a native Tcl script,
+ # checks if Garuda and Eagle are loaded and ready. If not, a script
+ # error is raised.
+ #
+ proc eagleMustBeReady {} {
+ #
+ # NOTE: This procedure is not allowed to actually load Garuda (and
+ # Eagle); therefore, they must already be loaded.
+ #
+ if {[isEagle]} then {
+ error "already running in Eagle language"
+ }
+
+ if {[llength [info commands eagle]] == 0} then {
+ error "cannot use Eagle language, supporting package is not loaded"
+ }
+ }
+
+ #
+ # NOTE: This procedure returns non-zero if the current script is being
+ # evaluated in Eagle with signed-only script security enabled.
+ # There are no arguments.
+ #
+ proc eagleHasSecurity {} {
+ #
+ # NOTE: If possible, check if the current interpreter has security
+ # enabled.
+ #
+ if {[isEagle] && [llength [info commands object]] > 0} then {
+ if {[catch {
+ object invoke -flags +NonPublic Interpreter.GetActive HasSecurity
+ } security] == 0 && $security} then {
+ return true
+ }
+ }
+
+ return false
+ }
+
+ #
+ # NOTE: This procedure uses the package lookup metadata. If the package
+ # script is properly signed, an attempt will be made to evaluate it
+ # in the target language. If the script was signed using PGP, then
+ # a conforming implementation of the OpenPGP specification (e.g.
+ # gpg2) must be installed locally. If the script was signed using
+ # Harpy then Garuda, Eagle, and Harpy must be installed locally.
+ # This procedure is designed to work for both native Tcl and Eagle
+ # packages. Additionally, it is designed to work when evaluated
+ # using either native Tcl or Eagle; however, it is up to the package
+ # script itself to either add the package or provide the package to
+ # the language(s) supported by that package. The varName argument
+ # is the name of an array variable in the call frame of the
+ # immediate caller, that contains the package lookup metadata. This
+ # procedure may raise script errors.
+ #
+ proc processLookupMetadata { varName } {
+ #
+ # NOTE: If the metadata variable name appears to be invalid, fail.
+ #
+ if {[string length $varName] == 0} then {
+ error "bad metadata"
+ }
+
+ #
+ # NOTE: This procedure requires that the metadata array variable is
+ # present in the call frame immediately above this one.
+ #
+ upvar 1 $varName metadata
+
+ #
+ # NOTE: If the entire package metadata array is missing, fail.
+ #
+ if {![info exists metadata]} then {
+ error "missing metadata"
+ }
+
+ #
+ # NOTE: If the patch level for the package is mising, fail.
+ #
+ if {![info exists metadata(patchLevel)]} then {
+ error "missing patch level"
+ }
+
+ #
+ # NOTE: If the language for the package script is mising, fail.
+ #
+ if {![info exists metadata(language)]} then {
+ error "missing language"
+ }
+
+ #
+ # NOTE: If the package script is mising, fail.
+ #
+ if {![info exists metadata(script)]} then {
+ error "missing script"
+ }
+
+ #
+ # NOTE: If the package script certificate is mising, fail.
+ #
+ if {![info exists metadata(certificate)]} then {
+ error "missing script certificate"
+ }
+
+ #
+ # NOTE: Create common cleanup script block that deletes any temporary
+ # files created for the script verification process.
+ #
+ set script(cleanup) {
+ if {[string length $fileName(2)] > 0 && \
+ [file exists $fileName(2)] && [file isfile $fileName(2)]} then {
+ if {![info exists ::env(pkgr_keep_files)]} then {
+ catch {file delete $fileName(2)}
+ }
+ unset -nocomplain fileName(2)
+ }
+
+ if {[string length $fileName(1)] > 0 && \
+ [file exists $fileName(1)] && [file isfile $fileName(1)]} then {
+ if {![info exists ::env(pkgr_keep_files)]} then {
+ catch {file delete $fileName(1)}
+ }
+ unset -nocomplain fileName(1)
+ }
+ }
+
+ #
+ # NOTE: Figure out the "type" of script certificate we are now dealing
+ # with.
+ #
+ if {[isHarpyCertificate $metadata(certificate)]} then {
+ #
+ # NOTE: Attempt to create a completely unique array variable name to
+ # hold the package metadata in this scripting language as well
+ # as possibly in the other necessary scripting language(s).
+ #
+ set newVarName(1) [appendArgs \
+ [getLookupVarNamePrefix] metadata_ [getLookupVarNameSuffix]]
+
+ set newVarName(2) [appendArgs \
+ [getLookupVarNamePrefix] cleanup_ [getLookupVarNameSuffix]]
+
+ set newProcName(1) [appendArgs \
+ [getLookupVarNamePrefix] eagleHasSecurity_ [getLookupVarNameSuffix]]
+
+ set newProcName(2) [appendArgs \
+ [getLookupVarNamePrefix] getFileTempName_ [getLookupVarNameSuffix]]
+
+ set newProcName(3) [appendArgs \
+ [getLookupVarNamePrefix] tclMustBeReady_ [getLookupVarNameSuffix]]
+
+ #
+ # NOTE: Create the Eagle script block that will be used to securely
+ # evaluate a signed package script. This must be evaluated in
+ # Eagle because it uses several plugins only available there.
+ #
+ set script(outer) [string map [list \
+ %metadata% $newVarName(1) %cleanup% $newVarName(2) \
+ %eagleHasSecurity% $newProcName(1) %getFileTempName% \
+ $newProcName(2) %tclMustBeReady% $newProcName(3)] {
+ try {
+ #
+ # NOTE: If there is no package script, there is nothing we
+ # can do here.
+ #
+ if {[string length ${%metadata%(script)}] > 0} then {
+ #
+ # NOTE: Save the security state for the interpreter. Then, attempt
+ # to enable it. This will fail if one of the needed plugins
+ # cannot be loaded.
+ #
+ set savedSecurity [{%eagleHasSecurity%}]
+ if {!$savedSecurity} then {source enableSecurity}
+
+ try {
+ #
+ # NOTE: Figure out temporary file name for the downloaded script
+ # and its associated script certificate.
+ #
+ set fileName(1) [{%getFileTempName%}]
+ set fileName(2) [appendArgs $fileName(1) .harpy]
+
+ try {
+ #
+ # NOTE: Write downloaded script to a temporary file.
+ #
+ writeFile $fileName(1) ${%metadata%(script)}
+
+ #
+ # NOTE: Write downloaded script certificate to a temporary
+ # file.
+ #
+ if {[string length ${%metadata%(certificate)}] > 0} then {
+ writeFile $fileName(2) ${%metadata%(certificate)}
+ }
+
+ #
+ # NOTE: This seems stupid. Why are we reading the downloaded
+ # script from the temporary file when we already had it
+ # in memory? The reason is that we need to make sure
+ # that the Harpy policy engine has a chance to check the
+ # downloaded script against its associated certificate.
+ # This will raise a script error if the script signature
+ # is missing or invalid.
+ #
+ set script(inner) [interp readorgetscriptfile -- \
+ "" $fileName(1)]
+
+ #
+ # NOTE: Determine the target language for the package script,
+ # which may or may not be the language that is currently
+ # evaluating this script (Eagle). The default language,
+ # when one was not explicitly specified, is Eagle. In
+ # the future, this may be changed, e.g. to use the file
+ # extension of the client script.
+ #
+ switch -exact -- ${%metadata%(language)} {
+ "" -
+ Eagle {
+ #
+ # NOTE: The target language is Eagle, which is evaluating
+ # this script. No special handling is needed here.
+ #
+ return [uplevel #0 $script(inner)]
+ }
+ Tcl {
+ #
+ # NOTE: The target language is Tcl; therefore, a bit of
+ # special handling is needed here.
+ #
+ {%tclMustBeReady%}; return [tcl eval [tcl master] [list \
+ uplevel #0 $script(inner)]]
+ }
+ default {
+ error "unsupported language"
+ }
+ }
+ } finally {
+ #
+ # NOTE: Perform any necessary cleanup steps.
+ #
+ eval ${%cleanup%}
+ }
+ } finally {
+ #
+ # NOTE: Restore the saved security state for the interpreter.
+ #
+ if {!$savedSecurity} then {source disableSecurity}
+ unset -nocomplain savedSecurity
+ }
+ }
+ } finally {
+ rename {%tclMustBeReady%} ""
+ rename {%getFileTempName%} ""
+ rename {%eagleHasSecurity%} ""
+
+ unset -nocomplain {%cleanup%}
+ unset -nocomplain {%metadata%}
+ }
+ }]
+
+ #
+ # NOTE: Copy the package metadata into the fresh array variable,
+ # if necessary, marshalling it from native Tcl to Eagle.
+ #
+ if {[isEagle]} then {
+ array set $newVarName(1) [array get metadata]
+ set $newVarName(2) $script(cleanup)
+
+ proc $newProcName(1) {} [info body [appendArgs \
+ [namespace current] ::eagleHasSecurity]]
+
+ proc $newProcName(2) {} [info body [appendArgs \
+ [namespace current] ::getFileTempName]]
+
+ proc $newProcName(3) {} [info body [appendArgs \
+ [namespace current] ::tclMustBeReady]]
+
+ return [eval $script(outer)]
+ } else {
+ eagleMustBeReady
+
+ eagle [list array set $newVarName(1) [array get metadata]]
+ eagle [list set $newVarName(2) $script(cleanup)]
+
+ eagle [list proc $newProcName(1) {} [info body [appendArgs \
+ [namespace current] ::eagleHasSecurity]]]
+
+ eagle [list proc $newProcName(2) {} [info body [appendArgs \
+ [namespace current] ::getFileTempName]]]
+
+ eagle [list proc $newProcName(3) {} [info body [appendArgs \
+ [namespace current] ::tclMustBeReady]]]
+
+ return [eagle $script(outer)]
+ }
+ } elseif {[isPgpSignature $metadata(certificate)]} then {
+ #
+ # NOTE: If there is no package script, there is nothing we
+ # can do here.
+ #
+ if {[string length $metadata(script)] > 0} then {
+ #
+ # NOTE: Figure out temporary file name for the downloaded script
+ # and its associated PGP signature.
+ #
+ set fileName(1) [getFileTempName]
+ set fileName(2) [appendArgs $fileName(1) .asc]
+
+ #
+ # NOTE: Write downloaded script to a temporary file.
+ #
+ writeFile $fileName(1) $metadata(script)
+
+ #
+ # NOTE: Write downloaded script PGP signature a temporary file.
+ #
+ if {[string length $metadata(certificate)] > 0} then {
+ writeFile $fileName(2) $metadata(certificate)
+ }
+
+ #
+ # NOTE: Attempt to verify the PGP signature for the package script.
+ #
+ if {[verifyPgpSignature $fileName(2)]} then {
+ #
+ # NOTE: Delete the temporary files that we created for the PGP
+ # signature verification.
+ #
+ eval $script(cleanup)
+ } else {
+ #
+ # NOTE: Delete the temporary files that we created for the PGP
+ # signature verification.
+ #
+ eval $script(cleanup)
+
+ #
+ # NOTE: PGP signature verification failed. Raise an error and
+ # do not proceed with evaluating the package script.
+ #
+ error "bad PGP signature"
+ }
+
+ #
+ # NOTE: The PGP signature was verified; use the downloaded package
+ # script verbatim.
+ #
+ set script(inner) $metadata(script)
+
+ #
+ # NOTE: Determine the target language for the package script, which
+ # may or may not be the language that is currently evaluating
+ # this script (Eagle). The default language, when one was not
+ # explicitly specified, is Eagle. In the future, this may be
+ # changed, e.g. to use the file extension of the client script.
+ #
+ switch -exact -- $metadata(language) {
+ "" -
+ Eagle {
+ if {[isEagle]} then {
+ return [uplevel #0 $script(inner)]
+ } else {
+ eagleMustBeReady
+
+ return [eagle [list uplevel #0 $script(inner)]]
+ }
+ }
+ Tcl {
+ if {[isEagle]} then {
+ tclMustBeReady; return [tcl eval [tcl master] [list \
+ uplevel #0 $script(inner)]]
+ } else {
+ return [uplevel #0 $script(inner)]
+ }
+ }
+ default {
+ error "unsupported language"
+ }
+ }
+ }
+ } else {
+ error "unsupported script certificate"
+ }
+ }
+
+ #
+ # NOTE: This procedure performs initial setup of the package repository
+ # client, using the current configuration parameters. There are
+ # no arguments. It may load the Garuda package when evaluated in
+ # native Tcl. It may load a native Tcl library when evaluated in
+ # Eagle. It may install the [package unknown] hook.
+ #
+ proc setupPackageUnknownHandler {} {
+ variable autoHook
+ variable autoLoadTcl
+ variable autoRequireGaruda
+
+ if {$autoRequireGaruda && ![isEagle]} then {
+ #
+ # TODO: Assume this package is trusted? How can we verify it
+ # at this point?
+ #
+ package require Garuda
+ }
+
+ if {$autoLoadTcl && [isEagle]} then {
+ #
+ # NOTE: Load a native Tcl library. It must be signed with a valid
+ # Authenticode signature.
+ #
+ tcl load -findflags +TrustedOnly -loadflags +SetDllDirectory
+ }
+
+ if {$autoHook && ![isPackageUnknownHandlerHooked]} then {
+ #
+ # NOTE: Install our [package unknown] handler and save the original
+ # one for our use as well.
+ #
+ hookPackageUnknownHandler
+ }
+ }
+
+ #
+ # NOTE: This procedure returns non-zero if the [package unknown] handler
+ # has already been hooked by the package repository client. There
+ # are no arguments.
+ #
+ proc isPackageUnknownHandlerHooked {} {
+ return [info exists [appendArgs \
+ [getLookupVarNamePrefix] saved_package_unknown]]
+ }
+
+ #
+ # NOTE: This procedure attempts to hook the [package unknown] handler. It
+ # will raise a script error if this has already been done. The old
+ # [package unknown] handler is saved and will be used by the new one
+ # as part of the overall package loading process. There are no
+ # arguments.
+ #
+ proc hookPackageUnknownHandler {} {
+ set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
+
+ if {[info exists $varName]} then {
+ error "package unknown handler already hooked"
+ }
+
+ set $varName [package unknown]
+ package unknown [appendArgs [namespace current] ::packageUnknownHandler]
+ }
+
+ #
+ # NOTE: This procedure attempts to unhook the [package unknown] handler.
+ # It will raise a script error if the [package unknown] handler is
+ # not hooked. The old [package unknown] handler is restored and
+ # the saved [package unknown] handler is cleared. There are no
+ # arguments.
+ #
+ proc unhookPackageUnknownHandler {} {
+ set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
+
+ if {![info exists $varName]} then {
+ error "package unknown handler is not hooked"
+ }
+
+ package unknown [set $varName]
+ unset $varName
+ }
+
+ #
+ # NOTE: The procedure runs the saved [package unknown] handler. Any script
+ # errors are raised to the caller. The package and version arguments
+ # are passed in from the current [package unknown] handler verbatim.
+ #
+ proc runSavedPackageUnknownHandler { package version } {
+ #
+ # NOTE: See if there is a saved [package unknown] handler. If so, then
+ # attempt to use it.
+ #
+ set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
+ set oldHandler [expr {[info exists $varName] ? [set $varName] : ""}]
+
+ if {[string length $oldHandler] > 0} then {
+ lappend oldHandler $package $version; uplevel #0 $oldHandler
+ }
+ }
+
+ #
+ # NOTE: This procedure is the [package unknown] handler entry point called
+ # by native Tcl and Eagle. The package argument is the name of the
+ # package being sought, it cannot be an empty string. The version
+ # argument must be a specific version -OR- a package specification
+ # that conforms to TIP #268. This version argument must be optional
+ # here, because Eagle does not add a version argument when one is
+ # not explicitly supplied to the [package require] sub-command.
+ #
+ proc packageUnknownHandler { package {version ""} } {
+ variable verboseUnknownResult
+
+ #
+ # NOTE: First, run our [package unknown] handler.
+ #
+ set code(1) [catch {main $package $version handler} result(1)]
+
+ if {$verboseUnknownResult} then {
+ pkgLog [appendArgs \
+ "repository handler results for package \"" [formatPackageName \
+ $package $version] "\" are " [formatResult $code(1) $result(1)]]
+ }
+
+ #
+ # NOTE: Next, run the saved [package unknown] handler.
+ #
+ set code(2) [catch {
+ runSavedPackageUnknownHandler $package $version
+ } result(2)]
+
+ if {$verboseUnknownResult} then {
+ pkgLog [appendArgs \
+ "saved handler results for package \"" [formatPackageName \
+ $package $version] "\" are " [formatResult $code(2) $result(2)]]
+ }
+
+ #
+ # NOTE: Maybe check for the package and then optionally log results.
+ #
+ if {$verboseUnknownResult} then {
+ set ifNeededVersion [getIfNeededVersion \
+ $package [packageRequirementToVersion $version]]
+
+ if {[string length $ifNeededVersion] > 0} then {
+ set command [list package ifneeded $package $ifNeededVersion]
+
+ if {[catch $command result(3)] == 0 && \
+ [string length $result(3)] > 0} then {
+ pkgLog [appendArgs \
+ "package script for \"" [formatPackageName $package \
+ $ifNeededVersion] "\" was added: " [list $result(3)]]
+ } else {
+ pkgLog [appendArgs \
+ "package script for \"" [formatPackageName $package \
+ $ifNeededVersion] "\" was not added: " [list $result(3)]]
+ }
+ } else {
+ pkgLog [appendArgs \
+ "package script for \"" [formatPackageName $package \
+ $ifNeededVersion] "\" was not added"]
+ }
+
+ set command [list package present $package]
+ if {[string length $version] > 0} then {lappend command $version}
+
+ if {[catch $command] == 0} then {
+ pkgLog [appendArgs \
+ "package \"" [formatPackageName $package $version] \
+ "\" was loaded"]
+ } else {
+ pkgLog [appendArgs \
+ "package \"" [formatPackageName $package $version] \
+ "\" was not loaded"]
+ }
+ }
+ }
+
+ #
+ # NOTE: This procedure evaluates the package repository client settings
+ # script file, if it exists. Any script errors raised are not
+ # masked. The script argument must be the fully qualified path
+ # and file name for the primary package repository client script
+ # file.
+ #
+ proc maybeReadSettingsFile { script } {
+ if {[string length $script] == 0 || \
+ ![file exists $script] || ![file isfile $script]} then {
+ return
+ }
+
+ set fileName [appendArgs \
+ [file rootname $script] .settings [file extension $script]]
+
+ if {[file exists $fileName] && [file isfile $fileName]} then {
+ uplevel 1 [list source $fileName]
+ }
+ }
+
+ #
+ # NOTE: This procedure sets up the default values for all configuration
+ # parameters used by the package repository client. There are no
+ # arguments.
+ #
+ proc setupPackageUnknownVars {} {
+ #
+ # NOTE: Automatically install our [package unknown] handler when this
+ # package is loaded?
+ #
+ variable autoHook; # DEFAULT: true
+
+ if {![info exists autoHook]} then {
+ set autoHook true
+ }
+
+ #
+ # NOTE: Automatically [tcl load] when this package is loaded from the
+ # Eagle language?
+ #
+ variable autoLoadTcl; # DEFAULT: true
+
+ if {![info exists autoLoadTcl]} then {
+ set autoLoadTcl true
+ }
+
+ #
+ # NOTE: Automatically [package require Garuda] when this package is
+ # loaded from the Tcl language?
+ #
+ variable autoRequireGaruda; # DEFAULT: true
+
+ if {![info exists autoRequireGaruda]} then {
+ set autoRequireGaruda true
+ }
+
+ #
+ # NOTE: The command to use when verifying OpenPGP signatures for the
+ # downloaded package scripts.
+ #
+ variable pgpCommand; # DEFAULT: gpg2 --verify {${fileName}}
+
+ if {![info exists pgpCommand]} then {
+ set pgpCommand {gpg2 --verify {${fileName}}}
+ }
+
+ #
+ # NOTE: Verify that the package script matches the current language
+ # when called from the [package unknown] handler?
+ #
+ variable strictUnknownLanguage; # DEFAULT: true
+
+ if {![info exists strictUnknownLanguage]} then {
+ set strictUnknownLanguage true
+ }
+
+ #
+ # NOTE: Emit diagnostic messages when a [package unknown] handler
+ # is called?
+ #
+ variable verboseUnknownResult; # DEFAULT: false
+
+ if {![info exists verboseUnknownResult]} then {
+ set verboseUnknownResult false
+ }
+
+ #
+ # NOTE: Emit diagnostic messages when a URI is fetched?
+ #
+ variable verboseUriDownload; # DEFAULT: false
+
+ if {![info exists verboseUriDownload]} then {
+ set verboseUriDownload false
+ }
+ }
+
+ #
+ # NOTE: This procedure is the primary entry point to the package repository
+ # client. It attempts to lookup the specified package using the
+ # currently configured package repository server. The package
+ # argument is the name of the package being sought, it cannot be an
+ # empty string. The version argument must be a specific version -OR-
+ # a package specification that conforms to TIP #268. The caller
+ # argument must be an empty string -OR- the literal string "handler".
+ #
+ #
+ proc main { package version caller } {
+ #
+ # NOTE: Get the list of API keys and try each one, in order, until
+ # the package is found.
+ #
+ set apiKeys [getLookupApiKeys]; lappend apiKeys ""
+
+ foreach apiKey $apiKeys {
+ #
+ # NOTE: Issue the lookup request to the remote package repository.
+ #
+ set data [getLookupData $apiKey $package $version]
+
+ #
+ # NOTE: Attempt to grab the lookup code from the response data.
+ #
+ set code [getLookupCodeFromData $data]
+
+ #
+ # NOTE: Did the lookup operation succeed? If so, stop trying
+ # other API keys.
+ #
+ if {[isLookupCodeOk $code]} then {
+ break
+ }
+ }
+
+ #
+ # NOTE: Attempt to grab the lookup data from the response data.
+ # Upon failure, this should contain the error message.
+ #
+ set result [getLookupResultFromData $data]
+
+ #
+ # NOTE: Did the lookup operation fail?
+ #
+ if {![isLookupCodeOk $code]} then {
+ #
+ # NOTE: Is there an error message?
+ #
+ if {[string length $result] > 0} then {
+ #
+ # NOTE: Yes. Use the returned error message verbatim.
+ #
+ error $result
+ } else {
+ #
+ # NOTE: No. Use the whole response data string as the error
+ # message.
+ #
+ error $data
+ }
+ }
+
+ #
+ # NOTE: Process the lookup data into the pieces of metadata that we
+ # need to load the requested package.
+ #
+ extractAndVerifyLookupMetadata $result metadata $caller
+
+ #
+ # NOTE: Attempt to load the requested package using the metadata
+ # extracted in the previous step.
+ #
+ processLookupMetadata metadata
+ }
+
+ if {![isEagle]} then {
+ ###########################################################################
+ ############################# BEGIN Tcl ONLY ##############################
+ ###########################################################################
+
+ #
+ # NOTE: This procedure was stolen from the "getEagle.tcl" script. It is
+ # designed to emit a progress indicator while an HTTP request is
+ # being processed. The channel argument is the Tcl channel where
+ # the progress indicator should be emitted. The type argument is
+ # the single-character progress indicator. The milliseconds
+ # argument is the number of milliseconds to wait until the next
+ # periodic progress indicator should be emitted. This procedure
+ # reschedules its own execution.
+ #
+ proc pageProgress { channel type milliseconds } {
+ #
+ # NOTE: This variable is used to keep track of the currently scheduled
+ # (i.e. pending) [after] event.
+ #
+ variable afterForPageProgress
+
+ #
+ # NOTE: Show that something is happening...
+ #
+ catch {puts -nonewline $channel $type; flush $channel}
+
+ #
+ # NOTE: Make sure that we are scheduled to run again, if requested.
+ #
+ if {$milliseconds > 0} then {
+ set afterForPageProgress [after $milliseconds \
+ [namespace code [list pageProgress $channel $type \
+ $milliseconds]]]
+ } else {
+ unset -nocomplain afterForPageProgress
+ }
+ }
+
+ #
+ # NOTE: This procedure was stolen from the "getEagle.tcl" script. It is
+ # designed to process a single HTTP request, including any HTTP
+ # 3XX redirects (up to the specified limit), and return the raw
+ # HTTP response data. It does not contain special code to handle
+ # HTTP status codes other than 3XX (e.g. 4XX, 5XX, etc).
+ #
+ #
+ proc getFileViaHttp { uri redirectLimit channel quiet args } {
+ #
+ # NOTE: This variable is used to keep track of the currently scheduled
+ # (i.e. pending) [after] event.
+ #
+ variable afterForPageProgress
+
+ #
+ # NOTE: This procedure requires the modern version of the HTTP package,
+ # which is typically included with the Tcl core distribution.
+ #
+ package require http 2.0
+
+ #
+ # NOTE: If the 'tls' package is available, always attempt to use HTTPS.
+ #
+ if {[catch {package require tls}] == 0} then {
+ ::http::register https 443 ::tls::socket
+
+ if {[string range $uri 0 6] eq "http://"} then {
+ set uri [appendArgs https:// [string range $uri 7 end]]
+ }
+ }
+
+ #
+ # NOTE: Unless the caller forbids it, display progress messages during
+ # the download.
+ #
+ if {!$quiet} then {
+ pageProgress $channel . 250
+ }
+
+ #
+ # NOTE: All downloads are handled synchronously, which is not ideal;
+ # however, it is simple. Keep going as long as there are less
+ # than X redirects.
+ #
+ set redirectCount 0
+
+ while {1} {
+ #
+ # NOTE: Issue the HTTP request now, grabbing the resulting token.
+ #
+ set token [eval [list ::http::geturl $uri] $args]
+
+ #
+ # NOTE: Check the HTTP response code, in order to follow any HTTP
+ # redirect responses.
+ #
+ switch -exact -- [http::ncode $token] {
+ 301 -
+ 302 -
+ 303 -
+ 307 {
+ #
+ # NOTE: Unless the caller forbids it, display progress messages
+ # when an HTTP redirect is returned.
+ #
+ if {!$quiet} then {
+ pageProgress $channel > 0
+ }
+
+ #
+ # NOTE: We hit another HTTP redirect. Stop if there are more
+ # than X.
+ #
+ incr redirectCount
+
+ #
+ # TODO: Maybe make this limit configurable?
+ #
+ if {$redirectCount > $redirectLimit} then {
+ #
+ # NOTE: Just "give up" and return whatever data that we have
+ # now.
+ #
+ set data [::http::data $token]
+ ::http::cleanup $token; break
+ }
+
+ #
+ # NOTE: Grab the metadata associated with this HTTP response.
+ #
+ array set meta [::http::meta $token]
+
+ #
+ # NOTE: Is there actually a new URI (location) to use?
+ #
+ if {[info exist meta(Location)]} then {
+ #
+ # NOTE: Ok, grab it now. Later, at the top of the loop,
+ # it will be used in the subsequent HTTP request.
+ #
+ set location $meta(Location); unset meta
+
+ #
+ # NOTE: For security, do NOT follow an HTTP redirect if
+ # it attempts to redirect from HTTPS to HTTP.
+ #
+ if {[string range $uri 0 7] eq "https://" && \
+ [string range $location 0 7] ne "https://"} then {
+ #
+ # NOTE: Just "give up" and return whatever data that
+ # we have now.
+ #
+ set data [::http::data $token]
+ ::http::cleanup $token; break
+ }
+
+ #
+ # NOTE: Replace the original URI with the new one, for
+ # use in the next HTTP request.
+ #
+ set uri $location
+
+ #
+ # NOTE: Cleanup the current HTTP token now beause a new
+ # one will be created for the next request.
+ #
+ ::http::cleanup $token
+ } else {
+ #
+ # NOTE: Just "give up" and return whatever data that we
+ # have now.
+ #
+ set data [::http::data $token]
+ ::http::cleanup $token; break
+ }
+ }
+ default {
+ #
+ # NOTE: Ok, the HTTP response is actual data of some kind
+ # (which may be an error); however, it is not any
+ # kind of supported HTTP redirect.
+ #
+ set data [::http::data $token]
+ ::http::cleanup $token; break
+ }
+ }
+ }
+
+ #
+ # NOTE: If there is a currently scheduled [after] event, cancel it.
+ #
+ if {[info exists afterForPageProgress]} then {
+ catch {after cancel $afterForPageProgress}
+ unset -nocomplain afterForPageProgress
+ }
+
+ #
+ # NOTE: If progress messages were emitted, start a fresh line.
+ #
+ if {!$quiet} then {
+ catch {puts $channel [appendArgs " " $uri]; flush $channel}
+ }
+
+ return $data
+ }
+
+ ###########################################################################
+ ############################## END Tcl ONLY ###############################
+ ###########################################################################
+ }
+
+ #
+ # NOTE: Attempt to read optional settings file now. This may override
+ # one or more of the variable setup in the next step.
+ #
+ maybeReadSettingsFile [info script]
+
+ #
+ # NOTE: Setup the variables, within this namespace, used by this script.
+ #
+ setupPackageUnknownVars
+
+ #
+ # NOTE: Setup for our [package unknown] handler, which may involve a few
+ # different operations.
+ #
+ setupPackageUnknownHandler
+
+ #
+ # NOTE: Provide the package to the interpreter.
+ #
+ package provide Eagle.Package.Repository \
+ [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
+}
+
ADDED client/1.0/pkgr.eagle.harpy
Index: client/1.0/pkgr.eagle.harpy
==================================================================
--- client/1.0/pkgr.eagle.harpy
+++ client/1.0/pkgr.eagle.harpy
@@ -0,0 +1,50 @@
+
+
+
+ None
+ Mistachkin Systems
+ 88d42a28-1e95-4dd7-aaf9-11bb262f10d0
+ SHA512
+ Script
+ 2016-08-19T02:47:51.4043437Z
+ -1.00:00:00
+ 0x2c322765603b5278
+
+ Mn+rsBh675oM30+X6J/Myzrc0MmxmLCjpzV4bDcl8nZcbdSXszHTHE9ma5tAXopb05bMomy5lHal
+ CjEGgYubJtQFcQzuKlxp0UMVgMpK28uTS/ik9RSKXwgq83N1pwvM7cmF2RzxF/fmD/0dtb0Ulc+h
+ Ior9NeJcpD6lBAE3XEB288f+79mA3U2X1io4qLYvFzktpKyjen8pC8J46078b3HXSoYGUHehmZo+
+ EJhVhD0Lfb9XtGh4V9hgmL9aMWJdv/jGmq+tKOJxxpU70avW4aaUzDKZE/zgR674/o2jhTw8LC+P
+ 7Ed5UhgnXXr6Ko0HlIZqWwwblP+/WJ91Rf3DBzlJDG1Wjwku2xAQN2JcLipbn0YGG3jr4qx9yrnw
+ /K1HT0CEWW/41F/LeZAZ36Kao76kGcl4OcamgAW4fPp2c85wRyIh3i6f4t1RxgixgVUuMWhbVVu5
+ Fb/opbLwHBLIGQpmYqmZhz6A97CSr5eyj1CpKEAz/v76ma3qgravdVZ59C5NdhPXHQGS5MpgsWUC
+ tHc5aXK9npgN3femt1czY8J+dLMFP0N4ENlqJNRP14zFOd0a2vNnc6KB8OE4GAdL0V1KaAK2WIOQ
+ h5cPFMKSphWT8cst4/nLbOhs9G8JlXD1PsIKxgGW5YSYutkZQJPUcDMFmSEdaQ6CCc1K+o6SEXvS
+ RcdPzCEDwJmgYUF77ILI0whNBNFSVD+UPcoD1j6KUmJKHhOt63EYVmRUFlYfw1afVeCjrgm2q5Tp
+ aSVYPaoqUlBuZ0lomqUD03/XsqdwVdiZXEuoObr4INoMeZnHyQf5wpLl1ZGBvGdc7ujOkU8y/sVX
+ Y9ATG3czSvQlNz/06J/ghVEK1t7ZNyEe0thwj6AHM52D/GuFTmfnFaBS5HQawOE9FkYppA7x+65Z
+ rZjUaIBEaybEYPok29IKqw+aqA2s21gJ9c70d/M7UlpwGbT9CQqV+o6/2frQF6vSPUhrFsZPCZZs
+ hE7hn/jluR+tT0g3awKqWayNfG5/ZfJruKwmXcipeacr42Affi0zNxuxsMglndGGEKFtsrGySjcF
+ 2NCquShXYNz4i/7jh0IO4Udb5t/PP1Brpp26t35/Oug/2i2eTO5gq4MvsffXvjeEPYWPjUBug0y1
+ HNAmHDDUqLoD3nK3AK+em1ukGdjMEsvlz+L9+IjOJ/po5ypkgNIsNqQITBY0S4ofp1XO2o9IHPGN
+ G0qKBB7G2PcGe7hh9FOAyPL81OYpxYc7Pe80zxqu+KZP6OPalBssNqIIHqj2p03cukS5X8U0QPO+
+ 2f7Iv9SxJ0t9pcKyZX2iHx5H9+u0TpsghdQPiu9u63GUnIkMJfEWUoBxfJNfWuIzuMoe3rugJQ==
+
+
ADDED client/1.0/pkgr.settings.eagle
Index: client/1.0/pkgr.settings.eagle
==================================================================
--- client/1.0/pkgr.settings.eagle
+++ client/1.0/pkgr.settings.eagle
@@ -0,0 +1,22 @@
+###############################################################################
+#
+# pkgr.settings.eagle --
+#
+# Extensible Adaptable Generalized Logic Engine (Eagle)
+# Package Repository Client Settings
+#
+# 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: $
+#
+###############################################################################
+
+# TODO: Set this to your list of API keys.
+# set ::pkgr_api_keys [list 0000000000000000000000000000000000000000]
+
+variable strictUnknownLanguage false
+variable verboseUnknownResult true
+variable verboseUriDownload true
ADDED client/1.0/pkgr.settings.eagle.harpy
Index: client/1.0/pkgr.settings.eagle.harpy
==================================================================
--- client/1.0/pkgr.settings.eagle.harpy
+++ client/1.0/pkgr.settings.eagle.harpy
@@ -0,0 +1,50 @@
+
+
+
+ None
+ Mistachkin Systems
+ b44b4ef2-76ad-4786-b4b7-e1d604e15e8b
+ SHA512
+ Script
+ 2016-08-17T22:22:56.6608906Z
+ -1.00:00:00
+ 0x2c322765603b5278
+
+ efFtWFrnFkJeMBafjl1MxA1lygnogjoQHoS8qP4ptK+GuB7mvyJbSgtjYyUVJ0Nj9W88qJ0eGtQ3
+ 5yd2fZrTX7nXmEkXaRFcSBiB/S6dtUrc6GGDO1PlOB7w3JGfSkh/4MgfRTrZyN+sRN6ODWPjFU4s
+ m1+HXSXynBUKyPaJ8qNd/0foXvNC/rGbHyZ+Z4FkbAfYZZSTiIz57kv9ZvlmxjSoZNffYpOGD0kQ
+ mFXkvDkoM4JxE3b19M/VFcKJ6NIn7o6Vqc3Xt40+9W5OTKjLVfpeV8gK01rU1d9+KuBnC3hQWyqZ
+ V0fF2mkyGnxO0LAZpOiQ82b8Myld/vl79iGcMLb9F5+SdnYeqBrT8VFRaiZz12MS+8BP+3JItBqn
+ WNFjKVWFXG5SI6aTaqbTDtiKRADqoJyb6HN5imfZll2tcK2ruICy4zYo79mDAolBEnwp4TnNcwKA
+ h5oQTnc44dQht8xeZdT5Ah2SNRBx0GA3nHmJO9AP68JMYbPWLABQQ6hZf2b6u6zB3ZzU8RN/+NIa
+ 3Y5jfKVD/f2BCJumU1jWh2R4785SNXfFT5Id5U0II9I9WhTdiylFXP3hiN/dNW0GAWq9v6TLG+pi
+ vfJrr/26RQfEwIiNa8keQkfJ/HgTmille05ct7DycbHu9Edq9NxWgfTtWDsAnlERTG+WhRc5hZyc
+ VegPWnHpoXeUHgEe5d4bkmmRfePnH+eWeibRveMErlv16jeTv4H28ftp3Vq8n0n+hkVHpYOHMV6i
+ J3/RhJ4G1Se/adEPdVUQRfYrP5HwI/szeR5DQoZ+zAsB34cfwWn0hsj21FeqitSE/rQ0j8pcD3yy
+ OIH07uf/sOqQ8hSEFnxVPTvQYp9H7QTBxFAxaMbpIUTpB6DyroPWzi4uSa+JXWSkf5sQOo2SLCoX
+ t3w7tpZ6o2FZNd3O519FiX3+cM78vyfIMkbT4ZFEHpFkccuG6g9nVgUDCTgMwNldSKQAC7JtwjOZ
+ tSQ9YjRTgZSGcJ+TjLnXJfWo8u0SM+J3K9o+zRcN+6zDZsCAo6inrxgICEFN+lTabJxyWas6MYeX
+ hkq7CnGT9nsDtynLniiF4FUsKTVlgHfR1ZVPwWGb0Ow/L4PdPMTlzPVttsE4bcrii6xnf85O9ijU
+ zfgBhDtRsst9TLXb514J8t4zT54AQPLav2DjXjDjChbm+/JF8ywAfq/v8/A0B3PIeDPgmRTouH48
+ 0MFanzDYI3r75OC0ZMuS8EoseqkcC2C3IvJY9ZtsgnuIPbpxzsdooCCaHXUWL2mHZ+QOk8Q+jn7J
+ 1V0BeUNi0hU9SZeAai1co8ehsCw3vUkOPUoYginn2ry5ALf/jEBHW+1CX3+jlT/snSZba0GPDg==
+
+
DELETED client/pkgIndex.eagle
Index: client/pkgIndex.eagle
==================================================================
--- client/pkgIndex.eagle
+++ client/pkgIndex.eagle
@@ -1,24 +0,0 @@
-###############################################################################
-#
-# pkgIndex.eagle --
-#
-# Extensible Adaptable Generalized Logic Engine (Eagle)
-# Package Index 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: $
-#
-###############################################################################
-
-if {![package vsatisfies [package provide Tcl] 8.4]} {return}
-if {![package vsatisfies [package provide Eagle] 1.0]} {return}
-
-package ifneeded Eagle.Package.Repository 1.0 \
- [list source [file join $dir pkgr.eagle]]
-
-package ifneeded Eagle.Package.Downloader 1.0 \
- [list source [file join $dir pkgd.eagle]]
DELETED client/pkgIndex.eagle.harpy
Index: client/pkgIndex.eagle.harpy
==================================================================
--- client/pkgIndex.eagle.harpy
+++ client/pkgIndex.eagle.harpy
@@ -1,50 +0,0 @@
-
-
-
- None
- Mistachkin Systems
- b0129e44-3b2c-42b0-a71f-1c07aa16afd2
- SHA512
- Script
- 2016-08-16T02:51:50.7605000Z
- -1.00:00:00
- 0x2c322765603b5278
-
- nF615q+lJascFI+duD9pIrNyquMbrsLaX1Za3HFLitpOmFxsTcj+cKQ6d5y48SHsN6OlU4DMbyJX
- egCciqoZqk8SEnkD6WgFjD+oKWQRsaRMnbmI3MmZOP/z1jSff6FeLwQQkDlkV9hhJRTo/rBBS6Vu
- hfTmX7eVy4Uy+ifV8/i9T+/9dfS8DTifSWq1+6YSJuhETNDCmjnBxT+SrHeOdSZE0n65SPlb6Fde
- yzVVPp/DfsA3cP3q9pMHDENyueXKAz0yXjunKJAXiGM1NNDLKkJ9YKpIxb4yV/uGMduK9KIy9hkQ
- PlQQpn0Eh+fWst+DZlTl1PTL6sc9WJf9GSoAnNERIYvwA6z8eqRgRfXRhAsTEa+Om76Nt5so2Prz
- jtUP39UldpoXhq87H2I4NkJfngcx0x3Jybv25nwMygQv0paXWAlaEFN49atMLXYO6F85ghi8dmps
- zCY6O06FjnyI43RkBUYIvuDyU1q9HjVZbKiHr0YoFVhBCZDZp/lcxucIYG2sXpX5YKDT09WPMiUz
- 1r/TO286Y2kJyzmgJMMjRmqTmOID6nTRSjvPSQCyFikJ8tCIWA78IiI2+/539J99VYfNmJoPRq3j
- sBJ0IERsQCrp7baZkPiF/vzGEIScXtqAsxOKbep4oLEMt8mBmLOONkAwfo+mjjvtUy5s2ZYdnqQJ
- 8EUbAKF7pRcgu7+w8LVMnGJr+dh5iJG0U8J6P2yrSeu+PRKr+aiX41/w1vJLRXZEljdqQ7PoIdPt
- vsgFY+HoWs0pydJDcReMQDQtNczgn+88gv0IH5YL+7bp91yMqABR4RL7wekVv9IHSt2Da3l884Zn
- WWb7Xso51BdH79a4zlSwHbbetu297ScvsmiNzCnyNYVa22Dx6UrVTl5OMao8219HJkjYlsXSkmQq
- IZQwQXcutbp+alQ3v/uZMytujpL4+2wldzAFCuKWEzTOoBcroxnWfrFY80XyLmGODWU0j1Np+iJC
- TAnErZYhU74BXFFHuRTLjjWhOqADSdCHk1K1zgs27k1uL6maIYU0wyYc4r/KuI+zKQ13JPYcauND
- L1fTB6DTropeAZIZxlJAhZGadgs3UX8yx7JHIHgJQz4LjxCcRpxwvbz+o2PVcHoav9YJOLOzhfHK
- 2+/XSxTalaF+XetBz2fDBYosj/JY61zy3YJPnaq/pc5r7TCDwF/hHPrAUZh84aMjsDNcOkU6DJSU
- 0ykiZeFDm/A7XxVWANeBbfgci1UgK5VCdJr4A8kFDzwBWj+u1Q3bxmYxTJurpXBC/LRNh5s1/30B
- KrG8eRNO4JlCGJbCqrgdVVF8gGa/MvuVKvsC2BWLtNsmVf2BUt3wkQEXxLtQdjv3yDMzxtBtTQ==
-
-
DELETED client/pkgIndex.tcl
Index: client/pkgIndex.tcl
==================================================================
--- client/pkgIndex.tcl
+++ client/pkgIndex.tcl
@@ -1,24 +0,0 @@
-###############################################################################
-#
-# pkgIndex.tcl --
-#
-# Extensible Adaptable Generalized Logic Engine (Eagle)
-# Package Index 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: $
-#
-###############################################################################
-
-if {![package vsatisfies [package provide Tcl] 8.4]} {return}
-if {[string length [package provide Eagle]] > 0} then {return}
-
-package ifneeded Eagle.Package.Repository 1.0 \
- [list source [file join $dir pkgr.eagle]]
-
-package ifneeded Eagle.Package.Downloader 1.0 \
- [list source [file join $dir pkgd.eagle]]
DELETED client/pkgIndex.tcl.harpy
Index: client/pkgIndex.tcl.harpy
==================================================================
--- client/pkgIndex.tcl.harpy
+++ client/pkgIndex.tcl.harpy
@@ -1,50 +0,0 @@
-
-
-
- None
- Mistachkin Systems
- 69ca970a-0c3d-447a-91cf-44fed99731ee
- SHA512
- Script
- 2016-08-16T02:54:51.9323750Z
- -1.00:00:00
- 0x2c322765603b5278
-
- HjolMDm2KhyxiFYnQ7OlS81iIPJnyriCCNo4ATggqUhZP1ag2J7e7j4EHbit8RSgAYuPUnT3SFQH
- yOxLq410LfAGS0p+jTfua7JwfeXIBOGf5zbOADM79TS9iTI0qSyqHBrvSmHBhsyoPxrGs07wcrpe
- hKYneaf+j9rjJpVL0bUasIEsBtoVhXUXEubuLuiLclcCT5w/VoHHa5IP6ogNdch2zPYv1wT0Vmo4
- RO3wHzvcMwCmyj0cV9z6QxoSVgmlHDRnODXRJP4kY+nzWsEkGlNy+Gy21qjL8h8fk+CWWU/AnqhC
- M4VR4fJJYlfKBXFipq6SKCWe3dQV3skkE/ETVqPoTNW3I1/UcrH7CGZiWgCPoPGKFT1uVZt0aw5y
- 9J9B1nuzNTxrPlyr3IM1UY91MBxyVO4sPUhvBYkhv36/CuWj7Nixlh9Mu7MyTGquj99l7K5/gThH
- VkThdOn/Vn3+7X+8OfB6aDJmQotZzu1bqvywCqrtu/DbwE0QNRI/4VbVunZilAE0ULwwAEsCVqOQ
- itILH2X2XVvNLFfRjK9BCVovyrzzmAj7bzj+furph1YY4XZmEDn/Sk+xbnHQencqAFjracL4kpOs
- gZ7FaGgXcAuk8LmCfVD0HWGLiVVGMVMON35lu6FUfjiFkEZTuE104/ijZUce2KxWYQfbSwrv/Ywu
- hUPSDRXnmaZwwYNSYVkR6zGinmWibVRWLWP6hLy0rf2xxU5bbRDhLddHoOVLdIV0s6SRMS87z1y4
- I7mNnql6OVVl55O/Ro/GQgIkp2+gaMkef9/FDGS6jMufZA6EuCEJD0yraARofd100tjnln3EVa/r
- tn0ggpaqEXyXlqv9plG9PONcjPbBp+/zPnfihOuzUEsxgi+mkoxmSQh9UWQ9ELdgrL0m9zoVr5IV
- jdyHqWkAIoVM4ILN7ORsRTIKGqxqHxSiier0ySvgjaPFxd7M1uzaAuvFeCjMx74XCmsDFGEHbI49
- jc++8u+rA+ZvCVL6nhv64QgP3ce4PYznUDhSDHkLGstaw5JOibPTgiUGvyPTFVJE1cwSmYUe6KuQ
- 2oeD1DKFs4/U0n902tq2aly5H7plz4NLuV5kUy1EWCANQFi2A1LX0xMoztHdSagmdmvykIronkbP
- kAawsH99A9ukY1Er09bw6WDMUX6aACZQw++/e0eQs/0hkWX7o+rFFQMgEbRz5g5q7+pXVkDd1T9x
- WTHAMsXWaaDeB0hcA53HkB92APDnrUi04+YOu5F1Eh0+lIi7GA+Y5fFcItVaXzuog9bUIzUAvuPh
- FJGnCHXQ+gKP2/Y6c2Kd/3+O8vHPUNwbQfH4vONk4j4WANYU7oqYczSkxejI7/FJ0qGO2pueoA==
-
-
DELETED client/pkgd.eagle
Index: client/pkgd.eagle
==================================================================
--- client/pkgd.eagle
+++ client/pkgd.eagle
@@ -1,291 +0,0 @@
-###############################################################################
-#
-# pkgd.eagle --
-#
-# Extensible Adaptable Generalized Logic Engine (Eagle)
-# Package Downloader Client
-#
-# 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 ::PackageDownloader {
- #
- # NOTE: This procedure sets up the default values for all configuration
- # parameters used by the package downloader client. There are no
- # arguments.
- #
- proc setupDownloadVars {} {
- #
- # NOTE: Prevent progress messages from being displayed while downloading
- # from the repository, etc? By default, this is enabled.
- #
- variable quiet; # DEFAULT: true
-
- if {![info exists quiet]} then {
- set quiet true
- }
-
- #
- # NOTE: The base URI for the package distribution web site.
- #
- variable baseUri; # DEFAULT: https://urn.to/r/pkgd
-
- if {![info exists baseUri]} then {
- set baseUri https://urn.to/r/pkgd
- }
-
- #
- # NOTE: The URI where a single package file may be found. This file will
- # belong to a specific version of one package.
- #
- variable downloadUri; # DEFAULT: ${baseUri}?...&filename=${fileName}
-
- if {![info exists downloadUri]} then {
- set downloadUri {${baseUri}?download&ci=trunk&filename=${fileName}}
- }
-
- #
- # NOTE: The root directory where any persistent packages will be saved.
- #
- variable persistentDirectory; # DEFAULT: [getPersistentRootDirectory]
-
- if {![info exists persistentDirectory]} then {
- set persistentDirectory [getPersistentRootDirectory]
- }
- }
-
- #
- # NOTE: This procedure returns the root directory where any packages that
- # are downloaded should be saved to permanent storage for subsequent
- # use. There are no arguments.
- #
- proc getPersistentRootDirectory {} {
- #
- # NOTE: Return a directory parallel to the one containing the library
- # directory.
- #
- return [file join [file dirname [info library]] pkgd]
- }
-
- #
- # NOTE: This procedure adds a directory to the auto-path of the specified
- # language (i.e. native Tcl or Eagle). The directory will not be
- # added if it is already present. The language argument must be the
- # literal string "eagle" or the literal string "tcl". The directory
- # argument is the fully qualified path for the directory to add to
- # the auto-path.
- #
- #
- proc addToAutoPath { language directory } {
- #
- # NOTE: Add the specified directory to the auto-path if not already
- # present.
- #
- if {[string length $language] == 0 || $language eq "eagle"} then {
- if {[isEagle]} then {
- if {![info exists ::auto_path] || \
- [lsearch -exact $::auto_path $directory] == -1} then {
- lappend ::auto_path $directory
- }
- } else {
- ::PackageRepository::eagleMustBeReady
-
- eagle [string map [list %directory% $directory] {
- if {![info exists ::auto_path] || \
- [lsearch -exact $::auto_path {%directory%}] == -1} then {
- lappend ::auto_path {%directory%}
- }
- }]
- }
- } elseif {$language eq "tcl"} then {
- if {[isEagle]} then {
- tcl eval [tcl master] [string map [list %directory% $directory] {
- if {![info exists ::auto_path] || \
- [lsearch -exact $::auto_path {%directory%}] == -1} then {
- lappend ::auto_path {%directory%}
- }
- }]
- } else {
- if {![info exists ::auto_path] || \
- [lsearch -exact $::auto_path $directory] == -1} then {
- lappend ::auto_path $directory
- }
- }
- } else {
- error "unsupported language, no idea how to modify auto-path"
- }
- }
-
- #
- # NOTE: This procedure attempts to download a list of files, optionally
- # persistening them for subsequent uses by the target language.
- # The language argument must be the literal string "eagle" or the
- # literal string "tcl". The version argument must be the literal
- # string "8.4", "8.5", or "8.6" when the language is "tcl" -OR-
- # the literal string "1.0" when the language is "eagle". The
- # fileNames argument must be a well-formed list of file names to
- # download, each one relative to the language/version-specific
- # directory on the package file server. The persistent argument
- # should be non-zero if the downloaded files should be saved to
- # permanent storage for subsequent use. The usePgp argument
- # should be non-zero when an OpenPGP signature file needs to be
- # downloaded and verified for each downloaded file. The
- # useAutoPath argument should be non-zero to modify the auto-path
- # to include the temporary or persistent directories containing
- # the downloaded files.
- #
- #
- proc downloadFiles {
- language version fileNames persistent usePgp useAutoPath } {
- variable baseUri
- variable downloadUri
- variable persistentDirectory
- variable quiet
-
- if {[string length $language] == 0 || $language eq "eagle"} then {
- if {$version ne "1.0"} then {
- error "unsupported Eagle version"
- }
- } elseif {$language eq "tcl"} then {
- if {$version ne "8.4" && $version ne "8.5" && $version ne "8.6"} then {
- error "unsupported Tcl version"
- }
- } else {
- error "unsupported language"
- }
-
- if {$persistent} then {
- set downloadRootDirectory $persistentDirectory
- } else {
- set directoryNameOnly [appendArgs \
- pkgd_ [string trim [pid] -] _ [string trim [clock seconds] -]]
-
- global env
-
- if {[info exists env(PKGD_TEMP)]} then {
- set downloadRootDirectory $env(PKGD_TEMP)
- } elseif {[info exists env(TEMP)]} then {
- set downloadRootDirectory $env(TEMP)
- } elseif {[info exists env(TMP)]} then {
- set downloadRootDirectory $env(TMP)
- } else {
- error "please set PKGD_TEMP (via environment) to temporary directory"
- }
-
- set downloadRootDirectory [file join \
- $downloadRootDirectory $directoryNameOnly]
- }
-
- set downloadDirectories [list]
-
- foreach fileName $fileNames {
- if {[string length $fileName] == 0 || \
- [file pathtype $fileName] ne "relative"} then {
- error [appendArgs \
- "bad file name \"" $fileName "\", not relative"]
- }
-
- set directoryParts [file split [file dirname $fileName]]
-
- if {[llength $directoryParts] == 0} then {
- error [appendArgs \
- "bad file name \"" $fileName "\", no directory parts"]
- }
-
- set downloadDirectory [file normalize [eval file join \
- [list $downloadRootDirectory] $directoryParts]]
-
- set downloadFileName [file normalize [file join \
- $downloadDirectory [file tail $fileName]]]
-
- if {!$persistent} then {
- catch {file delete $downloadFileName}
- }
-
- file mkdir [file dirname $downloadFileName]
-
- set savedFileName $fileName
- set fileName [file join $language $version $fileName]
- set uri [subst $downloadUri]
- set fileName $savedFileName
-
- if {[isEagle]} then {
- writeFile $downloadFileName \
- [interp readorgetscriptfile -- "" $uri]
- } else {
- writeFile $downloadFileName \
- [::PackageRepository::getFileViaHttp $uri 10 stdout $quiet]
- }
-
- if {$usePgp} then {
- set downloadSignatureFileName [appendArgs $downloadFileName .asc]
-
- set savedFileName $fileName
- set fileName [file join \
- $language $version [appendArgs $fileName .asc]]
-
- set uri [subst $downloadUri]
- set fileName $savedFileName
-
- if {[isEagle]} then {
- writeFile $downloadSignatureFileName \
- [interp readorgetscriptfile -- "" $uri]
- } else {
- writeFile $downloadSignatureFileName \
- [::PackageRepository::getFileViaHttp $uri 10 stdout $quiet]
- }
-
- if {![::PackageRepository::verifyPgpSignature \
- $downloadSignatureFileName]} then {
- error [appendArgs \
- "bad PGP signature \"" $downloadSignatureFileName \"]
- }
- }
-
- lappend downloadDirectories $downloadDirectory
- }
-
- set downloadDirectories [lsort -unique $downloadDirectories]
-
- if {$useAutoPath} then {
- foreach downloadDirectory $downloadDirectories {
- addToAutoPath $language $downloadDirectory
- }
- }
-
- return $downloadDirectories
- }
-
- #
- # NOTE: This package requires the package repository client package.
- #
- package require Eagle.Package.Repository
-
- #
- # NOTE: Attempt to read optional settings file now. This may override
- # one or more of the variable setup in the next step.
- #
- ::PackageRepository::maybeReadSettingsFile [info script]
-
- #
- # NOTE: Setup the variables, within this namespace, used by this script.
- #
- setupDownloadVars
-
- #
- # NOTE: Provide the package to the interpreter.
- #
- package provide Eagle.Package.Downloader \
- [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
-}
DELETED client/pkgd.eagle.harpy
Index: client/pkgd.eagle.harpy
==================================================================
--- client/pkgd.eagle.harpy
+++ client/pkgd.eagle.harpy
@@ -1,50 +0,0 @@
-
-
-
- None
- Mistachkin Systems
- 53a7ee35-d269-407b-9849-062af5a64876
- SHA512
- Script
- 2016-08-19T02:47:10.2744609Z
- -1.00:00:00
- 0x2c322765603b5278
-
- Yp/5NPzblsNKAItBjTMKYni6R3tyMPN2ZEGrwDcSZNi4/Y1QlXWD9BF/MdF0Glc93u7UpJw3Itwt
- dYziRGX2yMsaddIx7gUawg5L7vc1eCz0BTohnSctzR1wU8My0BV5wCqDvAgJICtHWJM53H6XTLW3
- CgtsZjXN0GRbDVEos3D77uK1BmPdSWLyi2L0SMA/QiGtlVY1lnP5/X6hpvBfbEX0YmDK45mEO1VR
- lh2Y+aN+Jf05jiKjJwdOR4ZK1wDuW313FByM9FgDlRDpCXlnZfAeSnTPmCIafwOILlK3EZdHDJCy
- 0gvFySMslL0m177+Sfpr7QW0F1ZZ4ENlse5i3ac33sF6RkAVvkmP9ZbjEq+N8+2G4v68+Yed7dET
- 5Rwo//rU4QJE+To2oqJJpgv1ZsWcdqASUuof3o73gn8fRCZo95ctYvQHURzK7mFT/tTndsl/nlUq
- PFeoltj0amd3sI86eHRR99rybruihdt6rETXCbhnh7+nJF6YL9SD73TX5O0+RBzOTRxkYKvdgGyX
- pJ83iJtZC5N6SEySjiZlTAaLe4YTuJyaIkYDn/HWKMme7k8A7gK/Ig2iPTRUJiXm31hIn6VLfJXt
- XFgoW9Ln0PAZlm4tNbeJraEeArU3YJ3vQ2FzNT7QgU1ruNiHbObOGhs76/a1XOSaoAXBRR8PgUIF
- l+GWC77nJVGGeFwdUsDaJf6seEfnEV1Srp2mMFKT3Zo34Z3PMOZrcUxjGVj4tylewlq6zOWLis41
- cKE450S7P/WZZ8I3Ab14uKUYfkwR0yI+DGo/Zp9rHvYcY7eadxMByFc0BjBoWv/kaGjjtnHmLaap
- e53Xm1u3oFiecYh/0+74gKZB3XcMWLJNXR/wSQR55NdOXGADoqnWBEGdlC8EHFObbE4K+v9mVmag
- F2nmPPk+mbqOl2hRA5ZLutV2iR49bRghbVNPD0Me/lhoiqT9FrSTZWbggLy8ZanTn/CcaWORMJJi
- gzDNED9UU/YAsXg4NYE376zKDuZWhUUwAmsjOlMksILIhiSCU0oH59AcXgLjKs9dtpCZP/t/IClr
- wKfnm6CgHO2KjnB5kvCsSEmBFiciPkzzLJYGn1PYON/8/9bLXqeu65NjEl/Z+mNRP65565DWVYiN
- QFcQbXbYZxDDgmjfYm85w4bOKkesGKkenT/o9jMnUksrbO85MVL1f77riYTvmK6w0mWuwmBxPxaD
- nPZc2+D6uB2GHhh4bkYdgtQtaiKOSbdKjGVba1eLLzODYlrxwOZ6I1bJNvP0HoxHkpVoLacF8MgV
- CODZzXo/MdVbDDT/5KHgBrXCvRUquhbpNNC7Ut5kvb5O9svvWrr6x0/S0oq8E3JYGD3/tZrErA==
-
-
DELETED client/pkgd.settings.eagle
Index: client/pkgd.settings.eagle
==================================================================
--- client/pkgd.settings.eagle
+++ client/pkgd.settings.eagle
@@ -1,17 +0,0 @@
-###############################################################################
-#
-# pkgd.settings.eagle --
-#
-# Extensible Adaptable Generalized Logic Engine (Eagle)
-# Package Downloader Client Settings
-#
-# 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: $
-#
-###############################################################################
-
-variable quiet false
DELETED client/pkgd.settings.eagle.harpy
Index: client/pkgd.settings.eagle.harpy
==================================================================
--- client/pkgd.settings.eagle.harpy
+++ client/pkgd.settings.eagle.harpy
@@ -1,50 +0,0 @@
-
-
-
- None
- Mistachkin Systems
- 88bd4979-4392-42f3-a0e6-a6d2bb881e55
- SHA512
- Script
- 2016-08-19T02:27:08.9736797Z
- -1.00:00:00
- 0x2c322765603b5278
-
- P36p/qj9tAsoQPeWuc9Pk3g0O51CX9d/AIsxoMlrjtIreeCFn1Ki3x2KA3Jp7CKuShzSd7ZVbtGD
- 4X7uNtPyoiRS3NitWI/hyR0wEN+tWqK+ImLatg4ZUjYCgbqJcGgTWsQZuJqj9X6a7nRhMrH4rJAB
- uu92jWB/AHIcGTyMY/1Uw1u5/M3K2kePYnKIkZTmuNndrLBJa525osq3OeiowCshJE2ao+Yjx1RW
- whTgplY5hBrgZVLnsSF/hXEXFCamsr7ZCHRjj99pX+7ycMUyyIIm+kVWY/OS9VjO+Mhu2Adq+JBu
- 266BF7hDvDReEk5musXDPhZJD//ZS8blH+x+YxGHGfjw88ij9ISudRLkuv53UaGyXRLEyWvaCAHq
- WSfiuaHgHSGTGPlXYWJBeQJO4r4NMs8kp/+cTL9HLwGN5UQpQ+CabnKnuGALrZdKwdojr/cS/QPK
- znw85PdV2v0cGsHcGy/1qPo84pvtCX1D9aq5djmwhh4Wkg0saXAdJyr0XyNH8xniJ97hHO621QfD
- BJpEtI5hOn9F74887mWsRb81zDpi66CgkFNQwgLY4tsJMulGc2inNC8Z4ZcPZHWUfSC9M1RfwlvL
- 8eZ4HVK+IlGJPZpWS4qbca+ph25Uu3EPnzHLzqHiEHXd/ybWeTvQyorqvBCsjVOQ0HOv7GC11+6+
- RrO92mnX0+u69guvosE/H+G59pXsTPTW8/mGHSvsRV0lihILje3bBUCpWZk8Vaa0HmH9i/hkDicY
- bs1LoTyfVRabBUIfLOujSnszlqVfc2EGZXdccVuBolsonVddzr+czcL+1SzSLtE2m7lsTgE/1mUj
- oGlFhUekWPtfHw/nHEHQ09XZHPsQ5E6uCw2sI0mYDtTa6sGTk1H3eWVEwOTFheqrAx+kyAAk6Rcp
- 18mg6QBaieARwUFXwdA7KT7tq7yDlB9x3yjem3aFLKWAszwqxA9RT+6WrdgcCKucWrE3gu3EZz+M
- GzZ9s87hsvah/6lATnPia11vfGJKiEkTS5WI7uTDwAY1Iru9+qyTxFqQLQzhxtz+p186VOvYbotU
- lZHXnl+bs1gzaUHnOSrSCiuMURaEjLfKBeySuHdzbBe8g5H6SISCujx2t7D7g/ZyBH0Lcfs1i1Wf
- awwzORvocDdoQbKV8rO/U+CPxLkvqyuhmDi/LJi0os3k9iTKYN5M7WS0hKitxKGslRf0eiV6pzFB
- yEDRUy5NlKwgz2Yi8dAJS2cr6O54NWCI7adW4L3PRL/La/2lISMS6oQgKe1NR6qmAiAECkqXDlHb
- uESRIJ0JRYNHgLwYPqGS0ZWTZ5yQGAitOcO2GXvbL8O3hXpLalLF8ePvGzCZZMuWxspMCk8D2g==
-
-
DELETED client/pkgr.eagle
Index: client/pkgr.eagle
==================================================================
--- client/pkgr.eagle
+++ client/pkgr.eagle
@@ -1,1567 +0,0 @@
-###############################################################################
-#
-# pkgr.eagle --
-#
-# Extensible Adaptable Generalized Logic Engine (Eagle)
-# Package Repository Client
-#
-# 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 ::PackageRepository {
- #
- # NOTE: This package absolutely requires the Eagle core script library
- # package, even when it is being used by native Tcl. If needed,
- # prior to loading this package, the native Tcl auto-path should
- # be modified to include the "Eagle1.0" directory (i.e. the one
- # containing the Eagle core script library file "init.eagle").
- #
- package require Eagle.Library
-
- #
- # NOTE: This procedure returns a formatted, possibly version-specific,
- # package name, for use in logging.
- #
- proc formatPackageName { package version } {
- return [string trim [appendArgs $package " " $version]]
- }
-
- #
- # NOTE: This procedure returns a formatted script result. If the string
- # result is empty, only the return code is used. The code argument
- # must be an integer Tcl return code (e.g. from [catch]) and the
- # result argument is the script result or error message.
- #
- proc formatResult { code result } {
- switch -exact -- $code {
- 0 {set codeString ok}
- 1 {set codeString error}
- 2 {set codeString return}
- 3 {set codeString break}
- 4 {set codeString continue}
- default {set codeString [appendArgs unknown( $code )]}
- }
-
- if {[string length $result] > 0} then {
- return [appendArgs $codeString ": " [list $result]]
- } else {
- return $codeString
- }
- }
-
- #
- # NOTE: This procedure emits a message to the package repository client
- # log. The string argument is the content of the message to emit.
- #
- #
- proc pkgLog { string } {
- catch {
- tclLog [appendArgs [pid] " : " [clock seconds] " : pkgr : " $string]
- }
- }
-
- #
- # NOTE: This procedure attempts to determine if a string is a valid list
- # and returns non-zero when that is true. The value argument is
- # the string to check.
- #
- proc stringIsList { value } {
- if {[isEagle]} then {
- return [string is list $value]
- } else {
- global tcl_version
-
- if {[info exists tcl_version] && $tcl_version >= 8.5} then {
- return [string is list $value]
- } elseif {[catch {llength $value}] == 0} then {
- return true
- } else {
- return false
- }
- }
- }
-
- #
- # NOTE: This procedure returns non-zero if the specified string value
- # looks like a Harpy (script) certificate. The value argument
- # is the string to check.
- #
- #
- proc isHarpyCertificate { value } {
- if {[string length $value] == 0 || [string first [string trim {
-
- proc isPgpSignature { value } {
- if {[string length $value] == 0 || [string first [string trim {
- -----BEGIN PGP SIGNATURE-----
- }] $value] != -1} then {
- return true
- } else {
- return false
- }
- }
-
- #
- # NOTE: This procedure returns a unique temporary file name. A script
- # error is raised if this task cannot be accomplished. There are
- # no arguments.
- #
- proc getFileTempName {} {
- if {[isEagle]} then {
- return [file tempname]
- } else {
- global env
-
- if {[info exists env(PKGR_TEMP)]} then {
- set directory $env(PKGD_TEMP)
- } elseif {[info exists env(TEMP)]} then {
- set directory $env(TEMP)
- } elseif {[info exists env(TMP)]} then {
- set directory $env(TMP)
- } else {
- error "please set PKGR_TEMP (via environment) to temporary directory"
- }
-
- set counter [expr {[pid] ^ int(rand() * 0xFFFF)}]
-
- while {1} {
- set fileNameOnly [format tcl%04X.tmp $counter]
- set fileName [file join $directory $fileNameOnly]
-
- if {![file exists $fileName]} then {
- return $fileName
- }
-
- incr counter
- }
- }
- }
-
- #
- # NOTE: This procedure attempts to verify the PGP signature contained in
- # the specified (named) file. Non-zero is only returned if the PGP
- # signature is verified successfully. A script error should not be
- # raised by this procedure. The fileName argument must be the fully
- # qualified path and file name of the PGP signature file to verify.
- #
- #
- proc verifyPgpSignature { fileName } {
- variable pgpCommand
-
- if {[isEagle]} then {
- set fileName [appendArgs \" $fileName \"]
-
- if {[catch {
- eval exec -success Success [subst $pgpCommand]
- }] == 0} then {
- return true
- }
- } else {
- if {[catch {
- eval exec [subst $pgpCommand] 2>@1
- }] == 0} then {
- return true
- }
- }
-
- return false
- }
-
- #
- # NOTE: This procedure returns the prefix for fully qualified variable
- # names that MAY be present in the global namespace. There are
- # no arguments.
- #
- proc getLookupVarNamePrefix {} {
- return ::pkgr_; # TODO: Make non-global?
- }
-
- #
- # NOTE: This procedure returns a unique suffix for a fully qualified
- # variable name that MAY be present in the global namespace.
- # It is used (internally) to avoid any name collisions with
- # variables and commands in the global namespace. There are
- # no arguments.
- #
- proc getLookupVarNameSuffix {} {
- return [appendArgs \
- [string trim [pid] -] _ [string trim [clock seconds] -] _ \
- [string trim [clock clicks -milliseconds] -]]; # TODO: Bad?
- }
-
- #
- # NOTE: This procedure returns the list of API keys to use when looking
- # up packages via the package repository server. An empty list
- # is returned if no API keys are currently configured. There are
- # no arguments.
- #
- proc getLookupApiKeys {} {
- set varName [appendArgs [getLookupVarNamePrefix] api_keys]
-
- if {[info exists $varName]} then {
- return [set $varName]
- }
-
- global env
- set varName [string trim $varName :]
-
- if {[info exists env($varName)]} then {
- return $env($varName)
- }
-
- return [list]; # NOTE: System default, which is "public-only".
- }
-
- proc getLookupBaseUri {} {
- set varName [appendArgs [getLookupVarNamePrefix] base_uri]
-
- if {[info exists $varName]} then {
- return [set $varName]
- }
-
- global env
- set varName [string trim $varName :]
-
- if {[info exists env($varName)]} then {
- return $env($varName)
- }
-
- return https://urn.to/r/pkg; # NOTE: System default.
- }
-
- #
- # NOTE: This procedure returns the full URI to use when looking up a
- # specific package via the package repository server. The apiKey
- # argument is the API key to use -OR- an empty string if a public
- # package is being looked up. The package argument is the name
- # of the package being looked up, it cannot be an empty string.
- # The version argument is the specific version being looked up
- # -OR- an empty string for any available version. No HTTP request
- # is issued by this procedure; it just returns the URI to use.
- #
- proc getLookupUri { apiKey package version } {
- set baseUri [getLookupBaseUri]
-
- if {[string length $baseUri] == 0} then {
- return ""
- }
-
- #
- # NOTE: Build the HTTP request URI using the specified query parameter
- # values, escaping them as necessary. Also, include the standard
- # query parameters with constant values for this request type.
- #
- if {[isEagle]} then {
- return [appendArgs \
- $baseUri ?raw=1&method=lookup&apiKey= [uri escape uri $apiKey] \
- &package= [uri escape uri $package] &version= [uri escape uri \
- $version]]
- } else {
- package require http 2.0
-
- return [appendArgs \
- $baseUri ? [http::formatQuery raw 1 method lookup apiKey $apiKey \
- package $package version $version]]
- }
- }
-
- #
- # NOTE: This procedure returns the version of the package that should be
- # used to lookup the associated [package ifneeded] script -OR- an
- # empty string if no such version exists. The package argument is
- # the name of the package, it cannot be an empty string. The
- # version argument is the specific version being looked up -OR- an
- # empty string for any available version.
- #
- proc getIfNeededVersion { package version } {
- if {[string length $version] > 0} then {
- return $version
- }
-
- return [lindex [package versions $package] 0]
- }
-
- #
- # NOTE: This procedure accepts a package requirement (spec) and returns
- # a simple package version, if possible. An empty string will be
- # returned, if appropriate (i.e. any version should be allowed).
- # The requirement argument must be a package specification that
- # conforms to TIP #268.
- #
- proc packageRequirementToVersion { requirement } {
- set result $requirement
-
- if {[set index [string first - $result]] != -1} then {
- incr index -1; set result [string range $result 0 $index]
- }
-
- if {[set index [string first a $result]] != -1 || \
- [set index [string first b $result]] != -1} then {
- incr index -1; set result [string range $result 0 $index]
- }
-
- if {$result eq "0"} then {
- set result ""
- } elseif {[regexp -- {^\d+$} $result]} then {
- append result .0
- }
-
- return $result
- }
-
- #
- # NOTE: This procedure issues an HTTP request that should return metadata
- # that can be used to load and/or provide the specified package.
- # The apiKey argument is the API key to use -OR- an empty string if
- # a public package is being looked up. The package argument is the
- # name of the package, it cannot be an empty string. The version
- # argument is the specific version being looked up -OR- an empty
- # string for any available version. This procedure may raise script
- # errors. All line-endings are normalized to Unix-style; therefore,
- # all script signatures must assume this.
- #
- proc getLookupData { apiKey package version } {
- variable verboseUriDownload
-
- set uri [getLookupUri $apiKey $package $version]
-
- if {[string length $uri] == 0} then {
- return ""
- }
-
- if {$verboseUriDownload} then {
- pkgLog [appendArgs \
- "attempting to download URI \"" $uri \"...]
- }
-
- if {[isEagle]} then {
- set data [uri download -inline $uri]
- } else {
- set quiet [expr {!$verboseUriDownload}]
- set data [getFileViaHttp $uri 10 stdout $quiet]
- }
-
- if {$verboseUriDownload} then {
- pkgLog [appendArgs \
- "raw response data is: " $data]
- }
-
- set data [string map [list <\; < >\; > "\; \" &\; &] $data]
- set data [string map [list \r\n \n \r \n] $data]
- set data [string trim $data]
-
- return $data
- }
-
- #
- # NOTE: This procedure attempts to extract the lookup code from the raw
- # HTTP response data. The data argument is the raw HTTP response
- # data. An empty string is returned if no lookup code is available.
- #
- proc getLookupCodeFromData { data } {
- if {![stringIsList $data] || [llength $data] < 1} then {
- return ""
- }
-
- return [lindex $data 0]
- }
-
- #
- # NOTE: This procedure attempts to extract the lookup result from the raw
- # HTTP response data. The data argument is the raw HTTP response
- # data. An empty string is returned if no lookup result is available.
- #
- proc getLookupResultFromData { data } {
- if {![stringIsList $data] || [llength $data] < 2} then {
- return ""
- }
-
- return [lindex $data 1]
- }
-
- #
- # NOTE: This procedure returns non-zero if the specified lookup response
- # code indicates success. The code argument is the extracted HTTP
- # lookup response code.
- #
- proc isLookupCodeOk { code } {
- #
- # NOTE: The code must be the literal string "OK" for the package lookup
- # request to be considered successful.
- #
- return [expr {$code eq "OK"}]
- }
-
- #
- # NOTE: This procedure was stolen from the "common.tcl" script used by the
- # package repository server. It has been modified to support both
- # native Tcl and Eagle. It should be noted here that TIP #268 syntax
- # is not supported by Eagle. For native Tcl, the requirement argument
- # must be a package version or requirement conforming to the TIP #268
- # syntax. For Eagle, the requirement argument must be a simple dotted
- # package version, with up to four components, without any 'a' or 'b'.
- # The emptyOk argument should be non-zero if an empty string should be
- # considered to be valid by the caller. The rangeOk argument should
- # be non-zero if the version range syntax is allowed; this argument is
- # ignored for Eagle because it requires TIP #268 support.
- #
- proc isValidPackageRequirement { requirement rangeOk {emptyOk false} } {
- if {$emptyOk && [string length $requirement] == 0} then {
- return true
- }
-
- if {[isEagle]} then {
- #
- # NOTE: Eagle does not support TIP #268. Use the built-in sub-command
- # that checks a version number.
- #
- return [string is version -strict $requirement]
- } else {
- #
- # HACK: If a version range is not allowed, make sure that the dash
- # character is not present.
- #
- if {!$rangeOk && [string first - $requirement] != -1} then {
- return false
- }
-
- #
- # HACK: There is no direct way to check if a package requirement
- # that uses the TIP #268 syntax is valid; however, we can
- # purposely "misuse" the [package present] command for this
- # purpose. We know the "Tcl" package is always present;
- # therefore, if an error is raised here, then the package
- # requirement is probably invalid. Unfortunately, the error
- # message text has to be checked as well; otherwise, there
- # is no way to verify version numbers that happen to be less
- # than the running patch level of Tcl.
- #
- if {[catch {package present Tcl $requirement} error] == 0} then {
- return true
- } else {
- #
- # TODO: Maybe this will require updates in the future?
- #
- set pattern(1) "expected version number but got *"
- set pattern(2) "expected versionMin-versionMax but got *"
-
- if {![string match $pattern(1) $error] && \
- ![string match $pattern(2) $error]} then {
- return true
- } else {
- return false
- }
- }
- }
- }
-
- #
- # NOTE: This procedure attempts to extract the package lookup metadata from
- # the lookup result. The result argument is the lookup result. The
- # varName argument is the name of an array variable, in the call frame
- # of the immediate caller, that should receive the extracted package
- # lookup metadata. The caller argument must be an empty string -OR-
- # the literal string "handler".
- #
- proc extractAndVerifyLookupMetadata { result varName caller } {
- variable strictUnknownLanguage
-
- #
- # NOTE: Grab the returned patch level. It cannot be an empty string
- # and it must conform to the TIP #268 requirements for a single
- # package version.
- #
- set patchLevel [getDictionaryValue $result PatchLevel]
-
- if {[string length $patchLevel] == 0} then {
- error "missing patch level"
- }
-
- if {![isValidPackageRequirement $patchLevel false]} then {
- error "bad patch level"
- }
-
- #
- # NOTE: Grab the language for the package script. It must be an empty
- # string, "Tcl", or "Eagle". If it is an empty string, "Eagle"
- # will be assumed.
- #
- set language [getDictionaryValue $result Language]
-
- if {[lsearch -exact [list "" Tcl Eagle] $language] == -1} then {
- error "unsupported language"
- }
-
- #
- # NOTE: Grab the package script. If it is an empty string, then the
- # package cannot be loaded and there is nothing to do. In that
- # case, just raise an error.
- #
- set script [getDictionaryValue $result Script]
-
- if {[string length $script] == 0} then {
- error "missing script"
- }
-
- #
- # NOTE: Grab the package script certificate. If it is an empty string
- # then the package script is unsigned, which is not allowed by
- # this client. In that case, just raise an error.
- #
- set certificate [getDictionaryValue $result Certificate]
-
- if {[string length $certificate] == 0} then {
- error "missing script certificate"
- }
-
- #
- # NOTE: Are we being called from the [package unknown] handler
- # in "strict" mode?
- #
- if {$strictUnknownLanguage && $caller eq "handler"} then {
- #
- # NOTE: If so, the package script must be targeted at the this
- # language; otherwise, there exists the possibility that
- # the package may not be provided to this language.
- #
- if {[isEagle]} then {
- if {$language ne "Eagle"} then {
- error "repository package is not for Eagle"
- }
- } else {
- if {$language ne "Tcl"} then {
- error "repository package is not for Tcl"
- }
- }
- }
-
- #
- # NOTE: If the caller wants the package lookup metadata, use their
- # array variable name.
- #
- if {[string length $varName] > 0} then {
- upvar 1 $varName metadata
-
- set metadata(patchLevel) $patchLevel
- set metadata(language) $language
- set metadata(script) $script
- set metadata(certificate) $certificate
- }
- }
-
- #
- # NOTE: This procedure, which may only be used from an Eagle script, checks
- # if a native Tcl library is loaded and ready. If not, a script error
- # is raised.
- #
- proc tclMustBeReady {} {
- #
- # NOTE: This procedure is not allowed to actually load a native Tcl
- # library; therefore, one must already be loaded.
- #
- if {![isEagle]} then {
- error "already running in Tcl language"
- }
-
- if {![tcl ready]} then {
- error "cannot use Tcl language, supporting library is not loaded"
- }
- }
-
- #
- # NOTE: This procedure, which may only be used from a native Tcl script,
- # checks if Garuda and Eagle are loaded and ready. If not, a script
- # error is raised.
- #
- proc eagleMustBeReady {} {
- #
- # NOTE: This procedure is not allowed to actually load Garuda (and
- # Eagle); therefore, they must already be loaded.
- #
- if {[isEagle]} then {
- error "already running in Eagle language"
- }
-
- if {[llength [info commands eagle]] == 0} then {
- error "cannot use Eagle language, supporting package is not loaded"
- }
- }
-
- #
- # NOTE: This procedure returns non-zero if the current script is being
- # evaluated in Eagle with signed-only script security enabled.
- # There are no arguments.
- #
- proc eagleHasSecurity {} {
- #
- # NOTE: If possible, check if the current interpreter has security
- # enabled.
- #
- if {[isEagle] && [llength [info commands object]] > 0} then {
- if {[catch {
- object invoke -flags +NonPublic Interpreter.GetActive HasSecurity
- } security] == 0 && $security} then {
- return true
- }
- }
-
- return false
- }
-
- #
- # NOTE: This procedure uses the package lookup metadata. If the package
- # script is properly signed, an attempt will be made to evaluate it
- # in the target language. If the script was signed using PGP, then
- # a conforming implementation of the OpenPGP specification (e.g.
- # gpg2) must be installed locally. If the script was signed using
- # Harpy then Garuda, Eagle, and Harpy must be installed locally.
- # This procedure is designed to work for both native Tcl and Eagle
- # packages. Additionally, it is designed to work when evaluated
- # using either native Tcl or Eagle; however, it is up to the package
- # script itself to either add the package or provide the package to
- # the language(s) supported by that package. The varName argument
- # is the name of an array variable in the call frame of the
- # immediate caller, that contains the package lookup metadata. This
- # procedure may raise script errors.
- #
- proc processLookupMetadata { varName } {
- #
- # NOTE: If the metadata variable name appears to be invalid, fail.
- #
- if {[string length $varName] == 0} then {
- error "bad metadata"
- }
-
- #
- # NOTE: This procedure requires that the metadata array variable is
- # present in the call frame immediately above this one.
- #
- upvar 1 $varName metadata
-
- #
- # NOTE: If the entire package metadata array is missing, fail.
- #
- if {![info exists metadata]} then {
- error "missing metadata"
- }
-
- #
- # NOTE: If the patch level for the package is mising, fail.
- #
- if {![info exists metadata(patchLevel)]} then {
- error "missing patch level"
- }
-
- #
- # NOTE: If the language for the package script is mising, fail.
- #
- if {![info exists metadata(language)]} then {
- error "missing language"
- }
-
- #
- # NOTE: If the package script is mising, fail.
- #
- if {![info exists metadata(script)]} then {
- error "missing script"
- }
-
- #
- # NOTE: If the package script certificate is mising, fail.
- #
- if {![info exists metadata(certificate)]} then {
- error "missing script certificate"
- }
-
- #
- # NOTE: Create common cleanup script block that deletes any temporary
- # files created for the script verification process.
- #
- set script(cleanup) {
- if {[string length $fileName(2)] > 0 && \
- [file exists $fileName(2)] && [file isfile $fileName(2)]} then {
- if {![info exists ::env(pkgr_keep_files)]} then {
- catch {file delete $fileName(2)}
- }
- unset -nocomplain fileName(2)
- }
-
- if {[string length $fileName(1)] > 0 && \
- [file exists $fileName(1)] && [file isfile $fileName(1)]} then {
- if {![info exists ::env(pkgr_keep_files)]} then {
- catch {file delete $fileName(1)}
- }
- unset -nocomplain fileName(1)
- }
- }
-
- #
- # NOTE: Figure out the "type" of script certificate we are now dealing
- # with.
- #
- if {[isHarpyCertificate $metadata(certificate)]} then {
- #
- # NOTE: Attempt to create a completely unique array variable name to
- # hold the package metadata in this scripting language as well
- # as possibly in the other necessary scripting language(s).
- #
- set newVarName(1) [appendArgs \
- [getLookupVarNamePrefix] metadata_ [getLookupVarNameSuffix]]
-
- set newVarName(2) [appendArgs \
- [getLookupVarNamePrefix] cleanup_ [getLookupVarNameSuffix]]
-
- set newProcName(1) [appendArgs \
- [getLookupVarNamePrefix] eagleHasSecurity_ [getLookupVarNameSuffix]]
-
- set newProcName(2) [appendArgs \
- [getLookupVarNamePrefix] getFileTempName_ [getLookupVarNameSuffix]]
-
- set newProcName(3) [appendArgs \
- [getLookupVarNamePrefix] tclMustBeReady_ [getLookupVarNameSuffix]]
-
- #
- # NOTE: Create the Eagle script block that will be used to securely
- # evaluate a signed package script. This must be evaluated in
- # Eagle because it uses several plugins only available there.
- #
- set script(outer) [string map [list \
- %metadata% $newVarName(1) %cleanup% $newVarName(2) \
- %eagleHasSecurity% $newProcName(1) %getFileTempName% \
- $newProcName(2) %tclMustBeReady% $newProcName(3)] {
- try {
- #
- # NOTE: If there is no package script, there is nothing we
- # can do here.
- #
- if {[string length ${%metadata%(script)}] > 0} then {
- #
- # NOTE: Save the security state for the interpreter. Then, attempt
- # to enable it. This will fail if one of the needed plugins
- # cannot be loaded.
- #
- set savedSecurity [{%eagleHasSecurity%}]
- if {!$savedSecurity} then {source enableSecurity}
-
- try {
- #
- # NOTE: Figure out temporary file name for the downloaded script
- # and its associated script certificate.
- #
- set fileName(1) [{%getFileTempName%}]
- set fileName(2) [appendArgs $fileName(1) .harpy]
-
- try {
- #
- # NOTE: Write downloaded script to a temporary file.
- #
- writeFile $fileName(1) ${%metadata%(script)}
-
- #
- # NOTE: Write downloaded script certificate to a temporary
- # file.
- #
- if {[string length ${%metadata%(certificate)}] > 0} then {
- writeFile $fileName(2) ${%metadata%(certificate)}
- }
-
- #
- # NOTE: This seems stupid. Why are we reading the downloaded
- # script from the temporary file when we already had it
- # in memory? The reason is that we need to make sure
- # that the Harpy policy engine has a chance to check the
- # downloaded script against its associated certificate.
- # This will raise a script error if the script signature
- # is missing or invalid.
- #
- set script(inner) [interp readorgetscriptfile -- \
- "" $fileName(1)]
-
- #
- # NOTE: Determine the target language for the package script,
- # which may or may not be the language that is currently
- # evaluating this script (Eagle). The default language,
- # when one was not explicitly specified, is Eagle. In
- # the future, this may be changed, e.g. to use the file
- # extension of the client script.
- #
- switch -exact -- ${%metadata%(language)} {
- "" -
- Eagle {
- #
- # NOTE: The target language is Eagle, which is evaluating
- # this script. No special handling is needed here.
- #
- return [uplevel #0 $script(inner)]
- }
- Tcl {
- #
- # NOTE: The target language is Tcl; therefore, a bit of
- # special handling is needed here.
- #
- {%tclMustBeReady%}; return [tcl eval [tcl master] [list \
- uplevel #0 $script(inner)]]
- }
- default {
- error "unsupported language"
- }
- }
- } finally {
- #
- # NOTE: Perform any necessary cleanup steps.
- #
- eval ${%cleanup%}
- }
- } finally {
- #
- # NOTE: Restore the saved security state for the interpreter.
- #
- if {!$savedSecurity} then {source disableSecurity}
- unset -nocomplain savedSecurity
- }
- }
- } finally {
- rename {%tclMustBeReady%} ""
- rename {%getFileTempName%} ""
- rename {%eagleHasSecurity%} ""
-
- unset -nocomplain {%cleanup%}
- unset -nocomplain {%metadata%}
- }
- }]
-
- #
- # NOTE: Copy the package metadata into the fresh array variable,
- # if necessary, marshalling it from native Tcl to Eagle.
- #
- if {[isEagle]} then {
- array set $newVarName(1) [array get metadata]
- set $newVarName(2) $script(cleanup)
-
- proc $newProcName(1) {} [info body [appendArgs \
- [namespace current] ::eagleHasSecurity]]
-
- proc $newProcName(2) {} [info body [appendArgs \
- [namespace current] ::getFileTempName]]
-
- proc $newProcName(3) {} [info body [appendArgs \
- [namespace current] ::tclMustBeReady]]
-
- return [eval $script(outer)]
- } else {
- eagleMustBeReady
-
- eagle [list array set $newVarName(1) [array get metadata]]
- eagle [list set $newVarName(2) $script(cleanup)]
-
- eagle [list proc $newProcName(1) {} [info body [appendArgs \
- [namespace current] ::eagleHasSecurity]]]
-
- eagle [list proc $newProcName(2) {} [info body [appendArgs \
- [namespace current] ::getFileTempName]]]
-
- eagle [list proc $newProcName(3) {} [info body [appendArgs \
- [namespace current] ::tclMustBeReady]]]
-
- return [eagle $script(outer)]
- }
- } elseif {[isPgpSignature $metadata(certificate)]} then {
- #
- # NOTE: If there is no package script, there is nothing we
- # can do here.
- #
- if {[string length $metadata(script)] > 0} then {
- #
- # NOTE: Figure out temporary file name for the downloaded script
- # and its associated PGP signature.
- #
- set fileName(1) [getFileTempName]
- set fileName(2) [appendArgs $fileName(1) .asc]
-
- #
- # NOTE: Write downloaded script to a temporary file.
- #
- writeFile $fileName(1) $metadata(script)
-
- #
- # NOTE: Write downloaded script PGP signature a temporary file.
- #
- if {[string length $metadata(certificate)] > 0} then {
- writeFile $fileName(2) $metadata(certificate)
- }
-
- #
- # NOTE: Attempt to verify the PGP signature for the package script.
- #
- if {[verifyPgpSignature $fileName(2)]} then {
- #
- # NOTE: Delete the temporary files that we created for the PGP
- # signature verification.
- #
- eval $script(cleanup)
- } else {
- #
- # NOTE: Delete the temporary files that we created for the PGP
- # signature verification.
- #
- eval $script(cleanup)
-
- #
- # NOTE: PGP signature verification failed. Raise an error and
- # do not proceed with evaluating the package script.
- #
- error "bad PGP signature"
- }
-
- #
- # NOTE: The PGP signature was verified; use the downloaded package
- # script verbatim.
- #
- set script(inner) $metadata(script)
-
- #
- # NOTE: Determine the target language for the package script, which
- # may or may not be the language that is currently evaluating
- # this script (Eagle). The default language, when one was not
- # explicitly specified, is Eagle. In the future, this may be
- # changed, e.g. to use the file extension of the client script.
- #
- switch -exact -- $metadata(language) {
- "" -
- Eagle {
- if {[isEagle]} then {
- return [uplevel #0 $script(inner)]
- } else {
- eagleMustBeReady
-
- return [eagle [list uplevel #0 $script(inner)]]
- }
- }
- Tcl {
- if {[isEagle]} then {
- tclMustBeReady; return [tcl eval [tcl master] [list \
- uplevel #0 $script(inner)]]
- } else {
- return [uplevel #0 $script(inner)]
- }
- }
- default {
- error "unsupported language"
- }
- }
- }
- } else {
- error "unsupported script certificate"
- }
- }
-
- #
- # NOTE: This procedure performs initial setup of the package repository
- # client, using the current configuration parameters. There are
- # no arguments. It may load the Garuda package when evaluated in
- # native Tcl. It may load a native Tcl library when evaluated in
- # Eagle. It may install the [package unknown] hook.
- #
- proc setupPackageUnknownHandler {} {
- variable autoHook
- variable autoLoadTcl
- variable autoRequireGaruda
-
- if {$autoRequireGaruda && ![isEagle]} then {
- #
- # TODO: Assume this package is trusted? How can we verify it
- # at this point?
- #
- package require Garuda
- }
-
- if {$autoLoadTcl && [isEagle]} then {
- #
- # NOTE: Load a native Tcl library. It must be signed with a valid
- # Authenticode signature.
- #
- tcl load -findflags +TrustedOnly -loadflags +SetDllDirectory
- }
-
- if {$autoHook && ![isPackageUnknownHandlerHooked]} then {
- #
- # NOTE: Install our [package unknown] handler and save the original
- # one for our use as well.
- #
- hookPackageUnknownHandler
- }
- }
-
- #
- # NOTE: This procedure returns non-zero if the [package unknown] handler
- # has already been hooked by the package repository client. There
- # are no arguments.
- #
- proc isPackageUnknownHandlerHooked {} {
- return [info exists [appendArgs \
- [getLookupVarNamePrefix] saved_package_unknown]]
- }
-
- #
- # NOTE: This procedure attempts to hook the [package unknown] handler. It
- # will raise a script error if this has already been done. The old
- # [package unknown] handler is saved and will be used by the new one
- # as part of the overall package loading process. There are no
- # arguments.
- #
- proc hookPackageUnknownHandler {} {
- set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
-
- if {[info exists $varName]} then {
- error "package unknown handler already hooked"
- }
-
- set $varName [package unknown]
- package unknown [appendArgs [namespace current] ::packageUnknownHandler]
- }
-
- #
- # NOTE: This procedure attempts to unhook the [package unknown] handler.
- # It will raise a script error if the [package unknown] handler is
- # not hooked. The old [package unknown] handler is restored and
- # the saved [package unknown] handler is cleared. There are no
- # arguments.
- #
- proc unhookPackageUnknownHandler {} {
- set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
-
- if {![info exists $varName]} then {
- error "package unknown handler is not hooked"
- }
-
- package unknown [set $varName]
- unset $varName
- }
-
- #
- # NOTE: The procedure runs the saved [package unknown] handler. Any script
- # errors are raised to the caller. The package and version arguments
- # are passed in from the current [package unknown] handler verbatim.
- #
- proc runSavedPackageUnknownHandler { package version } {
- #
- # NOTE: See if there is a saved [package unknown] handler. If so, then
- # attempt to use it.
- #
- set varName [appendArgs [getLookupVarNamePrefix] saved_package_unknown]
- set oldHandler [expr {[info exists $varName] ? [set $varName] : ""}]
-
- if {[string length $oldHandler] > 0} then {
- lappend oldHandler $package $version; uplevel #0 $oldHandler
- }
- }
-
- #
- # NOTE: This procedure is the [package unknown] handler entry point called
- # by native Tcl and Eagle. The package argument is the name of the
- # package being sought, it cannot be an empty string. The version
- # argument must be a specific version -OR- a package specification
- # that conforms to TIP #268. This version argument must be optional
- # here, because Eagle does not add a version argument when one is
- # not explicitly supplied to the [package require] sub-command.
- #
- proc packageUnknownHandler { package {version ""} } {
- variable verboseUnknownResult
-
- #
- # NOTE: First, run our [package unknown] handler.
- #
- set code(1) [catch {main $package $version handler} result(1)]
-
- if {$verboseUnknownResult} then {
- pkgLog [appendArgs \
- "repository handler results for package \"" [formatPackageName \
- $package $version] "\" are " [formatResult $code(1) $result(1)]]
- }
-
- #
- # NOTE: Next, run the saved [package unknown] handler.
- #
- set code(2) [catch {
- runSavedPackageUnknownHandler $package $version
- } result(2)]
-
- if {$verboseUnknownResult} then {
- pkgLog [appendArgs \
- "saved handler results for package \"" [formatPackageName \
- $package $version] "\" are " [formatResult $code(2) $result(2)]]
- }
-
- #
- # NOTE: Maybe check for the package and then optionally log results.
- #
- if {$verboseUnknownResult} then {
- set ifNeededVersion [getIfNeededVersion \
- $package [packageRequirementToVersion $version]]
-
- if {[string length $ifNeededVersion] > 0} then {
- set command [list package ifneeded $package $ifNeededVersion]
-
- if {[catch $command result(3)] == 0 && \
- [string length $result(3)] > 0} then {
- pkgLog [appendArgs \
- "package script for \"" [formatPackageName $package \
- $ifNeededVersion] "\" was added: " [list $result(3)]]
- } else {
- pkgLog [appendArgs \
- "package script for \"" [formatPackageName $package \
- $ifNeededVersion] "\" was not added: " [list $result(3)]]
- }
- } else {
- pkgLog [appendArgs \
- "package script for \"" [formatPackageName $package \
- $ifNeededVersion] "\" was not added"]
- }
-
- set command [list package present $package]
- if {[string length $version] > 0} then {lappend command $version}
-
- if {[catch $command] == 0} then {
- pkgLog [appendArgs \
- "package \"" [formatPackageName $package $version] \
- "\" was loaded"]
- } else {
- pkgLog [appendArgs \
- "package \"" [formatPackageName $package $version] \
- "\" was not loaded"]
- }
- }
- }
-
- #
- # NOTE: This procedure evaluates the package repository client settings
- # script file, if it exists. Any script errors raised are not
- # masked. The script argument must be the fully qualified path
- # and file name for the primary package repository client script
- # file.
- #
- proc maybeReadSettingsFile { script } {
- if {[string length $script] == 0 || \
- ![file exists $script] || ![file isfile $script]} then {
- return
- }
-
- set fileName [appendArgs \
- [file rootname $script] .settings [file extension $script]]
-
- if {[file exists $fileName] && [file isfile $fileName]} then {
- uplevel 1 [list source $fileName]
- }
- }
-
- #
- # NOTE: This procedure sets up the default values for all configuration
- # parameters used by the package repository client. There are no
- # arguments.
- #
- proc setupPackageUnknownVars {} {
- #
- # NOTE: Automatically install our [package unknown] handler when this
- # package is loaded?
- #
- variable autoHook; # DEFAULT: true
-
- if {![info exists autoHook]} then {
- set autoHook true
- }
-
- #
- # NOTE: Automatically [tcl load] when this package is loaded from the
- # Eagle language?
- #
- variable autoLoadTcl; # DEFAULT: true
-
- if {![info exists autoLoadTcl]} then {
- set autoLoadTcl true
- }
-
- #
- # NOTE: Automatically [package require Garuda] when this package is
- # loaded from the Tcl language?
- #
- variable autoRequireGaruda; # DEFAULT: true
-
- if {![info exists autoRequireGaruda]} then {
- set autoRequireGaruda true
- }
-
- #
- # NOTE: The command to use when verifying OpenPGP signatures for the
- # downloaded package scripts.
- #
- variable pgpCommand; # DEFAULT: gpg2 --verify {${fileName}}
-
- if {![info exists pgpCommand]} then {
- set pgpCommand {gpg2 --verify {${fileName}}}
- }
-
- #
- # NOTE: Verify that the package script matches the current language
- # when called from the [package unknown] handler?
- #
- variable strictUnknownLanguage; # DEFAULT: true
-
- if {![info exists strictUnknownLanguage]} then {
- set strictUnknownLanguage true
- }
-
- #
- # NOTE: Emit diagnostic messages when a [package unknown] handler
- # is called?
- #
- variable verboseUnknownResult; # DEFAULT: false
-
- if {![info exists verboseUnknownResult]} then {
- set verboseUnknownResult false
- }
-
- #
- # NOTE: Emit diagnostic messages when a URI is fetched?
- #
- variable verboseUriDownload; # DEFAULT: false
-
- if {![info exists verboseUriDownload]} then {
- set verboseUriDownload false
- }
- }
-
- #
- # NOTE: This procedure is the primary entry point to the package repository
- # client. It attempts to lookup the specified package using the
- # currently configured package repository server. The package
- # argument is the name of the package being sought, it cannot be an
- # empty string. The version argument must be a specific version -OR-
- # a package specification that conforms to TIP #268. The caller
- # argument must be an empty string -OR- the literal string "handler".
- #
- #
- proc main { package version caller } {
- #
- # NOTE: Get the list of API keys and try each one, in order, until
- # the package is found.
- #
- set apiKeys [getLookupApiKeys]; lappend apiKeys ""
-
- foreach apiKey $apiKeys {
- #
- # NOTE: Issue the lookup request to the remote package repository.
- #
- set data [getLookupData $apiKey $package $version]
-
- #
- # NOTE: Attempt to grab the lookup code from the response data.
- #
- set code [getLookupCodeFromData $data]
-
- #
- # NOTE: Did the lookup operation succeed? If so, stop trying
- # other API keys.
- #
- if {[isLookupCodeOk $code]} then {
- break
- }
- }
-
- #
- # NOTE: Attempt to grab the lookup data from the response data.
- # Upon failure, this should contain the error message.
- #
- set result [getLookupResultFromData $data]
-
- #
- # NOTE: Did the lookup operation fail?
- #
- if {![isLookupCodeOk $code]} then {
- #
- # NOTE: Is there an error message?
- #
- if {[string length $result] > 0} then {
- #
- # NOTE: Yes. Use the returned error message verbatim.
- #
- error $result
- } else {
- #
- # NOTE: No. Use the whole response data string as the error
- # message.
- #
- error $data
- }
- }
-
- #
- # NOTE: Process the lookup data into the pieces of metadata that we
- # need to load the requested package.
- #
- extractAndVerifyLookupMetadata $result metadata $caller
-
- #
- # NOTE: Attempt to load the requested package using the metadata
- # extracted in the previous step.
- #
- processLookupMetadata metadata
- }
-
- if {![isEagle]} then {
- ###########################################################################
- ############################# BEGIN Tcl ONLY ##############################
- ###########################################################################
-
- #
- # NOTE: This procedure was stolen from the "getEagle.tcl" script. It is
- # designed to emit a progress indicator while an HTTP request is
- # being processed. The channel argument is the Tcl channel where
- # the progress indicator should be emitted. The type argument is
- # the single-character progress indicator. The milliseconds
- # argument is the number of milliseconds to wait until the next
- # periodic progress indicator should be emitted. This procedure
- # reschedules its own execution.
- #
- proc pageProgress { channel type milliseconds } {
- #
- # NOTE: This variable is used to keep track of the currently scheduled
- # (i.e. pending) [after] event.
- #
- variable afterForPageProgress
-
- #
- # NOTE: Show that something is happening...
- #
- catch {puts -nonewline $channel $type; flush $channel}
-
- #
- # NOTE: Make sure that we are scheduled to run again, if requested.
- #
- if {$milliseconds > 0} then {
- set afterForPageProgress [after $milliseconds \
- [namespace code [list pageProgress $channel $type \
- $milliseconds]]]
- } else {
- unset -nocomplain afterForPageProgress
- }
- }
-
- #
- # NOTE: This procedure was stolen from the "getEagle.tcl" script. It is
- # designed to process a single HTTP request, including any HTTP
- # 3XX redirects (up to the specified limit), and return the raw
- # HTTP response data. It does not contain special code to handle
- # HTTP status codes other than 3XX (e.g. 4XX, 5XX, etc).
- #
- #
- proc getFileViaHttp { uri redirectLimit channel quiet args } {
- #
- # NOTE: This variable is used to keep track of the currently scheduled
- # (i.e. pending) [after] event.
- #
- variable afterForPageProgress
-
- #
- # NOTE: This procedure requires the modern version of the HTTP package,
- # which is typically included with the Tcl core distribution.
- #
- package require http 2.0
-
- #
- # NOTE: If the 'tls' package is available, always attempt to use HTTPS.
- #
- if {[catch {package require tls}] == 0} then {
- ::http::register https 443 ::tls::socket
-
- if {[string range $uri 0 6] eq "http://"} then {
- set uri [appendArgs https:// [string range $uri 7 end]]
- }
- }
-
- #
- # NOTE: Unless the caller forbids it, display progress messages during
- # the download.
- #
- if {!$quiet} then {
- pageProgress $channel . 250
- }
-
- #
- # NOTE: All downloads are handled synchronously, which is not ideal;
- # however, it is simple. Keep going as long as there are less
- # than X redirects.
- #
- set redirectCount 0
-
- while {1} {
- #
- # NOTE: Issue the HTTP request now, grabbing the resulting token.
- #
- set token [eval [list ::http::geturl $uri] $args]
-
- #
- # NOTE: Check the HTTP response code, in order to follow any HTTP
- # redirect responses.
- #
- switch -exact -- [http::ncode $token] {
- 301 -
- 302 -
- 303 -
- 307 {
- #
- # NOTE: Unless the caller forbids it, display progress messages
- # when an HTTP redirect is returned.
- #
- if {!$quiet} then {
- pageProgress $channel > 0
- }
-
- #
- # NOTE: We hit another HTTP redirect. Stop if there are more
- # than X.
- #
- incr redirectCount
-
- #
- # TODO: Maybe make this limit configurable?
- #
- if {$redirectCount > $redirectLimit} then {
- #
- # NOTE: Just "give up" and return whatever data that we have
- # now.
- #
- set data [::http::data $token]
- ::http::cleanup $token; break
- }
-
- #
- # NOTE: Grab the metadata associated with this HTTP response.
- #
- array set meta [::http::meta $token]
-
- #
- # NOTE: Is there actually a new URI (location) to use?
- #
- if {[info exist meta(Location)]} then {
- #
- # NOTE: Ok, grab it now. Later, at the top of the loop,
- # it will be used in the subsequent HTTP request.
- #
- set location $meta(Location); unset meta
-
- #
- # NOTE: For security, do NOT follow an HTTP redirect if
- # it attempts to redirect from HTTPS to HTTP.
- #
- if {[string range $uri 0 7] eq "https://" && \
- [string range $location 0 7] ne "https://"} then {
- #
- # NOTE: Just "give up" and return whatever data that
- # we have now.
- #
- set data [::http::data $token]
- ::http::cleanup $token; break
- }
-
- #
- # NOTE: Replace the original URI with the new one, for
- # use in the next HTTP request.
- #
- set uri $location
-
- #
- # NOTE: Cleanup the current HTTP token now beause a new
- # one will be created for the next request.
- #
- ::http::cleanup $token
- } else {
- #
- # NOTE: Just "give up" and return whatever data that we
- # have now.
- #
- set data [::http::data $token]
- ::http::cleanup $token; break
- }
- }
- default {
- #
- # NOTE: Ok, the HTTP response is actual data of some kind
- # (which may be an error); however, it is not any
- # kind of supported HTTP redirect.
- #
- set data [::http::data $token]
- ::http::cleanup $token; break
- }
- }
- }
-
- #
- # NOTE: If there is a currently scheduled [after] event, cancel it.
- #
- if {[info exists afterForPageProgress]} then {
- catch {after cancel $afterForPageProgress}
- unset -nocomplain afterForPageProgress
- }
-
- #
- # NOTE: If progress messages were emitted, start a fresh line.
- #
- if {!$quiet} then {
- catch {puts $channel [appendArgs " " $uri]; flush $channel}
- }
-
- return $data
- }
-
- ###########################################################################
- ############################## END Tcl ONLY ###############################
- ###########################################################################
- }
-
- #
- # NOTE: Attempt to read optional settings file now. This may override
- # one or more of the variable setup in the next step.
- #
- maybeReadSettingsFile [info script]
-
- #
- # NOTE: Setup the variables, within this namespace, used by this script.
- #
- setupPackageUnknownVars
-
- #
- # NOTE: Setup for our [package unknown] handler, which may involve a few
- # different operations.
- #
- setupPackageUnknownHandler
-
- #
- # NOTE: Provide the package to the interpreter.
- #
- package provide Eagle.Package.Repository \
- [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
-}
-
DELETED client/pkgr.eagle.harpy
Index: client/pkgr.eagle.harpy
==================================================================
--- client/pkgr.eagle.harpy
+++ client/pkgr.eagle.harpy
@@ -1,50 +0,0 @@
-
-
-
- None
- Mistachkin Systems
- 88d42a28-1e95-4dd7-aaf9-11bb262f10d0
- SHA512
- Script
- 2016-08-19T02:47:51.4043437Z
- -1.00:00:00
- 0x2c322765603b5278
-
- Mn+rsBh675oM30+X6J/Myzrc0MmxmLCjpzV4bDcl8nZcbdSXszHTHE9ma5tAXopb05bMomy5lHal
- CjEGgYubJtQFcQzuKlxp0UMVgMpK28uTS/ik9RSKXwgq83N1pwvM7cmF2RzxF/fmD/0dtb0Ulc+h
- Ior9NeJcpD6lBAE3XEB288f+79mA3U2X1io4qLYvFzktpKyjen8pC8J46078b3HXSoYGUHehmZo+
- EJhVhD0Lfb9XtGh4V9hgmL9aMWJdv/jGmq+tKOJxxpU70avW4aaUzDKZE/zgR674/o2jhTw8LC+P
- 7Ed5UhgnXXr6Ko0HlIZqWwwblP+/WJ91Rf3DBzlJDG1Wjwku2xAQN2JcLipbn0YGG3jr4qx9yrnw
- /K1HT0CEWW/41F/LeZAZ36Kao76kGcl4OcamgAW4fPp2c85wRyIh3i6f4t1RxgixgVUuMWhbVVu5
- Fb/opbLwHBLIGQpmYqmZhz6A97CSr5eyj1CpKEAz/v76ma3qgravdVZ59C5NdhPXHQGS5MpgsWUC
- tHc5aXK9npgN3femt1czY8J+dLMFP0N4ENlqJNRP14zFOd0a2vNnc6KB8OE4GAdL0V1KaAK2WIOQ
- h5cPFMKSphWT8cst4/nLbOhs9G8JlXD1PsIKxgGW5YSYutkZQJPUcDMFmSEdaQ6CCc1K+o6SEXvS
- RcdPzCEDwJmgYUF77ILI0whNBNFSVD+UPcoD1j6KUmJKHhOt63EYVmRUFlYfw1afVeCjrgm2q5Tp
- aSVYPaoqUlBuZ0lomqUD03/XsqdwVdiZXEuoObr4INoMeZnHyQf5wpLl1ZGBvGdc7ujOkU8y/sVX
- Y9ATG3czSvQlNz/06J/ghVEK1t7ZNyEe0thwj6AHM52D/GuFTmfnFaBS5HQawOE9FkYppA7x+65Z
- rZjUaIBEaybEYPok29IKqw+aqA2s21gJ9c70d/M7UlpwGbT9CQqV+o6/2frQF6vSPUhrFsZPCZZs
- hE7hn/jluR+tT0g3awKqWayNfG5/ZfJruKwmXcipeacr42Affi0zNxuxsMglndGGEKFtsrGySjcF
- 2NCquShXYNz4i/7jh0IO4Udb5t/PP1Brpp26t35/Oug/2i2eTO5gq4MvsffXvjeEPYWPjUBug0y1
- HNAmHDDUqLoD3nK3AK+em1ukGdjMEsvlz+L9+IjOJ/po5ypkgNIsNqQITBY0S4ofp1XO2o9IHPGN
- G0qKBB7G2PcGe7hh9FOAyPL81OYpxYc7Pe80zxqu+KZP6OPalBssNqIIHqj2p03cukS5X8U0QPO+
- 2f7Iv9SxJ0t9pcKyZX2iHx5H9+u0TpsghdQPiu9u63GUnIkMJfEWUoBxfJNfWuIzuMoe3rugJQ==
-
-
DELETED client/pkgr.settings.eagle
Index: client/pkgr.settings.eagle
==================================================================
--- client/pkgr.settings.eagle
+++ client/pkgr.settings.eagle
@@ -1,22 +0,0 @@
-###############################################################################
-#
-# pkgr.settings.eagle --
-#
-# Extensible Adaptable Generalized Logic Engine (Eagle)
-# Package Repository Client Settings
-#
-# 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: $
-#
-###############################################################################
-
-# TODO: Set this to your list of API keys.
-# set ::pkgr_api_keys [list 0000000000000000000000000000000000000000]
-
-variable strictUnknownLanguage false
-variable verboseUnknownResult true
-variable verboseUriDownload true
DELETED client/pkgr.settings.eagle.harpy
Index: client/pkgr.settings.eagle.harpy
==================================================================
--- client/pkgr.settings.eagle.harpy
+++ client/pkgr.settings.eagle.harpy
@@ -1,50 +0,0 @@
-
-
-
- None
- Mistachkin Systems
- b44b4ef2-76ad-4786-b4b7-e1d604e15e8b
- SHA512
- Script
- 2016-08-17T22:22:56.6608906Z
- -1.00:00:00
- 0x2c322765603b5278
-
- efFtWFrnFkJeMBafjl1MxA1lygnogjoQHoS8qP4ptK+GuB7mvyJbSgtjYyUVJ0Nj9W88qJ0eGtQ3
- 5yd2fZrTX7nXmEkXaRFcSBiB/S6dtUrc6GGDO1PlOB7w3JGfSkh/4MgfRTrZyN+sRN6ODWPjFU4s
- m1+HXSXynBUKyPaJ8qNd/0foXvNC/rGbHyZ+Z4FkbAfYZZSTiIz57kv9ZvlmxjSoZNffYpOGD0kQ
- mFXkvDkoM4JxE3b19M/VFcKJ6NIn7o6Vqc3Xt40+9W5OTKjLVfpeV8gK01rU1d9+KuBnC3hQWyqZ
- V0fF2mkyGnxO0LAZpOiQ82b8Myld/vl79iGcMLb9F5+SdnYeqBrT8VFRaiZz12MS+8BP+3JItBqn
- WNFjKVWFXG5SI6aTaqbTDtiKRADqoJyb6HN5imfZll2tcK2ruICy4zYo79mDAolBEnwp4TnNcwKA
- h5oQTnc44dQht8xeZdT5Ah2SNRBx0GA3nHmJO9AP68JMYbPWLABQQ6hZf2b6u6zB3ZzU8RN/+NIa
- 3Y5jfKVD/f2BCJumU1jWh2R4785SNXfFT5Id5U0II9I9WhTdiylFXP3hiN/dNW0GAWq9v6TLG+pi
- vfJrr/26RQfEwIiNa8keQkfJ/HgTmille05ct7DycbHu9Edq9NxWgfTtWDsAnlERTG+WhRc5hZyc
- VegPWnHpoXeUHgEe5d4bkmmRfePnH+eWeibRveMErlv16jeTv4H28ftp3Vq8n0n+hkVHpYOHMV6i
- J3/RhJ4G1Se/adEPdVUQRfYrP5HwI/szeR5DQoZ+zAsB34cfwWn0hsj21FeqitSE/rQ0j8pcD3yy
- OIH07uf/sOqQ8hSEFnxVPTvQYp9H7QTBxFAxaMbpIUTpB6DyroPWzi4uSa+JXWSkf5sQOo2SLCoX
- t3w7tpZ6o2FZNd3O519FiX3+cM78vyfIMkbT4ZFEHpFkccuG6g9nVgUDCTgMwNldSKQAC7JtwjOZ
- tSQ9YjRTgZSGcJ+TjLnXJfWo8u0SM+J3K9o+zRcN+6zDZsCAo6inrxgICEFN+lTabJxyWas6MYeX
- hkq7CnGT9nsDtynLniiF4FUsKTVlgHfR1ZVPwWGb0Ow/L4PdPMTlzPVttsE4bcrii6xnf85O9ijU
- zfgBhDtRsst9TLXb514J8t4zT54AQPLav2DjXjDjChbm+/JF8ywAfq/v8/A0B3PIeDPgmRTouH48
- 0MFanzDYI3r75OC0ZMuS8EoseqkcC2C3IvJY9ZtsgnuIPbpxzsdooCCaHXUWL2mHZ+QOk8Q+jn7J
- 1V0BeUNi0hU9SZeAai1co8ehsCw3vUkOPUoYginn2ry5ALf/jEBHW+1CX3+jlT/snSZba0GPDg==
-
-