buildr 1.4.4 → 1.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. data/CHANGELOG +46 -0
  2. data/Rakefile +0 -1
  3. data/addon/buildr/bnd.rb +147 -0
  4. data/addon/buildr/jaxb_xjc.rb +72 -0
  5. data/addon/buildr/protobuf.rb +14 -1
  6. data/buildr.gemspec +6 -2
  7. data/doc/artifacts.textile +6 -0
  8. data/doc/contributing.textile +3 -0
  9. data/doc/download.textile +60 -0
  10. data/doc/index.textile +9 -15
  11. data/doc/installing.textile +23 -6
  12. data/doc/mailing_lists.textile +4 -0
  13. data/doc/more_stuff.textile +333 -6
  14. data/doc/packaging.textile +187 -1
  15. data/lib/buildr.rb +8 -1
  16. data/lib/buildr/clojure.rb +34 -0
  17. data/lib/buildr/clojure/shell.rb +52 -0
  18. data/lib/buildr/core.rb +3 -0
  19. data/lib/buildr/core/#application.rb# +700 -0
  20. data/lib/buildr/core/application.rb +18 -8
  21. data/lib/buildr/core/build.rb +2 -2
  22. data/lib/buildr/core/cc.rb +57 -63
  23. data/lib/buildr/core/checks.rb +4 -5
  24. data/lib/buildr/core/doc.rb +3 -1
  25. data/lib/buildr/core/generate.rb +2 -0
  26. data/lib/buildr/core/jrebel.rb +42 -0
  27. data/lib/buildr/core/linux.rb +30 -0
  28. data/lib/buildr/core/project.rb +9 -8
  29. data/lib/buildr/core/run.rb +3 -3
  30. data/lib/buildr/core/shell.rb +29 -90
  31. data/lib/buildr/core/test.rb +3 -3
  32. data/lib/buildr/core/transports.rb +5 -5
  33. data/lib/buildr/core/util.rb +2 -2
  34. data/lib/buildr/groovy.rb +1 -0
  35. data/lib/buildr/groovy/compiler.rb +12 -1
  36. data/lib/buildr/groovy/doc.rb +76 -0
  37. data/lib/buildr/groovy/shell.rb +24 -15
  38. data/lib/buildr/ide.rb +1 -1
  39. data/lib/buildr/ide/idea.rb +527 -141
  40. data/lib/buildr/java/bdd.rb +18 -13
  41. data/lib/buildr/java/ecj.rb +1 -3
  42. data/lib/buildr/java/jtestr_result.rb +295 -0
  43. data/lib/buildr/java/jtestr_runner.rb.erb +4 -6
  44. data/lib/buildr/java/packaging.rb +14 -3
  45. data/lib/buildr/java/pom.rb +6 -2
  46. data/lib/buildr/java/test_result.rb +15 -243
  47. data/lib/buildr/java/tests.rb +1 -1
  48. data/lib/buildr/packaging.rb +2 -1
  49. data/lib/buildr/packaging/#package.rb.rej# +19 -0
  50. data/lib/buildr/packaging/archive.rb +13 -3
  51. data/lib/buildr/packaging/artifact.rb +11 -12
  52. data/lib/buildr/packaging/tar.rb +4 -1
  53. data/lib/buildr/packaging/zip.rb +106 -1
  54. data/lib/buildr/resources/completed.png +0 -0
  55. data/lib/buildr/resources/failed.png +0 -0
  56. data/lib/buildr/resources/icons-license.txt +17 -0
  57. data/lib/buildr/run.rb +7 -14
  58. data/lib/buildr/scala/#Untitled-2# +7 -0
  59. data/lib/buildr/scala/bdd.rb +1 -1
  60. data/lib/buildr/scala/compiler.rb +1 -1
  61. data/lib/buildr/scala/doc.rb +20 -2
  62. data/lib/buildr/scala/shell.rb +14 -22
  63. data/lib/buildr/scala/tests.rb +2 -2
  64. data/lib/buildr/shell.rb +113 -108
  65. data/lib/buildr/version.rb +1 -1
  66. data/rakelib/checks.rake +9 -7
  67. data/rakelib/doc.rake +10 -0
  68. data/rakelib/release.rake +9 -0
  69. data/rakelib/rspec.rake +27 -28
  70. data/rakelib/setup.rake +1 -1
  71. data/rakelib/stage.rake +2 -2
  72. data/spec/addon/bnd_spec.rb +330 -0
  73. data/spec/addon/jaxb_xjc_spec.rb +125 -0
  74. data/spec/core/application_spec.rb +1 -1
  75. data/spec/core/build_spec.rb +7 -7
  76. data/spec/core/cc_spec.rb +154 -104
  77. data/spec/core/compile_spec.rb +3 -3
  78. data/spec/core/project_spec.rb +10 -0
  79. data/spec/core/run_spec.rb +1 -0
  80. data/spec/core/shell_spec.rb +146 -0
  81. data/spec/groovy/doc_spec.rb +65 -0
  82. data/spec/ide/eclipse_spec.rb +1 -1
  83. data/spec/ide/idea_spec.rb +1145 -0
  84. data/spec/java/bdd_spec.rb +3 -3
  85. data/spec/java/emma_spec.rb +2 -0
  86. data/spec/java/packaging_spec.rb +40 -11
  87. data/spec/java/test_coverage_helper.rb +1 -1
  88. data/spec/packaging/archive_spec.rb +76 -21
  89. data/spec/packaging/artifact_namespace_spec.rb +1 -1
  90. data/spec/packaging/artifact_spec.rb +14 -7
  91. data/spec/sandbox.rb +11 -4
  92. data/spec/scala/bdd_spec.rb +2 -2
  93. data/spec/scala/compiler_spec.rb +2 -2
  94. data/spec/scala/doc_spec.rb +24 -4
  95. data/spec/scala/scala.rb +2 -2
  96. data/spec/scala/tests_spec.rb +2 -2
  97. data/spec/spec_helpers.rb +9 -8
  98. data/spec/xpath_matchers.rb +121 -0
  99. metadata +248 -164
  100. data/lib/buildr/ide/idea.ipr.template +0 -300
  101. data/lib/buildr/ide/idea7x.ipr.template +0 -290
  102. data/lib/buildr/ide/idea7x.rb +0 -231
  103. data/spec/ide/idea7x_spec.rb +0 -96
