mswin-build 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|