buildr 1.3.0-java

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 (138) hide show
  1. data/CHANGELOG +780 -0
  2. data/DISCLAIMER +7 -0
  3. data/KEYS +151 -0
  4. data/LICENSE +176 -0
  5. data/NOTICE +31 -0
  6. data/README +173 -0
  7. data/Rakefile +63 -0
  8. data/addon/buildr/antlr.rb +65 -0
  9. data/addon/buildr/cobertura.rb +232 -0
  10. data/addon/buildr/hibernate.rb +142 -0
  11. data/addon/buildr/javacc.rb +85 -0
  12. data/addon/buildr/jdepend.rb +60 -0
  13. data/addon/buildr/jetty.rb +248 -0
  14. data/addon/buildr/nailgun.rb +892 -0
  15. data/addon/buildr/openjpa.rb +90 -0
  16. data/addon/buildr/org/apache/buildr/JettyWrapper$1.class +0 -0
  17. data/addon/buildr/org/apache/buildr/JettyWrapper$BuildrHandler.class +0 -0
  18. data/addon/buildr/org/apache/buildr/JettyWrapper.class +0 -0
  19. data/addon/buildr/org/apache/buildr/JettyWrapper.java +144 -0
  20. data/addon/buildr/xmlbeans.rb +93 -0
  21. data/bin/buildr +21 -0
  22. data/buildr.gemspec +50 -0
  23. data/doc/css/default.css +225 -0
  24. data/doc/css/print.css +95 -0
  25. data/doc/css/syntax.css +43 -0
  26. data/doc/images/apache-incubator-logo.png +0 -0
  27. data/doc/images/buildr-hires.png +0 -0
  28. data/doc/images/buildr.png +0 -0
  29. data/doc/images/note.png +0 -0
  30. data/doc/images/tip.png +0 -0
  31. data/doc/images/zbuildr.tif +0 -0
  32. data/doc/pages/artifacts.textile +317 -0
  33. data/doc/pages/building.textile +501 -0
  34. data/doc/pages/contributing.textile +178 -0
  35. data/doc/pages/download.textile +25 -0
  36. data/doc/pages/extending.textile +229 -0
  37. data/doc/pages/getting_started.textile +337 -0
  38. data/doc/pages/index.textile +63 -0
  39. data/doc/pages/mailing_lists.textile +17 -0
  40. data/doc/pages/more_stuff.textile +367 -0
  41. data/doc/pages/packaging.textile +592 -0
  42. data/doc/pages/projects.textile +449 -0
  43. data/doc/pages/recipes.textile +127 -0
  44. data/doc/pages/settings_profiles.textile +339 -0
  45. data/doc/pages/testing.textile +475 -0
  46. data/doc/pages/troubleshooting.textile +121 -0
  47. data/doc/pages/whats_new.textile +389 -0
  48. data/doc/print.haml +52 -0
  49. data/doc/print.toc.yaml +28 -0
  50. data/doc/scripts/buildr-git.rb +411 -0
  51. data/doc/scripts/install-jruby.sh +44 -0
  52. data/doc/scripts/install-linux.sh +64 -0
  53. data/doc/scripts/install-osx.sh +52 -0
  54. data/doc/site.haml +55 -0
  55. data/doc/site.toc.yaml +44 -0
  56. data/lib/buildr.rb +47 -0
  57. data/lib/buildr/core.rb +27 -0
  58. data/lib/buildr/core/application.rb +373 -0
  59. data/lib/buildr/core/application_cli.rb +134 -0
  60. data/lib/buildr/core/build.rb +262 -0
  61. data/lib/buildr/core/checks.rb +382 -0
  62. data/lib/buildr/core/common.rb +155 -0
  63. data/lib/buildr/core/compile.rb +594 -0
  64. data/lib/buildr/core/environment.rb +120 -0
  65. data/lib/buildr/core/filter.rb +258 -0
  66. data/lib/buildr/core/generate.rb +195 -0
  67. data/lib/buildr/core/help.rb +118 -0
  68. data/lib/buildr/core/progressbar.rb +156 -0
  69. data/lib/buildr/core/project.rb +890 -0
  70. data/lib/buildr/core/test.rb +690 -0
  71. data/lib/buildr/core/transports.rb +486 -0
  72. data/lib/buildr/core/util.rb +235 -0
  73. data/lib/buildr/ide.rb +19 -0
  74. data/lib/buildr/ide/eclipse.rb +181 -0
  75. data/lib/buildr/ide/idea.ipr.template +300 -0
  76. data/lib/buildr/ide/idea.rb +194 -0
  77. data/lib/buildr/ide/idea7x.ipr.template +290 -0
  78. data/lib/buildr/ide/idea7x.rb +210 -0
  79. data/lib/buildr/java.rb +26 -0
  80. data/lib/buildr/java/ant.rb +71 -0
  81. data/lib/buildr/java/bdd_frameworks.rb +267 -0
  82. data/lib/buildr/java/commands.rb +210 -0
  83. data/lib/buildr/java/compilers.rb +432 -0
  84. data/lib/buildr/java/deprecated.rb +141 -0
  85. data/lib/buildr/java/groovyc.rb +137 -0
  86. data/lib/buildr/java/jruby.rb +99 -0
  87. data/lib/buildr/java/org/apache/buildr/BuildrNail$Main.class +0 -0
  88. data/lib/buildr/java/org/apache/buildr/BuildrNail.class +0 -0
  89. data/lib/buildr/java/org/apache/buildr/BuildrNail.java +41 -0
  90. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.class +0 -0
  91. data/lib/buildr/java/org/apache/buildr/JavaTestFilter.java +116 -0
  92. data/lib/buildr/java/packaging.rb +706 -0
  93. data/lib/buildr/java/pom.rb +178 -0
  94. data/lib/buildr/java/rjb.rb +142 -0
  95. data/lib/buildr/java/test_frameworks.rb +290 -0
  96. data/lib/buildr/java/version_requirement.rb +172 -0
  97. data/lib/buildr/packaging.rb +21 -0
  98. data/lib/buildr/packaging/artifact.rb +729 -0
  99. data/lib/buildr/packaging/artifact_namespace.rb +957 -0
  100. data/lib/buildr/packaging/artifact_search.rb +140 -0
  101. data/lib/buildr/packaging/gems.rb +102 -0
  102. data/lib/buildr/packaging/package.rb +233 -0
  103. data/lib/buildr/packaging/tar.rb +104 -0
  104. data/lib/buildr/packaging/zip.rb +719 -0
  105. data/rakelib/apache.rake +126 -0
  106. data/rakelib/changelog.rake +56 -0
  107. data/rakelib/doc.rake +103 -0
  108. data/rakelib/package.rake +44 -0
  109. data/rakelib/release.rake +53 -0
  110. data/rakelib/rspec.rake +81 -0
  111. data/rakelib/rubyforge.rake +45 -0
  112. data/rakelib/scm.rake +49 -0
  113. data/rakelib/setup.rake +59 -0
  114. data/rakelib/stage.rake +45 -0
  115. data/spec/application_spec.rb +316 -0
  116. data/spec/archive_spec.rb +494 -0
  117. data/spec/artifact_namespace_spec.rb +635 -0
  118. data/spec/artifact_spec.rb +738 -0
  119. data/spec/build_spec.rb +193 -0
  120. data/spec/checks_spec.rb +537 -0
  121. data/spec/common_spec.rb +579 -0
  122. data/spec/compile_spec.rb +561 -0
  123. data/spec/groovy_compilers_spec.rb +239 -0
  124. data/spec/java_bdd_frameworks_spec.rb +238 -0
  125. data/spec/java_compilers_spec.rb +446 -0
  126. data/spec/java_packaging_spec.rb +1042 -0
  127. data/spec/java_test_frameworks_spec.rb +414 -0
  128. data/spec/packaging_helper.rb +63 -0
  129. data/spec/packaging_spec.rb +589 -0
  130. data/spec/project_spec.rb +739 -0
  131. data/spec/sandbox.rb +116 -0
  132. data/spec/scala_compilers_spec.rb +239 -0
  133. data/spec/spec.opts +6 -0
  134. data/spec/spec_helpers.rb +283 -0
  135. data/spec/test_spec.rb +871 -0
  136. data/spec/transport_spec.rb +300 -0
  137. data/spec/version_requirement_spec.rb +115 -0
  138. metadata +324 -0