@@ -19,14 +19,16 @@ require 'buildr/java/commands'
19
19
  require 'buildr/core/util'
20
20
 
21
21
  module Buildr
22
+
22
23
  module Shell
23
24
 
24
25
  class BeanShell < Base
25
-
26
- include JavaRebel
26
+ include Buildr::JRebel
27
27
 
28
28
  VERSION = '2.0b4'
29
29
 
30
+ specify :name => :bsh, :languages => [:java]
31
+
30
32
  class << self
31
33
  def version
32
34
  Buildr.settings.build['bsh'] || VERSION
@@ -35,22 +37,16 @@ module Buildr
35
37
  def artifact
36
38
  "org.beanshell:bsh:jar:#{version}"
37
39
  end
38
-
39
- def lang
40
- :java
41
- end
42
-
43
- def to_sym
44
- :bsh
45
- end
46
40
  end
47
41
 
48
- def launch
49
- cp = project.compile.dependencies + [project.path_to(:target, :classes), Buildr.artifact(BeanShell.artifact)]
42
+ def launch(task)
43
+ cp = ( project.compile.dependencies +
44
+ [project.path_to(:target, :classes), Buildr.artifact(BeanShell.artifact)] +
45
+ task.classpath )
50
46
  Java::Commands.java 'bsh.Console', {
51
- :properties => rebel_props(project),
47
+ :properties => jrebel_props(project).merge(task.properties),
52
48
  :classpath => cp,
53
- :java_args => rebel_args
49
+ :java_args => jrebel_args + task.java_args
54
50
  }
55
51
  end
56
52
 
@@ -58,26 +54,23 @@ module Buildr
58
54
 
59
55
 
60
56
  class JIRB < Base
61
- include JavaRebel
57
+ include JRebel
62
58
 
63
59
  JRUBY_VERSION = '1.4.0'
64
60
 
65
- class << self
66
- def lang
67
- :none
68
- end
69
- end
70
-
71
- def launch
61
+ def launch(task)
72
62
  if jruby_home # if JRuby is installed, use it
73
63
  cp = project.compile.dependencies +
74
64
  [project.path_to(:target, :classes)] +
75
- Dir.glob("#{jruby_home}#{File::SEPARATOR}lib#{File::SEPARATOR}*.jar")
65
+ Dir.glob("#{jruby_home}#{File::SEPARATOR}lib#{File::SEPARATOR}*.jar") +
66
+ task.classpath
76
67
 
77
68
  props = {
78
69
  'jruby.home' => jruby_home,
79
70
  'jruby.lib' => "#{jruby_home}#{File::SEPARATOR}lib"
80
71
  }
72
+ props.merge! jrebel_props(project)
73
+ props.merge! task.properties
81
74
 
82
75
  if not Util.win_os?
83
76
  uname = `uname -m`
@@ -104,26 +97,27 @@ module Buildr
104
97
 
105
98
  args = [
106
99
  "-Xbootclasspath/a:#{Dir.glob("#{jruby_home}#{File::SEPARATOR}lib#{File::SEPARATOR}jruby*.jar").join File::PATH_SEPARATOR}"
107
- ]
100
+ ] + jrebel_args + task.java_args
108
101
 
109
102
  Java::Commands.java 'org.jruby.Main', "#{jruby_home}#{File::SEPARATOR}bin#{File::SEPARATOR}jirb", {
110
- :properties => props.merge(rebel_props(project)),
103
+ :properties => props,
111
104
  :classpath => cp,
112
- :java_args => args + rebel_args
105
+ :java_args => args
113
106
  }
114
107
  else
115
- cp = project.compile.dependencies + [
116
- jruby_artifact,
117
- project.path_to(:target, :classes)
118
- ]
108
+ cp = project.compile.dependencies + [ jruby_artifact, project.path_to(:target, :classes) ] +
109
+ task.classpath
110
+ props = jrebel_props(project).merge(task.properties)
111
+ args = jrebel_args + task.java_args
119
112
 
120
113
  Java::Commands.java 'org.jruby.Main', '--command', 'irb', {
121
- :properties => rebel_props(project),
114
+ :properties => props,
122
115
  :classpath => cp,
123
- :java_args => rebel_args
116
+ :java_args => args
124
117
  }
125
118
  end
126
119
  end
120
+
127
121
  private
128
122
  def jruby_home
129
123
  @jruby_home ||= RUBY_PLATFORM =~ /java/ ? Config::CONFIG['prefix'] : ENV['JRUBY_HOME']
@@ -135,64 +129,9 @@ module Buildr
135
129
  end
136
130
 
137
131
  end
138
-
139
- class Clojure < Base
140
- include JavaRebel
141
-
142
- JLINE_VERSION = '0.9.94'
143
-
144
- class << self
145
- def lang
146
- :none
147
- end
148
-
149
- def to_sym
150
- :clj # more common than `clojure`
151
- end
152
- end
153
-
154
- # don't build if it's *only* Clojure sources
155
- def build?
156
- !has_source?(:clojure) or has_source?(:java) or has_source?(:scala) or has_source?(:groovy)
157
- end
158
-
159
- def launch
160
- fail 'Are we forgetting something? CLOJURE_HOME not set.' unless clojure_home
161
-
162
- cp = project.compile.dependencies +
163
- [
164
- if build?
165
- project.path_to(:target, :classes)
166
- else
167
- project.path_to(:src, :main, :clojure)
168
- end,
169
- File.expand_path('clojure.jar', clojure_home),
170
- 'jline:jline:jar:0.9.94'
171
- ]
172
-
173
- if build?
174
- Java::Commands.java 'jline.ConsoleRunner', 'clojure.lang.Repl', {
175
- :properties => rebel_props(project),
176
- :classpath => cp,
177
- :java_args => rebel_args
178
- }
179
- else
180
- Java::Commands.java 'jline.ConsoleRunner', 'clojure.lang.Repl', :classpath => cp
181
- end
182
- end
183
-
184
- private
185
- def clojure_home
186
- @home ||= ENV['CLOJURE_HOME']
187
- end
188
-
189
- def has_source?(lang)
190
- File.exists? project.path_to(:src, :main, lang)
191
- end
192
- end
193
132
  end
