1
/* -*- tab-width: 4 -*-
3
* Electric(tm) VLSI Design System
5
* File: ExecProcess.java
7
* Copyright (c) 2009 Sun Microsystems and Static Free Software
9
* Electric(tm) is free software; you can redistribute it and/or modify
10
* it under the terms of the GNU General Public License as published by
11
* the Free Software Foundation; either version 3 of the License, or
12
* (at your option) any later version.
14
* Electric(tm) is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with Electric(tm); see the file COPYING. If not, write to
21
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
22
* Boston, Mass 02111-1307, USA.
24
package com.sun.electric.tool.io;
31
* This class provides the same functionality as Runtime.exec(), but
32
* with extra safeguards and utilities. Includes the ability to
33
* execute a command on a remote machine via ssh, optionally rsync'ing
34
* the working directory to the remote machine before execution and
37
* This class should not depend on other Electric classes.
39
* @author megacz (heavily influenced by gainsley's ExecProcess)
41
public class ExecProcess {
43
/** an OutputStream that discards anything written to it */
44
public static final OutputStream devNull = new OutputStream() {
45
public void write(int b) { }
46
public void write(byte[] b, int ofs, int len) { }
49
/** an InputStream that always returns EOF */
50
public static final InputStream eofInputStream = new InputStream() {
51
public int read() { return -1; }
52
public int read(byte[] buf, int ofs, int len) { return -1; }
53
public long skip(long ofs) { return 0; }
54
public int available() { return 0; }
58
* @param command the command to run (separated into argv[])
59
* @param workingDirectory the working directory on the LOCAL machine
61
public ExecProcess(String[] command, File workingDirectory) {
62
this.command = command;
64
// Using java.io.tmpdir as the default working directory leads
65
// to far more predictable behavior than simply using the
66
// JVM's working directory. Electric already has a lot of
67
// bugs and quirks that result from doing that -- let's not
69
if (workingDirectory==null)
70
workingDirectory = new File(System.getProperty("java.io.tmpdir"));
72
this.workingDirectory = workingDirectory;
76
* @param host the hostname to run on
77
* @param user the username on the remote machine (or null to use
78
* whatever default ssh chooses)
79
* @param remoteWorkingDirectory the directory to work in on the remote machine
80
* @param syncBefore if true then "rsync --delete
81
* workingDirectory host:remoteWorkingDirectory" before
83
* @param syncAfter if true and the command terminates with exit
84
* code zero, then "rsync --delete
85
* host:remoteWorkingDirectory workingDirectory" after
88
public synchronized void setRemote(String host, String user,
89
File remoteWorkingDirectory,
90
boolean syncBefore, boolean syncAfter) {
91
if (proc!=null) throw new RuntimeException("you cannot invoke ExecProcess.setRemote() after ExecProcess.start()");
92
throw new RuntimeException("not implemented");
95
/** undoes setRemote() */
96
public synchronized void setLocal() { }
98
public synchronized void redirectStdin(InputStream in) {
99
if (proc!=null) throw new RuntimeException("you cannot invoke ExecProcess.redirectStdin() after ExecProcess.start()");
100
this.redirectStdin = in;
103
public synchronized void redirectStdout(OutputStream os) {
104
if (proc!=null) throw new RuntimeException("you cannot invoke ExecProcess.redirectStdout() after ExecProcess.start()");
105
this.redirectStdout = os;
108
public synchronized void redirectStderr(OutputStream os) {
109
if (proc!=null) throw new RuntimeException("you cannot invoke ExecProcess.redirectStderr() after ExecProcess.start()");
110
this.redirectStderr = os;
113
public synchronized void start() throws IOException {
114
if (proc!=null) throw new RuntimeException("you cannot invoke ExecProcess.start() twice");
115
proc = Runtime.getRuntime().exec(command, null, workingDirectory);
116
if (redirectStdin != null) new StreamCopier(redirectStdin, proc.getOutputStream()).start();
117
if (redirectStdout != null) new StreamCopier(proc.getInputStream(), redirectStdout).start();
118
if (redirectStderr != null) new StreamCopier(proc.getErrorStream(), redirectStderr).start();
121
public synchronized void destroy() throws IOException {
122
if (proc==null) throw new RuntimeException("you must invoke ExecProcess.start() first");
126
public int waitFor() throws IOException {
127
if (proc==null) throw new RuntimeException("you must invoke ExecProcess.start() first");
129
return proc.waitFor();
130
} catch (InterruptedException ie) {
131
throw new RuntimeException(ie);
135
public synchronized OutputStream getStdin() {
136
if (proc==null) throw new RuntimeException("you must invoke ExecProcess.start() first");
137
if (redirectStdin!=null) throw new RuntimeException("you cannot invoke getStdin() after redirectStdin()");
138
return proc.getOutputStream();
141
public synchronized InputStream getStdout() {
142
if (proc==null) throw new RuntimeException("you must invoke ExecProcess.start() first");
143
if (redirectStdout!=null) throw new RuntimeException("you cannot invoke getStdout() after redirectStdout()");
144
return proc.getInputStream();
147
public synchronized InputStream getStderr() {
148
if (proc==null) throw new RuntimeException("you must invoke ExecProcess.start() first");
149
if (redirectStderr!=null) throw new RuntimeException("you cannot invoke getStderr() after redirectStderr()");
150
return proc.getErrorStream();
153
private Process proc;
154
private InputStream redirectStdin;
155
private OutputStream redirectStdout;
156
private OutputStream redirectStderr;
157
private String[] command;
158
private File workingDirectory;
161
* Copies from an InputStream to an OutputStream; used to implement redirectXXX().
163
private static class StreamCopier extends Thread {
164
private final byte[] buf = new byte[16 * 1024];
165
private final InputStream is;
166
private final OutputStream os;
167
public StreamCopier(InputStream is, OutputStream os) {
175
int numread = is.read(buf, 0, buf.length);
176
if (numread==-1) break;
177
os.write(buf, 0, numread);
179
} catch (Exception e) { throw new RuntimeException(e); }