#! /usr/bin/env tclkit lappend auto_path lib package require ascenc #source [file join [file dirname [info script]] kitten.kit] package require md5c # convert md5 + size into a path for that file proc amspath {md5 size {create 0}} { # 128b MD5 + 27b size -> 31 encoded chars (base-32) append x $md5 [binary format I [expr {$size<<5}]] set encoded [string range [ascenc::b2a_32 $x] 0 end-1] # first two chars are used to create up to 1024 subdirs set dn [file join data [string range $encoded 0 1]] if {$create && ![file isdir $dn]} { file mkdir $dn } file join $dn $encoded } proc traverse {args} { set sig 0 set mod 0 while {[llength $args] > 0} { set d [lindex $args 0] set args [lrange $args 1 end] foreach path [lsort [glob -nocomplain [file join $d *]]] { set t [file tail $path] switch -- $t CVS - RCS - core - a.out continue lappend sig $t if {[file isdir $path]} { lappend args $path } else { set m [file mtime $path] if {$m > $mod} { set mod $m } lappend sig $m [file size $path] } } } list [vfs::crc [join $sig " "]] $mod } proc version_id {dir {name ""}} { lassign [traverse $dir] sig mod set time [clock format $mod -format {%Y/%m/%d %H:%M:%S} -gmt 1] puts [format {%s %d-%d %s} $time [expr {(($sig>>16) & 0xFFFF) + 10000}] \ [expr {($sig & 0xFFFF) + 10000}] $name] } proc submitsk {path go} { set db [vfs::mk4::Mount $path $path -readonly] lassign [traverse $path] sig mod #version_id $path $path puts $path: mk::view layout $db.dirs {name parent:I {files {name size:I date:I md5:B}}} set paths(0) "" mk::loop d $db.dirs { set n [mk::cursor position d] if {$n > 0} { set paths($n) $paths([mk::get $d parent])[mk::get $d name]/ } mk::loop f $d.files { array set fr [mk::get $f] set data $fr(contents) if {[string length $data] != $fr(size)} { set data [vfs::zip -mode decompress $data] } set md [md5c $data] mk::set $f md5 $md set ams [amspath $md $fr(size) $go] if {![file exists $ams]} { puts " $ams $paths($n)$fr(name)" if {$go} { set fd [open $ams w] fconfigure $fd -translation binary puts -nonewline $fd $fr(contents) close $fd } } if {$go && $fr(date) < [file mtime $ams]} { file mtime $ams $fr(date) } } } #mk::file close db if {$go} { file mkdir kits set vid [format %d-%d [expr {(($sig>>16) & 0xFFFF) + 10000}] \ [expr {($sig & 0xFFFF) + 10000}]] set kpath [file join kits [file root [file tail $path]]-$vid] if {![file exists $kpath]} { set fd [open $kpath w] mk::file save $db $fd close $fd file mtime $kpath $mod puts "[file tail $kpath] stored: $path" } } vfs::unmount $path } set go 1 switch -- [lindex $argv 0] { "" { puts "Usage: submit ?-n? starkit ..." exit } -n { set go 0 set argv [lrange $argv 1 end] } } foreach sk $argv { submitsk $sk $go }