-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpacker.tcl
272 lines (232 loc) · 8.87 KB
/
packer.tcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#!/usr/bin/env tclsh
# Packer, a tool for creating Starpacks out of Git repositories.
# Copyright (c) 2015, 2017, 2018, 2019, 2024 D. Bohdan
# License: MIT
package require Tcl 8.6 9
namespace eval ::packer {
variable version 0.9.0
}
proc ::packer::init {} {
variable defaultBuildOptions [sl {
# Where Packer's files are located.
packerPath [pwd]
# The path to the temporary directory in which the Starpacks are to be
# built.
# Can be relative (to packerPath) or absolute.
buildPath build
# The path where to place the built Starpacks.
# Can be relative (to packerPath) or absolute.
artifactsPath artifacts
# The Tclkit with which to run SDX.
buildTclkit tclkit-8.6.3-rhel5-x86_64
# A list of the Tclkits to use as Starpack runtimes.
targetTclkits tclkit-8.6.3-rhel5-x86_64
# The SDX Starkit file.
sdx sdx-20110317.kit
# The Tcllib archive file.
tcllib tcllib-2.0.tar.zst
# The Git repository to clone. Can be local or remote.
sourceRepository https://github.com/tclssg/tclssg
# The name of the commit, branch, or tag to check out of the repository.
revision master
# The directory that will appear once the sourceRepository is cloned.
projectDir tclssg
# The filename of the Starpack to create. Normally should not include
# an extension -- see the "suffix" option below for how extensions are
# automatically added.
targetFilename tclssg
# Which file within the projectDir the Starpack should source on start.
fileToSource ssg.tcl
# A script to evaluate when the Starpack starts on Windows. If set and
# not empty it is run *instead of* sourcing the file in fileToSource
# like on other platforms.
windowsScript {
source $argv0
::tclssg::main $argv0 $argv
}
# The command line options to run the Starpack with once it has been
# built. Unset to not test. This will not work across incompatible
# platforms.
testCommand version
# The string to append to the targetFilename. If set to %AUTO%,
# everything after the first dash in the targetTclkit's rootname is
# used. E.g, if targetTclkit is "tclkit-8.6.3-win32.exe", then the
# automatic suffix will be "-8.6.3-win32.exe".
suffix %AUTO%
}]
}
proc ::packer::sha-1? s {
return [regexp {^[a-fA-F0-9]{40}$} $s]
}
proc ::packer::auto? key {
return [expr { $key eq {%AUTO%} }]
}
proc ::packer::run args {
return [exec -ignorestderr -- {*}$args]
}
proc ::packer::opt {key {default %NONE%}} {
upvar 1 options options
if {[dict exists $options $key]} {
return [dict get $options $key]
} elseif {$default ne {%NONE%}} {
return $default
} else {
error [list no key $key in options]
}
}
# Build Starpacks. $args is a dictionary; see the variable defaultBuildOptions
# for the keys.
proc ::packer::build args {
# Parse $args.
set options [dict merge $::packer::defaultBuildOptions $args]
dict for {key value} $options {
puts [format {%-18s %s} $key [list $value]]
}
set fullBuildPath [file join [opt packerPath] [opt buildPath]]
set fullArtifactsPath [file join [opt packerPath] [opt artifactsPath]]
# Build start.
file delete -force $fullBuildPath
file mkdir $fullBuildPath
with-path $fullBuildPath {
run git clone [opt sourceRepository]
with-path [opt projectDir] {
run git fetch [opt sourceRepository] [opt revision]
run git checkout [opt revision]
set commit [run git rev-parse HEAD]
}
foreach path [list [opt buildTclkit] \
[opt sdx] \
[opt tcllib] \
{*}[opt targetTclkits]] {
file copy -force [file join [opt packerPath] $path] .
}
catch { file attributes [opt buildTclkit] -permissions +x }
file mkdir vfs
write-file vfs/git-commit $commit
file rename [opt projectDir] vfs/app
# Create the file main.tcl to start fileToSource.
set mainScript [regsub -all {\n } [format {
package require starkit
if {[starkit::startup] ne "sourced"} {
set argv0 [file join $starkit::topdir app %s]
if {$tcl_platform(platform) eq "windows"} {
eval %s
} else {
source $argv0
}
}
} [list [opt fileToSource]] [list [opt windowsScript]]] \n]
write-file vfs/main.tcl $mainScript
# Unpack Tcllib and install it in the subdirectory lib/tcllib of the
# Starkit VFS.
run zstd -d < [opt tcllib] | tar xf -
with-path [regsub .tar.zst$ [opt tcllib] {}] {
run {*}[sl {
>@ stdout
[file join .. [opt buildTclkit]]
./installer.tcl -no-wait
-no-gui
-no-html
-no-nroff
-no-examples
-no-apps
-pkgs
-pkg-path [file join $fullBuildPath \
vfs/lib/tcllib]
}]
}
# Wrap the Starpack. We make a temporary copy of each targetTclkit in
# case it is the same as the buildTclkit, which we may not be able to
# read.
foreach targetTclkit [opt targetTclkits] {
puts stderr [list building starpack with runtime $targetTclkit]
file copy $targetTclkit ${targetTclkit}.temp
run [file join . [opt buildTclkit]] \
[opt sdx] wrap [opt targetFilename] \
-vfs vfs \
-runtime ${targetTclkit}.temp
file delete ${targetTclkit}.temp
# Run the test command.
if {[info exists testCommand]} {
file attributes [opt targetFilename] -permissions +x
puts [exec -- [file join . [opt targetFilename] \
{*}[opt testCommand]]]
}
if {[auto? [opt suffix]]} {
# Abbreviate commit checksum.
set fullSuffix -[opt revision]-[string range $commit 0 9]
append fullSuffix -$targetTclkit
} else {
set fullSuffix [opt suffix]
}
# Store the build artifact.
file mkdir $fullArtifactsPath
set artifactFilename [opt targetFilename]$fullSuffix
file copy -force [opt targetFilename] \
[file join $fullArtifactsPath $artifactFilename]
# Record build information in a Tcl-readable format.
write-file [file join $fullArtifactsPath \
${artifactFilename}.txt] [sl {
$artifactFilename
built [utc-date-time]
from [opt sourceRepository]
revision [opt revision]
commit $commit
}]\n
}
# Remove build directory.
file delete -force $fullBuildPath
}
}
proc ::packer::utc-date-time {} {
return [clock format [clock seconds] \
-format {%Y-%m-%d %H:%M:%S UTC} \
-timezone UTC]
}
# Write $content to the file $path.
proc ::packer::write-file {path content {binary 0}} {
set ch [open $path w]
if {$binary} {
fconfigure $ch -translation binary
}
puts -nonewline $ch $content
close $ch
}
# Run $code in the directory $path.
proc ::packer::with-path {path code} {
set prevPath [pwd]
try {
cd $path
uplevel 1 $code
} finally {
cd $prevPath
}
}
# Parse a scripted list.
proc ::packer::sl script {
# By Poor Yorick. From https://tcl.wiki/39972.
set res {}
set parts {}
foreach part [split $script \n] {
lappend parts $part
set part [join $parts \n]
#add the newline that was stripped because it can make a difference
if {[info complete $part\n]} {
set parts {}
set part [string trim $part]
if {$part eq {}} {
continue
}
if {[string index $part 0] eq {#}} {
continue
}
#Here, the double-substitution via uplevel is intended!
lappend res {*}[uplevel list $part]
}
}
if {$parts ne {}} {
error [list {incomplete parts} [join $parts]]
}
return $res
}
::packer::init