194
133
  end
195
134
 
196
- Buildr::ShellProviders << Buildr::Shell::BeanShell
197
- Buildr::ShellProviders << Buildr::Shell::JIRB
198
- Buildr::ShellProviders << Buildr::Shell::Clojure
135
+ Buildr::Shell.providers << Buildr::Shell::BeanShell
136
+ Buildr::Shell.providers << Buildr::Shell::JIRB
137
+
@@ -193,8 +193,8 @@ module Buildr
193
193
 
194
194
  # Used by the test/integration to include specific tests
195
195
  def include(includes)
196
+ includes = wildcardify(Array(includes))
196
197
  Project.projects.each do |project|
197
- includes = wildcardify(includes)
198
198
  project.test.send :include, *includes if includes.size > 0
199
199
  project.test.send :forced_need=, true
200
200
  end
@@ -202,8 +202,8 @@ module Buildr
202
202
 
203
203
  # Used by the test/integration to exclude specific tests
204
204
  def exclude(excludes)
205
+ excludes = wildcardify(Array(excludes))
205
206
  Project.projects.each do |project|
206
- excludes = wildcardify(excludes)
207
207
  project.test.send :exclude, *excludes if excludes.size > 0
208
208
  project.test.send :forced_need=, true
209
209
  end
@@ -646,7 +646,7 @@ module Buildr
646
646
  excludes.map! { |t| t[1..-1] }
647
647
 
648
648
  TestTask.clear
649
- TestTask.include(includes.empty? ? '*' : includes)
649
+ TestTask.include(includes.empty? ? ['*'] : includes)
650
650
  TestTask.exclude excludes
651
651
  end
652
652
  task('test').invoke
@@ -214,14 +214,14 @@ module URI
214
214
  elsif source.respond_to?(:read)
215
215
  digests = (options[:digests] || [:md5, :sha1]).
216
216
  inject({}) { |hash, name| hash[name] = Digest.const_get(name.to_s.upcase).new ; hash }
217
- size = source.size rescue nil
217
+ size = source.stat.size rescue nil
218
218
  write (options).merge(:progress=>verbose && size, :size=>size) do |bytes|
219
219
  source.read(bytes).tap do |chunk|
220
220
  digests.values.each { |digest| digest << chunk } if chunk
221
221
  end
222
222
  end
223
223
  digests.each do |key, digest|
224
- self.merge("#{self.path}.#{key}").write "#{digest.hexdigest} #{File.basename(path)}",
224
+ self.merge("#{self.path}.#{key}").write digest.hexdigest,
225
225
  (options).merge(:progress=>false)
226
226
  end
227
227
  else
@@ -406,7 +406,7 @@ module URI
406
406
  SFTP.passwords[host] = ssh_options[:password]
407
407
  trace 'connected'
408
408
 
409
- with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
409
+ with_progress_bar options[:progress] && options[:size], path.split('/').last, options[:size] || 0 do |progress|
410
410
  trace "Downloading from #{path}"
411
411
  sftp.file.open(path, 'r') do |file|
412
412
  while chunk = file.read(RW_CHUNK_SIZE)
@@ -450,7 +450,7 @@ module URI
450
450
  "#{combined}/"
451
451
  end
452
452
 
453
- with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
453
+ with_progress_bar options[:progress] && options[:size], path.split('/').last, options[:size] || 0 do |progress|
454
454
  trace "Uploading to #{path}"
455
455
  sftp.file.open(path, 'w') do |file|
456
456
  while chunk = yield(RW_CHUNK_SIZE)
@@ -546,7 +546,7 @@ module URI
546
546
  raise ArgumentError, 'Either you\'re attempting to write a file to another host (which we don\'t support), or you used two slashes by mistake, where you should have file:///<path>.' if host
547
547
  temp = Tempfile.new(File.basename(path))
548
548
  temp.binmode
549
- with_progress_bar options[:progress] && options[:size], path.split('/'), options[:size] || 0 do |progress|
549
+ with_progress_bar options[:progress] && options[:size], path.split('/').last, options[:size] || 0 do |progress|
550
550
  while chunk = yield(RW_CHUNK_SIZE)
551
551
  temp.write chunk
552
552
  progress << chunk
@@ -484,8 +484,8 @@ if Buildr::Util.java_platform?
484
484
  arg_str = args.map { |a| "'#{a}'" }
485
485
  __native_system__(cd + cmd.first + ' ' + arg_str.join(' '))
486
486
  end
487
- $? = Buildr::ProcessStatus.new(0, res == 0, res) # KLUDGE
488
- block.call(res == 0, $?)
487
+ status = Buildr::ProcessStatus.new(0, res == 0, res) # KLUDGE
488
+ block.call(res == 0, status)
489
489
  end
490
490
  end
491
491
 
@@ -16,4 +16,5 @@
16
16
 
17
17
  require 'buildr/groovy/compiler'
18
18
  require 'buildr/groovy/bdd'
19
+ require 'buildr/groovy/doc'
19
20
  require 'buildr/groovy/shell'
@@ -16,6 +16,17 @@
16
16
 
17
17
  module Buildr::Groovy
18
18
 
19
+ REQUIRES = ArtifactNamespace.for(self) do |ns|
20
+ ns.jansi! 'org.fusesource.jansi:jansi:jar:1.2.1'
21
+ ns.jline! 'jline:jline:jar:0.9.94'
22
+ end
23
+
24
+ class << self
25
+ def dependencies #:nodoc:
26
+ REQUIRES.artifacts + Groovyc.dependencies
27
+ end
28
+ end
29
+
19
30
  # Groovyc compiler:
20
31
  # compile.using(:groovyc)
21
32
  #
@@ -57,7 +68,7 @@ module Buildr::Groovy
57
68
  #
58
69
  # namespace before this file is required.
59
70
  REQUIRES = ArtifactNamespace.for(self) do |ns|
60
- ns.groovy! 'org.codehaus.groovy:groovy:jar:>=1.7.1'
71
+ ns.groovy! 'org.codehaus.groovy:groovy:jar:>=1.7.5'
61
72
  ns.commons_cli! 'commons-cli:commons-cli:jar:>=1.2'
62
73
  ns.asm! 'asm:asm:jar:>=3.2'
