Search in sources :

Example 1 with Result

use of org.apache.felix.gogo.runtime.Pipe.Result in project felix by apache.

the class Closure method execute.

@SuppressWarnings("unchecked")
private Object execute(List<Object> values, Channel capturingOutput) throws Exception {
    if (null != values) {
        parmv = new ArrayList<>(values);
        parms = new ArgList(parmv);
    } else if (null != parent) {
        // inherit parent closure parameters
        parmv = parent.parmv != null ? new ArrayList<>(parent.parmv) : null;
        parms = parmv != null ? new ArgList(parmv) : null;
    } else {
        // inherit session parameters
        Object args = session.get("args");
        if (null != args && args instanceof List<?>) {
            parmv = new ArrayList<>((List<Object>) args);
            parms = new ArgList(parmv);
        }
    }
    Result last = null;
    Operator operator = null;
    for (Iterator<Executable> iterator = program.tokens().iterator(); iterator.hasNext(); ) {
        Operator prevOperator = operator;
        Executable executable = iterator.next();
        if (iterator.hasNext()) {
            operator = (Operator) iterator.next();
        } else {
            operator = null;
        }
        if (prevOperator != null) {
            if (Token.eq("&&", prevOperator)) {
                if (!last.isSuccess()) {
                    continue;
                }
            } else if (Token.eq("||", prevOperator)) {
                if (last.isSuccess()) {
                    continue;
                }
            }
        }
        Channel[] streams;
        boolean[] toclose = new boolean[10];
        if (Pipe.getCurrentPipe() != null) {
            streams = Pipe.getCurrentPipe().streams.clone();
        } else {
            streams = new Channel[10];
            System.arraycopy(session.channels, 0, streams, 0, 3);
        }
        if (capturingOutput != null) {
            streams[1] = capturingOutput;
            toclose[1] = true;
        }
        CommandSessionImpl.JobImpl job;
        if (executable instanceof Pipeline) {
            Pipeline pipeline = (Pipeline) executable;
            List<Executable> exec = pipeline.tokens();
            Token s = exec.get(0);
            Token e = exec.get(exec.size() - 1);
            Token t = program.subSequence(s.start - program.start, e.start + e.length - program.start);
            job = session().createJob(t);
            for (int i = 0; i < exec.size(); i++) {
                Statement ex = (Statement) exec.get(i);
                Operator op = i < exec.size() - 1 ? (Operator) exec.get(++i) : null;
                Channel[] nstreams;
                boolean[] ntoclose;
                boolean endOfPipe;
                if (i == exec.size() - 1) {
                    nstreams = streams;
                    ntoclose = toclose;
                    endOfPipe = true;
                } else if (Token.eq("|", op)) {
                    PipedInputStream pis = new PipedInputStream();
                    PipedOutputStream pos = new PipedOutputStream(pis);
                    nstreams = streams.clone();
                    nstreams[1] = Channels.newChannel(pos);
                    ntoclose = toclose.clone();
                    ntoclose[1] = true;
                    streams[0] = Channels.newChannel(pis);
                    toclose[0] = true;
                    endOfPipe = false;
                } else if (Token.eq("|&", op)) {
                    PipedInputStream pis = new PipedInputStream();
                    PipedOutputStream pos = new PipedOutputStream(pis);
                    nstreams = streams.clone();
                    nstreams[1] = nstreams[2] = Channels.newChannel(pos);
                    ntoclose = toclose.clone();
                    ntoclose[1] = ntoclose[2] = true;
                    streams[0] = Channels.newChannel(pis);
                    toclose[0] = true;
                    endOfPipe = false;
                } else {
                    throw new IllegalStateException("Unrecognized pipe operator: '" + op + "'");
                }
                Pipe pipe = new Pipe(this, job, ex, nstreams, ntoclose, endOfPipe);
                job.addPipe(pipe);
            }
        } else {
            job = session().createJob(executable);
            Pipe pipe = new Pipe(this, job, (Statement) executable, streams, toclose, true);
            job.addPipe(pipe);
        }
        // Start pipe in background
        if (operator != null && Token.eq("&", operator)) {
            job.start(Status.Background);
            last = new Result((Object) null);
        } else // Start in foreground and wait for results
        {
            last = job.start(Status.Foreground);
            if (last == null) {
                last = new Result((Object) null);
            } else if (last.exception != null) {
                throw last.exception;
            }
        }
    }
    return last == null ? null : last.result;
}
Also used : Operator(org.apache.felix.gogo.runtime.Parser.Operator) Statement(org.apache.felix.gogo.runtime.Parser.Statement) Channel(java.nio.channels.Channel) ArrayList(java.util.ArrayList) PipedOutputStream(java.io.PipedOutputStream) PipedInputStream(java.io.PipedInputStream) Result(org.apache.felix.gogo.runtime.Pipe.Result) Pipeline(org.apache.felix.gogo.runtime.Parser.Pipeline) ArrayList(java.util.ArrayList) List(java.util.List) Executable(org.apache.felix.gogo.runtime.Parser.Executable)

