yugui-chkbuild 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/README.ja.rd +191 -0
  2. data/Rakefile +56 -0
  3. data/VERSION +1 -0
  4. data/bin/last-build +28 -0
  5. data/bin/start-build +37 -0
  6. data/chkbuild.gemspec +107 -0
  7. data/core_ext/io.rb +17 -0
  8. data/core_ext/string.rb +10 -0
  9. data/lib/chkbuild.rb +45 -0
  10. data/lib/chkbuild/build.rb +718 -0
  11. data/lib/chkbuild/lock.rb +57 -0
  12. data/lib/chkbuild/logfile.rb +230 -0
  13. data/lib/chkbuild/main.rb +138 -0
  14. data/lib/chkbuild/options.rb +62 -0
  15. data/lib/chkbuild/scm/cvs.rb +132 -0
  16. data/lib/chkbuild/scm/git.rb +223 -0
  17. data/lib/chkbuild/scm/svn.rb +215 -0
  18. data/lib/chkbuild/scm/xforge.rb +33 -0
  19. data/lib/chkbuild/target.rb +180 -0
  20. data/lib/chkbuild/targets/gcc.rb +94 -0
  21. data/lib/chkbuild/targets/ruby.rb +456 -0
  22. data/lib/chkbuild/title.rb +107 -0
  23. data/lib/chkbuild/upload.rb +66 -0
  24. data/lib/misc/escape.rb +535 -0
  25. data/lib/misc/gdb.rb +74 -0
  26. data/lib/misc/timeoutcom.rb +174 -0
  27. data/lib/misc/udiff.rb +244 -0
  28. data/lib/misc/util.rb +232 -0
  29. data/sample/build-autoconf-ruby +69 -0
  30. data/sample/build-gcc-ruby +43 -0
  31. data/sample/build-ruby +37 -0
  32. data/sample/build-ruby2 +36 -0
  33. data/sample/build-svn +55 -0
  34. data/sample/build-yarv +35 -0
  35. data/sample/test-apr +12 -0
  36. data/sample/test-catcherr +23 -0
  37. data/sample/test-combfail +21 -0
  38. data/sample/test-core +14 -0
  39. data/sample/test-core2 +19 -0
  40. data/sample/test-date +9 -0
  41. data/sample/test-dep +17 -0
  42. data/sample/test-depver +14 -0
  43. data/sample/test-echo +9 -0
  44. data/sample/test-env +9 -0
  45. data/sample/test-error +9 -0
  46. data/sample/test-fail +18 -0
  47. data/sample/test-fmesg +16 -0
  48. data/sample/test-gcc-v +15 -0
  49. data/sample/test-git +11 -0
  50. data/sample/test-leave-proc +9 -0
  51. data/sample/test-limit +9 -0
  52. data/sample/test-make +9 -0
  53. data/sample/test-neterr +16 -0
  54. data/sample/test-savannah +14 -0
  55. data/sample/test-sleep +9 -0
  56. data/sample/test-timeout +9 -0
  57. data/sample/test-timeout2 +10 -0
  58. data/sample/test-timeout3 +9 -0
  59. data/sample/test-upload +13 -0
  60. data/sample/test-warn +13 -0
  61. data/setup/upload-rsync-ssh +572 -0
  62. data/test/misc/test-escape.rb +17 -0
  63. data/test/misc/test-logfile.rb +108 -0
  64. data/test/misc/test-timeoutcom.rb +23 -0
  65. data/test/test_helper.rb +9 -0
  66. metadata +123 -0