63
74
  ns.antlr! 'antlr:antlr:jar:>=2.7.7'
@@ -0,0 +1,76 @@
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
+ require 'buildr/core/doc'
17
+ require 'buildr/groovy/compiler' # ensure Groovy dependencies are ready
18
+
19
+ module Buildr
20
+ module Doc
21
+
22
+ module GroovydocDefaults
23
+ include Extension
24
+
25
+ # Default groovydoc -doc-title to project's comment or name
26
+ after_define(:groovydoc => :doc) do |project|
27
+ if project.doc.engine? Groovydoc
28
+ options = project.doc.options
29
+ options[:windowtitle] = (project.comment || project.name) unless options[:windowtitle]
30
+ end
31
+ end
32
+ end
33
+
34
+ class Groovydoc < Base
35
+ specify :language => :groovy, :source_ext => ['java', 'groovy']
36
+
37
+ def generate(sources, target, options = {})
38
+ mkdir_p target
39
+ cmd_args = [ '-d', target, trace?(:groovydoc) ? '-verbose' : nil ].compact
40
+ options.reject { |key, value| [:sourcepath, :classpath].include?(key) }.
41
+ each { |key, value| value.invoke if value.respond_to?(:invoke) }.
42
+ each do |key, value|
43
+ case value
44
+ when true, nil
45
+ cmd_args << "-#{key}"
46
+ when false
47
+ cmd_args << "-no#{key}"
48
+ when Hash
49
+ value.each { |k,v| cmd_args << "-#{key}" << k.to_s << v.to_s }
50
+ else
51
+ cmd_args += Array(value).map { |item| ["-#{key}", item.to_s] }.flatten
52
+ end
53
+ end
54
+ [:sourcepath, :classpath].each do |option|
55
+ Array(options[option]).flatten.tap do |paths|
56
+ cmd_args << "-#{option}" << paths.flatten.map(&:to_s).join(File::PATH_SEPARATOR) unless paths.empty?
57
+ end
58
+ end
59
+ cmd_args += sources.flatten.uniq
60
+ unless Buildr.application.options.dryrun
61
+ info "Generating Groovydoc for #{project.name}"
62
+ trace (['groovydoc'] + cmd_args).join(' ')
63
+ result = Java::Commands.java('org.codehaus.groovy.tools.groovydoc.Main', cmd_args,
64
+ :classpath => Buildr::Groovy.dependencies)
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ class Project
71
+ include GroovydocDefaults
72
+ end
73
+ end
74
+
75
+ Buildr::Doc.engines << Buildr::Doc::Groovydoc
76
+
@@ -18,25 +18,34 @@ require 'buildr/shell'
18
18
  module Buildr
19
19
  module Groovy
20
20
  class GroovySH < Buildr::Shell::Base
21
+ include JRebel
22
+
21
23
  SUFFIX = if Util.win_os? then '.bat' else '' end
22
24
 
23
- class << self
24
- def lang
25
- :groovy
25
+ specify :name => :groovy, :languages => [:groovy]
26
+
27
+ def launch(task)
28
+ cp = Groovy.dependencies +
29
+ project.compile.dependencies +
30
+ [ project.path_to(:target, :classes) ] +
31
+ task.classpath
32
+ props = jrebel_props(project).merge(task.properties)
33
+ java_args = jrebel_args + task.java_args
34
+
35
+ groovy_home = nil
36
+ if groovy_home
37
+ cmd_args = " -classpath '#{cp.join(File::SEPARATOR)}'"
38
+ trace "groovysh #{cmd_args}"
39
+ system(File.expand_path("bin#{File::SEPARATOR}groovysh#{SUFFIX}", groovy_home) + cmd_args)
40
+ else
41
+ Java::Commands.java 'org.codehaus.groovy.tools.shell.Main', {
42
+ :properties => props,
43
+ :classpath => cp,
44
+ :java_args => java_args
45
+ }
26
46
  end
27
47
  end
28
48
 
29
- def launch
30
- fail 'Are we forgetting something? GROOVY_HOME not set.' unless groovy_home
31
-
32
- cp = project.compile.dependencies.join(File::PATH_SEPARATOR) +
33
- File::PATH_SEPARATOR + project.path_to(:target, :classes)
34
-
35
- cmd_args = " -classpath '#{cp}'"
36
- trace "groovysh #{cmd_args}"
37
- system(File.expand_path("bin#{File::SEPARATOR}groovysh#{SUFFIX}", groovy_home) + cmd_args)
38
- end
39
-
40
49
  private
41
50
  def groovy_home
42
51
  @home ||= ENV['GROOVY_HOME']
@@ -45,4 +54,4 @@ module Buildr
45
54
  end
46
55
  end
47
56
 
48
- Buildr::ShellProviders << Buildr::Groovy::GroovySH
57
+ Buildr::Shell.providers << Buildr::Groovy::GroovySH
@@ -16,4 +16,4 @@
16
16
 
17
17
  require 'buildr/ide/eclipse'
18
18
  require 'buildr/ide/idea'
19
- require 'buildr/ide/idea7x'
19
+
@@ -20,171 +20,557 @@ require 'stringio'
20
20
 
21
21
 
22
22
  module Buildr
23
- module Idea #:nodoc:
23
+ module IntellijIdea
24
+ # Abstract base class for IdeaModule and IdeaProject
25
+ class IdeaFile
26
+ DEFAULT_SUFFIX = ""
27
+
28
+ attr_reader :buildr_project
29
+ attr_writer :suffix
30
+ attr_writer :id
31
+ attr_accessor :template
32
+
33
+ def suffix
34
+ @suffix ||= DEFAULT_SUFFIX
35
+ end
24
36
 
25
- include Extension
37
+ def filename
38
+ buildr_project.path_to("#{name}.#{extension}")
39
+ end
26
40
 
27
- first_time do
28
- # Global task "idea" generates artifacts for all projects.
29
- desc "Generate Idea artifacts for all projects"
30
- Project.local_task "idea"=>"artifacts"
31
- end
41
+ def id
42
+ @id ||= buildr_project.name.split(':').last
43
+ end
44
+
45
+ def add_component(name, attrs = {}, &xml)
46
+ self.components << create_component(name, attrs, &xml)
47
+ end
48
+
49
+ def write(f)
50
+ document.write f
51
+ end
52
+
53
+ protected
54
+
55
+ def name
56
+ "#{self.id}#{suffix}"
57
+ end
32
58
 
