On Thu, 29 Jun 2006, Charles O Nutter defenestrated me: > > Whee!
I needed to do a surprising additional number of things to get rails silence_stderr working with this patch. Here is a break- down: 1. reopen with string as first arg should retain permissions/modes of IO it is reopening. I believe this has to be right. 2. dup should retain dup'd objects permissions/modes. This also seems like a for sure thing. 3. reopen needed same /dev/null check that RubyFile has in reopen. As hacky as hacky gets. 4. IOHandlerUnseekable now refuses to close System.out and System.err. This is also a hack. The solution involves much too much stuff to be safe right now. Really a io.dup should clone the underlying IOHandler. If multiple IO's point to same underlying stream then a close should not really close the underlying stream. I believe this is consistent with C FILE* and friends (C Ruby semantics I think rely on FILE* and friends)? Please look this over. I would like to include this for 0.9.0 since it makes Rails commands that perform command checks work without needing to patch Rails. -Tom -- + http://www.tc.umn.edu/~enebo +---- mailto:[EMAIL PROTECTED] ----+ | Thomas E Enebo, Protagonist | "Luck favors the prepared | | | mind." -Louis Pasteur |
Index: org/jruby/RubyFile.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/RubyFile.java,v retrieving revision 1.40 diff -u -r1.40 RubyFile.java --- org/jruby/RubyFile.java 30 May 2006 17:52:48 -0000 1.40 +++ org/jruby/RubyFile.java 30 Jun 2006 02:59:35 -0000 @@ -44,6 +44,7 @@ import org.jruby.exceptions.RaiseException; import org.jruby.runtime.builtin.IRubyObject; import org.jruby.util.IOHandler; +import org.jruby.util.IOHandlerNull; import org.jruby.util.IOHandlerSeekable; import org.jruby.util.IOHandlerUnseekable; import org.jruby.util.IOModes; @@ -105,9 +106,13 @@ public void openInternal(String newPath, IOModes newModes) { this.path = newPath; this.modes = newModes; - + try { - handler = new IOHandlerSeekable(getRuntime(), newPath, newModes); + if (newPath.equals("/dev/null")) { + handler = new IOHandlerNull(getRuntime(), newModes); + } else { + handler = new IOHandlerSeekable(getRuntime(), newPath, newModes); + } registerIOHandler(handler); } catch (InvalidValueException e) { Index: org/jruby/RubyIO.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/RubyIO.java,v retrieving revision 1.55 diff -u -r1.55 RubyIO.java --- org/jruby/RubyIO.java 28 Jun 2006 02:25:51 -0000 1.55 +++ org/jruby/RubyIO.java 30 Jun 2006 02:59:37 -0000 @@ -45,6 +45,7 @@ import org.jruby.util.IOHandler; import org.jruby.util.IOHandlerJavaIO; import org.jruby.util.IOHandlerNio; +import org.jruby.util.IOHandlerNull; import org.jruby.util.IOHandlerProcess; import org.jruby.util.IOHandlerSeekable; import org.jruby.util.IOHandlerUnseekable; @@ -333,21 +334,29 @@ registerIOHandler(handler); } else if (args[0].isKindOf(getRuntime().getClass("String"))) { String path = ((RubyString) args[0]).toString(); - String mode = "r"; + IOModes newModes = null; + if (args.length > 1) { if (!args[1].isKindOf(getRuntime().getClass("String"))) { throw getRuntime().newTypeError(args[1], getRuntime().getClass("String")); } - mode = ((RubyString) args[1]).toString(); + newModes = new IOModes(getRuntime(), ((RubyString) args[1]).toString()); } try { if (handler != null) { close(); } - modes = new IOModes(getRuntime(), mode); - handler = new IOHandlerSeekable(getRuntime(), path, modes); + + if (newModes != null) { + modes = newModes; + } + if ("/dev/null".equals(path)) { + handler = new IOHandlerNull(getRuntime(), modes); + } else { + handler = new IOHandlerSeekable(getRuntime(), path, modes); + } registerIOHandler(handler); } catch (IOHandler.InvalidValueException e) { @@ -743,6 +752,7 @@ // copy of the handler. In fact, ruby 1.8 must do this as the cloned // resource is in fact a different fileno. What is clone for again? io.handler = handler; + io.modes = (IOModes) modes.clone(); return io; } Index: org/jruby/util/IOHandlerUnseekable.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/util/IOHandlerUnseekable.java,v retrieving revision 1.16 diff -u -r1.16 IOHandlerUnseekable.java --- org/jruby/util/IOHandlerUnseekable.java 24 May 2006 01:34:04 -0000 1.16 +++ org/jruby/util/IOHandlerUnseekable.java 30 Jun 2006 02:59:38 -0000 @@ -163,7 +163,15 @@ } if (modes.isWriteable()) { - output.close(); + // Fixme: Only close underlying stream if it is not shared by another IO. + // HACK: We do not close these streams so that Rails silence_stderr will work. + // The real problem is that when silense_stderr clones STDERR, we do not actually + // clone the handler AND get a new fileno. The importance of this is coupled + // with the above Fixme, that we need to make sure we only close underlying streams + // that are not shared by multiple IOHandlers (at least I believe this to be true). + if (output != System.out && output != System.err) { + output.close(); + } } } Index: org/jruby/util/IOModes.java =================================================================== RCS file: /cvsroot/jruby/jruby/src/org/jruby/util/IOModes.java,v retrieving revision 1.11 diff -u -r1.11 IOModes.java --- org/jruby/util/IOModes.java 22 Jun 2006 02:11:16 -0000 1.11 +++ org/jruby/util/IOModes.java 30 Jun 2006 02:59:38 -0000 @@ -56,6 +56,10 @@ this.runtime = runtime; } + public Object clone() { + return new IOModes(runtime, modes); + } + public IOModes(IRuby runtime, String modesString) { this(runtime, convertModesStringToModesInt(runtime, modesString)); } Index: org/jruby/util/IOHandlerNull.java =================================================================== RCS file: org/jruby/util/IOHandlerNull.java diff -N org/jruby/util/IOHandlerNull.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ org/jruby/util/IOHandlerNull.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,101 @@ +package org.jruby.util; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.channels.FileChannel; + +import org.jruby.IRuby; + +public class IOHandlerNull extends IOHandler { + + public IOHandlerNull(IRuby runtime, IOModes modes) { + super(runtime); + + this.modes = modes; + } + + public FileChannel getFileChannel() { + // TODO Auto-generated method stub + return null; + } + + public String gets(String separatorString) throws IOException, + BadDescriptorException, EOFException { + throw new EOFException(); + } + + public String getsEntireStream() throws IOException, + BadDescriptorException, EOFException { + throw new EOFException(); + } + + public String read(int number) throws IOException, BadDescriptorException, + EOFException { + throw new EOFException(); + } + + public int write(String string) throws IOException, BadDescriptorException { + return string.length(); + } + + public int getc() throws IOException, BadDescriptorException, EOFException { + throw new EOFException(); + } + + public void ungetc(int c) { + } + + public void putc(int c) throws IOException, BadDescriptorException { + } + + public String sysread(int number) throws IOException, + BadDescriptorException, EOFException { + throw new EOFException(); + } + + public int syswrite(String buf) throws IOException, BadDescriptorException { + return buf.length(); + } + + public IOHandler cloneIOHandler() throws IOException, PipeException, + InvalidValueException { + return null; + } + + public void close() throws IOException, BadDescriptorException { + } + + public void flush() throws IOException, BadDescriptorException { + } + + public void sync() throws IOException, BadDescriptorException { + } + + public boolean isEOF() throws IOException, BadDescriptorException { + return true; + } + + public int pid() { + return 0; + } + + public long pos() throws IOException, PipeException { + return 0; + } + + protected void resetByModes(IOModes newModes) throws IOException, + InvalidValueException { + } + + public void rewind() throws IOException, PipeException, + InvalidValueException { + } + + public void seek(long offset, int type) throws IOException, PipeException, + InvalidValueException { + } + + public void truncate(long newLength) throws IOException, PipeException { + } + +}
Using Tomcat but need to do more? Need to support web services, security? Get stuff done quickly with pre-integrated technology to make your job easier Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________ Jruby-devel mailing list Jruby-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jruby-devel