View Javadoc

1   /*
2    * The Apache Software License, Version 1.1
3    *
4    * Copyright (c) 1999, 2000 The Apache Software Foundation.  All rights
5    * reserved.
6    *
7    * Redistribution and use in source and binary forms, with or without
8    * modification, are permitted provided that the following conditions
9    * are met:
10   *
11   * 1. Redistributions of source code must retain the above copyright
12   *    notice, this list of conditions and the following disclaimer.
13   *
14   * 2. Redistributions in binary form must reproduce the above copyright
15   *    notice, this list of conditions and the following disclaimer in
16   *    the documentation and/or other materials provided with the
17   *    distribution.
18   *
19   * 3. The end-user documentation included with the redistribution, if
20   *    any, must include the following acknowlegement:
21   *       "This product includes software developed by the
22   *        Apache Software Foundation (http://www.apache.org/)."
23   *    Alternately, this acknowlegement may appear in the software itself,
24   *    if and wherever such third-party acknowlegements normally appear.
25   *
26   * 4. The names "The Jakarta Project", "Ant", and "Apache Software
27   *    Foundation" must not be used to endorse or promote products derived
28   *    from this software without prior written permission. For written
29   *    permission, please contact apache@apache.org.
30   *
31   * 5. Products derived from this software may not be called "Apache"
32   *    nor may "Apache" appear in their names without prior written
33   *    permission of the Apache Group.
34   *
35   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46   * SUCH DAMAGE.
47   * ====================================================================
48   *
49   * This software consists of voluntary contributions made by many
50   * individuals on behalf of the Apache Software Foundation.  For more
51   * information on the Apache Software Foundation, please see
52   * <http://www.apache.org/>.
53   */
54  
55  package org.apache.tools.ant.taskdefs.optional.clearcase;
56  
57  import org.apache.tools.ant.BuildException;
58  import org.apache.tools.ant.Project;
59  import org.apache.tools.ant.taskdefs.Echo;
60  import org.apache.tools.ant.taskdefs.Execute;
61  import org.apache.tools.ant.taskdefs.LoadFile;
62  import org.apache.tools.ant.taskdefs.PumpStreamHandler;
63  import org.apache.tools.ant.taskdefs.optional.clearcase.ClearCase;
64  import org.apache.tools.ant.types.Commandline;
65  import org.apache.tools.ant.util.FileUtils;
66  import org.w3c.dom.*;
67  
68  import javax.xml.parsers.DocumentBuilderFactory;
69  import java.io.*;
70  import java.text.ParseException;
71  import java.text.SimpleDateFormat;
72  import java.util.Date;
73  import java.util.Random;
74  import java.util.StringTokenizer;
75  import java.util.Vector;
76  
77  /***
78   * The aim of this task is to generate a ClearCase change log report under the XML format, just like
79   * <code>CVSChangeLog</code> does it.
80   * <p/>
81   * Has been tested under Windows NT V4.0 SP6 and ClearCase 2002.05.00.
82   * </p>
83   *
84   * @taskname CCChangeLog
85   * @author Edouard Mercier
86   * @version 1.0 : 2004.04.25
87   */
88  public class CCChangeLog
89          extends ClearCase
90  {
91  
92    private String _from_date;
93  
94    /***
95     * Sets the date the history begins from. The format is the one expected by the ClearCase <code>lshistory -since</code>
96     * option (in French, <code>01-mars-04</code> is OK for instance).
97     *
98     * @optional start_date if not set, the history is taken from the beginning of the source history
99     */
100   public void setFromDate(String start_date)
101   {
102       _from_date = start_date;
103   }
104 
105   private String _from_label;
106 
107   /***
108    * Enables to tell from which label the change log will be generated.
109    *
110    * @optional from_label if not set, the history is taken from the beginning of the source history
111    */
112   public void setFromLabel(String from_label)
113   {
114       _from_label = from_label;
115   }
116 
117   private File _destination_file = new File("CCChangeLog.xml");
118 
119   /***
120    * Sets the output file for the XML log.
121    */
122   public void setDestfile(File destination_file)
123   {
124       _destination_file = destination_file;
125   }
126 
127   /***
128    * The file that will contain the log of the ClearCase command execution.
129    */
130   private File temporary_file;
131 
132   /***
133    * Checks that the input parameters are OK.
134    *
135    * @throws BuildException if some parameters are not OK
136    */
137   private void checkParameters()
138           throws BuildException
139   {
140   }
141 
142   /***
143    * The method that actually perform the ClearCase change history job.
144    *
145    * @throws BuildException if some unexpected error occured
146    */
147   public void execute()
148           throws BuildException
149   {
150       checkParameters();
151 
152       File lstype_log_file = performLsType();
153       analyzeLsType(lstype_log_file);
154 
155       File lshistory_log_file = performLsHistory();
156 
157       temporary_file = FileUtils.newFileUtils().createTempFile("ccchangelog", ".xml", null);
158       temporary_file.deleteOnExit();
159 
160       //Now, we create an XML log file that will contain the CC changes, via Ant native tasks
161       {
162           Echo echo = new Echo();
163           echo.setProject(getProject());
164           echo.setFile(temporary_file);
165           echo.setMessage("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><events>");
166           echo.execute();
167       }
168       String value = null;
169       /*{
170           LoadFile load_file = new LoadFile();
171           load_file.setProject(getProject());
172           load_file.setSrcFile(lshistory_log_file);
173           final String dummy_property = "DUMMY_PROPERTY" + Math.abs(new Random().nextInt());
174           load_file.setProperty(dummy_property);
175           load_file.execute();
176           value = getProject().getProperty(dummy_property);
177       }*/
178       {
179           value = "";
180           FileReader file_reader = null;
181           BufferedReader buffered_reader = null;
182           try
183           {
184               file_reader = new FileReader(lshistory_log_file);
185               buffered_reader = new BufferedReader(file_reader);
186               try
187               {
188                   String line = null;
189                   while ((line = buffered_reader.readLine()) != null)
190                   {
191                       value += line + "\n";
192                   }
193               }
194               catch (IOException io_exception)
195               {
196                   throw new BuildException("Internal error while reading file '" +
197                           lshistory_log_file.getAbsolutePath() + "'", io_exception, location);
198               }
199           }
200           catch (FileNotFoundException file_not_found_exception)
201           {
202               throw new BuildException("Internal error while reading file '" +
203                       lshistory_log_file.getAbsolutePath() + "'", file_not_found_exception, location);
204           }
205           finally
206           {
207               if (buffered_reader != null)
208               {
209                   try
210                   {
211                       buffered_reader.close();
212                   }
213                   catch (IOException io_exception)
214                   {
215                       // Does not matter
216                   }
217               }
218               if (file_reader != null)
219               {
220                   try
221                   {
222                       file_reader.close();
223                   }
224                   catch (IOException io_exception)
225                   {
226                       // Does not matter
227                   }
228               }
229           }
230       }
231       if (value == null)
232       {
233           throw new BuildException("There was an internal error while reading the temporary file '" +
234                   lshistory_log_file.getAbsolutePath() + "'", location);
235       }
236       {
237           Echo echo = new Echo();
238           echo.setProject(getProject());
239           echo.setFile(temporary_file);
240           echo.setAppend(true);
241           echo.setMessage(value);
242           echo.execute();
243       }
244       {
245           Echo echo = new Echo();
246           echo.setProject(getProject());
247           echo.setFile(temporary_file);
248           echo.setAppend(true);
249           echo.setMessage("</events>");
250           echo.execute();
251       }
252 
253       // Now that the XML file has been generated, we can handle it
254       CCEntry[] entry_array = analyzeLsHistory(temporary_file);
255       dumpChangeLog(entry_array);
256   }
257 
258   /***
259    * The 'lshistory' command
260    */
261   public static final String COMMAND_LSHISTORY = "lshistory";
262 
263   /***
264    * The 'lstype' command
265    */
266   public static final String COMMAND_LSTYPE = "lstype";
267 
268   /***
269    * The way ClearCase expresses the date format.
270    */
271   private final SimpleDateFormat clearCaseDateFormat = new SimpleDateFormat("yyyyMMdd.HHmmss");
272 
273   /***
274    * Performs the call to 'lstype' and outputs the result in the provided file.
275    *
276    * @return the file into which the log of the CC command execution should be output
277    */
278   private File performLsType()
279   {
280       log("We perform a 'lstype' call in order to determine the existing labels", Project.MSG_VERBOSE);
281       File temporary_log_file = FileUtils.newFileUtils().createTempFile("ccchangelog_lstype", ".log", null);
282       temporary_log_file.deleteOnExit();
283       ArgumentProvider argument_provider = new ArgumentProvider()
284       {
285           public void provideAdditionalArguments(Commandline command_line)
286           {
287               command_line.createArgument().setLine("-kind lbtype");
288           }
289       };
290       performCCCommand(temporary_log_file, COMMAND_LSTYPE, argument_provider, "%Nd | %n\n");
291       return temporary_log_file;
292   }
293 
294   private void analyzeLsType(File log_file)
295   {
296       log("We now analyze the result of the ClearCase '" + COMMAND_LSTYPE + "' call", Project.MSG_VERBOSE);
297       SimpleDateFormat clearcase_date_format = new SimpleDateFormat("dd-MMMM-yy");
298       try
299       {
300           FileReader file_reader = new FileReader(log_file);
301           BufferedReader buffered_reader = new BufferedReader(file_reader);
302           try
303           {
304               String line = null;
305               while ((line = buffered_reader.readLine()) != null)
306               {
307                   StringTokenizer tokenizer = new StringTokenizer(line, "|");
308                   String timestamp = ((String) tokenizer.nextElement()).trim();
309                   Date date = null;
310                   try
311                   {
312                       date = clearCaseDateFormat.parse(timestamp);
313                   }
314                   catch (ParseException parse_exception)
315                   {
316                       log(parse_exception.getMessage(), Project.MSG_ERR);
317                       throw new BuildException("Parsing of the ClearCase date '" + timestamp +
318                               "' failed during the 'lstype' command log analyzis", parse_exception, location);
319                   }
320                   String label = ((String) tokenizer.nextElement()).trim();
321                   log("Found the label '" + label + "' created '" + date + "'", Project.MSG_VERBOSE);
322                   if (label.equals(_from_label) == true)
323                   {
324                       _from_date = clearcase_date_format.format(date);
325                       log("Found the date of the label '" + label + "' and its creation date is '" + _from_date +
326                               "': this start date will be used", Project.MSG_INFO);
327                   }
328               }
329           }
330           catch (IOException io_exception)
331           {
332               throw new BuildException("Could not analyze the log of the ClearCase command", io_exception, location);
333           }
334       }
335       catch (FileNotFoundException file_not_found_exception)
336       {
337           // Should not happen, given the algorithm
338       }
339   }
340 
341   /***
342    * The XML element that is used internally.
343    */
344   private final String XML_EVENT = "event";
345 
346   /***
347    * Performs the call to 'lshistory' and outputs the result in the provided file.
348    *
349    * @return the file into which the log of the CC command execution should be output
350    */
351   private File performLsHistory()
352   {
353       log("We perform a 'lshistory' call in order to be able to build the ClearCase change log", Project.MSG_VERBOSE);
354       File temporary_log_file = FileUtils.newFileUtils().createTempFile("ccchangelog_lshistory", ".log", null);
355       temporary_log_file.deleteOnExit();
356       ArgumentProvider argument_provider = new ArgumentProvider()
357       {
358           public void provideAdditionalArguments(Commandline command_line)
359           {
360               command_line.createArgument().setValue("-minor");
361               command_line.createArgument().setValue("-recurse");
362               command_line.createArgument().setLine("-since " + _from_date);
363               command_line.createArgument().setValue(getViewPath());
364           }
365       };
366       // The format is very important
367       String format = "<" + XML_EVENT + "><a>%a</a><c><![CDATA[%c]]></c><d>%Nd</d><e>%e</e><f>%f</f><h>%h</h><i>%e</i>" +
368               "<l>%l</l><m>%m</m><n>%n</n>" +
369               "<o>%o</o><p>%p</p><u>%u</u></" + XML_EVENT + ">\n";
370       performCCCommand(temporary_log_file, COMMAND_LSHISTORY, argument_provider, format);
371       return temporary_log_file;
372   }
373 
374   /***
375    * This defines a ClearCase change event.
376    */
377   private static class CCEntry
378   {
379       Date timeStamp;
380       String user;
381       String comment;
382       int type = UNKNOWN;
383       String resource;
384       public String eventName;
385 
386       final static int UNKNOWN = -1;
387       final static int CREATE_VERSION = 1;
388       final static int CREATE_BRANCH = 2;
389       final static int CREATE_CHECKOUT = 3;
390       final static int CREATE_LABEL = 4;
391   }
392 
393   /***
394    * Analyzes the log file resulting from the CC 'lshistory' command execution,
395    * and a bit modified in order to be under the XML format.
396    *
397    * @param log_file
398    */
399   private CCEntry[] analyzeLsHistory(File log_file)
400   {
401       log("We now analyze the result of the ClearCase '" + COMMAND_LSHISTORY + "' call", Project.MSG_VERBOSE);
402       Vector entry_vector = new Vector();
403       Document document = null;
404       try
405       {
406           document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(log_file);
407       }
408       catch (Exception exception)
409       {
410           throw new BuildException("Cannot analyze the log of the ClearCase command", exception, location);
411       }
412       NodeList node_list = document.getDocumentElement().getElementsByTagName(XML_EVENT);
413       for (int index = 0; index < node_list.getLength(); index++)
414       {
415           Node node = node_list.item(index);
416           CCEntry entry = new CCEntry();
417           entry_vector.add(entry);
418           NodeList child_node_list = node.getChildNodes();
419           for (int child_index = 0; child_index < child_node_list.getLength(); child_index++)
420           {
421               Node child_node = child_node_list.item(child_index);
422               String value = null;
423               if (child_node.getChildNodes().item(0) != null)
424               {
425                   if (child_node.getChildNodes().item(0).getNodeType() == Node.TEXT_NODE)
426                   {
427                       value = ((Text) child_node.getChildNodes().item(0)).getData();
428                   }
429                   else if (child_node.getChildNodes().item(0).getNodeType() == Node.CDATA_SECTION_NODE)
430                   {
431                       value = ((CDATASection) child_node.getChildNodes().item(0)).getData();
432                   }
433               }
434               if (child_node.getNodeName().equals("c") == true)
435               {
436                   entry.comment = value;
437 
438               }
439               else if (child_node.getNodeName().equals("d"))
440               {
441                   try
442                   {
443                       entry.timeStamp = clearCaseDateFormat.parse(value);
444                   }
445                   catch (ParseException parse_exception)
446                   {
447                       throw new BuildException("Parsing of a ClearCase event failed", parse_exception, location);
448                   }
449               }
450               else if (child_node.getNodeName().equals("u") == true)
451               {
452                   entry.user = value;
453               }
454               else if (child_node.getNodeName().equals("n") == true)
455               {
456                   entry.resource = value;
457               }
458               else if (child_node.getNodeName().equals("e") == true)
459               {
460                   entry.eventName = value;
461               }
462           }
463       }
464       CCEntry[] entry_array = new CCEntry[entry_vector.size()];
465       entry_vector.toArray(entry_array);
466       return entry_array;
467   }
468 
469   /***
470    * Analyzes the log file resulting from the CC command execution.
471    * <p/>
472    * Has been tested under Windows NTV4.0 SP6 and ClearCase 2002.05.00.
473    * </p>
474    *
475    * @param log_file
476    */
477   private CCEntry[] analyzeLsHistoryOld(File log_file)
478   {
479       log("We now analyze the result of the ClearCase '" + COMMAND_LSHISTORY + "' call", Project.MSG_VERBOSE);
480       Vector entry_vector = new Vector();
481       try
482       {
483           FileReader file_reader = new FileReader(log_file);
484           BufferedReader buffered_reader = new BufferedReader(file_reader);
485           try
486           {
487               String line = buffered_reader.readLine();
488               while (line != null)
489               {
490                   log("Line read:" + line, Project.MSG_DEBUG);
491                   log("We first read the timestamp and the ClearCase user on the first line", Project.MSG_DEBUG);
492                   StringTokenizer timestamp_tokenizer = new StringTokenizer(line, " ");
493                   String timestamp = (String) timestamp_tokenizer.nextElement();
494                   Date date = null;
495                   try
496                   {
497                       date = clearCaseDateFormat.parse(timestamp);
498                   }
499                   catch (ParseException parse_exception)
500                   {
501                       throw new BuildException("Parsing of a ClearCase event failed", parse_exception, location);
502                   }
503                   CCEntry entry = new CCEntry();
504                   entry.timeStamp = date;
505                   entry_vector.add(entry);
506                   String user = line.substring(timestamp.length()).trim();
507                   entry.user = user;
508                   log("Then, the second line displays the ClearCase action", Project.MSG_DEBUG);
509                   line = buffered_reader.readLine();
510                   if (isNewEvent(line))
511                   {
512                       continue;
513                   }
514                   // This line should indicate the type of event
515                   if (line.indexOf("create version") != -1 || line.indexOf("create directory version") != -1)
516                   {
517                       entry.type = CCEntry.CREATE_VERSION;
518                   }
519                   else if (line.indexOf("create branch") != -1)
520                   {
521                       entry.type = CCEntry.CREATE_BRANCH;
522                   }
523                   else if (line.indexOf("checkout version") != -1)
524                   {
525                       entry.type = CCEntry.CREATE_CHECKOUT;
526                   }
527                   else if (line.indexOf("make label") != -1)
528                   {
529                       entry.type = CCEntry.CREATE_LABEL;
530                   }
531                   // If we have identified the type of event, we should be able to analyze the resource it applies on
532                   if (entry.type != CCEntry.UNKNOWN)
533                   {
534                       StringTokenizer resource_tokenizer = new StringTokenizer(line, "\"");
535                       resource_tokenizer.nextElement();
536                       entry.resource = (String) resource_tokenizer.nextElement();
537                   }
538                   line = buffered_reader.readLine().trim();
539                   if (isNewEvent(line))
540                   {
541                       continue;
542                   }
543                   if (line.startsWith("\"") == true)
544                   {
545                       log("We have reached the ClearCase comment", Project.MSG_DEBUG);
546                       String comment = "";
547                       line = line.substring(1);
548                       boolean add_cr = false;
549                       while (true)
550                       {
551                           if (line.endsWith("\"") == true)
552                           {
553                               comment += ((add_cr == true) ? "\n" : "") + line.substring(0, line.length() - 1);
554                               break;
555                           }
556                           comment += ((add_cr == true) ? "\n" : "") + line;
557                           add_cr = true;
558                           line = buffered_reader.readLine().trim();
559                       }
560                       entry.comment = comment;
561                   }
562                   // At last, we read the next line
563                   line = buffered_reader.readLine();
564               }
565           }
566           catch (IOException io_exception)
567           {
568               throw new BuildException("Could not analyze the log of the ClearCase command", io_exception, location);
569           }
570       }
571       catch (FileNotFoundException file_not_found_exception)
572       {
573           // Should not happen, given the algorithm
574       }
575       CCEntry[] entry_array = new CCEntry[entry_vector.size()];
576       entry_vector.toArray(entry_array);
577       return entry_array;
578   }
579 
580   /***
581    * @param line the raw line to analyze
582    * @return whether the given raw line corresponds to a new ClearCase event within the log file
583    */
584   private boolean isNewEvent(String line)
585   {
586       StringTokenizer timestamp_tokenizer = new StringTokenizer(line, " ");
587       try
588       {
589           clearCaseDateFormat.parse((String) timestamp_tokenizer.nextElement());
590       }
591       catch (ParseException parse_exception)
592       {
593           // This means that this is not a line that begins a new ClearCase event description
594           return false;
595       }
596       return true;
597   }
598 
599   /***
600    * Dumps into a file the result of the ClearCase change log analyzis.
601    *
602    * @param entry_array all ClearCase change events
603    */
604   private void dumpChangeLog(CCEntry[] entry_array)
605           throws BuildException
606   {
607       log("We dump the ClearCase change log", Project.MSG_VERBOSE);
608       FileOutputStream output = null;
609       try
610       {
611           output = new FileOutputStream(_destination_file);
612           PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, "ISO-8859-1"));
613           writer.println("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
614           writer.println("<changelog>");
615           SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd");
616           SimpleDateFormat time_format = new SimpleDateFormat("HH:mm");
617           for (int index = 0; index < entry_array.length; index++)
618           {
619               CCEntry entry = entry_array[index];
620               log("Handling the ClearCase event performed '" + entry.timeStamp + "' by '" + entry.user + "'", Project.MSG_VERBOSE);
621               writer.println("\t<entry>");
622               writer.println("\t\t<event>" + entry.eventName + "</event>");
623               if (entry.timeStamp != null)
624               {
625                   writer.println("\t\t<date>" + date_format.format(entry.timeStamp) + "</date>");
626                   writer.println("\t\t<time>" + time_format.format(entry.timeStamp) + "</time>");
627               }
628               writer.println("\t\t<author>" + entry.user + "</author>");
629               if (entry.resource != null)
630               {
631                   writer.println("\t\t<file>");
632                   writer.println("\t\t\t<name>" + entry.resource + "</name>");
633                   writer.println("\t\t</file>");
634               }
635               if (entry.comment != null)
636               {
637                   writer.println("\t\t<msg><![CDATA[" + entry.comment + "]]></msg>");
638               }
639               writer.println("\t</entry>");
640           }
641           writer.println("</changelog>");
642           writer.flush();
643           writer.close();
644       }
645       catch (final UnsupportedEncodingException unsupported_encoding_exception)
646       {
647           throw new BuildException("Does not support the encoding", unsupported_encoding_exception, location);
648       }
649       catch (final IOException io_exception)
650       {
651           throw new BuildException("Error while generating report", io_exception, location);
652       }
653       finally
654       {
655           if (output != null)
656           {
657               try
658               {
659                   output.close();
660               }
661               catch (final IOException io_exception)
662               {
663                   // Does not matter
664               }
665           }
666       }
667   }
668 
669   /***
670    * An interface designed in order to provide additional arguments to the ClearCase command execution.
671    */
672   interface ArgumentProvider
673   {
674       /***
675        * Enables to provide additional arguments to the provided command-line.
676        *
677        * @param command_line the command line additional arguments will be added to
678        */
679       void provideAdditionalArguments(Commandline command_line);
680   }
681 
682   private void performCCCommand(File log_file, String clearcase_command, ArgumentProvider argument_provider, String format)
683           throws BuildException
684   {
685       // We define the command line to be executed
686       Commandline command_line = new Commandline();
687       // Defaults the viewpath to the Ant project 'basedir' if it is not specified
688       if (getViewPath() == null)
689       {
690           setViewPath(getProject().getBaseDir().getPath());
691       }
692       command_line.setExecutable(getClearToolCommand());
693       command_line.createArgument().setValue(clearcase_command);
694       // We handle the format
695       log("The format used in order to extract the information from ClearCase is '" + format + "'", Project.MSG_VERBOSE);
696       command_line.createArgument().setLine("-fmt \"" + format + "\"");
697       // We use the additional arguments that the client needs
698       argument_provider.provideAdditionalArguments(command_line);
699       // Now, we run the command
700       int result = run(command_line, log_file);
701       if (result == Execute.INVALID || result != 0)
702       {
703           String msg = "Failed executing: " + command_line.toString();
704           throw new BuildException(msg, location);
705       }
706   }
707 
708   /***
709    * Runs the ClearCase command via the provided command line, and outputs the log into the provided log file.
710    */
711   protected int run(Commandline command_line, File log_file)
712           throws BuildException
713   {
714       try
715       {
716           Project project = getProject();
717           final FileOutputStream output = new FileOutputStream(log_file.getPath(), false);
718           //final PipedOutputStream output = new PipedOutputStream();
719           //final OutputStream output_stream = new PrintStream(new BufferedOutputStream(output));
720           Execute execute = new Execute(new PumpStreamHandler(output, output));
721           execute.setAntRun(project);
722           String execution_path = getViewPath();
723           if (execution_path == null)
724           {
725               execution_path = project.getBaseDir().getPath();
726           }
727           execute.setWorkingDirectory(new File(execution_path));
728           execute.setCommandline(command_line.getCommandline());
729 
730           /*new Thread(new Runnable()
731           {
732               public void run()
733               {
734                   try
735                   {
736                       PipedInputStream piped_input_stream = new PipedInputStream();
737                       piped_input_stream.connect(output);
738 
739                       //output_stream.write(new byte[]{1, 2, 3});
740                       int index = 0;
741                   }
742                   catch (IOException e)
743                   {
744                       e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
745                   }
746               }
747           }).start();*/
748 
749           return execute.execute();
750       }
751       catch (java.io.IOException io_exception)
752       {
753           throw new BuildException(io_exception, location);
754       }
755   }
756 
757 }