mswin-build 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/README.md +53 -0
- data/Rakefile +13 -0
- data/bin/build.rb +33 -0
- data/bin/kicker.rb +49 -0
- data/bin/tinyhttpd.rb +32 -0
- data/config/vc10-x86-1_9_3.yaml +3 -0
- data/config/vc10-x86-2_0_0.yaml +3 -0
- data/config/vc10-x86-trunk.yaml +3 -0
- data/lib/mswin-build/builder.rb +589 -0
- data/lib/mswin-build/process_tree.rb +80 -0
- data/lib/mswin-build/version.rb +3 -0
- data/mswin-build.gemspec +25 -0
- data/test/unit/test_builder.rb +260 -0
- data/test/unit/test_process_tree.rb +26 -0
- metadata +108 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cfe42674ee22526c93c3fd0347034be4f0af2f48
|
4
|
+
data.tar.gz: 599a68351770263a39ab8b8accf35d9eaa9a9915
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e90cc66dfc5614f26af3d2ecd259a78b4aeb7bd423ce4b50789d205e82dc72b2fb23d8a712344b6288ddec03451fee7d517363dba3e4a797b1c4ebad80178fff
|
7
|
+
data.tar.gz: b76b8068667a7c70447810af98fe555bd5fc8ad305694b86f7cf69f8bf234ba85d1a04b47d9b4b9edc79a018c6d041b415179dbe836ffca4e3c27c428241a4ee
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
mswin-build
|
2
|
+
===========
|
3
|
+
|
4
|
+
This software is originally published at https://github.com/unak/mswin-build .
|
5
|
+
|
6
|
+
|
7
|
+
What's This?
|
8
|
+
------------
|
9
|
+
|
10
|
+
A low quality clone of https://github.com/akr/chkbuild for mswin.
|
11
|
+
|
12
|
+
|
13
|
+
Requirements
|
14
|
+
------------
|
15
|
+
|
16
|
+
* ruby 1.9.3 or 2.0.0 or newer, with fiddle
|
17
|
+
* sed
|
18
|
+
* bison
|
19
|
+
* svn
|
20
|
+
* gzip
|
21
|
+
* and of cource, Visual C++ 6 or newer
|
22
|
+
|
23
|
+
|
24
|
+
How to Use
|
25
|
+
----------
|
26
|
+
|
27
|
+
Write a config file in config directory, and run `bin/build.rb`.
|
28
|
+
|
29
|
+
|
30
|
+
License
|
31
|
+
-------
|
32
|
+
|
33
|
+
Copyright (c) 2013 NAKAMURA Usaku usa@garbagecollect.jp
|
34
|
+
|
35
|
+
Redistribution and use in source and binary forms, with or without
|
36
|
+
modification, are permitted provided that the following conditions are met:
|
37
|
+
|
38
|
+
1. Redistributions of source code must retain the above copyright notice,
|
39
|
+
this list of conditions and the following disclaimer.
|
40
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
41
|
+
this list of conditions and the following disclaimer in the documentation
|
42
|
+
and/or other materials provided with the distribution.
|
43
|
+
|
44
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
|
45
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
46
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
47
|
+
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
|
48
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
49
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
50
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
51
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
52
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
53
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/Rakefile
ADDED
data/bin/build.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#! ruby
|
2
|
+
# expected ruby 1.9.x or later.
|
3
|
+
libdir = File.expand_path("../lib", File.dirname(__FILE__))
|
4
|
+
$LOAD_PATH.unshift(libdir) if File.directory?(libdir)
|
5
|
+
require "optparse"
|
6
|
+
require "rbconfig"
|
7
|
+
require "mswin-build/builder"
|
8
|
+
|
9
|
+
$debug = $DEBUG
|
10
|
+
opt = OptionParser.new
|
11
|
+
opt.banner = "Usage: ruby #$0 [options] <target name>"
|
12
|
+
opt.separator ""
|
13
|
+
opt.separator " This script automatically loads config/<target name>.yaml."
|
14
|
+
opt.separator ""
|
15
|
+
opt.separator "Options:"
|
16
|
+
opt.on('-v', '--verbose', 'Be verbose.') { $debug = true }
|
17
|
+
|
18
|
+
begin
|
19
|
+
opt.parse!(ARGV)
|
20
|
+
target = ARGV.shift
|
21
|
+
raise "target name is not specified." unless target
|
22
|
+
rescue RuntimeError => ex
|
23
|
+
puts ex.message
|
24
|
+
puts
|
25
|
+
puts opt.help
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
# use this running ruby as BASERUBY
|
30
|
+
baseruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"])
|
31
|
+
|
32
|
+
builder = MswinBuild::Builder.new(target: target, baseruby: baseruby, settings: File.expand_path("../config/#{target}.yaml", File.dirname(__FILE__)))
|
33
|
+
exit builder.run
|
data/bin/kicker.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!ruby
|
2
|
+
$LOAD_PATH.unshift(File.expand_path("../lib", File.dirname(__FILE__)))
|
3
|
+
require "tmpdir"
|
4
|
+
require "optparse"
|
5
|
+
require "rbconfig"
|
6
|
+
require "mswin-build/builder"
|
7
|
+
|
8
|
+
# use this running ruby as BASERUBY by default
|
9
|
+
baseruby = File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["ruby_install_name"] + RbConfig::CONFIG["EXEEXT"])
|
10
|
+
interval = 60
|
11
|
+
force_build = 24 * 60 * 60 # force build at least once in every day
|
12
|
+
|
13
|
+
opt = OptionParser.new
|
14
|
+
opt.banner = "Usage: ruby #$0 [options] <target name>"
|
15
|
+
opt.separator ""
|
16
|
+
opt.separator " This script automatically loads config/<target name>.yaml."
|
17
|
+
opt.separator ""
|
18
|
+
opt.separator "Options:"
|
19
|
+
opt.on('-v', '--verbose', "Be verbose. default = #{!$debug.nil? && $debug}") { $debug = true }
|
20
|
+
opt.on('-b <baseruby>', '--baseruby=<baserbuby>', "specify baseruby. default: #{baseruby}") { |v| baseruby = v }
|
21
|
+
opt.on('-i <seconds>', '--interval=<seconds>', "interval between each build. default: #{interval}") { |v| interval = Integer(v) }
|
22
|
+
opt.on('-f <seconds>', '--force-build=<seconds>', "force build after specified seconds from last bulid. default: #{force_build}") { |v| fource_build = Integer(v) }
|
23
|
+
|
24
|
+
begin
|
25
|
+
opt.parse!(ARGV)
|
26
|
+
raise "target name is not specified." if ARGV.empty?
|
27
|
+
rescue RuntimeError => ex
|
28
|
+
puts ex.message
|
29
|
+
puts
|
30
|
+
puts opt.help
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
loop do
|
35
|
+
ARGV.each do |target|
|
36
|
+
builder = MswinBuild::Builder.new(target: target, baseruby: baseruby, settings: File.expand_path("../config/#{target}.yaml", File.dirname(__FILE__)))
|
37
|
+
if !builder.get_last_build_time || builder.get_last_build_time + force_build < Time.now || builder.get_last_revision != builder.get_current_revision
|
38
|
+
cmd = [baseruby, File.expand_path("build.rb", File.dirname(__FILE__)), target]
|
39
|
+
cmd << "-v" if $debug
|
40
|
+
puts "+++ #{Time.now} Start #{target} +++" if $debug
|
41
|
+
system(*cmd)
|
42
|
+
puts "--- #{Time.now} Finish #{target} ---" if $debug
|
43
|
+
else
|
44
|
+
puts "=== #{Time.now} Skipped #{target} ===" if $debug
|
45
|
+
end
|
46
|
+
end
|
47
|
+
puts "=== #{Time.now} Pausing #{interval} seconds ===" if $debug
|
48
|
+
sleep interval
|
49
|
+
end
|
data/bin/tinyhttpd.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#! ruby
|
2
|
+
# expected ruby 1.9.x or later.
|
3
|
+
|
4
|
+
require "webrick"
|
5
|
+
|
6
|
+
class WEBrick::HTTPServer
|
7
|
+
alias :__rewrite_old_service :service
|
8
|
+
def service(req, res)
|
9
|
+
ret = __rewrite_old_service(req, res)
|
10
|
+
if /\.html\.gz\z/ =~ req.path
|
11
|
+
res.header["content-encoding"] = "gzip"
|
12
|
+
res.header["content-type"] = "text/html"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
root = ARGV.shift
|
18
|
+
unless root
|
19
|
+
puts "Usage: ruby #$0 <document root>"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
options = {
|
24
|
+
DocumentRoot: root,
|
25
|
+
}
|
26
|
+
|
27
|
+
server = WEBrick::HTTPServer.new(options)
|
28
|
+
shutdown = proc { server.shutdown }
|
29
|
+
(%w"TERM QUIT HUP INT" & Signal.list.keys).each do |sig|
|
30
|
+
Signal.trap(sig, shutdown)
|
31
|
+
end
|
32
|
+
server.start
|
@@ -0,0 +1,589 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "fileutils"
|
3
|
+
require "socket"
|
4
|
+
require "time"
|
5
|
+
require "timeout"
|
6
|
+
require "tmpdir"
|
7
|
+
require "yaml"
|
8
|
+
require "mswin-build/process_tree"
|
9
|
+
|
10
|
+
module MswinBuild
|
11
|
+
class Builder
|
12
|
+
def initialize(h)
|
13
|
+
@target = h.delete(:target) || raise("target not specified")
|
14
|
+
baseruby = h.delete(:baseruby)
|
15
|
+
yaml = h.delete(:settings) || raise("settings not specified")
|
16
|
+
unless h.empty?
|
17
|
+
raise "unknown option(s): #{h}"
|
18
|
+
end
|
19
|
+
@config = YAML.load(IO.read(yaml, encoding: "utf-8"))
|
20
|
+
@config["baseruby"] = baseruby if baseruby
|
21
|
+
@config["bison"] ||= "bison"
|
22
|
+
@config["svn"] ||= "svn"
|
23
|
+
@config["gzip"] ||= "gzip"
|
24
|
+
|
25
|
+
raise "baseruby not specified" unless @config["baseruby"]
|
26
|
+
raise "repository not specified" unless @config["repository"]
|
27
|
+
raise "logdir not specfied" unless @config["logdir"]
|
28
|
+
|
29
|
+
@title = []
|
30
|
+
@links = {}
|
31
|
+
|
32
|
+
@config["timeout"] ||= {}
|
33
|
+
@config["timeout"]["default"] ||= 10 * 60 # default 10 min
|
34
|
+
@config["timeout"]["default_short"] ||= 60 # default 1 min
|
35
|
+
@config["timeout"]["default_long"] ||= 30 * 60 # default 30 min
|
36
|
+
@config["timeout"]["start"] ||= @config["timeout"]["default_short"]
|
37
|
+
@config["timeout"]["bison-version"] ||= @config["timeout"]["default_short"]
|
38
|
+
@config["timeout"]["svn/ruby"] ||= @config["timeout"]["default"]
|
39
|
+
@config["timeout"]["svn/info"] ||= @config["timeout"]["default_short"]
|
40
|
+
@config["timeout"]["configure"] ||= @config["timeout"]["default"]
|
41
|
+
@config["timeout"]["cc-version"] ||= @config["timeout"]["default_short"]
|
42
|
+
@config["timeout"]["miniruby"] ||= @config["timeout"]["default"]
|
43
|
+
@config["timeout"]["miniversion"] ||= @config["timeout"]["default_short"]
|
44
|
+
@config["timeout"]["btest"] ||= @config["timeout"]["default"]
|
45
|
+
@config["timeout"]["test.rb"] ||= @config["timeout"]["default"]
|
46
|
+
@config["timeout"]["showflags"] ||= @config["timeout"]["default_short"]
|
47
|
+
@config["timeout"]["main"] ||= @config["timeout"]["default_long"]
|
48
|
+
@config["timeout"]["docs"] ||= @config["timeout"]["default"]
|
49
|
+
@config["timeout"]["version"] ||= @config["timeout"]["default_short"]
|
50
|
+
@config["timeout"]["install-nodoc"] ||= @config["timeout"]["default"]
|
51
|
+
@config["timeout"]["install-doc"] ||= @config["timeout"]["default"]
|
52
|
+
@config["timeout"]["test-knownbug"] ||= @config["timeout"]["default"]
|
53
|
+
@config["timeout"]["test-all"] ||= @config["timeout"]["default_long"]
|
54
|
+
|
55
|
+
@last_status = nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def run
|
59
|
+
begin
|
60
|
+
orig_path = insert_path("PATH", @config["path_add"])
|
61
|
+
orig_include = insert_path("INCLUDE", @config["include_add"])
|
62
|
+
orig_lib = insert_path("LIB", @config["lib_add"])
|
63
|
+
if @config["tmpdir"]
|
64
|
+
@config["env"] ||= {}
|
65
|
+
@config["env"]["TMP"] ||= @config["tmpdir"].gsub(%r(/), '\\')
|
66
|
+
@config["env"]["TEMP"] ||= @config["tmpdir"].gsub(%r(/), '\\')
|
67
|
+
end
|
68
|
+
orig_env = {}
|
69
|
+
(@config["env"] || {}).each do |name, value|
|
70
|
+
orig_env[name] = ENV[name]
|
71
|
+
ENV[name] = value
|
72
|
+
end
|
73
|
+
files = []
|
74
|
+
Dir.mktmpdir("mswin-build", @config["tmpdir"]) do |tmpdir|
|
75
|
+
files << baseinfo(tmpdir)
|
76
|
+
files << checkout(tmpdir)
|
77
|
+
if @last_status && @last_status.success?
|
78
|
+
files << configure(tmpdir)
|
79
|
+
files << cc_version(tmpdir)
|
80
|
+
files << miniruby(tmpdir)
|
81
|
+
files << miniversion(tmpdir)
|
82
|
+
files << btest(tmpdir)
|
83
|
+
files << testrb(tmpdir)
|
84
|
+
#files << method_list(tmpdir)
|
85
|
+
files << showflags(tmpdir) if ruby_version >= "1.9.3"
|
86
|
+
files << main(tmpdir)
|
87
|
+
files << docs(tmpdir)
|
88
|
+
files << version(tmpdir)
|
89
|
+
files << install_nodoc(tmpdir)
|
90
|
+
files << install_doc(tmpdir)
|
91
|
+
#files << version_list(tmpdir)
|
92
|
+
files << test_knownbug(tmpdir)
|
93
|
+
files << test_all(tmpdir)
|
94
|
+
files << rubyspec(tmpdir)
|
95
|
+
end
|
96
|
+
files << end_(tmpdir)
|
97
|
+
logfile = gather_log(files, tmpdir)
|
98
|
+
difffile = diff(tmpdir, logfile)
|
99
|
+
logfile = gzip(logfile)
|
100
|
+
gzip(difffile)
|
101
|
+
add_recent(logfile)
|
102
|
+
add_summary(logfile)
|
103
|
+
end
|
104
|
+
true
|
105
|
+
rescue
|
106
|
+
STDERR.puts $!
|
107
|
+
STDERR.puts $!.backtrace
|
108
|
+
false
|
109
|
+
ensure
|
110
|
+
orig_env.each_pair do |name, value|
|
111
|
+
if value
|
112
|
+
ENV[name] = value
|
113
|
+
else
|
114
|
+
ENV.delete(name)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
ENV["LIB"] = orig_lib if orig_lib
|
118
|
+
ENV["INCLUDE"] = orig_include if orig_include
|
119
|
+
ENV["PATH"] = orig_path if orig_path
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_current_revision
|
124
|
+
orig_lang = ENV["LANG"]
|
125
|
+
ENV["LANG"] = "C"
|
126
|
+
begin
|
127
|
+
if /^(?:SVN )?Last Changed Rev: (\d+)$/ =~ `#{@config['svn']} info #{@config['repository']}`
|
128
|
+
$1
|
129
|
+
else
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
rescue
|
133
|
+
nil
|
134
|
+
ensure
|
135
|
+
ENV["LANG"] = orig_lang
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def get_last_revision
|
140
|
+
recent = File.join(@config["logdir"], "recent.html")
|
141
|
+
return nil unless File.exist?(recent)
|
142
|
+
file = nil
|
143
|
+
open(recent, "r") do |f|
|
144
|
+
f.read.scan(/^<a href="(.+?)".*?<br>$/) do |line|
|
145
|
+
file = $1
|
146
|
+
break
|
147
|
+
end
|
148
|
+
end
|
149
|
+
return nil unless file
|
150
|
+
|
151
|
+
cmd = "#{@config['gzip']} -d -c #{File.join(@config['logdir'], file)}"
|
152
|
+
`#{cmd}`.scan(/^(?:SVN )?Last Changed Rev: (\d+)$/) do |line|
|
153
|
+
return $1
|
154
|
+
end
|
155
|
+
nil
|
156
|
+
end
|
157
|
+
|
158
|
+
def get_last_build_time
|
159
|
+
recent = File.join(@config["logdir"], "recent.html")
|
160
|
+
return nil unless File.exist?(recent)
|
161
|
+
open(recent, "r") do |f|
|
162
|
+
f.read.scan(/^<a href="(.+?)".*?<br>$/) do |line|
|
163
|
+
return Time.parse(File.basename($1, ".log.html"))
|
164
|
+
end
|
165
|
+
end
|
166
|
+
return nil
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
def u(str)
|
171
|
+
CGI.escape(str)
|
172
|
+
end
|
173
|
+
|
174
|
+
def h(str)
|
175
|
+
CGI.escapeHTML(str)
|
176
|
+
end
|
177
|
+
|
178
|
+
def insert_path(env, add)
|
179
|
+
return nil unless add
|
180
|
+
orig = ENV[env]
|
181
|
+
if orig
|
182
|
+
add += ";" unless add[-1] == ?;
|
183
|
+
ENV[env] = add + orig
|
184
|
+
else
|
185
|
+
ENV[env] = add
|
186
|
+
end
|
187
|
+
orig
|
188
|
+
end
|
189
|
+
|
190
|
+
def spawn_with_timeout(name, command, io)
|
191
|
+
pid = nil
|
192
|
+
begin
|
193
|
+
ret = nil
|
194
|
+
timeout(@config["timeout"][name] || @config["timeout"]["default"]) do
|
195
|
+
begin
|
196
|
+
pid = Process.spawn(command, out: io, err: io)
|
197
|
+
_, ret = Process.waitpid2(pid)
|
198
|
+
rescue
|
199
|
+
ret = nil
|
200
|
+
end
|
201
|
+
end
|
202
|
+
ret
|
203
|
+
rescue Timeout::Error => ex
|
204
|
+
MswinBuild::ProcessTree.terminate_process_tree(pid) if pid
|
205
|
+
raise ex
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def do_command(io, name, command, in_builddir = false, check_retval = true, lang = "C")
|
210
|
+
heading(io, name)
|
211
|
+
status = nil
|
212
|
+
if lang
|
213
|
+
orig_lang = ENV["LANG"]
|
214
|
+
ENV["LANG"] = lang
|
215
|
+
end
|
216
|
+
begin
|
217
|
+
if $debug
|
218
|
+
puts "+ #{command}"
|
219
|
+
$stdout.flush
|
220
|
+
end
|
221
|
+
io.puts "+ #{command}"
|
222
|
+
io.flush
|
223
|
+
if in_builddir
|
224
|
+
if File.exist?(@builddir)
|
225
|
+
Dir.chdir(@builddir) do
|
226
|
+
status = spawn_with_timeout(name, command, io)
|
227
|
+
end
|
228
|
+
else
|
229
|
+
status = nil
|
230
|
+
end
|
231
|
+
else
|
232
|
+
status = spawn_with_timeout(name, command, io)
|
233
|
+
end
|
234
|
+
|
235
|
+
if status.nil? || !status.success?
|
236
|
+
io.puts "exit #{status.to_i}" unless status.nil?
|
237
|
+
io.puts "failed(#{name})"
|
238
|
+
@title << "failed(#{name})" if check_retval || status.nil?
|
239
|
+
@links[name] << "failed"
|
240
|
+
if $debug
|
241
|
+
puts %'failed(#{name}) #{status.nil? ? "because maybe command not found" : "with status #{status.to_i}"}'
|
242
|
+
$stdout.flush
|
243
|
+
end
|
244
|
+
end
|
245
|
+
rescue Timeout::Error
|
246
|
+
io.puts
|
247
|
+
io.printf "|output interval exceeds %.1f seconds. (CommandTimeout)", @config["timeout"][name] || @config["timeout"]["default"]
|
248
|
+
io.puts $!.backtrace.join("\n| ")
|
249
|
+
io.puts "failed(#{name} CommandTimeout)"
|
250
|
+
@title << "failed(#{name} CommandTimeout)"
|
251
|
+
@links[name] << "failed"
|
252
|
+
if $debug
|
253
|
+
puts "failed(#{name} CommandTimeout)"
|
254
|
+
$stdout.flush
|
255
|
+
end
|
256
|
+
ensure
|
257
|
+
ENV["LANG"] = orig_lang if lang
|
258
|
+
end
|
259
|
+
@last_status = status
|
260
|
+
status.nil? ? nil : status.success?
|
261
|
+
end
|
262
|
+
|
263
|
+
def heading(io, name)
|
264
|
+
if $debug
|
265
|
+
puts "== #{name}"
|
266
|
+
$stdout.flush
|
267
|
+
end
|
268
|
+
anchor = u name.to_s.tr('_', '-')
|
269
|
+
text = h name.to_s.tr('_', '-')
|
270
|
+
io.puts %'<a name="#{anchor}">== #{text}</a> \# #{h Time.now.iso8601}'
|
271
|
+
@links[name] = [anchor, text]
|
272
|
+
end
|
273
|
+
|
274
|
+
def self.define_buildmethod(method, &blk)
|
275
|
+
define_method("bare_#{method.to_s}", blk)
|
276
|
+
define_method(method) do |tmpdir|
|
277
|
+
io = open(File.join(tmpdir, method.to_s), "w+")
|
278
|
+
begin
|
279
|
+
__send__("bare_#{method.to_s}", io, tmpdir)
|
280
|
+
ensure
|
281
|
+
io.close
|
282
|
+
end
|
283
|
+
io
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
define_buildmethod(:baseinfo) do |io, tmpdir|
|
288
|
+
@start_time = Time.now
|
289
|
+
# target
|
290
|
+
heading(io, @target)
|
291
|
+
host = Socket.gethostname.split(/\./).first
|
292
|
+
@title << "(#{host})"
|
293
|
+
io.puts "Nickname: #{host}"
|
294
|
+
io.puts "#{`ver`.gsub(/\r?\n/, '')} #{ENV['OS']} #{ENV['ProgramW6432'] ? 'x64' : 'i386'}"
|
295
|
+
|
296
|
+
# start
|
297
|
+
heading(io, "start")
|
298
|
+
|
299
|
+
# cpu-info
|
300
|
+
#heading(io, "cpu-info")
|
301
|
+
|
302
|
+
# bison-version
|
303
|
+
do_command(io, "bison-version", "#{@config['bison']} --version")
|
304
|
+
end
|
305
|
+
|
306
|
+
define_buildmethod(:checkout) do |io, tmpdir|
|
307
|
+
# svn/ruby
|
308
|
+
Dir.chdir(tmpdir) do
|
309
|
+
do_command(io, "svn/ruby", "#{@config['svn']} checkout #{@config['repository']} ruby")
|
310
|
+
end
|
311
|
+
|
312
|
+
# svn-info/ruby
|
313
|
+
@builddir = File.join(tmpdir, "ruby")
|
314
|
+
do_command(io, "svn-info/ruby", "#{@config['svn']} info", true)
|
315
|
+
end
|
316
|
+
|
317
|
+
define_buildmethod(:configure) do |io, tmpdir|
|
318
|
+
options = " --with-baseruby=#{@config['baseruby'].gsub(%r(/), '\\')}" if ruby_version >= "1.9.0"
|
319
|
+
do_command(io, "configure", "win32/configure.bat --prefix=#{destdir(tmpdir)}#{options}", true)
|
320
|
+
end
|
321
|
+
|
322
|
+
define_buildmethod(:cc_version) do |io, tmpdir|
|
323
|
+
do_command(io, "cc-version", "cl")
|
324
|
+
end
|
325
|
+
|
326
|
+
define_buildmethod(:miniruby) do |io, tmpdir|
|
327
|
+
do_command(io, "miniruby", "nmake -l miniruby", true)
|
328
|
+
end
|
329
|
+
|
330
|
+
define_buildmethod(:miniversion) do |io, tmpdir|
|
331
|
+
do_command(io, "miniversion", "./miniruby -v", true)
|
332
|
+
end
|
333
|
+
|
334
|
+
define_buildmethod(:btest) do |io, tmpdir|
|
335
|
+
ret = do_command(io, "btest", 'nmake -l "OPTS=-v -q" btest', true, false)
|
336
|
+
if !ret && !ret.nil?
|
337
|
+
io.rewind
|
338
|
+
if %r'^FAIL (\d+)/\d+' =~ io.read
|
339
|
+
@title << "#{$1}BFail"
|
340
|
+
else
|
341
|
+
@title << "failed(btest)"
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
define_buildmethod(:testrb) do |io, tmpdir|
|
347
|
+
ret = do_command(io, "test.rb", "./miniruby sample/test.rb", true, false)
|
348
|
+
if !ret && !ret.nil?
|
349
|
+
io.rewind
|
350
|
+
if %r'^not ok/test: \d+ failed (\d+)' =~ io.read
|
351
|
+
@title << "#{$1}NotOK"
|
352
|
+
else
|
353
|
+
@title << "failed(test.rb)"
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
define_buildmethod(:showflags) do |io, tmpdir|
|
359
|
+
do_command(io, "showflags", "nmake -l showflags", true)
|
360
|
+
end
|
361
|
+
|
362
|
+
define_buildmethod(:main) do |io, tmpdir|
|
363
|
+
do_command(io, "main", "nmake -l main", true)
|
364
|
+
end
|
365
|
+
|
366
|
+
define_buildmethod(:docs) do |io, tmpdir|
|
367
|
+
do_command(io, "docs", "nmake -l docs", true)
|
368
|
+
end
|
369
|
+
|
370
|
+
define_buildmethod(:version) do |io, tmpdir|
|
371
|
+
if do_command(io, "version", "./ruby -v", true)
|
372
|
+
io.rewind
|
373
|
+
@title.unshift(io.read.split(/\r?\n/).last.chomp)
|
374
|
+
else
|
375
|
+
@title.unshift(@target)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
define_buildmethod(:install_nodoc) do |io, tmpdir|
|
380
|
+
options = " DESTDIR=#{destdir(tmpdir)}" if ruby_version < "1.9.0"
|
381
|
+
do_command(io, "install-nodoc", "nmake -l install-nodoc#{options}", true)
|
382
|
+
end
|
383
|
+
|
384
|
+
define_buildmethod(:install_doc) do |io, tmpdir|
|
385
|
+
options = " DESTDIR=#{destdir(tmpdir)}" if ruby_version < "1.9.0"
|
386
|
+
do_command(io, "install-doc", "nmake -l install-doc#{options}", true)
|
387
|
+
end
|
388
|
+
|
389
|
+
define_buildmethod(:test_knownbug) do |io, tmpdir|
|
390
|
+
do_command(io, "test-knownbug", 'nmake -l "OPTS=-v -q" test-knownbug', true, false)
|
391
|
+
end
|
392
|
+
|
393
|
+
define_buildmethod(:test_all) do |io, tmpdir|
|
394
|
+
ret = do_command(io, "test-all", "nmake -l TESTS=-v RUBYOPT=-w test-all", true, false, nil)
|
395
|
+
if !ret && !ret.nil?
|
396
|
+
io.rewind
|
397
|
+
if %r'^\d+ tests, \d+ assertions, (\d+) failures, (\d+) errors, (\d+) skips' =~ io.read
|
398
|
+
@title << "#{$1}F#{$2}E"
|
399
|
+
else
|
400
|
+
@title << "failed(test-all)"
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
define_buildmethod(:rubyspec) do |io, tmpdir|
|
406
|
+
heading(io, "rubyspec")
|
407
|
+
io.puts "skipped."
|
408
|
+
@links["rubyspec"] << "skipped"
|
409
|
+
end
|
410
|
+
|
411
|
+
define_buildmethod(:end_) do |io, tmpdir|
|
412
|
+
unless /failed|BFail|NotOK|\d+F\d+E/ =~ @title.join
|
413
|
+
heading(io, "success")
|
414
|
+
@title << "success"
|
415
|
+
end
|
416
|
+
|
417
|
+
heading(io, "end")
|
418
|
+
diff = Time.now - @start_time
|
419
|
+
io.printf "elapsed %.1fs = %dm %04.1fs\n", diff, diff / 60, diff % 60
|
420
|
+
end
|
421
|
+
|
422
|
+
def destdir(tmpdir)
|
423
|
+
File.join(tmpdir, 'install')
|
424
|
+
end
|
425
|
+
|
426
|
+
def ruby_version
|
427
|
+
if /_(\d)_(\d)(?:_(\d+))?$/ =~ @config["repository"]
|
428
|
+
return "#{$1}.#{$2}.#{$3 || 9}"
|
429
|
+
else
|
430
|
+
return "9.9.9" # means unknown (maybe trunk)
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
def header(io)
|
435
|
+
title = @title.join(' ')
|
436
|
+
io.puts <<-EOH
|
437
|
+
<html>
|
438
|
+
<head>
|
439
|
+
<title>#{h title}</title>
|
440
|
+
<meta name="author" content="mswin-build">
|
441
|
+
<meta name="generator" content="mswin-build">
|
442
|
+
</head>
|
443
|
+
<body>
|
444
|
+
<h1>#{h title}</h1>
|
445
|
+
<p>
|
446
|
+
<a href="../../">mswin-build</a>
|
447
|
+
<a href="../summary.html">summary</a>
|
448
|
+
<a href="../recent.html">recent</a>
|
449
|
+
</p>
|
450
|
+
EOH
|
451
|
+
end
|
452
|
+
|
453
|
+
def footer(io)
|
454
|
+
io.puts <<-EOH
|
455
|
+
<hr>
|
456
|
+
<p>
|
457
|
+
<a href="../../">mswin-build</a>
|
458
|
+
<a href="../summary.html">summary</a>
|
459
|
+
<a href="../recent.html">recent</a>
|
460
|
+
</p>
|
461
|
+
</body>
|
462
|
+
</html>
|
463
|
+
EOH
|
464
|
+
end
|
465
|
+
|
466
|
+
def gather_log(files, tmpdir)
|
467
|
+
logdir = File.join(@config["logdir"], "log")
|
468
|
+
FileUtils.mkdir_p(logdir)
|
469
|
+
logfile = File.join(logdir, @start_time.dup.utc.strftime('%Y%m%dT%H%M%SZ.log.html'))
|
470
|
+
warns = 0
|
471
|
+
revision = nil
|
472
|
+
open(File.join(tmpdir, "gathered"), "w") do |out|
|
473
|
+
files.each_with_index do |io, i|
|
474
|
+
next unless io
|
475
|
+
io.reopen(io.path, "r")
|
476
|
+
begin
|
477
|
+
io.each_line do |line|
|
478
|
+
line = h(line) unless /^<a / =~ line
|
479
|
+
out.write line
|
480
|
+
warns += line.scan(/warn/i).length
|
481
|
+
if File.basename(io.path) == "checkout" && /^(?:SVN )?Last Changed Rev: (\d+)$/ =~ line
|
482
|
+
revision = $1
|
483
|
+
end
|
484
|
+
end
|
485
|
+
ensure
|
486
|
+
io.close
|
487
|
+
io.unlink rescue nil
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
@title.insert(2, "#{warns}W") if warns > 0
|
492
|
+
@title.unshift("r#{revision}") if revision
|
493
|
+
open(logfile, "w") do |out|
|
494
|
+
header(out)
|
495
|
+
out.puts " <ul>"
|
496
|
+
@links.each_value do |anchor, text, result = nil|
|
497
|
+
out.puts %' <li><a href="\##{anchor}">#{text}</a>#{" #{result}" if result}</li>'
|
498
|
+
end
|
499
|
+
out.puts " </ul>"
|
500
|
+
out.puts " <pre>"
|
501
|
+
out.write IO.read(File.join(tmpdir, "gathered"))
|
502
|
+
out.puts " </pre>"
|
503
|
+
footer(out)
|
504
|
+
end
|
505
|
+
logfile
|
506
|
+
end
|
507
|
+
|
508
|
+
def diff(tmpdir, logfile)
|
509
|
+
filename = logfile.sub(/\.log/, ".diff")
|
510
|
+
open(filename, "w") do |out|
|
511
|
+
header(out)
|
512
|
+
out.puts %'<p>Skipped. See the <a href="#{u File.basename(logfile)}.gz">full build log</a>.</p>'
|
513
|
+
footer(out)
|
514
|
+
end
|
515
|
+
filename
|
516
|
+
end
|
517
|
+
|
518
|
+
def gzip(file)
|
519
|
+
system("#{@config['gzip']} #{file}")
|
520
|
+
file + ".gz"
|
521
|
+
end
|
522
|
+
|
523
|
+
def add_recent(logfile)
|
524
|
+
add_recent_summary(logfile, :recent)
|
525
|
+
end
|
526
|
+
|
527
|
+
def add_summary(logfile)
|
528
|
+
add_recent_summary(logfile, :summary)
|
529
|
+
end
|
530
|
+
|
531
|
+
def add_recent_summary(logfile, mode)
|
532
|
+
if mode == :recent
|
533
|
+
filename = File.join(@config["logdir"], "recent.html")
|
534
|
+
else
|
535
|
+
filename = File.join(@config["logdir"], "summary.html")
|
536
|
+
end
|
537
|
+
old = []
|
538
|
+
if File.exist?(filename)
|
539
|
+
open(filename, "r") do |f|
|
540
|
+
f.read.scan(/^(<a .*?<br>)$/) do |line| #"
|
541
|
+
old << line
|
542
|
+
end
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
title = @title.join(' ')
|
547
|
+
time = File.basename(logfile, ".log.html.gz")
|
548
|
+
line = %'<a href="log/#{u time}.log.html.gz" name="#{u time}">#{h time}</a> #{h title} (<a href="log/#{u time}.diff.html.gz">#{@diff ? h(@diff) : "no diff"}</a>)<br>'
|
549
|
+
if mode == :recent
|
550
|
+
old = old[0..99]
|
551
|
+
old.unshift(line)
|
552
|
+
else
|
553
|
+
old.push(line)
|
554
|
+
end
|
555
|
+
open(filename, "w") do |f|
|
556
|
+
f.print <<-EOH
|
557
|
+
<html>
|
558
|
+
<head>
|
559
|
+
<title>#{h File.basename(@config['logdir'])} #{h mode.to_s} build summary (#{h @target})</title>
|
560
|
+
<meta name="author" content="mswin-build">
|
561
|
+
<meta name="generator" content="mswin-build">
|
562
|
+
</head>
|
563
|
+
<body>
|
564
|
+
<h1>#{h File.basename(@config['logdir'])} #{h mode.to_s} build summary (#{h @target})</h1>
|
565
|
+
<p>
|
566
|
+
<a href="../">mswin-build</a>
|
567
|
+
<a href="./summary.html">summary</a>
|
568
|
+
<a href="./recent.html">recent</a>
|
569
|
+
</p>
|
570
|
+
EOH
|
571
|
+
|
572
|
+
old.each do |line|
|
573
|
+
f.puts line
|
574
|
+
end
|
575
|
+
|
576
|
+
f.print <<-EOH
|
577
|
+
<hr>
|
578
|
+
<p>
|
579
|
+
<a href="../">mswin-build</a>
|
580
|
+
<a href="./summary.html">summary</a>
|
581
|
+
<a href="./recent.html">recent</a>
|
582
|
+
</p>
|
583
|
+
</body>
|
584
|
+
</html>
|
585
|
+
EOH
|
586
|
+
end
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
begin
|
2
|
+
require "fiddle/import"
|
3
|
+
require "fiddle/types"
|
4
|
+
rescue LoadError
|
5
|
+
# 1.9?
|
6
|
+
require "dl/import"
|
7
|
+
require "dl/types"
|
8
|
+
|
9
|
+
Fiddle::Importer = DL::Importer
|
10
|
+
Fiddle::Win32Types = DL::Win32Types
|
11
|
+
end
|
12
|
+
|
13
|
+
module MswinBuild
|
14
|
+
module ProcessTree
|
15
|
+
extend Fiddle::Importer
|
16
|
+
|
17
|
+
dlload "kernel32.dll", "ntdll.dll"
|
18
|
+
|
19
|
+
include Fiddle::Win32Types
|
20
|
+
if /64/ =~ RUBY_PLATFORM
|
21
|
+
typealias "ULONG_PTR", "unsigned long long"
|
22
|
+
else
|
23
|
+
typealias "ULONG_PTR", "unsigned long"
|
24
|
+
end
|
25
|
+
typealias "TCHAR", "char"
|
26
|
+
|
27
|
+
# from tlhelp32.h
|
28
|
+
TH32CS_SNAPPROCESS = 0x00000002
|
29
|
+
PROCESSENTRY32 = struct([
|
30
|
+
"DWORD dwSize",
|
31
|
+
"DWORD cntUsage",
|
32
|
+
"DWORD th32ProcessID",
|
33
|
+
"ULONG_PTR th32DefaultHeapID",
|
34
|
+
"DWORD th32ModuleID",
|
35
|
+
"DWORD cntThreads",
|
36
|
+
"DWORD th32ParentProcessID",
|
37
|
+
"long pcPriClassBase",
|
38
|
+
"DWORD dwFlags",
|
39
|
+
"TCHAR szExeFile[260]", # [MAX_PATH]
|
40
|
+
])
|
41
|
+
|
42
|
+
# from kernel32.dll
|
43
|
+
extern "BOOL CloseHandle(HANDLE)"
|
44
|
+
extern "HANDLE CreateToolhelp32Snapshot(DWORD, DWORD)"
|
45
|
+
extern "BOOL Process32First(HANDLE, VOID*)"
|
46
|
+
extern "BOOL Process32Next(HANDLE, VOID*)"
|
47
|
+
extern "DWORD GetLastError(void)"
|
48
|
+
|
49
|
+
def self.terminate_process_tree(pid, code = 0)
|
50
|
+
begin
|
51
|
+
terminated = 0
|
52
|
+
h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
|
53
|
+
unless pid == Process.pid
|
54
|
+
Process.kill(:KILL, pid)
|
55
|
+
terminated += 1
|
56
|
+
end
|
57
|
+
pe32 = PROCESSENTRY32.malloc
|
58
|
+
pe32.dwSize = PROCESSENTRY32.size
|
59
|
+
if Process32First(h, pe32) != 0
|
60
|
+
begin
|
61
|
+
if pe32.th32ParentProcessID == pid
|
62
|
+
terminated += terminate_process_tree(pe32.th32ProcessID, code)
|
63
|
+
end
|
64
|
+
end while Process32Next(h, pe32) != 0
|
65
|
+
else
|
66
|
+
raise sprintf("Cannot get processes: %d", GetLastError())
|
67
|
+
end
|
68
|
+
ensure
|
69
|
+
CloseHandle(h) if h
|
70
|
+
end
|
71
|
+
|
72
|
+
if pid == Process.pid
|
73
|
+
Process.kill(:KILL, pid)
|
74
|
+
terminated += 1
|
75
|
+
end
|
76
|
+
|
77
|
+
terminated
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/mswin-build.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# -*- Ruby -*-
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'mswin-build/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "mswin-build"
|
9
|
+
spec.version = MswinBuild::VERSION
|
10
|
+
spec.authors = ["U.Nakamura"]
|
11
|
+
spec.email = ["usa@garbagecollect.jp"]
|
12
|
+
spec.description = %q{A low quality clone of https://github.com/akr/chkbuild for mswin.}
|
13
|
+
spec.summary = %q{A low quality clone of https://github.com/akr/chkbuild for mswin.}
|
14
|
+
spec.homepage = "https://github.com/unak/mswin-build"
|
15
|
+
spec.license = "BSD-2-Clause"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "test-unit"
|
25
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "tmpdir"
|
3
|
+
require "tempfile"
|
4
|
+
require "test/unit"
|
5
|
+
require "mswin-build/builder.rb"
|
6
|
+
|
7
|
+
module ProcessMock
|
8
|
+
@callback = nil
|
9
|
+
|
10
|
+
def self.spawn(*args)
|
11
|
+
@status = @callback.call(args, @param)
|
12
|
+
@status.pid
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.waitpid2(pid, flags = 0)
|
16
|
+
[pid, @status]
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.set_callback(param = nil, &blk)
|
20
|
+
@param = param
|
21
|
+
@callback = blk
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class StatusMock
|
26
|
+
attr_accessor :to_i, :pid
|
27
|
+
alias to_int to_i
|
28
|
+
|
29
|
+
def initialize(retval, pid = rand(65536))
|
30
|
+
@to_i = retval
|
31
|
+
@pid = pid
|
32
|
+
end
|
33
|
+
|
34
|
+
def success?
|
35
|
+
@to_i.zero?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class TestBuilder < Test::Unit::TestCase
|
40
|
+
def setup
|
41
|
+
@tmpdir = Dir.mktmpdir('TestBuilder')
|
42
|
+
@yaml = Tempfile.open('TestBuilder', @tmpdir)
|
43
|
+
@yaml.puts <<-EOY
|
44
|
+
baseruby: ruby
|
45
|
+
repository: dummy_repository
|
46
|
+
logdir: #{@tmpdir}
|
47
|
+
tmpdir: #{@tmpdir}
|
48
|
+
env:
|
49
|
+
DUMMY: foo
|
50
|
+
EOY
|
51
|
+
@yaml.open # rewind for reading
|
52
|
+
end
|
53
|
+
|
54
|
+
def teardown
|
55
|
+
@yaml.close!
|
56
|
+
FileUtils.rm_r(@tmpdir)
|
57
|
+
end
|
58
|
+
|
59
|
+
def run_builder(hash = {}, &blk)
|
60
|
+
builder = MswinBuild::Builder.new(target: "dummy", settings: @yaml.path)
|
61
|
+
if !hash.empty?
|
62
|
+
config = builder.instance_variable_get(:@config)
|
63
|
+
config["timeout"]["test-all"] = hash[:timeout] if hash[:timeout]
|
64
|
+
builder.instance_variable_set(:@config, config)
|
65
|
+
end
|
66
|
+
begin
|
67
|
+
origProcess = Process
|
68
|
+
Object.class_eval do
|
69
|
+
remove_const :Process
|
70
|
+
const_set :Process, ProcessMock
|
71
|
+
end
|
72
|
+
|
73
|
+
commands = [
|
74
|
+
/^bison --version$/,
|
75
|
+
/^svn checkout dummy_repository ruby$/,
|
76
|
+
/^svn info$/,
|
77
|
+
/^win32\/configure\.bat --prefix=[^ ]+ --with-baseruby=ruby$/,
|
78
|
+
/^cl$/,
|
79
|
+
/^nmake -l miniruby$/,
|
80
|
+
/^\.\/miniruby -v$/,
|
81
|
+
/^nmake -l "OPTS=-v -q" btest$/,
|
82
|
+
/^\.\/miniruby sample\/test\.rb/,
|
83
|
+
/^nmake -l showflags$/,
|
84
|
+
/^nmake -l main$/,
|
85
|
+
/^nmake -l docs$/,
|
86
|
+
/^\.\/ruby -v$/,
|
87
|
+
/^nmake -l install-nodoc$/,
|
88
|
+
/^nmake -l install-doc$/,
|
89
|
+
/^nmake -l "OPTS=-v -q" test-knownbug$/,
|
90
|
+
/^nmake -l TESTS=-v RUBYOPT=-w test-all$/,
|
91
|
+
]
|
92
|
+
|
93
|
+
ProcessMock.set_callback(commands, &blk)
|
94
|
+
|
95
|
+
builder.run
|
96
|
+
|
97
|
+
assert_empty commands
|
98
|
+
assert_equal hash[:revision].to_s, builder.get_last_revision if hash[:revision]
|
99
|
+
ensure
|
100
|
+
Object.class_eval do
|
101
|
+
remove_const :Process
|
102
|
+
const_set :Process, origProcess
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
assert File.exist?(File.join(@tmpdir, "recent.html"))
|
107
|
+
assert File.exist?(File.join(@tmpdir, "summary.html"))
|
108
|
+
assert File.directory?(File.join(@tmpdir, "log"))
|
109
|
+
files = Dir.glob(File.join(@tmpdir, "log", "*"))
|
110
|
+
assert files.reject! {|e| /\.log\.html\.gz\z/ =~ e}
|
111
|
+
assert files.reject! {|e| /\.diff\.html\.gz\z/ =~ e}
|
112
|
+
assert_empty files
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_run_success
|
116
|
+
assert_raise(ArgumentError) do
|
117
|
+
MswinBuild::Builder.new
|
118
|
+
end
|
119
|
+
|
120
|
+
assert_raise(RuntimeError) do
|
121
|
+
MswinBuild::Builder.new(target: "dummy")
|
122
|
+
end
|
123
|
+
|
124
|
+
assert_raise(RuntimeError) do
|
125
|
+
MswinBuild::Builder.new(settings: @yaml.path)
|
126
|
+
end
|
127
|
+
|
128
|
+
assert_raise(RuntimeError) do
|
129
|
+
MswinBuild::Builder.new(target: "dummy", settings: @yaml.path, foo: nil)
|
130
|
+
end
|
131
|
+
|
132
|
+
run_builder(revision: 12345) do |args, commands|
|
133
|
+
assert_not_empty commands, "for ``#{args[0]}''"
|
134
|
+
assert_match commands.shift, args[0]
|
135
|
+
|
136
|
+
case args[0]
|
137
|
+
when /^svn checkout\b/
|
138
|
+
Dir.mkdir("ruby")
|
139
|
+
when /^svn info\b/
|
140
|
+
if args[1].is_a?(Hash) && args[1][:out]
|
141
|
+
args[1][:out].puts "Revision: 54321"
|
142
|
+
args[1][:out].puts "Last Changed Rev: 12345"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
StatusMock.new(0)
|
147
|
+
end
|
148
|
+
|
149
|
+
recent = File.read(File.join(@tmpdir, "recent.html"))
|
150
|
+
assert_match /\bsuccess\b/, recent
|
151
|
+
assert_match /^<a href="[^"]+" name="[^"]+">[^<]+<\/a> r12345 /, recent
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_run_btest_failure
|
155
|
+
run_builder do |args, commands|
|
156
|
+
commands.shift
|
157
|
+
|
158
|
+
status = 0
|
159
|
+
case args[0]
|
160
|
+
when /^svn checkout\b/
|
161
|
+
Dir.mkdir("ruby")
|
162
|
+
when /\bbtest\b/
|
163
|
+
if args[1].is_a?(Hash) && args[1][:out]
|
164
|
+
args[1][:out].puts "FAIL 3/456"
|
165
|
+
end
|
166
|
+
status = 3
|
167
|
+
end
|
168
|
+
|
169
|
+
StatusMock.new(status)
|
170
|
+
end
|
171
|
+
|
172
|
+
recent = File.read(File.join(@tmpdir, "recent.html"))
|
173
|
+
assert_match /\b3BFail\b/, recent
|
174
|
+
assert_not_match /\bfailed\b/, recent
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_run_testrb_failure
|
178
|
+
run_builder do |args, commands|
|
179
|
+
commands.shift
|
180
|
+
|
181
|
+
status = 0
|
182
|
+
case args[0]
|
183
|
+
when /^svn checkout\b/
|
184
|
+
Dir.mkdir("ruby")
|
185
|
+
when /\btest\.rb\b/
|
186
|
+
if args[1].is_a?(Hash) && args[1][:out]
|
187
|
+
args[1][:out].puts "not ok/test: 123 failed 4"
|
188
|
+
end
|
189
|
+
status = 3
|
190
|
+
end
|
191
|
+
|
192
|
+
StatusMock.new(status)
|
193
|
+
end
|
194
|
+
|
195
|
+
recent = File.read(File.join(@tmpdir, "recent.html"))
|
196
|
+
assert_match /\b4NotOK\b/, recent
|
197
|
+
assert_not_match /\bfailed\b/, recent
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_run_test_all_failure
|
201
|
+
run_builder do |args, commands|
|
202
|
+
commands.shift
|
203
|
+
|
204
|
+
status = 0
|
205
|
+
case args[0]
|
206
|
+
when /^svn checkout\b/
|
207
|
+
Dir.mkdir("ruby")
|
208
|
+
when /\btest-all\b/
|
209
|
+
if args[1].is_a?(Hash) && args[1][:out]
|
210
|
+
args[1][:out].puts "123 tests, 4567 assertions, 2 failures, 1 errors, 4 skips"
|
211
|
+
end
|
212
|
+
status = 3
|
213
|
+
end
|
214
|
+
|
215
|
+
StatusMock.new(status)
|
216
|
+
end
|
217
|
+
|
218
|
+
recent = File.read(File.join(@tmpdir, "recent.html"))
|
219
|
+
assert_match /\b2F1E\b/, recent
|
220
|
+
assert_not_match /\bfailed\b/, recent
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_run_timeout
|
224
|
+
run_builder(timeout: 0.1) do |args, commands|
|
225
|
+
commands.shift
|
226
|
+
|
227
|
+
case args[0]
|
228
|
+
when /^svn checkout\b/
|
229
|
+
Dir.mkdir("ruby")
|
230
|
+
when /\btest-all\b/
|
231
|
+
StatusMock.new(nil)
|
232
|
+
sleep 2
|
233
|
+
break
|
234
|
+
end
|
235
|
+
|
236
|
+
StatusMock.new(0)
|
237
|
+
end
|
238
|
+
|
239
|
+
recent = File.read(File.join(@tmpdir, "recent.html"))
|
240
|
+
assert_match /\bfailed\(test-all CommandTimeout\)/, recent
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_get_current_revision
|
244
|
+
TOPLEVEL_BINDING.eval <<-EOS
|
245
|
+
alias orig_backquote ` #`
|
246
|
+
def `(cmd) #`
|
247
|
+
"Revision: 54321\nLast Changed Rev: 12345\n"
|
248
|
+
end
|
249
|
+
EOS
|
250
|
+
|
251
|
+
begin
|
252
|
+
builder = MswinBuild::Builder.new(target: "dummy", settings: @yaml.path)
|
253
|
+
assert_equal "12345", builder.get_current_revision
|
254
|
+
ensure
|
255
|
+
TOPLEVEL_BINDING.eval <<-EOS
|
256
|
+
alias ` orig_backquote #`
|
257
|
+
EOS
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "mswin-build/process_tree"
|
3
|
+
|
4
|
+
class TestProcessTree < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@makefile = "Makefile"
|
7
|
+
open(@makefile, "w") do |f|
|
8
|
+
f.puts <<-EOM
|
9
|
+
all:
|
10
|
+
@ruby -e "Process.waitpid Process.spawn('ruby -e \"sleep\"')"
|
11
|
+
EOM
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
File.delete(@makefile) if File.exist?(@makefile)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_s_terminate_process_tree
|
20
|
+
pid = Process.spawn("nmake -l")
|
21
|
+
sleep 1
|
22
|
+
|
23
|
+
assert_nil Process.waitpid(pid, Process::WNOHANG)
|
24
|
+
assert_equal 3, MswinBuild::ProcessTree.terminate_process_tree(pid)
|
25
|
+
end
|
26
|
+
end if /mswin|mingw/ =~ RUBY_PLATFORM
|
metadata
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mswin-build
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- U.Nakamura
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-04-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: test-unit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: A low quality clone of https://github.com/akr/chkbuild for mswin.
|
56
|
+
email:
|
57
|
+
- usa@garbagecollect.jp
|
58
|
+
executables:
|
59
|
+
- build.rb
|
60
|
+
- kicker.rb
|
61
|
+
- tinyhttpd.rb
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- ".gitignore"
|
66
|
+
- ".travis.yml"
|
67
|
+
- Gemfile
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/build.rb
|
71
|
+
- bin/kicker.rb
|
72
|
+
- bin/tinyhttpd.rb
|
73
|
+
- config/vc10-x86-1_9_3.yaml
|
74
|
+
- config/vc10-x86-2_0_0.yaml
|
75
|
+
- config/vc10-x86-trunk.yaml
|
76
|
+
- lib/mswin-build/builder.rb
|
77
|
+
- lib/mswin-build/process_tree.rb
|
78
|
+
- lib/mswin-build/version.rb
|
79
|
+
- mswin-build.gemspec
|
80
|
+
- test/unit/test_builder.rb
|
81
|
+
- test/unit/test_process_tree.rb
|
82
|
+
homepage: https://github.com/unak/mswin-build
|
83
|
+
licenses:
|
84
|
+
- BSD-2-Clause
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.2.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: A low quality clone of https://github.com/akr/chkbuild for mswin.
|
106
|
+
test_files:
|
107
|
+
- test/unit/test_builder.rb
|
108
|
+
- test/unit/test_process_tree.rb
|