33
- before_define(:idea) do |project|
34
- project.recursive_task("idea")
59
+ def create_component(name, attrs = {})
60
+ target = StringIO.new
61
+ Builder::XmlMarkup.new(:target => target, :indent => 2).component(attrs.merge({:name => name})) do |xml|
62
+ yield xml if block_given?
63
+ end
64
+ REXML::Document.new(target.string).root
65
+ end
66
+
67
+ def components
68
+ @components ||= self.default_components.compact
69
+ end
70
+
71
+ def load_document(filename)
72
+ REXML::Document.new(File.read(filename))
73
+ end
74
+
75
+ def document
76
+ if File.exist?(self.filename)
77
+ doc = load_document(self.filename)
78
+ else
79
+ doc = base_document
80
+ inject_components(doc, self.initial_components)
81
+ end
82
+ if self.template
83
+ template_doc = load_document(self.template)
84
+ REXML::XPath.each(template_doc, "//component") do |element|
85
+ inject_component(doc, element)
86
+ end
87
+ end
88
+ inject_components(doc, self.components)
89
+ doc
90
+ end
91
+
92
+ def inject_components(doc, components)
93
+ components.each do |component|
94
+ # execute deferred components
95
+ component = component.call if Proc === component
96
+ inject_component(doc, component) if component
97
+ end
98
+ end
99
+
100
+ # replace overridden component (if any) with specified component
101
+ def inject_component(doc, component)
102
+ doc.root.delete_element("//component[@name='#{component.attributes['name']}']")
103
+ doc.root.add_element component
104
+ end
35
105
  end
36
106
 
