#punkapps app manager # deck cli namespace eval punk::mod::cli { namespace export help list run namespace ensemble create # namespace ensemble configure [namespace current] -unknown punk::mod::cli::_unknown if 0 { proc _unknown {ns args} { puts stderr "punk::mod::cli::_unknown '$ns' '$args'" puts stderr "punk::mod::cli::help $args" puts stderr "arglen:[llength $args]" punk::mod::cli::help {*}$args } } #cli must have _init method - usually used to load commandsets lazily # variable initialised 0 proc _init {args} { variable initialised if {$initialised} { return } #... set initialised 1 } proc help {args} { set basehelp [punk::mix::base help {*}$args] #namespace export return $basehelp } proc getraw {appname} { set app_folders [punk::config::configure running apps] #todo search each app folder set bases [::list] set versions [::list] set mains [::list] set appinfo [::list bases {} mains {} versions {}] foreach containerfolder $app_folders { lappend bases $containerfolder if {[file exists $containerfolder]} { if {[file exists $containerfolder/$appname/main.tcl]} { #exact match - only return info for the exact one specified set namematches $appname set parts [split $appname -] } else { set namematches [glob -nocomplain -dir $containerfolder -type d -tail ${appname}-*] set namematches [lsort $namematches] ;#todo - -ascii? -dictionary? natsort? } foreach nm $namematches { set mainfile $containerfolder/$nm/main.tcl set parts [split $nm -] if {[llength $parts] == 1} { set ver "" } else { set ver [lindex $parts end] } if {$ver ni $versions} { lappend versions $ver lappend mains $ver $mainfile } else { puts stderr "punk::apps::app version '$ver' of app '$appname' already encountered at $mainfile. (will use earliest encountered in running-config apps and ignore others of same version)" } } } else { puts stderr "punk::apps::app missing apps_folder:'$containerfolder' Ensure apps_folder is set in punk::config" } } dict set appinfo versions $versions #todo - natsort! set sorted_versions [lsort $versions] set latest [lindex $sorted_versions 0] if {$latest eq "" && [llength $sorted_versions] > 1} { set latest [lindex $sorted_versions 1] } dict set appinfo latest $latest dict set appinfo bases $bases dict set appinfo mains $mains return $appinfo } proc list {{glob *}} { set apps_folder [punk::config::configure running apps] if {[file exists $apps_folder]} { if {[file exists $apps_folder/$glob]} { #tailcall source $apps_folder/$glob/main.tcl return $glob } set apps [glob -nocomplain -dir $apps_folder -type d -tail $glob] if {[llength $apps] == 0} { if {[string first * $glob] <0 && [string first ? $glob] <0} { #no glob chars supplied - only launch if exact match for name part set namematches [glob -nocomplain -dir $apps_folder -type d -tail ${glob}-*] set namematches [lsort $namematches] ;#todo - -ascii? -dictionary? natsort? if {[llength $namematches] > 0} { set latest [lindex $namematches end] lassign $latest nm ver #tailcall source $apps_folder/$latest/main.tcl } } } return $apps } } #todo - way to launch as separate process # solo-opts only before appname - args following appname are passed to the app proc run {args} { set nameposn [lsearch -not $args -*] if {$nameposn < 0} { error "punkapp::run unable to determine application name" } set appname [lindex $args $nameposn] set controlargs [lrange $args 0 $nameposn-1] set appargs [lrange $args $nameposn+1 end] set appinfo [punk::mod::cli::getraw $appname] if {[llength [dict get $appinfo versions]]} { set ver [dict get $appinfo latest] puts stdout "info: $appinfo" set ::argc [llength $appargs] set ::argv $appargs source [dict get $appinfo mains $ver] if {"-hideconsole" in $controlargs} { puts stderr "attempting console hide" #todo - something better - a callback when window mapped? after 500 {::punkapp::hide_console} } return $appinfo } else { error "punk::mod::cli unable to run '$appname'. main.tcl not found in [dict get $appinfo bases]" } } } namespace eval punk::mod::cli { proc _cli {args} { #don't use tailcall - base uses info level to determine caller ::punk::mix::base::_cli {*}$args } variable default_command help package require punk::mix::base package require punk::overlay punk::overlay::custom_from_base [namespace current] ::punk::mix::base } package provide punk::mod [namespace eval punk::mod { variable version set version 0.1 }]