forked from RubyLane/rl_json
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfetch_test_cases.tcl
executable file
·183 lines (152 loc) · 4.66 KB
/
fetch_test_cases.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
#!/usr/bin/env tclsh
# Doesn't work. It should, but github is serving the binary .json files as utf-8, which breaks all the carefully
# crafted encoding tests
# Dependencies:
# rl_json: https://github.com/RubyLane/rl_json
# parse_args: https://github.com/RubyLane/parse_args
# rl_http: https://github.com/RubyLane/rl_http
# urlencode: copied to support/
# uri: tcllib
# Thread: https://core.tcl-lang.org/thread
# tls: https://core.tcl-lang.org/tcltls/index
set here [file dirname [file normalize [info script]]]
tcl::tm::path add [file join $here support]
lappend auto_path $here
package require rl_json ;# yeah...
package require rl_http
package require parse_args
package require urlencode
interp alias {} json {} ::rl_json::json
interp alias {} parse_args {} ::parse_args::parse_args
proc http {method url args} { #<<<
parse_args $args {
-log {-default {{lvl msg} {}}}
-if_modified_since {-# {seconds since 1970-01-01 00:00:00 UTC}}
}
set headers {}
if {[info exists if_modified_since]} {
lappend headers If-Modified-Since [clock format $if_modified_since -format {%a, %d %b %Y %H:%M:%S GMT} -gmt 1]
#puts "If-Modified-Since: [lindex $headers end]"
}
while {[incr tries] <= 3} {
try {
apply $log notice "Fetching $method $url"
rl_http instvar h $method $url -headers $headers
} on error {errmsg options} {
throw [list HTTP RL_HTTP {*}[dict get $options -errorcode]] $errmsg
}
switch -glob -- [$h code] {
2* {
#puts "Headers:\n\t[join [lmap {k v} [$h headers] {format {%s: %s} $k $v}] \n\t]"
return [$h body]
}
304 {throw [list HTTP CODE [$h code]] "Not modified"}
301 - 302 - 307 {set url [lindex [dict get [$h headers] location] 0]}
403 {
if {[dict exists [$h headers] x-ratelimit-limit]} { # Rate limiting <<<
set limit [lindex [dict get [$h headers] x-ratelimit-limit] 0]
set remaining [lindex [dict get [$h headers] x-ratelimit-remaining] 0]
set reset [lindex [dict get [$h headers] x-ratelimit-reset] 0]
throw [list HTTP RATELIMIT $reset $limit $remaining] "Rate limited until [clock format $reset]"
#>>>
}
throw [list HTTP CODE [$h code]] [$h body]
}
503 {
apply $log warning "Got 503 error, waiting and trying again"
after 2000
}
default {
throw [list HTTP CODE [$h code]] "Error fetching $method $url: [$h code]\n[$h body]"
}
}
}
throw [list HTTP TOO_MANY_TRIES [expr {$tries-1}]] "Ran out of patience fetching $method $endoint after $tries failures"
}
#>>>
namespace eval ::github {
namespace export *
namespace ensemble create -prefixes no
proc endpoint args { #<<<
parse_args $args {
-owner {-required}
-repo {-required}
args {-name path_parts}
}
string cat \
https://api.github.com/repos/ \
[urlencode rfc_urlencode -part path -- $owner] \
/ \
[urlencode rfc_urlencode -part path -- $repo] \
/contents/ \
[join [lmap e $path_parts {urlencode rfc_urlencode -part path -- $e}] /]
}
#>>>
proc api {method args} { #<<<
set endpoint [github endpoint {*}$args]
http $method $endpoint
}
#>>>
}
proc writetext {fn data} { #<<<
set h [open $fn w]
try {
puts -nonewline $h $data
} finally {
close $h
}
}
#>>>
proc writebin {fn data} { #<<<
set h [open $fn wb]
try {
puts -nonewline $h $data
} finally {
close $h
}
}
#>>>
proc fetch_file {dest file} { #<<<
set fn [file join $dest [json get $file name]]
if {[file exists $fn]} {
set mtime [file mtime $fn]
try {
puts -nonewline "Fetching [json get $file name] -if_modified_since $mtime"
http GET [json get $file download_url] -if_modified_since $mtime
} on ok contents {
puts " [string length $contents] bytes"
writebin [file join $dest [json get $file name]] $contents
} trap {HTTP CODE 304} {} {
puts " not modified"
return
} on error {errmsg options} {
puts " Error: $errmsg"
}
} else {
try {
puts -nonewline "Fetching [json get $file name]"
http GET [json get $file download_url]
} on ok contents {
puts " [string length $contents] bytes"
writebin [file join $dest [json get $file name]] $contents
} on error {errmsg options} {
puts " Error: $errmsg"
}
}
}
#>>>
set dest [file join $here tests JSONTestSuite test_parsing]
file mkdir $dest
set listing [github api GET -owner nst -repo JSONTestSuite test_parsing]
#puts [json pretty $listing]
json foreach file $listing {
fetch_file $dest $file
}
set dest [file join $here tests JSONTestSuite test_transform]
file mkdir $dest
set listing [github api GET -owner nst -repo JSONTestSuite test_transform]
#puts [json pretty $listing]
json foreach file $listing {
fetch_file $dest $file
}
# vim: foldmethod=marker foldmarker=<<<,>>> ts=4 shiftwidth=4