001: // This file is part of KeY - Integrated Deductive Software Design
002: // Copyright (C) 2001-2007 Universitaet Karlsruhe, Germany
003: // Universitaet Koblenz-Landau, Germany
004: // Chalmers University of Technology, Sweden
005: //
006: // The KeY system is protected by the GNU General Public License.
007: // See LICENSE.TXT for details.
008: //
009: //
010:
011: // CvsRunner.java
012: // $Id: CvsRunner.java 1.4.1.9.1.2.1.3.1.3 Wed, 23 Aug 2006 17:11:07 +0200 richard $
013: // (c) COPYRIGHT MIT and INRIA, 1997.
014: // Please first read the full copyright statement in file COPYRIGHT.html
015: // http://dev.w3.org/cvsweb/java/classes/org/w3c/cvs/CvsRunner.java
016:
017: // Contains code from com.ice.jcvslet.JCVSletLog by Tim Endres, time@gjt.org
018:
019: package de.uka.ilkd.key.proof.mgt;
020:
021: import java.io.*;
022:
023: import org.apache.log4j.Logger;
024:
025: import de.uka.ilkd.key.gui.configuration.PathConfig;
026: import de.uka.ilkd.key.util.Debug;
027:
028: public class CvsRunner {
029: // private static final File tmpdir = new File("/tmp");
030: public static boolean debug = true;
031:
032: private static final String REP_ROOT = PathConfig.KEY_CONFIG_DIR
033: + File.separator + "CVS-PO-REP" + File.separator;
034: // private static final String ROOT_OPT = "-d "+REP_ROOT;
035:
036: private Logger mgtLogger = Logger.getLogger("key.proof.mgt");
037:
038: /**
039: * Dump the given string into a temporary file.
040: * This is used for th <code>-f</code> argument of the cvs commit command.
041: * This method should only be used from a synchronized method.
042: * @param string The string to dump.
043: */
044:
045: File getTemporaryFile(String string) throws CvsException {
046: // Create a pseudo-random temporary filename
047: String fn = "cvs-" + System.currentTimeMillis() + "-"
048: + string.length();
049: File temp = null;
050: try {
051: temp = File.createTempFile(fn, "-" + string.length());
052: temp.deleteOnExit();
053: PrintStream out = new PrintStream(
054: new FileOutputStream(temp));
055: out.print(string);
056: out.close();
057: return temp;
058: } catch (IOException ex) {
059: error("temporaryFile",
060: "unable to create/use temporary file: "
061: + (temp == null ? "(creation failed)"
062: : temp.getAbsolutePath()));
063: }
064: return temp;
065: }
066:
067: /**
068: * Emit an error.
069: * Some abnormal situation occured, emit an error message.
070: * @param mth The method in which the error occured.
071: * @param msg The message to emit.
072: * @exception CvsException The exception that will be thrown as a
073: * result of the error.
074: */
075:
076: protected void error(String mth, String msg) throws CvsException {
077: String emsg = this .getClass().getName() + "[" + mth + "]: "
078: + msg;
079: throw new CvsException(emsg);
080: }
081:
082: /**
083: * Get a filename between quote contained in this String.
084: * @return the filename of null.
085: */
086: protected String getQuotedFilename(String line) {
087: int idx = line.indexOf('\'');
088: if (idx == -1)
089: return null;
090: char ch;
091: StringBuffer buffer = new StringBuffer();
092: try {
093: while ((ch = line.charAt(idx++)) != '\'')
094: buffer.append(ch);
095: } catch (ArrayIndexOutOfBoundsException ex) {
096: Debug
097: .out("Exception thrown by class CsvRunner at buffer.append()");
098: }
099: return buffer.toString();
100: }
101:
102: /**
103: * Wait for the underlying CVS process to finish.
104: * Once the process is terminated, all relevant streams are closed, and
105: * an exception if potentially thrown if the process indicated failure.
106: * @param proc The CVS process.
107: * @param ccode Should we expect a zero status from the child process.
108: * @exception CvsException If a zero status is expected, and the CVS
109: * @return true iff operation successful
110: * process exit status is not zero.
111: */
112:
113: protected synchronized boolean waitForCompletion(
114: ProcessEnvironment proc, boolean ccode) throws CvsException {
115: proc.waitForTermination();
116:
117: //no exception thrown, that's an unknown exception.
118: int ecode = proc.proc.exitValue();
119: if (ecode != 0) {
120: String msg = ("Process exited with error code: " + ecode
121: + " error [" + proc.errorLog + "]");
122: if (debug)
123: mgtLogger.error(msg);
124: if (ccode) {
125: throw new CvsException(msg);
126: }
127: return false;
128: }
129: return true;
130:
131: }
132:
133: public boolean cvsImport(String moduleName, String workingDir,
134: String vendorTag, String releaseTag) throws CvsException {
135: initRep();
136: String[] command = new String[] { "cvs", "-d", REP_ROOT,
137: "import", "-d", "-I", "*.tpr", "-I", "*.tws", "-I",
138: "*.df*", "-I", "*.txv*", "-m", "your.message.here",
139: moduleName, vendorTag.replace(' ', '_'), releaseTag };
140: // Run it:
141: try {
142: mgtLogger.info("Executing " + print(command) + " in "
143: + workingDir);
144: return waitForCompletion(new ProcessEnvironment(Runtime
145: .getRuntime().exec(command, null,
146: new File(workingDir))), false);
147: } catch (IOException ex) {
148: ex.printStackTrace();
149: throw new CvsException(ex.getMessage());
150: }
151: }
152:
153: /*
154: public void cvsLog(String moduleName) throws CvsException {
155: String command = "/usr/bin/cvs " + ROOT_OPT + " rlog -h "+ moduleName;
156: // Run it:
157: try {
158: mgtLogger.info("Executing "+command);
159: ProcessEnvironment proc =
160: new ProcessEnvironment ( Runtime.getRuntime().exec(command) );
161: parseLogOutput(proc.proc.getInputStream());
162: waitForCompletion(proc, false);
163: } catch (IOException ex) {
164: ex.printStackTrace();
165: throw new CvsException(ex.getMessage());
166: }
167: }
168: */
169:
170: public String cvsDiff(String moduleName, String tag1, String tag2)
171: throws CvsException {
172: String[] command = new String[] { "cvs", "-d", REP_ROOT,
173: "rdiff", "-u", "-r", tag1, "-r", tag2, moduleName };
174: String s = "";
175: // Run it:
176: try {
177: mgtLogger.info("Executing " + print(command));
178: ProcessEnvironment proc = new ProcessEnvironment(Runtime
179: .getRuntime().exec(command, null,
180: new File(System.getProperty("user.home"))));
181: BufferedReader in = new BufferedReader(
182: new InputStreamReader(proc.proc.getInputStream()));
183: String line = null;
184: while ((line = in.readLine()) != null) {
185: // Make sure the line isn't empty:
186: if (line.length() <= 0)
187: continue;
188: s += line + "\n";
189: }
190: waitForCompletion(proc, true);
191: } catch (IOException ex) {
192: ex.printStackTrace();
193: throw new CvsException(ex.getMessage());
194: }
195: mgtLogger.debug("Diff:\n" + s);
196: return s;
197: }
198:
199: private void parseLogOutput(InputStream procin) throws IOException {
200:
201: boolean collectSymbols = false;
202:
203: BufferedReader in = new BufferedReader(new InputStreamReader(
204: procin));
205: String line = null;
206: while ((line = in.readLine()) != null) {
207: // Make sure the line isn't empty:
208: if (line.length() <= 0)
209: continue;
210:
211: if (collectSymbols) {
212: if (line.startsWith("\t")) {
213: String symStr = line.substring(1);
214: int colonPos = symStr.indexOf(':');
215: symStr = symStr.substring(0, colonPos).trim();
216: mgtLogger.debug("CVS Symbols: " + symStr);
217: } else {
218: collectSymbols = false;
219: }
220: } else if (line.startsWith("symbolic names:"))
221: collectSymbols = true;
222:
223: }
224: }
225:
226: private void initRep() throws CvsException {
227: File rep = new File(REP_ROOT + File.separator + "CVSROOT");
228: File anchor = new File(PathConfig.KEY_CONFIG_DIR
229: + File.separator + "CVS_ANCHOR_DIR" + File.separator
230: + "KEY_CVS_ANCHOR");
231:
232: try {
233: if (!rep.exists()) {
234: rep.mkdirs();
235: String[] command = new String[] { "cvs", "-d",
236: REP_ROOT, "init" };
237: // Run it:
238: mgtLogger.info("Executing " + print(command));
239: Process proc = Runtime.getRuntime().exec(command);
240: waitForCompletion(new ProcessEnvironment(proc), false);
241: }
242:
243: // if (!anchor.exists()) anchor.createNewFile();
244: } catch (IOException ex) {
245: ex.printStackTrace();
246: throw new CvsException(ex.getMessage());
247: }
248:
249: }
250:
251: private String print(String[] arr) {
252: StringBuffer s = new StringBuffer(300);
253: for (int i = 0; i < arr.length; i++)
254: s.append(arr[i]);
255: return s.toString();
256: }
257:
258: /**
259: * Thread that reads data from a given input stream and stores it in a
260: * string buffer
261: */
262: private static class StreamReaderThread extends Thread {
263: private final StringBuffer log;
264: private final InputStream procin;
265:
266: public StreamReaderThread(final StringBuffer log,
267: final InputStream in) {
268: this .log = log;
269: this .procin = in;
270: }
271:
272: public void run() {
273: BufferedReader in = new BufferedReader(
274: new InputStreamReader(procin));
275: String line = null;
276:
277: try {
278: while ((line = in.readLine()) != null) {
279: log.append(line + "\n");
280: }
281: } catch (IOException ex) {
282: ex.printStackTrace();
283: }
284:
285: synchronized (this ) {
286: notifyAll();
287: }
288: }
289:
290: public synchronized void waitForTermination() {
291: while (isAlive()) {
292: try {
293: wait();
294: } catch (InterruptedException e) {
295: Debug
296: .out(
297: "Exception thrown by class CvsRunner at IO: ",
298: e);
299: }
300: }
301: }
302: }
303:
304: /**
305: * Encapsulate a given process object. By default a thread is spawn that
306: * handles error output of the process, to ensure that pending error output
307: * does not block the process. Error output is stored in a string buffer and
308: * can be accessed after termination of the process.
309: */
310: private static class ProcessEnvironment {
311: public final Process proc;
312: public final StringBuffer errorLog;
313:
314: private final StreamReaderThread errReader;
315:
316: public ProcessEnvironment(final Process proc) {
317: this .proc = proc;
318: errorLog = new StringBuffer();
319: errReader = new StreamReaderThread(errorLog, proc
320: .getErrorStream());
321: errReader.start();
322: }
323:
324: /**
325: * Wait for the termination of the process. To this end further standard
326: * output the process produces is read and discarded.
327: */
328: public void waitForTermination() {
329: final StreamReaderThread stdReader = new StreamReaderThread(
330: new StringBuffer(), proc.getInputStream());
331: stdReader.start();
332: errReader.waitForTermination();
333: stdReader.waitForTermination();
334: try {
335: proc.waitFor();
336: } catch (InterruptedException e) {
337: Debug.out(
338: "Exception thrown by class CvsRunner at IO: ",
339: e);
340: } finally {
341: // Close all streams, just to make sure...
342: try {
343: proc.getInputStream().close();
344: } catch (Exception ex) {
345: Debug
346: .out("Exception thrown by class CvsRunner at IO-close");
347: }
348: try {
349: proc.getOutputStream().close();
350: } catch (Exception ex) {
351: Debug
352: .out("Exception thrown by class CvsRunner at IO-close");
353: }
354: try {
355: proc.getErrorStream().close();
356: } catch (Exception ex) {
357: Debug
358: .out("Exception thrown by class CvsRunner at IO-close");
359: }
360: }
361: }
362: }
363:
364: }
|