Posted to tcl by dbohdan at Wed Nov 04 12:25:27 GMT 2020view pretty
#! /usr/bin/env tclsh # # A configuration deployment script. # Requires: Tcl 8.6 or later, rsync(1). # # Copyright (c) 2020 D. Bohdan. # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. proc main home { cd [file dirname [info script]] set vars [dict create \ hostname [exec hostname] \ ] foreach src { config/awesome/ config/gxkb/ config/icewm/ config/mc/ config/tclsh/ config/udiskie/ } { sync $src {} --delete } foreach src { config/fish/ config/mpv/ gitconfig gitignore jimrc tclshrc tmux.conf xinitrc xscreensaver.template } { sync $src } } proc with-path {path script} { set prev [pwd] try { cd $path uplevel 1 $script } finally { cd $prev } } proc sync {src {dst {}} args} { upvar 1 home home upvar 1 vars vars if {$dst eq {}} { set dst $home/.$src } exec rsync -av {*}$args $src $dst >@ stdout 2>@ stderr foreach template [find $dst -iname *.template] { puts stderr [list expanding template $template] expand-template $template {} $vars } } proc find args { set paths [split [exec find {*}$args -print0] \0] lrange $paths 0 end-1 } proc expand-template {src {dst {}} {vars {}}} { if {$dst eq {}} { set dst [file rootname $src] } set ch [open $src r] set template [read $ch] set contents [safe-eval [template::parse $template] $vars] set ch2 [open $dst w] puts -nonewline $ch2 $contents file delete $src close $ch2 close $ch } proc safe-eval {script vars} { ::safe::interpCreate templateInterp dict for {k v} $vars { templateInterp eval [list set $k $v] } set result [templateInterp eval $script] ::safe::interpDelete templateInterp return $result } namespace eval template {} # Convert a template into Tcl code. proc template::parse template { set result {} set regExpr {^(.*?)<%(.*?)%>(.*)$} set listing "set _output {}\n" while {[regexp $regExpr $template match preceding token template]} { append listing [list append _output $preceding]\n switch -exact -- [string index $token 0] { = { set code [list [string range $token 1 end]] append listing [format {append _output [expr %s]} $code] } ! { set code [string range $token 1 end] append listing [format {append _output [%s]} $code] } default { append listing $token } } append listing \n } append listing [list append _output $template]\n return $listing } main $env(HOME)