pluginmgr/pluginmgr.tcl
Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 package require Tcl 8.4
00027 package require snit
00028 
00029 
00030 
00031 
00032 snit::type ::pluginmgr {
00033 
00034     
00035     
00036 
00037     
00038     
00039     
00040     
00041     
00042     
00043     
00044     
00045 
00046     option -pattern {}
00047     option -api     {}
00048     option -check   {}
00049     option -cmds    {}
00050     option -cmdip   {}
00051     option -up =    {}
00052 
00053     
00054     
00055 
00056     ret  do (type args) {
00057     if {$plugin eq ""} {
00058         return -code error "No plugin defined"
00059     }
00060     return [$sip eval $args]
00061     }
00062 
00063     ret  interpreter () {
00064     return $sip
00065     }
00066 
00067     ret  plugin () {
00068     return $plugin
00069     }
00070 
00071     ret  load (type name) {
00072     if {$name eq $plugin} return
00073 
00074     if {$options(-pattern) eq ""} {
00075         return -code error "Translation pattern is not configured"
00076     }
00077 
00078     set save $sip
00079 
00080     $self SetupIp
00081     if {![$self LoadPlugin $name]} {
00082         set sip $save
00083         return -code error "Unable to locate plugin \"$name\""
00084     }
00085 
00086     if {![$self CheckAPI missing]} {
00087         set sip $save
00088         return -code error \
00089             "Cannot use plugin \"$name\", API incomplete: \"$missing\" missing"
00090     }
00091 
00092     set savedname $plugin
00093     set plugin    $name
00094     if {![$self CheckExternal]} {
00095         set sip    $save
00096         set plugin $savedname
00097         return -code error \
00098             "Cannot use plugin \"$name\", API bad"
00099     }
00100     $self SetupExternalCmds
00101 
00102     if {$save ne ""} {interp delete $save}
00103     return
00104     }
00105 
00106     ret  unload () {
00107     if {$sip eq ""} return
00108     interp delete $sip
00109     set sip    ""
00110     set plugin ""
00111     return
00112     }
00113 
00114     ret  list () {
00115     if {$options(-pattern) eq ""} {
00116         return -code error "Translation pattern is not configured"
00117     }
00118 
00119     set save $sip
00120     $self SetupIp
00121 
00122     set result {}
00123     set pattern [string map [list \
00124         +  \\+  ?  \\?    \
00125         \[ \\\[ \] \\\]   \
00126         (  \\(  )  \\)    \
00127         . \\. \ *  {(.*)} \
00128         ] $options(-pattern)]
00129 
00130     # @mdgen NODEP: bogus-package
00131     $sip eval {catch {package require bogus-package}}
00132     foreach p [$sip eval {package names}] {
00133         if {![regexp $pattern $p -> plugin]} continue
00134         lappend result $plugin
00135     }
00136 
00137     interp delete $sip
00138     set sip $save
00139     return $result
00140     }
00141 
00142     ret  path (type path) {
00143     set path [file join [pwd] $path]
00144     if {[lsearch -exact $paths $path] < 0} {
00145         lappend paths $path
00146     }
00147     return
00148     }
00149 
00150     ret  paths () {
00151     return $paths
00152     }
00153 
00154     ret  clone () {
00155     set o [$type create %AUTO% \
00156         -pattern $options(-pattern) \
00157         -api     $options(-api)    \
00158         -check   $options(-check) \
00159         -cmds    $options(-cmds) \
00160         -cmdip   $options(-cmdip) \
00161         -setup   $options(-setup)]
00162 
00163     $o __clone__ $paths $sip $plugin
00164 
00165     # Clone has become owner of the interp.
00166     set sip    {}
00167     set plugin {}
00168 
00169     return $o
00170     }
00171 
00172     ret  __clone__ (_type paths _, type sip _, type plugin) {
00173     set paths  $_paths
00174     set sip    $_sip
00175     set plugin $_plugin
00176     return
00177     }
00178 
00179     
00180     
00181 
00182     variable paths  {} ; 
00183     variable sip    {} ; 
00184     variable plugin {} ; 
00185 
00186     
00187     
00188 
00189     constructor {args} {
00190     $self configurelist $args
00191     return
00192     }
00193 
00194     destructor {
00195     if {$sip ne ""} {interp delete $sip}
00196     return
00197     }
00198 
00199     
00200     
00201 
00202     onconfigure -pattern {newvalue} {
00203      current =  $options(-pattern)
00204     if {$newvalue eq $current} return
00205 
00206      n =  [regexp -all "\\*" $newvalue]
00207     if {$n < 1} {
00208         return -code error "Invalid pattern, * missing"
00209     } elseif {$n > 1} {
00210         return -code error "Invalid pattern, too many *'s"
00211     }
00212 
00213      options = (-pattern) $newvalue
00214     return
00215     }
00216 
00217     onconfigure -api {newvalue} {
00218      current =  $options(-api)
00219     if {$newvalue eq $current} return
00220      options = (-api) $newvalue
00221     return
00222     }
00223 
00224     onconfigure -cmds {newvalue} {
00225      current =  $options(-cmds)
00226     if {$newvalue eq $current} return
00227      options = (-cmds) $newvalue
00228     return
00229     }
00230 
00231     onconfigure -cmdip {newvalue} {
00232      current =  $options(-cmdip)
00233     if {$newvalue eq $current} return
00234      options = (-cmdip) $newvalue
00235     return
00236     }
00237 
00238 
00239     
00240     
00241 
00242     ret  SetupIp () {
00243     set sip [::safe::interpCreate]
00244     foreach p $paths {
00245         ::safe::interpAddToAccessPath $sip $p
00246     }
00247 
00248     if {![llength $options(-setup)]} return
00249     uplevel \#0 [linsert $options(-setup) end $self $sip]
00250     return
00251     }
00252 
00253     ret  LoadPlugin (type name) {
00254     if {[file exists $name]} {
00255         # Plugin files are loaded directly.
00256 
00257         $sip invokehidden source $name
00258         return 1
00259     }
00260 
00261     # Otherwise the name is transformed into a package name
00262     # and loaded thorugh the package management.
00263 
00264     set pluginpackage [string map \
00265         [list * $name] $options(-pattern)]
00266     if {[catch {
00267         $sip eval [list package require $pluginpackage]
00268     } res]} {
00269         return 0
00270     }
00271     return 1
00272     }
00273 
00274     ret  CheckAPI (type mv) {
00275     upvar 1 $mv missing
00276     if {![llength $options(-api)]} {return 1}
00277 
00278     # Check the plugin for useability.
00279 
00280     foreach p $options(-api) {
00281         if {[llength [$sip eval [list info commands $p]]] == 1} continue
00282         interp delete $sip
00283         set missing $p
00284         return 0
00285     }
00286     return 1
00287     }
00288 
00289     ret  CheckExternal () {
00290     if {![llength $options(-check)]} {return 1}
00291     return [uplevel \#0 [linsert $options(-check) end $self]]
00292     }
00293 
00294 
00295     ret  SetupExternalCmds () {
00296     if {![llength $options(-cmds)]} return
00297 
00298     set cip $options(-cmdip)
00299     foreach {pcmd ecmd} $options(-cmds) {
00300         eval [linsert $ecmd 0 interp alias $sip $pcmd $cip]
00301         #interp alias $sip $pcmd $cip {*}$ecmd
00302     }
00303     return
00304     }
00305 
00306     
00307 
00308     ret  paths (type pmgr , type args) {
00309     if {[llength $args] == 0} {
00310         return -code error "wrong#args: Expect \"[info level 0] object name...\""
00311     }
00312     foreach name $args {
00313         AddPaths $pmgr $name
00314     }
00315     return
00316     }
00317 
00318     ret  AddPaths (type pmgr , type name) {
00319     global env tcl_platform
00320 
00321     if {$tcl_platform(platform) eq "windows"} {
00322         set sep \;
00323     } else {
00324         set sep :
00325     }
00326 
00327     #puts "$pmgr += ($name) $sep"
00328 
00329     regsub -all {::+} $name \000 name
00330     set name [split $name \000]
00331 
00332     # Environment variables
00333 
00334     set prefix {}
00335     foreach part $name {
00336         lappend prefix $part
00337         set ev [string toupper [join $prefix _]]_PLUGINS
00338 
00339         #puts "+? env($ev)"
00340 
00341         if {[info exists env($ev)]} {
00342         foreach path [split $env($ev) $sep] {
00343             $pmgr path $path
00344         }
00345         }
00346     }
00347 
00348     # Windows registry
00349 
00350     if {
00351         ($tcl_platform(platform) eq "windows") &&
00352         ![catch {package require registry}]
00353     } {
00354         foreach root {
00355         HKEY_LOCAL_MACHINE
00356         HKEY_CURRENT_USER
00357         } {
00358         set prefix {}
00359         foreach part $name {
00360             lappend prefix $part
00361             set rk $root\\SOFTWARE\\[join $prefix \\]PLUGINS
00362 
00363             #puts "+? registry($rk)"
00364 
00365             if {![catch {set data [registry get $rk {}]}]} {
00366             foreach path [split $data $sep] {
00367                 $pmgr path $path
00368             }
00369             }
00370         }
00371         }
00372     }
00373 
00374     # Home directory dot path
00375 
00376     set prefix {}
00377     foreach part $name {
00378         lappend prefix $part
00379         set pd [file join ~ .[join $prefix /] plugin]
00380 
00381         #puts "+? path($pd)"
00382 
00383         if {[file exists $pd]} {
00384         $pmgr path $pd
00385         }
00386     }
00387     return
00388     }
00389 }
00390 
00391 
00392 
00393 
00394 package provide pluginmgr 0.1
00395