37
- after_define(:idea => :package) do |project|
38
- idea = project.task("idea")
39
- # We need paths relative to the top project's base directory.
40
- root_path = lambda { |p| f = lambda { |p| p.parent ? f[p.parent] : p.base_dir }; f[p] }[project]
41
-
42
- # Find a path relative to the project's root directory.
43
- relative = lambda { |path| Util.relative_path(path.to_s, project.path_to) }
44
-
45
- m2repo = Buildr::Repositories.instance.local
46
- excludes = [ '**/.svn/', '**/CVS/' ].join('|')
47
-
48
- # Only for projects that are packageable.
49
- task_name = project.path_to("#{project.name.gsub(':', '-')}.iml")
50
- idea.enhance [ file(task_name) ]
51
-
52
- # The only thing we need to look for is a change in the Buildfile.
53
- file(task_name=>Buildr.application.buildfile) do |task|
54
- info "Writing #{task.name}"
55
-
56
- # Idea handles modules slightly differently if they're WARs
57
- idea_types = Hash.new("JAVA_MODULE")
58
- idea_types["war"] = "J2EE_WEB_MODULE"
59
-
60
- # Note: Use the test classpath since Eclipse compiles both "main" and "test" classes using the same classpath
61
- deps = project.test.compile.dependencies.map(&:to_s) - [ project.compile.target.to_s ]
62
-
63
- # Convert classpath elements into applicable Project objects
64
- deps.collect! { |path| Buildr.projects.detect { |prj| prj.packages.detect { |pkg| pkg.to_s == path } } || path }
65
-
66
- # project_libs: artifacts created by other projects
67
- project_libs, others = deps.partition { |path| path.is_a?(Project) }
68
-
69
- # Separate artifacts from Maven2 repository
70
- m2_libs, others = others.partition { |path| path.to_s.index(m2repo) == 0 }
71
-
72
- # Generated: classpath elements in the project are assumed to be generated
73
- generated, libs = others.partition { |path| path.to_s.index(project.path_to.to_s) == 0 }
74
-
75
- # Project type is going to be the first package type
76
- if package = project.packages.first
77
- File.open(task.name, "w") do |file|
78
- xml = Builder::XmlMarkup.new(:target=>file, :indent=>2)
79
-
80
- xml.module(:version=>"4", :relativePaths=>"false", :type=>idea_types[package.type.to_s]) do
81
- xml.component :name=>"ModuleRootManager"
82
- xml.component "name"=>"NewModuleRootManager", "inherit-compiler-output"=>"false" do
83
- has_compile_sources = project.compile.target.to_s.size > 0
84
- xml.output :url=>"file://$MODULE_DIR$/#{relative[project.compile.target.to_s]}" if has_compile_sources
85
- xml.tag! "exclude-output"
86
-
87
- # TODO project.test.target isn't recognized, what's the proper way to get the test compile path?
88
- xml.tag! "output-test", :url=>"file://$MODULE_DIR$/target/test-classes"
89
-
90
- xml.content(:url=>"file://$MODULE_DIR$") do
91
- if has_compile_sources
92
- srcs = project.compile.sources.map { |src| relative[src.to_s] } + generated.map { |src| relative[src.to_s] }
93
- srcs.sort.uniq.each do |path|
94
- xml.sourceFolder :url=>"file://$MODULE_DIR$/#{path}", :isTestSource=>"false"
95
- end
96
-
97
- test_sources = project.test.compile.sources.map { |src| relative[src.to_s] }
98
- test_sources.each do |paths|
99
- paths.sort.uniq.each do |path|
100
- xml.sourceFolder :url=>"file://$MODULE_DIR$/#{path}", :isTestSource=>"true"
101
- end
102
- end
103
- end
104
- [project.resources=>false, project.test.resources=>true].each do |resources, test|
105
- resources.each do |path|
106
- path[0].sources.each do |srcpath|
107
- xml.sourceFolder :url=>"file://#{srcpath}", :isTestSource=>path[1].to_s
108
- end
109
- end
110
- end
111
- xml.excludeFolder :url=>"file://$MODULE_DIR$/#{relative[project.compile.target.to_s]}" if has_compile_sources
112
- end
113
-
114
- xml.orderEntry :type=>"sourceFolder", :forTests=>"false"
115
- xml.orderEntry :type=>"inheritedJdk"
116
-
117
- # Classpath elements from other projects
118
- project_libs.map(&:id).sort.uniq.each do |project_id|
119
- xml.orderEntry :type=>'module', "module-name"=>project_id
120
- end
121
-
122
- # Libraries
123
- ext_libs = libs.map {|path| "$MODULE_DIR$/#{path.to_s}" } +
124
- m2_libs.map { |path| path.to_s.sub(m2repo, "$M2_REPO$") }
125
- ext_libs.each do |path|
126
- xml.orderEntry :type=>"module-library" do
127
- xml.library do
128
- xml.CLASSES do
129
- xml.root :url=>"jar://#{path}!/"
130
- end
131
- xml.JAVADOC
132
- xml.SOURCES do
133
- xml.root :url=>"jar://#{path.sub(/\.jar$/, "-sources.jar")}!/"
134
- end
135
- end
136
- end
137
- end
138
-
139
- xml.orderEntryProperties
107
+ # IdeaModule represents an .iml file
108
+ class IdeaModule < IdeaFile
109
+ DEFAULT_TYPE = "JAVA_MODULE"
110
+ DEFAULT_LOCAL_REPOSITORY_ENV_OVERRIDE = "MAVEN_REPOSITORY"
111
+
112
+ attr_accessor :type
113
+ attr_accessor :local_repository_env_override
114
+ attr_accessor :group
115
+ attr_reader :facets
116
+
117
+ def initialize
118
+ @type = DEFAULT_TYPE
119
+ @local_repository_env_override = DEFAULT_LOCAL_REPOSITORY_ENV_OVERRIDE
120
+ end
121
+
122
+ def buildr_project=(buildr_project)
123
+ @id = nil
124
+ @facets = []
125
+ @skip_content = false
126
+ @buildr_project = buildr_project
127
+ end
128
+
129
+ def extension
130
+ "iml"
131
+ end
132
+
133
+ def main_source_directories
134
+ @main_source_directories ||= [
135
+ buildr_project.compile.sources,
136
+ buildr_project.resources.sources
137
+ ].flatten.compact
138
+ end
139
+
140
+ def test_source_directories
141
+ @test_source_directories ||= [
142
+ buildr_project.test.compile.sources,
143
+ buildr_project.test.resources.sources
144
+ ].flatten.compact
145
+ end
146
+
147
+ def excluded_directories
148
+ @excluded_directories ||= [
149
+ buildr_project.resources.target,
150
+ buildr_project.test.resources.target,
151
+ buildr_project.path_to(:target, :main),
152
+ buildr_project.path_to(:target, :test),
153
+ buildr_project.path_to(:reports)
154
+ ].flatten.compact
155
+ end
156
+
157
+ attr_writer :main_output_dir
158
+
159
+ def main_output_dir
160
+ @main_output_dir ||= buildr_project._(:target, :main, :java)
161
+ end
162
+
163
+ attr_writer :test_output_dir
164
+
165
+ def test_output_dir
166
+ @test_output_dir ||= buildr_project._(:target, :test, :java)
167
+ end
168
+
169
+ def main_dependencies
170
+ @main_dependencies ||= buildr_project.compile.dependencies
171
+ end
172
+
173
+ def test_dependencies
174
+ @test_dependencies ||= buildr_project.test.compile.dependencies
175
+ end
176
+
177
+ def add_facet(name, type)
178
+ target = StringIO.new
179
+ Builder::XmlMarkup.new(:target => target, :indent => 2).facet(:name => name, :type => type) do |xml|
180
+ yield xml if block_given?
181
+ end
182
+ self.facets << REXML::Document.new(target.string).root
183
+ end
184
+
185
+ def skip_content?
186
+ !!@skip_content
187
+ end
188
+
189
+ def skip_content!
190
+ @skip_content = true
191
+ end
192
+
193
+ protected
194
+
195
+ def test_dependency_details
196
+ main_dependencies_paths = main_dependencies.map(&:to_s)
197
+ target_dir = buildr_project.compile.target.to_s
198
+ test_dependencies.select { |d| d.to_s != target_dir }.collect do |d|
199
+ dependency_path = d.to_s
200
+ export = main_dependencies_paths.include?(dependency_path)
201
+ source_path = nil
202
+ if d.respond_to?(:to_spec_hash)
203
+ source_spec = d.to_spec_hash.merge(:classifier => 'sources')
204
+ source_path = Buildr.artifact(source_spec).to_s
205
+ source_path = nil unless File.exist?(source_path)
206
+ end
207
+ [dependency_path, export, source_path]
208
+ end
209
+
210
+ end
211
+
212
+ def base_directory
213
+ buildr_project.path_to
214
+ end
215
+
216
+ def base_document
217
+ target = StringIO.new
218
+ Builder::XmlMarkup.new(:target => target).module(:version => "4", :relativePaths => "true", :type => self.type)
219
+ REXML::Document.new(target.string)
220
+ end
221
+
222
+ def initial_components
223
+ []
224
+ end
225
+
226
+ def default_components
227
+ [
228
+ lambda { module_root_component },
229
+ lambda { facet_component }
230
+ ]
231
+ end
232
+
233
+ def facet_component
234
+ return nil if self.facets.empty?
235
+ fm = self.create_component("FacetManager")
236
+ self.facets.each do |facet|
237
+ fm.add_element facet
238
+ end
239
+ fm
240
+ end
241
+
242
+ def module_root_component
243
+ create_component("NewModuleRootManager", "inherit-compiler-output" => "false") do |xml|
244
+ generate_compile_output(xml)
245
+ generate_content(xml) unless skip_content?
246
+ generate_initial_order_entries(xml)
247
+ project_dependencies = []
248
+
249
+ # Note: Use the test classpath since IDEA compiles both "main" and "test" classes using the same classpath
250
+ self.test_dependency_details.each do |dependency_path, export, source_path|
251
+ project_for_dependency = Buildr.projects.detect do |project|
252
+ [project.packages, project.compile.target, project.test.compile.target].flatten.
253
+ detect { |proj_art| proj_art.to_s == dependency_path }
254
+ end
255
+ if project_for_dependency
256
+ if project_for_dependency.iml? && !project_dependencies.include?(project_for_dependency)
257
+ generate_project_dependency(xml, project_for_dependency.iml.name, export)
140
258
  end
