Julian Noble
1 year ago
11 changed files with 478 additions and 0 deletions
@ -0,0 +1,84 @@ |
|||||||
|
package provide punk::config [namespace eval punk::config { |
||||||
|
variable version |
||||||
|
set version 0.1 |
||||||
|
|
||||||
|
}] |
||||||
|
|
||||||
|
namespace eval punk::config { |
||||||
|
variable loaded |
||||||
|
variable startup ;#include env overrides |
||||||
|
variable running |
||||||
|
variable known_punk_env_vars |
||||||
|
|
||||||
|
|
||||||
|
variable vars |
||||||
|
set vars [list \ |
||||||
|
apps \ |
||||||
|
scriptlib \ |
||||||
|
color_stdout \ |
||||||
|
color_stderr \ |
||||||
|
logfile_stdout \ |
||||||
|
logfile_stderr \ |
||||||
|
syslog_stdout \ |
||||||
|
syslog_stderr \ |
||||||
|
exec_unknown \ |
||||||
|
] |
||||||
|
#todo pkg punk::config |
||||||
|
|
||||||
|
#defaults |
||||||
|
|
||||||
|
dict set startup exec_unknown true ;#whether to use exec instead of experimental shellfilter::run |
||||||
|
dict set startup color_stdout [list cyan bold] |
||||||
|
dict set startup color_stderr [list red bold] |
||||||
|
dict set startup syslog_stdout "127.0.0.1:514" |
||||||
|
dict set startup syslog_stderr "127.0.0.1:514" |
||||||
|
#default file logs to logs folder at same location as exe if writable, or empty string |
||||||
|
dict set startup logfile_stdout "" |
||||||
|
dict set startup logfile_stderr "" |
||||||
|
set exefolder [file dirname [info nameofexecutable]] |
||||||
|
set log_folder $exefolder/logs |
||||||
|
dict set startup scriptlib $exefolder/scriptlib |
||||||
|
dict set startup apps $exefolder/../punkapps |
||||||
|
if {[file exists $log_folder]} { |
||||||
|
if {[file isdirectory $log_folder] && [file writable $log_folder]} { |
||||||
|
dict set startup logfile_stdout $log_folder/repl-exec-stdout.txt |
||||||
|
dict set startup logfile_stderr $log_folder/repl-exec-stderr.txt |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#todo - load/write config file |
||||||
|
|
||||||
|
#env vars override the configuration |
||||||
|
|
||||||
|
#todo - define which configvars are settable in env |
||||||
|
set known_punk_env_vars [list \ |
||||||
|
PUNK_APPS \ |
||||||
|
PUNK_SCRIPTLIB \ |
||||||
|
PUNK_EXECUNKNOWN \ |
||||||
|
PUNK_COLOR_STDERR \ |
||||||
|
PUNK_COLOR_STDOUT \ |
||||||
|
PUNK_LOGFILE_STDOUT \ |
||||||
|
PUNK_LOGFILE_STDERR \ |
||||||
|
PUNK_SYSLOG_STDOUT \ |
||||||
|
PUNK_SYSLOG_STDERR \ |
||||||
|
] |
||||||
|
|
||||||
|
#override with env vars if set |
||||||
|
variable evar |
||||||
|
foreach evar $known_punk_env_vars { |
||||||
|
if {[info exists ::env($evar)]} { |
||||||
|
set f [set ::env($evar)] |
||||||
|
if {$f ne "default"} { |
||||||
|
#e.g PUNK_SCRIPTLIB -> scriptlib |
||||||
|
set varname [string tolower [string range $evar 5 end]] |
||||||
|
dict set startup $varname $f |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
unset -nocomplain evar |
||||||
|
unset -nocomplain vars |
||||||
|
|
||||||
|
set running [dict create] |
||||||
|
set running [dict merge $running $startup] |
||||||
|
} |
@ -0,0 +1,82 @@ |
|||||||
|
package provide punk::mix [namespace eval punk::mix { |
||||||
|
variable version |
||||||
|
set version 0.1 |
||||||
|
|
||||||
|
}] |
||||||
|
namespace eval punk::mix { |
||||||
|
proc runcli {args} { |
||||||
|
if {![llength $args]} { |
||||||
|
tailcall punk::mix::clicommands help |
||||||
|
} else { |
||||||
|
tailcall punk::mix::clicommands {*}$args |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
namespace eval punk::mix::clicommands { |
||||||
|
namespace export help new |
||||||
|
namespace ensemble create |
||||||
|
namespace ensemble configure [namespace current] -unknown punk::mix::clicommands::_unknown |
||||||
|
|
||||||
|
proc set_alias {cmdname} { |
||||||
|
uplevel #0 [list interp alias {} $cmdname {} punk::mix::runcli] |
||||||
|
} |
||||||
|
proc _unknown {ns args} { |
||||||
|
puts stderr "arglen:[llength $args]" |
||||||
|
puts stdout "_unknown '$ns' '$args'" |
||||||
|
|
||||||
|
list punk::mix::clicommands::help {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
proc new {name} { |
||||||
|
set curdir [pwd] |
||||||
|
if {[file exists $curdir/$name]} { |
||||||
|
error "Unable to create new project at $curdir/$name - file/folder already exists" |
||||||
|
} |
||||||
|
set base $curdir/$name |
||||||
|
file mkdir $base |
||||||
|
file mkdir $base/src |
||||||
|
file mkdir $base/modules |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
package require punk |
||||||
|
package require punk::mix_custom |
||||||
|
punk::ensemble::extend punk::mix::clicommands punk::mix_custom |
||||||
|
|
||||||
|
|
||||||
|
namespace eval punk::mix::clicommands { |
||||||
|
proc help {args} { |
||||||
|
#' **%ensemblecommand% help** *args* |
||||||
|
#' |
||||||
|
#' Help for ensemble commands in the command line interface |
||||||
|
#' |
||||||
|
#' |
||||||
|
#' Arguments: |
||||||
|
#' |
||||||
|
#' * args - first word of args is the helptopic requested - usually a command name |
||||||
|
#' - calling help with no arguments will list available commands |
||||||
|
#' |
||||||
|
#' Returns: help text (text) |
||||||
|
#' |
||||||
|
#' Examples: |
||||||
|
#' |
||||||
|
#' ``` |
||||||
|
#' %ensemblecommand% help <commandname> |
||||||
|
#' ``` |
||||||
|
#' |
||||||
|
#' |
||||||
|
|
||||||
|
|
||||||
|
set commands [namespace export] |
||||||
|
set helpstr "" |
||||||
|
append helpstr "commands:\n" |
||||||
|
foreach cmd $commands { |
||||||
|
append helpstr " $cmd" |
||||||
|
} |
||||||
|
return $helpstr |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
package provide punk::mix [namespace eval punk::mix { |
||||||
|
variable version |
||||||
|
set version 0.2 |
||||||
|
|
||||||
|
}] |
||||||
|
namespace eval punk::mix { |
||||||
|
proc runcli {args} { |
||||||
|
if {![llength $args]} { |
||||||
|
tailcall punk::mix::clicommands help |
||||||
|
} else { |
||||||
|
tailcall punk::mix::clicommands {*}$args |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
oo::object create punk::mix::clicommands |
||||||
|
|
||||||
|
oo::objdefine punk::mix::clicommands { |
||||||
|
#namespace ensemble configure [namespace current] -unknown punk::mix::clicommands::_unknown |
||||||
|
|
||||||
|
method set_alias {cmdname} { |
||||||
|
uplevel #0 [list interp alias {} $cmdname {} punk::mix::runcli] |
||||||
|
} |
||||||
|
#method _unknown {ns args} { |
||||||
|
# puts stderr "arglen:[llength $args]" |
||||||
|
# puts stdout "_unknown '$ns' '$args'" |
||||||
|
# |
||||||
|
# list punk::mix::clicommands::help {*}$args |
||||||
|
#} |
||||||
|
|
||||||
|
|
||||||
|
method new {name} { |
||||||
|
set curdir [pwd] |
||||||
|
if {[file exists $curdir/$name]} { |
||||||
|
error "Unable to create new project at $curdir/$name - file/folder already exists" |
||||||
|
} |
||||||
|
set base $curdir/$name |
||||||
|
file mkdir $base |
||||||
|
file mkdir $base/src |
||||||
|
file mkdir $base/modules |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
method help {args} { |
||||||
|
#' **%ensemblecommand% help** *args* |
||||||
|
#' |
||||||
|
#' Help for ensemble commands in the command line interface |
||||||
|
#' |
||||||
|
#' |
||||||
|
#' Arguments: |
||||||
|
#' |
||||||
|
#' * args - first word of args is the helptopic requested - usually a command name |
||||||
|
#' - calling help with no arguments will list available commands |
||||||
|
#' |
||||||
|
#' Returns: help text (text) |
||||||
|
#' |
||||||
|
#' Examples: |
||||||
|
#' |
||||||
|
#' ``` |
||||||
|
#' %ensemblecommand% help <commandname> |
||||||
|
#' ``` |
||||||
|
#' |
||||||
|
#' |
||||||
|
|
||||||
|
|
||||||
|
set commands [namespace export] |
||||||
|
set helpstr "" |
||||||
|
append helpstr "commands:\n" |
||||||
|
foreach cmd $commands { |
||||||
|
append helpstr " $cmd" |
||||||
|
} |
||||||
|
return $helpstr |
||||||
|
} |
||||||
|
|
||||||
|
unexport destroy |
||||||
|
} |
||||||
|
#package require punk |
||||||
|
#package require punk::mix_extension |
||||||
|
#punk::ensemble::extend punk::mix::clicommands punk::mix_extension |
||||||
|
|
@ -0,0 +1,14 @@ |
|||||||
|
#The directory for compiled/built Tcl modules |
||||||
|
/modules/ |
||||||
|
|
||||||
|
#Temporary files e.g from tests |
||||||
|
/tmp/ |
||||||
|
|
||||||
|
/logs/ |
||||||
|
|
||||||
|
#Built tclkits (if any) |
||||||
|
punk*.exe |
||||||
|
tcl*.exe |
||||||
|
|
||||||
|
#miscellaneous editor files etc |
||||||
|
*.swp |
@ -0,0 +1,66 @@ |
|||||||
|
package provide punk::clitemplate [namespace eval punk::clitemplate { |
||||||
|
variable version |
||||||
|
set version 0.1 |
||||||
|
|
||||||
|
}] |
||||||
|
namespace eval punk::clitemplate { |
||||||
|
|
||||||
|
proc runcli {args} { |
||||||
|
if {![llength $args]} { |
||||||
|
tailcall punk::clitemplate::clicommands help |
||||||
|
} else { |
||||||
|
tailcall punk::clitemplate::clicommands {*}$args |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
namespace eval punk::clitemplate::clicommands { |
||||||
|
variable last_alias "" |
||||||
|
namespace export help |
||||||
|
namespace ensemble create |
||||||
|
namespace ensemble configure [namespace current] -unknown punk::clitemplate::clicommands::_unknown |
||||||
|
|
||||||
|
proc set_alias {cmdname} { |
||||||
|
variable last_alias |
||||||
|
set last_alias $cmdname |
||||||
|
uplevel #0 [list interp alias {} $cmdname {} punk::clitemplate::runcli] |
||||||
|
} |
||||||
|
proc _unknown {ns args} { |
||||||
|
punk::clitemplate::clicommands::help {*}$args |
||||||
|
} |
||||||
|
|
||||||
|
proc help {args} { |
||||||
|
#' **%ensemblecommand% help** *args* |
||||||
|
#' |
||||||
|
#' Help for ensemble commands in the command line interface |
||||||
|
#' |
||||||
|
#' |
||||||
|
#' Arguments: |
||||||
|
#' |
||||||
|
#' * args - first word of args is the helptopic requested - usually a command name |
||||||
|
#' - calling help with no arguments will list available commands |
||||||
|
#' |
||||||
|
#' Returns: help text (text) |
||||||
|
#' |
||||||
|
#' Examples: |
||||||
|
#' |
||||||
|
#' ``` |
||||||
|
#' %ensemblecommand% help <commandname> |
||||||
|
#' ``` |
||||||
|
#' |
||||||
|
#' |
||||||
|
|
||||||
|
|
||||||
|
set commands [namespace export] |
||||||
|
set output "" |
||||||
|
append output "commands:\n |
||||||
|
foreach cmd $commands { |
||||||
|
append output " $cmd" |
||||||
|
} |
||||||
|
return $output |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
Identifier: %package% |
||||||
|
Version: %version% |
||||||
|
Title: %title% |
||||||
|
Creator: %name% <%email%> |
||||||
|
Description: %description% |
||||||
|
Rights: BSD |
||||||
|
URL: %url% |
||||||
|
Available: |
||||||
|
Architecture: tcl |
||||||
|
Subject: |
@ -0,0 +1,12 @@ |
|||||||
|
package provide punk::mix_custom [namespace eval punk::mix_custom { |
||||||
|
variable version |
||||||
|
set version 0.1 |
||||||
|
}] |
||||||
|
|
||||||
|
|
||||||
|
namespace eval punk::mix_custom { |
||||||
|
proc dostuff {args} { |
||||||
|
puts stdout doingstuff-$args |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
#punkapps app manager |
||||||
|
package provide punk::mod [namespace eval punk::mod { |
||||||
|
variable version |
||||||
|
set version 0.1 |
||||||
|
|
||||||
|
}] |
||||||
|
|
||||||
|
|
||||||
|
namespace eval punk::mod::cli { |
||||||
|
namespace export help list run |
||||||
|
namespace ensemble create |
||||||
|
|
||||||
|
namespace ensemble configure [namespace current] -unknown punk::mod::cli::_unknown |
||||||
|
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 |
||||||
|
} |
||||||
|
proc help {args} { |
||||||
|
namespace export |
||||||
|
} |
||||||
|
proc getraw {appname} { |
||||||
|
upvar ::punk::config::running running_config |
||||||
|
set app_folders [dict get $running_config 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 bases $bases |
||||||
|
dict set appinfo mains $mains |
||||||
|
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 |
||||||
|
return $appinfo |
||||||
|
} |
||||||
|
|
||||||
|
proc list {{glob *}} { |
||||||
|
upvar ::punk::config::running running_config |
||||||
|
set apps_folder [dict get $running_config 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 |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
proc run {appname} { |
||||||
|
set appinfo [punk::mod::cli::getraw $appname] |
||||||
|
if {[llength [dict get $appinfo versions]]} { |
||||||
|
set ver [dict get $appinfo latest] |
||||||
|
puts stdout "info: $appinfo" |
||||||
|
tailcall source [dict get $appinfo mains $ver] |
||||||
|
return $appinfo |
||||||
|
} else { |
||||||
|
error "punk::mod::cli unable to run '$appname'. main.tcl not found in [dict get $appinfo bases]" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue