buildr 0.16.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,7 +1,10 @@
1
+ require 'stringio'
2
+
1
3
  module Buildr
2
4
  module Java
3
5
 
4
6
  JAVA_OPTIONS = [ :verbose, :noop, :cp, :classpath, :name, :java_args ]
7
+ JUNIT_REQUIRES = [ "junit:junit:jar:3.8.1", "jmock:jmock:jar:1.1.0" ]
5
8
 
6
9
  def self.java(*args)
7
10
  options = Hash === args.last ? args.pop : {}
@@ -44,6 +47,19 @@ module Buildr
44
47
  end
45
48
  end
46
49
 
50
+ # Gets the version of the java VM
51
+ def self.version()
52
+ @version ||= `java -version 2>&1`.scan(/java version "(.*)"/)[0][0]
53
+ end
54
+
55
+ def self.tools()
56
+ unless @tools
57
+ tools = File.join(ENV['JAVA_HOME'], "lib", "tools.jar")
58
+ @tools = File.exist?(tools) ? tools : []
59
+ end
60
+ @tools
61
+ end
62
+
47
63
  class AptTask < Rake::FileTask
48
64
 
49
65
  def initialize(*args)
@@ -94,9 +110,27 @@ module Buildr
94
110
  end
95
111
  end
96
112
 
113
+ def self.junit(*args)
114
+ options = Hash === args.last ? args.pop : {}
115
+ options[:verbose] ||= Rake.application.options.trace || false
116
+ fu_check_options options, :verbose, :noop, :cp, :classpath, :sourcepath, :output, :javac_args, :name
117
+
118
+ classpath = classpath_from(options) + junit_artifacts
119
+ tests = args.flatten
120
+ failed = tests.inject([]) do |failed, test|
121
+ begin
122
+ java "junit.textui.TestRunner", test, :classpath=>classpath, :name=>"tests in #{test}"
123
+ failed
124
+ rescue
125
+ failed << test
126
+ end
127
+ end
128
+ [ tests - failed, failed ]
129
+ end
130
+
97
131
  protected
98
132
 
99
- def self.path_to_bin(name)
133
+ def self.path_to_bin(name = "java")
100
134
  ENV["JAVA_HOME"] ? File.join(ENV["JAVA_HOME"], "bin", name) : name
101
135
  end
102
136
 
@@ -105,6 +139,10 @@ module Buildr
105
139
  artifacts(classpath).each { |t| t.invoke if t.respond_to?(:invoke) }.map(&:to_s)
106
140
  end
107
141
 
142
+ def self.junit_artifacts()
143
+ @junit_artifacts ||= artifacts(JUNIT_REQUIRES).each { |task| task.invoke }
144
+ end
145
+
108
146
  end
109
147
 
110
148
  def java(*args)
@@ -0,0 +1,123 @@
1
+ require 'net/http'
2
+
3
+ # Monkeypatching: forcing FileUtils to ignore .svn files when
4
+ # copying files around. We may want to implement our own deep
5
+ # copy instead of hacking FileUtils in the future, but the cases
6
+ # where you effectively want to copy .svn files are very, very
7
+ # rare.
8
+ module FileUtils
9
+ class Entry_
10
+ alias original_cp copy
11
+ def copy(dest)
12
+ unless path['.svn']
13
+ original_cp(dest)
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ module Buildr
20
+
21
+ module Jetty
22
+
23
+ VERSION = "6.1.1"
24
+
25
+ REQUIRES = [ "org.mortbay.jetty:jetty:jar:#{VERSION}",
26
+ "org.mortbay.jetty:jetty-util:jar:#{VERSION}",
27
+ "org.mortbay.jetty:servlet-api-2.5:jar:#{VERSION}",
28
+ "log4j:log4j:jar:1.2.13",
29
+ "commons-logging:commons-logging:jar:1.1"
30
+ ]
31
+
32
+ OPTIONS = [ :classpath, :war_path, :context_path, :noop, :base_url, :process_alias ]
33
+
34
+ # Bouncing a webapp deployed in the Jetty web server. Just does a post
35
+ # to a buildr specific handler. If there's nothing on the other side,
36
+ # a new Jetty instance is spawned.
37
+ def self.bounce(options)
38
+ fu_check_options options, *OPTIONS
39
+ options[:classpath] ||= []
40
+
41
+ begin
42
+ puts "Bouncing webapp #{options[:war_path]}" if verbose
43
+ res = jetty_call('/bounce', :post, options)
44
+ puts "done." if verbose
45
+ rescue Errno::ECONNREFUSED => e
46
+ puts "Web server not found, spawning it."
47
+ runtool options.merge(:class=>"JettyWrapper",
48
+ :args=>[ options[:war_path], options[:context_path] ],
49
+ :classpath=>options[:classpath] + ['../buildr/lib/java/jetty'])
50
+ end
51
+
52
+ case res
53
+ when Net::HTTPNotFound
54
+ fail "A web server seems to be already running without Buildr deployment hooks."
55
+ when Net::HTTPInternalServerError
56
+ fail "Server error occured when redeploying the WAR, see the web server logs."
57
+ end
58
+ end
59
+
60
+ # Sends an http request to the buildr handler deployed in Jetty.
61
+ def self.jetty_call(rel_url, get_post, options)
62
+ base_url = URI.parse((options[:base_url] || 'http://localhost:8080/buildr') + rel_url)
63
+ req = get_post == :post ? Net::HTTP::Post.new(base_url.path) : Net::HTTP::Get.new(base_url.path)
64
+ res = Net::HTTP.start(base_url.host, base_url.port) {|http| http.request(req) }
65
+ end
66
+
67
+ protected
68
+
69
+ def self.runtool(options)
70
+ classpath = REQUIRES + (options[:classpath] || []).collect | (options[:cp] || []).collect
71
+ classpath = artifacts(classpath).each { |t| t.invoke if t.respond_to?(:invoke) }.map(&:to_s)
72
+ cmd_args = ["-cp", classpath.join(File::PATH_SEPARATOR)]
73
+ cmd_args << options[:class]
74
+ cmd_args += options[:args]
75
+ unless options[:noop]
76
+ if fork.nil?
77
+ STDOUT.reopen File.new("stdout.log", "w")
78
+ STDERR.reopen File.new("stderr.log", "w")
79
+ exec ([Java.path_to_bin("java")] + cmd_args).join(' ')
80
+ end
81
+ end
82
+ end
83
+
84
+ class JettyTask < Rake::Task
85
+ def initialize(*args)
86
+ super
87
+ enhance do |task|
88
+ Jetty.bounce task.options
89
+ end
90
+ end
91
+
92
+ def options()
93
+ @options ||= {}
94
+ end
95
+
96
+ def using(options)
97
+ self.options.merge!(options)
98
+ self
99
+ end
100
+ end
101
+ end
102
+
103
+ class Project
104
+ def webserve(&block)
105
+ task "jetty:shutdown" do
106
+ begin
107
+ res = Jetty.jetty_call('/stop', :put, @webserve_task.options)
108
+ puts "Response #{res}" if verbose
109
+ rescue Errno::ECONNREFUSED
110
+ puts "Jetty server couldn't be contacted, nothing done."
111
+ rescue EOFError
112
+ puts "Shutdown successful."
113
+ rescue Exception => e
114
+ puts "Unexpected error: #{e.class}"
115
+ end
116
+ end
117
+ returning(@webserve_task ||= Jetty::JettyTask.define_task("jetty:bounce"=>package(:war))) do |task|
118
+ task.enhance &block if block
119
+ end
120
+ end
121
+ end
122
+
123
+ end
@@ -0,0 +1,107 @@
1
+ import org.mortbay.jetty.Server;
2
+ import org.mortbay.jetty.Request;
3
+ import org.mortbay.jetty.Handler;
4
+ import org.mortbay.jetty.handler.AbstractHandler;
5
+ import org.mortbay.jetty.handler.ContextHandler;
6
+ import org.mortbay.jetty.handler.ContextHandlerCollection;
7
+ import org.mortbay.jetty.webapp.WebAppContext;
8
+
9
+ import javax.servlet.http.HttpServletRequest;
10
+ import javax.servlet.http.HttpServletResponse;
11
+ import javax.servlet.ServletException;
12
+ import java.io.IOException;
13
+
14
+ /**
15
+ * @author Matthieu Riou <mriou at apache dot org>
16
+ */
17
+ public class JettyWrapper {
18
+
19
+ private Server _server;
20
+ private WebAppContext _webAppHandler;
21
+ private ContextHandlerCollection _handlerColl;
22
+ private String _webAppDir;
23
+ private String _contextPath;
24
+
25
+ public JettyWrapper(String webAppDir, String contextPath) {
26
+ _server = new Server(8080);
27
+ _webAppDir = webAppDir;
28
+ _contextPath = contextPath;
29
+
30
+ // Adding handler for the war to deploy
31
+ _webAppHandler = new WebAppContext(_webAppDir, _contextPath);
32
+ _webAppHandler.setConfigurationClasses(new String[] {
33
+ "org.mortbay.jetty.webapp.WebInfConfiguration",
34
+ "org.mortbay.jetty.webapp.WebXmlConfiguration"});
35
+
36
+ // Adding the buildr handler to control our server lifecycle
37
+ ContextHandler context = new ContextHandler();
38
+ context.setContextPath("/buildr");
39
+ Handler handler = new BuildrHandler();
40
+ context.setHandler(handler);
41
+
42
+ _handlerColl = new ContextHandlerCollection();
43
+ _handlerColl.setHandlers(new Handler[] {_webAppHandler, context});
44
+
45
+ _server.addHandler(_handlerColl);
46
+ }
47
+
48
+ public void start() {
49
+ try {
50
+ _server.start();
51
+ _server.join();
52
+ } catch (Exception e) {
53
+ e.printStackTrace();
54
+ }
55
+ }
56
+
57
+ public static void main(String[] args) {
58
+ if (args.length != 2) {
59
+ System.out.println("Please provide the webapp directory and the context path.");
60
+ }
61
+ String webAppDir = args[0];
62
+ String contextPath = args[1];
63
+ JettyWrapper jetwrap = new JettyWrapper(webAppDir, contextPath);
64
+ jetwrap.start();
65
+ }
66
+
67
+ private class BuildrHandler extends AbstractHandler {
68
+
69
+ public void handle(String string, HttpServletRequest request,
70
+ HttpServletResponse response, int i) throws IOException, ServletException {
71
+ response.setContentType("text/html");
72
+ if (request.getPathInfo().equals("/bounce")) {
73
+ try {
74
+ _webAppHandler.stop();
75
+ _handlerColl.removeHandler(_webAppHandler);
76
+ _webAppHandler = new WebAppContext(_webAppDir, _contextPath);
77
+ _webAppHandler.setConfigurationClasses(new String[] {
78
+ "org.mortbay.jetty.webapp.WebInfConfiguration",
79
+ "org.mortbay.jetty.webapp.WebXmlConfiguration"});
80
+ _handlerColl.addHandler(_webAppHandler);
81
+ _webAppHandler.start();
82
+ } catch (Throwable e) {
83
+ e.printStackTrace();
84
+ response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
85
+ ((Request)request).setHandled(true);
86
+ return;
87
+ }
88
+ } else if (request.getPathInfo().equals("/stop")) {
89
+ try {
90
+ _server.stop();
91
+ _server.destroy();
92
+ // Brute force
93
+ System.exit(0);
94
+ } catch (Exception e) {
95
+ e.printStackTrace();
96
+ }
97
+ } else if (request.getPathInfo().equals("/war")) {
98
+ response.getWriter().println(_webAppHandler.getTempDirectory());
99
+ ((Request)request).setHandled(true);
100
+ return;
101
+ }
102
+ response.getWriter().println("OK " + request.getPathInfo());
103
+ ((Request)request).setHandled(true);
104
+ }
105
+
106
+ }
107
+ }
@@ -36,16 +36,14 @@ module Buildr
36
36
  protected
