| Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
|---|---|---|---|---|
| lib/buildr/ide/eclipse.rb | 433 | 268 | 16.86%
|
20.52%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 # Licensed to the Apache Software Foundation (ASF) under one or more |
2 # contributor license agreements. See the NOTICE file distributed with this |
3 # work for additional information regarding copyright ownership. The ASF |
4 # licenses this file to you under the Apache License, Version 2.0 (the |
5 # "License"); you may not use this file except in compliance with the License. |
6 # You may obtain a copy of the License at |
7 # |
8 # http://www.apache.org/licenses/LICENSE-2.0 |
9 # |
10 # Unless required by applicable law or agreed to in writing, software |
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
13 # License for the specific language governing permissions and limitations under |
14 # the License. |
15 |
16 |
17 require 'buildr/core/project' |
18 require 'buildr/packaging' |
19 |
20 |
21 module Buildr |
22 module Eclipse #:nodoc: |
23 include Extension |
24 |
25 class Eclipse |
26 |
27 attr_reader :options |
28 attr_writer :name |
29 |
30 def initialize(project) |
31 @project = project |
32 @options = Options.new(project) |
33 end |
34 |
35 def name |
36 return @name if @name |
37 return @project.id.split('-').last if @options.short_names |
38 @project.id |
39 end |
40 |
41 # :call-seq: |
42 # classpath_variables :VAR => '/path/to/location' |
43 # Sets classpath variables to be used for library path substitution |
44 # on the project. |
45 # |
46 def classpath_variables(*values) |
47 fail "eclipse.classpath_variables expects a single hash argument" if values.size > 1 |
48 if values.size == 1 |
49 fail "eclipse.classpath_variables expects a Hash argument" unless values[0].is_a? Hash |
50 # convert keys to strings |
51 values = values[0].inject({}) { |h, (k,v)| h[k.to_s] = @project.path_to(v); h } |
52 @variables = values.merge(@variables || {}) |
53 end |
54 @variables || (@project.parent ? @project.parent.eclipse.classpath_variables : default_classpath_variables) |
55 end |
56 |
57 def default_classpath_variables |
58 vars = {} |
59 vars[:SCALA_HOME] = ENV['SCALA_HOME'] if ENV['SCALA_HOME'] |
60 vars[:JAVA_HOME] = ENV['JAVA_HOME'] if ENV['JAVA_HOME'] |
61 vars |
62 end |
63 |
64 # :call-seq: |
65 # natures=(natures) |
66 # Sets the Eclipse project natures on the project. |
67 # |
68 def natures=(var) |
69 @natures = arrayfy(var) |
70 end |
71 |
72 # :call-seq: |
73 # natures() => [n1, n2] |
74 # Returns the Eclipse project natures on the project. |
75 # They may be derived from the parent project if no specific natures have been set |
76 # on the project. |
77 # |
78 # An Eclipse project nature is used internally by Eclipse to determine the aspects of a project. |
79 def natures(*values) |
80 if values.size > 0 |
81 @natures ||= [] |
82 @natures += values.flatten |
83 else |
84 @natures || (@project.parent ? @project.parent.eclipse.natures : []) |
85 end |
86 end |
87 |
88 # :call-seq: |
89 # classpath_containers=(cc) |
90 # Sets the Eclipse project classpath containers on the project. |
91 # |
92 def classpath_containers=(var) |
93 @classpath_containers = arrayfy(var) |
94 end |
95 |
96 # :call-seq: |
97 # classpath_containers() => [con1, con2] |
98 # Returns the Eclipse project classpath containers on the project. |
99 # They may be derived from the parent project if no specific classpath containers have been set |
100 # on the project. |
101 # |
102 # A classpath container is an Eclipse pre-determined ensemble of dependencies made available to |
103 # the project classpath. |
104 def classpath_containers(*values) |
105 if values.size > 0 |
106 @classpath_containers ||= [] |
107 @classpath_containers += values.flatten |
108 else |
109 @classpath_containers || (@project.parent ? @project.parent.eclipse.classpath_containers : []) |
110 end |
111 end |
112 |
113 # :call-seq: |
114 # exclude_libs() => [lib1, lib2] |
115 # Returns the an array of libraries to be excluded from the generated Eclipse classpath |
116 def exclude_libs(*values) |
117 if values.size > 0 |
118 @exclude_libs ||= [] |
119 @exclude_libs += values.flatten |
120 else |
121 @exclude_libs || (@project.parent ? @project.parent.eclipse.exclude_libs : []) |
122 end |
123 end |
124 |
125 # :call-seq: |
126 # exclude_libs=(lib1, lib2) |
127 # Sets libraries to be excluded from the generated Eclipse classpath |
128 # |
129 def exclude_libs=(libs) |
130 @exclude_libs = arrayfy(libs) |
131 end |
132 |
133 # :call-seq: |
134 # builders=(builders) |
135 # Sets the Eclipse project builders on the project. |
136 # |
137 def builders=(var) |
138 @builders = arrayfy(var) |
139 end |
140 |
141 # :call-seq: |
142 # builders() => [b1, b2] |
143 # Returns the Eclipse project builders on the project. |
144 # They may be derived from the parent project if no specific builders have been set |
145 # on the project. |
146 # |
147 # A builder is an Eclipse background job that parses the source code to produce built artifacts. |
148 def builders(*values) |
149 if values.size > 0 |
150 @builders ||= [] |
151 @builders += values.flatten |
152 else |
153 @builders || (@project.parent ? @project.parent.eclipse.builders : []) |
154 end |
155 end |
156 |
157 private |
158 |
159 def arrayfy(obj) |
160 obj.is_a?(Array) ? obj : [obj] |
161 end |
162 end |
163 |
164 class Options |
165 |
166 attr_writer :m2_repo_var, :short_names |
167 |
168 def initialize(project) |
169 @project = project |
170 end |
171 |
172 # The classpath variable used to point at the local maven2 repository. |
173 # Example: |
174 # eclipse.options.m2_repo_var = 'M2_REPO' |
175 def m2_repo_var(*values) |
176 fail "m2_repo_var can only accept one value: #{values}" if values.size > 1 |
177 if values.size > 0 |
178 @m2_repo_var = values[0] |
179 else |
180 @m2_repo_var || (@project.parent ? @project.parent.eclipse.options.m2_repo_var : 'M2_REPO') |
181 end |
182 end |
183 |
184 def short_names |
185 @short_names || (@project.parent ? @project.parent.eclipse.options.short_names : false) |
186 end |
187 end |
188 |
189 def eclipse |
190 @eclipse ||= Eclipse.new(self) |
191 @eclipse |
192 end |
193 |
194 first_time do |
195 # Global task "eclipse" generates artifacts for all projects. |
196 desc 'Generate Eclipse artifacts for all projects' |
197 Project.local_task('eclipse'=>'artifacts') { |name| "Generating Eclipse project for #{name}" } |
198 end |
199 |
200 before_define do |project| |
201 project.recursive_task('eclipse') |
202 end |
203 |
204 after_define(:eclipse => :package) do |project| |
205 # Need to enhance because using project.projects during load phase of the |
206 # buildfile has harmful side-effects on project definition order |
207 project.enhance do |
208 eclipse = project.task('eclipse') |
209 # We don't create the .project and .classpath files if the project contains projects. |
210 if project.projects.empty? |
211 |
212 eclipse.enhance [ file(project.path_to('.classpath')), file(project.path_to('.project')) ] |
213 |
214 # The only thing we need to look for is a change in the Buildfile. |
215 file(project.path_to('.classpath')=>Buildr.application.buildfile) do |task| |
216 if (project.eclipse.natures.reject { |x| x.is_a?(Symbol) }.size > 0) |
217 info "Writing #{task.name}" |
218 |
219 m2repo = Buildr::Repositories.instance.local |
220 |
221 File.open(task.name, 'w') do |file| |
222 classpathentry = ClasspathEntryWriter.new project, file |
223 classpathentry.write do |
224 # Note: Use the test classpath since Eclipse compiles both "main" and "test" classes using the same classpath |
225 cp = project.test.compile.dependencies.map(&:to_s) - [ project.compile.target.to_s, project.resources.target.to_s ] |
226 cp = cp.uniq |
227 |
228 # Convert classpath elements into applicable Project objects |
229 cp.collect! { |path| Buildr.projects.detect { |prj| prj.packages.detect { |pkg| pkg.to_s == path } } || path } |
230 |
231 # Remove excluded libs |
232 cp -= project.eclipse.exclude_libs.map(&:to_s) |
233 |
234 # project_libs: artifacts created by other projects |
235 project_libs, others = cp.partition { |path| path.is_a?(Project) } |
236 |
237 # Separate artifacts under known classpath variable paths |
238 # including artifacts located in local Maven2 repository |
239 vars = [] |
240 project.eclipse.classpath_variables.merge(project.eclipse.options.m2_repo_var => m2repo).each do |name, path| |
241 matching, others = others.partition { |f| File.expand_path(f.to_s).index(path) == 0 } |
242 matching.each do |m| |
243 vars << [m, name, path] |
244 end |
245 end |
246 |
247 # Generated: Any non-file classpath elements in the project are assumed to be generated |
248 libs, generated = others.partition { |path| File.file?(path.to_s) } |
249 |
250 classpathentry.src project.compile.sources + generated |
251 classpathentry.src project.resources |
252 |
253 if project.test.compile.target |
254 classpathentry.src project.test.compile |
255 classpathentry.src project.test.resources |
256 end |
257 |
258 # Classpath elements from other projects |
259 classpathentry.src_projects project_libs |
260 |
261 classpathentry.output project.compile.target if project.compile.target |
262 classpathentry.lib libs |
263 classpathentry.var vars |
264 |
265 project.eclipse.classpath_containers.each { |container| |
266 classpathentry.con container |
267 } |
268 end |
269 end |
270 end |
271 end |
272 |
273 # The only thing we need to look for is a change in the Buildfile. |
274 file(project.path_to('.project')=>Buildr.application.buildfile) do |task| |
275 info "Writing #{task.name}" |
276 File.open(task.name, 'w') do |file| |
277 xml = Builder::XmlMarkup.new(:target=>file, :indent=>2) |
278 xml.projectDescription do |
279 xml.name project.eclipse.name |
280 xml.projects |
281 unless project.eclipse.builders.empty? |
282 xml.buildSpec do |
283 project.eclipse.builders.each { |builder| |
284 xml.buildCommand do |
285 xml.name builder |
286 end |
287 } |
288 end |
289 end |
290 unless project.eclipse.natures.empty? |
291 xml.natures do |
292 project.eclipse.natures.each { |nature| |
293 xml.nature nature unless nature.is_a? Symbol |
294 } |
295 end |
296 end |
297 end |
298 end |
299 end |
300 end |
301 end |
302 end |
303 |
304 |
305 # Writes 'classpathentry' tags in an xml file. |
306 # It converts tasks to paths. |
307 # It converts absolute paths to relative paths. |
308 # It ignores duplicate directories. |
309 class ClasspathEntryWriter #:nodoc: |
310 def initialize project, target |
311 @project = project |
312 @xml = Builder::XmlMarkup.new(:target=>target, :indent=>2) |
313 @excludes = [ '**/.svn/', '**/CVS/' ].join('|') |
314 @paths_written = [] |
315 end |
316 |
317 def write &block |
318 @xml.classpath &block |
319 end |
320 |
321 def con path |
322 @xml.classpathentry :kind=>'con', :path=>path |
323 end |
324 |
325 def lib libs |
326 libs.map(&:to_s).sort.uniq.each do |path| |
327 @xml.classpathentry :kind=>'lib', :path=>relative(path) |
328 end |
329 end |
330 |
331 # Write a classpathentry of kind 'src'. |
332 # Accept an array of absolute paths or a task. |
333 def src arg |
334 if [:sources, :target].all? { |message| arg.respond_to?(message) } |
335 src_from_task arg |
336 else |
337 src_from_absolute_paths arg |
338 end |
339 end |
340 |
341 # Write a classpathentry of kind 'src' for dependent projects. |
342 # Accept an array of projects. |
343 def src_projects project_libs |
344 project_libs.map { |project| project.eclipse.name }.sort.uniq.each do |eclipse_name| |
345 @xml.classpathentry :kind=>'src', :combineaccessrules=>'false', :path=>"/#{eclipse_name}" |
346 end |
347 end |
348 |
349 def output target |
350 @xml.classpathentry :kind=>'output', :path=>relative(target) |
351 end |
352 |
353 # Write a classpathentry of kind 'var' (variable) for a library in a local repo. |
354 # * +libs+ is an array of library paths. |
355 # * +var_name+ is a variable name as defined in Eclipse (e.g., 'M2_REPO'). |
356 # * +var_value+ is the value of this variable (e.g., '/home/me/.m2'). |
357 # E.g., <tt>var([lib1, lib2], 'M2_REPO', '/home/me/.m2/repo')</tt> |
358 def var(libs) |
359 libs.each do |lib_path, var_name, var_value| |
360 lib_artifact = file(lib_path) |
361 |
362 attribs = { :kind => 'var', :path => lib_path } |
363 |
364 if lib_artifact.respond_to? :sources_artifact |
365 attribs[:sourcepath] = lib_artifact.sources_artifact |
366 end |
367 |
368 if lib_artifact.respond_to? :javadoc_artifact |
369 attribs[:javadocpath] = lib_artifact.javadoc_artifact |
370 end |
371 |
372 # make all paths relative |
373 attribs.each_key do |k| |
374 attribs[k] = attribs[k].to_s.sub(var_value, var_name.to_s) if k.to_s =~ /path/ |
375 end |
376 |
377 @xml.classpathentry attribs |
378 end |
379 end |
380 |
381 private |
382 |
383 # Find a path relative to the project's root directory if possible. If the |
384 # two paths do not share the same root the absolute path is returned. This |
385 # can happen on Windows, for instance, when the two paths are not on the |
386 # same drive. |
387 def relative path |
388 path or raise "Invalid path '#{path.inspect}'" |
389 msg = [:to_path, :to_str, :to_s].find { |msg| path.respond_to? msg } |
390 path = path.__send__(msg) |
391 begin |
392 relative = Util.relative_path(File.expand_path(path), @project.path_to) |
393 if relative['..'] |
394 # paths don't share same root |
395 Util.normalize_path(path) |
396 else |
397 relative |
398 end |
399 rescue ArgumentError |
400 Util.normalize_path(path) |
401 end |
402 end |
403 |
404 def src_from_task task |
405 src_from_absolute_paths task.sources, task.target |
406 end |
407 |
408 def src_from_absolute_paths absolute_paths, output=nil |
409 relative_paths = absolute_paths.map { |src| relative(src) } |
410 relative_paths.sort.uniq.each do |path| |
411 unless @paths_written.include?(path) |
412 attributes = { :kind=>'src', :path=>path, :excluding=>@excludes } |
413 attributes[:output] = relative(output) if output |
414 @xml.classpathentry attributes |
415 @paths_written << path |
416 end |
417 end |
418 end |
419 end |
420 |
421 end |
422 |
423 end # module Buildr |
424 |
425 class Buildr::Project |
426 include Buildr::Eclipse |
427 end |
428 |
429 # Order is significant for auto-detection, from most specific to least |
430 require 'buildr/ide/eclipse/plugin' |
431 require 'buildr/ide/eclipse/scala' |
432 require 'buildr/ide/eclipse/java' |
433 |
Generated on 2011-07-06 23:35:37 -0700 with rcov 0.9.8