###############################################################################
#
# pkgr_install.eagle --
#
# Extensible Adaptable Generalized Logic Engine (Eagle)
# Package Repository Client (Package Installer)
#
# 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 ::PackageInstaller {
#
# NOTE: This procedure is used to report errors that prevent this tool
# from running to completion (e.g. invalid command line arguments,
# etc). It may be used to report a specific error. It will always
# emit the command line usage information.
#
proc usage { {error ""} } {
if {[string length $error] > 0} then {puts stdout $error}
puts stdout "usage:\
[file tail [info nameofexecutable]]\
[file tail [info script]] <apiKey> <name> \[version\] \[language\]"
exit 1
}
#
# 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
# directory as the current script file.
#
variable pkgr_path; # DEFAULT: <unset>
if {![info exists pkgr_path]} then {
set pkgr_path [file normalize [file dirname [info script]]]
if {![info exists ::auto_path] || \
[lsearch -exact $::auto_path $pkgr_path] == -1} then {
lappend ::auto_path $pkgr_path
}
}
#
# NOTE: *TODO* Pre-create the namespace for the Package Repository Client
# package and then forcibly adjust various settings to the values
# necessary for this tool. In the future, this section may need to
# be tweaked to account for changes to the Package Repository Client
# package.
#
namespace eval ::PackageRepository {
variable autoHook true
variable autoLoadTcl false
variable autoRequireGaruda false
variable verboseUnknownResult true
variable verboseUriDownload true
}
#
# NOTE: *TODO* Pre-create the namespace for the Package Downloader Client
# package and then forcibly adjust various settings to the values
# necessary for this tool. In the future, this section may need to
# be tweaked to account for changes to the Package Downloader Client
# package. Technically, the package being handled by this tool may
# not actually use the downloader; however, if it does, this should
# make sure the downloaded package files are persisted locally.
#
namespace eval ::PackageDownloader {
variable quiet false
variable viaInstall true
}
#
# NOTE: Load the Package Repository Client package now. This will install
# the [package unknown] hook and prepare it for use.
#
package require Eagle.Package.Repository
#
# NOTE: Verify that the number of command line arguments meets the basic
# requirements of this tool.
#
if {[info exists ::argv] && \
[llength $::argv] >= 2 && [llength $::argv] <= 4} then {
#
# NOTE: Get the API key. This is always required. If this API key is
# not valid or cannot be found by the server, execution of this
# tool will fail.
#
set apiKey [lindex $::argv 0]
#
# NOTE: Get the package name. This is always required. If this package
# name is invalid or cannot be found by the server, execution of
# this tool will fail.
#
set package [lindex $::argv 1]
#
# NOTE: Grab the package version (or requirement?). This is optional.
# If this package version is specified, it must conform with TIP
# #268 when the target language is native Tcl. For Eagle, only
# the dotted decimal version syntax, with between 2 to 4 numbers,
# is supported.
#
if {[llength $::argv] >= 3} then {
set version [lindex $::argv 2]
if {[isEagle] && ![string is version -strict $version]} then {
set pattern {^\d+\.\d+(?:\.\d+){0,2}$}
error [appendArgs \
"version must match regular expression: " $pattern]
}
} else {
set version ""
}
#
# NOTE: Grab the target language. This is optional. Without this, it
# is assumed that the target language is the one evaluating the
# current script file. The only supported target languages are
# native Tcl ("Tcl") and Eagle ("Eagle"), both case-sensitive.
# If the target language differs from the current language, this
# tool will attempt to gain access to the target language and a
# script error will be raised if that attempt fails.
#
if {[llength $::argv] >= 4} then {
set language [lindex $::argv 3]
} else {
set language ""
}
#
# NOTE: If the target language was specified, attempt to gain access to
# it, if necessary. If the current language matches the target
# language, nothing is done.
#
if {[string length $language] > 0} then {
switch -exact -- $language {
Eagle {
if {![isEagle]} then {
::PackageRepository::makeEagleReady
}
}
Tcl {
if {[isEagle]} then {
::PackageRepository::makeTclReady
}
}
default {
error "unsupported language: must be Tcl or Eagle"
}
}
}
#
# NOTE: If a non-empty API key was specified on the command line then
# add it to the global list now.
#
if {[string length $apiKey] > 0} then {
lappend ::pkgr_api_keys $apiKey
}
#
# NOTE: For Eagle, make sure that the [package unknown] handler will be
# used for the current interpreter.
#
if {[isEagle]} then {
object invoke -flags +NonPublic Interpreter.GetActive InterpreterFlags \
[appendArgs [object invoke -flags +NonPublic Interpreter.GetActive \
InterpreterFlags] " -NoPackageUnknown"]
}
#
# NOTE: Attempt to require the target package now. If this succeeds
# -AND- the Package Downloader Client was used, the package will
# be persisted locally; otherwise, the [package ifneeded] script
# may still be evaluated; however, the effects may not actually
# cause anything to persist.
#
if {[string length $version] > 0} then {
set result [package require $package $version]
} else {
set result [package require $package]
}
puts stdout [appendArgs "package require result: " $result]
} else {
usage
}
}