@@ -0,0 +1,85 @@
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/java'
18
+
19
+
20
+ module Buildr
21
+ # Provides JavaCC compile tasks. Require explicitly using <code>require "buildr/javacc"</code>.
22
+ module JavaCC
23
+
24
+ REQUIRES = [ "net.java.dev.javacc:javacc:jar:4.0", "net.java.dev.javacc:javacc:jar:4.0" ]
25
+
26
+ Java.classpath << REQUIRES
27
+
28
+ class << self
29
+
30
+ def javacc(*args)
31
+ options = Hash === args.last ? args.pop : {}
32
+ rake_check_options options, :output
33
+
34
+ args = args.flatten.map(&:to_s).collect { |f| File.directory?(f) ? FileList[f + "/**/*.jj"] : f }.flatten
35
+ args.unshift "-OUTPUT_DIRECTORY=#{options[:output]}" if options[:output]
36
+ Java.load
37
+ Java.org.javacc.parser.Main.mainProgram(args.to_java(Java.java.lang.String)) == 0 or
38
+ fail "Failed to run JavaCC, see errors above."
39
+ end
40
+
41
+ def jjtree(*args)
42
+ options = Hash === args.last ? args.pop : {}
43
+ rake_check_options options, :output, :build_node_files
44
+
45
+ args = args.flatten.map(&:to_s).collect { |f| File.directory?(f) ? FileList[f + "**/*.jjt"] : f }.flatten
46
+ args.unshift "-OUTPUT_DIRECTORY=#{options[:output]}" if options[:output]
47
+ args.unshift "-BUILD_NODE_FILES=#{options[:build_node_files] || false}"
48
+ Java.load
49
+ Java.org.javacc.jjtree.JJTree.new.main(args.to_java(Java.java.lang.String)) == 0 or
50
+ fail "Failed to run JJTree, see errors above."
51
+ end
52
+
53
+ end
54
+
55
+ def javacc(*args)
56
+ if Hash === args.last
57
+ options = args.pop
58
+ in_package = options[:in_package].split(".")
59
+ else
60
+ in_package = []
61
+ end
62
+ file(path_to(:target, :generated, :javacc)=>args.flatten) do |task|
63
+ JavaCC.javacc task.prerequisites, :output=>File.join(task.name, in_package)
64
+ end
65
+ end
66
+
67
+ def jjtree(*args)
68
+ if Hash === args.last
69
+ options = args.pop
70
+ in_package = options[:in_package].split(".")
71
+ build_node_files = options[:build_node_files]
72
+ else
73
+ in_package = []
74
+ end
75
+ file(path_to(:target, :generated, :jjtree)=>args.flatten) do |task|
76
+ JavaCC.jjtree task.prerequisites, :output=>File.join(task.name, in_package), :build_node_files=>build_node_files
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ class Project
83
+ include JavaCC
84
+ end
85
+ end
@@ -0,0 +1,60 @@
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/java'
18
+
19
+
20
+ module Buildr
21
+
22
+ # Addes the <code>jdepend:swing</code>, <code>jdepend:text</code> and <code>jdepend:xml</code> tasks.
23
+ # Require explicitly using <code>require "buildr/jdepend"</code>.
24
+ module Jdepend
25
+
26
+ REQUIRES = ["jdepend:jdepend:jar:2.9.1"]
27
+
28
+ class << self
29
+
30
+ def requires()
31
+ @requires ||= Buildr.artifacts(REQUIRES).each(&:invoke).map(&:to_s)
32
+ end
33
+
34
+ def paths()
35
+ Project.projects.map(&:compile).each(&:invoke).map(&:target).
36
+ map(&:to_s).select { |path| File.exist?(path) }.map { |path| File.expand_path(path) }
37
+ end
38
+
39
+ end
40
+
41
+ namespace "jdepend" do
42
+
43
+ desc "Runs JDepend on all your projects (Swing UI)"
44
+ task "swing" do
45
+ Java::Commands.java "jdepend.swingui.JDepend", paths, :classpath=>requires, :name=>"JDepend"
46
+ end
47
+
48
+ desc "Runs JDepend on all your projects (Text UI)"
49
+ task "text" do
50
+ Java::Commands.java "jdepend.textui.JDepend", paths, :classpath=>requires, :name=>"JDepend"
51
+ end
52
+
53
+ desc "Runs JDepend on all your projects (XML output to jdepend.xml)"
54
+ task "xml" do
55
+ Java::Commands.java "jdepend.xmlui.JDepend", "-file", "jdepend.xml", paths, :classpath=>requires, :name=>"JDepend"
56
+ puts "Created jdepend.xml"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,248 @@
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 'uri'
18
+ require 'net/http'
19
+ require 'buildr/core/project'
20
+ require 'buildr/java'
21
+ require 'buildr/packaging'
22
+ require 'thread'
23
+
24
+
25
+ module Buildr
26
+
27
+ # Provides a collection of tasks and methods for using Jetty, specifically as a server
28
+ # for testing your application.
29
+ #
30
+ # Build files should always start Jetty by invoking the #use task, typically as
31
+ # a prerequisite. This task will start Jetty once during the build, and shut it down
32
+ # when the build completes.
33
+ #
34
+ # If you want to keep Jetty running across builds, and look at error messages, you can
35
+ # start Jetty in a separate console with:
36
+ # buildr jetty:start
37
+ # To stop this instance of Jetty, simply kill the process (Ctrl-C) or run:
38
+ # buildr jetty:stop
39
+ #
40
+ # If you start Jetty separately from the build, the #use task will connect to that
41
+ # existing server. Since you are using Jetty across several builds, you will want to
42
+ # cleanup any mess created by each build. You can use the #setup and #teardown tasks,
43
+ # which are called when Jetty is first used in the build, and when the build ends.
44
+ class Jetty
45
+
46
+ # Which version of Jetty we're using by default (change with options.jetty.version).
47
+ VERSION = "6.1.3" unless const_defined?('VERSION')
48
+ SLF4J_VERSION = "1.4.3"
49
+
50
+ # Libraries used by Jetty.
51
+ REQUIRES = [ "org.mortbay.jetty:jetty:jar:#{VERSION}", "org.mortbay.jetty:jetty-util:jar:#{VERSION}",
52
+ "org.mortbay.jetty:servlet-api-2.5:jar:#{VERSION}", "org.slf4j:slf4j-api:jar:#{SLF4J_VERSION}",
53
+ "org.slf4j:slf4j-simple:jar:#{SLF4J_VERSION}", "org.slf4j:jcl104-over-slf4j:jar:#{SLF4J_VERSION}" ]
54
+
55
+ Java.classpath << REQUIRES
56
+ Java.classpath << File.dirname(__FILE__)
57
+
58
+ # Default URL for Jetty (change with options.jetty.url).
59
+ URL = "http://localhost:8080"
60
+
61
+ class << self
62
+
63
+ # :call-seq:
64
+ # instance() => Jetty
65
+ #
66
+ # Returns an instance of Jetty.
67
+ def instance()
68
+ @instance ||= Jetty.new("jetty", URL)
69
+ end
70
+
71
+ end
72
+
73
+ def initialize(name, url) #:nodoc:
74
+ @url = url
75
+ namespace name do
76
+ @setup = task("setup")
77
+ @teardown = task("teardown")
78
+ @use = task("use") { fire }
79
+ end
80
+ end
81
+
82
+ # The URL for the Jetty server. Leave as is if you want to use the default server
83
+ # (http://localhost:8080).
84
+ attr_accessor :url
85
+
86
+ # :call-seq:
87
+ # start(pipe?)
88
+ #
89
+ # Starts Jetty. This method does not return, it keeps the thread running until
90
+ # Jetty is stopped. If you want to run Jetty parallel with other tasks in the build,
91
+ # invoke the #use task instead.
92
+ def start(sync = nil)
93
+ begin
94
+ puts "classpath #{Java.classpath.inspect}"
95
+ port = URI.parse(url).port
96
+ puts "Starting Jetty at http://localhost:#{port}" if verbose
97
+ Java.load
98
+ jetty = Java.org.apache.buildr.JettyWrapper.new(port)
99
+ sync << "Started" if sync
100
+ sleep # Forever
101
+ rescue Interrupt # Stopped from console
102
+ rescue Exception=>error
103
+ puts "#{error.class}: #{error.message}"
104
+ end
105
+ exit! # No at_exit
106
+ end
107
+
108
+ # :call-seq:
109
+ # stop()
110
+ #
111
+ # Stops Jetty. Stops a server running in a separate process.
112
+ def stop()
113
+ uri = URI.parse(url)
114
+ begin
115
+ Net::HTTP.start(uri.host, uri.port) do |http|
116
+ http.request_post "/buildr/stop", ""
117
+ end
118
+ rescue Errno::ECONNREFUSED
119
+ # Expected if Jetty server not running.
120
+ rescue EOFError
121
+ # We get EOFError because Jetty is brutally killed.
122
+ end
123
+ puts "Jetty server stopped"
124
+ end
125
+
126
+ # :call-seq:
127
+ # running?() => boolean
128
+ #
129
+ # Returns true if it finds a running Jetty server that supports the Buildr
130
+ # requests for deploying, stopping, etc.
131
+ def running?()
132
+ uri = URI.parse(url)
133
+ begin
134
+ Net::HTTP.start(uri.host, uri.port) do |http|
135
+ response = http.request_get("/buildr/")
136
+ response.is_a?(Net::HTTPSuccess) && response.body =~ /Alive/
137
+ end
138
+ rescue Errno::ECONNREFUSED, Errno::EBADF
139
+ false
140
+ end
141
+ end
142
+
143
+ # :call-seq:
144
+ # deploy(url, webapp) => path
145
+ #
146
+ # Deploy a WAR in the specified URL.
147
+ def deploy(url, webapp)
148
+ use.invoke
149
+ uri = URI.parse(url)
150
+ Net::HTTP.start(uri.host, uri.port) do |http|
151
+ response = http.request_post("/buildr/deploy", "webapp=#{webapp}&path=#{uri.path}")
152
+ if Net::HTTPOK === response && response.body =~ /Deployed/
153
+ path = response.body.split[1]
154
+ puts "Deployed #{webapp}, context path #{uri.path}" if Rake.application.options.trace
155
+ path
156
+ else
157
+ fail "Deployment failed: #{response}"
158
+ end
159
+ end
160
+ end
161
+
162
+ # :call-seq:
163
+ # undeploy(url) => boolean
164
+ #
165
+ # Undeploys a WAR from the specified URL.
166
+ def undeploy(url)
167
+ use.invoke
168
+ uri = URI.parse(url)
169
+ Net::HTTP.start(uri.host, uri.port) do |http|
170
+ response = http.request_post("/buildr/undeploy", "path=#{uri.path}")
171
+ if Net::HTTPOK === response && response.body =~ /Undeployed/
172
+ true
173
+ else
174
+ fail "Deployment failed: #{response}"
175
+ end
176
+ end
177
+ end
178
+
179
+ # :call-seq:
180
+ # setup(*prereqs) => task
181
+ # setup(*prereqs) { |task| .. } => task
182
+ #
183
+ # This task executes when Jetty is first used in the build. You can use it to
184
+ # deploy artifacts into Jetty.
185
+ def setup(*prereqs, &block)
186
+ @setup.enhance prereqs, &block
187
+ end
188
+
189
+ # :call-seq:
190
+ # teardown(*prereqs) => task
191
+ # teardown(*prereqs) { |task| .. } => task
192
+ #
193
+ # This task executes when the build is done. You can use it to undeploy artifacts
194
+ # previously deployed into Jetty.
195
+ def teardown(*prereqs, &block)
196
+ @teardown.enhance prereqs, &block
197
+ end
198
+
199
+ # :call-seq:
200
+ # use(*prereqs) => task
201
+ # use(*prereqs) { |task| .. } => task
202
+ #
203
+ # If you intend to use Jetty, invoke this task. It will start a new instance of
204
+ # Jetty and close it when the build is done. However, if you already have a server
205
+ # running in the background (e.g. jetty:start), it will use that server and will
206
+ # not close it down.
207
+ def use(*prereqs, &block)
208
+ @use.enhance prereqs, &block
209
+ end
210
+
211
+ protected
212
+
213
+ # If you want to start Jetty inside the build, call this method instead of #start.
214
+ # It will spawn a separate process that will run Jetty, and will stop Jetty when
215
+ # the build ends. However, if you already started Jetty from the console (with
216
+ # take jetty:start), it will use the existing instance without shutting it down.
217
+ def fire()
218
+ unless running?
219
+ sync = Queue.new
220
+ Thread.new { start sync }
221
+ # Wait for Jetty to fire up before doing anything else.
222
+ sync.pop == "Started" or fail "Jetty not started"
223
+ puts "Jetty started" if verbose
224
+ at_exit { stop }
225
+ end
226
+ @setup.invoke
227
+ at_exit { @teardown.invoke }
228
+ end
229
+
230
+ end
231
+
232
+ namespace "jetty" do
233
+ desc "Start an instance of Jetty running in the background"
234
+ task("start") { Jetty.instance.start }
235
+ desc "Stop an instance of Jetty running in the background"
236
+ task("stop") { Jetty.instance.stop }
237
+ end
238
+
239
+ # :call-seq:
240
+ # jetty() => Jetty
241
+ #
242
+ # Returns a Jetty object. You can use this to discover the Jetty#use task,
243
+ # configure the Jetty#setup and Jetty#teardown tasks, deploy and undeploy to Jetty.
244
+ def jetty()
245
+ @jetty ||= Jetty.instance
246
+ end
247
+
248
+ end
@@ -0,0 +1,892 @@
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 'benchmark'
18
+ require 'jruby'
19
+ require 'monitor'
20
+ require 'ostruct'
21
+ require 'rbconfig'
22
+ require 'thread'
23
+ require 'buildr/core/application_cli'
24
+
25
+ module Buildr
26
+
27
+ # See the nailgun_help method for documentation.
28
+ module Nailgun # :nodoc:
29
+ extend self
30
+
31
+ VERSION = '0.7.1'
32
+ NAME = "nailgun-#{VERSION}"
33
+ URL = "http://downloads.sourceforge.net/nailgun/#{NAME}.zip"
34
+ ARTIFACT_SPEC = "com.martiansoftware:nailgun:jar:#{VERSION}"
35
+ BUILDR_PATHS = [File.expand_path('../', File.dirname(__FILE__)),
36
+ File.expand_path('../../lib', File.dirname(__FILE__))]
37
+
38
+ attr_accessor :artifact
39
+ attr_accessor :server, :port, :jruby_queue_size, :buildr_queue_size
40
+ attr_accessor :jruby_home, :home
41
+
42
+ self.jruby_home = if PLATFORM =~ /java/
43
+ Config::CONFIG['prefix']
44
+ else
45
+ ENV['JRUBY_HOME'] || File.join(ENV['HOME'], '.jruby')
46
+ end
47
+
48
+ self.home = ENV['NAILGUN_HOME'] || File.join(jruby_home, 'tool', 'nailgun')
49
+ self.server = 'localhost'
50
+ self.port = 2113
51
+ self.jruby_queue_size = 3
52
+ self.buildr_queue_size = 3
53
+
54
+ def namespace(&block)
55
+ if Object.const_defined?(:Rake)
56
+ Rake.application.in_namespace(:nailgun, &block)
57
+ end
58
+ end
59
+
60
+ def boot(&block)
61
+ if block
62
+ @boot = block
63
+ else
64
+ @boot.call
65
+ end
66
+ end
67
+
68
+ module Application
69
+ def nailgun_help
70
+ " " + <<-DESC.strip.gsub(/ *\n +/, "\n ")
71
+ NailGun is a client, protocol, and server for running Java
72
+ programs from the command line without incurring the JVM
73
+ startup overhead. Nailgun integration is currently available
74
+ only when running Buildr with JRuby.
75
+
76
+ Buildr provides a custom nailgun server, allowing you to
77
+ start a single JVM and let buildr create a queue of runtimes.
78
+ These JRuby runtimes can be cached (indexed by buildfile path)
79
+ and are automatically reloaded when the buildfile has been modified.
80
+ Runtime caching allows you to execute tasks without
81
+ spending time creating the buildr environment. Some nailgun
82
+ tasks have been provided to manage the cached runtimes.
83
+
84
+ To start the buildr server execute the following task:
85
+
86
+ nailgun:start
87
+
88
+ Server output will display a message when it becomes ready, you
89
+ will also see messages when the JRuby runtimes are being created,
90
+ or when a new buildr environment is being loaded on them.
91
+ After the runtime queues have been populated, you can start calling
92
+ buildr as you normally do, by invoking the $NAILGUN_HOME/ng binary:
93
+
94
+ # on another terminal, change directory to a project.
95
+ # if this project is the same nailgun:start was invoked on, it's
96
+ # runtime has been cached, so no loading is performed unless
97
+ # the buildfile has been modified. otherwise the buildfile
98
+ # will be loaded on a previously loaded fresh-buildr runtime
99
+ # and it will be cached.
100
+ cd /some/buildr/project
101
+ ng nailgun:help # display nailgun help
102
+ ng nailgun:tasks # display overview of ng tasks
103
+ ng clean compile # just invoke those two tasks
104
+
105
+ Configuration and Environment Variables.
106
+
107
+ Before starting the server, buildr will check if you have
108
+ nailgun already installed by seeking the nailgun jar under
109
+
110
+ $NAILGUN_HOME
111
+
112
+ You can override this environment variable to tell buildr where
113
+ to find or where to install nailgun. If missing, NAILGUN_HOME
114
+ defaults to the $JRUBY_HOME/tool/nailgun directory. You can
115
+ also specify the nailgun_home on your buildfile with the following
116
+ code:
117
+
118
+ require 'buildr/nailgun'
119
+ Buildr::Nailgun.home = File.expand_path('~/.jruby/tool/nailgun')
120
+
121
+ Buildr will also check that the nailgun client binary (ng.exe for
122
+ Windows systems, ng otherwise) is installed on NAILGUN_HOME.
123
+ If no binary is found, buildr will download nailgun and
124
+ compile+install it.
125
+
126
+
127
+ The buildr server binds itself to localhost, port 2113. You can
128
+ override this on your buildfile, by placing the following code:
129
+
130
+ require 'buildr/nailgun'
131
+ Buildr::Nailgun.server = '127.0.0.1'
132
+ Buildr::Nailgun.port = 2233
133
+
134
+ If you provided custom host/port settings you need
135
+ to tell the nailgun client where to connect to:
136
+
137
+ ng --nailgun-server 127.0.0.1 --nailgun-port 2233 nailgun:tasks
138
+
139
+ The buildr server starts a BuildrFactory responsible for providing
140
+ a pool of JRuby runtimes configured and ready for task execution.
141
+ This BuildrFactory consists of two queues: One of pure JRuby runtimes
142
+ with almost nothing loaded, and another of Buildr runtimes (consumed
143
+ from the first queue) with the Buildr runtime preloaded but without
144
+ any project definition. The jruby queue is used for sandboxing code
145
+ like running GetoptLong, but most importantly its the place where
146
+ buildr runtimes begin life, to be later added on the buildr queue.
147
+ By default both queues are of size 3, you can customize this with:
148
+
149
+ require 'buildr/nailgun'
150
+ Buildr::Nailgun.jruby_queue_size = 4 # JRuby creation is fast!
151
+ Buildr::Nailgun.buildr_queue_size = 5 # loading buildr takes longer
152
+
153
+ The buildr_queue_size is of particular importance if you expect to
154
+ reload lots of buildfiles.
155
+
156
+ Execute nailgun:tasks get an overview of available nailgun tasks.
157
+
158
+ DESC
159
+ end
160
+
161
+ def nailgun_tasks
162
+ tasks = {}
163
+ tasks['nailgun:help'] = 'Display nailgun help'
164
+ tasks['nailgun:start'] = 'Start the Nailgun server.'
165
+ tasks['nailgun:stop'] = 'Stop the Nailgun server.'
166
+ tasks['nailgun:tasks'] = 'Display this message'
167
+ tasks['nailgun:list'] = <<-DESC
168
+ Display a list of builfile paths having an associated
169
+ buildr runtime. Having a cached runtime reduces buidlr
170
+ execution time.
171
+
172
+ If buildr finds the current buildfile on this list,
173
+ no file loading will be performed, only execution of
174
+ specified tasks on the previously loaded environment.
175
+ However if the cached runtime is out of date (buildfile
176
+ has been modified) the runtime will be reloaded.
177
+
178
+ This feature becomes handy when performing development
179
+ cycle: edit -> compile -> test -> report.
180
+
181
+ This task exits inmediatly after printing the file list.
182
+ DESC
183
+ tasks['nailgun:clear'] = <<-DESC
184
+ Remove all cached buildr runtimes and exit
185
+ DESC
186
+ tasks['nailgun:load'] = <<-DESC
187
+ Add or update a cached runtime.
188
+
189
+ Use this task to create a cached buildr runtime for a
190
+ buildfile.
191
+ DESC
192
+ tasks['nailgun:delete'] = <<-DESC
193
+ Delete cached runtime for a buildfile and exit.
194
+ DESC
195
+ tasks['nailgun:once [tasks]'] = <<-DESC
196
+ Ignore cached runtime and perform tasks on a newly
197
+ created environment. This new runtime is dropped right
198
+ after buildr completion.
199
+ DESC
200
+
201
+ out = ""
202
+ out << "\nNailgun tasks:\n"
203
+ tasks.each_pair do |task, desc|
204
+ out << "\n"
205
+ out << sprintf(" %20-s\n", [task].flatten.join(' | '))
206
+ out << sprintf(" %s\n", desc.strip.gsub(/ *\n +/, "\n "))
207
+ end
208
+ out
209
+ end
210
+
211
+ def buildfile(dir = nil, candidates = nil)
212
+ dir ||= Dir.pwd
213
+ candidates ||= @rakefiles.dup
214
+ Util.find_buildfile(dir, candidates, options.nosearch)
215
+ end
216
+
217
+ def clear_invoked
218
+ tasks.each do |task|
219
+ is_project = Project.instance_variable_get(:@projects).key?(task.name)
220
+ task.instance_variable_set(:@already_invoked, false) unless is_project
221
+ end
222
+ end
223
+
224
+ if Buildr.const_defined?(:Application)
225
+ class Buildr::Application
226
+ include Nailgun::Application
227
+ public :requires
228
+ end
229
+ end
230
+ end
231
+
232
+ module ContextRunner
233
+ extend self
234
+
235
+ def parse_options(ctx, opts)
236
+ opts.requires = []
237
+ Buildr.const_set(:VERSION, ctx.server.runtime.object.const_get(:Buildr)::VERSION)
238
+
239
+ obj = OpenStruct.new(:ctx => ctx, :opts => opts)
240
+ class << obj
241
+ include Buildr::CommandLineInterface
242
+
243
+ def help
244
+ super
245
+ puts
246
+ puts 'To get a summary of Nailgun features use'
247
+ puts ' nailgun:help'
248
+ end
249
+
250
+ def do_option(opt, value)
251
+ case opt
252
+ when '--help'
253
+ help
254
+ opts.exit = true
255
+ when '--version'
256
+ puts version
257
+ opts.exit = true
258
+ when '--environment'
259
+ ctx.env['BUILDR_ENV'] = value
260
+ when '--buildfile'
261
+ opts.buildfile = value
262
+ when '--require'
263
+ opts.requires << value
264
+ when '--nosearch'
265
+ opts.nosearch = true
266
+ end
267
+ end
268
+ end
269
+
270
+ ARGV.replace(ctx.argv)
271
+ obj.parse_options
272
+ end
273
+
274
+ def run(ctx)
275
+ ARGV.replace(ctx.argv)
276
+ Dir.chdir(ctx.pwd)
277
+ ctx.env.each { |k, v| ENV[k.to_s] = v.to_s }
278
+ Buildr::Application.module_eval do
279
+ include Nailgun::Application
280
+ end
281
+ task 'nailgun:load' do
282
+ puts "Buildfile #{Rake.application.buildfile} loaded"
283
+ end
284
+ if ctx.fresh
285
+ run_fresh(ctx)
286
+ else
287
+ run_local(ctx)
288
+ end
289
+ end
290
+
291
+ private
292
+
293
+ def run_fresh(ctx)
294
+ Project.clear
295
+ old_app = Rake.application
296
+ Rake.application = Buildr::Application.new
297
+ Rake.application.instance_eval do
298
+ @tasks = old_app.instance_variable_get(:@tasks)
299
+ @rules = old_app.instance_variable_get(:@rules)
300
+ run
301
+ end
302
+ end
303
+
304
+ def run_local(ctx)
305
+ Rake.application.instance_eval do
306
+ verbose(nil)
307
+ options.trace = false
308
+ parse_options
309
+ collect_tasks
310
+ clear_invoked
311
+ top_level_tasks.delete('buildr:initialize')
312
+ Util.benchmark { top_level }
313
+ end
314
+ end
315
+ end
316
+
317
+ module Util
318
+ extend self
319
+
320
+ def find_buildfile(pwd, candidates, nosearch=false)
321
+ candidates = [candidates].flatten
322
+ buildfile = candidates.find { |c| File.file?(File.expand_path(c, pwd)) }
323
+ return File.expand_path(buildfile, pwd) if buildfile
324
+ return nil if nosearch
325
+ updir = File.dirname(pwd)
326
+ return nil if File.expand_path(updir) == File.expand_path(pwd)
327
+ find_buildfile(updir, candidates)
328
+ end
329
+
330
+ def benchmark(action = ['Completed'], verbose = true)
331
+ result = nil
332
+ times = Benchmark.measure do
333
+ result = yield(action)
334
+ end
335
+ if verbose
336
+ real = []
337
+ real << ("%ih" % (times.real / 3600)) if times.real >= 3600
338
+ real << ("%im" % ((times.real / 60) % 60)) if times.real >= 60
339
+ real << ("%.3fs" % (times.real % 60))
340
+ puts "#{[action].flatten.join(' ')} in #{real.join}"
341
+ end
342
+ result
343
+ end
344
+
345
+ def on_runtime(runtime, *args, &block)
346
+ raise_error = lambda do |cls, msg, trace|
347
+ raise RuntimeError.new(cls + ": "+ msg.to_s).tap { |e| e.set_backtrace(trace.map(&:to_s)) }
348
+ end
349
+ executor = runtime.object.const_get(:Module).new do
350
+ extend self
351
+ def runtime_exec(*args, &prc)
352
+ define_method(:runtime_exec, &prc)
353
+ runtime_exec(*args)
354
+ rescue => e
355
+ [:error, e.class.name, e.message, e.backtrace]
356
+ end
357
+ end
358
+ result = executor.runtime_exec(*args, &block)
359
+ raise_error.call(*result[1..-1]) if result.kind_of?(Array) && result.first == :error
360
+ result
361
+ end
362
+ end # module Util
363
+
364
+ boot do
365
+
366
+ class ::ConcreteJavaProxy
367
+ def self.jclass(name = nil)
368
+ name ||= self.java_class.name
369
+ Nailgun::Util.class_for_name(name)
370
+ end
371
+
372
+ def self.jnew(*args)
373
+ objs = []
374
+ classes = args.map do |a|
375
+ case a
376
+ when nil
377
+ obj << nil
378
+ nil
379
+ when Hash
380
+ objs << a.keys.first
381
+ cls = a.values.first
382
+ cls = Nailgun::Util.proxy_class(cls) if String == cls
383
+ cls
384
+ else
385
+ objs << a
386
+ a.java_class
387
+ end
388
+ end
389
+ classes = classes.to_java(java.lang.Class)
390
+ ctor = jclass.getDeclaredConstructor(classes)
391
+ ctor.setAccessible(true)
392
+ ctor.newInstance(objs.to_java(java.lang.Object))
393
+ end
394
+ end
395
+
396
+ module Util
397
+ def class_for_name(name)
398
+ java.lang.Class.forName(name)
399
+ end
400
+
401
+ def add_to_sysloader(path)
402
+ sysloader = java.lang.ClassLoader.system_class_loader
403
+ add_url_method = class_for_name('java.net.URLClassLoader').
404
+ getDeclaredMethod('addURL', [java.net.URL].to_java(java.lang.Class))
405
+ add_url_method.accessible = true
406
+ add_url_method.invoke(sysloader, [java.io.File.new(path.to_s).
407
+ toURL].to_java(java.net.URL))
408
+ end
409
+ add_to_sysloader Nailgun.artifact
410
+
411
+ def proxy_class(name)
412
+ JavaUtilities.get_proxy_class(name)
413
+ end
414
+
415
+ import org.jruby.RubyIO
416
+ def set_stdio(runtime, dev)
417
+ set_global = lambda do |global, constant, stream|
418
+ runtime.global_variables.set(global, stream)
419
+ runtime.object.send(:remove_const, constant)
420
+ runtime.object.send(:const_set, constant, stream)
421
+ end
422
+ stdin = runtime.global_variables.get('$stdin')
423
+ stdout = runtime.global_variables.get('$stdout')
424
+ stderr = runtime.global_variables.get('$stderr')
425
+ input = RubyIO.jnew(runtime, dev.in => java.io.InputStream)
426
+ output = RubyIO.jnew(runtime, dev.out => java.io.OutputStream)
427
+ error = RubyIO.jnew(runtime, dev.err => java.io.OutputStream)
428
+ # stdin.reopen(input, 'r') # not working on jruby, :(
429
+ set_global.call('$stdin', 'STDIN', input)
430
+ stdout.reopen(output, 'w')
431
+ stderr.reopen(error, 'w')
432
+ end
433
+
434
+ def redirect_stdio(runtime, nail)
435
+ result = nil
436
+ begin
437
+ set_stdio(runtime, nail)
438
+ result = yield
439
+ ensure
440
+ set_stdio(runtime, java.lang.System)
441
+ end
442
+ result
443
+ end
444
+ end
445
+
446
+ class Buildfile
447
+ attr_reader :path, :requires, :loaded_time
448
+ attr_accessor :runtime
449
+
450
+ def initialize(path, *requires)
451
+ @path = File.expand_path(path)
452
+ @requires = requires.dup
453
+ end
454
+
455
+ def loaded!
456
+ @loaded_time = Time.now
457
+ end
458
+
459
+ def last_modification
460
+ File.timestamp(path)
461
+ end
462
+
463
+ def should_be_loaded?
464
+ (loaded_time || Rake::EARLY) < last_modification
465
+ end
466
+
467
+ def to_s
468
+ buff = path.dup
469
+ buff << sprintf("\n %-25s %s", "Last Modified:", last_modification)
470
+ unless requires.empty?
471
+ buff << sprintf("\n %-25s %s", "Requires:", requires.join(" "))
472
+ end
473
+ if should_be_loaded?
474
+ buff << sprintf("\n %-25s %s", "Needs reload, last was:", loaded_time)
475
+ else
476
+ buff << sprintf("\n %-25s %s", "Loaded at:", loaded_time)
477
+ end
478
+ buff << sprintf("\n %-25s %s", "Runtime:", runtime)
479
+ buff
480
+ end
481
+ end
482
+
483
+ class BuildrNail
484
+ include org.apache.buildr.BuildrNail
485
+ Main = Util.proxy_class 'org.apache.buildr.BuildrNail$Main'
486
+
487
+ attr_reader :buildfile
488
+
489
+ def initialize
490
+ buildfile = Buildfile.new(Rake.application.buildfile,
491
+ *Rake.application.requires)
492
+ buildfile.loaded!
493
+ buildfile.runtime = JRuby.runtime
494
+ @buildfiles = { buildfile.path => buildfile }
495
+ end
496
+
497
+ def main(nail)
498
+ Thread.exclusive { Thread.current.priority = 100; run(nail) }
499
+ end
500
+
501
+ private
502
+ def run(nail)
503
+ nail.assert_loopback_client
504
+ nail.out.println "Using #{nail.getNGServer}"
505
+ ctx = context_from_nail(nail)
506
+
507
+ case ctx.action
508
+ when :start
509
+ nail.out.println "Cannot start nailgun when running as client"
510
+ return nail.exit(0)
511
+ when :stop
512
+ puts "Stopping #{nail.getNGServer}"
513
+ nail.out.println "Stopping #{nail.getNGServer}"
514
+ return nail.getNGServer.shutdown(true)
515
+ when :list
516
+ if @buildfiles.empty?
517
+ nail.out.println "No defined runtimes"
518
+ else
519
+ nail.out.println "Defined runtimes:"
520
+ @buildfiles.each_value { |f| nail.out.println "- #{f}" }
521
+ end
522
+ return nail.exit(0)
523
+ when :clear
524
+ @buildfiles.clear
525
+ nail.out.println "Cleared all runtimes"
526
+ return nail.exit(0)
527
+ when :tasks
528
+ nail.out.println ""
529
+ nail.out.println Rake.application.nailgun_tasks
530
+ return nail.exit(0)
531
+ when :help
532
+ nail.out.println ""
533
+ nail.out.println Rake.application.nailgun_help
534
+ return nail.exit(0)
535
+ end
536
+
537
+ opts = OpenStruct.new
538
+
539
+ runtime = ctx.runtime
540
+ #Util.set_stdio(runtime, nail)
541
+ runtime.object.const_get(:Buildr)::Nailgun::ContextRunner.parse_options(ctx, opts)
542
+ return nail.exit(0) if opts.exit
543
+
544
+ candidates = Buildr::Application::DEFAULT_BUILDFILES
545
+ candidates = [opts.buildfile] if opts.buildfile
546
+
547
+ path = Util.find_buildfile(ctx.pwd, candidates, opts.nosearch) ||
548
+ File.expand_path(candidates.first, ctx.pwd)
549
+
550
+ if ctx.action == :delete
551
+ nail.out.println "Deleting runtime for #{path}"
552
+ @buildfiles.delete(path)
553
+ return nail.exit(0)
554
+ end
555
+
556
+ puts "Getting buildr runtime for #{path}"
557
+ buildfile = @buildfiles[path] || Buildfile.new(path, *opts.requires)
558
+
559
+ save = buildfile.should_be_loaded? || ctx.action == :load
560
+
561
+ runtime = buildfile.runtime
562
+
563
+ if save || ctx.action == :once
564
+ ctx.argv.unshift 'nailgun:load'
565
+ ctx.fresh = true
566
+ runtime = ctx.buildr
567
+ if save
568
+ buildfile.runtime = runtime
569
+ buildfile.loaded!
570
+ @buildfiles[buildfile.path] = buildfile
571
+ end
572
+ end
573
+
574
+ Util.redirect_stdio(runtime, nail) do
575
+ runtime.object.send :puts
576
+ runtime.object.const_get(:Buildr)::Nailgun::ContextRunner.run(ctx)
577
+ end
578
+ end
579
+
580
+ def context_from_nail(nail)
581
+ ctx = OpenStruct.new
582
+ ctx.pwd = nail.getWorkingDirectory
583
+ ctx.env = nail.env
584
+ ctx.argv = [nail.command] + nail.args.map(&:to_s)
585
+ ctx.server = nail.getNGServer
586
+ def ctx.runtime; @runtime ||= server.buildr_factory.runtime; end
587
+ def ctx.buildr; @buildr ||= server.buildr_factory.obtain; end
588
+ actions = {
589
+ :load => %w{ nailgun:load },
590
+ :delete => %w{ nailgun:delete },
591
+ :clear => %w{ nailgun:clear },
592
+ :list => %w{ nailgun:list },
593
+ :start => %w{ nailgun:boot nailgun:start },
594
+ :stop => %w{ nailgun:stop },
595
+ :once => %w{ nailgun:once },
596
+ :tasks => %w{ nailgun:tasks },
597
+ :help => %w{ nailgun:help help:nailgun },
598
+ }
599
+ action = actions.find { |k,v| k if v.any? { |t| ctx.argv.delete(t) } }
600
+ ctx.action = action.first if action
601
+ ctx
602
+ end
603
+
604
+ end # class BuildrNail
605
+
606
+ class BuildrFactory
607
+
608
+ attr_accessor :buildrs_size, :runtimes_size
609
+
610
+ def initialize(buildrs_size = 1, runtimes_size = nil)
611
+ runtimes_size ||= buildrs_size
612
+ @buildrs_size = buildrs_size < 1 ? 1 : buildrs_size
613
+ @runtimes_size = runtimes_size < 1 ? 1 : runtimes_size
614
+
615
+ @buildrs = [].extend(MonitorMixin)
616
+ @buildrs_ready = @buildrs.new_cond
617
+ @buildrs_needed = @buildrs.new_cond
618
+
619
+ @buildrs_creators = [].extend(MonitorMixin)
620
+
621
+ @runtimes = [].extend(MonitorMixin)
622
+ @runtimes_ready = @runtimes.new_cond
623
+ @runtimes_needed = @runtimes.new_cond
624
+
625
+ @runtimes_creators = [].extend(MonitorMixin)
626
+ end
627
+
628
+ def obtain
629
+ get(:buildr)
630
+ end
631
+
632
+ def runtime
633
+ get(:runtime)
634
+ end
635
+
636
+ def start
637
+ debug "Starting Buildr runtime factory"
638
+ @runtime_creator = Thread.new { loop { create :runtime } }
639
+ @runtime_creator.priority = -2
640
+ @buildr_creator = Thread.new { loop { create :buildr } }
641
+ @buildr_creator.priority = 1
642
+ end
643
+
644
+ def stop
645
+ @buildr_creator.kill if @buildr_creator
646
+ @runtime_creator.kill if @runtime_creator
647
+ end
648
+
649
+ private
650
+ def debug(*msg)
651
+ puts *msg if Rake.application.options.trace
652
+ end
653
+
654
+ def get(thing)
655
+ collection = instance_variable_get("@#{thing}s")
656
+ needs = instance_variable_get("@#{thing}s_needed")
657
+ ready = instance_variable_get("@#{thing}s_ready")
658
+ result = nil
659
+ collection.synchronize do
660
+ if collection.empty?
661
+ debug "no #{thing} available, ask to create more"
662
+ needs.broadcast
663
+ debug "should be creating #{thing}"
664
+ ready.wait_while { collection.empty? }
665
+ end
666
+ debug "Getting my #{thing}"
667
+ result = collection.shift
668
+ debug "would need more #{thing}s"
669
+ needs.broadcast
670
+ debug "got my #{thing}: #{result.inspect}"
671
+ Thread.pass
672
+ end
673
+ debug "returning #{result.inspect}"
674
+ result
675
+ end
676
+
677
+ def create(thing, *args, &prc)
678
+ creator = needed(thing)
679
+ collection = instance_variable_get("@#{thing}s")
680
+ ready = instance_variable_get("@#{thing}s_ready")
681
+ needs = instance_variable_get("@#{thing}s_needed")
682
+ unless creator
683
+ collection.synchronize do
684
+ debug "awake those wanting a #{thing}"
685
+ ready.broadcast
686
+ Thread.pass
687
+ debug "wait until more #{thing}s are needed"
688
+ # needs.wait(1); return
689
+ needs.wait_until { creator = needed(thing) }
690
+ end
691
+ end
692
+ debug "About to create #{thing} # #{creator}"
693
+ method = "create_#{thing}"
694
+ creators = instance_variable_get("@#{thing}s_creators")
695
+ debug "registering creator for #{thing} #{creator}"
696
+ creators.synchronize { creators << creator }
697
+ result = send(method, creator, *args, &prc)
698
+ debug "created #{thing}[#{creator}] => #{result.inspect}"
699
+ creators.synchronize do
700
+ debug "unregistering creator for #{thing} #{creator}"
701
+ creators.delete(creator)
702
+ collection.synchronize do
703
+ debug "adding object on queue for #{thing} #{creator}"
704
+ collection << result
705
+ end
706
+ end
707
+ rescue => e
708
+ puts "#{e.backtrace.shift}: #{e.message}"
709
+ e.backtrace.each { |i| puts "\tfrom #{i}" }
710
+ end
711
+
712
+ def needed(thing)
713
+ collection = instance_variable_get("@#{thing}s")
714
+ creators = instance_variable_get("@#{thing}s_creators")
715
+ size = instance_variable_get("@#{thing}s_size")
716
+ collection.synchronize do
717
+ count = collection.size
718
+ if count < size
719
+ count += creators.synchronize { creators.size }
720
+ end
721
+ count if count < size
722
+ end
723
+ end
724
+
725
+ def create_runtime(creator)
726
+ debug "Creating runtime[#{creator}]"
727
+ Util.benchmark do |header|
728
+ runtime = org.jruby.Ruby.newInstance
729
+ runtime.global_variables.set('$nailgun_server', JRuby.reference($nailgun_server))
730
+ BUILDR_PATHS.each { |path| runtime.load_service.load_path.unshift path }
731
+ runtime.load_service.require 'buildr/nailgun'
732
+ header.replace ["Created runtime[#{creator}]", runtime]
733
+ runtime
734
+ end
735
+ end
736
+
737
+ def create_buildr(creator)
738
+ debug "Obtaining runtime to load buildr[#{creator}] on it"
739
+ runtime = get(:runtime)
740
+ debug "Loading buildr[#{creator}] on #{runtime} ..."
741
+ Util.benchmark ["Loaded buildr[#{creator}] on #{runtime}"] do
742
+ load_service = runtime.load_service
743
+ load_service.require 'rubygems'
744
+ load_service.require 'buildr'
745
+ end
746
+ runtime
747
+ end
748
+
749
+ end # BuildrFactory
750
+
751
+ class BuildrServer < com.martiansoftware.nailgun.NGServer
752
+
753
+ attr_reader :buildr_factory
754
+
755
+ def initialize(host = 'localhost', port = 2113, buildr_factory = nil)
756
+ super(java.net.InetAddress.get_by_name(host), port)
757
+ @buildr_factory = buildr_factory
758
+ @host, @port = host, port
759
+ end
760
+
761
+ def runtime
762
+ JRuby.runtime
763
+ end
764
+
765
+ def start_server
766
+ self.allow_nails_by_class_name = false
767
+
768
+ BuildrNail::Main.nail = BuildrNail.new
769
+ self.default_nail_class = BuildrNail::Main
770
+ buildr_factory.start
771
+
772
+ @thread = java.lang.Thread.new(self)
773
+ @thread.setName(to_s)
774
+ @thread.start
775
+
776
+ sleep 1 while getPort == 0
777
+ puts "#{self} Started."
778
+ end
779
+
780
+ def stop_server
781
+ buildr_factory.stop
782
+ @thread.kill
783
+ end
784
+
785
+ def to_s
786
+ "BuildrServer(" <<
787
+ [Rake.application.version, @host, @port].join(", ") <<
788
+ ")"
789
+ end
790
+ end # class BuildrServer
791
+
792
+ end # Nailgun boot
793
+
794
+ namespace do
795
+ tmp = lambda { |*files| File.join(Dir.tmpdir, "nailgun", *files) }
796
+ dist_zip = Buildr.download(tmp[NAME + ".zip"] => URL)
797
+ dist_dir = Buildr.unzip(tmp[NAME] => dist_zip)
798
+
799
+ if File.exist?(File.join(home, NAME + ".jar"))
800
+ ng_jar = file(File.join(home, NAME + ".jar"))
801
+ else
802
+ ng_jar = file(tmp[NAME, NAME, NAME+".jar"] => dist_dir)
803
+ end
804
+
805
+ self.artifact = Buildr.artifact(ARTIFACT_SPEC).from(ng_jar)
806
+
807
+ compiled_bin = tmp[NAME, NAME, "ng"+Config::CONFIG['EXEEXT']]
808
+ compiled_bin = file(compiled_bin => dist_dir.target) do |task|
809
+ unless task.to_s.pathmap('%x') == '.exe'
810
+ Dir.chdir(task.to_s.pathmap('%d')) do
811
+ puts "Compiling #{task.to_s}"
812
+ system('make', task.to_s.pathmap('%f')) or
813
+ fail "Nailgun binary compilation failed."
814
+ end
815
+ end
816
+ end
817
+
818
+ installed_bin = file(File.join(home,
819
+ compiled_bin.to_s.pathmap('%f')) => compiled_bin) do |task|
820
+ mkpath task.to_s.pathmap('%d'), :verbose => false
821
+ cp compiled_bin.to_s, task.to_s, :verbose => false
822
+ end
823
+
824
+ task :boot => artifact do |task|
825
+ if $nailgun_server
826
+ raise "Already nunning on Nailgun server: #{$nailgun_server}"
827
+ end
828
+ tasks = Rake.application.instance_eval { @top_level_tasks.dup }
829
+ tasks.delete_if do |t|
830
+ t =~ /^(buildr:initialize|(ng|nailgun):.+)$/
831
+ end
832
+ unless tasks.empty?
833
+ raise "Don't specify more targets when starting Nailgun server"
834
+ end
835
+ boot
836
+ end
837
+
838
+ task :start => [installed_bin, :boot] do
839
+ factory = BuildrFactory.new(buildr_queue_size, jruby_queue_size)
840
+ $nailgun_server = BuildrServer.new(server, port, factory)
841
+ puts "Starting #{$nailgun_server}"
842
+ $nailgun_server.start_server
843
+
844
+ is_win = Buildr::Util.win_os?
845
+ bin_path = File.expand_path(installed_bin.to_s.pathmap("%d"))
846
+ bin_name = installed_bin.to_s.pathmap("%f")
847
+
848
+ puts <<-NOTICE
849
+
850
+ Buildr server has been started, you may need to update your PATH
851
+ variable in order to execute the #{bin_name} binary.
852
+
853
+ #{ is_win ?
854
+ "> set NAILGUN_HOME=#{bin_path}" :
855
+ "$ export NAILGUN_HOME=#{bin_path}"
856
+ }
857
+ #{ is_win ?
858
+ "> set PATH=%NAILGUN_HOME%;%PATH%" :
859
+ "$ export PATH=${NAILGUN_HOME}:${PATH}"
860
+ }
861
+
862
+ Runtime for #{Rake.application.buildfile} has been cached, this
863
+ means you can open a terminal inside
864
+
865
+ #{Rake.application.buildfile.pathmap("%d")}
866
+
867
+ Invoke tasks by executing the #{bin_name} program, it takes the
868
+ same parameters you normally use for ``buildr''.
869
+
870
+ To display Nailgun related help, execute the command:
871
+ ``#{bin_name} nailgun:help''
872
+
873
+ To get an overview of Nailgun tasks, execute the command:
874
+ ``#{bin_name} nailgun:tasks''
875
+
876
+ NOTICE
877
+ end
878
+
879
+ task :help do
880
+ puts Rake.application.nailgun_help
881
+ end
882
+
883
+ task :tasks do
884
+ puts Rake.application.nailgun_tasks
885
+ end
886
+
887
+ end # namespace :nailgun
888
+
889
+ end # module Nailgun
890
+
891
+ end
892
+