-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathInstall.tcl
191 lines (171 loc) · 4.92 KB
/
Install.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
# Install.tcl -- download or update Wub from its svn repository
# NB: uses old-style coro form so it can cope with older 8.6 beta versions
if {[catch {package require Tcl 8.6}]} {
puts stderr "Tcl 8.6 required, you have [package provide Tcl]"
}
if {[catch {package require fileutil}]} {
puts stderr "tcllib required, doesn't appear to be present"
}
package require http
package provide Install 1.1
namespace eval Install {
variable base http://wub.googlecode.com/svn/
variable version trunk
variable home [file dirname [info script]]
proc gotfile {file token} {
if {[::http::status $token] ne "ok"} {
puts stderr "Failed to fetch file $file"
} elseif {[catch {
# copy file contents to $home
variable home
set file [string map {%20 " "} $file]
::fileutil::writeFile -encoding binary [file join $home $file] [::http::data $token]
::http::cleanup $token
} e eo]} {
puts stderr "gotfile error: $e ($eo)"
}
getter [list FILE $file] ;# signal file completion
}
proc gotdir {dir token} {
variable home
set dirn [string map {%20 " "} $dir]
if {[::http::status $token] ne "ok"} {
puts stderr "Failed to fetch dir $dir"
} elseif {![file exists [file join $home $dirn]] && [catch {
# create destination directory if needed
file mkdir [file join $home $dirn]
} e eo]} {
error $e
} elseif {[catch {
# decode body as a <li> of <A> tags pointing to directory contents
set body [::http::data $token]
set urls [regexp -inline -all -- {href="([^\"]+)"} $body]
set urls [dict values $urls]
variable dl
foreach name $urls {
set name [string map [list $dl/ ""] $name]
switch -glob -- $name {
http://* -
.* {
#puts "discarding $name"
continue
}
*/ {
# initiate directory fetch of $name
getter [list dir [file join $dir $name]/]
}
default {
# initiate file fetch of $name
getter [list file [file join $dir $name]]
}
}
}
::http::cleanup $token ;# finished dir page
} e eo]} {
puts "gotdir error $e ($eo)"
}
getter [list DIR $dir] ;# signal dir completion
}
# getter coroutine implementation
proc getC {args} {
variable queue ;# queued fetches
variable dl ;# base URL
variable limit ;# limit simultaneous fetches
variable loading 0 ;# number of pending fetches
variable pending {} ;# dict of pending fetches
variable loaded 0 ;# count of pages loaded
while {1} {
if {[catch {
lassign $args op path ;# decode args
# first process any completed fetches
switch -- $op {
FILE -
DIR {
incr loaded
incr loading -1
dict unset pending [string map {" " %20} $path]
puts stderr "DONE $loaded: $op $path ($loading/$limit) queue: [llength $queue] pending: [dict keys $pending]"
set queue [lassign $queue op path]
}
}
switch -- $op {
"" {
# nothing more queued yet, wait for completion
}
file -
dir {
# requested a fetch
if {$loading < $limit} {
# can fetch now
incr loading 1
variable dl
set cmd [list ::http::geturl $dl/$path -command [namespace code [list got$op $path]]]
puts stderr "GETTING: $op $path $loading/$limit ($cmd)"
puts stderr "$cmd"
dict set pending $path $op
{*}$cmd
} else {
# fetching would exceed limit on simultaneous fetches
lappend queue $op $path
puts stderr "QUEUEING: $op $path $loading/$limit queued: [llength $queue] pending: [dict keys $pending]"
}
}
default {
error "getter doesn't do $op $path"
}
}
} e eo]} {
puts stderr "CORO error: $e ($eo)"
}
set args [yield]
}
}
# waiter - vwaits until all pages are fetched
proc waiter {} {
variable queue
variable loading
while {1} {
vwait loading
puts "countdown: $loading/$limit queued: [llength $queue]"
if {$loading == 0} {
variable loaded
return $loaded
}
}
}
# start recursive getter coro to fetch all files from a repo
proc fetch {args} {
variable limit 10
variable version trunk
variable overwrite 0
variable {*}$args ;# set variables passed in
# clean up directories and URLs
variable home [file normalize $home]
variable base [string trimright $base /]
variable version [string trimright $version /]
if {!$overwrite
&& [file exists [file join $home .svn]]
} {
error "Refusing to overwrite subversion-controlled directory. Use 'overwrite 1' if you insist upon this."
}
# work on release
switch -glob -- $version {
trunk - head {
set version trunk
}
[2-9]* {
set version branches/RB-$version
}
}
variable dl [string trimright $base/$version /]
puts "Install '$dl' to '$home'"
coroutine ::Install::getter getC dir
if {[info exists wait] && $wait} {
waiter ;# caller asked us to vwait
}
}
namespace export -clear *
namespace ensemble create -subcommands {}
}
Install fetch home [pwd] {*}$argv
Install waiter