37
37
 
38
38
  def self.runtool(options)
39
- classpath = REQUIRES + (options[:classpath] || []).collect | (options[:cp] || []).collect
40
- classpath = artifacts(classpath).each { |t| t.invoke if t.respond_to?(:invoke) }.map(&:to_s)
41
- cmd_args = ["-cp", classpath.join(File::PATH_SEPARATOR)]
42
- cmd_args << options[:class]
43
- cmd_args += options[:args].select { |n, v| v }.map { |n, v| [ n, v ] }.flatten
44
- cmd_args << { :verbose=>options[:verbose] }
45
- unless options[:noop]
46
- verbose { puts "Running OpenJPA #{options[:name]}" }
47
- sh(Java.path_to_bin("java"), *cmd_args) { |ok, res| fail "Failed to execute OpenJPA #{options[:name]}, see errors above" unless ok }
48
- end
39
+ args = [options[:class]] + options[:args].select { |n, v| v }.map { |n, v| [ n, v ] }.flatten
40
+ args << { :classpath=>requires + (options[:classpath] || []),
41
+ :name=>"OpenJPA #{options[:name]}", :verbose=>options[:verbose] }
42
+ java *args
43
+ end
44
+
45
+ def self.requires()
46
+ @required ||= artifacts(REQUIRES).each { |artifact| artifact.invoke }.map(&:to_s)
49
47
  end
50
48
 
51
49
  end
@@ -3,10 +3,11 @@ module Buildr
3
3
 
4
4
  module Packaging
5
5
 
6
- MANIFEST_HEADER = "Manifest-Version: 1.0\nCreated-By: Ruby Build System"
6
+ MANIFEST_HEADER = "Manifest-Version: 1.0\nCreated-By: Buildr\n"
7
7
 
8
8
  class JarTask < ZipTask
9
9
  attr_accessor :manifest
10
+ attr_accessor :meta_inf
10
11
 
11
12
  def initialize(*args)
12
13
  super
@@ -16,6 +17,8 @@ module Buildr
16
17
  def []=(key, value)
17
18
  if key.to_sym == :manifest
18
19
  self.manifest = value
20
+ elsif key.to_sym == :meta_inf
21
+ self.meta_inf = value
19
22
  else
20
23
  super key, value
21
24
  end
@@ -25,23 +28,25 @@ module Buildr
25
28
  protected
26
29
 
27
30
  def create(zip)
28
- if manifest
29
- zip.mkdir "META-INF"
31
+ zip.mkdir "META-INF"
32
+ meta_inf.each { |file| zip.add "META-INF/#{File.basename(file)}", file } if meta_inf
33
+ unless manifest == false
30
34
  zip.file.open("META-INF/MANIFEST.MF", "w") do |output|
31
35
  output.write MANIFEST_HEADER
32
- case manifest
33
- when Hash
34
- output.write manifest.map { |pair| pair.join(": ") }.join("\n")
35
- when Array
36
- manifest.each do |section|
37
- output.write "\n"
38
- output.write section.map { |pair| pair.join(": ") }.join("\n")
36
+ if manifest
37
+ case manifest
38
+ when Hash
39
+ output.write manifest.map { |pair| pair.join(": ") }.sort.join("\n")
40
+ when Array
41
+ manifest.each do |section|
42
+ output.write "\n"
43
+ output.write section.map { |pair| pair.join(": ") }.sort.join("\n")
44
+ end
45
+ when Proc, Method
46
+ output.write manifest.call
47
+ when String
48
+ output.write File.read(manifest)
39
49
  end
40
- when Proc, Method
41
- output.write manifest.call
42
- when String
43
- output.write File.read(manifest)
44
- when true # Default behavior
45
50
  end
46
51
  output.write "\n"
47
52
  end
@@ -56,7 +61,7 @@ module Buildr
56
61
  def []=(key, value)
57
62
  case key.to_sym
58
63
  when :libs
59
- self.include value, :path=>"WEB-INF/lib"
64
+ self.include artifacts(value), :path=>"WEB-INF/lib"
60
65
  when :classes
61
66
  self.include value, :path=>"WEB-INF/classes"
62
67
  else
@@ -79,13 +84,22 @@ module Buildr
79
84
  Packaging::JarTask.define_task(file)
80
85
  end
81
86
 
82
-
83
87
  class Project
84
88
 
85
89
  # Group used for packaging. Inherited from parent project.
86
90
  inherited_attr :group
87
91
  # Version used for packaging. Inherited from parent project.
88
92
  inherited_attr :version
93
+ # Manifest used for packaging. Inherited from parent project.
94
+ inherited_attr :manifest do |project|
95
+ manifest = { "Build-By"=>ENV['USER'], "Build-Jdk"=>Java.version }
96
+ manifest["Implementation-Version"] = project.version if project.version
97
+ manifest
98
+ end
99
+ # Files to always include in the package META-INF directory.
100
+ inherited_attr :meta_inf do |project|
101
+ meta_inf = ["DISCLAIMER", "LICENSE", "NOTICE"].map { |f| path_to(f) if File.exist?(path_to(f)) }.compact
102
+ end
89
103
 
