lucidimagination-warbler 1.3.2.dev
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +16 -0
- data/History.txt +217 -0
- data/LICENSE.txt +26 -0
- data/Manifest.txt +92 -0
- data/README.txt +255 -0
- data/Rakefile +103 -0
- data/bin/warble +11 -0
- data/ext/JarMain.java +148 -0
- data/ext/WarMain.java +112 -0
- data/ext/WarblerJar.java +182 -0
- data/ext/WarblerJarService.java +18 -0
- data/lib/warbler.rb +33 -0
- data/lib/warbler/application.rb +86 -0
- data/lib/warbler/config.rb +223 -0
- data/lib/warbler/gems.rb +37 -0
- data/lib/warbler/jar.rb +253 -0
- data/lib/warbler/task.rb +183 -0
- data/lib/warbler/templates/bundler.erb +3 -0
- data/lib/warbler/templates/config.erb +1 -0
- data/lib/warbler/templates/jar.erb +5 -0
- data/lib/warbler/templates/rack.erb +1 -0
- data/lib/warbler/templates/rails.erb +1 -0
- data/lib/warbler/templates/war.erb +1 -0
- data/lib/warbler/traits.rb +107 -0
- data/lib/warbler/traits/bundler.rb +104 -0
- data/lib/warbler/traits/gemspec.rb +59 -0
- data/lib/warbler/traits/jar.rb +56 -0
- data/lib/warbler/traits/merb.rb +35 -0
- data/lib/warbler/traits/nogemspec.rb +42 -0
- data/lib/warbler/traits/rack.rb +33 -0
- data/lib/warbler/traits/rails.rb +62 -0
- data/lib/warbler/traits/war.rb +197 -0
- data/lib/warbler/version.rb +10 -0
- data/lib/warbler/war.rb +8 -0
- data/lib/warbler_jar.jar +0 -0
- data/spec/drb_helper.rb +41 -0
- data/spec/sample_bundler/Gemfile.lock +10 -0
- data/spec/sample_bundler/config.ru +0 -0
- data/spec/sample_jar/History.txt +6 -0
- data/spec/sample_jar/Manifest.txt +8 -0
- data/spec/sample_jar/README.txt +30 -0
- data/spec/sample_jar/lib/sample_jar.rb +6 -0
- data/spec/sample_jar/sample_jar.gemspec +40 -0
- data/spec/sample_jar/test/test_sample_jar.rb +8 -0
- data/spec/sample_war/app/controllers/application.rb +15 -0
- data/spec/sample_war/app/helpers/application_helper.rb +3 -0
- data/spec/sample_war/config/boot.rb +109 -0
- data/spec/sample_war/config/database.yml +19 -0
- data/spec/sample_war/config/environment.rb +67 -0
- data/spec/sample_war/config/environments/development.rb +17 -0
- data/spec/sample_war/config/environments/production.rb +25 -0
- data/spec/sample_war/config/environments/test.rb +22 -0
- data/spec/sample_war/config/initializers/inflections.rb +10 -0
- data/spec/sample_war/config/initializers/mime_types.rb +5 -0
- data/spec/sample_war/config/initializers/new_rails_defaults.rb +15 -0
- data/spec/sample_war/config/routes.rb +41 -0
- data/spec/sample_war/lib/tasks/utils.rake +0 -0
- data/spec/sample_war/public/404.html +30 -0
- data/spec/sample_war/public/422.html +30 -0
- data/spec/sample_war/public/500.html +30 -0
- data/spec/sample_war/public/favicon.ico +0 -0
- data/spec/sample_war/public/index.html +274 -0
- data/spec/sample_war/public/robots.txt +5 -0
- data/spec/spec_helper.rb +112 -0
- data/spec/warbler/application_spec.rb +95 -0
- data/spec/warbler/bundler_spec.rb +136 -0
- data/spec/warbler/config_spec.rb +130 -0
- data/spec/warbler/gems_spec.rb +40 -0
- data/spec/warbler/jar_spec.rb +718 -0
- data/spec/warbler/task_spec.rb +170 -0
- data/spec/warbler/traits_spec.rb +17 -0
- data/spec/warbler/war_spec.rb +14 -0
- data/warble.rb +142 -0
- data/web.xml.erb +32 -0
- metadata +198 -0
data/Rakefile
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2010-2011 Engine Yard, Inc.
|
3
|
+
# Copyright (c) 2007-2009 Sun Microsystems, Inc.
|
4
|
+
# This source code is available under the MIT license.
|
5
|
+
# See the file LICENSE.txt for details.
|
6
|
+
#++
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'bundler/setup'
|
10
|
+
rescue LoadError
|
11
|
+
puts "Please install Bundler and run 'bundle install' to ensure you have all dependencies"
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'spec/rake/spectask'
|
15
|
+
require 'spec/rake/verify_rcov'
|
16
|
+
|
17
|
+
MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt", "Gemfile",
|
18
|
+
"LICENSE.txt", "Rakefile", "*.erb", "*.rb", "bin/*",
|
19
|
+
"ext/**/*", "lib/**/*", "spec/**/*.rb", "spec/sample*/**/*.*"
|
20
|
+
].to_a.reject{|f| f=~%r{spec/sample/(MANIFEST|link|web.xml)}}.sort.uniq
|
21
|
+
|
22
|
+
begin
|
23
|
+
File.open("Manifest.txt", "wb") {|f| MANIFEST.each {|n| f << "#{n}\n"} }
|
24
|
+
require 'hoe'
|
25
|
+
require File.dirname(__FILE__) + '/lib/warbler/version'
|
26
|
+
Hoe.plugin :rubyforge
|
27
|
+
hoe = Hoe.spec("warbler") do |p|
|
28
|
+
p.version = Warbler::VERSION
|
29
|
+
p.rubyforge_name = "caldersphere"
|
30
|
+
p.url = "http://caldersphere.rubyforge.org/warbler"
|
31
|
+
p.author = "Nick Sieger"
|
32
|
+
p.email = "nick@nicksieger.com"
|
33
|
+
p.summary = "Warbler chirpily constructs .war files of your Rails applications."
|
34
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
35
|
+
p.description = p.paragraphs_of('README.txt', 1...2).join("\n\n")
|
36
|
+
p.extra_deps += [['rake', '~> 0.8.7'], ['jruby-jars', '>= 1.4.0'], ['jruby-rack', '>= 1.0.0'], ['rubyzip', '>= 0.9.4']]
|
37
|
+
p.clean_globs += %w(MANIFEST web.xml init.rb).map{|f| "spec/sample*/#{f}*" }
|
38
|
+
end
|
39
|
+
hoe.spec.files = MANIFEST
|
40
|
+
hoe.spec.rdoc_options += ["-SHN", "-f", "darkfish"]
|
41
|
+
|
42
|
+
task :gemspec do
|
43
|
+
File.open("#{hoe.name}.gemspec", "w") {|f| f << hoe.spec.to_ruby }
|
44
|
+
end
|
45
|
+
task :package => :gemspec
|
46
|
+
rescue LoadError
|
47
|
+
puts "You really need Hoe installed to be able to package this gem"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Leave my tasks alone, Hoe
|
51
|
+
%w(default spec rcov).each do |task|
|
52
|
+
Rake::Task[task].prerequisites.clear
|
53
|
+
Rake::Task[task].actions.clear
|
54
|
+
end
|
55
|
+
|
56
|
+
Spec::Rake::SpecTask.new do |t|
|
57
|
+
t.spec_opts ||= []
|
58
|
+
t.spec_opts << "--options" << "spec/spec.opts"
|
59
|
+
end
|
60
|
+
|
61
|
+
Spec::Rake::SpecTask.new("spec:rcov") do |t|
|
62
|
+
t.spec_opts ||= []
|
63
|
+
t.spec_opts << "--options" << "spec/spec.opts"
|
64
|
+
t.rcov_opts ||= []
|
65
|
+
t.rcov_opts << "-x" << "/gems/"
|
66
|
+
t.rcov = true
|
67
|
+
end
|
68
|
+
|
69
|
+
RCov::VerifyTask.new(:rcov => "spec:rcov") do |t|
|
70
|
+
t.threshold = 100
|
71
|
+
end
|
72
|
+
|
73
|
+
task :default => :spec
|
74
|
+
|
75
|
+
desc "Compile and jar the Warbler Java helper classes"
|
76
|
+
begin
|
77
|
+
require 'ant'
|
78
|
+
task :jar => :compile do
|
79
|
+
ant.jar :basedir => "pkg/classes", :destfile => "lib/warbler_jar.jar", :includes => "*.class"
|
80
|
+
end
|
81
|
+
|
82
|
+
directory "pkg/classes"
|
83
|
+
task :compile => "pkg/classes" do |t|
|
84
|
+
ant.javac :srcdir => "ext", :destdir => t.prerequisites.first,
|
85
|
+
:source => "1.5", :target => "1.5", :debug => true,
|
86
|
+
:classpath => "${java.class.path}:${sun.boot.class.path}",
|
87
|
+
:includeantRuntime => false
|
88
|
+
end
|
89
|
+
rescue LoadError
|
90
|
+
task :jar do
|
91
|
+
puts "Run 'jar' with JRuby >= 1.5 to re-compile the java jar booster"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Make sure jar gets compiled before the gem is built
|
96
|
+
task Rake::Task['gem'].prerequisites.first => :jar
|
97
|
+
|
98
|
+
task :warbler_jar => 'pkg' do
|
99
|
+
ruby "-rubygems", "-Ilib", "-S", "bin/warble"
|
100
|
+
mv "warbler.jar", "pkg/warbler-#{Warbler::VERSION}.jar"
|
101
|
+
end
|
102
|
+
|
103
|
+
task :package => :warbler_jar
|
data/bin/warble
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# Copyright (c) 2010-2011 Engine Yard, Inc.
|
5
|
+
# Copyright (c) 2007-2009 Sun Microsystems, Inc.
|
6
|
+
# This source code is available under the MIT license.
|
7
|
+
# See the file LICENSE.txt for details.
|
8
|
+
#++
|
9
|
+
|
10
|
+
require 'warbler'
|
11
|
+
Warbler::Application.new.run
|
data/ext/JarMain.java
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2010-2011 Engine Yard, Inc.
|
3
|
+
* Copyright (c) 2007-2009 Sun Microsystems, Inc.
|
4
|
+
* This source code is available under the MIT license.
|
5
|
+
* See the file LICENSE.txt for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
import java.io.File;
|
9
|
+
import java.io.FileOutputStream;
|
10
|
+
import java.io.InputStream;
|
11
|
+
import java.lang.reflect.Method;
|
12
|
+
import java.net.URL;
|
13
|
+
import java.net.URLClassLoader;
|
14
|
+
import java.util.ArrayList;
|
15
|
+
import java.util.Arrays;
|
16
|
+
import java.util.Enumeration;
|
17
|
+
import java.util.List;
|
18
|
+
import java.util.jar.JarEntry;
|
19
|
+
import java.util.jar.JarFile;
|
20
|
+
|
21
|
+
public class JarMain implements Runnable {
|
22
|
+
public static final String MAIN = "/" + JarMain.class.getName().replace('.', '/') + ".class";
|
23
|
+
|
24
|
+
private String[] args;
|
25
|
+
private String path, jarfile;
|
26
|
+
private boolean debug;
|
27
|
+
private File extractRoot;
|
28
|
+
|
29
|
+
public JarMain(String[] args) throws Exception {
|
30
|
+
this.args = args;
|
31
|
+
URL mainClass = getClass().getResource(MAIN);
|
32
|
+
this.path = mainClass.toURI().getSchemeSpecificPart();
|
33
|
+
this.jarfile = this.path.replace("!" + MAIN, "").replace("file:", "");
|
34
|
+
this.debug = isDebug();
|
35
|
+
this.extractRoot = File.createTempFile("jruby", "extract");
|
36
|
+
this.extractRoot.delete();
|
37
|
+
this.extractRoot.mkdirs();
|
38
|
+
Runtime.getRuntime().addShutdownHook(new Thread(this));
|
39
|
+
}
|
40
|
+
|
41
|
+
private URL[] extractJRuby() throws Exception {
|
42
|
+
JarFile jf = new JarFile(this.jarfile);
|
43
|
+
List<String> jarNames = new ArrayList<String>();
|
44
|
+
for (Enumeration<JarEntry> eje = jf.entries(); eje.hasMoreElements(); ) {
|
45
|
+
String name = eje.nextElement().getName();
|
46
|
+
if (name.startsWith("META-INF/lib") && name.endsWith(".jar")) {
|
47
|
+
jarNames.add("/" + name);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
List<URL> urls = new ArrayList<URL>();
|
52
|
+
for (String name : jarNames) {
|
53
|
+
urls.add(extractJar(name));
|
54
|
+
}
|
55
|
+
|
56
|
+
return (URL[]) urls.toArray(new URL[urls.size()]);
|
57
|
+
}
|
58
|
+
|
59
|
+
private URL extractJar(String jarpath) throws Exception {
|
60
|
+
InputStream jarStream = new URL("jar:" + path.replace(MAIN, jarpath)).openStream();
|
61
|
+
String jarname = jarpath.substring(jarpath.lastIndexOf("/") + 1, jarpath.lastIndexOf("."));
|
62
|
+
File jarFile = new File(extractRoot, jarname + ".jar");
|
63
|
+
jarFile.deleteOnExit();
|
64
|
+
FileOutputStream outStream = new FileOutputStream(jarFile);
|
65
|
+
try {
|
66
|
+
byte[] buf = new byte[65536];
|
67
|
+
int bytesRead = 0;
|
68
|
+
while ((bytesRead = jarStream.read(buf)) != -1) {
|
69
|
+
outStream.write(buf, 0, bytesRead);
|
70
|
+
}
|
71
|
+
} finally {
|
72
|
+
jarStream.close();
|
73
|
+
outStream.close();
|
74
|
+
}
|
75
|
+
debug(jarname + ".jar extracted to " + jarFile.getPath());
|
76
|
+
return jarFile.toURI().toURL();
|
77
|
+
}
|
78
|
+
|
79
|
+
private int launchJRuby(URL[] jars) throws Exception {
|
80
|
+
System.setProperty("org.jruby.embed.class.path", "");
|
81
|
+
URLClassLoader loader = new URLClassLoader(jars);
|
82
|
+
Class scriptingContainerClass = Class.forName("org.jruby.embed.ScriptingContainer", true, loader);
|
83
|
+
Object scriptingContainer = scriptingContainerClass.newInstance();
|
84
|
+
|
85
|
+
Method argv = scriptingContainerClass.getDeclaredMethod("setArgv", new Class[] {String[].class});
|
86
|
+
argv.invoke(scriptingContainer, new Object[] {args});
|
87
|
+
Method setClassLoader = scriptingContainerClass.getDeclaredMethod("setClassLoader", new Class[] {ClassLoader.class});
|
88
|
+
setClassLoader.invoke(scriptingContainer, new Object[] {loader});
|
89
|
+
debug("invoking " + jarfile + " with: " + Arrays.deepToString(args));
|
90
|
+
|
91
|
+
Method runScriptlet = scriptingContainerClass.getDeclaredMethod("runScriptlet", new Class[] {String.class});
|
92
|
+
return ((Number) runScriptlet.invoke(scriptingContainer, new Object[] {
|
93
|
+
"begin\n" +
|
94
|
+
"require 'META-INF/init.rb'\n" +
|
95
|
+
"require 'META-INF/main.rb'\n" +
|
96
|
+
"0\n" +
|
97
|
+
"rescue SystemExit => e\n" +
|
98
|
+
"e.status\n" +
|
99
|
+
"end"
|
100
|
+
})).intValue();
|
101
|
+
}
|
102
|
+
|
103
|
+
private int start() throws Exception {
|
104
|
+
URL[] u = extractJRuby();
|
105
|
+
return launchJRuby(u);
|
106
|
+
}
|
107
|
+
|
108
|
+
private void debug(String msg) {
|
109
|
+
if (debug) {
|
110
|
+
System.out.println(msg);
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
private void delete(File f) {
|
115
|
+
if (f.isDirectory()) {
|
116
|
+
File[] children = f.listFiles();
|
117
|
+
for (int i = 0; i < children.length; i++) {
|
118
|
+
delete(children[i]);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
f.delete();
|
122
|
+
}
|
123
|
+
|
124
|
+
public void run() {
|
125
|
+
delete(extractRoot);
|
126
|
+
}
|
127
|
+
|
128
|
+
public static void main(String[] args) {
|
129
|
+
try {
|
130
|
+
int exit = new JarMain(args).start();
|
131
|
+
System.exit(exit);
|
132
|
+
} catch (Exception e) {
|
133
|
+
Throwable t = e;
|
134
|
+
while (t.getCause() != null && t.getCause() != t) {
|
135
|
+
t = t.getCause();
|
136
|
+
}
|
137
|
+
|
138
|
+
if (isDebug()) {
|
139
|
+
t.printStackTrace();
|
140
|
+
}
|
141
|
+
System.exit(1);
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
private static boolean isDebug() {
|
146
|
+
return System.getProperty("warbler.debug") != null;
|
147
|
+
}
|
148
|
+
}
|
data/ext/WarMain.java
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2010-2011 Engine Yard, Inc.
|
3
|
+
* Copyright (c) 2007-2009 Sun Microsystems, Inc.
|
4
|
+
* This source code is available under the MIT license.
|
5
|
+
* See the file LICENSE.txt for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
import java.net.URLClassLoader;
|
9
|
+
import java.net.URL;
|
10
|
+
import java.lang.reflect.Method;
|
11
|
+
import java.io.IOException;
|
12
|
+
import java.io.InputStream;
|
13
|
+
import java.io.File;
|
14
|
+
import java.io.FileOutputStream;
|
15
|
+
import java.util.Arrays;
|
16
|
+
|
17
|
+
public class WarMain implements Runnable {
|
18
|
+
public static final String MAIN = "/" + WarMain.class.getName().replace('.', '/') + ".class";
|
19
|
+
public static final String WINSTONE_JAR = "/WEB-INF/winstone.jar";
|
20
|
+
|
21
|
+
private String[] args;
|
22
|
+
private String path, warfile;
|
23
|
+
private boolean debug;
|
24
|
+
private File webroot;
|
25
|
+
|
26
|
+
public WarMain(String[] args) throws Exception {
|
27
|
+
this.args = args;
|
28
|
+
URL mainClass = getClass().getResource(MAIN);
|
29
|
+
this.path = mainClass.toURI().getSchemeSpecificPart();
|
30
|
+
this.warfile = this.path.replace("!" + MAIN, "").replace("file:", "");
|
31
|
+
this.debug = isDebug();
|
32
|
+
this.webroot = File.createTempFile("winstone", "webroot");
|
33
|
+
this.webroot.delete();
|
34
|
+
this.webroot.mkdirs();
|
35
|
+
this.webroot = new File(this.webroot, new File(warfile).getName());
|
36
|
+
Runtime.getRuntime().addShutdownHook(new Thread(this));
|
37
|
+
}
|
38
|
+
|
39
|
+
private URL extractWinstone() throws Exception {
|
40
|
+
InputStream jarStream = new URL("jar:" + path.replace(MAIN, WINSTONE_JAR)).openStream();
|
41
|
+
File jarFile = File.createTempFile("winstone", ".jar");
|
42
|
+
jarFile.deleteOnExit();
|
43
|
+
FileOutputStream outStream = new FileOutputStream(jarFile);
|
44
|
+
try {
|
45
|
+
byte[] buf = new byte[4096];
|
46
|
+
int bytesRead = 0;
|
47
|
+
while ((bytesRead = jarStream.read(buf)) != -1) {
|
48
|
+
outStream.write(buf, 0, bytesRead);
|
49
|
+
}
|
50
|
+
} finally {
|
51
|
+
jarStream.close();
|
52
|
+
outStream.close();
|
53
|
+
}
|
54
|
+
debug("winstone.jar extracted to " + jarFile.getPath());
|
55
|
+
return jarFile.toURI().toURL();
|
56
|
+
}
|
57
|
+
|
58
|
+
private void launchWinstone(URL jar) throws Exception {
|
59
|
+
URLClassLoader loader = new URLClassLoader(new URL[] {jar});
|
60
|
+
Class klass = Class.forName("winstone.Launcher", true, loader);
|
61
|
+
Method main = klass.getDeclaredMethod("main", new Class[] {String[].class});
|
62
|
+
String[] newargs = new String[args.length + 3];
|
63
|
+
newargs[0] = "--warfile=" + warfile;
|
64
|
+
newargs[1] = "--webroot=" + webroot;
|
65
|
+
newargs[2] = "--directoryListings=false";
|
66
|
+
System.arraycopy(args, 0, newargs, 3, args.length);
|
67
|
+
debug("invoking Winstone with: " + Arrays.deepToString(newargs));
|
68
|
+
main.invoke(null, new Object[] {newargs});
|
69
|
+
}
|
70
|
+
|
71
|
+
private void start() throws Exception {
|
72
|
+
URL u = extractWinstone();
|
73
|
+
launchWinstone(u);
|
74
|
+
}
|
75
|
+
|
76
|
+
private void debug(String msg) {
|
77
|
+
if (debug) {
|
78
|
+
System.out.println(msg);
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
private void delete(File f) {
|
83
|
+
if (f.isDirectory()) {
|
84
|
+
File[] children = f.listFiles();
|
85
|
+
for (int i = 0; i < children.length; i++) {
|
86
|
+
delete(children[i]);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
f.delete();
|
90
|
+
}
|
91
|
+
|
92
|
+
public void run() {
|
93
|
+
delete(webroot.getParentFile());
|
94
|
+
}
|
95
|
+
|
96
|
+
public static void main(String[] args) {
|
97
|
+
try {
|
98
|
+
new WarMain(args).start();
|
99
|
+
} catch (Exception e) {
|
100
|
+
System.err.println("error: " + e.toString());
|
101
|
+
if (isDebug()) {
|
102
|
+
e.printStackTrace();
|
103
|
+
}
|
104
|
+
System.exit(1);
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
private static boolean isDebug() {
|
109
|
+
return System.getProperty("warbler.debug") != null;
|
110
|
+
}
|
111
|
+
}
|
112
|
+
|
data/ext/WarblerJar.java
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (c) 2010-2011 Engine Yard, Inc.
|
3
|
+
* Copyright (c) 2007-2009 Sun Microsystems, Inc.
|
4
|
+
* This source code is available under the MIT license.
|
5
|
+
* See the file LICENSE.txt for details.
|
6
|
+
*/
|
7
|
+
|
8
|
+
import java.io.Closeable;
|
9
|
+
import java.io.File;
|
10
|
+
import java.io.FileInputStream;
|
11
|
+
import java.io.FileNotFoundException;
|
12
|
+
import java.io.FileOutputStream;
|
13
|
+
import java.io.IOException;
|
14
|
+
import java.io.InputStream;
|
15
|
+
import java.util.regex.Matcher;
|
16
|
+
import java.util.regex.Pattern;
|
17
|
+
import java.util.zip.ZipEntry;
|
18
|
+
import java.util.zip.ZipInputStream;
|
19
|
+
import java.util.zip.ZipOutputStream;
|
20
|
+
|
21
|
+
import org.jruby.Ruby;
|
22
|
+
import org.jruby.RubyArray;
|
23
|
+
import org.jruby.RubyHash;
|
24
|
+
import org.jruby.RubyModule;
|
25
|
+
import org.jruby.RubyString;
|
26
|
+
import org.jruby.anno.JRubyMethod;
|
27
|
+
import org.jruby.runtime.Block;
|
28
|
+
import org.jruby.runtime.ThreadContext;
|
29
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
30
|
+
import org.jruby.util.ByteList;
|
31
|
+
import org.jruby.util.JRubyFile;
|
32
|
+
|
33
|
+
public class WarblerJar {
|
34
|
+
public static void create(Ruby runtime) {
|
35
|
+
RubyModule task = runtime.getClassFromPath("Warbler::Jar");
|
36
|
+
task.defineAnnotatedMethods(WarblerJar.class);
|
37
|
+
}
|
38
|
+
|
39
|
+
@JRubyMethod
|
40
|
+
public static IRubyObject create_jar(ThreadContext context, IRubyObject recv, IRubyObject jar_path, IRubyObject entries) {
|
41
|
+
final Ruby runtime = recv.getRuntime();
|
42
|
+
|
43
|
+
if (!(entries instanceof RubyHash)) {
|
44
|
+
throw runtime.newArgumentError("expected a hash for the second argument");
|
45
|
+
}
|
46
|
+
|
47
|
+
RubyHash hash = (RubyHash) entries;
|
48
|
+
try {
|
49
|
+
FileOutputStream file = newFile(jar_path);
|
50
|
+
try {
|
51
|
+
ZipOutputStream zip = new ZipOutputStream(file);
|
52
|
+
addEntries(context, zip, hash);
|
53
|
+
zip.finish();
|
54
|
+
} finally {
|
55
|
+
close(file);
|
56
|
+
}
|
57
|
+
} catch (IOException e) {
|
58
|
+
if (runtime.isDebug()) {
|
59
|
+
e.printStackTrace();
|
60
|
+
}
|
61
|
+
throw runtime.newIOErrorFromException(e);
|
62
|
+
}
|
63
|
+
|
64
|
+
return runtime.getNil();
|
65
|
+
}
|
66
|
+
|
67
|
+
@JRubyMethod
|
68
|
+
public static IRubyObject entry_in_jar(ThreadContext context, IRubyObject recv, IRubyObject jar_path, IRubyObject entry) {
|
69
|
+
final Ruby runtime = recv.getRuntime();
|
70
|
+
try {
|
71
|
+
InputStream entryStream = getStream(jar_path.convertToString().getUnicodeValue(),
|
72
|
+
entry.convertToString().getUnicodeValue());
|
73
|
+
try {
|
74
|
+
byte[] buf = new byte[16384];
|
75
|
+
ByteList blist = new ByteList();
|
76
|
+
int bytesRead = -1;
|
77
|
+
while ((bytesRead = entryStream.read(buf)) != -1) {
|
78
|
+
blist.append(buf, 0, bytesRead);
|
79
|
+
}
|
80
|
+
IRubyObject stringio = runtime.getModule("StringIO");
|
81
|
+
return stringio.callMethod(context, "new", runtime.newString(blist));
|
82
|
+
} finally {
|
83
|
+
close(entryStream);
|
84
|
+
}
|
85
|
+
} catch (IOException e) {
|
86
|
+
if (runtime.isDebug()) {
|
87
|
+
e.printStackTrace();
|
88
|
+
}
|
89
|
+
throw runtime.newIOErrorFromException(e);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
private static void addEntries(ThreadContext context, ZipOutputStream zip, RubyHash entries) throws IOException {
|
94
|
+
RubyArray keys = entries.keys().sort(context, Block.NULL_BLOCK);
|
95
|
+
for (int i = 0; i < keys.getLength(); i++) {
|
96
|
+
IRubyObject key = keys.entry(i);
|
97
|
+
IRubyObject value = entries.op_aref(context, key);
|
98
|
+
addEntry(context, zip, key.convertToString().getUnicodeValue(), value);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
private static void addEntry(ThreadContext context, ZipOutputStream zip, String entryName, IRubyObject value) throws IOException {
|
103
|
+
if (value.respondsTo("read")) {
|
104
|
+
RubyString str = (RubyString) value.callMethod(context, "read").checkStringType();
|
105
|
+
byte[] contents = str.getByteList().getUnsafeBytes();
|
106
|
+
zip.putNextEntry(new ZipEntry(entryName));
|
107
|
+
zip.write(contents);
|
108
|
+
} else {
|
109
|
+
File f;
|
110
|
+
if (value.isNil() || (f = getFile(value)).isDirectory()) {
|
111
|
+
zip.putNextEntry(new ZipEntry(entryName + "/"));
|
112
|
+
} else {
|
113
|
+
String path = f.getPath();
|
114
|
+
if (!f.exists()) {
|
115
|
+
path = value.convertToString().getUnicodeValue();
|
116
|
+
}
|
117
|
+
|
118
|
+
InputStream inFile = getStream(path, null);
|
119
|
+
try {
|
120
|
+
zip.putNextEntry(new ZipEntry(entryName));
|
121
|
+
byte[] buf = new byte[16384];
|
122
|
+
int bytesRead = -1;
|
123
|
+
while ((bytesRead = inFile.read(buf)) != -1) {
|
124
|
+
zip.write(buf, 0, bytesRead);
|
125
|
+
}
|
126
|
+
} finally {
|
127
|
+
close(inFile);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
private static FileOutputStream newFile(IRubyObject jar_path) throws IOException {
|
134
|
+
return new FileOutputStream(getFile(jar_path));
|
135
|
+
}
|
136
|
+
|
137
|
+
private static File getFile(IRubyObject path) {
|
138
|
+
return JRubyFile.create(path.getRuntime().getCurrentDirectory(),
|
139
|
+
path.convertToString().getUnicodeValue());
|
140
|
+
}
|
141
|
+
|
142
|
+
private static void close(Closeable c) {
|
143
|
+
try {
|
144
|
+
c.close();
|
145
|
+
} catch (Exception e) {
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
private static Pattern PROTOCOL = Pattern.compile("^[a-z][a-z0-9]+:");
|
150
|
+
|
151
|
+
private static InputStream getStream(String jar, String entry) throws IOException {
|
152
|
+
Matcher m = PROTOCOL.matcher(jar);
|
153
|
+
while (m.find()) {
|
154
|
+
jar = jar.substring(m.end());
|
155
|
+
m = PROTOCOL.matcher(jar);
|
156
|
+
}
|
157
|
+
|
158
|
+
String[] path = jar.split("!/");
|
159
|
+
InputStream stream = new FileInputStream(path[0]);
|
160
|
+
for (int i = 1; i < path.length; i++) {
|
161
|
+
stream = entryInJar(stream, path[i]);
|
162
|
+
}
|
163
|
+
|
164
|
+
if (entry == null) {
|
165
|
+
return stream;
|
166
|
+
}
|
167
|
+
|
168
|
+
return entryInJar(stream, entry);
|
169
|
+
}
|
170
|
+
|
171
|
+
private static InputStream entryInJar(InputStream jar, String entry) throws IOException {
|
172
|
+
ZipInputStream jstream = new ZipInputStream(jar);
|
173
|
+
ZipEntry zentry = null;
|
174
|
+
while ((zentry = jstream.getNextEntry()) != null) {
|
175
|
+
if (zentry.getName().equals(entry)) {
|
176
|
+
return jstream;
|
177
|
+
}
|
178
|
+
jstream.closeEntry();
|
179
|
+
}
|
180
|
+
throw new FileNotFoundException("entry '" + entry + "' not found in " + jar);
|
181
|
+
}
|
182
|
+
}
|