259
+ project_dependencies << project_for_dependency
260
+ next
261
+ else
262
+ generate_module_lib(xml, url_for_path(dependency_path), export, (source_path ? url_for_path(source_path) : nil))
263
+ end
264
+ end
265
+
266
+ xml.orderEntryProperties
267
+ end
268
+ end
269
+
270
+ def jar_path(path)
271
+ "jar://#{resolve_path(path)}!/"
272
+ end
273
+
274
+ def file_path(path)
275
+ "file://#{resolve_path(path)}"
276
+ end
277
+
278
+ def url_for_path(path)
279
+ if path =~ /jar$/i
280
+ jar_path(path)
281
+ else
282
+ file_path(path)
283
+ end
284
+ end
285
+
286
+ def resolve_path(path)
287
+ m2repo = Buildr::Repositories.instance.local
288
+ if path.to_s.index(m2repo) == 0 && !self.local_repository_env_override.nil?
289
+ return path.sub(m2repo, "$#{self.local_repository_env_override}$")
290
+ else
291
+ begin
292
+ return "$MODULE_DIR$/#{relative(path)}"
293
+ rescue ArgumentError
294
+ # ArgumentError happens on windows when self.base_directory and path are on different drives
295
+ return path
296
+ end
297
+ end
298
+ end
299
+
300
+ def relative(path)
301
+ ::Buildr::Util.relative_path(File.expand_path(path.to_s), self.base_directory)
302
+ end
303
+
304
+ def generate_compile_output(xml)
305
+ xml.output(:url => file_path(self.main_output_dir.to_s))
306
+ xml.tag!("output-test", :url => file_path(self.test_output_dir.to_s))
307
+ xml.tag!("exclude-output")
308
+ end
309
+
310
+ def generate_content(xml)
311
+ xml.content(:url => "file://$MODULE_DIR$") do
312
+ # Source folders
313
+ {
314
+ :main => self.main_source_directories,
315
+ :test => self.test_source_directories
316
+ }.each do |kind, directories|
317
+ directories.map { |dir| dir.to_s }.compact.sort.uniq.each do |dir|
318
+ xml.sourceFolder :url => file_path(dir), :isTestSource => (kind == :test ? 'true' : 'false')
141
319
  end
142
320
  end
321
+
322
+ # Exclude target directories
323
+ self.net_excluded_directories.
324
+ collect { |dir| file_path(dir) }.
325
+ select { |dir| relative_dir_inside_dir?(dir) }.
326
+ sort.each do |dir|
327
+ xml.excludeFolder :url => dir
328
+ end
143
329
  end
144
330
  end
145
331
 
146
- # Root project aggregates all the subprojects.
147
- if project.parent == nil
148
- task_name = project.path_to("#{project.name.gsub(':', '-')}.ipr")
149
- idea.enhance [ file(task_name) ]
332
+ def relative_dir_inside_dir?(dir)
333
+ !dir.include?("../")
334
+ end
335
+
336
+ def generate_initial_order_entries(xml)
337
+ xml.orderEntry :type => "sourceFolder", :forTests => "false"
338
+ xml.orderEntry :type => "inheritedJdk"
339
+ end
150
340
 
151
- file(task_name=>Buildr.application.buildfile) do |task|
152
- info "Writing #{task.name}"
341
+ def generate_project_dependency(xml, other_project, export = true)
342
+ attribs = {:type => 'module', "module-name" => other_project}
343
+ attribs[:exported] = '' if export
344
+ xml.orderEntry attribs
345
+ end
153
346
 
154
- # Generating just the little stanza that chanages from one project to another
155
- partial = StringIO.new
156
- xml = Builder::XmlMarkup.new(:target=>partial, :indent=>2)
157
- xml.component(:name=>"ProjectModuleManager") do
158
- xml.modules do
159
- project.projects.each do |subp|
160
- module_name = subp.name.gsub(":", "-")
161
- module_path = subp.name.split(":"); module_path.shift
162
- module_path = module_path.join("/")
163
- path = "#{module_path}/#{module_name}.iml"
164
- xml.module :fileurl=>"file://$PROJECT_DIR$/#{path}", :filepath=>"$PROJECT_DIR$/#{path}"
347
+ def generate_module_lib(xml, path, export, source_path)
348
+ attribs = {:type => 'module-library'}
349
+ attribs[:exported] = '' if export
350
+ xml.orderEntry attribs do
351
+ xml.library do
352
+ xml.CLASSES do
353
+ xml.root :url => path
354
+ end
355
+ xml.JAVADOC
356
+ xml.SOURCES do
357
+ if source_path
358
+ xml.root :url => source_path
165
359
  end
