gri 10.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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/MIT-LICENSE.txt +20 -0
  4. data/README.md +132 -0
  5. data/Rakefile +5 -0
  6. data/bin/grapher +17 -0
  7. data/bin/gri +5 -0
  8. data/bin/gricast +17 -0
  9. data/bin/grispark +5 -0
  10. data/bin/griwalk +9 -0
  11. data/bin/trad +19 -0
  12. data/bin/trad-http +17 -0
  13. data/gri.gemspec +21 -0
  14. data/lib/fluent/plugin/out_gri.rb +56 -0
  15. data/lib/gri/api.rb +28 -0
  16. data/lib/gri/app_collector.rb +154 -0
  17. data/lib/gri/app_walker.rb +23 -0
  18. data/lib/gri/blank.rb +49 -0
  19. data/lib/gri/builtindefs.rb +211 -0
  20. data/lib/gri/cast.rb +84 -0
  21. data/lib/gri/cgraph.rb +37 -0
  22. data/lib/gri/clist.rb +163 -0
  23. data/lib/gri/collector.rb +284 -0
  24. data/lib/gri/config.rb +134 -0
  25. data/lib/gri/ds_list.rb +166 -0
  26. data/lib/gri/format_helper.rb +112 -0
  27. data/lib/gri/gparams.rb +43 -0
  28. data/lib/gri/graph.rb +239 -0
  29. data/lib/gri/grapher.rb +70 -0
  30. data/lib/gri/ldb.rb +160 -0
  31. data/lib/gri/list.rb +242 -0
  32. data/lib/gri/log.rb +140 -0
  33. data/lib/gri/loop.rb +109 -0
  34. data/lib/gri/ltsv.rb +58 -0
  35. data/lib/gri/main.rb +107 -0
  36. data/lib/gri/mlog.rb +22 -0
  37. data/lib/gri/mmsgpack.rb +57 -0
  38. data/lib/gri/msnmp.rb +601 -0
  39. data/lib/gri/page.rb +235 -0
  40. data/lib/gri/pcollector.rb +209 -0
  41. data/lib/gri/plugin.rb +75 -0
  42. data/lib/gri/plugin/bootstrap.rb +65 -0
  43. data/lib/gri/plugin/cisco.rb +98 -0
  44. data/lib/gri/plugin/exec_collector.rb +89 -0
  45. data/lib/gri/plugin/juniper.rb +5 -0
  46. data/lib/gri/plugin/netsnmp.rb +8 -0
  47. data/lib/gri/plugin/ucdavis.rb +176 -0
  48. data/lib/gri/plugin/writer_fluentd.rb +26 -0
  49. data/lib/gri/polling_unit.rb +88 -0
  50. data/lib/gri/q.rb +5 -0
  51. data/lib/gri/request.rb +29 -0
  52. data/lib/gri/rrd.rb +438 -0
  53. data/lib/gri/scheduler.rb +68 -0
  54. data/lib/gri/sgraph.rb +147 -0
  55. data/lib/gri/spark.rb +94 -0
  56. data/lib/gri/tra_collector.rb +80 -0
  57. data/lib/gri/trad.rb +170 -0
  58. data/lib/gri/updater.rb +201 -0
  59. data/lib/gri/util_daemon.rb +19 -0
  60. data/lib/gri/util_marshal.rb +13 -0
  61. data/lib/gri/utils.rb +63 -0
  62. data/lib/gri/vendor.rb +76 -0
  63. data/lib/gri/version.rb +3 -0
  64. data/lib/gri/wmain.rb +67 -0
  65. data/lib/gri/writer.rb +184 -0
  66. data/mcollector +47 -0
  67. data/test/mock.rb +60 -0
  68. data/test/root/gra/.sysdb/sysdb.txt +3 -0
  69. data/test/root/gra/testhost/.records.txt +2 -0
  70. data/test/root/if.def +2 -0
  71. data/test/root/test.conf +4 -0
  72. data/test/root/testtab +9 -0
  73. data/test/root/testtab2 +2 -0
  74. data/test/root/tra/testhost/_/20130614 +20 -0
  75. data/test/test_app.rb +58 -0
  76. data/test/test_builtindefs.rb +24 -0
  77. data/test/test_collector.rb +58 -0
  78. data/test/test_config.rb +62 -0
  79. data/test/test_ds_list.rb +48 -0
  80. data/test/test_exec_collector.rb +33 -0
  81. data/test/test_format_helper.rb +68 -0
  82. data/test/test_graph.rb +69 -0
  83. data/test/test_ldb.rb +29 -0
  84. data/test/test_list.rb +65 -0
  85. data/test/test_log.rb +16 -0
  86. data/test/test_loop.rb +35 -0
  87. data/test/test_ltsv.rb +38 -0
  88. data/test/test_main.rb +19 -0
  89. data/test/test_mmsgpack.rb +27 -0
  90. data/test/test_msnmp.rb +147 -0
  91. data/test/test_page.rb +51 -0
  92. data/test/test_pcollector.rb +71 -0
  93. data/test/test_plugin.rb +62 -0
  94. data/test/test_plugin_cisco.rb +23 -0
  95. data/test/test_polling_unit.rb +58 -0
  96. data/test/test_request.rb +26 -0
  97. data/test/test_rrd.rb +53 -0
  98. data/test/test_rrd_updater.rb +139 -0
  99. data/test/test_scheduler.rb +31 -0
  100. data/test/test_tra_collector.rb +40 -0
  101. data/test/test_trad.rb +33 -0
  102. data/test/test_util_marshal.rb +17 -0
  103. data/test/test_utils.rb +15 -0
  104. data/test/test_vendor.rb +40 -0
  105. data/test/test_writer.rb +33 -0
  106. data/test/unittest_helper.rb +27 -0
  107. metadata +208 -0
