-#!/usr/bin/env tclsh
+#!/usr/bin/env jimsh
# dsc -- damn small configuration manager
# Copyright (C) 2025 Sergey Matveev <stargrave@stargrave.org>
#
proc walk {root typ} {
set rv [list]
set root [string trimright $root /]
- set dirs [glob -directory $root -types $typ -tails -nocomplain -- *]
+ set dirs [glob -directory $root -tails -nocomplain -- *]
+ set dirs [lmap d $dirs {if {[file type $root/$d] == $typ} {set d} {continue}}]
foreach s [lsort $dirs] {
lappend rv $root/$s
lappend rv {*}[walk $root/$s $typ]
}
proc run-checker {opt v} {
+ lassign [pipe] r w
global Schema
- set fh [open |[list "$Schema/[find-opt-schema $opt]/check" $opt 2>@1] r+]
+ set fh [open |[list "$Schema/[find-opt-schema $opt]/check" $opt 2>@1 >@$w] w]
puts $fh $v
- close $fh w
- set v [read $fh]
+ set failed no
if {[catch {close $fh}]} {
+ set failed yes
+ }
+ close $w
+ set v [$r read]
+ close $r
+ if {$failed} {
puts -nonewline stderr $v
exit 1
}
+ untaint v
return $v
}
set opt [lindex $argv 1]
switch [lindex $argv 0] {
list {
- set verbose n
+ set verbose no
set prefix [lindex $argv 1]
if {$argc > 1 && [lindex $argv 1] == "-v"} {
- set verbose y
+ set verbose yes
set prefix [lindex $argv 2]
}
- foreach opt [walk $Schema d] {
+ foreach opt [walk $Schema directory] {
if {! [file exists $opt/title]} {continue}
set name [string range $opt [expr {[string length $Schema] + 1}] end]
if {$prefix != ""} {
set fh [open $Stash/$opt w]
fconfigure $fh -translation binary
fconfigure stdin -translation binary
- fcopy stdin $fh
+ stdin copyto $fh
close $fh
} else {
set v [run-checker $opt $v]
if {! [file exists $Stash/$opt]} {
exit
}
- set dirs [glob -directory $Stash/$opt -types d -tails -nocomplain -- *]
+ set dirs [glob -directory $Stash/$opt -tails -nocomplain -- *]
+ set dirs [lmap d $dirs { \
+ if {[file type $Stash/$opt/$d] == "directory"} {set d} {continue}}]
foreach dir [lsort $dirs] {
puts $dir
}
set fh [open $Stash/$opt r]
fconfigure $fh -translation binary
fconfigure stdout -translation binary
- fcopy $fh stdout
+ $fh copyto stdout
close $fh
} else {
puts -nonewline [fileread $Stash/$opt]
puts -nonewline [run-checker $opt ""]
}
diff {
- set fh [file tempfile dirsSaved]
- foreach fn [walk $Saved/$opt d] {
+ set dirsSaved [file tempfile dirsSaved.XXXXX]
+ set fh [open $dirsSaved w]
+ foreach fn [walk $Saved/$opt directory] {
puts $fh [string range $fn [string length $Saved]+1 end]
}
close $fh
- set fh [file tempfile dirsStash]
- foreach fn [walk $Stash/$opt d] {
+ set dirsStash [file tempfile dirsStash.XXXXX]
+ set fh [open $dirsStash w]
+ foreach fn [walk $Stash/$opt directory] {
puts $fh [string range $fn [string length $Stash]+1 end]
}
close $fh
}
revert {
catch {file delete -force $Stash/$opt}
- catch {file copy $Saved/$opt $Stash/$opt}
+ exec | [list cp -a $Saved/$opt $Stash/$opt]
}
commit {
file delete -force $Saved.bak
set tmp $Saved.[expr {int(rand() * 1000000)}]
- file copy $Stash $tmp
+ exec | [list cp -a $Stash $tmp]
exec sync
file rename $Saved $Saved.bak
file rename $tmp $Saved
file delete -force $Saved.bak
}
export {
- set dirs [walk $Saved/$opt d]
+ set dirs [walk $Saved/$opt directory]
if {$opt != ""} {
set dirs [list $Saved/$opt {*}$dirs]
}
puts [string range $fn [string length $Saved]+1 end]
}
foreach dir $dirs {
- foreach fn [walk $dir f] {
+ foreach fn [walk $dir file] {
set sfn [string range $fn [string length $Saved]+1 end]
if {[is-bin $sfn]} {
puts "-- $sfn:base64 --"
set fh [open "|base64 $fn" r]
- fcopy $fh stdout
+ $fh copyto stdout
close $fh
} else {
puts "-- $sfn --"