Skip to content

Commit

Permalink
extend nqp::shell/nqp::spawn with in/out/err/flags params
Browse files Browse the repository at this point in the history
This means that we can use shell() and run() in rakudo for purposes we
used pipe() for, but with extra freedom and flexibility.
nqp::openpipe, as well as nqp::shell1 and nqp::shell3 are removed.
  • Loading branch information
FROGGS committed Jun 26, 2015
1 parent 9d4c5d8 commit 9794dfa
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 114 deletions.
24 changes: 13 additions & 11 deletions src/vm/jvm/QAST/Compiler.nqp
Original file line number Diff line number Diff line change
Expand Up @@ -1980,6 +1980,16 @@ my %const_map := nqp::hash(
'STAT_PLATFORM_BLOCKSIZE', -6,
'STAT_PLATFORM_BLOCKS', -7,

'PIPE_INHERIT_IN', 1,
'PIPE_IGNORE_IN', 2,
'PIPE_CAPTURE_IN', 4,
'PIPE_INHERIT_OUT', 8,
'PIPE_IGNORE_OUT', 16,
'PIPE_CAPTURE_OUT', 32,
'PIPE_INHERIT_ERR', 64,
'PIPE_IGNORE_ERR', 128,
'PIPE_CAPTURE_ERR', 256,

'TYPE_CHECK_CACHE_DEFINITIVE', 0,
'TYPE_CHECK_CACHE_THEN_METHOD', 1,
'TYPE_CHECK_NEEDS_ACCEPTS', 2,
Expand Down Expand Up @@ -2055,17 +2065,9 @@ QAST::OperationsJAST.map_classlib_core_op('link', $TYPE_OPS, 'link', [$RT_STR, $

QAST::OperationsJAST.map_classlib_core_op('gethostname', $TYPE_OPS, 'gethostname', [], $RT_STR);

# Two variants of shell until we deprecate shell1
QAST::OperationsJAST.map_classlib_core_op('shell1', $TYPE_OPS, 'shell1', [$RT_STR], $RT_INT, :tc);
QAST::OperationsJAST.map_classlib_core_op('shell3', $TYPE_OPS, 'shell3', [$RT_STR, $RT_STR, $RT_OBJ], $RT_INT, :tc);
QAST::OperationsJAST.add_core_op('shell', -> $qastcomp, $op {
my @operands := $op.list;
$qastcomp.as_jast(+@operands == 1
?? QAST::Op.new( :op('shell1'), |@operands )
!! QAST::Op.new( :op('shell3'), |@operands ));
});
QAST::OperationsJAST.map_classlib_core_op('spawn', $TYPE_OPS, 'spawn', [$RT_OBJ, $RT_STR, $RT_OBJ], $RT_INT, :tc);
QAST::OperationsJAST.map_classlib_core_op('openpipe', $TYPE_OPS, 'openpipe', [$RT_STR, $RT_STR, $RT_OBJ, $RT_STR], $RT_OBJ, :tc);
QAST::OperationsJAST.map_classlib_core_op('shell', $TYPE_OPS, 'shell', [$RT_STR, $RT_STR, $RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_INT], $RT_INT, :tc);
QAST::OperationsJAST.map_classlib_core_op('spawn', $TYPE_OPS, 'spawn', [$RT_OBJ, $RT_STR, $RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_OBJ, $RT_INT], $RT_INT, :tc);
QAST::OperationsJAST.map_classlib_core_op('syncpipe', $TYPE_OPS, 'syncpipe', [], $RT_OBJ, :tc);

QAST::OperationsJAST.map_classlib_core_op('symlink', $TYPE_OPS, 'symlink', [$RT_STR, $RT_STR], $RT_INT, :tc);

Expand Down
67 changes: 51 additions & 16 deletions src/vm/jvm/runtime/org/perl6/nqp/io/ProcessChannel.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.perl6.nqp.io;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Expand All @@ -9,41 +8,77 @@
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.util.Map;

import org.perl6.nqp.runtime.ExceptionHandling;
import org.perl6.nqp.runtime.ThreadContext;

public class ProcessChannel implements ByteChannel {
protected WritableByteChannel stdin;
protected ReadableByteChannel stdout;
protected Process process;

public ProcessChannel(Process process, OutputStream stdin, InputStream stdout) {
this.stdin = Channels.newChannel(stdin);
this.stdout = Channels.newChannel(stdout);
public class ProcessChannel implements ByteChannel, java.lang.Runnable {
public WritableByteChannel out;
public OutputStream out_stream;
public ReadableByteChannel in;
public Process process;

public void run() {
try {
ByteBuffer bb = ByteBuffer.allocate(32768);
int read = 1;
while (read > 0) {
read = in.read(bb);
if (read > 0) {
out_stream.write(bb.array(), 0, read);
}
}
} catch (Exception e) {
throw new RuntimeException("Broken pipe", e);
} finally {
try {
out.close();
} catch (Exception e) {
}
try {
in.close();
} catch (Exception e) {
}
}
}

public ProcessChannel(Process process, OutputStream out, ReadableByteChannel in) {
this.out = Channels.newChannel(out);
this.out_stream = out;
this.in = in;
this.process = process;
}

public ProcessChannel(Process process, OutputStream out) {
this.out = Channels.newChannel(out);
this.process = process;
}

public ProcessChannel(Process process, InputStream in) {
this.in = Channels.newChannel(in);
this.process = process;
}

public int read(ByteBuffer dst) throws IOException {
return stdout.read(dst);
return in.read(dst);
}

public boolean isOpen() {
return stdin.isOpen();
return in.isOpen();
}

public void close() throws IOException {
stdin.close();
stdout.close();
if (in instanceof ReadableByteChannel)
in.close();
if (out instanceof WritableByteChannel)
out.close();
}

public int exitValue() throws InterruptedException {
return process.waitFor();
}

public int write(ByteBuffer src) throws IOException {
return stdin.write(src);
return out.write(src);
}
}
45 changes: 18 additions & 27 deletions src/vm/jvm/runtime/org/perl6/nqp/io/ProcessHandle.java
Original file line number Diff line number Diff line change
@@ -1,41 +1,32 @@
package org.perl6.nqp.io;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ProcessBuilder.Redirect;
import java.nio.charset.Charset;
import java.util.Map;

import org.perl6.nqp.runtime.ExceptionHandling;
import org.perl6.nqp.runtime.ThreadContext;

public class ProcessHandle extends SyncHandle {

Process process;

public ProcessHandle(ThreadContext tc, String cmd, String dir, Map<String, String> env) {
ProcessBuilder pb;
String os = System.getProperty("os.name").toLowerCase();
if (os.indexOf("win") >= 0) {
pb = new ProcessBuilder("cmd", "/c", cmd.replace('/', '\\'));
} else {
pb = new ProcessBuilder("sh", "-c", cmd);
}
pb.directory(new File(dir));
pb.redirectError(Redirect.INHERIT);

// Clear the JVM inherited environment and use provided only
Map<String, String> pbEnv = pb.environment();
pbEnv.clear();
pbEnv.putAll(env);

try {
process = pb.start();
chan = new ProcessChannel(process, process.getOutputStream(), process.getInputStream());
setEncoding(tc, Charset.forName("UTF-8"));
} catch (IOException e) {
throw ExceptionHandling.dieInternal(tc, e);
}
public Process process;

public ProcessHandle(ThreadContext tc) {
setEncoding(tc, Charset.forName("UTF-8"));
}

public void bindChannel(ThreadContext tc, Process process, OutputStream out) {
this.process = process;
this.chan = new ProcessChannel(process, out);
setEncoding(tc, Charset.forName("UTF-8"));
}

public void bindChannel(ThreadContext tc, Process process, InputStream in) {
this.process = process;
this.chan = new ProcessChannel(process, in);
setEncoding(tc, Charset.forName("UTF-8"));
}

public void flush(ThreadContext tc) {
Expand Down
2 changes: 1 addition & 1 deletion src/vm/jvm/runtime/org/perl6/nqp/io/SyncHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
public abstract class SyncHandle implements IIOClosable, IIOEncodable,
IIOSyncReadable, IIOSyncWritable, IIOLineSeparable, IIOExitable {

protected ByteChannel chan;
public ByteChannel chan;
protected CharsetEncoder enc;
protected CharsetDecoder dec;
protected boolean eof = false;
Expand Down
Loading

0 comments on commit 9794dfa

Please sign in to comment.