|
|
|
@ -1,23 +1,109 @@
|
|
|
|
|
|
|
|
|
|
tcl::namespace::eval punk::config { |
|
|
|
|
variable loaded |
|
|
|
|
variable startup ;#include env overrides |
|
|
|
|
variable running |
|
|
|
|
variable configdata [dict create] ;#key on config names. At least default, startup, running |
|
|
|
|
|
|
|
|
|
#variable startup ;#include env overrides |
|
|
|
|
#variable running |
|
|
|
|
|
|
|
|
|
variable punk_env_vars |
|
|
|
|
variable other_env_vars |
|
|
|
|
|
|
|
|
|
variable vars |
|
|
|
|
|
|
|
|
|
namespace export {[a-z]*} |
|
|
|
|
namespace ensemble create |
|
|
|
|
namespace eval punk {namespace export config} |
|
|
|
|
|
|
|
|
|
proc _homedir {} { |
|
|
|
|
if {[info exists ::env(HOME)]} { |
|
|
|
|
set home [file normalize $::env(HOME)] |
|
|
|
|
} else { |
|
|
|
|
#not available on 8.6? ok will error out here. |
|
|
|
|
set home [file tildeexpand ~] |
|
|
|
|
} |
|
|
|
|
return $home |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
lappend PUNKARGS [list { |
|
|
|
|
@id -id ::punk::config::dir |
|
|
|
|
@cmd -name punk::config::dir -help\ |
|
|
|
|
"Get the path for the default config folder |
|
|
|
|
Config files are in toml format. |
|
|
|
|
|
|
|
|
|
The XDG_CONFIG_HOME env var is the preferred |
|
|
|
|
choice of location. |
|
|
|
|
A folder under the user's home directory, |
|
|
|
|
at .config/punk/shell is chosen if |
|
|
|
|
XDG_CONFIG_HOME is not configured. |
|
|
|
|
" |
|
|
|
|
@leaders -min 0 -max 0 |
|
|
|
|
@opts |
|
|
|
|
-quiet -type none -help\ |
|
|
|
|
"Suppress warning given when the folder does |
|
|
|
|
not yet exist" |
|
|
|
|
@values -min 0 -max 0 |
|
|
|
|
}] |
|
|
|
|
proc dir {args} { |
|
|
|
|
if {"-quiet" in $args} { |
|
|
|
|
set be_quiet [dict exists $received -quiet] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
set was_noisy 0 |
|
|
|
|
|
|
|
|
|
set config_home [punk::config::configure running xdg_config_home] |
|
|
|
|
|
|
|
|
|
set config_dir [file join $config_home punk shell] |
|
|
|
|
|
|
|
|
|
if {!$be_quiet && ![file exists $config_dir]} { |
|
|
|
|
set msg "punk::shell data storage folder at $config_dir does not yet exist." |
|
|
|
|
puts stderr $msg |
|
|
|
|
set was_noisy 1 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if {!$be_quiet && $was_noisy} { |
|
|
|
|
puts stderr "punk::config::dir - call with -quiet option to suppress these messages" |
|
|
|
|
} |
|
|
|
|
return $config_dir |
|
|
|
|
|
|
|
|
|
#if {[info exists ::env(XDG_CONFIG_HOME)]} { |
|
|
|
|
# set config_home $::env(XDG_CONFIG_HOME) |
|
|
|
|
#} else { |
|
|
|
|
# set config_home [file join [_homedir] .config] |
|
|
|
|
# if {!$be_quiet} { |
|
|
|
|
# puts stderr "Environment variable XDG_CONFIG_HOME does not exist - consider setting it if $config_home is not a suitable location" |
|
|
|
|
# set was_noisy 1 |
|
|
|
|
# } |
|
|
|
|
#} |
|
|
|
|
#if {!$be_quiet && ![file exists $config_home]} { |
|
|
|
|
# #parent folder for 'punk' config dir doesn't exist |
|
|
|
|
# set msg "configuration location (XDG_CONFIG_HOME or ~/.config) $config_home does not yet exist" |
|
|
|
|
# append msg \n " - please create it and/or set XDG_CONFIG_HOME env var." |
|
|
|
|
# puts stderr $msg |
|
|
|
|
# set was_noisy 1 |
|
|
|
|
#} |
|
|
|
|
#set config_dir [file join $config_home punk shell] |
|
|
|
|
#if {!$be_quiet && ![file exists $config_dir]} { |
|
|
|
|
# set msg "punk::shell data storage folder at $config_dir does not yet exist." |
|
|
|
|
# append msg \n " It will be created if api_context_save is called without specifying an alternate location." |
|
|
|
|
# puts stderr $msg |
|
|
|
|
# set was_noisy 1 |
|
|
|
|
#} |
|
|
|
|
#if {!$be_quiet && $was_noisy} { |
|
|
|
|
# puts stderr "punk::config::dir - call with -quiet option to suppress these messages" |
|
|
|
|
#} |
|
|
|
|
#return [file join $configdir config.toml] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#todo - XDG_DATA_HOME etc |
|
|
|
|
#https://specifications.freedesktop.org/basedir-spec/latest/ |
|
|
|
|
# see also: http://hiphish.github.io/blog/2020/08/30/dotfiles-were-a-mistake/ |
|
|
|
|
|
|
|
|
|
proc init {} { |
|
|
|
|
variable defaults |
|
|
|
|
variable startup |
|
|
|
|
variable running |
|
|
|
|
variable configdata |
|
|
|
|
|
|
|
|
|
#variable defaults |
|
|
|
|
#variable startup |
|
|
|
|
#variable running |
|
|
|
|
variable punk_env_vars |
|
|
|
|
variable punk_env_vars_config |
|
|
|
|
variable other_env_vars |
|
|
|
@ -108,12 +194,14 @@ tcl::namespace::eval punk::config {
|
|
|
|
|
#we have a choice of LOCALAPPDATA vs APPDATA (local to machine vs potentially roaming/redirected in a corporate environment) |
|
|
|
|
#using the roaming location should not impact users who aren't using a domain controller but is potentially much more convenient for those who do. |
|
|
|
|
if {[info exists ::env(APPDATA)]} { |
|
|
|
|
#Typical existing/default value for env(APPDATA) on windows is c:\Users\<username>\AppData\Roaming |
|
|
|
|
set default_xdg_config_home $::env(APPDATA) |
|
|
|
|
set default_xdg_data_home $::env(APPDATA) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#The xdg_cache_home should be kept local |
|
|
|
|
if {[info exists ::env(LOCALAPPDATA)]} { |
|
|
|
|
#Typical existing/default value for env(APPDATA) on windows is c:\Users\<username>\AppData\Local |
|
|
|
|
set default_xdg_data_home $::env(LOCALAPPDATA) |
|
|
|
|
set default_xdg_cache_home $::env(LOCALAPPDATA) |
|
|
|
|
set default_xdg_state_home $::env(LOCALAPPDATA) |
|
|
|
|
} |
|
|
|
@ -133,10 +221,10 @@ tcl::namespace::eval punk::config {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
set defaults [dict create\ |
|
|
|
|
dict set configdata defaults [dict create\ |
|
|
|
|
apps $default_apps\ |
|
|
|
|
config ""\ |
|
|
|
|
configset ".punkshell"\ |
|
|
|
|
config "startup"\ |
|
|
|
|
configset "main"\ |
|
|
|
|
scriptlib $default_scriptlib\ |
|
|
|
|
color_stdout $default_color_stdout\ |
|
|
|
|
color_stdout_repl $default_color_stdout_repl\ |
|
|
|
@ -160,7 +248,7 @@ tcl::namespace::eval punk::config {
|
|
|
|
|
posh_themes_path ""\ |
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
set startup $defaults |
|
|
|
|
dict set configdata startup [dict get $configdata defaults] |
|
|
|
|
#load values from saved config file - $xdg_config_home/punk/punk.config ? |
|
|
|
|
#typically we want env vars to override the stored config - as env vars conventionally used on some commandlines. |
|
|
|
|
#that's possibly ok for the PUNK_ vars |
|
|
|
@ -219,9 +307,9 @@ tcl::namespace::eval punk::config {
|
|
|
|
|
lappend final $p |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
tcl::dict::set startup $varname $final |
|
|
|
|
tcl::dict::set configdata startup $varname $final |
|
|
|
|
} else { |
|
|
|
|
tcl::dict::set startup $varname $f |
|
|
|
|
tcl::dict::set configdata startup $varname $f |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -273,29 +361,46 @@ tcl::namespace::eval punk::config {
|
|
|
|
|
lappend final $p |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
tcl::dict::set startup $varname $final |
|
|
|
|
tcl::dict::set configdata startup $varname $final |
|
|
|
|
} else { |
|
|
|
|
tcl::dict::set startup $varname $f |
|
|
|
|
tcl::dict::set configdata startup $varname $f |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
set config_home [dict get $configdata startup xdg_config_home] |
|
|
|
|
|
|
|
|
|
if {![file exists $config_home]} { |
|
|
|
|
puts stderr "punk::config::init creating punk shell config dir: $config_home" |
|
|
|
|
if {[catch {file mkdir $config_home} errM]} { |
|
|
|
|
puts stderr "punk::config::init failed to create dir at $config_home\n$errM" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
set configset [dict get $configdata defaults configset] |
|
|
|
|
set config [dict get $configdata defaults config] |
|
|
|
|
|
|
|
|
|
set startupfile [file join $config_home $configset $config.toml] |
|
|
|
|
if {![file exists $startupfile]} { |
|
|
|
|
puts stderr "punk::config::init creating punk shell config file: $config for configset: $configset" |
|
|
|
|
puts stderr "(todo)" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#unset -nocomplain vars |
|
|
|
|
|
|
|
|
|
#todo |
|
|
|
|
set running [tcl::dict::create] |
|
|
|
|
set running [tcl::dict::merge $running $startup] |
|
|
|
|
dict set configdata running [tcl::dict::merge $running [dict get $configdata startup]] |
|
|
|
|
} |
|
|
|
|
init |
|
|
|
|
|
|
|
|
|
#todo |
|
|
|
|
proc Apply {config} { |
|
|
|
|
variable configdata |
|
|
|
|
puts stderr "punk::config::Apply partially implemented" |
|
|
|
|
set configname [string map {-config ""} $config] |
|
|
|
|
if {$configname in {startup running}} { |
|
|
|
|
upvar ::punk::config::$configname applyconfig |
|
|
|
|
set applyconfig [dict get $configdata $configname] |
|
|
|
|
|
|
|
|
|
if {[dict exists $applyconfig auto_noexec]} { |
|
|
|
|
set auto [dict get $applyconfig auto_noexec] |
|
|
|
@ -315,67 +420,128 @@ tcl::namespace::eval punk::config {
|
|
|
|
|
} |
|
|
|
|
return "apply done" |
|
|
|
|
} |
|
|
|
|
Apply startup |
|
|
|
|
|
|
|
|
|
#todo - consider how to divide up settings, categories, 'devices', decks etc |
|
|
|
|
proc get_running_global {varname} { |
|
|
|
|
variable running |
|
|
|
|
variable configdata |
|
|
|
|
set running [dict get $configdata running] |
|
|
|
|
if {[dict exists $running $varname]} { |
|
|
|
|
return [dict get $running $varname] |
|
|
|
|
} |
|
|
|
|
error "No such global configuration item '$varname' found in running config" |
|
|
|
|
} |
|
|
|
|
proc get_startup_global {varname} { |
|
|
|
|
variable startup |
|
|
|
|
variable configdata |
|
|
|
|
set startup [dict get $configdata startup] |
|
|
|
|
if {[dict exists $startup $varname]} { |
|
|
|
|
return [dict get $startup $varname] |
|
|
|
|
} |
|
|
|
|
error "No such global configuration item '$varname' found in startup config" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
proc get {whichconfig {globfor *}} { |
|
|
|
|
variable startup |
|
|
|
|
variable running |
|
|
|
|
lappend PUNKARGS [list { |
|
|
|
|
@id -id ::punk::config::get |
|
|
|
|
@cmd -name punk::config::get -help\ |
|
|
|
|
"Get configuration values from a config. |
|
|
|
|
Accepts globs eg XDG*" |
|
|
|
|
@leaders -min 1 -max 1 |
|
|
|
|
whichconfig -type string -choices {config startup-configuration running-configuration} |
|
|
|
|
@values -min 0 -max -1 |
|
|
|
|
globkey -type string -default * -optional 1 -multiple 1 |
|
|
|
|
}] |
|
|
|
|
proc get {args} { |
|
|
|
|
set argd [punk::args::parse $args withid ::punk::config::get] |
|
|
|
|
lassign [dict values $argd] leaders opts values received solos |
|
|
|
|
set whichconfig [dict get $leaders whichconfig] |
|
|
|
|
set globs [dict get $values globkey] ;#list |
|
|
|
|
|
|
|
|
|
variable configdata |
|
|
|
|
|
|
|
|
|
switch -- $whichconfig { |
|
|
|
|
config - startup - startup-config - startup-configuration { |
|
|
|
|
config - startup-configuration { |
|
|
|
|
#review 'config' ?? |
|
|
|
|
#show *startup* config - different behaviour may be confusing to those used to router startup and running configs |
|
|
|
|
set configdata $startup |
|
|
|
|
set configrecords [dict get $configdata startup] |
|
|
|
|
} |
|
|
|
|
running - running-config - running-configuration { |
|
|
|
|
set configdata $running |
|
|
|
|
running-configuration { |
|
|
|
|
set configrecords [dict get $configdata running] |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
error "Unknown config name '$whichconfig' - try startup or running" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if {$globfor eq "*"} { |
|
|
|
|
return $configdata |
|
|
|
|
if {"*" in $globs} { |
|
|
|
|
return $configrecords |
|
|
|
|
} else { |
|
|
|
|
set keys [dict keys $configdata [string tolower $globfor]] |
|
|
|
|
set keys [list] |
|
|
|
|
foreach g $globs { |
|
|
|
|
lappend keys {*}[dict keys $configrecords [string tolower $g]] ;#review tolower? |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
set filtered [dict create] |
|
|
|
|
foreach k $keys { |
|
|
|
|
dict set filtered $k [dict get $configdata $k] |
|
|
|
|
dict set filtered $k [dict get $configrecords $k] |
|
|
|
|
} |
|
|
|
|
return $filtered |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
proc configure {args} { |
|
|
|
|
set argdef { |
|
|
|
|
lappend PUNKARGS [list { |
|
|
|
|
@id -id ::punk::config::configure |
|
|
|
|
@cmd -name punk::config::configure -help\ |
|
|
|
|
"UNIMPLEMENTED" |
|
|
|
|
@values -min 1 -max 1 |
|
|
|
|
whichconfig -type string -choices {startup running stop} |
|
|
|
|
"Get/set configuration values from a config" |
|
|
|
|
@leaders -min 1 -max 1 |
|
|
|
|
whichconfig -type string -choices {defaults startup-configuration running-configuration} |
|
|
|
|
@values -min 0 -max 2 |
|
|
|
|
key -type string -optional 1 |
|
|
|
|
newvalue -optional 1 |
|
|
|
|
}] |
|
|
|
|
proc configure {args} { |
|
|
|
|
set argd [punk::args::parse $args withid ::punk::config::configure] |
|
|
|
|
lassign [dict values $argd] leaders opts values received solos |
|
|
|
|
set whichconfig [dict get $argd leaders whichconfig] |
|
|
|
|
variable configdata |
|
|
|
|
if {"running" ni [dict keys $configdata]} { |
|
|
|
|
init |
|
|
|
|
Apply startup |
|
|
|
|
} |
|
|
|
|
set argd [punk::args::get_dict $argdef $args] |
|
|
|
|
return "unimplemented - $argd" |
|
|
|
|
switch -- $whichconfig { |
|
|
|
|
defaults { |
|
|
|
|
set configrecords [dict get $configdata defaults] |
|
|
|
|
} |
|
|
|
|
startup-configuration { |
|
|
|
|
set configrecords [dict get $configdata startup] |
|
|
|
|
} |
|
|
|
|
running-configuration { |
|
|
|
|
set configrecords [dict get $configdata running] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if {![dict exists $received key]} { |
|
|
|
|
return $configrecords |
|
|
|
|
} |
|
|
|
|
set key [dict get $values key] |
|
|
|
|
if {![dict exists $received newvalue]} { |
|
|
|
|
return [dict get $configrecords $key] |
|
|
|
|
} |
|
|
|
|
error "setting value not implemented" |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
proc show {whichconfig {globfor *}} { |
|
|
|
|
lappend PUNKARGS [list { |
|
|
|
|
@dynamic |
|
|
|
|
@id -id ::punk::config::show |
|
|
|
|
@cmd -name punk::config::get -help\ |
|
|
|
|
"Display configuration values from a config. |
|
|
|
|
Accepts globs eg XDG*" |
|
|
|
|
@leaders -min 1 -max 1 |
|
|
|
|
}\ |
|
|
|
|
{${[punk::args::resolved_def -types leaders ::punk::config::get]}}\ |
|
|
|
|
"@values -min 0 -max -1"\ |
|
|
|
|
{${[punk::args::resolved_def -types values ::punk::config::get]}}\ |
|
|
|
|
] |
|
|
|
|
proc show {args} { |
|
|
|
|
#todo - tables for console |
|
|
|
|
set configdata [punk::config::get $whichconfig $globfor] |
|
|
|
|
return [punk::lib::showdict $configdata] |
|
|
|
|
set configrecords [punk::config::get {*}$args] |
|
|
|
|
return [punk::lib::showdict $configrecords] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -459,27 +625,35 @@ tcl::namespace::eval punk::config {
|
|
|
|
|
::tcl::namespace::eval punk::config { |
|
|
|
|
#todo - something better - 'previous' rather than reverting to startup |
|
|
|
|
proc channelcolors {{onoff {}}} { |
|
|
|
|
variable running |
|
|
|
|
variable startup |
|
|
|
|
variable configdata |
|
|
|
|
#variable running |
|
|
|
|
#variable startup |
|
|
|
|
|
|
|
|
|
if {![string length $onoff]} { |
|
|
|
|
return [list stdout [dict get $running color_stdout] stderr [dict get $running color_stderr]] |
|
|
|
|
return [list stdout [dict get $configdata running color_stdout] stderr [dict get $configdata running color_stderr]] |
|
|
|
|
} else { |
|
|
|
|
if {![string is boolean $onoff]} { |
|
|
|
|
error "channelcolors: invalid value $onoff - expected boolean: true|false|on|off|1|0|yes|no" |
|
|
|
|
} |
|
|
|
|
if {$onoff} { |
|
|
|
|
dict set running color_stdout [dict get $startup color_stdout] |
|
|
|
|
dict set running color_stderr [dict get $startup color_stderr] |
|
|
|
|
dict set configdata running color_stdout [dict get $startup color_stdout] |
|
|
|
|
dict set configdata running color_stderr [dict get $startup color_stderr] |
|
|
|
|
} else { |
|
|
|
|
dict set running color_stdout "" |
|
|
|
|
dict set running color_stderr "" |
|
|
|
|
dict set configdata running color_stdout "" |
|
|
|
|
dict set configdata running color_stderr "" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return [list stdout [dict get $running color_stdout] stderr [dict get $running color_stderr]] |
|
|
|
|
return [list stdout [dict get $configdata running color_stdout] stderr [dict get $configdata running color_stderr]] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
namespace eval ::punk::args::register { |
|
|
|
|
#use fully qualified so 8.6 doesn't find existing var in global namespace |
|
|
|
|
lappend ::punk::args::register::NAMESPACES ::punk::config |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
package provide punk::config [tcl::namespace::eval punk::config { |
|
|
|
|
variable version |
|
|
|
|
set version 0.1 |
|
|
|
|