install.tcl 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. ###
  2. # Installer actions built into tclsh and invoked
  3. # if the first command line argument is "install"
  4. ###
  5. if {[llength $argv] < 2} {
  6. exit 0
  7. }
  8. namespace eval ::practcl {}
  9. ###
  10. # Installer tools
  11. ###
  12. proc ::practcl::_isdirectory name {
  13. return [file isdirectory $name]
  14. }
  15. ###
  16. # Return true if the pkgindex file contains
  17. # any statement other than "package ifneeded"
  18. # and/or if any package ifneeded loads a DLL
  19. ###
  20. proc ::practcl::_pkgindex_directory {path} {
  21. set buffer {}
  22. set pkgidxfile [file join $path pkgIndex.tcl]
  23. if {![file exists $pkgidxfile]} {
  24. # No pkgIndex file, read the source
  25. foreach file [glob -nocomplain $path/*.tm] {
  26. set file [file normalize $file]
  27. set fname [file rootname [file tail $file]]
  28. ###
  29. # We used to be able to ... Assume the package is correct in the filename
  30. # No hunt for a "package provides"
  31. ###
  32. set package [lindex [split $fname -] 0]
  33. set version [lindex [split $fname -] 1]
  34. ###
  35. # Read the file, and override assumptions as needed
  36. ###
  37. set fin [open $file r]
  38. fconfigure $fin -encoding utf-8 -eofchar \x1A
  39. set dat [read $fin]
  40. close $fin
  41. # Look for a teapot style Package statement
  42. foreach line [split $dat \n] {
  43. set line [string trim $line]
  44. if { [string range $line 0 9] != "# Package " } continue
  45. set package [lindex $line 2]
  46. set version [lindex $line 3]
  47. break
  48. }
  49. # Look for a package provide statement
  50. foreach line [split $dat \n] {
  51. set line [string trim $line]
  52. if { [string range $line 0 14] != "package provide" } continue
  53. set package [lindex $line 2]
  54. set version [lindex $line 3]
  55. break
  56. }
  57. append buffer "package ifneeded $package $version \[list source \[file join \$dir [file tail $file]\]\]" \n
  58. }
  59. foreach file [glob -nocomplain $path/*.tcl] {
  60. if { [file tail $file] == "version_info.tcl" } continue
  61. set fin [open $file r]
  62. fconfigure $fin -encoding utf-8 -eofchar \x1A
  63. set dat [read $fin]
  64. close $fin
  65. if {![regexp "package provide" $dat]} continue
  66. set fname [file rootname [file tail $file]]
  67. # Look for a package provide statement
  68. foreach line [split $dat \n] {
  69. set line [string trim $line]
  70. if { [string range $line 0 14] != "package provide" } continue
  71. set package [lindex $line 2]
  72. set version [lindex $line 3]
  73. if {[string index $package 0] in "\$ \[ @"} continue
  74. if {[string index $version 0] in "\$ \[ @"} continue
  75. append buffer "package ifneeded $package $version \[list source \[file join \$dir [file tail $file]\]\]" \n
  76. break
  77. }
  78. }
  79. return $buffer
  80. }
  81. set fin [open $pkgidxfile r]
  82. fconfigure $fin -encoding utf-8 -eofchar \x1A
  83. set dat [read $fin]
  84. close $fin
  85. set trace 0
  86. #if {[file tail $path] eq "tool"} {
  87. # set trace 1
  88. #}
  89. set thisline {}
  90. foreach line [split $dat \n] {
  91. append thisline $line \n
  92. if {![info complete $thisline]} continue
  93. set line [string trim $line]
  94. if {[string length $line]==0} {
  95. set thisline {} ; continue
  96. }
  97. if {[string index $line 0] eq "#"} {
  98. set thisline {} ; continue
  99. }
  100. if {[regexp "if.*catch.*package.*Tcl.*return" $thisline]} {
  101. if {$trace} {puts "[file dirname $pkgidxfile] Ignoring $thisline"}
  102. set thisline {} ; continue
  103. }
  104. if {[regexp "if.*package.*vsatisfies.*package.*provide.*return" $thisline]} {
  105. if {$trace} { puts "[file dirname $pkgidxfile] Ignoring $thisline" }
  106. set thisline {} ; continue
  107. }
  108. if {![regexp "package.*ifneeded" $thisline]} {
  109. # This package index contains arbitrary code
  110. # source instead of trying to add it to the main
  111. # package index
  112. if {$trace} { puts "[file dirname $pkgidxfile] Arbitrary code $thisline" }
  113. return {source [file join $dir pkgIndex.tcl]}
  114. }
  115. append buffer $thisline \n
  116. set thisline {}
  117. }
  118. if {$trace} {puts [list [file dirname $pkgidxfile] $buffer]}
  119. return $buffer
  120. }
  121. proc ::practcl::_pkgindex_path_subdir {path} {
  122. set result {}
  123. foreach subpath [glob -nocomplain [file join $path *]] {
  124. if {[file isdirectory $subpath]} {
  125. lappend result $subpath {*}[_pkgindex_path_subdir $subpath]
  126. }
  127. }
  128. return $result
  129. }
  130. ###
  131. # Index all paths given as though they will end up in the same
  132. # virtual file system
  133. ###
  134. proc ::practcl::pkgindex_path args {
  135. set stack {}
  136. set buffer {
  137. lappend ::PATHSTACK $dir
  138. }
  139. foreach base $args {
  140. set base [file normalize $base]
  141. set paths {}
  142. foreach dir [glob -nocomplain [file join $base *]] {
  143. if {[file tail $dir] eq "teapot"} continue
  144. lappend paths $dir {*}[::practcl::_pkgindex_path_subdir $dir]
  145. }
  146. set i [string length $base]
  147. # Build a list of all of the paths
  148. if {[llength $paths]} {
  149. foreach path $paths {
  150. if {$path eq $base} continue
  151. set path_indexed($path) 0
  152. }
  153. } else {
  154. puts [list WARNING: NO PATHS FOUND IN $base]
  155. }
  156. set path_indexed($base) 1
  157. set path_indexed([file join $base boot tcl]) 1
  158. foreach teapath [glob -nocomplain [file join $base teapot *]] {
  159. set pkg [file tail $teapath]
  160. append buffer [list set pkg $pkg]
  161. append buffer {
  162. set pkginstall [file join $::g(HOME) teapot $pkg]
  163. if {![file exists $pkginstall]} {
  164. installDir [file join $dir teapot $pkg] $pkginstall
  165. }
  166. }
  167. }
  168. foreach path $paths {
  169. if {$path_indexed($path)} continue
  170. set thisdir [file_relative $base $path]
  171. set idxbuf [::practcl::_pkgindex_directory $path]
  172. if {[string length $idxbuf]} {
  173. incr path_indexed($path)
  174. append buffer "set dir \[set PKGDIR \[file join \[lindex \$::PATHSTACK end\] $thisdir\]\]" \n
  175. append buffer [string map {$dir $PKGDIR} [string trimright $idxbuf]] \n
  176. }
  177. }
  178. }
  179. append buffer {
  180. set dir [lindex $::PATHSTACK end]
  181. set ::PATHSTACK [lrange $::PATHSTACK 0 end-1]
  182. }
  183. return $buffer
  184. }
  185. ###
  186. # topic: 64319f4600fb63c82b2258d908f9d066
  187. # description: Script to build the VFS file system
  188. ###
  189. proc ::practcl::installDir {d1 d2} {
  190. puts [format {%*sCreating %s} [expr {4 * [info level]}] {} [file tail $d2]]
  191. file delete -force -- $d2
  192. file mkdir $d2
  193. foreach ftail [glob -directory $d1 -nocomplain -tails *] {
  194. set f [file join $d1 $ftail]
  195. if {[file isdirectory $f] && [string compare CVS $ftail]} {
  196. installDir $f [file join $d2 $ftail]
  197. } elseif {[file isfile $f]} {
  198. file copy -force $f [file join $d2 $ftail]
  199. if {$::tcl_platform(platform) eq {unix}} {
  200. file attributes [file join $d2 $ftail] -permissions 0o644
  201. } else {
  202. file attributes [file join $d2 $ftail] -readonly 1
  203. }
  204. }
  205. }
  206. if {$::tcl_platform(platform) eq {unix}} {
  207. file attributes $d2 -permissions 0o755
  208. } else {
  209. file attributes $d2 -readonly 1
  210. }
  211. }
  212. proc ::practcl::copyDir {d1 d2 {toplevel 1}} {
  213. #if {$toplevel} {
  214. # puts [list ::practcl::copyDir $d1 -> $d2]
  215. #}
  216. #file delete -force -- $d2
  217. file mkdir $d2
  218. foreach ftail [glob -directory $d1 -nocomplain -tails *] {
  219. set f [file join $d1 $ftail]
  220. if {[file isdirectory $f] && [string compare CVS $ftail]} {
  221. copyDir $f [file join $d2 $ftail] 0
  222. } elseif {[file isfile $f]} {
  223. file copy -force $f [file join $d2 $ftail]
  224. }
  225. }
  226. }
  227. switch [lindex $argv 1] {
  228. mkzip {
  229. zipfs mkzip {*}[lrange $argv 2 end]
  230. }
  231. mkzip {
  232. zipfs mkimg {*}[lrange $argv 2 end]
  233. }
  234. default {
  235. ::practcl::[lindex $argv 1] {*}[lrange $argv 2 end]
  236. }
  237. }
  238. exit 0