lucidimagination-warbler 1.3.2.dev

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 (75) hide show
  1. data/Gemfile +16 -0
  2. data/History.txt +217 -0
  3. data/LICENSE.txt +26 -0
  4. data/Manifest.txt +92 -0
  5. data/README.txt +255 -0
  6. data/Rakefile +103 -0
  7. data/bin/warble +11 -0
  8. data/ext/JarMain.java +148 -0
  9. data/ext/WarMain.java +112 -0
  10. data/ext/WarblerJar.java +182 -0
  11. data/ext/WarblerJarService.java +18 -0
  12. data/lib/warbler.rb +33 -0
  13. data/lib/warbler/application.rb +86 -0
  14. data/lib/warbler/config.rb +223 -0
  15. data/lib/warbler/gems.rb +37 -0
  16. data/lib/warbler/jar.rb +253 -0
  17. data/lib/warbler/task.rb +183 -0
  18. data/lib/warbler/templates/bundler.erb +3 -0
  19. data/lib/warbler/templates/config.erb +1 -0
  20. data/lib/warbler/templates/jar.erb +5 -0
  21. data/lib/warbler/templates/rack.erb +1 -0
  22. data/lib/warbler/templates/rails.erb +1 -0
  23. data/lib/warbler/templates/war.erb +1 -0
  24. data/lib/warbler/traits.rb +107 -0
  25. data/lib/warbler/traits/bundler.rb +104 -0
  26. data/lib/warbler/traits/gemspec.rb +59 -0
  27. data/lib/warbler/traits/jar.rb +56 -0
  28. data/lib/warbler/traits/merb.rb +35 -0
  29. data/lib/warbler/traits/nogemspec.rb +42 -0
  30. data/lib/warbler/traits/rack.rb +33 -0
  31. data/lib/warbler/traits/rails.rb +62 -0
  32. data/lib/warbler/traits/war.rb +197 -0
  33. data/lib/warbler/version.rb +10 -0
  34. data/lib/warbler/war.rb +8 -0
  35. data/lib/warbler_jar.jar +0 -0
  36. data/spec/drb_helper.rb +41 -0
  37. data/spec/sample_bundler/Gemfile.lock +10 -0
  38. data/spec/sample_bundler/config.ru +0 -0
  39. data/spec/sample_jar/History.txt +6 -0
  40. data/spec/sample_jar/Manifest.txt +8 -0
  41. data/spec/sample_jar/README.txt +30 -0
  42. data/spec/sample_jar/lib/sample_jar.rb +6 -0
  43. data/spec/sample_jar/sample_jar.gemspec +40 -0
  44. data/spec/sample_jar/test/test_sample_jar.rb +8 -0
  45. data/spec/sample_war/app/controllers/application.rb +15 -0
  46. data/spec/sample_war/app/helpers/application_helper.rb +3 -0
  47. data/spec/sample_war/config/boot.rb +109 -0
  48. data/spec/sample_war/config/database.yml +19 -0
  49. data/spec/sample_war/config/environment.rb +67 -0
  50. data/spec/sample_war/config/environments/development.rb +17 -0
  51. data/spec/sample_war/config/environments/production.rb +25 -0
  52. data/spec/sample_war/config/environments/test.rb +22 -0
  53. data/spec/sample_war/config/initializers/inflections.rb +10 -0
  54. data/spec/sample_war/config/initializers/mime_types.rb +5 -0
  55. data/spec/sample_war/config/initializers/new_rails_defaults.rb +15 -0
  56. data/spec/sample_war/config/routes.rb +41 -0
  57. data/spec/sample_war/lib/tasks/utils.rake +0 -0
  58. data/spec/sample_war/public/404.html +30 -0
  59. data/spec/sample_war/public/422.html +30 -0
  60. data/spec/sample_war/public/500.html +30 -0
  61. data/spec/sample_war/public/favicon.ico +0 -0
  62. data/spec/sample_war/public/index.html +274 -0
  63. data/spec/sample_war/public/robots.txt +5 -0
  64. data/spec/spec_helper.rb +112 -0
  65. data/spec/warbler/application_spec.rb +95 -0
  66. data/spec/warbler/bundler_spec.rb +136 -0
  67. data/spec/warbler/config_spec.rb +130 -0
  68. data/spec/warbler/gems_spec.rb +40 -0
  69. data/spec/warbler/jar_spec.rb +718 -0
  70. data/spec/warbler/task_spec.rb +170 -0
  71. data/spec/warbler/traits_spec.rb +17 -0
  72. data/spec/warbler/war_spec.rb +14 -0
  73. data/warble.rb +142 -0
  74. data/web.xml.erb +32 -0
  75. metadata +198 -0
@@ -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
@@ -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
@@ -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
+ }
@@ -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
+
@@ -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
+ }