What | tcl-augeas |
Where | https://github.com/dbohdan/tcl-augeas |
Description | A binary Tcl extension that provides bindings for the Augeas configuration editing tool. |
Platforms | Linux, FreeBSD, OpenBSD, MacOS, Illumos |
Prerequisites | Tcl 8.5 or newer, Augeas 0.10 or newer. |
Updated | 2018-03-30 (v0.4.0) |
License | MIT |
Sample code edit
package require augeas
set id [::augeas::init /]
foreach x [::augeas::match $id {/files/etc/hosts/*}] {
set ipaddr [::augeas::get $id $x/ipaddr]
set hostname [::augeas::get $id $x/canonical]
puts [format %-30s%s $hostname $ipaddr]
}
::augeas::close $id
On the default installation of
Fedora 21 with no extra hosts added this produces the output of
localhost.localdomain 127.0.0.1
localhost6.localdomain6 ::1
Dung Fork edit
chw 2016-07-11: verrry versatile! Couldn't resist to make a little regedit like read-only toy and call it "Dung Fork" in memory of King Augeias, maybe an ancient acronym for "All Useful Garbage Extracted Is A String". Warning however: on my CentOS 6 system opening /files/etc/services takes centuries but this certainly isn't Tcl's fault.
dbohdan 2016-07-12: Cool stuff! You could grow a configuration management GUI tool on top of it if you let the user edit the values, record his actions and spit out Augeas or Tcl + tcl-augeas scripts.
domcleal 2016-07-12: @chw, the /etc/services performance ought to be a lot better in Augeas 1.5.0 which contains some optimisations for iterating and calling aug_get on every entry.
chw 2016-07-12: @domcleal, yes that's exactly my observation, too. CentOS 6 is at Augeas 1.0, but Ubuntu 16.04 is at 1.2.0 which is an order of magnitude faster. @dbohdan: thanks for this useful invention. Please review my somewhat changed tcl-augeas variant which I gladly integrated into
undroidwish, the source code is in
http://www.androwish.org/index.html/dir?name=undroid/tcl-augeas. However, to make a full scale editor from it is a Herculean task requiring a hero, two rivers, root, and a better name for the tool.
dbohdan 2016-07-13:
chw, I haven't tried compiling it but at a glace the Autoconf port looks reasonable. As for storing
augeas objects in a
Tcl_HashTable, I like that! I've integrated your changes into the master branch on GitHub.
Screenshot
Code
# Dung Fork -- use augeas to browse system info from /etc etc
# 0.1.0
package require augeas
set ::AUG [augeas::init /]
set ::ABORT 0
array set ::AUGCACHE {}
proc treeview_focus {w} {
if {![::tk::FocusOK $w]} return
set item [$w focus]
if {$item eq ""} {
catch {
set item [lindex [$w children {}] 0]
$w focus $item
$w see $item
ttk::treeview::select.choose.browse $w $item
}
}
}
ttk::style configure Treeview -rowheight \
[expr {[font metrics TkDefaultFont -linespace] + 4}]
bind Treeview <FocusIn> {treeview_focus %W}
proc augeas_match pat {
if {[info exists ::AUGCACHE($pat)]} {
return $::AUGCACHE($pat)
}
set ::AUGCACHE($pat) [augeas::match $::AUG $pat]
}
proc fill_roots {tree} {
set ::ABORT 0
foreach dir [lsort -dictionary [augeas::match $::AUG /*]] {
fill_tree $tree [$tree insert {} end -text $dir \
-values [list $dir {} "directory"]]
}
}
proc fill_tree {tree node {open 0} {dobusy 1}} {
if {![string match "*irectory" [$tree set $node type]]} return
if {$open < 0} {
$tree item $node -open 0
return
}
# already processed?
if {[$tree set $node type] ne "directory"} return
if {$dobusy} {
set count0 0
set ::ABORT 0
catch {tk busy hold .}
update
set oldfocus [focus]
catch {
focus ._Busy
bind ._Busy <Escape> {set ::ABORT 1}
bind ._Busy <Any-Key> break
}
upvar 0 count0 count
} else {
upvar 1 count0 count
}
set path [$tree set $node fullpath]
$tree delete [$tree children $node]
set list {}
set toopen {}
set list [lsort -dictionary [augeas_match "$path/*"]]
foreach f $list {
if {[catch {augeas::get $::AUG $f} data]} continue
set sublist [augeas_match $f/*]
if {[llength $sublist]} {
set id [$tree insert $node end -text [file tail $f] \
-values [list $f $data "directory"]]
# make this node openable
$tree insert $id 0 -text dummy ;# a dummy
if {$open > 0} {
lappend toopen $id
}
} else {
set id [$tree insert $node end -text [file tail $f] \
-values [list $f $data "file"]]
}
incr count
if {$count > 100} {
set count 0
update
}
if {$::ABORT} break
}
if {!$::ABORT} {
# stop from rerunning on the current node
$tree set $node type "processedDirectory"
}
if {($open > 0) && [llength $list]} {
$tree item $node -open 1
}
foreach id $toopen {
fill_tree $tree $id $open 0
}
if {$dobusy} {
focus $oldfocus
catch {tk busy forget .}
set ::ABORT 0
}
}
proc dung_fork {} {
wm title . "Dung Fork"
ttk::treeview .tree -columns {fullpath value type} -displaycolumns value \
-yscroll [list .scroll set] -selectmode browse -show {headings tree}
ttk::scrollbar .scroll -orient vertical -command [list .tree yview]
.tree heading \#0 -text Path
.tree heading value -text Value
bind .tree <<TreeviewOpen>> {fill_tree %W [%W focus]}
bind .tree <<TreeviewClose>> {fill_tree %W [%W focus] -1}
grid .tree -row 0 -column 0 -sticky nsew
grid .scroll -row 0 -column 1 -sticky ns
grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
fill_roots .tree
}
dung_fork