90
104
  # The project ID is the project name, and for a sub-project the
91
105
  # parent project ID followed by the project name, separated with a
@@ -97,7 +111,7 @@ module Buildr
97
111
 
98
112
  def package(*args)
99
113
  if Hash === args.last
100
- options = args.pop.clone
114
+ options = args.pop.dup
101
115
  else
102
116
  options = {}
103
117
  end
@@ -117,14 +131,14 @@ module Buildr
117
131
  fail("Do not know how to create a package of type #{options[:type]}")
118
132
  package = packager.call(file, options) or fail("Do not know how to create a package of type #{options[:type]}")
119
133
 
120
- task("package").enhance [package]
121
- package.enhance [task("build")]
134
+ task "package"=>package
135
+ package.enhance [ task("build")]
122
136
 
123
- task "install"=>[
124
- file_create(File.dirname(repositories.locate(package))) { |task| mkpath task.name, :verbose=>false },
125
- file(repositories.locate(package)=>package) { |task| cp package.name, task.name },
126
- package.pom
127
- ]
137
+ task "install"=>(file(repositories.locate(package)=>package) { |task|
138
+ mkpath File.dirname(task.name), :verbose=>false
139
+ cp package.name, task.name
140
+ })
141
+ task "install"=>package.pom
128
142
 
129
143
  task "uninstall" do |task|
130
144
  verbose(Rake.application.options.trace) do
@@ -147,30 +161,49 @@ module Buildr
147
161
  protected
148
162
 
149
163
  def package_as_jar(file, options)
164
+ unless Rake::Task.task_defined?(file)
165
+ returning(Java::Packaging::JarTask.define_task(file)) do |task|
166
+ package_extend task, options
167
+ task.enhance [path_to(:java_target_dir)]
168
+ task.include path_to(:java_target_dir, "*")
169
+ task.manifest = manifest.merge("Implementation-Title"=>self.comment)
170
+ task.meta_inf = meta_inf
171
+ end
172
+ end
150
173
  returning(Java::Packaging::JarTask.define_task(file)) do |task|
151
- package_extend task, options
152
- task.include path_to(:java_target_dir, "*")
153
174
  task.include options[:include] if options[:include]
154
175
  task.manifest = options[:manifest] if options[:manifest]
155
176
  end
156
177
  end
157
178
 
158
179
  def package_as_war(file, options)
180
+ unless Rake::Task.task_defined?(file)
181
+ returning(Java::Packaging::WarTask.define_task(file)) do |task|
182
+ package_extend task, options
183
+ task.include path_to(:webapp_src_dir, "*")
184
+ task.with :classes=>path_to(:java_target_dir, "**")
185
+ task.manifest = manifest.merge("Implementation-Title"=>self.comment)
186
+ task.meta_inf = meta_inf
187
+ end
188
+ end
159
189
  # Add anything we find in webapp sources directory.
160
190
  returning(Java::Packaging::WarTask.define_task(file)) do |task|
161
- package_extend task, options
162
- task.include path_to(:webapp_src_dir, "*")
163
191
  task.include options[:include] if options[:include]
164
192
  # Add libraries in WEB-INF lib, and classes in WEB-INF classes
165
193
  task.with :libs=>options[:libs].collect if options[:libs]
166
- task.with :classes=>(options[:classes] || path_to(:java_target_dir, "**")) unless options[:classes] == false
194
+ task.with :classes=>options[:classes] if options[:classes]
195
+ task.manifest = options[:manifest] if options[:manifest]
167
196
  end
168
197
  end
169
198
 
170
199
  def package_as_zip(file, options)
200
+ unless Rake::Task.task_defined?(file)
201
+ returning(ZipTask.define_task(file)) do |task|
202
+ package_extend task, options
203
+ task.include path_to(:java_target_dir, "*")
204
+ end
205
+ end
171
206
  returning(ZipTask.define_task(file)) do |task|
172
- package_extend task, options
173
- task.include path_to(:java_target_dir, "*")
174
207
  task.include options[:include] if options[:include]
175
208
  end
176
209
  end