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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 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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 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-----