buildr 1.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
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
+