166
- if package = project.packages.first
167
- xml.module :fileurl=>"file://$PROJECT_DIR$/#{project.name}.iml", :filepath=>"$PROJECT_DIR$/#{project.name}.iml"
360
+ end
361
+ end
362
+ end
363
+ end
364
+
365
+ # Don't exclude things that are subdirectories of other excluded things
366
+ def net_excluded_directories
367
+ net = []
368
+ all = self.excluded_directories.map { |dir| buildr_project._(dir.to_s) }.sort_by { |d| d.size }
369
+ all.each_with_index do |dir, i|
370
+ unless all[0 ... i].find { |other| dir =~ /^#{other}/ }
371
+ net << dir
372
+ end
373
+ end
374
+ net
375
+ end
376
+ end
377
+
378
+ # IdeaModule represents an .ipr file
379
+ class IdeaProject < IdeaFile
380
+ attr_accessor :vcs
381
+ attr_accessor :extra_modules
382
+ attr_writer :jdk_version
383
+
384
+ def initialize(buildr_project)
385
+ @buildr_project = buildr_project
386
+ @vcs = detect_vcs
387
+ @extra_modules = []
388
+ end
389
+
390
+ def jdk_version
391
+ @jdk_version ||= buildr_project.compile.options.source || "1.6"
392
+ end
393
+
394
+ protected
395
+
396
+ def extension
397
+ "ipr"
398
+ end
399
+
400
+ def detect_vcs
401
+ if File.directory?(buildr_project._('.svn'))
402
+ "svn"
403
+ elsif File.directory?(buildr_project._('.git'))
404
+ "Git"
405
+ end
406
+ end
407
+
408
+ def base_document
409
+ target = StringIO.new
410
+ Builder::XmlMarkup.new(:target => target).project(:version => "4", :relativePaths => "false")
411
+ REXML::Document.new(target.string)
412
+ end
413
+
414
+ def default_components
415
+ [
416
+ lambda { modules_component },
417
+ vcs_component
418
+ ]
419
+ end
420
+
421
+ def initial_components
422
+ [
423
+ lambda { project_root_manager_component },
424
+ lambda { project_details_component }
425
+ ]
426
+ end
427
+
428
+ def project_root_manager_component
429
+ attribs = {"version" => "2",
430
+ "assert-keyword" => "true",
431
+ "jdk-15" => "true",
432
+ "project-jdk-name" => self.jdk_version,
433
+ "project-jdk-type" => "JavaSDK",
434
+ "languageLevel" => "JDK_#{self.jdk_version.gsub('.', '_')}"}
435
+ create_component("ProjectRootManager", attribs) do |xml|
436
+ xml.output("url" => "file://$PROJECT_DIR$/out")
437
+ end
438
+ end
439
+
440
+ def project_details_component
441
+ create_component("ProjectDetails") do |xml|
442
+ xml.option("name" => "projectName", "value" => self.name)
443
+ end
444
+ end
445
+
446
+ def modules_component
447
+ create_component("ProjectModuleManager") do |xml|
448
+ xml.modules do
449
+ buildr_project.projects.select { |subp| subp.iml? }.each do |subproject|
450
+ module_path = subproject.base_dir.gsub(/^#{buildr_project.base_dir}\//, '')
451
+ path = "#{module_path}/#{subproject.iml.name}.iml"
452
+ attribs = {:fileurl => "file://$PROJECT_DIR$/#{path}", :filepath => "$PROJECT_DIR$/#{path}"}
453
+ if subproject.iml.group == true
454
+ attribs[:group] = subproject.parent.name.gsub(':', '/')
455
+ elsif !subproject.iml.group.nil?
456
+ attribs[:group] = subproject.group.to_s
168
457
  end
458
+ xml.module attribs
459
+ end
460
+ self.extra_modules.each do |iml_file|
461
+ xml.module :fileurl => "file://$PROJECT_DIR$/#{iml_file}",
462
+ :filepath => "$PROJECT_DIR$/#{iml_file}"
463
+ end
464
+ if buildr_project.iml?
465
+ xml.module :fileurl => "file://$PROJECT_DIR$/#{buildr_project.iml.name}.iml",
466
+ :filepath => "$PROJECT_DIR$/#{buildr_project.iml.name}.iml"
467
+ end
468
+ end
469
+ end
470
+ end
471
+
472
+ def vcs_component
473
+ if vcs
474
+ create_component("VcsDirectoryMappings") do |xml|
475
+ xml.mapping :directory => "", :vcs => vcs
476
+ end
477
+ end
478
+ end
479
+ end
480
+
481
+ module ProjectExtension
482
+ include Extension
483
+
484
+ first_time do
485
+ desc "Generate Intellij IDEA artifacts for all projects"
486
+ Project.local_task "idea:generate" => "artifacts"
487
+
488
+ desc "Delete the generated Intellij IDEA artifacts"
489
+ Project.local_task "idea:clean"
490
+ end
491
+
492
+ before_define do |project|
493
+ project.recursive_task("idea:generate")
494
+ project.recursive_task("idea:clean")
495
+ end
496
+
497
+ after_define do |project|
498
+ idea = project.task("idea:generate")
499
+
500
+ files = [
501
+ (project.iml if project.iml?),
502
+ (project.ipr if project.ipr?)
503
+ ].compact
504
+
505
+ files.each do |ideafile|
506
+ module_dir = File.dirname(ideafile.filename)
507
+ # Need to clear the actions else the extension included as part of buildr will run
508
+ file(ideafile.filename).clear_actions
509
+ idea.enhance [file(ideafile.filename)]
510
+ file(ideafile.filename => [Buildr.application.buildfile]) do |task|
511
+ mkdir_p module_dir
512
+ info "Writing #{task.name}"
513
+ t = Tempfile.open("buildr-idea")
514
+ temp_filename = t.path
515
+ t.close!
516
+ File.open(temp_filename, "w") do |f|
517
+ ideafile.write f
169
518
  end
519
+ mv temp_filename, ideafile.filename
170
520
  end
521
+ end
171
522
 
172
- # Loading the whole fairly constant crap
173
- template_xml = REXML::Document.new(File.open(File.dirname(__FILE__)+"/idea.ipr.template"))
174
- include_xml = REXML::Document.new(partial.string)
175
- template_xml.root.add_element(include_xml.root)
176
- File.open task.name, 'w' do |file|
177
- template_xml.write file
523
+ project.task("idea:clean") do
524
+ files.each do |f|
525
+ info "Removing #{f.filename}" if File.exist?(f.filename)
526
+ rm_rf f.filename
178
527
  end
179
528
  end
180
529
  end
181
530
 
182
- end #after define
531
+ def ipr
532
+ if ipr?
533
+ @ipr ||= IdeaProject.new(self)
534
+ else
535
+ raise "Only the root project has an IPR"
536
+ end
537
+ end
183
538
 
184
- end #module Idea
185
- end # module Buildr
539
+ def ipr?
540
+ !@no_ipr && self.parent.nil?
541
+ end
186
542
 
543
+ def iml
544
+ if iml?
545
+ unless @iml
546
+ inheritable_iml_source = self.parent
547
+ while inheritable_iml_source && !inheritable_iml_source.iml?
548
+ inheritable_iml_source = inheritable_iml_source.parent;
549
+ end
550
+ @iml = inheritable_iml_source ? inheritable_iml_source.iml.clone : IdeaModule.new
551
+ @iml.buildr_project = self
552
+ end
553
+ return @iml
554
+ else
555
+ raise "IML generation is disabled for #{self.name}"
556
+ end
557
+ end
558
+
559
+ def no_ipr
560
+ @no_ipr = true
561
+ end
562
+
563
+ def no_iml
564
+ @has_iml = false
565
+ end
566
+
567
+ def iml?
568
+ @has_iml = @has_iml.nil? ? true : @has_iml
569
+ end
570
+ end
571
+ end
572
+ end
187
573
 
188
574
  class Buildr::Project
189
- include Buildr::Idea
575
+ include Buildr::IntellijIdea::ProjectExtension
190
576
  end