Example 2 with Result

use of org.apache.felix.gogo.runtime.Pipe.Result in project felix by apache.

the class Pipe method doCall.

private Result doCall() {
    // The errChannel will be used to print errors to the error stream
    // Before the command is actually executed (i.e. during the initialization,
    // including the redirection processing), it will be the original error stream.
    // This value may be modified by redirections and the redirected error stream
    // will be effective just before actually running the command.
    WritableByteChannel errChannel = (WritableByteChannel) streams[2];
    ThreadIO threadIo = closure.session().threadIO();
    try {
        List<Token> tokens = statement.redirections();
        for (int i = 0; i < tokens.size(); i++) {
            Token t = tokens.get(i);
            Matcher m;
            if ((m = Pattern.compile("(?:([0-9])?|(&)?)>(>)?").matcher(t)).matches()) {
                int fd;
                if (m.group(1) != null) {
                    fd = Integer.parseInt(m.group(1));
                } else if (m.group(2) != null) {
                    // both 1 and 2
                    fd = -1;
                } else {
                    fd = 1;
                }
                boolean append = m.group(3) != null;
                Set<StandardOpenOption> options = new HashSet<>();
                options.add(StandardOpenOption.WRITE);
                options.add(StandardOpenOption.CREATE);
                options.add(append ? StandardOpenOption.APPEND : StandardOpenOption.TRUNCATE_EXISTING);
                Token tok = tokens.get(++i);
                Object val = Expander.expand(tok, closure);
                for (Path p : toPaths(val)) {
                    p = closure.session().redirect(p, WRITE);
                    Channel ch = Files.newByteChannel(p, options);
                    if (fd >= 0) {
                        setStream(ch, fd, WRITE);
                    } else {
                        setStream(ch, 1, WRITE);
                        setStream(ch, 2, WRITE);
                    }
                }
            } else if ((m = Pattern.compile("([0-9])?>&([0-9])").matcher(t)).matches()) {
                int fd0 = 1;
                if (m.group(1) != null) {
                    fd0 = Integer.parseInt(m.group(1));
                }
                int fd1 = Integer.parseInt(m.group(2));
                if (streams[fd0] != null && toclose[fd0]) {
                    streams[fd0].close();
                }
                // If the stream has to be closed, close it when both streams are closed
                if (toclose[fd1]) {
                    Channel channel = streams[fd1];
                    AtomicInteger references = new AtomicInteger();
                    streams[fd0] = new RefByteChannel(channel, references);
                    streams[fd1] = new RefByteChannel(channel, references);
                    toclose[fd0] = true;
                } else {
                    streams[fd0] = streams[fd1];
                    toclose[fd0] = false;
                }
            } else if ((m = Pattern.compile("([0-9])?<(>)?").matcher(t)).matches()) {
                int fd = 0;
                if (m.group(1) != null) {
                    fd = Integer.parseInt(m.group(1));
                }
                boolean output = m.group(2) != null;
                Set<StandardOpenOption> options = new HashSet<>();
                options.add(StandardOpenOption.READ);
                if (output) {
                    options.add(StandardOpenOption.WRITE);
                    options.add(StandardOpenOption.CREATE);
                }
                Token tok = tokens.get(++i);
                Object val = Expander.expand(tok, closure);
                for (Path p : toPaths(val)) {
                    p = closure.session().redirect(p, READ + (output ? WRITE : 0));
                    Channel ch = Files.newByteChannel(p, options);
                    setStream(ch, fd, READ + (output ? WRITE : 0));
                }
            } else if ((m = Pattern.compile("<<-?").matcher(t)).matches()) {
                final Token hereDoc = tokens.get(++i);
                final boolean stripLeadingTabs = t.charAt(t.length() - 1) == '-';
                InputStream doc = new InputStream() {

                    final byte[] bytes = hereDoc.toString().getBytes();

                    int index = 0;

                    boolean nl = true;

                    @Override
                    public int read() throws IOException {
                        if (nl && stripLeadingTabs) {
                            while (index < bytes.length && bytes[index] == '\t') {
                                index++;
                            }
                        }
                        if (index < bytes.length) {
                            int ch = bytes[index++];
                            nl = ch == '\n';
                            return ch;
                        }
                        return -1;
                    }
                };
                Channel ch = Channels.newChannel(doc);
                setStream(ch, 0, READ);
            } else if (Token.eq("<<<", t)) {
                Token word = tokens.get(++i);
                Object val = Expander.expand("\"" + word + "\"", closure);
                String str = val != null ? String.valueOf(val) : "";
                Channel ch = Channels.newChannel(new ByteArrayInputStream(str.getBytes()));
                setStream(ch, 0, READ);
            }
        }
        for (int i = 0; i < streams.length; i++) {
            streams[i] = wrap(streams[i]);
        }
        // Create streams
        in = Channels.newInputStream((ReadableByteChannel) streams[0]);
        out = new PrintStream(Channels.newOutputStream((WritableByteChannel) streams[1]), true);
        err = new PrintStream(Channels.newOutputStream((WritableByteChannel) streams[2]), true);
        // Change the error stream to the redirected one, now that
        // the command is about to be executed.
        errChannel = (WritableByteChannel) streams[2];
        if (threadIo != null) {
            threadIo.setStreams(in, out, err);
        }
        Pipe previous = setCurrentPipe(this);
        try {
            Object result;
            // Very special case for empty statements with redirection
            if (statement.tokens().isEmpty() && toclose[0]) {
                ByteBuffer bb = ByteBuffer.allocate(1024);
                while (((ReadableByteChannel) streams[0]).read(bb) >= 0 || bb.position() != 0) {
                    bb.flip();
                    ((WritableByteChannel) streams[1]).write(bb);
                    bb.compact();
                }
                result = null;
            } else {
                result = closure.execute(statement);
            }
            // If an error has been set
            if (error != 0) {
                return new Result(error);
            }
            // We don't print the result if we're at the end of the pipe
            if (result != null && !endOfPipe && !Boolean.FALSE.equals(closure.session().get(".FormatPipe"))) {
                out.println(closure.session().format(result, Converter.INSPECT));
            }
            return new Result(result);
        } finally {
            setCurrentPipe(previous);
        }
    } catch (Exception e) {
        if (!endOfPipe) {
            String msg = "gogo: " + e.getClass().getSimpleName() + ": " + e.getMessage() + "\n";
            try {
                errChannel.write(ByteBuffer.wrap(msg.getBytes()));
            } catch (IOException ioe) {
                e.addSuppressed(ioe);
            }
        }
        return new Result(e);
    } finally {
        if (out != null) {
            out.flush();
        }
        if (err != null) {
            err.flush();
        }
        if (threadIo != null) {
            threadIo.close();
        }
        try {
            for (int i = 0; i < 10; i++) {
                if (toclose[i] && streams[i] != null) {
                    streams[i].close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Also used : ReadableByteChannel(java.nio.channels.ReadableByteChannel) Matcher(java.util.regex.Matcher) StandardOpenOption(java.nio.file.StandardOpenOption) Result(org.apache.felix.gogo.runtime.Pipe.Result) HashSet(java.util.HashSet) ThreadIO(org.apache.felix.service.threadio.ThreadIO) Path(java.nio.file.Path) PrintStream(java.io.PrintStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) ByteChannel(java.nio.channels.ByteChannel) Channel(java.nio.channels.Channel) ReadableByteChannel(java.nio.channels.ReadableByteChannel) WritableByteChannel(java.nio.channels.WritableByteChannel) WritableByteChannel(java.nio.channels.WritableByteChannel) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) InterruptedIOException(java.io.InterruptedIOException) ClosedChannelException(java.nio.channels.ClosedChannelException) IOException(java.io.IOException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ByteArrayInputStream(java.io.ByteArrayInputStream)

Aggregations

Channel (java.nio.channels.Channel)2 Result (org.apache.felix.gogo.runtime.Pipe.Result)2 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 InterruptedIOException (java.io.InterruptedIOException)1 PipedInputStream (java.io.PipedInputStream)1 PipedOutputStream (java.io.PipedOutputStream)1 PrintStream (java.io.PrintStream)1 ByteBuffer (java.nio.ByteBuffer)1 ByteChannel (java.nio.channels.ByteChannel)1 ClosedChannelException (java.nio.channels.ClosedChannelException)1 ReadableByteChannel (java.nio.channels.ReadableByteChannel)1 WritableByteChannel (java.nio.channels.WritableByteChannel)1 Path (java.nio.file.Path)1 StandardOpenOption (java.nio.file.StandardOpenOption)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 List (java.util.List)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1