Improved handling of case where child is killed by a signal
[tcl-tlc.git] / scripts / hconfig.itcl
blobaa68013b8ea9a1529b1256fee7b10bfb0cccd515
1 # vim: ft=tcl foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4
3 class tlc::Hconfig {
4 inherit tlc::Baselog
6 constructor {backend info args} {}
8 public {
9 variable exact 1
11 method load {path {inherited {}} {datatypes {}} {inh_info {}}}
12 method load_only {path}
13 method exists {path}
14 method listsub {path {immediate 0}}
15 method save {path configlist {datatype_list ""}}
16 method trash {path}
17 method rename {frompath topath {allsub 0}}
20 private {
21 variable sql_obj
22 variable table
24 method init_db {}
29 body tlc::Hconfig::constructor {backend info args} { #<<<1
30 log debug $this
31 eval configure $args
33 switch -- $backend {
34 "pg_sql" {
35 foreach {sql_obj table} $info break
36 log debug "sql_obj: ($sql_obj) ($table)"
39 default {
40 error "Unsupported backend: ($backend)" "" \
41 [list invalid_backend $backend]
45 init_db
49 body tlc::Hconfig::init_db {} { #<<<1
50 log debug
51 if {![$sql_obj table_exists $table]} {
52 $sql_obj getlist "
53 create table $table (
54 id serial,
55 path text unique not null,
56 data text,
57 leaf int4 default 0,
58 datatypes text default ''
61 $sql_obj getlist "
62 create index ${table}_path_idx on ${table}(path);
68 body tlc::Hconfig::load {path {inherited {}} {datatypes {}} {inh_info {}}} { #<<<1
69 log debug
70 set path [string trim $path "/ "]
72 if {$inherited != {}} {
73 upvar $inherited inh
75 if {$datatypes != {}} {
76 upvar $datatypes dt
79 if {$inh_info != {}} {
80 upvar $inh_info inh_inf
83 array set build {}
85 set p ""
86 set sep ""
87 set leaf 0
88 set real 0
89 set last {}
90 # Initialize from root "" <<<
91 set rows [$sql_obj getlist "
92 select
93 data,
94 leaf,
95 datatypes
96 from
97 $table
98 where
99 path = ''
101 set real [expr {[llength $rows] == 1}]
102 set raw [lindex $rows 0]
103 set last [lindex $raw 0]
104 set leaf [lindex $raw 1]
105 set types [lindex $raw 2]
107 #log debug "path: ($p) data: ($last)"
108 array set build $last
110 # look for this variable's data type in the (should be a list) types var
111 # the default type is text, so if the variable is not found in the types list
112 # then we set to that
113 foreach {idx val} $last {
114 set dt($idx) "text"
116 array set dt $types
118 set inh_inf(parent) [array get build]
119 set inh_inf(this) $last
120 set inh_inf(parent_dt) [array get dt]
121 set inh_inf(this_dt) $types
122 # Initialize from root "" >>>
124 foreach elem [split $path /] {
125 append p $sep $elem
126 set rows [$sql_obj getlist "
127 select
128 data,
129 leaf,
130 datatypes
131 from
132 $table
133 where
134 path = '[$sql_obj quote $p]'
136 set real [expr {[llength $rows] == 1}]
137 set raw [lindex $rows 0]
138 set last [lindex $raw 0]
139 set leaf [lindex $raw 1]
140 set types [lindex $raw 2]
142 set inh_inf(parent) [array get build]
143 set inh_inf(this) $last
144 set inh_inf(parent_dt) [array get dt]
145 set inh_inf(this_dt) $types
147 array set dt $types
148 foreach {key val} $last {
149 if {![info exists dt($key)]} {
150 set dt($key) "text"
152 switch -- $dt($key) {
153 "mergelist" { #<<<
154 log debug "Compositing mergelist: $p, $key, $val"
155 set chopitems {}
156 set newitems {}
158 if {![info exists build($key)]} {
159 set build($key) {}
162 foreach item $val {
163 switch -- [string index $item 0] {
164 "-" {
165 lappend chopitems [string range $item 1 end]
168 "+" {
169 lappend newitems [string range $item 1 end]
172 default {
173 lappend newitems $item
178 set chopped \
179 [lindex [tlc::intersect3 $build($key) $chopitems] 0]
180 set build($key) \
181 [lsort -unique [concat $chopped $newitems]]
182 #>>>
185 "mergearray" { #<<<
186 log debug "Compositing mergelist: $p, $key, $val"
187 set chopitems {}
188 set newitems {}
190 catch {unset tmparr}
191 if {![info exists build($key)]} {
192 array set tmparr {}
193 } else {
194 array set tmparr $build($key)
197 foreach {skey sval} $val {
198 switch -- [string index $skey 0] {
199 "-" {
200 lappend chopitems [string range $skey 1 end]
203 "+" {
204 lappend newitems \
205 [string range $skey 1 end] \
206 $sval
209 default {
210 lappend newitems $skey $sval
215 foreach chopitem $chopitems {
216 array unset tmparr $chopitem
218 foreach {skey sval} $newitems {
219 set tmparr($skey) $sval
221 set build($key) \
222 [array get tmparr]
223 #>>>
226 default -
227 "text" { #<<<
228 set build($key) $val
229 #>>>
234 set sep "/"
235 if {$leaf == 1} break
237 if {$exact && (($p != $path) || !$real)} {
238 error "path not found: ($path) exact: ($exact)" "" \
239 [list not_found $path]
242 foreach name [array names build] {
243 set inh($name) 1
245 foreach {name value} $last {
246 set inh($name) 0
249 return [array get build]
253 body tlc::Hconfig::load_only {path} { #<<<1
254 log debug
255 set path [string trim $path "/ "]
257 array set build {}
259 set p ""
260 set sep ""
261 set leaf 0
262 set real 0
263 set last {}
264 foreach elem [split $path /] {
265 append p $sep $elem
266 set rows [$sql_obj getlist "
267 select
268 data,
269 leaf
270 from
271 $table
272 where
273 path = '[$sql_obj quote $p]'
275 set real [expr {[llength $rows] == 1}]
276 set raw [lindex $rows 0]
277 set last [lindex $raw 0]
278 set leaf [lindex $raw 1]
279 set sep "/"
280 if {$leaf == 1} break
282 if {$exact && (($p != $path) || !$real)} {
283 error "path not found: ($path) exact: ($exact)" "" \
284 [list path_not_found $path]
286 array set build $last
288 return [array get build]
292 body tlc::Hconfig::exists {path} { #<<<1
293 log debug
294 set path [string trim $path "/ "]
296 set count [lindex [lindex [$sql_obj getlist "
297 select
298 count(*)
299 from
300 $table
301 where
302 path = '[$sql_obj quote $path]'
303 "] 0] 0]
305 return [expr {$count > 0}]
309 body tlc::Hconfig::save {path configlist {datatype_list ""}} { #<<<1
310 log debug
311 set path [string trim $path "/ "]
313 if {[catch {array set test $configlist}]} {
314 error "Badly formatted configlist. Should be result of array get" "" \
315 [list bad_format]
318 set id [lindex [lindex [$sql_obj getlist "
319 select
320 count(*)
321 from
322 $table
323 where
324 path = '[$sql_obj quote $path]'
325 "] 0] 0]
327 if {$id == 0} {
328 $sql_obj getlist "
329 insert into $table (
330 path,
331 data,
332 datatypes
333 ) values (
334 '[$sql_obj quote $path]',
335 '[$sql_obj quote $configlist]',
336 '[$sql_obj quote $datatype_list]'
339 } else {
340 set row [lindex [$sql_obj getlist "
341 select
342 data,
343 datatypes
344 from
345 $table
346 where
347 path = '[$sql_obj quote $path]'
348 "] 0]
349 array set build [lindex $row 0]
350 array set datatypes [lindex $row 1]
351 array set build $configlist
352 array set datatypes $datatype_list
353 $sql_obj getlist "
354 update
355 $table
357 data = '[$sql_obj quote [array get build]]',
358 datatypes = '[$sql_obj quote [array get datatypes]]'
359 where
360 path = '[$sql_obj quote $path]'
366 body tlc::Hconfig::trash {path} { #<<<1
367 log debug
368 set path [string trim $path "/ "]
370 $sql_obj getlist "
371 delete from
372 $table
373 where
374 path = '[$sql_obj quote $path]'
379 body tlc::Hconfig::rename {frompath topath {allsub 0}} { #<<<1
380 log debug
381 set frompath [string trim $frompath "/ "]
382 set topath [string trim $topath "/ "]
384 if {$allsub != 1} {
385 $sql_obj getlist "
386 update
387 $table
389 path = '[$sql_obj quote $topath]'
390 where
391 path = '[$sql_obj quote $frompath]'
393 } else {
394 set subs [listsub $frompath 0]
395 $sql_obj getlist "begin"
396 foreach sub $subs {
397 set from [join [list $frompath $sub] /]
398 set to [join [list $topath $sub] /]
399 $sql_obj getlist "
400 update
401 $table
403 path = '[$sql_obj quote $to]'
404 where
405 path = '[$sql_obj quote $from]'
409 $sql_obj getlist "
410 update
411 $table
413 path = '[$sql_obj quote $topath]'
414 where
415 path = '[$sql_obj quote $frompath]'
417 $sql_obj getlist "commit"
422 body tlc::Hconfig::listsub {path {immediate 0}} { #<<<1
423 log debug
424 set path [string trim $path "/ "]
425 #log debug "listsub of ($path) ($immediate)"
426 if {$path == ""} {
427 set spec ""
428 } else {
429 #set spec "$path/"
430 set spec "$path/"
432 set speclen [string length $spec]
434 set build {}
435 set rows [$sql_obj getlist "
436 select
437 path
438 from
439 $table
440 where
441 path like '[$sql_obj quote ${spec}%]'
444 # log debug "
445 # select
446 # path
447 # from
448 # $table
449 # where
450 # path like '${spec}%'
453 foreach row $rows {
454 set subpath [lindex $row 0]
455 set subpath [string range $subpath $speclen end]
457 if {$subpath == ""} continue
459 if {$immediate} {
460 set trimpoint [string first "/" $subpath]
461 if {$trimpoint == -1} {
462 #log debug "($subpath): no \"/\" - appending as is"
463 lappend build $subpath
464 } else {
465 incr trimpoint -1
466 #log debug "($subpath): \"/\" at $trimpoint appending ([string range $subpath 0 $trimpoint])"
467 lappend build [string range $subpath 0 $trimpoint]
469 } else {
470 lappend build $subpath
474 if {$immediate} {
475 set build [lsort -unique $build]
478 return $build