@@ -0,0 +1,57 @@
1
+ # Copyright (C) 2006,2009 Tanaka Akira <akr@fsij.org>
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ module ChkBuild
26
+ LOCK_PATH = ChkBuild.build_top + '.lock'
27
+
28
+ def self.lock_start
29
+ if !defined?(@lock_io)
30
+ @lock_io = LOCK_PATH.open(File::WRONLY|File::CREAT)
31
+ end
32
+ if @lock_io.flock(File::LOCK_EX|File::LOCK_NB) == false
33
+ raise "another chkbuild is running."
34
+ end
35
+ @lock_io.truncate(0)
36
+ @lock_io.sync = true
37
+ @lock_io.close_on_exec = true
38
+ @lock_io.puts "locked pid:#{$$}"
39
+ lock_pid = $$
40
+ at_exit {
41
+ @lock_io.puts "exit pid:#{$$}" if $$ == lock_pid
42
+ }
43
+ end
44
+
45
+ def self.lock_puts(mesg)
46
+ if block_given?
47
+ t1 = Time.now
48
+ @lock_io.print "#{t1.iso8601} #{mesg}"
49
+ ret = yield
50
+ t2 = Time.now
51
+ @lock_io.puts "\t#{t2-t1}"
52
+ ret
53
+ else
54
+ @lock_io.puts "#{Time.now.iso8601} #{mesg}"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,230 @@
1
+ # Copyright (C) 2006,2009 Tanaka Akira <akr@fsij.org>
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ require 'time'
26
+
27
+ module ChkBuild
28
+ end
29
+
30
+ class ChkBuild::LogFile
31
+ InitialMark = '=='
32
+
33
+ def self.write_open(filename, build)
34
+ logfile = self.new(filename, true)
35
+ logfile.start_section build.depsuffixed_name
36
+ logfile.with_default_output {
37
+ system("uname -a")
38
+ section_started = false
39
+ build.traverse_depbuild {|depbuild|
40
+ if !section_started
41
+ logfile.start_section 'dependencies'
42
+ section_started = true
43
+ end
44
+ if depbuild.suffixed_name == depbuild.version
45
+ puts "#{depbuild.suffixed_name} #{depbuild.start_time}"
46
+ else
47
+ puts "#{depbuild.suffixed_name} #{depbuild.start_time} (#{depbuild.version})"
48
+ end
49
+ }
50
+ }
51
+ logfile
52
+ end
53
+
54
+ def dependencies
55
+ return [] unless log = self.get_section('dependencies')
56
+ r = []
57
+ log.each_line {|line|
58
+ if /^(\S+) (\d+T\d+) \((.*)\)$/ =~ line
59
+ r << [$1, $2, $3]
60
+ elsif /^(\S+) (\d+T\d+)$/ =~ line
61
+ r << [$1, $2, $1]
62
+ end
63
+ }
64
+ r
65
+ end
66
+
67
+ def depsuffixed_name
68
+ return @depsuffixed_name if defined? @depsuffixed_name
69
+ if /\A\S+\s+(\S+)/ =~ self.get_all_log
70
+ return @depsuffixed_name = $1
71
+ end
72
+ raise "unexpected log format"
73
+ end
74
+
75
+ def suffixed_name() depsuffixed_name.sub(/_.*/, '') end
76
+ def target_name() suffixed_name.sub(/-.*/, '') end
77
+ def suffixes() suffixed_name.split(/-/)[1..-1] end
78
+
79
+ def self.read_open(filename)
80
+ self.new(filename, false)
81
+ end
82
+
83
+ def initialize(filename, writemode)
84
+ @writemode = writemode
85
+ mode = writemode ? File::RDWR|File::CREAT|File::APPEND : File::RDONLY
86
+ @filename = filename
87
+ @io = File.open(filename, mode)
88
+ @io.set_encoding("ascii-8bit") if @io.respond_to? :set_encoding
89
+ @io.sync = true
90
+ @mark = read_separator
91
+ @sections = detect_sections
92
+ end
93
+
94
+ def read_separator
95
+ mark = nil
96
+ if @io.stat.size != 0
97
+ @io.rewind
98
+ mark = @io.gets[/\A\S+/]
99
+ end
100
+ mark || InitialMark
101
+ end
102
+ private :read_separator
103
+
104
+ def detect_sections
105
+ ret = {}
106
+ @io.rewind
107
+ pat = /\A#{Regexp.quote @mark} /
108
+ @io.each {|line|
109
+ if pat =~ line
110
+ epos = @io.pos
111
+ spos = epos - line.length
112
+ secname = $'.chomp.sub(/#.*/, '').strip
113
+ ret[secname] = spos
114
+ end
115
+ }
116
+ ret
117
+ end
118
+ private :detect_sections
119
+
120
+ # logfile.with_default_output { ... }
121
+ def with_default_output
122
+ raise "not opened for writing" if !@writemode
123
+ File.open(@filename, File::WRONLY|File::APPEND) {|f|
124
+ STDERR.tmp_reopen(f) {
125
+ STDERR.sync = true
126
+ STDOUT.tmp_reopen(f) {
127
+ STDOUT.sync = true
128
+ yield
129
+ }
130
+ }
131
+ }
132
+ end
133
+
134
+ def change_default_output
135
+ raise "not opened for writing" if !@writemode
136
+ STDOUT.reopen(@save_io = File.for_fd(@io.fileno, File::WRONLY|File::APPEND))
137
+ STDERR.reopen(STDOUT)
138
+ STDOUT.sync = true
139
+ STDERR.sync = true
140
+ end
141
+
142
+ # start_section returns the (unique) section name.
143
+ def start_section(secname)
144
+ @io.flush
145
+ if 0 < @io.stat.size
146
+ @io.seek(-1, IO::SEEK_END)
147
+ if @io.read != "\n"
148
+ @io.write "\n"
149
+ end
150
+ end
151
+ spos = @io.pos
152
+ secname = secname.strip
153
+ if @sections[secname]
154
+ i = 2
155
+ while @sections["#{secname}(#{i})"]
156
+ i += 1
157
+ end
158
+ secname = "#{secname}(#{i})"
159
+ end
160
+ @sections[secname] = spos
161
+ @io.write "#{@mark} #{secname} \# #{Time.now.iso8601}\n"
162
+ secname
163
+ end
164
+
165
+ def secnames
166
+ @sections.keys.sort_by {|secname| @sections[secname] }
167
+ end
168
+
169
+ def each_secname(&block)
170
+ @sections.keys.sort_by {|secname| @sections[secname] }.each(&block)
171
+ end
172
+
173
+ def section_size(secname)
174
+ spos = @sections[secname]
175
+ raise ArgumentError, "no section : #{secname.inspect}" if !spos
176
+ epos = @sections.values.reject {|pos| pos <= spos }.min
177
+ epos = @io.stat.size if !epos
178
+ epos - spos
179
+ end
180
+
181
+ def get_section(secname)
182
+ spos = @sections[secname]
183
+ return nil if !spos
184
+ @io.seek spos
185
+ @io.gets("\n#{@mark} ").chomp("#{@mark} ").sub(/\A.*\n/, '')
186
+ end
187
+
188
+ def get_all_log
189
+ @io.rewind
190
+ @io.read
191
+ end
192
+
193
+ def modify_section(secname, data)
194
+ raise "not opened for writing" if !@writemode
195
+ spos = @sections[secname]
196
+ raise ArgumentError, "no section: #{secname.inspect}" if !spos
197
+ data += "\n" if /\n\z/ !~ data
198
+ old = nil
199
+ File.open(@filename, File::RDWR) {|f|
200
+ f.seek spos
201
+ rest = f.read
202
+ if /\n#{Regexp.quote @mark} / =~ rest
203
+ epos = $~.begin(0) + 1
204
+ curr = rest[0...epos]
205
+ rest = rest[epos..-1]
206
+ else
207
+ curr = rest
208
+ rest = ''
209
+ end
210
+ if /\n/ =~ curr
211
+ secline = $` + $&
212
+ old = $'
213
+ else
214
+ secline = curr + "\n"
215
+ old = ''
216
+ end
217
+ f.seek spos
218
+ f.print secline, data, rest
219
+ f.flush
220
+ f.truncate(f.pos)
221
+ }
222
+ off = data.length - old.length
223
+ @sections.each_pair {|n, pos|
224
+ if spos < pos
225
+ @sections[n] = pos + off
226
+ end
227
+ }
228
+ nil
229
+ end
230
+ end
@@ -0,0 +1,138 @@
1
+ # Copyright (C) 2006 Tanaka Akira <akr@fsij.org>
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ require 'pathname'
26
+ require 'optparse'
27
+
28
+ module ChkBuild
29
+ TOP_DIRECTORY = Pathname.getwd
30
+ def ChkBuild.build_top() TOP_DIRECTORY+"tmp/build" end
31
+ def ChkBuild.public_top() TOP_DIRECTORY+"tmp/public_html" end
32
+
33
+ def ChkBuild.main_help(status=true)
34
+ if File.executable? $0
35
+ command = $0
36
+ else
37
+ require 'rbconfig'
38
+ ruby = "#{Config::CONFIG["bindir"]}/#{Config::CONFIG["ruby_install_name"]}"
39
+ command = "#{ruby} #{$0}"
40
+ end
41
+ print <<"End"
42
+ usage:
43
+ #{command} [build [--procmemsize]]
44
+ #{command} list
45
+ #{command} title [depsuffixed_name...]
46
+ #{command} logdiff [depsuffixed_name [date1 [date2]]]
47
+ End
48
+ exit status
49
+ end
50
+
51
+ @target_list = []
52
+ def ChkBuild.main_build
53
+ o = OptionParser.new
54
+ o.def_option('--procmemsize') {
55
+ @target_list.each {|t|
56
+ t.update_option(:procmemsize => true)
57
+ }
58
+ }
59
+ o.parse!
60
+ begin
61
+ Process.setpriority(Process::PRIO_PROCESS, 0, 10)
62
+ rescue Errno::EACCES # already niced to 11 or more
63
+ end
64
+ File.umask(002)
65
+ STDIN.reopen("/dev/null", "r")
66
+ STDOUT.sync = true
67
+ ChkBuild.build_top.mkpath
68
+ ChkBuild.lock_start
69
+ @target_list.each {|t|
70
+ t.make_result
71
+ }
72
+ end
73
+
74
+ def ChkBuild.def_target(target_name, *args, &block)
75
+ t = ChkBuild::Target.new(target_name, *args, &block)
76
+ @target_list << t
77
+ t
78
+ end
79
+
80
+ def ChkBuild.main_list
81
+ @target_list.each {|t|
82
+ t.each_build_obj {|build|
83
+ puts build.depsuffixed_name
84
+ }
85
+ }
86
+ end
87
+
88
+ def ChkBuild.main_title
89
+ @target_list.each {|t|
90
+ t.each_build_obj {|build|
91
+ next if !ARGV.empty? && !ARGV.include?(build.depsuffixed_name)
92
+ last_txt = ChkBuild.public_top + build.depsuffixed_name + 'last.txt'
93
+ if last_txt.exist?
94
+ logfile = ChkBuild::LogFile.read_open(last_txt)
95
+ title = ChkBuild::Title.new(t, logfile)
96
+ title.run_hooks
97
+ puts "#{build.depsuffixed_name}:\t#{title.make_title}"
98
+ end
99
+ }
100
+ }
101
+ end
102
+
103
+ def ChkBuild.main_logdiff
104
+ depsuffixed_name, arg_t1, arg_t2 = ARGV
105
+ @target_list.each {|t|
106
+ t.each_build_obj {|build|
107
+ next if depsuffixed_name && build.depsuffixed_name != depsuffixed_name
108
+ ts = build.log_time_sequence
109
+ raise "no log: #{build.depsuffixed_name}/#{arg_t1}" if arg_t1 and !ts.include?(arg_t1)
110
+ raise "no log: #{build.depsuffixed_name}/#{arg_t2}" if arg_t2 and !ts.include?(arg_t2)
111
+ if ts.length < 2
112
+ puts "#{build.depsuffixed_name}: less than 2 logs"
113
+ next
114
+ end
115
+ t1 = arg_t1 || ts[-2]
116
+ t2 = arg_t2 || ts[-1]
117
+ puts "#{build.depsuffixed_name}: #{t1}->#{t2}"
118
+ build.output_diff(t1, t2, STDOUT)
119
+ puts
120
+ }
121
+ }
122
+ end
123
+
124
+ def ChkBuild.main
125
+ ARGV.unshift 'build' if ARGV.empty?
126
+ subcommand = ARGV.shift
127
+ case subcommand
128
+ when 'help', '-h' then ChkBuild.main_help
129
+ when 'build' then ChkBuild.main_build
130
+ when 'list' then ChkBuild.main_list
131
+ when 'title' then ChkBuild.main_title
132
+ when 'logdiff' then ChkBuild.main_logdiff
133
+ else
134
+ puts "unexpected subcommand: #{subcommand}"
135
+ exit 1
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright (C) 2006 Tanaka Akira <akr@fsij.org>
2
+ #
3
+ # Redistribution and use in source and binary forms, with or without
4
+ # modification, are permitted provided that the following conditions are met:
5
+ #
6
+ # 1. Redistributions of source code must retain the above copyright notice, this
7
+ # list of conditions and the following disclaimer.
8
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
9
+ # this list of conditions and the following disclaimer in the documentation
10
+ # and/or other materials provided with the distribution.
11
+ # 3. The name of the author may not be used to endorse or promote products
12
+ # derived from this software without specific prior written permission.
13
+ #
14
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
15
+ # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
+ # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
17
+ # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
19
+ # OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
22
+ # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
23
+ # OF SUCH DAMAGE.
24
+
25
+ module ChkBuild
26
+ @default_options = {
27
+ :num_oldbuilds => 3,
28
+ :limit_cpu => 3600 * 4,
29
+ :limit_stack => 1024 * 1024 * 40,
30
+ :limit_data => 1024 * 1024 * 100,
31
+ :limit_as => 1024 * 1024 * 100
32
+ }
33
+
34
+ def self.get_options
35
+ @default_options.dup
36
+ end
37
+
38
+ def self.num_oldbuilds
39
+ @default_options[:num_oldbuilds]
40
+ end
41
+ def self.num_oldbuilds=(val)
42
+ @default_options[:num_oldbuilds] = val
43
+ end
44
+
45
+ def self.limit(hash)
46
+ hash.each {|k, v|
47
+ s = "limit_#{k}".intern
48
+ raise "unexpected resource name: #{k}" if !@default_options[s]
49
+ @default_options[s] = v
50
+ }
51
+ end
52
+
53
+ def self.get_limit
54
+ ret = {}
55
+ @default_options.each {|k, v|
56
+ next if /\Alimit_/ !~ k.to_s
57
+ s = $'.intern
58
+ ret[s] = v
59
+ }
60
+ ret
61
+ end
62
+ end