data/lib/gri/page.rb ADDED
@@ -0,0 +1,235 @@
1
+ require 'time'
2
+ require 'gri/builtindefs'
3
+ require 'gri/utils'
4
+ require 'gri/request'
5
+ require 'gri/format_helper'
6
+
7
+ module GRI
8
+ class Page
9
+ include Utils
10
+ include FormatHelper
11
+
12
+ def initialize options={}
13
+ @options = options
14
+ end
15
+
16
+ def mk_page_title dirs, rs, params
17
+ jstr = (params['p'] == 't' or params['p'] == 'v') ? ', ' : ' + '
18
+ hosthash = {}
19
+ descrs = []
20
+ headlegend = nil
21
+
22
+ for rname in rs
23
+ host, key = rname.split('_', 2)
24
+ hosthash[host] = true
25
+ dir, records = search_records dirs, host
26
+ if records and (prop = get_prop records[key])
27
+ xhost = prop[:description] ? nil : host
28
+ descr = (prop[:description] || prop[:name] || '?').to_s
29
+ url = if params['grp'].blank?
30
+ url_to("?r=#{rname}")
31
+ else
32
+ url_to("?grp=#{params['grp']}&r=#{rname}")
33
+ end
34
+ descrs.push [url, xhost, descr]
35
+ unless headlegend or params['grp']
36
+ ub = prop[:ub]
37
+ if descr or ub
38
+ name = prop[:name].to_s
39
+ url = url_to("#{host}")
40
+ headlegend = "<a href=\"#{h url}\">#{h host}</a>"
41
+ headlegend << ' ' + name if descr
42
+ #headlegend << ", MAX: #{to_scalestr ub, 1000}"
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ html_title = descrs.map {|url, xhost, descr|
49
+ if xhost and hosthash.size > 1
50
+ xhost + ':' + descr
51
+ else
52
+ descr
53
+ end
54
+ }.join(jstr)
55
+ body_title = descrs.collect {|url, xhost, descr|
56
+ if xhost and hosthash.size > 1
57
+ "<a href=\"#{h url}\">#{h xhost}:#{h descr}</a>"
58
+ else
59
+ "<a href=\"#{h url}\">#{h descr}</a>"
60
+ end
61
+ }.join(jstr)
62
+
63
+ return html_title, body_title, headlegend
64
+ end
65
+
66
+ def mk_param_str stime, etime, rs, ds, params
67
+ res = rs.map {|r| "r=#{u r}"}
68
+ res << "grp=#{u params['grp']}" if params['grp']
69
+ res << "stime=#{stime.to_i}"
70
+ res << "etime=#{etime.to_i}" if etime.to_i.nonzero?
71
+ res << "z=#{u params['z']}"
72
+ res << "tz=#{u params['tz']}"
73
+ res << "y=#{u params['y']}"
74
+ res << "p=#{u params['p']}" if params['p']
75
+ res << "ds=#{ds}" if ds
76
+ res.join('&')
77
+ end
78
+
79
+ def mk_graph_tag stime, etime, rs, params
80
+ if params['p'] == 't'
81
+ rs.map {|rname|
82
+ mk_graph_tag_r stime, etime, [rname], params
83
+ }.join("\n")
84
+ else
85
+ mk_graph_tag_r stime, etime, rs, params
86
+ end
87
+ end
88
+
89
+ def mk_graph_tag_r stime, etime, rs, params
90
+ specs = DEFS.get_specs @data_name
91
+ if (gr_specs = specs[:graph]) and gr_specs.size >= 1
92
+ if params['p'] == 's' or params['p'] == 'v'
93
+ (0..gr_specs.size-1).map {|gidx|
94
+ gr_spec = gr_specs[gidx]
95
+ pickup_re = gr_spec[3]
96
+ dss = specs[:ds] || []
97
+ dss = dss.grep pickup_re if pickup_re
98
+ dss = dss.map {|ds| ds.split(',', 3)[1]}
99
+ dss.map {|ds|
100
+ param_str = mk_param_str stime, etime, rs, ds, params
101
+ mk_graph_tag_s param_str, gidx
102
+ }.join ''
103
+ }.join ''
104
+ else
105
+ param_str = mk_param_str stime, etime, rs, nil, params
106
+ (0..gr_specs.size-1).map {|gidx|
107
+ mk_graph_tag_s param_str, gidx}.join ''
108
+ end
109
+ end
110
+ end
111
+
112
+ def mk_graph_tag_s param_str, gidx=nil
113
+ param_str += "&g=#{gidx}" if gidx
114
+ name = ENV['SCRIPT_NAME'] || ''
115
+ "<a href=\"#{name}/#{h param_str}\">" +
116
+ "<img ismap src=\"#{name}?#{h param_str}\"></a><br/>"
117
+ end
118
+
119
+ def parse_tstr tstr
120
+ (tstr and !tstr.empty?) ? Time.parse(tstr) : nil
121
+ end
122
+
123
+ def parse_request req
124
+ now = Time.now
125
+ if @options[:clicked]
126
+ s = req.path_info[1..-1]
127
+ req.query_string = s
128
+ params = req.gparams
129
+ z = params['z']
130
+ width, = GRI::Graph::SIZE[z]
131
+
132
+ canvas_x_offset = (Config['canvas-x-offset'] || 75).to_i
133
+ imgx = @options[:imgx].to_i - canvas_x_offset
134
+ imgy = @options[:imgy].to_i
135
+
136
+ stime = params['stime'].to_i
137
+ etime = params['etime'].to_i
138
+ etime = (now + etime).to_i if etime <= 0
139
+ stime = (etime + stime).to_i if stime <= 0
140
+ stime = Time.at stime
141
+ time = stime + ((Time.at(etime) - stime) / width) * imgx
142
+ stime = Time.local(time.year, time.mon, time.day)
143
+ etime = stime + 24*3600
144
+ params['pt'] = 's'
145
+ else
146
+ params = req.gparams
147
+ deftime = now - now.to_i % 60
148
+ stime = parse_tstr(params['cs']) || deftime - 7*24*3600
149
+ etime = parse_tstr(params['ce']) || deftime
150
+ end
151
+ return stime, etime, params
152
+ end
153
+
154
+ def call env
155
+ req = GRI::Request.new env
156
+ ENV['TZ'] = req.params['tz'].to_s unless req.params['tz'].blank?
157
+ stime, etime, params = parse_request req
158
+
159
+ cs = stime.strftime '%Y-%m-%d %H:%M:%S'
160
+ ce = etime.strftime '%Y-%m-%d %H:%M:%S'
161
+
162
+ r = params['r'] || ''
163
+ host, @data_name, index = parse_host_key r
164
+ rs = params.getvar 'r'
165
+
166
+ @title, body_title, headlegend =
167
+ mk_page_title @options[:dirs], rs, params
168
+
169
+ defs_term = DEFS[:term]
170
+ sym = params['tm'].blank? ? '' : params['tm'].intern
171
+ terms = defs_term[sym] || defs_term[:default]
172
+ body = render(Grapher.layout) {render template, binding}
173
+ [200, {'Content-type' => 'text/html'}, [body]]
174
+ end
175
+
176
+ TZS = [['', 'localtime'], ['JST-9', 'JST-9'],
177
+ ['EST5EDT', 'EST5EDT'], ['PST8PDT', 'PST8PDT'],
178
+ ['Europe/London', 'Europe/London'],
179
+ ['Europe/Amsterdam', 'Europe/Amsterdam'],
180
+ ['Singapore', 'Singapore']]
181
+ def template
182
+ <<'EOS'
183
+ <span class="large"><%= body_title %></span><br/>
184
+ <% if params['z'] != 'll' and rs.size == 1 and headlegend and headlegend.size > 0 -%>
185
+ <span class="small"><%= headlegend %></span><br/>
186
+ <% end -%>
187
+ <br/>
188
+
189
+ <form enctype="application/x-www-form-urlencoded" method="get"
190
+ action="<%= url_to '?' %>">
191
+ <% rs.each {|r| -%><%= hidden 'r', r %><% } -%>
192
+ <% if params['grp'] then %><%= hidden 'grp', params['grp'] %><% end %>
193
+ <% tzs = TZS -%>
194
+ <% (tzs.assoc(params['tz']) || tzs[0])[2] = true -%>
195
+ TIMEZONE: <%= popup_menu('tz', nil, *tzs) %>
196
+ <% nflag, uflag = (params['y'] == 'u') ? [false, true] : [true, false] -%>
197
+ Y-axis scale:
198
+ <%= radio_button 'y', 'a', nflag %>auto
199
+ <%= radio_button 'y', 'u', uflag %>upper limit<br/>
200
+ <%= check_box 'pt', 's', (params['pt'] == 's') %>
201
+ <nobr>
202
+ from <%= text_field 'cs', cs, 20, 19, nil %>
203
+ to <%= text_field 'ce', ce, 20, 19, nil %>
204
+ </nobr>
205
+ <% zs = [['ss', 'SS'], ['s', 'S'], ['m', 'M'], ['l', 'L'], ['ll', 'LL']] -%>
206
+ <% (zs.assoc(params['z']) || zs[2])[2] = true -%>
207
+ Graph size: <%= popup_menu('z', nil, *zs) %>
208
+ <% tms = defs_term.sort_by {|k, v| v[0][1]}.map {|k,| [k.to_s, k.to_s]} -%>
209
+ <% (tms.assoc(params['tm']) || tms[1])[2] = true -%>
210
+ term: <%= popup_menu('tm', nil, *tms) %>
211
+ <br/>
212
+ <% if rs.size > 1 -%>
213
+ <% c_ary = [['', 'sum'], ['s', 'stack'], ['v', 'overlay'], ['t', 'tile']] -%>
214
+ <% (c_ary.assoc(params['p']) || c_ary[0])[2] = true -%>
215
+ Composite type: <%= popup_menu('p', nil, *c_ary) %><br/>
216
+ <% end -%>
217
+ <input class="btn btn-primary btn-sm" type="submit" value="submit">
218
+ </form>
219
+
220
+ <% if params['pt'] == 's' -%>
221
+ <%= mk_graph_tag stime.to_i, etime.to_i, rs, params %>
222
+ <% else -%>
223
+ <% for label, int in terms -%>
224
+ <hr/><p>
225
+ <strong><%=h label %> Graph</strong><br/>
226
+ <%= mk_graph_tag -int, 0, rs, params %>
227
+ </p>
228
+ <% end -%>
229
+ <% end -%>
230
+
231
+ <hr/><!--%= RUBY_VERSION %-->
232
+ EOS
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,209 @@
1
+ require 'timeout'
2
+ require 'gri/util_marshal'
3
+ require 'gri/app_collector'
4
+
5
+ module GRI
6
+ class AppCollector
7
+ def run_para targets, scheduler_class, start_time, fdh
8
+ sock_path = config['sock-path'] || '/tmp/.gcollectsock'
9
+ begin
10
+ server_sock = UNIXServer.new sock_path
11
+ rescue SystemCallError
12
+ puts "#{$!}: server_sock error" if $debug
13
+ Log.fatal "#{$!}: server_sock error"
14
+ return
15
+ end
16
+
17
+ duration = (config['duration'] || 0).to_i
18
+ if duration.zero?
19
+ basetime = start_time
20
+ offset = 0
21
+ else
22
+ basetime = start_time - start_time % duration
23
+ offset = start_time - basetime
24
+ end
25
+ interval = (config['interval'] || 300).to_i
26
+ ptargets = get_ptargets targets, basetime, duration, offset, interval
27
+ log_dir = config['log-dir'] || (config['root-dir'] + '/log')
28
+ Dir.glob("#{log_dir}/res.*.dump") {|path| File.unlink path} rescue nil
29
+ max_processes = (config['max-processes'] ||
30
+ config['max-fork-process']).to_i
31
+ max_processes = 30 if max_processes < 1
32
+ nproc = [targets.size * 2 / 3 + 1, max_processes].min
33
+ waittime = [20, duration].min
34
+ begin
35
+ pids = fork_child server_sock, sock_path, nproc, targets, log_dir,
36
+ scheduler_class, fdh
37
+ server_loop targets, ptargets, server_sock, waittime
38
+ rescue TimeoutError, SystemCallError
39
+ Log.error $!.inspect
40
+ ensure
41
+ server_sock.close
42
+ Log.info "server_sock.close"
43
+ File.unlink sock_path
44
+ end
45
+ pids.each {|pid| Process.waitpid pid}
46
+ Dir.glob("#{log_dir}/res.#{$$}.*.dump") {|path|
47
+ begin
48
+ res = Marshal.load_from_file path
49
+ res.each {|k, v| @metrics[k] += v}
50
+ File.unlink path
51
+ rescue SystemCallError
52
+ Log.error "{$!}"
53
+ end
54
+ }
55
+ end
56
+
57
+ def server_loop targets, ptargets, server_sock, waittime
58
+ sock = nil
59
+ pkeys = ptargets.keys.sort
60
+ pts = []
61
+ while true
62
+ break if pkeys.empty?
63
+ now = Time.now.to_f
64
+ t = pkeys.first
65
+ if t <= now
66
+ pkeys.shift
67
+ pts += ptargets[t]
68
+ while (n = pts.shift)
69
+ timeout(waittime) {sock = server_sock.accept}
70
+ if (res = IO.select(nil, [sock], nil, 20))
71
+ thost = targets[n].first
72
+ sock.puts "#{n} #{thost}"
73
+ sock.close
74
+ else
75
+ sock.close
76
+ raise TimeoutError, 'select timeout'
77
+ end
78
+ if pts.empty? and (t = pkeys.first)
79
+ now = Time.now.to_f
80
+ if t <= now
81
+ pkeys.shift
82
+ small, big = [pts, ptargets[t]].sort_by {|e| e.size}
83
+ pts.replace big.zip(small)
84
+ pts.flatten!
85
+ pts.compact!
86
+ #pts += ptargets[t]
87
+ end
88
+ end
89
+ end
90
+ else
91
+ sleep(t - now)
92
+ end
93
+ end
94
+ end
95
+
96
+ def get_ptargets targets, basetime, duration, offset=0, default_interval=300
97
+ if duration.zero?
98
+ ptargets = {basetime=>(0..targets.size-1).to_a}
99
+ else
100
+ intervals = {}
101
+ n = 0
102
+ for host, options in targets
103
+ interval = (options['interval'] || default_interval).to_i
104
+ next if interval.zero?
105
+ (intervals[interval] ||= []).push n
106
+ n += 1
107
+ end
108
+ ptargets = {}
109
+ et = basetime + duration
110
+ for interval in intervals.keys
111
+ st = basetime - basetime % interval
112
+ (0..duration/interval).each {|n|
113
+ s = n * interval
114
+ if (t = st + s) >= basetime and t < et
115
+ ptargets[t+offset] ||= []
116
+ ptargets[t+offset] += intervals[interval]
117
+ end
118
+ }
119
+ end
120
+ end
121
+ ptargets
122
+ end
123
+
124
+ def get_max_queue_size
125
+ 4
126
+ end
127
+
128
+ def fillup_queue n, sock_path, targets, scheduler
129
+ e = false
130
+ mqs = get_max_queue_size
131
+ while scheduler.queue.size < mqs
132
+ begin
133
+ unless File.socket? sock_path
134
+ e = true
135
+ break
136
+ end
137
+ sock = UNIXSocket.new sock_path
138
+ rescue Errno::ECONNREFUSED
139
+ sock.close rescue nil
140
+ sleep(0.1 + rand)
141
+ retry
142
+ rescue SystemCallError
143
+ sock.close rescue nil
144
+ e = true
145
+ break
146
+ end
147
+ begin
148
+ unless (line = sock.gets)
149
+ e = true
150
+ break
151
+ end
152
+ rescue
153
+ e = true
154
+ break
155
+ ensure
156
+ sock.close
157
+ end
158
+ num, host = line.split
159
+ scheduler.queue.push targets[num.to_i]
160
+ scheduler.process_queue
161
+ end
162
+ e
163
+ end
164
+
165
+ def fork_child server_sock, sock_path, nproc, targets, log_dir,
166
+ scheduler_class, fdh
167
+ pids = []
168
+ ppid = $$
169
+ for n in 1..nproc
170
+ pid = fork {
171
+ server_sock.close
172
+ start_time = Time.now
173
+ sleep 0.05 * n
174
+ Log.debug "child ##{n}"
175
+ loop = Loop.new
176
+ @writers.each {|writer| writer.loop = loop}
177
+ scheduler = scheduler_class.new loop, @metrics
178
+ scheduler.queue = []
179
+ scheduler.writers = @writers
180
+ scheduler.fake_descr_hash = fdh
181
+
182
+ e = fillup_queue n, sock_path, targets, scheduler
183
+ scheduler.process_queue
184
+ if !e or loop.has_active_watchers?
185
+ while true
186
+ loop.run_once
187
+ break if e and !loop.has_active_watchers?
188
+ e = fillup_queue n, sock_path, targets, scheduler
189
+ scheduler.process_queue
190
+ end
191
+ end
192
+ scheduler.finalize
193
+ rc = @metrics[:run_count]
194
+ elapsed = Time.now - start_time
195
+ Log.debug "end ##{n} #{rc} #{rc/elapsed}"
196
+ #@metrics["run_count#{n}".intern] = rc
197
+ begin
198
+ path = "#{log_dir}/res.#{ppid}.#{$$}.dump"
199
+ Marshal.dump_to_file @metrics, path
200
+ rescue SystemCallError
201
+ Log.error "#{$!}"
202
+ end
203
+ }
204
+ pids.push pid
205
+ end
206
+ pids
207
+ end
208
+ end
209
+ end
data/lib/gri/plugin.rb ADDED
@@ -0,0 +1,75 @@
1
+ module GRI
2
+ module Plugin
3
+ extend Plugin
4
+
5
+ def load_plugins dirs=[], config=nil
6
+ @loaded = {}
7
+ dirs += get_gem_dirs
8
+ dirs.push File.join(File.dirname(__FILE__), 'plugin')
9
+ dirs.each {|dir| load_plugin_dir dir, config}
10
+ end
11
+
12
+ def load_plugin_dir dir, config=nil
13
+ dir = File.expand_path dir
14
+ return unless File.exists? dir
15
+ files = get_plugin_files dir, config
16
+ files.each {|fname|
17
+ unless @loaded[fname]
18
+ path = File.join dir, fname
19
+ require path
20
+ @loaded[fname] = path
21
+ end
22
+ }
23
+ end
24
+
25
+ def get_plugin_files dir, config=nil
26
+ files = Dir.entries(dir).sort.select {|fname| fname =~ /\A[^.].*\.rb$/}
27
+ if config
28
+ if config['enable-plugin']
29
+ eps = config.getvar 'enable-plugin'
30
+ files = files.select {|fname|
31
+ s = fname.sub(/\.rb$/, '')
32
+ eps.detect {|pname| pname == s}
33
+ }
34
+ end
35
+ if config['disable-plugin']
36
+ dps = config.getvar 'disable-plugin'
37
+ files = files.select {|fname|
38
+ s = fname.sub(/\.rb$/, '')
39
+ !dps.detect {|pname| pname == s}
40
+ }
41
+ end
42
+ end
43
+ files
44
+ end
45
+
46
+ def get_gem_dirs
47
+ dirs = []
48
+ if Object.const_defined?(:Gem)
49
+ if defined?(::Gem::Specification) and
50
+ Gem::Specification.respond_to?(:find_all)
51
+ specs = Gem::Specification.find_all {|spec|
52
+ spec.full_require_paths.map {|path|
53
+ File.directory?(path + '/gri/plugin')}.any?
54
+ }.sort_by {|spec| spec.version}.reverse
55
+ names = {}
56
+ specs.each {|spec| names[spec.name] ||= spec}
57
+ names.values.each {|spec|
58
+ dirs += spec.full_require_paths.map {|path| path + '/gri/plugin'}
59
+ }
60
+ elsif Gem.respond_to?(:searcher)
61
+ specs = Gem.searcher.find_all 'gri/plugin/*.rb'
62
+ names = {}
63
+ specs.sort_by {|spec| spec.version}.reverse.each {|spec|
64
+ names[spec.name] ||= spec
65
+ }
66
+ names.values.each {|spec|
67
+ files = Gem.searcher.matching_files spec, 'gri/plugin/*.rb'
68
+ dirs += files.map {|fname| File.dirname fname}
69
+ }
70
+ end
71
+ end
72
+ dirs
73
+ end
74
+ end
75
+ end