Package hudson.plugins.perforce

Source Code of hudson.plugins.perforce.HudsonP4RemoteExecutor$RemoteCall

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package hudson.plugins.perforce;

import java.io.*;
import java.util.Map;
import java.util.Set;

import com.tek42.perforce.PerforceException;
import com.tek42.perforce.process.Executor;
import hudson.CloseProofOutputStream;
import hudson.FilePath;
import hudson.Launcher;
import hudson.Launcher.LocalLauncher;
import hudson.Proc;
import hudson.Proc.RemoteProc;
import hudson.model.Hudson;
import hudson.model.TaskListener;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.Channel.Listener;
import hudson.remoting.FastPipedInputStream;
import hudson.remoting.FastPipedOutputStream;
import hudson.remoting.Future;
import hudson.remoting.RemoteInputStream;
import hudson.remoting.RemoteOutputStream;
import hudson.remoting.VirtualChannel;
import hudson.util.StreamTaskListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/* Implementation of the P4Java Executor interface that provides support for
* remotely executing Perforce commands.
* <p/>
*
* This differs from HudsonP4Executor in that it doesn't use the native hudson
* launcher. We need to use our own callable in order to gain better control over
* the remote streams.
*
* <p/>
*
* User contract: Use this class only once to execute a command. ,to execute
* another command, spawn another Exector using the Exector Factory
*
* @author rpetti
*/
public class HudsonP4RemoteExecutor implements HudsonP4Executor {

    private BufferedReader reader;
    private BufferedWriter writer;

    private InputStream input;
    private OutputStream output;

    private Launcher hudsonLauncher;
    private String[] env;
    private FilePath filePath;
   
    private Proc currentProcess;

    /**
     * Constructor that takes Hudson specific details for launching the
     * Perforce commands.
     *
     * @param hudsonLauncher
     * @param envMap
     * @param filePath
     */
    HudsonP4RemoteExecutor(Launcher hudsonLauncher, Map<String, String> envMap, FilePath filePath) {
        this.hudsonLauncher = hudsonLauncher;
        this.env = convertEnvMaptoArray(envMap);
        this.filePath = filePath;
    }

    public void close() {
        // Need to close writer
        // (reader gets closed by remote process)
        try {
            output.close();
        } catch(IOException e) {
            // Do nothing
        }
    }

    public void exec(String[] cmd) throws PerforceException {
        try {
            // ensure we actually have a valid hudson launcher
            if (null == hudsonLauncher) {
                hudsonLauncher = Hudson.getInstance().createLauncher(new StreamTaskListener(System.out));
            }
            VirtualChannel channel = hudsonLauncher.getChannel();

            // hudsonOut->p4in->reader
            FastPipedOutputStream hudsonOut = new FastPipedOutputStream();
            FastPipedInputStream p4in = new FastPipedInputStream(hudsonOut);
            input = p4in;

            // hudsonIn<-p4Out<-writer
            FastPipedInputStream hudsonIn = new FastPipedInputStream();
            FastPipedOutputStream p4out = new FastPipedOutputStream(hudsonIn);
            output = p4out;

            final OutputStream out = hudsonOut == null ? null : new RemoteOutputStream(hudsonOut);
            final InputStream  in  = hudsonIn ==null ? null : new RemoteInputStream(hudsonIn);

            String remotePath = filePath.getRemote();
            TaskListener listener = hudsonLauncher.getListener();
            RemoteCall remoteCall = new RemoteCall(
                    Arrays.asList(cmd), env, in, out, null,
                    remotePath,
                    listener);
            Future future = channel.callAsync(remoteCall);
            currentProcess = new RemoteProc(future);

        } catch(IOException e) {
            //try to close all the pipes before throwing an exception
            closeBuffers();

            throw new PerforceException("Could not run perforce command.", e);
        }
    }

    public BufferedWriter getWriter() {
        if(writer==null){
            writer = new BufferedWriter(new OutputStreamWriter(output));
        }
        return writer;
    }

    public BufferedReader getReader() {
        if(reader==null){
            reader = new BufferedReader(new InputStreamReader(input));
        }
        return reader;
    }

    private static class RemoteCall implements Callable<Integer,IOException> {
        private final List<String> cmd;
        private final String[] env;
        private final InputStream in;
        private final OutputStream out;
        private final OutputStream err;
        private final String workDir;
        private final TaskListener listener;

        RemoteCall(List<String> cmd, String[] env, InputStream in, OutputStream out, OutputStream err, String workDir, TaskListener listener) {
            this.cmd = new ArrayList<String>(cmd);
            this.env = env;
            this.in = in;
            this.out = out;
            this.err = err;
            this.workDir = workDir;
            this.listener = listener;
        }
        public Integer call() throws IOException {
            Launcher.ProcStarter ps = new LocalLauncher(listener).launch();
            ps.cmds(cmd).envs(env).stdin(in).stdout(out);
            if(err != null) ps.stderr(err);
            if(workDir!=null)   ps.pwd(workDir);

            Proc p;
            try {
                p = ps.start();
                Integer ret = p.join();
                if(out!=null) out.close();
                if(err!=null) err.close();
                return ret;
            } catch (InterruptedException e) {
                if(out!=null) out.close();
                if(err!=null) err.close();
                return -1;
            } catch (IOException e) {
                if(out!=null) out.close();
                if(err!=null) err.close();
                throw new IOException(e);
            }
        }
    }

    /**
     * Function for converting map of environment variables to a String
     * array as hudson does not provide a launcher method that takes
     * <p/>
     * (1) Environment Map (2) InputStream (3) OutputStream
     * <p> .. at the same time
     *
     * @param envMap
     *
     * @return
     */
    private String[] convertEnvMaptoArray(Map<String, String> envMap) {
        Set<String> keySet = envMap.keySet();
        String[] keys = keySet.toArray(new String[0]);

        String[] result = new String[keys.length];
        for (int i = 0; i < keys.length; i++)
            result[i] = keys[i] + "=" + envMap.get(keys[i]);

        return result;
    }

    public InputStream getInputStream() {
        return input;
    }

    public OutputStream getOutputStream() {
        return output;
    }

    private void closeBuffers(){
        try {
            input.close();
        } catch(IOException ignoredException) {};
        try {
            output.close();
        } catch(IOException ignoredException) {};
    }
   
    @Override
    public boolean isAlive() throws IOException, InterruptedException {
        return currentProcess != null ? currentProcess.isAlive() : false;
    }
}
TOP

Related Classes of hudson.plugins.perforce.HudsonP4RemoteExecutor$RemoteCall

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.