Index: client/1.0/neutral/pkgIndex.eagle
==================================================================
--- client/1.0/neutral/pkgIndex.eagle
+++ client/1.0/neutral/pkgIndex.eagle
@@ -20,5 +20,8 @@
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]]
+
+package ifneeded Eagle.Package.Uploader 1.0 \
+ [list source [file join $dir pkgu.eagle]]
Index: client/1.0/neutral/pkgIndex.eagle.asc
==================================================================
--- client/1.0/neutral/pkgIndex.eagle.asc
+++ client/1.0/neutral/pkgIndex.eagle.asc
@@ -1,18 +1,18 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
Comment: Eagle Package Repository
-iQIcBAABCAAGBQJXt2XQAAoJEFAslq9JXcLZ32EQAMPPN6pbNpqtm3OPnEtle0i2
-xXP/0oX1VmdHLpLMDO+DwvlIw4eLB6vDZs2Zmje3t+WxcJPlH2QWgjI4UDmmWS7h
-HOt4/EUftPgjKWKUYPNpCj0S1vpVnLv19GWiDp++uYAA+YrdxTu+szeeI/rVaS3k
-8dmVdAB7vO+EexhTywB883be5OWNBg1Jr+X7r/362CmXcL0Tdq31VDEP+q6JYTvW
-PLM5kf4YMvFREtINhG2eg1s8BZts5Vz4b1NzVmMF9yyngu1pVQ+jkPAgM2A1OM6x
-YQTMDTGZlanDDC+l131ts2GE4Lx96PwJBqbPii8Jhbkl+BqBZudDZ+mKhNhehBk5
-nlOJAsKNUNdV+9Zj94AsnqXjNymvocx2n1jI0xJl1mipqJ5S1Awh9s8WyYeXINp0
-WPxyQcamlLOnRz12tic3ht/07kwXjmZXNmy6wfVWX0FyljBhSiOmSxw8z77nLmy+
-hwHB9534Wlg4pEP8x+7N4NP0vu+cyfX9p1DHvNjklpcQLlHxGWAeu8vl87w+uamR
-XcJpOnTxLshoVKI6CQunn0/OXAWDk3gi4MuU9+ZtytNfOMErNl85kuFtJLTzP5+H
-2p8yGAliXQKET6+1a35u6xiPmjpfa3MABaQH5ooRMPm8Ii9t5pe3Ay3ylq4yB+Zn
-IF7GNZh4xmipcTCy/skB
-=suyk
+iQIcBAABCAAGBQJYXa+wAAoJEFAslq9JXcLZxNIP/AtM8si3DijLofsQY7HqWiWg
+b9b1s1GY/XWeEi1d/55U+YTRaVcf3SXpaK6bL/VvTeYTcKZVF1RFxiDJmWXLByhK
+DDbOhkliLHy3v16UQUe/gS5dWl+VneC+YbXm5Xa9ihjYq2It03WNdnRjzBucbrt6
+9MBSkIT7EQ9liE8qUDN0Iiv9gMoBvlQJUesSC5oNIBYD1Qtq5cm4i9u93rEqYu30
+pmZTejh0bxoCuu4HTde0twkLBavbrOvD3dve302BNs8IcseV8U8YtWnDwWrJTcTq
+5EhXnUFTxM3UVDvBkn1vWqo21PFunv/rwmTj37pLDnZtQPcsSD3HmcVV1oAMm20E
+aGExYo40UrBXu2TCTOwyermMXp753ESIMIVp/AtnfdvHQmm4ktJpjX4OGDmfzZ4T
+3BhbT9Zr+zQtsg4MtPIBDpumOibLfwtJjucA4wzvO+nI5BfCh7HHtNpFHb46N8a0
+SCTxtj8mW/ti80sREc3Mjgzj1blGpuV511R401pX7Wr7434HTVQqKwMTysUbxeWs
+Zom4YLD0UTintppqG0GWxmJ+hb4jx2UltxenjPopMFOaJaOhxtjsMdF+QtDziwC1
+No39CCPxPPNx3TTUnuWOYDJ0Ui1Zoab71ODv9dRAXIk7euOJ/LPtsAR93ci4ijCr
+FFA+eHUt/m1irua6x84T
+=/mzj
-----END PGP SIGNATURE-----
Index: client/1.0/neutral/pkgIndex.eagle.harpy
==================================================================
--- client/1.0/neutral/pkgIndex.eagle.harpy
+++ client/1.0/neutral/pkgIndex.eagle.harpy
@@ -19,50 +19,50 @@
None
Mistachkin Systems
- e1a22fd8-1cd1-4652-b0c9-b340408f1966
+ 2b5d4415-bd4e-4c28-9e40-ca22c349a18d
SHA512
Script
- 2016-08-23T04:07:23.6465312Z
+ 2016-12-23T23:01:34.3681640Z
-1.00:00:00
0x9559f6017247e3e2
- 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
+ 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
Index: client/1.0/neutral/pkgIndex.eagle.harpy.asc
==================================================================
--- client/1.0/neutral/pkgIndex.eagle.harpy.asc
+++ client/1.0/neutral/pkgIndex.eagle.harpy.asc
@@ -1,18 +1,18 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
Comment: Eagle Package Repository
-iQIcBAABCAAGBQJX3ddfAAoJEFAslq9JXcLZZ64P/1KwUGRntTrhpe1JY7EggZOc
-p/CYp3Q/FrWSLA+3Kk3AmQfj0E0JEIHX6rjNNcTX+lK538OxS1wTXL23qx5M7KRD
-HesRavZoypr2WrFUHf1zCFBrllkYP/zyeXj6hpz7J+QeTaGAsbiBVRCLVOc82wIf
-l+ZYaKevKIoMiivaxn2WmrrdlmP3dsgGdQcZohGwActvON6HGIUE0EeAxpNN0Mw5
-bwPeNl2ldRJ6M4slswYqV3QuAwV68oR6rPGA//bSTfzKM/+RTpX0XscnYcuV48GN
-A7Gjzz8YIl4ohAYaSUmIwfS0YhHHWz+GPdchPE9itG0qeltDO3zBqu2ldU6pIRXR
-dZizDy+bWh+6fzNV9Pd74aIDiVDHSb3f4PdNrxLj4g2ZrHhJ8fTs4zPP7yHBWCA0
-6G4Rbjz/+P20tcO344LexvFc/qYwx59S8BiXOkbnot9Qu8sD+L192ZoEzKCxE6R3
-fUt8FdNoOBuM2rO4PwqmZr6siYPXA6UTCe04c7uKglUpFEtYHedAvPG0zeRZkHc8
-YhvIpA5CG1WL/Z5RLx2IMfMTGhVh4tKv6rg1HYmLiyHnUk/Yp/hzD9AfGztaig73
-26MZb98eBN9AhlvKfnL9XyQsGNiGPoll/9zK1il4B33Y+dfaqDwROtDbjCjqt3cS
-SEJcWOFSMZzAMS6FYQtP
-=qmAI
+iQIcBAABCAAGBQJYXa+yAAoJEFAslq9JXcLZrgQQAKdWxKp68ZBkqCoN1sni6sMH
+nEqwSQS9MXOsonwV625j0ngnfZ7TWOw4TYz7LKRjdjDsLOmMGcbALigeUfnD38sW
+Bh8Hb0hBOSlUN4mJw2B3/tbtTl+0HsqF+9QSpF2/YmDV+DQ/oph8SgelrSHn9A5O
+6+MRrtsmu0pMt8RpSC98iXzbQ7rLZlq7j145ek+VXd+K8zZ/UjXz+3HBVdm5hr2k
+hpD70wpuyFOzIl3Q6Ur4tWcTJCWuvOXiuNTeTA1s1fQizZG9nwNUypB5XXwgGm09
+49EOPpZnYslUAW9icUWpDKj2jDKj24BvvFBDsPzFKS5K9K8mODqwMI3ae7OYrE5Y
+9p2HtZS+FuVWhhumavavbTLHUJCaGM2HIou3mzG6HUuQDG/AcvnEyU+F/DCVYxjz
+42+rJyKvtw8BKgOhR6V8DqwV4m6uot4cDZVfM4092zkxvMtIQnRt6lyr3zuLOTzp
+kb/UFYoPfolav50c5sAkgAuagAnUBRB3bqbRLDOTy0nWyVZOLHP0y60vTjttC/Zg
+zycp0dKuLWKZMJnFNFqCN+uTCShxpdqvO/H23DrCBr65KSyL5eTIQly0CEGUR6Aj
+dwMR7Q29eM3HIodfwuV0UAN2wswBHlR2eMaLMIf8PAxpAzIF4S6B1gUqpcHtXe3H
+tdjCX9uHCWoLlvh35E7D
+=5k0H
-----END PGP SIGNATURE-----
Index: client/1.0/neutral/pkgIndex.tcl
==================================================================
--- client/1.0/neutral/pkgIndex.tcl
+++ client/1.0/neutral/pkgIndex.tcl
@@ -20,5 +20,8 @@
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]]
+
+package ifneeded Eagle.Package.Uploader 1.0 \
+ [list source [file join $dir pkgu.eagle]]
Index: client/1.0/neutral/pkgIndex.tcl.asc
==================================================================
--- client/1.0/neutral/pkgIndex.tcl.asc
+++ client/1.0/neutral/pkgIndex.tcl.asc
@@ -1,18 +1,18 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
Comment: Eagle Package Repository
-iQIcBAABCAAGBQJXt2XQAAoJEFAslq9JXcLZrdcP/joLk0SYgo+rOoLeqzvneJdS
-3m4wOn6Dr6xzfT3d9Hmh/U5GeAabG6nGXroqHlF6RCXDlw2MuzxjwyEYn1ZxXQpT
-++gzlxaBtJpo7D6j9CbWtghvDkFQyW+5ucruCFKH2rYr/U5akWiAHke4txFeXJMp
-C6zFY0paMD39f0Si/prqwK07MdxtiUCM5wNNs2/hl0sbckV4Blit+BhShi1H74My
-NPr4k0GmOSAo1QyYmBb6D0ciCkl6AmbCtj6KQuPXzkhPu0rh0eduxAjcImu70jSu
-peQ692PVYUV3vtHd5UVyZFKZeWGWUs27n4oIq/WNv60AocaS09QRikVNvf7kyHDy
-+zEXF+yjnFnSdpHplVyfwMQdLz9LCjlqUivYq35Ir6n/C9tMLfqiZChUhyHX9hmB
-rnyokRFh45mcF8gJLKC/4D/PKDDjBKyjHdbKLQrJ4bH3y7FSUzOvb3iI8K4/Omyt
-uS18QYYtlovub0Bkc26TCVqlsytuv9Zc3Y6P8YlrLV7+lxGQs3hhgK6X0xK4GU6h
-5aNE964elyYapPC3ToVEqvZaQsDM9vs1avW8SxcCvudixnzAycslcysv8JVaZXnG
-u6WPT/zxt65BF+gXOBm5qpeFEQIn34WZdTHqXMgmUslT+uJ7y3cRXIKWGkzkebHZ
-1PissA/AN1MgUYPp69ZV
-=BbsA
+iQIcBAABCAAGBQJYXa0BAAoJEFAslq9JXcLZf7IP/jEyWM0eE6W4O5kDEattRIVq
+1v1QWnRjtRAOxjh3tL4gL0fw12heD2GRvu8Bg878oVLafSiAaXV02cCGoPupA6R3
+cl+vYRJ8SiGkaUVD4SwP9oPo8ijGsHPhK3bZjUTPMia30lUhoVhEYbYYT4B64iHH
+Jlu6E6ZQoMHbnIYSSDjbUJo69d8xi/YEUuOT8T0wKY1K3NUsVGIdYTYUXXDMHb4N
+WhyFEvYnEWffdthgGOIK4LyOCI3sNEsRK9ptA0d7CqpqQSzQaSFAZqFVsgc5p6V0
+jXReoASO1WvGR3TcsN6azyBGI2xfZcg9I+li6Ass0edXcblUjlnhJJPZPfP8QDEy
++gWZSXFZbnrMuN7Xr09ZrwAmRf0FEbJhhLN82yY9P3jZbSk2lMftDNpD+HciOXvj
+mz+2p9h91uOhgtrYeZ0cxYoIop7O4OjmOzF0sGAHrVXQitQuxvmtFPRZo7T284nT
+rJmSG6VQYVkdxfcPIy9dgquvaaDehfYZeHxsaD2qGB8CZvEfHb3L+GQIuJHcgX1c
+LfmLRvt6Ba3L+WD6u/4wpqdPskdlZXSPcRG72x57En53Bhc7U2YrRgE2FFEH68LC
+QH453r++hjCbXZEP4lM5gAkpOtVChzpwCZSSA4P2GYUy+xVVexhIRjqOHxhTZGEk
+8JEP7cd7Rgegi5aY5dO5
+=ryeC
-----END PGP SIGNATURE-----
Index: client/1.0/neutral/pkgr_upload.eagle
==================================================================
--- client/1.0/neutral/pkgr_upload.eagle
+++ client/1.0/neutral/pkgr_upload.eagle
@@ -35,1620 +35,10 @@
\[language\] \[version\] \[platform\] \[fileName1\] ... \[fileNameN\]"
exit 1
}
- #
- # NOTE: This procedure sets up the default values for all configuration
- # parameters used by the package uploader client. There are no
- # arguments.
- #
- proc setupUploadVars {} {
- #
- # NOTE: This variable must exist and must be the fully qualified path
- # of the directory containing this script.
- #
- variable pkgr_path
-
- if {![info exists pkgr_path]} then {
- error "required namespace variable 'pkgr_path' does not exist"
- }
-
- #
- # NOTE: The project code for the Fossil repository. This will be checked
- # prior to staging or committing any files.
- #
- variable projectCode; # DEFAULT: 9ceada8dbb8678898e5b2c05386e73b3ff2c2dec
-
- if {![info exists projectCode]} then {
- set projectCode 9ceada8dbb8678898e5b2c05386e73b3ff2c2dec
- }
-
- #
- # NOTE: What is the fully qualified path to the directory containing
- # package client toolset?
- #
- variable scriptDirectory; # DEFAULT:
-
- if {![info exists scriptDirectory]} then {
- set scriptDirectory $pkgr_path
- }
-
- #
- # NOTE: The command to use when attempting to verify that Fossil is
- # available for use.
- #
- variable fossilVersionCommand; # DEFAULT: fossil version
-
- if {![info exists fossilVersionCommand]} then {
- set fossilVersionCommand {fossil version}
- }
-
- #
- # NOTE: The regular expression pattern used when attempting to verify
- # that Fossil is installed.
- #
- variable fossilVersionPattern; # DEFAULT: {^This is fossil version 1\.\d+ }
-
- if {![info exists fossilVersionPattern]} then {
- set fossilVersionPattern {^This is fossil version 1\.\d+ }
- }
-
- #
- # NOTE: The command to use when attempting to check for changes prior to
- # staging files using Fossil.
- #
- variable fossilChangesCommand; # DEFAULT: fossil changes ...
-
- if {![info exists fossilChangesCommand]} then {
- set fossilChangesCommand {fossil changes --chdir {${directory}}}
- }
-
- #
- # NOTE: The regular expression pattern used when attempting to verify
- # that the Fossil checkout has no changes staged. Generally, this
- # pattern should only match an empty string.
- #
- variable fossilChangesPattern; # DEFAULT: {^$}
-
- if {![info exists fossilChangesPattern]} then {
- set fossilChangesPattern {^$}
- }
-
- #
- # NOTE: The command to use when attempting to check the checkout status
- # prior to staging files using Fossil.
- #
- variable fossilInfoCommand; # DEFAULT: fossil info ...
-
- if {![info exists fossilInfoCommand]} then {
- set fossilInfoCommand {fossil info --chdir {${directory}}}
- }
-
- #
- # NOTE: The regular expression pattern used when attempting to extract
- # the root directory for the Fossil checkout.
- #
- variable fossilInfoLocalRootPattern; # DEFAULT: {^local-root:\s+(.*?)$}
-
- if {![info exists fossilInfoLocalRootPattern]} then {
- set fossilInfoLocalRootPattern {^local-root:\s+(.*?)$}
- }
-
- #
- # NOTE: The regular expression pattern used when attempting to verify
- # that the Fossil checkout belongs to the correct project.
- #
- variable fossilInfoProjectCodePattern; # DEFAULT: {^project-code:\\s+...\$}
-
- if {![info exists fossilInfoProjectCodePattern]} then {
- set fossilInfoProjectCodePattern [appendArgs \
- {^project-code:\\s+${projectCode}\$}]
- }
-
- #
- # NOTE: The regular expression pattern used when attempting to verify
- # that the Fossil checkout is sitting on the correct branch.
- #
- variable fossilInfoTagsPattern; # DEFAULT: {^tags:\s+trunk(?:,|$)}
-
- if {![info exists fossilInfoTagsPattern]} then {
- set fossilInfoTagsPattern {^tags:\s+trunk(?:,|$)}
- }
-
- #
- # NOTE: The command to use when attempting to reset the checkout to the
- # default branch prior to staging files using Fossil.
- #
- variable fossilUpdateCommand; # DEFAULT: fossil update trunk ...
-
- if {![info exists fossilUpdateCommand]} then {
- set fossilUpdateCommand \
- {fossil update trunk --chdir {${directory}}}
- }
-
- #
- # NOTE: The command to use when attempting to stage package files using
- # Fossil.
- #
- variable fossilAddCommand; # DEFAULT: fossil add ...
-
- if {![info exists fossilAddCommand]} then {
- set fossilAddCommand \
- {fossil add --chdir {${directory}} {${fileName}}}
- }
-
- #
- # NOTE: The command to use when attempting to commit package files using
- # Fossil.
- #
- variable fossilCommitCommand; # DEFAULT: fossil commit ...
-
- if {![info exists fossilCommitCommand]} then {
- set fossilCommitCommand {fossil commit -m {${comment}}\
- --branch {${branch}} --user anonymous --chdir \
- {${directory}} --no-prompt}
- }
-
- #
- # NOTE: The regular expression pattern used when attempting to verify
- # that Fossil committed a set of files.
- #
- variable fossilCommitPattern; # DEFAULT: {^New_Version: ([0-9a-f]{40})$}
-
- if {![info exists fossilCommitPattern]} then {
- set fossilCommitPattern {^New_Version: ([0-9a-f]{40})$}
- }
-
- #
- # NOTE: Emit diagnostic messages when a new package is submitted?
- #
- variable verboseMetadataSubmit; # DEFAULT: false
-
- if {![info exists verboseMetadataSubmit]} then {
- set verboseMetadataSubmit false
- }
- }
-
- #
- # NOTE: This procedure sets up the default values for all configuration
- # parameters used by the package uploader client that require the
- # location of the checkout directory. There are no arguments.
- #
- proc setupCheckoutVars {} {
- #
- # NOTE: What is the fully qualified path to the root directory of the
- # Fossil checkout containing the package client toolset? This
- # procedure may raise script errors.
- #
- variable checkoutDirectory; # DEFAULT:
-
- if {![info exists checkoutDirectory]} then {
- set checkoutDirectory [getCheckoutDirectory]
- }
- }
-
- #
- # NOTE: This procedure returns a string value, formatted for use within a
- # script block being processed by the [string map] command. The
- # value argument is the string value to format. No return value is
- # reserved to indicate an error. This procedure may not raise any
- # script errors.
- #
- proc formatStringMapValue { value } {
- if {[string length $value] == 0} then {
- return \"\"
- }
-
- set list [list $value]
-
- if {$value eq $list} then {
- return $value
- } else {
- return $list
- }
- }
-
- #
- # NOTE: This procedure counts the common path components for two paths. The
- # count is returned, zero if there are no common path components. The
- # path1 and path2 arguments are the paths to compare. This procedure
- # may not raise script errors.
- #
- proc countCommonPathParts { path1 path2 } {
- set parts1 [file split $path1]
- set length1 [llength $parts1]
-
- set parts2 [file split $path2]
- set length2 [llength $parts2]
-
- set length [expr {min($length1, $length2)}]
-
- for {set index 0} {$index < $length} {incr index} {
- set part1 [lindex $parts1 $index]
- set part2 [lindex $parts2 $index]
-
- if {$part1 ne $part2} then {
- return $index
- }
- }
-
- return $length
- }
-
- #
- # NOTE: This procedure processes a list of (fully?) qualified file names and
- # tries to determine their common containing directory, if any. The
- # fileNames argument is the list of (fully?) qualified file names to
- # process. This procedure may not raise script errors. If there is
- # no common containing directory, an empty string is returned.
- #
- proc getCommonContainingDirectory { fileNames } {
- set length [llength $fileNames]
-
- if {$length == 0} then {
- return ""
- }
-
- set oldFileName [lindex $fileNames 0]
-
- if {$length == 1} then {
- return [file dirname $oldFileName]
- }
-
- set minimumCount 0
-
- for {set index 1} {$index < $length} {incr index} {
- set newFileName [lindex $fileNames $index]
- set newCount [countCommonPathParts $oldFileName $newFileName]
-
- if {$newCount == 0} then {
- return ""
- }
-
- if {$minimumCount == 0 || $newCount < $minimumCount} then {
- set oldFileName $newFileName
- set minimumCount $newCount
- }
- }
-
- if {$minimumCount == 0} then {
- return ""
- }
-
- incr minimumCount -1
-
- return [eval file join [lrange [file split $oldFileName] 0 $minimumCount]]
- }
-
- #
- # NOTE: This procedure attempts to process a list of (fully?) qualified file
- # names and return the corresponding list of relative file names. The
- # fileNames argument is the list of (fully?) qualified file names to
- # process. The maximumLevels argument is the maximum path depth that
- # is allowed for all file names. This procedure may raise script
- # errors.
- #
- proc getRelativeFileNames { fileNames maximumLevels } {
- set directory [getCommonContainingDirectory $fileNames]
- set directoryParts [file split $directory]
- set fileNameIndex [expr {[llength $directoryParts] - 1}]
-
- if {$fileNameIndex < 0} then {
- error [appendArgs \
- "invalid containing directory \"" $directory \
- "\": cannot go up one level"]
- }
-
- set relativeFileNames [list]
-
- foreach fileName $fileNames {
- set fileNameParts [lrange \
- [file split $fileName] $fileNameIndex end]
-
- if {$maximumLevels > 0 && \
- [llength $fileNameParts] > $maximumLevels} then {
- error [appendArgs \
- "depth for file name \"" $fileName \
- "\" exceeds maximum (" $maximumLevels )]
- }
-
- set relativeFileName [eval file join $fileNameParts]
-
- if {[string length $relativeFileName] == 0 || \
- [file pathtype $relativeFileName] ne "relative"} then {
- error [appendArgs \
- "bad file name \"" $relativeFileName "\", not relative"]
- }
-
- lappend relativeFileNames $relativeFileName
- }
-
- return $relativeFileNames
- }
-
- #
- # NOTE: This procedure attempts to create a script chunk that appends the
- # specified list of file names to a list variable. The fileNames
- # argument is the list of (fully?) qualified file names to append to
- # the list variable. The maximumLevels argument is the maximum path
- # depth that is allowed for all file names. This procedure may raise
- # script errors.
- #
- proc getScriptChunkForFileNames { fileNames maximumLevels } {
- set result ""
- set relativeFileNames [getRelativeFileNames $fileNames $maximumLevels]
-
- foreach relativeFileName $relativeFileNames {
- if {[string length $result] > 0} then {
- append result \n
- }
-
- append result { lappend fileNames [file join }
- append result [file split $relativeFileName]
- append result \]
- }
-
- return $result
- }
-
- #
- # NOTE: This procedure creates and returns a script block designed for use
- # with the package repository server in order to download and provide
- # a package consisting of a set of files. The serverId argument is
- # the identifier for the specific server to use, if any. The
- # versionId argument is the identifier for the specific version to use,
- # if any. The language argument must be the literal string "eagle" or
- # the literal string "tcl". The version argument must be one of the
- # literal strings "8.4", "8.5", or "8.6" when the language is "tcl"
- # -OR- the literal string "1.0" when the language is "eagle". The
- # platform argument must be an empty string -OR- one of the literal
- # strings "neutral", "win32-arm", "win32-x86", "win64-arm64",
- # "win64-ia64", or "win64-x64". The fileNames argument is the list of
- # (fully?) qualified file names to be downloaded when the associated
- # package is being provided. The options argument is reserved for
- # future use, it should be an empty list.
- #
- #
- proc createRepositoryScript {
- serverId versionId language version platform fileNames options } {
- ::PackageDownloader::verifyServerId $serverId
- ::PackageDownloader::verifyVersionId $versionId
- ::PackageDownloader::verifyLanguageAndVersion $language $version isClient
-
- set prologue ""
-
- if {[string length $serverId] > 0} then {
- append prologue " ::PackageDownloader::useServerId " $serverId \n
- }
-
- if {[string length $versionId] > 0} then {
- append prologue " ::PackageDownloader::useVersionId " $versionId \n
- }
-
- append prologue " "
-
- return [string trim [string map [list \r\n \n \
- %language% [formatStringMapValue $language] \
- %version% [formatStringMapValue $version] \
- %platform% [formatStringMapValue $platform] \
- %prologue% $prologue %ns% ::PackageDownloader \
- %backslash% \\ %fileNames% \
- [getScriptChunkForFileNames $fileNames 2]] {
-apply [list [list] {
- package require Eagle.Package.Downloader
-
-%prologue%%ns%::resetCookieAndLoginSimple
-
- set fileNames [list]
-
-%fileNames%
-
- set options [list %backslash%
- -persistent false -usePgp true -useAutoPath true]
-
- %ns%::downloadFiles %language% %version% %platform% $fileNames $options
- %ns%::logoutAndResetCookie
-}]
- }]]
- }
-
- #
- # NOTE: This procedure creates textual data that conforms to the content
- # type "multipart/form-data", per RFC 2388. The boundary argument
- # is a boundary value, as specified in section 4.1 of the RFC. The
- # request argument is the dictionary of name/value pairs to include
- # in the form body. This procedure may not raise script errors.
- #
- proc createMultipartFormData { boundary request } {
- set result ""
-
- foreach {name value} $request {
- append result -- $boundary \r\n
- append result "Content-Disposition: form-data; name=\""
- append result $name \"\r\n\r\n
- append result $value \r\n
- }
-
- if {[string length $result] > 0} then {
- append result -- $boundary --\r\n
- }
-
- if {[isEagle]} then {
- return [object create -alias String $result]
- } else {
- return $result
- }
- }
-
- #
- # NOTE: This procedure returns the full URI to use when submitting a new
- # package to the package repository server. There are no arguments.
- # This procedure may raise script errors.
- #
- proc getSubmitUri {} {
- #
- # NOTE: Fetch the base URI for the package repository server. If it
- # is not available for some reason, just return an empty string
- # to the caller (i.e. as we cannot do anything productive).
- #
- set baseUri [::PackageRepository::getLookupBaseUri]
-
- if {[string length $baseUri] == 0} then {
- return ""
- }
-
- #
- # NOTE: Build the HTTP request URI and include the standard query
- # parameters (with constant values) for this request type.
- #
- if {[isEagle]} then {
- return [appendArgs \
- $baseUri ?raw=1&method=submit]
- } else {
- package require http 2.0
-
- return [appendArgs \
- $baseUri ? [::http::formatQuery raw 1 method submit]]
- }
- }
-
- #
- # NOTE: This procedure attempts to submit the metadata for a new package to
- # the package repository server. Upon success, an empty string will
- # be returned. Upon failure, a script error will be raised. The
- # apiKey argument is the list of API keys to use. The package argument
- # is the name of the package. The patchLevel argument is the specific
- # patch level being submitted. The language argument must be an empty
- # string, "Tcl", or "Eagle". If it is an empty string, the current
- # language will be assumed. The script argument is the script to be
- # evaluated when the package needs to be provided. The certificate
- # argument is the certificate associated with the script, which may be
- # an OpenPGP signature or a Harpy script certificate.
- #
- #
- proc submitPackageMetadata {
- apiKey package patchLevel language script certificate } {
- variable verboseMetadataSubmit
-
- #
- # NOTE: Fetch the submission URI for the package repository server. If
- # it is not available for some reason, raise a script error.
- #
- set uri [getSubmitUri]
-
- if {[string length $uri] == 0} then {
- error ""
- }
-
- if {[string length $language] == 0} then {
- set language [expr {[isEagle] ? "Eagle" : "Tcl"}]
- }
-
- if {[isEagle]} then {
- set boundary [string map \
- [list + "" / "" = ""] [base64 encode [expr {randstr(50)}]]]
- } else {
- set boundary [::PackageRepository::getUniqueSuffix]
- }
-
- set contentType [appendArgs \
- "multipart/form-data; boundary=" $boundary]
-
- set formData [createMultipartFormData $boundary \
- [list apiKey $apiKey package $package patchLevel \
- $patchLevel language $language script $script \
- certificate $certificate]]
-
- if {[isEagle]} then {
- if {![object invoke Eagle._Tests.Default \
- TestHasScriptNewWebClientCallback ""]} then {
- set error null
-
- set code [object invoke Eagle._Tests.Default \
- TestSetScriptNewWebClientCallback "" true true error]
-
- if {$code ne "Ok"} then {
- error [getStringFromObjectHandle $error]
- }
- }
-
- set script [object create String {
- if {[methodName ToString] eq "GetWebRequest"} then {
- webRequest ContentType $contentType
- }
- }]
-
- set data [uri upload \
- -inline -raw -encoding identity -webclientdata \
- $script -data $formData $uri]
- } else {
- set options [list \
- -binary true -type $contentType -query $formData]
-
- set data [eval ::PackageRepository::getFileViaHttp \
- [list $uri] [list 20] [list stdout] [list \
- [expr {!$verboseMetadataSubmit}]] $options]
- }
-
- set code [::PackageRepository::getLookupCodeFromData $data]
- set result [::PackageRepository::getLookupResultFromData $data]
-
- if {[::PackageRepository::isLookupCodeOk $code]} then {
- return $result
- } else {
- error [appendArgs \
- "failed to submit package metadata: " $data]
- }
- }
-
- #
- # NOTE: This procedure attempts to query the root directory of the Fossil
- # checkout. There are no arguments. An empty string is returned if
- # the root directory of the Fossil checkout cannot be determined.
- #
- proc getCheckoutDirectory {} {
- variable fossilInfoCommand
- variable fossilInfoLocalRootPattern
- variable scriptDirectory
-
- fossilMustBeInstalled
-
- if {[isEagle]} then {
- set directory [::PackageRepository::formatExecArgument \
- $scriptDirectory]
-
- if {[catch {
- eval exec -nocarriagereturns -stdout output -stderr error \
- [subst $fossilInfoCommand]
- } result] == 0} then {
- set result [appendArgs $output $error]
- } else {
- return false
- }
- } else {
- set directory $scriptDirectory
-
- if {[catch {
- eval exec [subst $fossilInfoCommand]
- } result]} then {
- return false
- }
- }
-
- if {![info exists result] || ![regexp -line -- \
- $fossilInfoLocalRootPattern $result dummy directory]} then {
- return ""
- }
-
- return [string trim $directory]
- }
-
- #
- # NOTE: This procedure attempts to verify that the root directory of the
- # Fossil checkout is present, valid, and is actually a directory.
- # There are no arguments. Script errors will be raised if any of
- # the checks fail.
- #
- proc verifyCheckoutDirectory {} {
- variable checkoutDirectory
-
- if {![info exists checkoutDirectory]} then {
- error "checkout directory is missing"
- }
-
- if {[string length $checkoutDirectory] == 0} then {
- error "checkout directory is invalid"
- }
-
- if {![file isdir $checkoutDirectory]} then {
- error [appendArgs \
- "checkout directory \"" $checkoutDirectory \
- "\" is not really a directory"]
- }
- }
-
- #
- # NOTE: This procedure attempts to verify that an implementation of Fossil
- # is installed locally. There are no arguments. Script errors are
- # raised if any problems are found. The return value is undefined.
- #
- proc fossilMustBeInstalled {} {
- variable fossilVersionCommand
- variable fossilVersionPattern
-
- if {[isEagle]} then {
- if {[catch {
- eval exec -nocarriagereturns -stdout output -stderr error \
- $fossilVersionCommand
- } result] == 0} then {
- set result [appendArgs $output $error]
- } else {
- error "cannot use Fossil: may not be installed and/or configured"
- }
- } else {
- if {[catch {
- eval exec $fossilVersionCommand
- } result]} then {
- error "cannot use Fossil: may not be installed and/or configured"
- }
- }
-
- if {![info exists result] || \
- ![regexp -- $fossilVersionPattern $result]} then {
- error "cannot use Fossil: unknown or unsupported version"
- }
- }
-
- #
- # NOTE: This procedure attempts to verify that the checkout directory does
- # not contain any (stray) changes. There are no arguments. Non-zero
- # is returned if the verification is successful.
- #
- proc verifyThereAreNoChanges {} {
- variable checkoutDirectory
- variable fossilChangesCommand
- variable fossilChangesPattern
-
- fossilMustBeInstalled
- verifyCheckoutDirectory
-
- if {[isEagle]} then {
- set directory [::PackageRepository::formatExecArgument \
- $checkoutDirectory]
-
- if {[catch {
- eval exec -nocarriagereturns -stdout output -stderr error \
- [subst $fossilChangesCommand]
- } result] == 0} then {
- set result [appendArgs $output $error]
- } else {
- return false
- }
- } else {
- set directory $checkoutDirectory
-
- if {[catch {
- eval exec [subst $fossilChangesCommand]
- } result]} then {
- return false
- }
- }
-
- if {![info exists result] || \
- ![regexp -- $fossilChangesPattern $result]} then {
- return false
- }
-
- return true
- }
-
- #
- # NOTE: This procedure attempts to verify that the checkout directory does
- # belong to the correct project. There are no arguments. Non-zero
- # is returned if the verification is successful.
- #
- proc verifyThisIsTheCorrectProject {} {
- variable fossilInfoCommand
- variable fossilInfoProjectCodePattern
- variable projectCode
- variable scriptDirectory
-
- fossilMustBeInstalled
-
- if {[isEagle]} then {
- set directory [::PackageRepository::formatExecArgument \
- $scriptDirectory]
-
- if {[catch {
- eval exec -nocarriagereturns -stdout output -stderr error \
- [subst $fossilInfoCommand]
- } result] == 0} then {
- set result [appendArgs $output $error]
- } else {
- return false
- }
- } else {
- set directory $scriptDirectory
-
- if {[catch {
- eval exec [subst $fossilInfoCommand]
- } result]} then {
- return false
- }
- }
-
- if {![info exists result] || ![regexp -line -- \
- [subst $fossilInfoProjectCodePattern] $result]} then {
- return false
- }
-
- return true
- }
-
- #
- # NOTE: This procedure attempts to verify that the checkout directory does
- # belong to the correct branch. There are no arguments. Non-zero
- # is returned if the verification is successful.
- #
- proc verifyThisIsTheCorrectBranch {} {
- variable fossilInfoCommand
- variable fossilInfoTagsPattern
- variable scriptDirectory
-
- fossilMustBeInstalled
-
- if {[isEagle]} then {
- set directory [::PackageRepository::formatExecArgument \
- $scriptDirectory]
-
- if {[catch {
- eval exec -nocarriagereturns -stdout output -stderr error \
- [subst $fossilInfoCommand]
- } result] == 0} then {
- set result [appendArgs $output $error]
- } else {
- return false
- }
- } else {
- set directory $scriptDirectory
-
- if {[catch {
- eval exec [subst $fossilInfoCommand]
- } result]} then {
- return false
- }
- }
-
- if {![info exists result] || \
- ![regexp -line -- $fossilInfoTagsPattern $result]} then {
- return false
- }
-
- return true
- }
-
- #
- # NOTE: This procedure attempts to change the branch for the checkout
- # directory. There are no arguments. This procedure may raise
- # script errors.
- #
- proc changeToTheCorrectBranch {} {
- variable checkoutDirectory
- variable fossilUpdateCommand
-
- fossilMustBeInstalled
- verifyCheckoutDirectory
-
- if {[isEagle]} then {
- set directory [::PackageRepository::formatExecArgument \
- $checkoutDirectory]
-
- if {[catch {
- eval exec -success Success [subst $fossilUpdateCommand]
- } error]} then {
- error [appendArgs \
- "could not change branch: " $error]
- }
- } else {
- set directory $checkoutDirectory
-
- if {[catch {
- eval exec [subst $fossilUpdateCommand]
- } error]} then {
- error [appendArgs \
- "could not change branch: " $error]
- }
- }
- }
-
- #
- # NOTE: This procedure attempts to stage the specified package file using
- # Fossil. The targetDirectory argument is the fully qualified path
- # to the package platform directory. The fileName argument is the
- # relative name of the file to be staged. This procedure may raise
- # script errors.
- #
- proc stageOnePackageFile { targetDirectory fileName } {
- variable fossilAddCommand
-
- fossilMustBeInstalled
-
- if {[isEagle]} then {
- set directory [::PackageRepository::formatExecArgument \
- $targetDirectory]
-
- set fileName [::PackageRepository::formatExecArgument $fileName]
-
- if {[catch {
- eval exec -success Success [subst $fossilAddCommand]
- } error]} then {
- error [appendArgs \
- "could not stage file \"" $fileName "\": " $error]
- }
- } else {
- set directory $targetDirectory
-
- if {[catch {
- eval exec [subst $fossilAddCommand]
- } error]} then {
- error [appendArgs \
- "could not stage file \"" $fileName "\": " $error]
- }
- }
- }
-
- #
- # NOTE: This procedure attempts to stage the specified package files using
- # Fossil. The fileNames argument is a list of (fully?) qualified
- # local file names to stage.
- #
- #
- proc stagePackageFiles { language version platform fileNames } {
- variable checkoutDirectory
- variable fossilAddCommand
-
- verifyCheckoutDirectory
-
- if {![verifyThereAreNoChanges]} then {
- error "cannot stage files: there are pending changes"
- }
-
- if {![verifyThisIsTheCorrectProject]} then {
- error "cannot stage files: wrong project"
- }
-
- if {![verifyThisIsTheCorrectBranch]} then {
- changeToTheCorrectBranch
-
- if {![verifyThisIsTheCorrectBranch]} then {
- error "cannot stage files: still on wrong branch"
- }
- }
-
- set targetDirectory [file join \
- $checkoutDirectory $language $version $platform]
-
- set relativeFileNames [getRelativeFileNames $fileNames 2]
-
- foreach fileName $fileNames relativeFileName $relativeFileNames {
- file mkdir [file join \
- $targetDirectory [file dirname $relativeFileName]]
-
- set checkoutFileName [file join $targetDirectory $relativeFileName]
-
- file copy $fileName $checkoutFileName
-
- if {![::PackageRepository::createOpenPgpSignature \
- $checkoutFileName]} then {
- error [appendArgs \
- "could not stage file \"" $fileName \
- "\": OpenPGP signing failed"]
- }
-
- stageOnePackageFile $targetDirectory $relativeFileName
- stageOnePackageFile $targetDirectory [appendArgs $relativeFileName .asc]
- }
- }
-
- #
- # NOTE: This procedure attempts to commit the staged package files to the
- # remote package file repository using Fossil. The varName argument
- # is the name of a scalar variable in the context of the immediate
- # caller that will receive the resulting Fossil check-in identifier.
- #
- #
- proc commitPackageFiles { package patchLevel language version varName } {
- variable checkoutDirectory
- variable fossilCommitCommand
- variable fossilCommitPattern
-
- fossilMustBeInstalled
- verifyCheckoutDirectory
-
- set branch [appendArgs pkg_ $package _ $patchLevel]
-
- set comment [appendArgs \
- "Add package " $package " v" $patchLevel " for " $language \
- " v" $version .]
-
- if {[isEagle]} then {
- set directory [::PackageRepository::formatExecArgument \
- $checkoutDirectory]
-
- set branch [::PackageRepository::formatExecArgument $branch]
- set comment [::PackageRepository::formatExecArgument $comment]
-
- if {[catch {
- eval exec -nocarriagereturns -stdout output -stderr error \
- [subst $fossilCommitCommand]
- } result] == 0} then {
- set result [appendArgs $output $error]
- } else {
- return false
- }
- } else {
- set directory $checkoutDirectory
-
- if {[catch {
- eval exec [subst $fossilCommitCommand]
- } result]} then {
- return false
- }
- }
-
- if {[string length $varName] > 0} then {
- upvar 1 $varName checkin
- }
-
- if {![info exists result] || \
- ![regexp -line -- $fossilCommitPattern $result dummy checkin]} then {
- return false
- }
-
- return true
- }
-
- #
- # NOTE: This procedure initializes the array containing data derived from
- # the command line arguments, if any. The argv argument should be
- # the list of command line arguments.
- #
- proc setupArgumentData { argv } {
- variable argumentData
-
- if {![info exists argumentData(apiKey)]} then {
- set argumentData(apiKey) ""
- }
-
- if {![info exists argumentData(package)]} then {
- set argumentData(package) ""
- }
-
- if {![info exists argumentData(patchLevel)]} then {
- set argumentData(patchLevel) ""
- }
-
- if {![info exists argumentData(language)]} then {
- set argumentData(language) ""
- }
-
- if {![info exists argumentData(version)]} then {
- set argumentData(version) ""
- }
-
- if {![info exists argumentData(platform)]} then {
- set argumentData(platform) ""
- }
-
- if {![info exists argumentData(fileNames)]} then {
- set argumentData(fileNames) [list]
- }
-
- if {[llength $argv] >= 1} then {
- set argumentData(apiKey) [lindex $argv 0]
- }
-
- if {[llength $argv] >= 2} then {
- set argumentData(package) [lindex $argv 1]
- }
-
- if {[llength $argv] >= 3} then {
- set argumentData(patchLevel) [lindex $argv 2]
- }
-
- if {[llength $argv] >= 4} then {
- set argumentData(language) [lindex $argv 3]
- }
-
- if {[llength $argv] >= 5} then {
- set argumentData(version) [lindex $argv 4]
- }
-
- if {[llength $argv] >= 6} then {
- set argumentData(platform) [lindex $argv 5]
- }
-
- if {[llength $argv] >= 7} then {
- set argumentData(fileNames) [lrange $argv 6 end]
- }
- }
-
- #
- # NOTE: This procedure is used to determine if all the package submission
- # data is available. There are no arguments. Non-zero is returned
- # if all the package submission data is available. This procedure
- # should not raise script errors.
- #
- proc haveArgumentData {} {
- variable argumentData
-
- if {![info exists argumentData(apiKey)]} then {
- return false
- }
-
- if {[string length $argumentData(apiKey)] == 0} then {
- return false
- }
-
- if {![info exists argumentData(package)]} then {
- return false
- }
-
- if {[string length $argumentData(package)] == 0} then {
- return false
- }
-
- if {![info exists argumentData(patchLevel)]} then {
- return false
- }
-
- if {[string length $argumentData(patchLevel)] == 0} then {
- return false
- }
-
- if {![info exists argumentData(language)]} then {
- return false
- }
-
- if {[string length $argumentData(language)] == 0} then {
- return false
- }
-
- if {![info exists argumentData(version)]} then {
- return false
- }
-
- if {[string length $argumentData(version)] == 0} then {
- return false
- }
-
- if {![info exists argumentData(platform)]} then {
- return false
- }
-
- if {[string length $argumentData(platform)] == 0} then {
- return false
- }
-
- if {![info exists argumentData(fileNames)]} then {
- return false
- }
-
- if {[llength $argumentData(fileNames)] == 0} then {
- return false
- }
-
- return true
- }
-
- #
- # NOTE: This procedure is an event handler. It handles the Changed event
- # for a text box. It is not used when the user interface was built
- # with Tk. The varName argument is the name of the scalar variable
- # that must be updated with the contents of the text box. The sender
- # and e arguments are provided by the framework and represent the
- # control involved in the event and any extra data that may be
- # necessary to process the event.
- #
- proc textBoxEventHandler { varName sender e } {
- set $varName [$sender Text]
- }
-
- #
- # NOTE: This procedure is an event handler. It handles double-clicking the
- # list box in both Tk and Eagle. The varName argument is the name of
- # the scalar variable that must be updated with the list of items from
- # the list box -OR- the list of items from an interactive file picker
- # dialog. The args argument, which is only used for Eagle, is a list
- # containing two elements. The first element is the control involved
- # in the event. The second element is any extra data that may be
- # necessary to process the event.
- #
- proc listBoxEventHandler { varName args } {
- if {[isEagle]} then {
- set sender [lindex $args 0]
- set e [lindex $args 1]
-
- set dialog [object create -alias OpenFileDialog]
-
- $dialog RestoreDirectory true
- $dialog Multiselect true
- $dialog ShowDialog
-
- set fileNames [$dialog -create FileNames]
-
- $sender Items.Clear
- $sender Items.AddRange $fileNames
-
- set list [object create -alias StringList $fileNames]
- set $varName [$list ToString]
- } else {
- set $varName [tk_getOpenFile -multiple true]
- }
- }
-
- #
- # NOTE: This procedure is an event handler. It handles the Closed event for
- # a WinForms form. It is not used when the user interface was built
- # with Tk. The sender and e arguments are provided by the framework
- # and represent the control involved in the event and any extra data
- # that may be necessary to process the event.
- #
- proc handleFormClosedEvent { sender e } {
- variable forever; set forever 1; # NOTE: Terminate the [vwait].
- }
-
- #
- # NOTE: This procedure is an event handler. It handles the submit button in
- # both Tk and Eagle. It starts the package submission process. The
- # args argument is not really used, it is a placeholder to make this
- # procedure more portable between Tcl and Eagle. This procedure may
- # raise script errors.
- #
- proc submitEventHandler { args } {
- variable argumentData
-
- set batchMode [lindex $args 0]
-
- if {[isEagle]} then {
- set sender [lindex $args 1]; # NOTE: Disposal.
- set e [lindex $args 2]; # NOTE: Disposal.
- }
-
- if {[haveArgumentData]} then {
- set apiKey $argumentData(apiKey)
- set package $argumentData(package)
- set patchLevel $argumentData(patchLevel)
- set language $argumentData(language)
- set version $argumentData(version)
- set platform $argumentData(platform)
- set fileNames $argumentData(fileNames)
-
- ::PackageRepository::probeForOpenPgpInstallation
- ::PackageRepository::openPgpMustBeInstalled
-
- if {1} then {
- stagePackageFiles \
- [string tolower $language] $version $platform $fileNames
-
- if {![commitPackageFiles \
- $package $patchLevel [string totitle $language] $version \
- checkin]} then {
- error "failed to commit package files"
- }
-
- #
- # TODO: Is this the best heuristic here for figuring out that the
- # platform should really be "automatic" in the repository?
- #
- if {$platform eq "neutral" || \
- $platform eq [::PackageDownloader::getPlatform]} then {
- set scriptPlatform ""
- } else {
- set scriptPlatform $platform
- }
-
- set script [createRepositoryScript \
- "" $checkin [string tolower $language] $version $scriptPlatform \
- $fileNames [list]]
-
- set scriptFileName [file join \
- [::PackageRepository::getFileTempDirectory PKGR_UPLOAD_TEMP] \
- [appendArgs pkgr_upload_ [::PackageRepository::getUniqueSuffix]]]
-
- writeFile $scriptFileName $script
-
- if {![::PackageRepository::createOpenPgpSignature \
- $scriptFileName]} then {
- error [appendArgs \
- "cannot submit package metadata: OpenPGP signing of \"" \
- $scriptFileName "\" failed"]
- }
-
- set certificate [readFile [appendArgs $scriptFileName .asc]]
-
- set result [submitPackageMetadata \
- $apiKey $package $patchLevel [string totitle $language] \
- $script $certificate]
-
- if {!$batchMode} then {
- set title [appendArgs \
- "Package Uploader Client: " [lindex [info level 0] 0]]
-
- if {[string length $result] > 0} then {
- set message [appendArgs \
- "Package was submitted successfully: " $result]
- } else {
- set message "Package was submitted successfully."
- }
-
- if {[isEagle]} then {
- catch {
- object invoke MessageBox Show $message $title
- }
- } else {
- catch {
- tk_messageBox -type ok -message $message -title $title
- }
- }
- }
- }
- } else {
- error "cannot initiate package submission: one or more fields missing"
- }
- }
-
- #
- # NOTE: This procedure is an event handler. It handles the clear button in
- # Tk and Eagle. It is used to clear the package submission data. The
- # args argument is not really used, it is a placeholder to make this
- # procedure more portable between Tcl and Eagle. This procedure may
- # raise script errors.
- #
- proc clearEventHandler { args } {
- variable argumentData
-
- if {[isEagle]} then {
- set sender [lindex $args 0]; # NOTE: Disposal.
- set e [lindex $args 1]; # NOTE: Disposal.
-
- variable widgets
-
- $widgets(2) Text ""
- $widgets(4) Text ""
- $widgets(6) Text ""
- $widgets(8) Text ""
- $widgets(10) Text ""
- $widgets(12) Text ""
- $widgets(14) Items.Clear
- } else {
- set argumentData(apiKey) ""
- set argumentData(package) ""
- set argumentData(patchLevel) ""
- set argumentData(language) ""
- set argumentData(version) ""
- set argumentData(platform) ""
- }
-
- #
- # NOTE: This is done for Tk because it will also clear the on-screen
- # widget itself. For Eagle, this is necessary because there is
- # no "listvariable" option and clearing the on-screen widget has
- # no impact on the underyling list.
- #
- set argumentData(fileNames) [list]
- }
-
- #
- # NOTE: This procedure creates the user interface for this tool using Eagle
- # and WinForms. The existing argument data, if any, will be used to
- # populate it. There are no arguments.
- #
- proc setupWinFormsUserInterface {} {
- variable argumentData
- variable widgets
-
- object load -import System.Windows.Forms
-
- set form [object create -alias Form]
- set widgets(0) $form
-
- $form Text "Package Uploader Client"
-
- ###########################################################################
-
- set widgets(1) [object create -alias Label]
- $widgets(1) Name lblApiKey
- $widgets(1) Text "API Key"
-
- ###########################################################################
-
- set widgets(2) [object create -alias TextBox]
-
- $widgets(2) Name txtApiKey
- $widgets(2) Text $argumentData(apiKey)
-
- $widgets(2) add_TextChanged [namespace code \
- [list textBoxEventHandler [appendArgs [namespace current] \
- ::argumentData(apiKey)]]]
-
- ###########################################################################
-
- set widgets(3) [object create -alias Label]
- $widgets(3) Name lblPackage
- $widgets(3) Text "Package Name"
-
- ###########################################################################
-
- set widgets(4) [object create -alias TextBox]
-
- $widgets(4) Name txtPackage
- $widgets(4) Text $argumentData(package)
-
- $widgets(4) add_TextChanged [namespace code \
- [list textBoxEventHandler [appendArgs [namespace current] \
- ::argumentData(package)]]]
-
- ###########################################################################
-
- set widgets(5) [object create -alias Label]
- $widgets(5) Name lblPatchLevel
- $widgets(5) Text "Package Patch Level"
-
- ###########################################################################
-
- set widgets(6) [object create -alias TextBox]
-
- $widgets(6) Name txtPatchLevel
- $widgets(6) Text $argumentData(patchLevel)
-
- $widgets(6) add_TextChanged [namespace code \
- [list textBoxEventHandler [appendArgs [namespace current] \
- ::argumentData(patchLevel)]]]
-
- ###########################################################################
-
- set widgets(7) [object create -alias Label]
- $widgets(7) Name lblLanguage
- $widgets(7) Text Language
-
- ###########################################################################
-
- set widgets(8) [object create -alias TextBox]
-
- $widgets(8) Name txtLanguage
- $widgets(8) Text $argumentData(language)
-
- $widgets(8) add_TextChanged [namespace code \
- [list textBoxEventHandler [appendArgs [namespace current] \
- ::argumentData(language)]]]
-
- ###########################################################################
-
- set widgets(9) [object create -alias Label]
- $widgets(9) Name lblVersion
- $widgets(9) Text Version
-
- ###########################################################################
-
- set widgets(10) [object create -alias TextBox]
-
- $widgets(10) Name txtVersion
- $widgets(10) Text $argumentData(version)
-
- $widgets(10) add_TextChanged [namespace code \
- [list textBoxEventHandler [appendArgs [namespace current] \
- ::argumentData(version)]]]
-
- ###########################################################################
-
- set widgets(11) [object create -alias Label]
- $widgets(11) Name lblPlatform
- $widgets(11) Text Platform
-
- ###########################################################################
-
- set widgets(12) [object create -alias TextBox]
-
- $widgets(12) Name txtPlatform
- $widgets(12) Text $argumentData(platform)
-
- $widgets(12) add_TextChanged [namespace code \
- [list textBoxEventHandler [appendArgs [namespace current] \
- ::argumentData(platform)]]]
-
- ###########################################################################
-
- set widgets(13) [object create -alias Label]
- $widgets(13) Name lblFileNames
- $widgets(13) Text Files
-
- ###########################################################################
-
- set widgets(14) [object create -alias ListBox]
- $widgets(14) Name lstFileNames
-
- $widgets(14) add_DoubleClick [namespace code \
- [list listBoxEventHandler [appendArgs [namespace current] \
- ::argumentData(fileNames)]]]
-
- ###########################################################################
-
- set widgets(15) [object create -alias Button]
- $widgets(15) Name btnSubmit
- $widgets(15) Text Submit
- $widgets(15) add_Click [namespace code [list submitEventHandler false]]
-
- ###########################################################################
-
- set widgets(16) [object create -alias Button]
- $widgets(16) Name btnClear
- $widgets(16) Text Clear
- $widgets(16) add_Click [namespace code [list clearEventHandler]]
-
- ###########################################################################
-
- set horizontalMargin \
- [expr {([$form Width] - [$form ClientSize.Width]) / 2}]
-
- set verticalMargin \
- [expr {([$form Height] - [$form ClientSize.Height]) / 2}]
-
- ###########################################################################
-
- set top $verticalMargin
-
- foreach name [lsort -integer [array names widgets]] {
- if {$name eq "0"} then continue
-
- $widgets($name) Width [expr {
- [$form ClientSize.Width] - ($horizontalMargin * 2)
- }]
-
- $widgets($name) Left $horizontalMargin
- $widgets($name) Top $top
- $form Controls.Add $widgets($name)
-
- incr top [$widgets($name) Height]
- incr top $verticalMargin
- }
-
- $form add_Closed [namespace code [list handleFormClosedEvent]]
- $form MaximizeBox false
- $form AutoSize true
- $form Show
-
- after 0 [list nop]; # NOTE: Needed for the [vwait].
- }
-
- #
- # NOTE: This procedure creates the user interface for this tool using Tcl
- # and Tk. The existing argument data, if any, will be used to
- # populate it. There are no arguments.
- #
- proc setupTkUserInterface {} {
- variable widgets
-
- package require Tk
- catch {console show}
-
- catch {wm withdraw .}; set toplevel [toplevel .uploader]
- set widgets(toplevel) $toplevel
-
- wm title $toplevel "Package Uploader Client"
- wm minsize $toplevel 250 0
-
- ###########################################################################
-
- set widgets(label,apiKey) [label [appendArgs \
- $toplevel .la_apiKey] -text "API Key"]
-
- ###########################################################################
-
- set widgets(entry,apiKey) [entry [appendArgs \
- $toplevel .e_apiKey] -textvariable [appendArgs \
- [namespace current] ::argumentData(apiKey)]]
-
- ###########################################################################
-
- set widgets(label,package) [label [appendArgs \
- $toplevel .la_package] -text "Package Name"]
-
- ###########################################################################
-
- set widgets(entry,package) [entry [appendArgs \
- $toplevel .e_package] -textvariable [appendArgs \
- [namespace current] ::argumentData(package)]]
-
- ###########################################################################
-
- set widgets(label,patchLevel) [label [appendArgs \
- $toplevel .la_patchLevel] -text "Package Patch Level"]
-
- ###########################################################################
-
- set widgets(entry,patchLevel) [entry [appendArgs \
- $toplevel .e_patchLevel] -textvariable [appendArgs \
- [namespace current] ::argumentData(patchLevel)]]
-
- ###########################################################################
-
- set widgets(label,language) [label [appendArgs \
- $toplevel .la_language] -text Language]
-
- ###########################################################################
-
- set widgets(entry,language) [entry [appendArgs \
- $toplevel .e_language] -textvariable [appendArgs \
- [namespace current] ::argumentData(language)]]
-
- ###########################################################################
-
- set widgets(label,version) [label [appendArgs \
- $toplevel .la_version] -text Version]
-
- ###########################################################################
-
- set widgets(entry,version) [entry [appendArgs \
- $toplevel .e_version] -textvariable [appendArgs \
- [namespace current] ::argumentData(version)]]
-
- ###########################################################################
-
- set widgets(label,platform) [label [appendArgs \
- $toplevel .la_platform] -text Platform]
-
- ###########################################################################
-
- set widgets(entry,platform) [entry [appendArgs \
- $toplevel .e_platform] -textvariable [appendArgs \
- [namespace current] ::argumentData(platform)]]
-
- ###########################################################################
-
- set widgets(label,fileNames) [label [appendArgs \
- $toplevel .la_fileNames] -text Files]
-
- ###########################################################################
-
- set widgets(listbox,fileNames) [listbox [appendArgs \
- $toplevel .li_fileNames] -listvariable [appendArgs \
- [namespace current] ::argumentData(fileNames)]]
-
- bind $widgets(listbox,fileNames) \
- [namespace code [list listBoxEventHandler [appendArgs \
- [namespace current] ::argumentData(fileNames)]]]
-
- ###########################################################################
-
- set widgets(button,submit) [button \
- [appendArgs $toplevel .b_submit] -text Submit -command \
- [namespace code [list submitEventHandler false]]]
-
- ###########################################################################
-
- set widgets(button,clear) [button \
- [appendArgs $toplevel .b_clear] -text Clear -command \
- [namespace code [list clearEventHandler]]]
-
- ###########################################################################
-
- pack $widgets(label,apiKey) $widgets(entry,apiKey) \
- $widgets(label,package) $widgets(entry,package) \
- $widgets(label,patchLevel) $widgets(entry,patchLevel) \
- $widgets(label,language) $widgets(entry,language) \
- $widgets(label,version) $widgets(entry,version) \
- $widgets(label,platform) $widgets(entry,platform) \
- $widgets(label,fileNames) $widgets(listbox,fileNames) \
- $widgets(button,submit) $widgets(button,clear) \
- -expand true -fill both
-
- pack $widgets(button,submit) $widgets(button,clear) \
- -anchor e -expand false -fill none
- }
-
#
# NOTE: Figure out the fully qualified path to the current script file.
# If necessary, add it to the auto-path for the interpreter. The
# necessary supporting packages (i.e. the Package Repository and
# other support packages) that are assumed to exist in the same
@@ -1678,40 +68,13 @@
variable autoLoadTcl false
variable autoHook false
}
#
- # NOTE: This package requires both the package repository and downloader
- # client packages.
- #
- package require Eagle.Package.Downloader
-
- #
- # NOTE: This package requires that support for namespaces, which is an
- # optional feature of Eagle, must be enabled.
- #
- if {[isEagle] && ![namespace enable]} then {
- error "namespaces must be enabled for this package"
- }
-
- #
- # 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.
- #
- setupUploadVars
- setupCheckoutVars
-
- #
- # NOTE: Provide the package to the interpreter.
- #
- package provide Eagle.Package.Uploader \
- [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
+ # NOTE: This package requires both the package uploader client package.
+ #
+ package require Eagle.Package.Uploader
#
# NOTE: Process the command line arguments into their corresponding data
# values, which are contained in an array.
#
@@ -1737,15 +100,21 @@
# command line, use interactive mode. This will create a graphical
# user interface, using Tk or WinForms. If any of the necessary
# arguments were supplied on the command line, they will be used to
# populate those fields on the graphical user interface.
#
+ variable guiError
+
if {[isEagle]} then {
- setupWinFormsUserInterface
+ if {[catch {setupWinFormsUserInterface} guiError]} then {
+ usage $guiError
+ }
} else {
- setupTkUserInterface
+ if {[catch {setupTkUserInterface} guiError]} then {
+ usage $guiError
+ }
}
- variable forever; vwait forever
+ vwait [appendArgs [namespace current] ::forever]
}
}
Index: client/1.0/neutral/pkgr_upload.eagle.asc
==================================================================
--- client/1.0/neutral/pkgr_upload.eagle.asc
+++ client/1.0/neutral/pkgr_upload.eagle.asc
@@ -1,18 +1,18 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
Comment: Eagle Package Repository
-iQIcBAABCAAGBQJYXZZ0AAoJEFAslq9JXcLZqQsQAKRc/+ZiWXfVLgM0LRkxz5Jn
-ZQJZ6bhseTMDD9NHZMp4kIsjv3xApz7VXcdStzeo3s+7c+jMB2vl2iyVbyWv4TNT
-6HIRWThrLawUzL7XSHpOYHG4wkRldIDNQUiZv3mop9kGFg296XldENfBkiyz625C
-MyzuZ9pcRK23t2YvvXUAaKvoTt81MAUNzUFimSDdv8VXQRg+q6nFgUEoR98NISL0
-kfgtaEmn/KSj2A87YvjhPg7dF5AGdepNrC51zwtX7T1f+oB5I68PunvrFIQJc9oU
-xF6C9CWksnQ7bL6sotO5lHDuOcod9OShY3p1r24C6OoxuybgBZqhHKpk2ABeuCgH
-dhZYh26wDGkEhV1sIKbNCZFVX99+u17QUvcGRSo9eM8mGAmYCcxvUYBrZ1CYFB7s
-dioypnGgKv10C0nLfn23DKvH6v4FV5kdvFdXWIZEv7fZoeIWUMQRFcngT3wRNZr0
-yn9dG0jBPQs0dWvd79p49fe5eDfFRix7n9aLeN88tUiIsZxpNa/OedOP/RJp/tR/
-oZXzs2kBrn+FoKaIEyNZBfadiQSzVrLDmjZCKHWdjuDJyNRMR+f2ikysZyFKusgy
-pNwx3sCyotHCspWbtvd3Ta8baKsC1AXzjunU98nSExB6irqDeLNF8PKD07ZE9/jL
-dHOwePlaxz7CihvcmDNU
-=B9v0
+iQIcBAABCAAGBQJYXa9WAAoJEFAslq9JXcLZuGkP/27jhh5ndcJQa0s4cCbahTd/
+Wl/xjILMiCGeSQrXiAWJibLxRn8hSEoozNyT28Gu0raIgjgW2IrW34r3BhafHYAK
+TjyuZXK6kMBKi/yydz+079T/6KL2fAlkhygL4YBGaI2D+pSmDOvqeNrf5IMWPnkv
+GYpoN1mpYmerAp/BNfSLepScVXswzEUIcTHScSK4i75cdq8gpxMdRxOd3GlK91Ss
+WzPtyc4+FUGgBuDSgfbrnO6JLBEOe5gM5tWllJ0ViCFxDGL5OK1hKk40P0qvh5m4
+cem23//xAOjwriJfoM/jAipJmKNIFiSgvTJHMZgWXmmB3rh11DTZykFWv+AX1vnP
+V8zIP8mK1NYMCBoYVwtJxL2x/FeKjQBi2ytFIEfAxTva+ZU6OMxkqDSj5xGv3Bh+
+HvDMQXsf+T6AQQVPx07VnjWrwz56MsMBiBhyrcmSbDfc8s2wwtdUFxOVzienTE+C
+cwpijwxlG5gzKRrPeIGwvkUULjHBSzGhh6UQ/lDUR9X+U069gu0HmvuL/H+RKg6+
+30Vh78TGt1ITwKk2OPfItrUtuxz5QFvnklMUQ0JNwVTWQB+e4CJFQY1fuCN/mS1h
+0/JxsmA2w6p7JHetJFYavlX+e0nGthoPiygvrCBLJIOVpTKPULn7rFx34ZmO7ALX
+siSg2yrX0irpS2amdjjR
+=i0mO
-----END PGP SIGNATURE-----
Index: client/1.0/neutral/pkgr_upload.eagle.harpy
==================================================================
--- client/1.0/neutral/pkgr_upload.eagle.harpy
+++ client/1.0/neutral/pkgr_upload.eagle.harpy
@@ -19,50 +19,50 @@
None
Mistachkin Systems
- b6aa3d48-dcff-4c6b-a64c-72c77f5be30d
+ adda0a31-cfd8-463d-bbe4-96f778c6ac28
SHA512
Script
- 2016-12-23T21:25:37.3613281Z
+ 2016-12-23T23:11:23.5292968Z
-1.00:00:00
0x9559f6017247e3e2
- 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
+ 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
Index: client/1.0/neutral/pkgr_upload.eagle.harpy.asc
==================================================================
--- client/1.0/neutral/pkgr_upload.eagle.harpy.asc
+++ client/1.0/neutral/pkgr_upload.eagle.harpy.asc
@@ -1,18 +1,18 @@
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
Comment: Eagle Package Repository
-iQIcBAABCAAGBQJYXZZ1AAoJEFAslq9JXcLZwzQQAIHgjEiXZvcEE+WMK14i54CP
-+HzfxisJ0uV68ok1hq+LS5j+rnW2STkH2lTluPoT5v1Dfgza4OPyDJUz9NKzV63S
-zhPRv3HtJzBkrIwrHu2Er2RAE674rzxsoki4SrGhw/TYfPW6skiBsErMs6/DFldo
-N3UbWyEUXtgfuqzD3sltuADKY86rVg6Q0rEZ1llIUxXT/c+99T/eAR6+F0RnQIg3
-ZRnGnN+IL4HCjBZY66rYEgnJ3KHmbGLEYgoQPY5deTvpZt+EZJNkH4UhEtXxb/aN
-iLmNg3RnYh3wbpD3utqIXGeT32rNaR8o87HgYati41AKZBRg3OBrcWjBH2x6a2jd
-1uf0qx008o1WAl7VfeE7x9vbFg/oLUUU+Ku8f3NtIp9GtZZyF+8SJJ4xAPFtHJ1B
-FWRxm8kUPdZhKQXd5KHwJq8+TSJ85nn3oVXvhg57mOPVWYgugc1DU1chOeBwC4Ag
-GRr6jIYQdpcexc19XgWg03f3gHnylAJH7u8SJ6HZ/TBAJmqppjtOzYLvWFIP/3d3
-VbO5RP8+Len8745IQjhdxLxys0uwCgny3vQOq12MJTmAPlLlK17chdE65Ic/Xymm
-PNulVvT/Y3cSQoGhNeQ3afpKNG1CSkmktBT3SFAfdKDwAr5qLZ6IRuZxru9wBUAQ
-sG5ruyypKot/lL6QfKSQ
-=6o5a
+iQIcBAABCAAGBQJYXa9YAAoJEFAslq9JXcLZ1+sP/jJTv4cJ8bK/AfND+sV9ReOp
+2PyJYf191DuUXaypsW0YghKmHOqC5lHMEV2d7GtEq90fE9rIfEEO92c05GOz/yel
+IGqyoPAPGNSzZv8SateBWcx56jizbzDh+++TRiN4hZ1mpRUOXk9+S+9rf09tlGDh
+0l8lg3fxfdlAedn7BEZ/wgLbcfXN+gXMGCDKJ/PrAvXTKlwwBqjAo6yN4nh6yrl2
+Jy+Bp0VT54Ve+U0wwKH1rBWw/RaVnBp01KxB1kuCsVcsOblbhZsMw/YorYu+4S/M
+QXfRE6kxX6Nix6O1Yw36T6f8DP58Ocpi71IA7YkX5fxtrwjD39AlPby40kmR4q/Q
+PKuuoeDNpWRjeRWAOLh1DgVzi4eKWqaSGhqMAhrd0aABy80avYEdqpGoskQ7o4hy
+Rx50OACxIRT7BeNaTyX7lHZNVRywtPi03zU+vSS2976JTw2u5K5N51iJmwAv8qim
+pxnhrIeUhJkfjxgRHt0aRriDYguwIsFstO2gYReCM+ZJfsA/c1bJgK+FTxNbpt1+
+dIvz5x8hT2OkHpfgQ3lho/eEPFgBU+aajLmfSZPIAgoLfVaxkbjQ5t+UlkGyqI1u
+vigIpb3mSnBGd9dIPwOkS71lBLRY4W/hp1fGfG1CEImbo5h8Wkw2MEszQOFgTcqL
+veADnHyRMBxDLgmleVbh
+=ZSeW
-----END PGP SIGNATURE-----
ADDED client/1.0/neutral/pkgu.eagle
Index: client/1.0/neutral/pkgu.eagle
==================================================================
--- client/1.0/neutral/pkgu.eagle
+++ client/1.0/neutral/pkgu.eagle
@@ -0,0 +1,1694 @@
+###############################################################################
+#
+# pkgu.eagle --
+#
+# Extensible Adaptable Generalized Logic Engine (Eagle)
+# Package Uploader 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 ::PackageUploader {
+ #
+ # NOTE: This procedure sets up the default values for all configuration
+ # parameters used by the package uploader client. There are no
+ # arguments.
+ #
+ proc setupUploadVars {} {
+ #
+ # NOTE: This variable must exist and must be the fully qualified path
+ # of the directory containing this script.
+ #
+ variable pkgr_path
+
+ if {![info exists pkgr_path]} then {
+ error [appendArgs \
+ "required namespace variable \"" [namespace current] \
+ "::pkgr_path\" does not exist"]
+ }
+
+ #
+ # NOTE: The project code for the Fossil repository. This will be checked
+ # prior to staging or committing any files.
+ #
+ variable projectCode; # DEFAULT: 9ceada8dbb8678898e5b2c05386e73b3ff2c2dec
+
+ if {![info exists projectCode]} then {
+ set projectCode 9ceada8dbb8678898e5b2c05386e73b3ff2c2dec
+ }
+
+ #
+ # NOTE: What is the fully qualified path to the directory containing
+ # package client toolset?
+ #
+ variable scriptDirectory; # DEFAULT:
+
+ if {![info exists scriptDirectory]} then {
+ set scriptDirectory $pkgr_path
+ }
+
+ #
+ # NOTE: The command to use when attempting to verify that Fossil is
+ # available for use.
+ #
+ variable fossilVersionCommand; # DEFAULT: fossil version
+
+ if {![info exists fossilVersionCommand]} then {
+ set fossilVersionCommand {fossil version}
+ }
+
+ #
+ # NOTE: The regular expression pattern used when attempting to verify
+ # that Fossil is installed.
+ #
+ variable fossilVersionPattern; # DEFAULT: {^This is fossil version 1\.\d+ }
+
+ if {![info exists fossilVersionPattern]} then {
+ set fossilVersionPattern {^This is fossil version 1\.\d+ }
+ }
+
+ #
+ # NOTE: The command to use when attempting to check for changes prior to
+ # staging files using Fossil.
+ #
+ variable fossilChangesCommand; # DEFAULT: fossil changes ...
+
+ if {![info exists fossilChangesCommand]} then {
+ set fossilChangesCommand {fossil changes --chdir {${directory}}}
+ }
+
+ #
+ # NOTE: The regular expression pattern used when attempting to verify
+ # that the Fossil checkout has no changes staged. Generally, this
+ # pattern should only match an empty string.
+ #
+ variable fossilChangesPattern; # DEFAULT: {^$}
+
+ if {![info exists fossilChangesPattern]} then {
+ set fossilChangesPattern {^$}
+ }
+
+ #
+ # NOTE: The command to use when attempting to check the checkout status
+ # prior to staging files using Fossil.
+ #
+ variable fossilInfoCommand; # DEFAULT: fossil info ...
+
+ if {![info exists fossilInfoCommand]} then {
+ set fossilInfoCommand {fossil info --chdir {${directory}}}
+ }
+
+ #
+ # NOTE: The regular expression pattern used when attempting to extract
+ # the root directory for the Fossil checkout.
+ #
+ variable fossilInfoLocalRootPattern; # DEFAULT: {^local-root:\s+(.*?)$}
+
+ if {![info exists fossilInfoLocalRootPattern]} then {
+ set fossilInfoLocalRootPattern {^local-root:\s+(.*?)$}
+ }
+
+ #
+ # NOTE: The regular expression pattern used when attempting to verify
+ # that the Fossil checkout belongs to the correct project.
+ #
+ variable fossilInfoProjectCodePattern; # DEFAULT: {^project-code:\\s+...\$}
+
+ if {![info exists fossilInfoProjectCodePattern]} then {
+ set fossilInfoProjectCodePattern [appendArgs \
+ {^project-code:\\s+${projectCode}\$}]
+ }
+
+ #
+ # NOTE: The regular expression pattern used when attempting to verify
+ # that the Fossil checkout is sitting on the correct branch.
+ #
+ variable fossilInfoTagsPattern; # DEFAULT: {^tags:\s+trunk(?:,|$)}
+
+ if {![info exists fossilInfoTagsPattern]} then {
+ set fossilInfoTagsPattern {^tags:\s+trunk(?:,|$)}
+ }
+
+ #
+ # NOTE: The command to use when attempting to reset the checkout to the
+ # default branch prior to staging files using Fossil.
+ #
+ variable fossilUpdateCommand; # DEFAULT: fossil update trunk ...
+
+ if {![info exists fossilUpdateCommand]} then {
+ set fossilUpdateCommand \
+ {fossil update trunk --chdir {${directory}}}
+ }
+
+ #
+ # NOTE: The command to use when attempting to stage package files using
+ # Fossil.
+ #
+ variable fossilAddCommand; # DEFAULT: fossil add ...
+
+ if {![info exists fossilAddCommand]} then {
+ set fossilAddCommand \
+ {fossil add --chdir {${directory}} {${fileName}}}
+ }
+
+ #
+ # NOTE: The command to use when attempting to commit package files using
+ # Fossil.
+ #
+ variable fossilCommitCommand; # DEFAULT: fossil commit ...
+
+ if {![info exists fossilCommitCommand]} then {
+ set fossilCommitCommand {fossil commit -m {${comment}}\
+ --branch {${branch}} --user anonymous --chdir \
+ {${directory}} --no-prompt}
+ }
+
+ #
+ # NOTE: The regular expression pattern used when attempting to verify
+ # that Fossil committed a set of files.
+ #
+ variable fossilCommitPattern; # DEFAULT: {^New_Version: ([0-9a-f]{40})$}
+
+ if {![info exists fossilCommitPattern]} then {
+ set fossilCommitPattern {^New_Version: ([0-9a-f]{40})$}
+ }
+
+ #
+ # NOTE: Emit diagnostic messages when a new package is submitted?
+ #
+ variable verboseMetadataSubmit; # DEFAULT: false
+
+ if {![info exists verboseMetadataSubmit]} then {
+ set verboseMetadataSubmit false
+ }
+ }
+
+ #
+ # NOTE: This procedure sets up the default values for all configuration
+ # parameters used by the package uploader client that require the
+ # location of the checkout directory. There are no arguments.
+ #
+ proc setupCheckoutVars {} {
+ #
+ # NOTE: What is the fully qualified path to the root directory of the
+ # Fossil checkout containing the package client toolset? This
+ # procedure may raise script errors.
+ #
+ variable checkoutDirectory; # DEFAULT:
+
+ if {![info exists checkoutDirectory]} then {
+ set checkoutDirectory [getCheckoutDirectory]
+ }
+ }
+
+ #
+ # NOTE: This procedure returns a string value, formatted for use within a
+ # script block being processed by the [string map] command. The
+ # value argument is the string value to format. No return value is
+ # reserved to indicate an error. This procedure may not raise any
+ # script errors.
+ #
+ proc formatStringMapValue { value } {
+ if {[string length $value] == 0} then {
+ return \"\"
+ }
+
+ set list [list $value]
+
+ if {$value eq $list} then {
+ return $value
+ } else {
+ return $list
+ }
+ }
+
+ #
+ # NOTE: This procedure counts the common path components for two paths. The
+ # count is returned, zero if there are no common path components. The
+ # path1 and path2 arguments are the paths to compare. This procedure
+ # may not raise script errors.
+ #
+ proc countCommonPathParts { path1 path2 } {
+ set parts1 [file split $path1]
+ set length1 [llength $parts1]
+
+ set parts2 [file split $path2]
+ set length2 [llength $parts2]
+
+ set length [expr {min($length1, $length2)}]
+
+ for {set index 0} {$index < $length} {incr index} {
+ set part1 [lindex $parts1 $index]
+ set part2 [lindex $parts2 $index]
+
+ if {$part1 ne $part2} then {
+ return $index
+ }
+ }
+
+ return $length
+ }
+
+ #
+ # NOTE: This procedure processes a list of (fully?) qualified file names and
+ # tries to determine their common containing directory, if any. The
+ # fileNames argument is the list of (fully?) qualified file names to
+ # process. This procedure may not raise script errors. If there is
+ # no common containing directory, an empty string is returned.
+ #
+ proc getCommonContainingDirectory { fileNames } {
+ set length [llength $fileNames]
+
+ if {$length == 0} then {
+ return ""
+ }
+
+ set oldFileName [lindex $fileNames 0]
+
+ if {$length == 1} then {
+ return [file dirname $oldFileName]
+ }
+
+ set minimumCount 0
+
+ for {set index 1} {$index < $length} {incr index} {
+ set newFileName [lindex $fileNames $index]
+ set newCount [countCommonPathParts $oldFileName $newFileName]
+
+ if {$newCount == 0} then {
+ return ""
+ }
+
+ if {$minimumCount == 0 || $newCount < $minimumCount} then {
+ set oldFileName $newFileName
+ set minimumCount $newCount
+ }
+ }
+
+ if {$minimumCount == 0} then {
+ return ""
+ }
+
+ incr minimumCount -1
+
+ return [eval file join [lrange [file split $oldFileName] 0 $minimumCount]]
+ }
+
+ #
+ # NOTE: This procedure attempts to process a list of (fully?) qualified file
+ # names and return the corresponding list of relative file names. The
+ # fileNames argument is the list of (fully?) qualified file names to
+ # process. The maximumLevels argument is the maximum path depth that
+ # is allowed for all file names. This procedure may raise script
+ # errors.
+ #
+ proc getRelativeFileNames { fileNames maximumLevels } {
+ set directory [getCommonContainingDirectory $fileNames]
+ set directoryParts [file split $directory]
+ set fileNameIndex [expr {[llength $directoryParts] - 1}]
+
+ if {$fileNameIndex < 0} then {
+ error [appendArgs \
+ "invalid containing directory \"" $directory \
+ "\": cannot go up one level"]
+ }
+
+ set relativeFileNames [list]
+
+ foreach fileName $fileNames {
+ set fileNameParts [lrange \
+ [file split $fileName] $fileNameIndex end]
+
+ if {$maximumLevels > 0 && \
+ [llength $fileNameParts] > $maximumLevels} then {
+ error [appendArgs \
+ "depth for file name \"" $fileName \
+ "\" exceeds maximum (" $maximumLevels )]
+ }
+
+ set relativeFileName [eval file join $fileNameParts]
+
+ if {[string length $relativeFileName] == 0 || \
+ [file pathtype $relativeFileName] ne "relative"} then {
+ error [appendArgs \
+ "bad file name \"" $relativeFileName "\", not relative"]
+ }
+
+ lappend relativeFileNames $relativeFileName
+ }
+
+ return $relativeFileNames
+ }
+
+ #
+ # NOTE: This procedure attempts to create a script chunk that appends the
+ # specified list of file names to a list variable. The fileNames
+ # argument is the list of (fully?) qualified file names to append to
+ # the list variable. The maximumLevels argument is the maximum path
+ # depth that is allowed for all file names. This procedure may raise
+ # script errors.
+ #
+ proc getScriptChunkForFileNames { fileNames maximumLevels } {
+ set result ""
+ set relativeFileNames [getRelativeFileNames $fileNames $maximumLevels]
+
+ foreach relativeFileName $relativeFileNames {
+ if {[string length $result] > 0} then {
+ append result \n
+ }
+
+ append result { lappend fileNames [file join }
+ append result [file split $relativeFileName]
+ append result \]
+ }
+
+ return $result
+ }
+
+ #
+ # NOTE: This procedure creates and returns a script block designed for use
+ # with the package repository server in order to download and provide
+ # a package consisting of a set of files. The serverId argument is
+ # the identifier for the specific server to use, if any. The
+ # versionId argument is the identifier for the specific version to use,
+ # if any. The language argument must be the literal string "eagle" or
+ # the literal string "tcl". The version argument must be one of the
+ # literal strings "8.4", "8.5", or "8.6" when the language is "tcl"
+ # -OR- the literal string "1.0" when the language is "eagle". The
+ # platform argument must be an empty string -OR- one of the literal
+ # strings "neutral", "win32-arm", "win32-x86", "win64-arm64",
+ # "win64-ia64", or "win64-x64". The fileNames argument is the list of
+ # (fully?) qualified file names to be downloaded when the associated
+ # package is being provided. The options argument is reserved for
+ # future use, it should be an empty list.
+ #
+ #
+ proc createRepositoryScript {
+ serverId versionId language version platform fileNames options } {
+ ::PackageDownloader::verifyServerId $serverId
+ ::PackageDownloader::verifyVersionId $versionId
+ ::PackageDownloader::verifyLanguageAndVersion $language $version isClient
+
+ set prologue ""
+
+ if {[string length $serverId] > 0} then {
+ append prologue " ::PackageDownloader::useServerId " $serverId \n
+ }
+
+ if {[string length $versionId] > 0} then {
+ append prologue " ::PackageDownloader::useVersionId " $versionId \n
+ }
+
+ append prologue " "
+
+ return [string trim [string map [list \r\n \n \
+ %language% [formatStringMapValue $language] \
+ %version% [formatStringMapValue $version] \
+ %platform% [formatStringMapValue $platform] \
+ %prologue% $prologue %ns% ::PackageDownloader \
+ %backslash% \\ %fileNames% \
+ [getScriptChunkForFileNames $fileNames 2]] {
+apply [list [list] {
+ package require Eagle.Package.Downloader
+
+%prologue%%ns%::resetCookieAndLoginSimple
+
+ set fileNames [list]
+
+%fileNames%
+
+ set options [list %backslash%
+ -persistent false -usePgp true -useAutoPath true]
+
+ %ns%::downloadFiles %language% %version% %platform% $fileNames $options
+ %ns%::logoutAndResetCookie
+}]
+ }]]
+ }
+
+ #
+ # NOTE: This procedure creates textual data that conforms to the content
+ # type "multipart/form-data", per RFC 2388. The boundary argument
+ # is a boundary value, as specified in section 4.1 of the RFC. The
+ # request argument is the dictionary of name/value pairs to include
+ # in the form body. This procedure may not raise script errors.
+ #
+ proc createMultipartFormData { boundary request } {
+ set result ""
+
+ foreach {name value} $request {
+ append result -- $boundary \r\n
+ append result "Content-Disposition: form-data; name=\""
+ append result $name \"\r\n\r\n
+ append result $value \r\n
+ }
+
+ if {[string length $result] > 0} then {
+ append result -- $boundary --\r\n
+ }
+
+ if {[isEagle]} then {
+ return [object create -alias String $result]
+ } else {
+ return $result
+ }
+ }
+
+ #
+ # NOTE: This procedure returns the full URI to use when submitting a new
+ # package to the package repository server. There are no arguments.
+ # This procedure may raise script errors.
+ #
+ proc getSubmitUri {} {
+ #
+ # NOTE: Fetch the base URI for the package repository server. If it
+ # is not available for some reason, just return an empty string
+ # to the caller (i.e. as we cannot do anything productive).
+ #
+ set baseUri [::PackageRepository::getLookupBaseUri]
+
+ if {[string length $baseUri] == 0} then {
+ return ""
+ }
+
+ #
+ # NOTE: Build the HTTP request URI and include the standard query
+ # parameters (with constant values) for this request type.
+ #
+ if {[isEagle]} then {
+ return [appendArgs \
+ $baseUri ?raw=1&method=submit]
+ } else {
+ package require http 2.0
+
+ return [appendArgs \
+ $baseUri ? [::http::formatQuery raw 1 method submit]]
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to submit the metadata for a new package to
+ # the package repository server. Upon success, an empty string will
+ # be returned. Upon failure, a script error will be raised. The
+ # apiKey argument is the list of API keys to use. The package argument
+ # is the name of the package. The patchLevel argument is the specific
+ # patch level being submitted. The language argument must be an empty
+ # string, "Tcl", or "Eagle". If it is an empty string, the current
+ # language will be assumed. The script argument is the script to be
+ # evaluated when the package needs to be provided. The certificate
+ # argument is the certificate associated with the script, which may be
+ # an OpenPGP signature or a Harpy script certificate.
+ #
+ #
+ proc submitPackageMetadata {
+ apiKey package patchLevel language script certificate } {
+ variable verboseMetadataSubmit
+
+ #
+ # NOTE: Fetch the submission URI for the package repository server. If
+ # it is not available for some reason, raise a script error.
+ #
+ set uri [getSubmitUri]
+
+ if {[string length $uri] == 0} then {
+ error ""
+ }
+
+ if {[string length $language] == 0} then {
+ set language [expr {[isEagle] ? "Eagle" : "Tcl"}]
+ }
+
+ if {[isEagle]} then {
+ set boundary [string map \
+ [list + "" / "" = ""] [base64 encode [expr {randstr(50)}]]]
+ } else {
+ set boundary [::PackageRepository::getUniqueSuffix]
+ }
+
+ set contentType [appendArgs \
+ "multipart/form-data; boundary=" $boundary]
+
+ set formData [createMultipartFormData $boundary \
+ [list apiKey $apiKey package $package patchLevel \
+ $patchLevel language $language script $script \
+ certificate $certificate]]
+
+ if {[isEagle]} then {
+ if {![object invoke Eagle._Tests.Default \
+ TestHasScriptNewWebClientCallback ""]} then {
+ set error null
+
+ set code [object invoke Eagle._Tests.Default \
+ TestSetScriptNewWebClientCallback "" true true error]
+
+ if {$code ne "Ok"} then {
+ error [getStringFromObjectHandle $error]
+ }
+ }
+
+ set script [object create String {
+ if {[methodName ToString] eq "GetWebRequest"} then {
+ webRequest ContentType $contentType
+ }
+ }]
+
+ set data [uri upload \
+ -inline -raw -encoding identity -webclientdata \
+ $script -data $formData $uri]
+ } else {
+ set options [list \
+ -binary true -type $contentType -query $formData]
+
+ set data [eval ::PackageRepository::getFileViaHttp \
+ [list $uri] [list 20] [list stdout] [list \
+ [expr {!$verboseMetadataSubmit}]] $options]
+ }
+
+ set code [::PackageRepository::getLookupCodeFromData $data]
+ set result [::PackageRepository::getLookupResultFromData $data]
+
+ if {[::PackageRepository::isLookupCodeOk $code]} then {
+ return $result
+ } else {
+ error [appendArgs \
+ "failed to submit package metadata: " $data]
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to query the root directory of the Fossil
+ # checkout. There are no arguments. An empty string is returned if
+ # the root directory of the Fossil checkout cannot be determined.
+ #
+ proc getCheckoutDirectory {} {
+ variable fossilInfoCommand
+ variable fossilInfoLocalRootPattern
+ variable scriptDirectory
+
+ fossilMustBeInstalled
+
+ if {[isEagle]} then {
+ set directory [::PackageRepository::formatExecArgument \
+ $scriptDirectory]
+
+ if {[catch {
+ eval exec -nocarriagereturns -stdout output -stderr error \
+ [subst $fossilInfoCommand]
+ } result] == 0} then {
+ set result [appendArgs $output $error]
+ } else {
+ return false
+ }
+ } else {
+ set directory $scriptDirectory
+
+ if {[catch {
+ eval exec [subst $fossilInfoCommand]
+ } result]} then {
+ return false
+ }
+ }
+
+ if {![info exists result] || ![regexp -line -- \
+ $fossilInfoLocalRootPattern $result dummy directory]} then {
+ return ""
+ }
+
+ return [string trim $directory]
+ }
+
+ #
+ # NOTE: This procedure attempts to verify that the root directory of the
+ # Fossil checkout is present, valid, and is actually a directory.
+ # There are no arguments. Script errors will be raised if any of
+ # the checks fail.
+ #
+ proc verifyCheckoutDirectory {} {
+ variable checkoutDirectory
+
+ if {![info exists checkoutDirectory]} then {
+ error "checkout directory is missing"
+ }
+
+ if {[string length $checkoutDirectory] == 0} then {
+ error "checkout directory is invalid"
+ }
+
+ if {![file isdir $checkoutDirectory]} then {
+ error [appendArgs \
+ "checkout directory \"" $checkoutDirectory \
+ "\" is not really a directory"]
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to verify that an implementation of Fossil
+ # is installed locally. There are no arguments. Script errors are
+ # raised if any problems are found. The return value is undefined.
+ #
+ proc fossilMustBeInstalled {} {
+ variable fossilVersionCommand
+ variable fossilVersionPattern
+
+ set message [string trim {
+ Cannot use Fossil: it does not appear to be installed.
+
+ Fossil may be downloaded from "https://www.fossil-scm.org/"
+ and then installed by copying the (single) Fossil binary to
+ a directory that lies somewhere along the executable search
+ path.
+
+ Alternatively, it may be possible to install Fossil via the
+ package management subsystem included with your operating
+ system.
+ }]
+
+ if {[isEagle]} then {
+ if {[catch {
+ eval exec -nocarriagereturns -stdout output -stderr error \
+ $fossilVersionCommand
+ } result] == 0} then {
+ set result [appendArgs $output $error]
+ } else {
+ error $message
+ }
+ } else {
+ if {[catch {
+ eval exec $fossilVersionCommand
+ } result]} then {
+ error $message
+ }
+ }
+
+ if {![info exists result] || \
+ ![regexp -- $fossilVersionPattern $result]} then {
+ error "cannot use Fossil: unknown or unsupported version"
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to verify that the checkout directory does
+ # not contain any (stray) changes. There are no arguments. Non-zero
+ # is returned if the verification is successful.
+ #
+ proc verifyThereAreNoChanges {} {
+ variable checkoutDirectory
+ variable fossilChangesCommand
+ variable fossilChangesPattern
+
+ fossilMustBeInstalled
+ verifyCheckoutDirectory
+
+ if {[isEagle]} then {
+ set directory [::PackageRepository::formatExecArgument \
+ $checkoutDirectory]
+
+ if {[catch {
+ eval exec -nocarriagereturns -stdout output -stderr error \
+ [subst $fossilChangesCommand]
+ } result] == 0} then {
+ set result [appendArgs $output $error]
+ } else {
+ return false
+ }
+ } else {
+ set directory $checkoutDirectory
+
+ if {[catch {
+ eval exec [subst $fossilChangesCommand]
+ } result]} then {
+ return false
+ }
+ }
+
+ if {![info exists result] || \
+ ![regexp -- $fossilChangesPattern $result]} then {
+ return false
+ }
+
+ return true
+ }
+
+ #
+ # NOTE: This procedure attempts to verify that the checkout directory does
+ # belong to the correct project. There are no arguments. Non-zero
+ # is returned if the verification is successful.
+ #
+ proc verifyThisIsTheCorrectProject {} {
+ variable fossilInfoCommand
+ variable fossilInfoProjectCodePattern
+ variable projectCode
+ variable scriptDirectory
+
+ fossilMustBeInstalled
+
+ if {[isEagle]} then {
+ set directory [::PackageRepository::formatExecArgument \
+ $scriptDirectory]
+
+ if {[catch {
+ eval exec -nocarriagereturns -stdout output -stderr error \
+ [subst $fossilInfoCommand]
+ } result] == 0} then {
+ set result [appendArgs $output $error]
+ } else {
+ return false
+ }
+ } else {
+ set directory $scriptDirectory
+
+ if {[catch {
+ eval exec [subst $fossilInfoCommand]
+ } result]} then {
+ return false
+ }
+ }
+
+ if {![info exists result] || ![regexp -line -- \
+ [subst $fossilInfoProjectCodePattern] $result]} then {
+ return false
+ }
+
+ return true
+ }
+
+ #
+ # NOTE: This procedure attempts to verify that the checkout directory does
+ # belong to the correct branch. There are no arguments. Non-zero
+ # is returned if the verification is successful.
+ #
+ proc verifyThisIsTheCorrectBranch {} {
+ variable fossilInfoCommand
+ variable fossilInfoTagsPattern
+ variable scriptDirectory
+
+ fossilMustBeInstalled
+
+ if {[isEagle]} then {
+ set directory [::PackageRepository::formatExecArgument \
+ $scriptDirectory]
+
+ if {[catch {
+ eval exec -nocarriagereturns -stdout output -stderr error \
+ [subst $fossilInfoCommand]
+ } result] == 0} then {
+ set result [appendArgs $output $error]
+ } else {
+ return false
+ }
+ } else {
+ set directory $scriptDirectory
+
+ if {[catch {
+ eval exec [subst $fossilInfoCommand]
+ } result]} then {
+ return false
+ }
+ }
+
+ if {![info exists result] || \
+ ![regexp -line -- $fossilInfoTagsPattern $result]} then {
+ return false
+ }
+
+ return true
+ }
+
+ #
+ # NOTE: This procedure attempts to change the branch for the checkout
+ # directory. There are no arguments. This procedure may raise
+ # script errors.
+ #
+ proc changeToTheCorrectBranch {} {
+ variable checkoutDirectory
+ variable fossilUpdateCommand
+
+ fossilMustBeInstalled
+ verifyCheckoutDirectory
+
+ if {[isEagle]} then {
+ set directory [::PackageRepository::formatExecArgument \
+ $checkoutDirectory]
+
+ if {[catch {
+ eval exec -success Success [subst $fossilUpdateCommand]
+ } error]} then {
+ error [appendArgs \
+ "could not change branch: " $error]
+ }
+ } else {
+ set directory $checkoutDirectory
+
+ if {[catch {
+ eval exec [subst $fossilUpdateCommand]
+ } error]} then {
+ error [appendArgs \
+ "could not change branch: " $error]
+ }
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to stage the specified package file using
+ # Fossil. The targetDirectory argument is the fully qualified path
+ # to the package platform directory. The fileName argument is the
+ # relative name of the file to be staged. This procedure may raise
+ # script errors.
+ #
+ proc stageOnePackageFile { targetDirectory fileName } {
+ variable fossilAddCommand
+
+ fossilMustBeInstalled
+
+ if {[isEagle]} then {
+ set directory [::PackageRepository::formatExecArgument \
+ $targetDirectory]
+
+ set fileName [::PackageRepository::formatExecArgument $fileName]
+
+ if {[catch {
+ eval exec -success Success [subst $fossilAddCommand]
+ } error]} then {
+ error [appendArgs \
+ "could not stage file \"" $fileName "\": " $error]
+ }
+ } else {
+ set directory $targetDirectory
+
+ if {[catch {
+ eval exec [subst $fossilAddCommand]
+ } error]} then {
+ error [appendArgs \
+ "could not stage file \"" $fileName "\": " $error]
+ }
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to stage the specified package files using
+ # Fossil. The fileNames argument is a list of (fully?) qualified
+ # local file names to stage.
+ #
+ #
+ proc stagePackageFiles { language version platform fileNames } {
+ variable checkoutDirectory
+ variable fossilAddCommand
+
+ verifyCheckoutDirectory
+
+ if {![verifyThereAreNoChanges]} then {
+ error "cannot stage files: there are pending changes"
+ }
+
+ if {![verifyThisIsTheCorrectProject]} then {
+ error "cannot stage files: wrong project"
+ }
+
+ if {![verifyThisIsTheCorrectBranch]} then {
+ changeToTheCorrectBranch
+
+ if {![verifyThisIsTheCorrectBranch]} then {
+ error "cannot stage files: still on wrong branch"
+ }
+ }
+
+ set targetDirectory [file join \
+ $checkoutDirectory $language $version $platform]
+
+ set relativeFileNames [getRelativeFileNames $fileNames 2]
+
+ foreach fileName $fileNames relativeFileName $relativeFileNames {
+ file mkdir [file join \
+ $targetDirectory [file dirname $relativeFileName]]
+
+ set checkoutFileName [file join $targetDirectory $relativeFileName]
+
+ file copy $fileName $checkoutFileName
+
+ if {![::PackageRepository::createOpenPgpSignature \
+ $checkoutFileName]} then {
+ error [appendArgs \
+ "could not stage file \"" $fileName \
+ "\": OpenPGP signing failed"]
+ }
+
+ stageOnePackageFile $targetDirectory $relativeFileName
+ stageOnePackageFile $targetDirectory [appendArgs $relativeFileName .asc]
+ }
+ }
+
+ #
+ # NOTE: This procedure attempts to commit the staged package files to the
+ # remote package file repository using Fossil. The varName argument
+ # is the name of a scalar variable in the context of the immediate
+ # caller that will receive the resulting Fossil check-in identifier.
+ #
+ #
+ proc commitPackageFiles { package patchLevel language version varName } {
+ variable checkoutDirectory
+ variable fossilCommitCommand
+ variable fossilCommitPattern
+
+ fossilMustBeInstalled
+ verifyCheckoutDirectory
+
+ set branch [appendArgs pkg_ $package _ $patchLevel]
+
+ set comment [appendArgs \
+ "Add package " $package " v" $patchLevel " for " $language \
+ " v" $version .]
+
+ if {[isEagle]} then {
+ set directory [::PackageRepository::formatExecArgument \
+ $checkoutDirectory]
+
+ set branch [::PackageRepository::formatExecArgument $branch]
+ set comment [::PackageRepository::formatExecArgument $comment]
+
+ if {[catch {
+ eval exec -nocarriagereturns -stdout output -stderr error \
+ [subst $fossilCommitCommand]
+ } result] == 0} then {
+ set result [appendArgs $output $error]
+ } else {
+ return false
+ }
+ } else {
+ set directory $checkoutDirectory
+
+ if {[catch {
+ eval exec [subst $fossilCommitCommand]
+ } result]} then {
+ return false
+ }
+ }
+
+ if {[string length $varName] > 0} then {
+ upvar 1 $varName checkin
+ }
+
+ if {![info exists result] || \
+ ![regexp -line -- $fossilCommitPattern $result dummy checkin]} then {
+ return false
+ }
+
+ return true
+ }
+
+ #
+ # NOTE: This procedure initializes the array containing data derived from
+ # the command line arguments, if any. The argv argument should be
+ # the list of command line arguments.
+ #
+ proc setupArgumentData { argv } {
+ variable argumentData
+
+ if {![info exists argumentData(apiKey)]} then {
+ set argumentData(apiKey) ""
+ }
+
+ if {![info exists argumentData(package)]} then {
+ set argumentData(package) ""
+ }
+
+ if {![info exists argumentData(patchLevel)]} then {
+ set argumentData(patchLevel) ""
+ }
+
+ if {![info exists argumentData(language)]} then {
+ set argumentData(language) ""
+ }
+
+ if {![info exists argumentData(version)]} then {
+ set argumentData(version) ""
+ }
+
+ if {![info exists argumentData(platform)]} then {
+ set argumentData(platform) ""
+ }
+
+ if {![info exists argumentData(fileNames)]} then {
+ set argumentData(fileNames) [list]
+ }
+
+ if {[llength $argv] >= 1} then {
+ set argumentData(apiKey) [lindex $argv 0]
+ }
+
+ if {[llength $argv] >= 2} then {
+ set argumentData(package) [lindex $argv 1]
+ }
+
+ if {[llength $argv] >= 3} then {
+ set argumentData(patchLevel) [lindex $argv 2]
+ }
+
+ if {[llength $argv] >= 4} then {
+ set argumentData(language) [lindex $argv 3]
+ }
+
+ if {[llength $argv] >= 5} then {
+ set argumentData(version) [lindex $argv 4]
+ }
+
+ if {[llength $argv] >= 6} then {
+ set argumentData(platform) [lindex $argv 5]
+ }
+
+ if {[llength $argv] >= 7} then {
+ set argumentData(fileNames) [lrange $argv 6 end]
+ }
+ }
+
+ #
+ # NOTE: This procedure is used to determine if all the package submission
+ # data is available. There are no arguments. Non-zero is returned
+ # if all the package submission data is available. This procedure
+ # should not raise script errors.
+ #
+ proc haveArgumentData {} {
+ variable argumentData
+
+ if {![info exists argumentData(apiKey)]} then {
+ return false
+ }
+
+ if {[string length $argumentData(apiKey)] == 0} then {
+ return false
+ }
+
+ if {![info exists argumentData(package)]} then {
+ return false
+ }
+
+ if {[string length $argumentData(package)] == 0} then {
+ return false
+ }
+
+ if {![info exists argumentData(patchLevel)]} then {
+ return false
+ }
+
+ if {[string length $argumentData(patchLevel)] == 0} then {
+ return false
+ }
+
+ if {![info exists argumentData(language)]} then {
+ return false
+ }
+
+ if {[string length $argumentData(language)] == 0} then {
+ return false
+ }
+
+ if {![info exists argumentData(version)]} then {
+ return false
+ }
+
+ if {[string length $argumentData(version)] == 0} then {
+ return false
+ }
+
+ if {![info exists argumentData(platform)]} then {
+ return false
+ }
+
+ if {[string length $argumentData(platform)] == 0} then {
+ return false
+ }
+
+ if {![info exists argumentData(fileNames)]} then {
+ return false
+ }
+
+ if {[llength $argumentData(fileNames)] == 0} then {
+ return false
+ }
+
+ return true
+ }
+
+ #
+ # NOTE: This procedure is an event handler. It handles the Changed event
+ # for a text box. It is not used when the user interface was built
+ # with Tk. The varName argument is the name of the scalar variable
+ # that must be updated with the contents of the text box. The sender
+ # and e arguments are provided by the framework and represent the
+ # control involved in the event and any extra data that may be
+ # necessary to process the event.
+ #
+ proc textBoxEventHandler { varName sender e } {
+ set $varName [$sender Text]
+ }
+
+ #
+ # NOTE: This procedure is an event handler. It handles double-clicking the
+ # list box in both Tk and Eagle. The varName argument is the name of
+ # the scalar variable that must be updated with the list of items from
+ # the list box -OR- the list of items from an interactive file picker
+ # dialog. The args argument, which is only used for Eagle, is a list
+ # containing two elements. The first element is the control involved
+ # in the event. The second element is any extra data that may be
+ # necessary to process the event.
+ #
+ proc listBoxEventHandler { varName args } {
+ if {[isEagle]} then {
+ set sender [lindex $args 0]
+ set e [lindex $args 1]
+
+ set dialog [object create -alias OpenFileDialog]
+
+ $dialog RestoreDirectory true
+ $dialog Multiselect true
+ $dialog ShowDialog
+
+ set fileNames [$dialog -create FileNames]
+
+ $sender Items.Clear
+ $sender Items.AddRange $fileNames
+
+ set list [object create -alias StringList $fileNames]
+ set $varName [$list ToString]
+ } else {
+ set $varName [tk_getOpenFile -multiple true]
+ }
+ }
+
+ #
+ # NOTE: This procedure is an event handler. It handles the Closed event for
+ # a WinForms form -OR- the WM_DELETE_WINDOW event on a Tk window. The
+ # args argument is not really used, it is a placeholder to make this
+ # procedure more portable between Tcl and Eagle. This procedure may
+ # raise script errors.
+ #
+ proc handleFormClosedEvent { args } {
+ if {[isEagle]} then {
+ set sender [lindex $args 0]; # NOTE: Disposal.
+ set e [lindex $args 1]; # NOTE: Disposal.
+ } else {
+ variable widgets; destroy $widgets(toplevel)
+ }
+
+ #
+ # NOTE: Terminate the [vwait].
+ #
+ set [appendArgs [namespace current] ::forever] 1
+ }
+
+ #
+ # NOTE: This procedure is an event handler. It handles the submit button in
+ # both Tk and Eagle. It starts the package submission process. The
+ # args argument is not really used, it is a placeholder to make this
+ # procedure more portable between Tcl and Eagle. This procedure may
+ # raise script errors.
+ #
+ proc submitEventHandler { args } {
+ variable argumentData
+
+ set batchMode [lindex $args 0]
+
+ if {[isEagle]} then {
+ set sender [lindex $args 1]; # NOTE: Disposal.
+ set e [lindex $args 2]; # NOTE: Disposal.
+ }
+
+ if {[haveArgumentData]} then {
+ set apiKey $argumentData(apiKey)
+ set package $argumentData(package)
+ set patchLevel $argumentData(patchLevel)
+ set language $argumentData(language)
+ set version $argumentData(version)
+ set platform $argumentData(platform)
+ set fileNames $argumentData(fileNames)
+
+ ::PackageRepository::probeForOpenPgpInstallation
+ ::PackageRepository::openPgpMustBeInstalled
+
+ if {1} then {
+ stagePackageFiles \
+ [string tolower $language] $version $platform $fileNames
+
+ if {![commitPackageFiles \
+ $package $patchLevel [string totitle $language] $version \
+ checkin]} then {
+ error "failed to commit package files"
+ }
+
+ #
+ # TODO: Is this the best heuristic here for figuring out that the
+ # platform should really be "automatic" in the repository?
+ #
+ if {$platform eq "neutral" || \
+ $platform eq [::PackageDownloader::getPlatform]} then {
+ set scriptPlatform ""
+ } else {
+ set scriptPlatform $platform
+ }
+
+ set script [createRepositoryScript \
+ "" $checkin [string tolower $language] $version $scriptPlatform \
+ $fileNames [list]]
+
+ set scriptFileName [file join \
+ [::PackageRepository::getFileTempDirectory PKGR_UPLOAD_TEMP] \
+ [appendArgs pkgr_upload_ [::PackageRepository::getUniqueSuffix]]]
+
+ writeFile $scriptFileName $script
+
+ if {![::PackageRepository::createOpenPgpSignature \
+ $scriptFileName]} then {
+ error [appendArgs \
+ "cannot submit package metadata: OpenPGP signing of \"" \
+ $scriptFileName "\" failed"]
+ }
+
+ set certificate [readFile [appendArgs $scriptFileName .asc]]
+
+ set result [submitPackageMetadata \
+ $apiKey $package $patchLevel [string totitle $language] \
+ $script $certificate]
+
+ if {!$batchMode} then {
+ set title [appendArgs \
+ "Package Uploader Client: " [lindex [info level 0] 0]]
+
+ if {[string length $result] > 0} then {
+ set message [appendArgs \
+ "Package was submitted successfully: " $result]
+ } else {
+ set message "Package was submitted successfully."
+ }
+
+ if {[isEagle]} then {
+ catch {
+ object invoke MessageBox Show $message $title
+ }
+ } else {
+ catch {
+ tk_messageBox -type ok -message $message -title $title
+ }
+ }
+ }
+ }
+ } else {
+ error "cannot initiate package submission: one or more fields missing"
+ }
+ }
+
+ #
+ # NOTE: This procedure is an event handler. It handles the clear button in
+ # Tk and Eagle. It is used to clear the package submission data. The
+ # args argument is not really used, it is a placeholder to make this
+ # procedure more portable between Tcl and Eagle. This procedure may
+ # raise script errors.
+ #
+ proc clearEventHandler { args } {
+ variable argumentData
+
+ if {[isEagle]} then {
+ set sender [lindex $args 0]; # NOTE: Disposal.
+ set e [lindex $args 1]; # NOTE: Disposal.
+
+ variable widgets
+
+ $widgets(2) Text ""
+ $widgets(4) Text ""
+ $widgets(6) Text ""
+ $widgets(8) Text ""
+ $widgets(10) Text ""
+ $widgets(12) Text ""
+ $widgets(14) Items.Clear
+ } else {
+ set argumentData(apiKey) ""
+ set argumentData(package) ""
+ set argumentData(patchLevel) ""
+ set argumentData(language) ""
+ set argumentData(version) ""
+ set argumentData(platform) ""
+ }
+
+ #
+ # NOTE: This is done for Tk because it will also clear the on-screen
+ # widget itself. For Eagle, this is necessary because there is
+ # no "listvariable" option and clearing the on-screen widget has
+ # no impact on the underyling list.
+ #
+ set argumentData(fileNames) [list]
+ }
+
+ #
+ # NOTE: This procedure creates the user interface for this tool using Eagle
+ # and WinForms. The existing argument data, if any, will be used to
+ # populate it. There are no arguments.
+ #
+ proc setupWinFormsUserInterface {} {
+ variable argumentData
+ variable widgets
+
+ object load -import System.Windows.Forms
+
+ set form [object create -alias Form]
+ set widgets(0) $form
+
+ $form Text "Package Uploader Client"
+
+ ###########################################################################
+
+ set widgets(1) [object create -alias Label]
+ $widgets(1) Name lblApiKey
+ $widgets(1) Text "API Key"
+
+ ###########################################################################
+
+ set widgets(2) [object create -alias TextBox]
+
+ $widgets(2) Name txtApiKey
+ $widgets(2) Text $argumentData(apiKey)
+
+ $widgets(2) add_TextChanged [namespace code \
+ [list textBoxEventHandler [appendArgs [namespace current] \
+ ::argumentData(apiKey)]]]
+
+ ###########################################################################
+
+ set widgets(3) [object create -alias Label]
+ $widgets(3) Name lblPackage
+ $widgets(3) Text "Package Name"
+
+ ###########################################################################
+
+ set widgets(4) [object create -alias TextBox]
+
+ $widgets(4) Name txtPackage
+ $widgets(4) Text $argumentData(package)
+
+ $widgets(4) add_TextChanged [namespace code \
+ [list textBoxEventHandler [appendArgs [namespace current] \
+ ::argumentData(package)]]]
+
+ ###########################################################################
+
+ set widgets(5) [object create -alias Label]
+ $widgets(5) Name lblPatchLevel
+ $widgets(5) Text "Package Patch Level"
+
+ ###########################################################################
+
+ set widgets(6) [object create -alias TextBox]
+
+ $widgets(6) Name txtPatchLevel
+ $widgets(6) Text $argumentData(patchLevel)
+
+ $widgets(6) add_TextChanged [namespace code \
+ [list textBoxEventHandler [appendArgs [namespace current] \
+ ::argumentData(patchLevel)]]]
+
+ ###########################################################################
+
+ set widgets(7) [object create -alias Label]
+ $widgets(7) Name lblLanguage
+ $widgets(7) Text Language
+
+ ###########################################################################
+
+ set widgets(8) [object create -alias TextBox]
+
+ $widgets(8) Name txtLanguage
+ $widgets(8) Text $argumentData(language)
+
+ $widgets(8) add_TextChanged [namespace code \
+ [list textBoxEventHandler [appendArgs [namespace current] \
+ ::argumentData(language)]]]
+
+ ###########################################################################
+
+ set widgets(9) [object create -alias Label]
+ $widgets(9) Name lblVersion
+ $widgets(9) Text Version
+
+ ###########################################################################
+
+ set widgets(10) [object create -alias TextBox]
+
+ $widgets(10) Name txtVersion
+ $widgets(10) Text $argumentData(version)
+
+ $widgets(10) add_TextChanged [namespace code \
+ [list textBoxEventHandler [appendArgs [namespace current] \
+ ::argumentData(version)]]]
+
+ ###########################################################################
+
+ set widgets(11) [object create -alias Label]
+ $widgets(11) Name lblPlatform
+ $widgets(11) Text Platform
+
+ ###########################################################################
+
+ set widgets(12) [object create -alias TextBox]
+
+ $widgets(12) Name txtPlatform
+ $widgets(12) Text $argumentData(platform)
+
+ $widgets(12) add_TextChanged [namespace code \
+ [list textBoxEventHandler [appendArgs [namespace current] \
+ ::argumentData(platform)]]]
+
+ ###########################################################################
+
+ set widgets(13) [object create -alias Label]
+ $widgets(13) Name lblFileNames
+ $widgets(13) Text Files
+
+ ###########################################################################
+
+ set widgets(14) [object create -alias ListBox]
+ $widgets(14) Name lstFileNames
+
+ $widgets(14) add_DoubleClick [namespace code \
+ [list listBoxEventHandler [appendArgs [namespace current] \
+ ::argumentData(fileNames)]]]
+
+ ###########################################################################
+
+ set widgets(15) [object create -alias Button]
+ $widgets(15) Name btnSubmit
+ $widgets(15) Text Submit
+ $widgets(15) add_Click [namespace code [list submitEventHandler false]]
+
+ ###########################################################################
+
+ set widgets(16) [object create -alias Button]
+ $widgets(16) Name btnClear
+ $widgets(16) Text Clear
+ $widgets(16) add_Click [namespace code [list clearEventHandler]]
+
+ ###########################################################################
+
+ set horizontalMargin \
+ [expr {([$form Width] - [$form ClientSize.Width]) / 2}]
+
+ set verticalMargin \
+ [expr {([$form Height] - [$form ClientSize.Height]) / 2}]
+
+ ###########################################################################
+
+ set top $verticalMargin
+
+ foreach name [lsort -integer [array names widgets]] {
+ if {$name eq "0"} then continue
+
+ $widgets($name) Width [expr {
+ [$form ClientSize.Width] - ($horizontalMargin * 2)
+ }]
+
+ $widgets($name) Left $horizontalMargin
+ $widgets($name) Top $top
+ $form Controls.Add $widgets($name)
+
+ incr top [$widgets($name) Height]
+ incr top $verticalMargin
+ }
+
+ $form add_Closed [namespace code [list handleFormClosedEvent]]
+ $form MaximizeBox false
+ $form AutoSize true
+ $form Show
+
+ after 0 [list nop]; # NOTE: Needed for the [vwait].
+ }
+
+ #
+ # NOTE: This procedure creates the user interface for this tool using Tcl
+ # and Tk. The existing argument data, if any, will be used to
+ # populate it. There are no arguments.
+ #
+ proc setupTkUserInterface {} {
+ variable widgets
+
+ package require Tk
+ catch {console show}
+
+ catch {wm withdraw .}; set toplevel [toplevel .uploader]
+ set widgets(toplevel) $toplevel
+
+ wm title $toplevel "Package Uploader Client"
+ wm minsize $toplevel 250 0
+
+ wm protocol $toplevel WM_DELETE_WINDOW \
+ [namespace code [list handleFormClosedEvent]]
+
+ ###########################################################################
+
+ set widgets(label,apiKey) [label [appendArgs \
+ $toplevel .la_apiKey] -text "API Key"]
+
+ ###########################################################################
+
+ set widgets(entry,apiKey) [entry [appendArgs \
+ $toplevel .e_apiKey] -textvariable [appendArgs \
+ [namespace current] ::argumentData(apiKey)]]
+
+ ###########################################################################
+
+ set widgets(label,package) [label [appendArgs \
+ $toplevel .la_package] -text "Package Name"]
+
+ ###########################################################################
+
+ set widgets(entry,package) [entry [appendArgs \
+ $toplevel .e_package] -textvariable [appendArgs \
+ [namespace current] ::argumentData(package)]]
+
+ ###########################################################################
+
+ set widgets(label,patchLevel) [label [appendArgs \
+ $toplevel .la_patchLevel] -text "Package Patch Level"]
+
+ ###########################################################################
+
+ set widgets(entry,patchLevel) [entry [appendArgs \
+ $toplevel .e_patchLevel] -textvariable [appendArgs \
+ [namespace current] ::argumentData(patchLevel)]]
+
+ ###########################################################################
+
+ set widgets(label,language) [label [appendArgs \
+ $toplevel .la_language] -text Language]
+
+ ###########################################################################
+
+ set widgets(entry,language) [entry [appendArgs \
+ $toplevel .e_language] -textvariable [appendArgs \
+ [namespace current] ::argumentData(language)]]
+
+ ###########################################################################
+
+ set widgets(label,version) [label [appendArgs \
+ $toplevel .la_version] -text Version]
+
+ ###########################################################################
+
+ set widgets(entry,version) [entry [appendArgs \
+ $toplevel .e_version] -textvariable [appendArgs \
+ [namespace current] ::argumentData(version)]]
+
+ ###########################################################################
+
+ set widgets(label,platform) [label [appendArgs \
+ $toplevel .la_platform] -text Platform]
+
+ ###########################################################################
+
+ set widgets(entry,platform) [entry [appendArgs \
+ $toplevel .e_platform] -textvariable [appendArgs \
+ [namespace current] ::argumentData(platform)]]
+
+ ###########################################################################
+
+ set widgets(label,fileNames) [label [appendArgs \
+ $toplevel .la_fileNames] -text Files]
+
+ ###########################################################################
+
+ set widgets(listbox,fileNames) [listbox [appendArgs \
+ $toplevel .li_fileNames] -listvariable [appendArgs \
+ [namespace current] ::argumentData(fileNames)]]
+
+ bind $widgets(listbox,fileNames) \
+ [namespace code [list listBoxEventHandler [appendArgs \
+ [namespace current] ::argumentData(fileNames)]]]
+
+ ###########################################################################
+
+ set widgets(button,submit) [button \
+ [appendArgs $toplevel .b_submit] -text Submit -command \
+ [namespace code [list submitEventHandler false]]]
+
+ ###########################################################################
+
+ set widgets(button,clear) [button \
+ [appendArgs $toplevel .b_clear] -text Clear -command \
+ [namespace code [list clearEventHandler]]]
+
+ ###########################################################################
+
+ pack $widgets(label,apiKey) $widgets(entry,apiKey) \
+ $widgets(label,package) $widgets(entry,package) \
+ $widgets(label,patchLevel) $widgets(entry,patchLevel) \
+ $widgets(label,language) $widgets(entry,language) \
+ $widgets(label,version) $widgets(entry,version) \
+ $widgets(label,platform) $widgets(entry,platform) \
+ $widgets(label,fileNames) $widgets(listbox,fileNames) \
+ $widgets(button,submit) $widgets(button,clear) \
+ -expand true -fill both
+
+ pack $widgets(button,submit) $widgets(button,clear) \
+ -anchor e -expand false -fill none
+ }
+
+ #
+ # NOTE: This package requires both the package repository and downloader
+ # client packages.
+ #
+ package require Eagle.Package.Repository
+ package require Eagle.Package.Downloader
+
+ #
+ # NOTE: This package requires that support for namespaces, which is an
+ # optional feature of Eagle, must be enabled.
+ #
+ if {[isEagle] && ![namespace enable]} then {
+ error "namespaces must be enabled for this package"
+ }
+
+ #
+ # 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 package.
+ #
+ setupUploadVars
+ setupCheckoutVars
+
+ #
+ # NOTE: Provide the package to the interpreter.
+ #
+ package provide Eagle.Package.Uploader \
+ [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
+}
+
ADDED client/1.0/neutral/pkgu.eagle.asc
Index: client/1.0/neutral/pkgu.eagle.asc
==================================================================
--- client/1.0/neutral/pkgu.eagle.asc
+++ client/1.0/neutral/pkgu.eagle.asc
@@ -0,0 +1,18 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+Comment: Eagle Package Repository
+
+iQIcBAABCAAGBQJYXa9dAAoJEFAslq9JXcLZw64QAIfsDz2hFHLg2C7Vd4lHtiAb
+OBH7+p73HDGCr1lmnyKUpMYjcztbWsqsFtuY2iPXcJgjoaNsSK/+MAkDL+LbDiMF
+oMyb3tWTu70nOei8WR0hR7uCwvdoxiXXOBGn7KZmBqWWdyvTW3W/D5I4idbgiL1x
+iIhOn4L2EHvdRNPKzoEUUcKroVyzijdtNcHRBAQLxjbmh5Tr6FpnHvx1Ao7k1yUM
+tHHukhtG3rYzhREq1RJ7canfLvufxu8tFwvg1DoI087p+ckwoyYuD4edQC+5+7wv
+Q/xEsnl5+MU6nv9wJz+vXZZelazg78OI/D223T5bKOppUvlV1Oa9IoQEos6hBZk4
+rFVoIzWXQiMQwd8eNKJ2/yeh4wJVtt96eYg0RI+ZKW3qwWsQjd8DJOLXk664wPSO
+dDCxqgPB/5Ak8Prz2JSnkWWFVlBdyg5xjEEPdszqvqFT463nIO9RlyJdkpHBlhLT
+8hzn3RG6KNrZSrKsOjyqxeu1h7fITZmnyvb8Cb8OTVXd9KDqQ3mJ0YyGT4Z5SgtX
+7t61ntYtVNyw0gA8gTOjBw12EmCEXgKLdGI3iBYhw5qz2YMULiMTrW8VmaJHJa3U
+Fq1uhcJCbYKiZmYUvcnWN4OSC73K/Ly3aNgYYdBc9aDI8rh1ZLeZDWR15zpv4ZvG
+NpAE1BF+Aayq3KRzg9l0
+=cuQY
+-----END PGP SIGNATURE-----
ADDED client/1.0/neutral/pkgu.eagle.harpy
Index: client/1.0/neutral/pkgu.eagle.harpy
==================================================================
--- client/1.0/neutral/pkgu.eagle.harpy
+++ client/1.0/neutral/pkgu.eagle.harpy
@@ -0,0 +1,68 @@
+
+
+
+ None
+ Mistachkin Systems
+ 0a536d27-985f-4b13-875f-b70633697684
+ SHA512
+ Script
+ 2016-12-23T23:11:47.9423828Z
+ -1.00:00:00
+ 0x9559f6017247e3e2
+
+ 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
+
+
ADDED client/1.0/neutral/pkgu.eagle.harpy.asc
Index: client/1.0/neutral/pkgu.eagle.harpy.asc
==================================================================
--- client/1.0/neutral/pkgu.eagle.harpy.asc
+++ client/1.0/neutral/pkgu.eagle.harpy.asc
@@ -0,0 +1,18 @@
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v2
+Comment: Eagle Package Repository
+
+iQIcBAABCAAGBQJYXa9fAAoJEFAslq9JXcLZLmIP/jTeQFPUUzN467WNmzN9eaQz
+FnSQk1Z31Z1HEaX3q6VT4Yy4sXXPmRUnwd/uoFpC+ap1WxGmuPz+ncJRI1r8nsY4
+2Q4UQecNbWobioerq41GkhHjuxiHNvsxcGJrbBKjVAKOGaHEs8Ee2KNe8/gCXXAB
+RwJpzdyHc2eAvmXEgokch2Nq9uhTW9dFqTFNwjlwwRlSyHFU9ghiNbYV/+rvpnWu
+f8F0GiCsp8mqkERFWuZnEsU7yc5Ull6QBpIOdOuDfWQby2I0/lA6ZwQ/lNPOQZ1a
+6NShCX1TgBjWs7/IIvfULPeyzfsA57p1XLz86zmejcmwG6ejcwJTvx4u8S9FvBNE
+lCppbWZRuhkZznqy6c//1eP0aLm8WHVMm7uo6aA1FQi2PWm2nds4ne2/+1R4c5zM
+LKYGa9XNy4E6eTBqBS0cARhOvIptkU1qIXQPdHf6FEh85LB3Mc2/dKG3EnHfR7Vo
+O2xcOSgt35BxALVEalZUaOHbYOv5C7NAqA6/W2iI/ZZPRqzhNqdhe0gWOrivhQcy
+N2N9C88f0NccSaGuhj6x71bvN2m3BFIC1B+eS+nkMqsKPoJZhDGhjHLRV7oQ0bCW
+ueQMq1UIsmmx/e/0suQ4YFzZGuuGwUyzzeIR+opVCN8ltQvKkty3dcAU9P7AQkxy
+dvKjU/W2G/3c64mBHgZA
+=jscJ
+-----END PGP SIGNATURE-----