KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > cpmake > CPMake


1 /*
2  * Copyright (c) 2004, Brian Hawkins
3  * brianhks@activeclickweb.com
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the Free
7  * Software Foundation; either version 2 of the License, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the
17  * Free Software Foundation, Inc.,
18  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  */

20  
21 package cpmake;
22  
23 import bsh.*;
24 import java.util.regex.*;
25 import java.util.*;
26 import java.io.*;
27 import java.net.*;
28 import java.lang.reflect.*;
29
30
31 /**
32     General Comments
33 */

34
35 public class CPMake
36     {
37     /**
38     Use with createFileList. Recurse into sub directories when creating file
39     list.
40     */

41     public static final int RECURSE = 0x00000001;
42     /**
43     Use with createFileList. Includes the full path when listing files.
44     */

45     public static final int INCLUDE_PATH = 0x00000002;
46     /**
47     Use with createFileList and in conjunction with INCLUDE_PATH. This makes the
48     path relative to the first parameter of createFileList
49     */

50     public static final int RELATIVE_PATH = 0x00000004;
51     
52     private Vector m_rules;
53     private Vector m_dependencies;
54     private ScriptInterpreter m_interpreter;
55     private Vector m_searchPaths;
56     private String JavaDoc m_defaultTarget;
57     private LinkedList m_buildQueue;
58     private int m_threadCount; //Number of threads to use for building
59
private LinkedList m_threadQueue; //Threads waiting for dependencies
60
private int m_waitingThreadCnt; //Number of threads waiting in build queue for a dependency
61
private int m_activeThreadCnt; //Number of threads working on the build queue. This may be less then m_threadCount as the queue empties
62
private Properties m_properties;
63     private CPMakeException m_makeException;
64     private boolean m_verbose;
65     private boolean m_buildInProgress;
66     private String JavaDoc m_currentTarget;
67     private String JavaDoc m_primaryTarget;
68     private String JavaDoc m_buildFile;
69     private InputWatcher m_inputWatcher;
70     private Vector m_autoCleanDirs; //Directories set with directory rule, used by autocleans
71
private boolean m_modifiedEnv;
72     private DependencyCache m_depCache;
73     private File m_workingDir; //This is the directory in which the build file is located
74
private Map m_scriptObjects; //Map of objects to be added to the script namespace
75

76     
77     private static final int DO_NOT_BUILD = 0;
78     private static final int UNBUILT_DEPENDENCIES = 1;
79     private static final int OUT_OF_DATE = 2;
80     
81     private static final String JavaDoc VERSION = "1.2.0 beta 1";
82     
83     private static boolean s_printDebug = false;
84     
85 /**
86     Creates an instance of CPMake and process the targets on the command line.
87     The options main takes are:<br/>
88     -v Verbose mode. This will echo every command passed to exec and every file
89     copy<br/>
90     -f <file> Build file. If no file is specified "build.bsh" is the default.<br/>
91     -t <num> Number of threads to use. This is the number of threads to use
92     when building a target.<br/>
93     After the options are the list of targets to build.
94     <p>
95     Property files. CPMake loads properties from three locations and makes them
96     available to the script via the getProperty methods. First the system
97     properties are read. Second a cpmake.properties file is read if it exists.
98     Third an env.properties file is read if it exists. In order to gain access
99     to the environment variables the last properties file is used. To use this
100     file you will need to echo the environment to this file before calling CPMake.<br/>
101     An example of this would be to write a script as follows<br/>
102     <code>(windows)<br/>
103     set > env.properties<br/>
104     java -jar cpmake.jar<br/>
105     </code>
106     or<br/>
107     <code>(linux)<br/>
108     env > env.properties<br/>
109     java -jar cpmake.jar<br/>
110     </code>
111     Then for neetness cpmake will delete the env.properties file when it is done.<p>
112     
113     Properties that effect cpmake<br/>
114     (note the underscore versions are for linux envoronment variable compatibility)<br/>
115     cpmake.threadCount or cpmake_threadCount - Setting this property will tell
116     cpmake the number of threads to use while building a target.
117     
118 */

119     public static void main(String JavaDoc[] args)
120         {
121         long startTime;
122         long stopTime;
123         CommandLine cl = new CommandLine(args);
124         String JavaDoc[] targets;
125         CPMake make = null;
126         String JavaDoc buildFile = "";
127         int threadCount = 0;
128         boolean verbose = false;
129         int err = 0;
130
131         
132         cl.setBooleanOptions("?vda");
133         cl.setValueOptions("ft");
134         
135         if (cl.isSet('?'))
136             {
137             printHelp();
138             System.exit(0);
139             }
140         
141         try
142             {
143             if (cl.isSet('v'))
144                 verbose = true;
145             
146             if (cl.isSet('f'))
147                 buildFile = cl.getOptionValue('f');
148             else
149                 {
150                 File f = new File("build.bsh");
151                 if (!f.exists())
152                     f = new File("build.py");
153                     
154                 if (!f.exists())
155                     f = new File("build.gvy");
156                     
157                 if (!f.exists())
158                     f = new File("build.groovy");
159                 
160                 if (!f.exists())
161                     {
162                     System.out.println("No build file specified");
163                     System.exit(-1);
164                     }
165                 else
166                     buildFile = f.getName();
167                 }
168                 
169             if (cl.isSet('d'))
170                 s_printDebug = true;
171             
172             if (cl.isSet('t'))
173                 {
174                 threadCount = Integer.parseInt(cl.getOptionValue('t'));
175                 }
176             
177             startTime = System.currentTimeMillis();
178             targets = cl.getNonOptions();
179             if (targets.length > 0)
180                 for (int I = 0; I < targets.length; I++)
181                     {
182                     make = new CPMake(buildFile, targets[I]);
183                     if (threadCount != 0)
184                         make.setThreadCount(threadCount);
185                     if (make.getProperty("cpmake.debug", "off").equals("on"))
186                         s_printDebug = true;
187                     make.setVerbose(verbose);
188                     make.processBuildFile();
189                     }
190             else
191                 {
192                 make = new CPMake(buildFile, null);
193                 if (threadCount != 0)
194                     make.setThreadCount(threadCount);
195                 if (make.getProperty("cpmake.debug", "off").equals("on"))
196                     s_printDebug = true;
197                 make.setVerbose(verbose);
198                 make.processBuildFile();
199                 }
200                 
201             stopTime = System.currentTimeMillis();
202             long totalTime = stopTime - startTime;
203             long seconds = totalTime / 1000;
204             long minutes = seconds / 60;
205             long hours = minutes / 60;
206             seconds -= minutes * 60;
207             minutes -= hours * 60;
208             Object JavaDoc pargs[] = new Object JavaDoc[] {new Long JavaDoc(hours), new Long JavaDoc(minutes),
209                     new Long JavaDoc(seconds)};
210             System.out.println(Printf.print("Build time: %02d:%02d:%02d", pargs));
211             //System.out.println("Build time: "+hours+":"+minutes+":"+seconds);
212
}
213         catch (CPMakeException cpme)
214             {
215             System.out.println(cpme.getDescription());
216             err = cpme.getReturnError();
217             //System.exit(cpme.getReturnError());
218
}
219         catch (Exception JavaDoc e)
220             {
221             System.out.println(e.getMessage());
222             e.printStackTrace();
223             }
224             
225         //Clean up the environment properties file
226
File env = new File("env.properties");
227         if (env.exists())
228             env.delete();
229             
230         try
231             {
232             debugPrint("Saving cache file");
233             DependencyCache.writeDependencyCache();
234             }
235         catch (IOException ioe)
236             {
237             debugPrint(ioe.getMessage());
238             StringWriter sw = new StringWriter();
239             ioe.printStackTrace(new PrintWriter(sw));
240             debugPrint(sw.toString());
241             System.out.println("Unable to save cache file "+DependencyCache.getCacheFile());
242             }
243             
244         if (cl.isSet('a')||(make.getProperty("cpmake.finishNotify", "off").equals("on")))
245             {
246             System.out.write(7);
247             System.out.flush();
248             }
249                     
250         //System.exit is required to kill the InputWatcher thread
251
System.exit(err);
252         }
253
254 //-------------------------------------------------------------------
255
private static void printHelp()
256         {
257         System.out.println("CPMake the Cross Platform Make Utility (version = " + VERSION+")");
258         System.out.println("Copyright (C) 2004, Brian Hawkins");
259         System.out.println("Licensed under GNU General Public License\n");
260         System.out.println("CPMake Command line help.");
261         System.out.println("Usage: java -jar cpmake.jar [-v] [-f <build file>] [-t <thread count>] [<targets>]");
262         System.out.println(" -v : Verbose output");
263         System.out.println(" -f : Build file to process");
264         System.out.println(" -t : Number of threads to use");
265         System.out.println(" -d : Print debug messages");
266         System.out.println(" -a : System beep when build is done");
267         
268         }
269         
270 //===================================================================
271
public static void debugPrint(String JavaDoc msg)
272         {
273         if (s_printDebug)
274             System.out.println("CPMake-Debug: "+msg);
275         }
276         
277 //-------------------------------------------------------------------
278
private int getActiveThreadCnt()
279         {
280         return (m_activeThreadCnt);
281         }
282         
283 //-------------------------------------------------------------------
284
private String JavaDoc[] getEnvArr()
285         {
286         Enumeration e = m_properties.propertyNames();
287         String JavaDoc key;
288         Vector env = new Vector();
289         
290         if (!m_modifiedEnv)
291             return (null);
292         
293         while (e.hasMoreElements())
294             {
295             key = (String JavaDoc)e.nextElement();
296             env.add(key+"="+m_properties.getProperty(key));
297             }
298             
299         return ((String JavaDoc[])env.toArray(new String JavaDoc[0]));
300         }
301         
302 //-------------------------------------------------------------------
303
private Rule getRule(String JavaDoc target)
304             throws CPMakeException
305         {
306         Iterator it = m_rules.iterator();
307         Rule rule = null;
308         Rule ret = null;
309         Rule patret = null;
310         boolean patexists = false;
311         boolean tmpexists = false;
312         
313         while (it.hasNext())
314             {
315             rule = (Rule)it.next();
316             
317             if (rule.matchTarget(target))
318                 {
319                 if (rule instanceof PatternRule)
320                     {
321                     if (patret != null)
322                         {
323                         tmpexists = locateFile(rule.getPrerequisites(target)[0]) != null;
324                         if (patexists && tmpexists)
325                             throw new CPMakeException("Multiple pattern rules for target: "+target, -1);
326                         else if (tmpexists)
327                             {
328                             patexists = true;
329                             patret = rule;
330                             }
331                         }
332                     else
333                         {
334                         patret = rule;
335                         patexists = (locateFile(patret.getPrerequisites(target)[0]) != null);
336                         }
337                     }
338                 else if (ret != null)
339                     throw new CPMakeException("Multiple rules for target: "+target, -1);
340                 else
341                     ret = rule;
342                 }
343             }
344         
345         //This gives precidence to explicit rules over pattern rules
346
if (ret == null)
347             ret = patret;
348             
349         return (ret);
350         }
351         
352     
353 //-------------------------------------------------------------------
354
private File getFile(String JavaDoc file)
355         {
356         File f = locateFile(file);
357         if (f == null)
358             f = new File(m_workingDir, file);
359             
360         return (f);
361         }
362
363 //-------------------------------------------------------------------
364
private void loadVector(Vector v, String JavaDoc[] s)
365         {
366         if (s.length > 0)
367             {
368             for (int I = 0; I < s.length; I++)
369                 {
370                 if (s[I].length() != 0)
371                     v.add(s[I]);
372                 //System.out.print(s[I] + " ");
373
}
374             }
375         }
376         
377 //-------------------------------------------------------------------
378
private String JavaDoc[] getPrerequisites(String JavaDoc target, Rule rule, boolean useDepCache)
379             throws CPMakeException
380         {
381         Vector prereqs = new Vector();
382         Dependency dep;
383         String JavaDoc[] rulePre;
384         
385         rulePre = rule.getPrerequisites(target);
386         
387         loadVector(prereqs, rulePre);
388         
389         
390         if ((!getProperty("cpmake.dependencyCheck", "on").equals("off")) &&
391                 (useDepCache))
392             {
393             if ((rulePre.length > 0) && (m_depCache.canParse(rulePre[0])))
394                 prereqs.addAll(m_depCache.getDependencies(this, rulePre[0]));
395             else if (m_depCache.canParse(target))
396                 prereqs.addAll(m_depCache.getDependencies(this, target));
397             }
398             
399         if (m_dependencies.size() > 0)
400             {
401             for (int I = 0; I < m_dependencies.size(); I++)
402                 {
403                 dep = (Dependency)m_dependencies.elementAt(I);
404                 if (dep.matchTarget(target))
405                     {
406                     loadVector(prereqs, dep.getDependencies(target));
407                     }
408                 }
409             }
410         
411         
412         return ((String JavaDoc[])prereqs.toArray(new String JavaDoc[0]));
413         }
414         
415 //-------------------------------------------------------------------
416
private BuildAction[] rebuildTarget(String JavaDoc target, Rule rule)
417             throws CPMakeException
418         {
419         String JavaDoc[] prereqs = getPrerequisites(target, rule, true);
420         BuildAction[] ret = null;
421         Vector buildDep = new Vector();
422         BuildAction ba;
423         long targetTime = 0;
424         File f;
425         boolean tExists = true;
426         boolean tDir = false;
427         boolean tPhony = true;
428         
429         
430         //lastModified returns 0 if the file does not exist
431
if (!(rule instanceof PhonyRule))
432             {
433             File t = getFile(target);
434             
435             targetTime = t.lastModified();
436             tExists = t.exists();
437             tDir = t.isDirectory();
438             tPhony = false;
439             }
440             
441         //System.out.println(target + " = "+ targetTime);
442
if (prereqs.length > 0)
443             {
444             for (int I = 0; I < prereqs.length; I++)
445                 {
446                 f = getFile(prereqs[I]);
447                 if ((ba = addToBuildQueue(prereqs[I])) != null)
448                     buildDep.add(ba);
449                 else if ( (ret == null) && (((!tDir) && (!f.isDirectory()) && (!tPhony)) &&
450                         (f.lastModified() > targetTime) || (!tExists) ))
451                     {
452                     ret = new BuildAction[0];
453                     }
454                 }
455             
456             if (buildDep.size() > 0)
457                 ret = (BuildAction[])buildDep.toArray(new BuildAction[0]);
458             }
459         else if (((!tExists) && (!tPhony)) || (tPhony && target.equals(m_primaryTarget)))
460             {
461             debugPrint("target: "+target+" does not exist.");
462             ret = new BuildAction[0];
463             }
464             
465         return (ret);
466         }
467         
468 //-------------------------------------------------------------------
469
private BuildAction addToBuildQueue(String JavaDoc target)
470             throws CPMakeException
471         {
472         return (addToBuildQueue(target, false));
473         }
474         
475 //-------------------------------------------------------------------
476
private BuildAction addToBuildQueue(String JavaDoc target, boolean primaryTarget)
477             throws CPMakeException
478         {
479         Rule rule = getRule(target);
480         File targetFile = null;
481         BuildAction[] buildDep = null;
482         BuildAction ba = null;
483         
484         if ((rule == null)&&(target.equals("clean")))
485             rule = new CleanRule(this);
486         
487         if (rule == null)
488             {
489             targetFile = getFile(target);
490             
491             if (!targetFile.exists())
492                 {
493                 throw new CPMakeException("Unable to locate rule for " + target, -1);
494                 }
495             }
496         else
497             {
498             ba = new BuildAction(target, rule);
499             int index;
500             
501             if ((index = m_buildQueue.indexOf(ba)) != -1)
502                 {
503                 debugPrint("target: "+target+" already in build queue.");
504                 //Target has already been added to build queue
505
ba = (BuildAction)m_buildQueue.get(index);
506                 }
507             else if ((buildDep = rebuildTarget(target, rule)) != null)
508                 {
509                 debugPrint("Adding target: "+target+" to build queue.");
510                 ba.addDependencies(buildDep);
511                 
512                 m_buildQueue.addFirst(ba);
513                 }
514             else if (primaryTarget && (rule instanceof PhonyRule))
515                 {
516                 debugPrint("Adding primary target: "+target+" to build queue.");
517                 m_buildQueue.addFirst(ba);
518                 }
519             else
520                 {
521                 //System.out.println("Not adding "+target);
522
ba = null;
523                 }
524             }
525             
526         return (ba);
527         }
528         
529 //-------------------------------------------------------------------
530
private void processBuildQueue()
531             throws CPMakeException
532         {
533         BuildAction ba;
534         Rule rule;
535         String JavaDoc target;
536         Thread JavaDoc t;
537         //Create the script variable names that use the current
538
//thread name so as to be unique
539
String JavaDoc param1 = "param1t" + Thread.currentThread().getName();
540         String JavaDoc param2 = "param2t" + Thread.currentThread().getName();
541         
542         do
543             {
544             synchronized (this)
545                 {
546                 try
547                     {
548                     ba = (BuildAction)m_buildQueue.removeLast();
549                     }
550                 catch (NoSuchElementException nsee)
551                     {
552                     ba = new BuildAction(null, null);
553                     }
554                 
555                 if (m_threadCount > 1)
556                     {
557                     int depCount = ba.getDependencyCount();
558                     if ((m_waitingThreadCnt > 0)||(depCount > 0))
559                         {
560                         m_threadQueue.addFirst(Thread.currentThread());
561                         if (depCount > 0)
562                             m_waitingThreadCnt++;
563                             
564                         if (m_threadQueue.size() == m_threadCount)
565                             {
566                             t = (Thread JavaDoc)m_threadQueue.getLast();
567                             t.interrupt();
568                             }
569                             
570                         do
571                             {
572                             try
573                                 {
574                                 wait();
575                                 }
576                             catch (InterruptedException JavaDoc ie)
577                                 {
578                                 Thread.interrupted(); //Clear interupted flag
579
}
580                             } while ((ba.getDependencyCount() > 0)&&(m_makeException == null));
581                         
582                         if (m_makeException != null)
583                             {
584                             notifyAll();
585                             throw m_makeException;
586                             }
587                         
588                         m_threadQueue.removeLast(); //Remove this thread
589
if (depCount > 0)
590                             m_waitingThreadCnt--;
591                             
592                         try
593                             {
594                             t = (Thread JavaDoc)m_threadQueue.getLast();
595                             t.interrupt(); //Wake up the next thread so it can see if it can go
596
}
597                         catch (NoSuchElementException nsee) {}
598                         }
599                     }
600                 }
601                 
602             rule = ba.getTargetRule();
603             target = ba.getTarget();
604             if ((rule != null)&&(rule.hasAction()))
605                 {
606                 rule.callAction(fixPath(target));
607                 
608                 if (rule.getScriptCall() != null)
609                     {
610                     m_interpreter.set(param1, fixPath(target));
611                     m_interpreter.set(param2, rule.getPrerequisites(target));
612                     
613                     debugPrint("Calling "+rule.getScriptCall()+" for "+target);
614                     m_interpreter.call(rule.getScriptCall(), param1, param2);
615                     }
616                     
617                 if (rule.verify())
618                     {
619                     File f = new File(m_workingDir, target);
620                     if (!f.exists())
621                         {
622                         throw new CPMakeException("Unable to verify target "+target, -1);
623                         }
624                     }
625                     
626                 ba.complete(); //Complete the BuildAction
627
}
628             } while ((ba.getTarget() != null)&&(m_makeException == null));
629             
630         //This causes worker threads to die off and the exception to
631
//pass to the main thread
632
if (m_makeException != null)
633             throw m_makeException;
634         }
635         
636 //-------------------------------------------------------------------
637
private void loadPropertiesFile(String JavaDoc fileName)
638         {
639         PropertiesFile pf = new PropertiesFile(new File(m_workingDir, fileName).getAbsolutePath());
640         
641         loadProperties(pf);
642         }
643         
644 //---------------------------------------------------------------------
645
private void loadProperties(Properties prop)
646         {
647         Enumeration en = prop.propertyNames();
648         String JavaDoc name;
649         
650         while (en.hasMoreElements())
651             {
652             name = (String JavaDoc)en.nextElement();
653             
654             setProperty(name, prop.getProperty(name));
655             }
656         }
657
658 //---------------------------------------------------------------------
659
private void loadProperties(Reader input)
660         {
661         BufferedReader br;
662         String JavaDoc line;
663         String JavaDoc[] split;
664         
665         try
666             {
667             br = new BufferedReader(input);
668             while ((line = br.readLine()) != null)
669                 {
670                 split = line.split("=", 2);
671                 setProperty(split[0], split[1]);
672                 }
673             br.close();
674             }
675         catch (IOException e)
676             {
677             debugPrint(e.getMessage());
678             }
679         }
680         
681 //---------------------------------------------------------------------
682
private void loadEnvProperties()
683         {
684         File f = new File("env.properties");
685         Process JavaDoc proc;
686         String JavaDoc cmd;
687         
688         if (f.exists())
689             {
690             m_modifiedEnv = true;
691             try
692                 {
693                 loadProperties(new FileReader(f));
694                 }
695             catch (FileNotFoundException fnfe) {}
696             }
697         else
698             {
699             if (System.getProperty("os.name").startsWith("Windows"))
700                 cmd = "cmd /D /C set";
701             else
702                 cmd = "printenv";
703
704             try
705                 {
706                 proc = Runtime.getRuntime().exec(cmd);
707             
708                 loadProperties(new InputStreamReader(proc.getInputStream()));
709             
710                 proc.waitFor();
711                 }
712             catch (Exception JavaDoc e)
713                 {
714                 debugPrint(e.getMessage());
715                 }
716             }
717         }
718         
719 //---------------------------------------------------------------------
720
private void runThread()
721         {
722         try
723             {
724             synchronized(this)
725                 {
726                 m_activeThreadCnt++;
727                 }
728             processBuildQueue();
729             synchronized(this)
730                 {
731                 m_activeThreadCnt--;
732                 if (m_activeThreadCnt == 0)
733                     notify();
734                 }
735             }
736         catch (CPMakeException cpme)
737             {
738             m_makeException = cpme;
739             synchronized(this)
740                 {
741                 notifyAll();
742                 }
743             }
744         }
745         
746         
747 //===================================================================
748
/**
749     Creaes a CPMake object.
750     
751     @param buildFile Build file to process in order to build the primary
752     target
753     @param primaryTarget After reading the build file this target will be passed
754     to buildTarget. If this is null the default target will be built if one is set
755     in the build file.
756 */

757     public CPMake(String JavaDoc buildFile, String JavaDoc primaryTarget)
758         {
759         this(null, buildFile, primaryTarget);
760         }
761
762 //===================================================================
763
/**
764     Creates a CPMake object.
765     
766     @param make CPMake object to inherit settings from.
767     @param buildFile Build file to process in order to build the primary
768     target
769     @param primaryTarget After reading the build file this target will be passed
770     to buildTarget. If this is null the default target will be built if one is set
771     in the build file.
772 */

773     public CPMake(CPMake make, String JavaDoc buildFile, String JavaDoc primaryTarget)
774         {
775         m_rules = new Vector();
776         m_dependencies = new Vector();
777         m_searchPaths = new Vector();
778         m_buildFile = buildFile;
779         m_primaryTarget = primaryTarget;
780         m_defaultTarget = null;
781         m_buildInProgress = false;
782         m_threadQueue = new LinkedList();
783         m_waitingThreadCnt = 0;
784         m_properties = new Properties(System.getProperties());
785         m_inputWatcher = InputWatcher.getInputWatcher();
786         m_autoCleanDirs = new Vector();
787         m_modifiedEnv = false;
788         m_depCache = DependencyCache.getDependencyCache(".cpmakecache");
789         m_scriptObjects = new HashMap();
790         
791         m_workingDir = new File(m_buildFile).getParentFile();
792         
793         if (make == null)
794             {
795             File f = new File(m_workingDir, "cpmake.properties");
796             if (f.exists())
797                 loadPropertiesFile("cpmake.properties");
798             loadEnvProperties();
799             
800             m_activeThreadCnt = 0;
801             m_makeException = null;
802             m_threadCount = Integer.parseInt(getProperty("cpmake.threadCount", "1"));
803             }
804         else
805             {
806             m_threadCount = make.m_threadCount;
807             loadProperties(make.m_properties);
808             m_verbose = make.m_verbose;
809             }
810         }
811         
812 //-------------------------------------------------------------------
813
/**
814     Processes the build file and builds the primary target.
815 */

816     public void processBuildFile()
817             throws CPMakeException
818         {
819         if (m_buildFile.endsWith(".bsh"))
820             {
821             try
822                 {
823                 m_interpreter = new BeanShellInterpreter();
824                 }
825             catch (NoClassDefFoundError JavaDoc ncdfe)
826                 {
827                 throw new CPMakeException("Unable to find Bean shell interpreter", -1);
828                 }
829             }
830         else if (m_buildFile.endsWith(".py"))
831             {
832             try
833                 {
834                 m_interpreter = new JythonShellInterpreter(this);
835                 }
836             catch (NoClassDefFoundError JavaDoc ncdfe)
837                 {
838                 throw new CPMakeException("Unable to find Jython interpreter", -1);
839                 }
840             }
841         else if (m_buildFile.endsWith(".groovy")||(m_buildFile.endsWith(".gvy")))
842             {
843             try
844                 {
845                 m_interpreter = new GroovyShellInterpreter();
846                 }
847             catch (NoClassDefFoundError JavaDoc ncdfe)
848                 {
849                 throw new CPMakeException("Unable to find Groovy interpreter\n" + ncdfe.toString(), -1);
850                 }
851             }
852         else
853             throw new CPMakeException("Unknown build script type", -1);
854             
855         try
856             {
857             String JavaDoc name;
858             Iterator it = m_scriptObjects.keySet().iterator();
859             while (it.hasNext())
860                 {
861                 name = (String JavaDoc)it.next();
862                 m_interpreter.set(name, m_scriptObjects.get(name));
863                 }
864             m_interpreter.set("make", this);
865             debugPrint("Processing "+m_buildFile);
866             m_interpreter.source(m_buildFile);
867             
868             if (m_primaryTarget == null)
869                 throw new CPMakeException("No target specified", -1);
870             debugPrint("Building target "+m_primaryTarget);
871             buildTarget(m_primaryTarget);
872             m_interpreter.cleanup();
873             }
874         catch(CPMakeException cpme)
875             {
876             m_makeException = cpme;
877             synchronized(this)
878                 {
879                 notifyAll();
880                 }
881             throw cpme;
882             }
883         catch(IOException ioe)
884             {
885             m_makeException = new CPMakeException("Unable to load "+m_buildFile, -1);
886             synchronized(this)
887                 {
888                 notifyAll();
889                 }
890             throw m_makeException;
891             }
892         
893         }
894         
895 //-------------------------------------------------------------------
896
/**
897     Returns the primary build target. This may be null if no primary target
898     has been given and a default has not yet been set.
899     
900     @return Primary build target or null.
901 */

902     public String JavaDoc getPrimaryTarget()
903         {
904         return (m_primaryTarget);
905         }
906         
907 //-------------------------------------------------------------------
908
/**
909     Creates a pattern rule for building a target.<p>
910     
911     Example:<br/>
912     createPatternRule("(.*)\.obj", "$1.cpp", "compile", true);<br/>
913     In this example to build any .obj file the corosponding .cpp file is
914     the prerequisite and the script method compile is called to build this
915     target. Also the target will be verified afterwards.
916     
917     @param pattern Regex pattern of the target
918     @param replacement Replacement string used to identify the prerequisite of
919     the target.
920     @param scriptCall The name of the method in the make file to call in order
921     to process this rule.
922     @param verify Verify the target after the script call is made
923 */

924     public void createPatternRule(String JavaDoc pattern, String JavaDoc replacement, String JavaDoc scriptCall, boolean verify)
925         {
926         m_rules.add(new PatternRule(this, pattern, replacement, scriptCall, verify));
927         }
928         
929 //-------------------------------------------------------------------
930
/**
931     Creates an explicit rule for building a target.<p>
932     
933     The target can either be a file or a directory in the file system. This rule
934     is excercised if any of the prerequisites are new then the target.
935     
936     @param target The file or directory to create by this rule.
937     @param prerequisites This can either be a single prerequisite or a list
938     that is sperated by spaces. Can be null.
939     @param scriptCall The name of the method in the make file to call in order
940     to process this rule.
941     @param verify Verify the target after the script call is made.
942 */

943     public void createExplicitRule(String JavaDoc target, String JavaDoc prerequisites, String JavaDoc scriptCall, boolean verify)
944             throws CPMakeException
945         {
946         if (prerequisites == null)
947             createExplicitRule(target, new String JavaDoc[0], scriptCall, verify);
948         else
949             createExplicitRule(target, prerequisites.split(" "), scriptCall, verify);
950         }
951         
952 //-------------------------------------------------------------------
953
/**
954     Creates an explicit rule for building a target.<p>
955     
956     The target can either be a file or a directory in the file system. This rule
957     is excercised if any of the prerequisites are new then the target.
958     
959     @param target The file or directory to create by this rule.
960     @param prerequisites An array of prerequisites for this target.
961     @param scriptCall The name of the method in the make file to call in order
962     to process this rule.
963     @param verify Verify the target after the script call is made.
964 */

965     public void createExplicitRule(String JavaDoc target, String JavaDoc[] prerequisites, String JavaDoc scriptCall, boolean verify)
966             throws CPMakeException
967         {
968         Rule r;
969         if (prerequisites == null)
970             prerequisites = new String JavaDoc[0];
971             
972         /*if ((r = getRule(target)) != null)
973             {
974             if ((r.getPrerequisites(target).length == 0)&&(!r.hasAction()))
975                 {
976                 m_rules.remove(r); //Remove empty rule that was added by createDependency
977                 }
978             else
979                 {
980                 throw new CPMakeException("Multiple rules defined for "+target, -1);
981                 }
982             }*/

983         m_rules.add(new ExplicitRule(target, prerequisites, scriptCall, verify));
984         }
985         
986 //-------------------------------------------------------------------
987
/**
988 */

989     public void createDirectoryRule(String JavaDoc directory, String JavaDoc[] prerequisites, boolean echo)
990             throws CPMakeException
991         {
992         Rule r;
993         if (prerequisites == null)
994             prerequisites = new String JavaDoc[0];
995             
996         m_autoCleanDirs.add(fullPath(directory));
997         
998         m_rules.add(new DirectoryRule(this, directory, prerequisites, echo));
999         }
1000//-------------------------------------------------------------------
1001
/**
1002    Creates a phony target rule.
1003    
1004    If the phony rule has no prerequisites it is excersized all the time. If the
1005    prerequisites are up to date then this rule is not processed.
1006    
1007    @param target Phony target
1008    @param prerequisites A list of prerequisites that are sperated by spaces. Can
1009    be null.
1010    @param scriptCall The name of the method in the make file to call in order
1011    to process this rule.
1012*/

1013    public void createPhonyRule(String JavaDoc target, String JavaDoc prerequisites, String JavaDoc scriptCall)
1014        {
1015        if (prerequisites == null)
1016            createPhonyRule(target, new String JavaDoc[0], scriptCall);
1017        else
1018            createPhonyRule(target, prerequisites.split(" "), scriptCall);
1019        }
1020        
1021//-------------------------------------------------------------------
1022
/**
1023    Creates a phony target rule.
1024    
1025    If the phony rule has no prerequisites it is excersized all the time. If the
1026    prerequisites are up to date then this rule is not processed.
1027    
1028    @param target Phony target
1029    @param prerequisites An array of prerequisites.
1030    @param scriptCall The name of the method in the make file to call in order
1031    to process this rule.
1032*/

1033    public void createPhonyRule(String JavaDoc target, String JavaDoc[] prerequisites, String JavaDoc scriptCall)
1034        {
1035        if (prerequisites == null)
1036            prerequisites = new String JavaDoc[0];
1037            
1038        m_rules.add(new PhonyRule(target, prerequisites, scriptCall));
1039        }
1040        
1041//-------------------------------------------------------------------
1042
/**
1043    Creates a pattern dependency.
1044    
1045    Example<br/>
1046    createPatternDependency("(.*)\\.obj", "$1.h");<br/>
1047    This states that all obj files are dependent on a corrosponding h file.
1048    I the h file is newer then the obj file a rule will be located to rebuild
1049    the obj file.
1050    These prerequisites are not passed to the script file.
1051    
1052    @param pattern Pattern of the target files to add dependencies to.
1053    @param replacement The dependency of the target. This can either be a
1054    replacement pattern as the one in the example above or the name of a target.
1055*/

1056    public void createPatternDependency(String JavaDoc pattern, String JavaDoc replacement)
1057        {
1058        m_dependencies.add(new PatternDependency(this, pattern, replacement));
1059        }
1060        
1061//-------------------------------------------------------------------
1062
/**
1063    Creates a pattern dependency
1064    
1065    Calling this is the same as calling createPatternDependency(String, String)
1066    over and over for each string in the prerequisite array.
1067    
1068    @param pattern Pattern of the target files to add depenencies to.
1069    @param prerequisites List of dependencies to add to this pattern.
1070*/

1071    public void createPatternDependency(String JavaDoc pattern, String JavaDoc[] prerequisites)
1072        {
1073        for (int I = 0; I < prerequisites.length; I++)
1074            m_dependencies.add(new PatternDependency(this, pattern, prerequisites[I]));
1075        }
1076        
1077//-------------------------------------------------------------------
1078
/**
1079    Creates dependecies for the given target.
1080    
1081    These prerequisites are not passed to the script file.
1082    @param target Target to add dependencies to.
1083    @param prerequisites A list of prerequisites seperated by spaces. Can be null.
1084*/

1085    public void createExplicitDependency(String JavaDoc target, String JavaDoc prerequisites)
1086        {
1087        if (prerequisites == null)
1088            createExplicitDependency(target, new String JavaDoc[0]);
1089        else
1090            createExplicitDependency(target, prerequisites.split(" "));
1091        }
1092        
1093//-------------------------------------------------------------------
1094
/**
1095    Creates dependecies for the given target.
1096    
1097    These prerequisites are not passed to the script file.
1098    @param target Target to add dependencies to.
1099    @param prerequisites An array of prerequisites.
1100*/

1101    public void createExplicitDependency(String JavaDoc target, String JavaDoc[] prerequisites)
1102        {
1103        /*if (getRule(target) == null)
1104            {
1105            System.out.println("ExplicitRule for "+target);
1106            m_rules.add(new ExplicitRule(target, new String[0], null, false));
1107            }*/

1108        m_dependencies.add(new ExplicitDependency(this, new File(m_workingDir, target), prerequisites));
1109        }
1110        
1111//-------------------------------------------------------------------
1112
/**
1113    Processes the rule for the given target.
1114    
1115    Before the build queue is generated for the specified target an attempt is
1116    made to call a script function that matches the following signiture<br/>
1117    void prepForTarget(String target);<p>
1118    This allows the script to set up any special varaibles for the target.
1119    
1120    @param target Target to be built.
1121*/

1122    public void buildTarget(String JavaDoc target)
1123            throws CPMakeException
1124        {
1125        buildTarget(target, true);
1126        }
1127        
1128//-------------------------------------------------------------------
1129
/**
1130    Processes the rule for the given target.
1131    
1132    Before the build queue is generated for the specified target an attempt is
1133    made to call a script function that matches the following signiture<br/>
1134    void prepForTarget(String target);<p>
1135    This allows the script to set up any special varaibles for the target.
1136    
1137    @param target Target to be built.
1138    @param prep If true prepForTarget is called otherwise it is not
1139*/

1140    public void buildTarget(String JavaDoc target, boolean prep)
1141            throws CPMakeException
1142        {
1143        Rule rule = getRule(target);
1144        File targetFile = null;
1145        Thread JavaDoc t;
1146        Dependency d;
1147        
1148        if (prep)
1149            {
1150            try
1151                {
1152                m_interpreter.set("currentBuildTarget", target);
1153                m_interpreter.call("prepForTarget", "currentBuildTarget");
1154                }
1155            catch (Exception JavaDoc e)
1156                {
1157                //Need to catch specific exception for when method does not exist
1158
}
1159            }
1160        
1161        if (m_buildInProgress)
1162            throw new CPMakeException("Build already in progress for "+m_currentTarget, -1);
1163            
1164        /*for (int I = 0; I < m_dependencies.size(); I++)
1165            {
1166            d = (Dependency)m_dependencies.elementAt(I);
1167            System.out.println(d.toString());
1168            }*/

1169            
1170            
1171        m_currentTarget = target;
1172        m_buildInProgress = true;
1173        m_buildQueue = new LinkedList();
1174        if (addToBuildQueue(target, true) != null)
1175            {
1176            if (m_verbose)
1177                System.out.println("Using " + m_threadCount +" threads");
1178            //Using the thread name as a unique id for that thread
1179
//Used to set script variables for that thread
1180
Thread.currentThread().setName("0");
1181            if (m_threadCount > 1)
1182                for (int I = 1; I < m_threadCount; I++)
1183                    {
1184                    t = new Thread JavaDoc(new Runnable JavaDoc()
1185                        {
1186                        public void run()
1187                            {
1188                            runThread();
1189                            }
1190                        });
1191                    t.setName("" + I);
1192                    t.start();
1193                    }
1194            
1195            processBuildQueue();
1196            }
1197            
1198        try
1199            {
1200            synchronized(this)
1201                {
1202                if (getActiveThreadCnt() > 0)
1203                    wait();
1204                }
1205            }
1206        catch (InterruptedException JavaDoc ie) {}
1207        
1208        m_buildInProgress = false;
1209            
1210        }
1211        
1212//-------------------------------------------------------------------
1213
/**
1214    Converts an array into a string seperated by spaces.
1215    There is also a space left on the end of the string.<p>
1216    {"foo", "bar"} would become "foo bar "
1217    
1218    @param array Array to be turned into a string.
1219*/

1220    public static String JavaDoc arrayToString(String JavaDoc[] array)
1221        {
1222        StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
1223        
1224        for (int I = 0; I < array.length; I++)
1225            sb.append(array[I] + " ");
1226            
1227        return (sb.toString());
1228        }
1229        
1230//-------------------------------------------------------------------
1231
/**
1232    Adds a path to search when looking for targets.
1233    
1234    @param path Path to search for targets and prerequisites.
1235*/

1236    public void addSearchPath(String JavaDoc path)
1237        {
1238        addSearchPaths(".*", new String JavaDoc[] {path});
1239        }
1240        
1241//-------------------------------------------------------------------
1242
/**
1243    Tells CPMake to echo out build information
1244    
1245    @param verbose Whether to be verbose or not.
1246*/

1247    public void setVerbose(boolean verbose)
1248        {
1249        m_verbose = verbose;
1250        }
1251        
1252//-------------------------------------------------------------------
1253
/**
1254    Adds a path to search when looking for targets that match the given
1255    pattern.
1256    
1257    @param pattern File pattern (regex) for this search path.
1258    @param path Path to search
1259*/

1260    public void addSearchPath(String JavaDoc pattern, String JavaDoc path)
1261        {
1262        addSearchPaths(pattern, new String JavaDoc[] {path});
1263        }
1264        
1265//-------------------------------------------------------------------
1266
/**
1267    Adds search paths to look in when trying to find files.
1268    
1269    @param paths Array of file paths to search
1270*/

1271    public void addSearchPaths(String JavaDoc[] paths)
1272        {
1273        addSearchPaths(".*", paths);
1274        }
1275        
1276//-------------------------------------------------------------------
1277
/**
1278    Adss paths to search when looking for targets that match the given
1279    pattern
1280    
1281    @param pattern File pattern (regex) for this search path.
1282    @param paths Paths to search
1283*/

1284    public void addSearchPaths(String JavaDoc pattern, String JavaDoc[] paths)
1285        {
1286        for (int I = 0; I < paths.length; I++)
1287            m_searchPaths.add(new SearchPath(pattern, paths[I]));
1288        }
1289        
1290//-------------------------------------------------------------------
1291
/**
1292    Tries to locate a file by looking in the search paths.
1293    
1294    @param file The file name to look for.
1295    
1296    @return The file object or null if none is found.
1297*/

1298    public File locateFile(String JavaDoc file)
1299        {
1300        Iterator it = m_searchPaths.iterator();
1301        SearchPath sp;
1302        String JavaDoc path;
1303        File ret = null;
1304        File f;
1305        
1306        f = new File(m_workingDir, file);
1307        if (f.exists())
1308            ret = f;
1309        else
1310            {
1311            while (it.hasNext())
1312                {
1313                sp = (SearchPath)it.next();
1314                
1315                if (sp.matches(file))
1316                    {
1317                    path = sp.getPath();
1318                    f = new File(new File(m_workingDir, path), file);
1319                    if (f.exists())
1320                        {
1321                        ret = f;
1322                        break;
1323                        }
1324                    }
1325                }
1326            }
1327        return (ret);
1328        }
1329        
1330//--------------------------------------------------------------------
1331
/**
1332    
1333*/

1334    String JavaDoc getPath(File file)
1335        {
1336        String JavaDoc ret;
1337        
1338        ret = file.getPath();
1339        
1340        if (m_workingDir != null)
1341            {
1342            if (ret.startsWith(m_workingDir.getPath()))
1343                ret = ret.substring(m_workingDir.getPath().length() +1);
1344            }
1345        
1346        return (ret);
1347        }
1348//--------------------------------------------------------------------
1349
/**
1350    Fixes the directory seperators for the current platform.
1351    
1352    It is encuraged to use only forward slashes in make files and then call
1353    this function when the path will be handed to a platform specific call.
1354    
1355    @param path Path to be checked for correct seperators
1356    
1357    @return The path with the directory sperators appropriat for the platform.
1358*/

1359    public static String JavaDoc fixPath(String JavaDoc path)
1360        {
1361        String JavaDoc slash = System.getProperty("file.separator");
1362        
1363        if (slash.equals("/"))
1364            path = path.replace('\\', '/');
1365        else
1366            path = path.replace('/', '\\');
1367            
1368        return (path);
1369        }
1370
1371//--------------------------------------------------------------------
1372
/**
1373    Fixes the directory seperators for the current platform.
1374    
1375    It is encuraged to use only forward slashes in make files and then call
1376    this function when the path will be handed to a platform specific call.
1377    
1378    @param paths Array of paths to be checked for correct seperators
1379    
1380    @return The path with the directory sperators appropriat for the platform.
1381*/

1382    public static String JavaDoc[] fixPath(String JavaDoc[] paths)
1383        {
1384        String JavaDoc[] newPaths = new String JavaDoc[paths.length];
1385        
1386        for (int I = 0; I < paths.length; I++)
1387            {
1388            newPaths[I] = fixPath(paths[I]);
1389            }
1390            
1391        return (newPaths);
1392        }
1393
1394//--------------------------------------------------------------------
1395
/**
1396    Sets the target that will be build if none is specified on the command line.
1397    
1398    @param target Target to be built.
1399*/

1400    public void setDefaultTarget(String JavaDoc target)
1401        {
1402        if (m_primaryTarget == null)
1403            m_primaryTarget = target;
1404        }
1405        
1406//--------------------------------------------------------------------
1407
/**
1408    Reutrns the number of threads to be used when processing the build queue
1409    
1410    @return thread count
1411*/

1412    public int getThreadCount()
1413        {
1414        return (m_threadCount);
1415        }
1416        
1417//---------------------------------------------------------------------
1418
/**
1419    Sets the number of threads to be used when processing the build queue.
1420    
1421    @param threadCount Number of threads to use.
1422*/

1423    public void setThreadCount(int threadCount)
1424        {
1425        m_threadCount = threadCount;
1426        }
1427        
1428//---------------------------------------------------------------------
1429
/**
1430    Sets properties for this instance of CPMake
1431    
1432    @param name Property name.
1433    @param value Value of the property.
1434*/

1435    public void setProperty(String JavaDoc name, String JavaDoc value)
1436        {
1437        m_modifiedEnv = true;
1438        m_properties.setProperty(name, value);
1439        }
1440        
1441//---------------------------------------------------------------------
1442
/**
1443    Gets a property from CPMake. These propeties are a combination of
1444    the System properties, cpmake.properties and any properties files that
1445    are specified on the command line.
1446    
1447    @param name Name of the property to get.
1448    @param def Default value to return if no property is found.
1449    
1450    @return property value of the property or the default if none is found.
1451*/

1452    public String JavaDoc getProperty(String JavaDoc name, String JavaDoc def)
1453        {
1454        String JavaDoc value = getProperty(name);
1455        
1456        if (value == null)
1457            return (def);
1458        else
1459            return (value);
1460            
1461        }
1462        
1463//---------------------------------------------------------------------
1464
/**
1465    Gets a property from CPMake. These propeties are a combination of
1466    the System properties, cpmake.properties and any properties files that
1467    are specified on the command line.
1468    
1469    @param name Name of the property to get.
1470    
1471    @return property value of the property.
1472*/

1473    public String JavaDoc getProperty(String JavaDoc name)
1474        {
1475        String JavaDoc value = m_properties.getProperty(name);
1476        
1477        if (value == null)
1478            value = m_properties.getProperty(name.replace('.', '_'));
1479            
1480        return (value);
1481        }
1482        
1483//---------------------------------------------------------------------
1484
/**
1485    Returns the CPMake properites object.
1486*/

1487    public Properties getProperties()
1488        {
1489        return (m_properties);
1490        }
1491//---------------------------------------------------------------------
1492
/**
1493    Executes a command and waits until it is finnished.
1494    
1495    Executes a command and then pipes the stdin and stdout of the process to
1496    System.in and System.out.
1497    
1498    @param cmd command line of the process to start.
1499    @param logFile Output is sent to this log file as well
1500*/

1501    public void exec(String JavaDoc cmd, String JavaDoc logFile)
1502            throws CPMakeException
1503        {
1504        exec(null, cmd, false, logFile);
1505        }
1506        
1507//---------------------------------------------------------------------
1508
/**
1509    Executes a command and waits until it is finnished.
1510    
1511    Executes a command and then pipes the stdin and stdout of the process to
1512    System.in and System.out.
1513    
1514    @param cmd command line of the process to start.
1515*/

1516    public void exec(String JavaDoc cmd)
1517            throws CPMakeException
1518        {
1519        exec(null, cmd, false, null);
1520        }
1521
1522//-------------------------------------------------------------------
1523
/**
1524    Executes a command and waits until it is finnished.
1525    
1526    Executes a command and then pipes the stdin and stdout of the process to
1527    System.in and System.out.
1528    
1529    @param cmd command line of the process to start.
1530    @param exitOnError If the process reutrns an error the make will stop.
1531    @param logFile Output is sent to this log file as well
1532*/

1533    public void exec(String JavaDoc cmd, boolean exitOnError, String JavaDoc logFile)
1534            throws CPMakeException
1535        {
1536        exec(null, cmd, exitOnError, logFile);
1537        }
1538        
1539//-------------------------------------------------------------------
1540
/**
1541    Executes a command and waits until it is finnished.
1542    
1543    Executes a command and then pipes the stdin and stdout of the process to
1544    System.in and System.out.
1545    
1546    @param cmd command line of the process to start.
1547    @param exitOnError If the process reutrns an error the make will stop.
1548*/

1549    public void exec(String JavaDoc cmd, boolean exitOnError)
1550            throws CPMakeException
1551        {
1552        exec(null, cmd, exitOnError, null);
1553        }
1554        
1555//-------------------------------------------------------------------
1556
/**
1557    Executes a command and waits until it is finnished.
1558    
1559    Executes a command and then pipes the stdin and stdout of the process to
1560    System.in and System.out. Passing in a current working directory requires
1561    the path in cmd to be the absolute path. You can use the fullPath method
1562    to aid in retrieving the absolute path.
1563    
1564    @param cwd Sets the current working directory of the process.
1565    @param cmd command line of the process to start.
1566    @param exitOnError If the process reutrns an error the make will stop.
1567*/

1568    public void exec(String JavaDoc cwd, String JavaDoc cmd, boolean exitOnError)
1569            throws CPMakeException
1570        {
1571        exec(cwd, cmd, exitOnError, null);
1572        }
1573//-------------------------------------------------------------------
1574
/**
1575    Executes a command and waits until it is finnished.
1576    
1577    Executes a command and then pipes the stdin and stdout of the process to
1578    System.in and System.out. Passing in a current working directory requires
1579    the path in cmd to be the absolute path. You can use the fullPath method
1580    to aid in retrieving the absolute path.
1581    
1582    @param cwd Sets the current working directory of the process.
1583    @param cmd command line of the process to start.
1584    @param exitOnError If the process reutrns an error the make will stop.
1585    @param logFile Output is sent to this log file as well
1586*/

1587    public void exec(String JavaDoc cwd, String JavaDoc cmd, boolean exitOnError, String JavaDoc logFile)
1588            throws CPMakeException
1589        {
1590        Process JavaDoc proc;
1591        BufferedReader br;
1592        String JavaDoc line;
1593        File cwdf = null;
1594        StreamPipe stderr, stdout;
1595        boolean multiThreaded = false;
1596        
1597        if ((m_activeThreadCnt - m_waitingThreadCnt) > 1)
1598            multiThreaded = true;
1599        
1600        if (cwd != null)
1601            {
1602            cwdf = new File(m_workingDir, cwd);
1603            //cmd = cwdf.getPath()+getProperty("file.separator")+cmd;
1604
}
1605        else
1606            cwdf = m_workingDir;
1607        
1608        if (m_verbose)
1609            {
1610            if (cwd != null)
1611                System.out.print(cwdf.getPath()+" ");
1612            System.out.println(cmd+"\n");
1613            }
1614            
1615        try
1616            {
1617            proc = Runtime.getRuntime().exec(cmd, getEnvArr(), cwdf);
1618            
1619            m_inputWatcher.addProcess(proc);
1620            
1621            if (logFile == null)
1622                {
1623                stdout = new StreamPipe(proc.getInputStream(), System.out, multiThreaded);
1624                stderr = new StreamPipe(proc.getErrorStream(), System.out, multiThreaded);
1625                //new StreamPipe(System.in, proc.getOutputStream());
1626
}
1627            else
1628                {
1629                stdout = new StreamPipe(proc.getInputStream(), System.out, new File(m_workingDir, logFile), multiThreaded);
1630                stderr = new StreamPipe(proc.getErrorStream(), System.out, new File(m_workingDir, logFile), multiThreaded);
1631                }
1632            
1633            stdout.waitForClose();
1634            stderr.waitForClose();
1635            
1636            if (proc.waitFor() != 0)
1637                {
1638                m_inputWatcher.removeProcess(proc);
1639                throw new CPMakeException("", proc.exitValue());
1640                }
1641            m_inputWatcher.removeProcess(proc);
1642            }
1643        catch (IOException ioe)
1644            {
1645            ioe.printStackTrace();
1646            System.exit(-1);
1647            }
1648        catch (InterruptedException JavaDoc ie)
1649            {
1650            ie.printStackTrace();
1651            System.exit(-1);
1652            }
1653
1654        }
1655        
1656//---------------------------------------------------------------------
1657
private Vector getFileList(File dir, Pattern pattern, boolean recurse, boolean filePath)
1658        {
1659        String JavaDoc[] list = dir.list();
1660        Vector retList = new Vector();
1661        File f;
1662        
1663        if (list != null)
1664            for (int I = 0; I < list.length; I ++)
1665                {
1666                if (list[I].equals(".") || list[I].equals(".."))
1667                    continue;
1668                    
1669                f = new File(dir, list[I]);
1670                if (recurse && f.isDirectory())
1671                    {
1672                    retList.addAll(getFileList(f, pattern, recurse, filePath));
1673                    continue;
1674                    }
1675                    
1676                if (pattern.matcher(list[I]).matches())
1677                    {
1678                    if (filePath)
1679                        retList.add(f.getPath());
1680                    else
1681                        retList.add(list[I]);
1682                    }
1683                }
1684            
1685        return (retList);
1686        }
1687//---------------------------------------------------------------------
1688
/**
1689    This calls createFileList(String, String, int) but with 0 as the flags.
1690*/

1691    public String JavaDoc[] createFileList(String JavaDoc rootDirectory, String JavaDoc regexFilePattern)
1692        {
1693        return (createFileList(rootDirectory, regexFilePattern, 0));
1694        }
1695//---------------------------------------------------------------------
1696
/**
1697    @deprecated
1698*/

1699    public String JavaDoc[] createFileList(String JavaDoc rootDirectory, String JavaDoc regexFilePattern,
1700            boolean recurse, boolean filePath)
1701        {
1702        int flags = 0;
1703        if (recurse)
1704            flags |= RECURSE;
1705            
1706        if (filePath)
1707            flags |= INCLUDE_PATH;
1708            
1709        return (createFileList(rootDirectory, regexFilePattern, flags));
1710        }
1711//---------------------------------------------------------------------
1712
/**
1713    Creates a list of files in rootDirectory that match the pattern denoted by
1714    regexFilePattern.
1715    
1716    @param rootDirectory Starting directory to begin search for files.
1717    @param regexFilePattern Regular expression pattern used to match files returned
1718        from this call.
1719    @param flags Flags can be any combination of RECURSE, INCLUDE_PATH or RELATIVE_PATH.
1720*/

1721    public String JavaDoc[] createFileList(String JavaDoc rootDirectory, String JavaDoc regexFilePattern,
1722            int flags)
1723        {
1724        File root = new File(m_workingDir, rootDirectory);
1725        Pattern pattern = Pattern.compile(regexFilePattern);
1726        String JavaDoc[] strList;
1727        
1728        Vector fileList = getFileList(root, pattern, ((flags & RECURSE)>0), ((flags & INCLUDE_PATH)>0));
1729        if (fileList.size() > 0)
1730            strList = (String JavaDoc[])fileList.toArray(new String JavaDoc[0]);
1731        else
1732            strList = new String JavaDoc[0];
1733    
1734        if ((m_workingDir != null) && ((flags & INCLUDE_PATH)>0))
1735            {
1736            int workdirSz = m_workingDir.getPath().length();
1737            for (int I = 0; I < strList.length; I ++)
1738                strList[I] = strList[I].substring(workdirSz+1);
1739            }
1740            
1741        //Strip off root directory so file nams are relative to rootDirectory
1742
if (((flags & INCLUDE_PATH)>0) && ((flags & RELATIVE_PATH)>0))
1743            {
1744            int rootSz = rootDirectory.length();
1745            for (int I = 0; I < strList.length; I ++)
1746                {
1747                strList[I] = strList[I].substring(rootSz+1); //Add one to get rid of seperator
1748
}
1749            }
1750        
1751        return (strList);
1752        }
1753        
1754//---------------------------------------------------------------------
1755
/**
1756    Deletes the entire sub tree.
1757*/

1758    public void deltree(File directory)
1759        {
1760        if (!directory.exists())
1761            return;
1762        File[] list = directory.listFiles();
1763        
1764        if (list.length > 0)
1765            {
1766            for (int I = 0; I < list.length; I++)
1767                {
1768                if (list[I].isDirectory())
1769                    deltree(list[I]);
1770                
1771                list[I].delete();
1772                }
1773            }
1774        
1775        directory.delete();
1776        }
1777        
1778//---------------------------------------------------------------------
1779
/**
1780    Deletes the entire sub tree including the directory.
1781*/

1782    public void deltree(String JavaDoc directory)
1783        {
1784        File f = new File(directory);
1785        
1786        if (f.isAbsolute())
1787            deltree(f);
1788        else
1789            deltree(new File(m_workingDir, directory));
1790        }
1791        
1792//-------------------------------------------------------------------
1793
/**
1794    Deletes a file
1795    @param file File to delete.
1796*/

1797    public void delete(String JavaDoc file)
1798        {
1799        File f = new File(m_workingDir, file);
1800        f.delete();
1801        }
1802        
1803//-------------------------------------------------------------------
1804
/**
1805    Copies all files in the source directory that match the file pattern to the
1806    destination directory if they are newer.
1807    
1808    @param sourceDir Source directory.
1809    @param filePattern Regex file pattern.
1810    @param dest Destination directory to copy files to.
1811*/

1812    public void copyIfNewer(String JavaDoc sourceDir, String JavaDoc filePattern, String JavaDoc dest)
1813        {
1814        String JavaDoc[] files = createFileList(sourceDir, filePattern);
1815        
1816        if (files.length > 0)
1817            {
1818            for (int I = 0; I < files.length; I++)
1819                copyIfNewer(sourceDir+"/"+files[I], dest);
1820            }
1821        }
1822        
1823//-------------------------------------------------------------------
1824
/**
1825    Performes a file copy if the source is newer then the destination
1826    
1827    @param source Source file to copy
1828    @param dest Destination directory or file to copy to
1829*/

1830    public void copyIfNewer(String JavaDoc source, String JavaDoc dest)
1831        {
1832        File destf = new File(m_workingDir, dest);
1833        File sourcef = new File(m_workingDir, source);
1834        
1835        if (destf.isDirectory())
1836            destf = new File(destf, sourcef.getName());
1837        
1838        if (sourcef.lastModified() > destf.lastModified())
1839            copy(source, dest);
1840        }
1841        
1842//-------------------------------------------------------------------
1843
/**
1844    Copies all files in the source directory that match the file pattern to the
1845    destination directory.
1846    
1847    @param sourceDir Source directory.
1848    @param filePattern Regex file pattern.
1849    @param dest Destination directory to copy files to.
1850*/

1851    public void copy(String JavaDoc sourceDir, String JavaDoc filePattern, String JavaDoc dest)
1852        {
1853        String JavaDoc[] files = createFileList(sourceDir, filePattern);
1854        
1855        if (files.length > 0)
1856            {
1857            for (int I = 0; I < files.length; I++)
1858                copy(sourceDir+"/"+files[I], dest);
1859            }
1860        }
1861//-------------------------------------------------------------------
1862
/**
1863    Performs a file copy. The file denoted by source is copied to dest.
1864    dest can either be a file name or a directory.
1865*/

1866    public void copy(String JavaDoc source, String JavaDoc dest)
1867        {
1868        File destf = new File(m_workingDir, dest);
1869        File sourcef = new File(m_workingDir, source);
1870        BufferedInputStream in;
1871        BufferedOutputStream out;
1872        byte[] buff = new byte[32*1024];
1873        int len;
1874        
1875        if (sourcef.isDirectory())
1876            return;
1877        
1878        if (m_verbose)
1879            System.out.println("Copying "+source+" to "+dest);
1880            
1881        if (destf.isDirectory())
1882            destf = new File(destf, sourcef.getName());
1883        
1884        try
1885            {
1886            in = new BufferedInputStream(new FileInputStream(sourcef));
1887            out = new BufferedOutputStream(new FileOutputStream(destf));
1888            while ((len = in.read(buff)) > 0)
1889                out.write(buff, 0, len);
1890                
1891            in.close();
1892            out.close();
1893            destf.setLastModified(sourcef.lastModified());
1894            }
1895        catch (FileNotFoundException fnfe)
1896            {
1897            fnfe.printStackTrace();
1898            System.exit(-1);
1899            }
1900        catch (IOException ioe)
1901            {
1902            ioe.printStackTrace();
1903            System.exit(-1);
1904            }
1905        }
1906        
1907//-------------------------------------------------------------------
1908
/**
1909    Reads a list of GNU style dependency files and adds them to the CPMake
1910    dependency list. If a file does not exist and create is set to true
1911    CPMake will try and find a rule to build the file.
1912    
1913    @param files List of GNU style dependency files.
1914    @param create Attempst to create the file if it does not exist
1915    @param soft Tells CPMake that the dependencies in this file are to be
1916        treated as soft meaning if the file does not exist do not try to build it.
1917*/

1918    public void processMakeDependencyFiles(String JavaDoc[] files, boolean create,
1919            boolean soft)
1920            throws CPMakeException
1921        {
1922        for (int I = 0; I < files.length; I ++)
1923            processMakeDependencyFile(files[I], create, soft);
1924        }
1925//-------------------------------------------------------------------
1926
/**
1927    Reads a GNU make file and addes the dependencies to the build.
1928    If the file does not exist and create is set to true CPMake will
1929    try and find a rule to build this file.
1930    
1931    @param file GNU make dependency file to include
1932    @param create Attempt to create the file if it does not exist
1933    @param soft Tells CPMake that the dependencies in this file are to be
1934        treated as soft meaning if the file does not exist do not try to build it.
1935*/

1936    public void processMakeDependencyFile(String JavaDoc file, boolean create,
1937            boolean soft)
1938            throws CPMakeException
1939        {
1940        File f = new File(m_workingDir, file);
1941        BufferedReader br;
1942        String JavaDoc line;
1943        String JavaDoc[] splitLine;
1944        String JavaDoc[] targets;
1945        Vector dependencies;
1946        boolean continued = false;
1947        
1948        if ((!f.exists())&&(create))
1949            buildTarget(file, false);
1950        
1951        if (f.exists())
1952            {
1953            try
1954                {
1955                br = new BufferedReader(new FileReader(f));
1956                
1957                while ((line = br.readLine()) != null)
1958                    {
1959                    line = line.trim();
1960                    if (line.charAt(0) == '#') //Skip comment lines
1961
continue;
1962                        
1963                    if (line.length() == 0)
1964                        continue;
1965                    
1966                    dependencies = new Vector();
1967                    splitLine = line.split(": ");
1968                    
1969                    if (splitLine.length == 1) //Emtpy dependency
1970
continue;
1971                        
1972                    targets = splitLine[0].trim().split(" ");
1973                    line = splitLine[1].trim();
1974                    if (line.charAt(line.length() - 1) == '\\')
1975                        {
1976                        continued = true;
1977                        line = line.substring(0, (line.length()-1)).trim(); //chop off the \
1978
}
1979                    
1980                    loadVector(dependencies, line.split(" "));
1981                    while(continued)
1982                        {
1983                        line = br.readLine();
1984                        line = line.trim();
1985                        if (line.charAt(line.length() - 1) == '\\')
1986                            {
1987                            continued = true;
1988                            line = line.substring(0, (line.length()-1)).trim(); //chop off the \
1989
}
1990                        else
1991                            continued = false;
1992                            
1993                        loadVector(dependencies, line.split(" "));
1994                        }
1995                    
1996                    if (soft)
1997                        {
1998                        String JavaDoc[] temp = (String JavaDoc[])dependencies.toArray(new String JavaDoc[0]);
1999                        dependencies = new Vector();
2000                        for (int I = 0; I < temp.length; I++)
2001                            {
2002                            if ((new File(m_workingDir, temp[I])).exists())
2003                                dependencies.add(temp[I]);
2004                            }
2005                        }
2006                    
2007                    for (int I = 0; I < targets.length; I++)
2008                        {
2009                        createExplicitDependency(targets[I].replace('\\', '/'), (String JavaDoc[])dependencies.toArray(new String JavaDoc[0]));
2010                        }
2011                    }
2012                br.close();
2013                }
2014            catch (Exception JavaDoc e)
2015                {
2016                }
2017            }
2018        
2019        }
2020        
2021//-------------------------------------------------------------------
2022
/**
2023    Clears all rules and dependencies.
2024*/

2025    public void clearMakeRules()
2026        {
2027        m_rules.clear();
2028        m_dependencies.clear();
2029        }
2030
2031//-------------------------------------------------------------------
2032
/**
2033    Includes an additional script file that has a rule to generate it.
2034    CPMake will call build target on the include file before processing it.
2035    
2036    @param fileName Name of the script file to include.
2037*/

2038    public void include(String JavaDoc fileName)
2039            throws CPMakeException
2040        {
2041        File f = new File(m_workingDir, fileName);
2042        
2043        buildTarget(fileName, false); //Calling this makes sure the make file is up to date
2044

2045        try
2046            {
2047            m_interpreter.source(fileName);
2048            }
2049        catch (Exception JavaDoc e) {} //Should never happen because the build would have thrown an exception
2050
}
2051
2052//-------------------------------------------------------------------
2053
/**
2054    Perform pattern substitution on the srcList String array. This method
2055    goes through each String in srcList and calls replaceAll on the string using
2056    srcPattern and destPattern as arguments.
2057    
2058    @param srcPattern Regular expression search pattern.
2059    @param destPattern Replacement pattern.
2060    @param srcList Array of strings to perform pattern substitution on.
2061    @return New string array containing the substituted strings
2062*/

2063    public static String JavaDoc[] substitute(String JavaDoc srcPattern, String JavaDoc destPattern, String JavaDoc[] srcList)
2064        {
2065        String JavaDoc[] dest = new String JavaDoc[srcList.length];
2066        
2067        for (int I = 0; I < srcList.length; I++)
2068            {
2069            dest[I] = srcList[I].replaceAll(srcPattern, destPattern);
2070            }
2071        
2072        return (dest);
2073        }
2074        
2075//-------------------------------------------------------------------
2076
/**
2077    Creates a directory
2078    
2079    @param directory Directory to create
2080*/

2081    public void mkdir(String JavaDoc directory)
2082        {
2083        File f = new File(m_workingDir, directory);
2084        f.mkdirs();
2085        }
2086        
2087//-------------------------------------------------------------------
2088
/**
2089    Returns the absolute path from a relative path
2090    
2091    @param relPath Relative Path
2092    @return absolute path.
2093*/

2094    public String JavaDoc fullPath(String JavaDoc relPath)
2095        {
2096        File f = new File(m_workingDir, relPath);
2097        return(f.getAbsolutePath());
2098        }
2099        
2100//-------------------------------------------------------------------
2101
/**
2102    Throws and exception.
2103    This is for testing purposes only
2104    @since 1.2
2105*/

2106    public static void throwException(String JavaDoc msg)
2107            throws CPMakeException
2108        {
2109        throw new CPMakeException(msg, -1);
2110        }
2111        
2112//-------------------------------------------------------------------
2113
private boolean isInCleanDir(String JavaDoc target)
2114        {
2115        Iterator it = m_autoCleanDirs.iterator();
2116        String JavaDoc dir;
2117        
2118        //System.out.println("inDir="+target);
2119
while (it.hasNext())
2120            {
2121            dir = (String JavaDoc)it.next();
2122            
2123            if (target.startsWith(dir))
2124                return (true);
2125            }
2126            
2127        return (false);
2128        }
2129        
2130//-------------------------------------------------------------------
2131
private void getTargets(Set targets, Set phonies, String JavaDoc target, Rule rule)
2132            throws CPMakeException
2133        {
2134        String JavaDoc[] prereqs;
2135        Rule pRule;
2136        boolean addSuccess;
2137        
2138        prereqs = getPrerequisites(target, rule, false);
2139        for (int I = 0; I < prereqs.length; I++)
2140            {
2141            pRule = getRule(prereqs[I]);
2142            if (pRule != null)
2143                {
2144                if (pRule instanceof PhonyRule)
2145                    addSuccess = phonies.add(prereqs[I]);
2146                else
2147                    addSuccess = targets.add(prereqs[I]);
2148                
2149                if (addSuccess)
2150                    getTargets(targets, phonies, prereqs[I], pRule);
2151                }
2152            }
2153        }
2154        
2155//-------------------------------------------------------------------
2156
/**
2157    Automatically cleans the build area by removing targets that are specified
2158    in the build file.
2159    This can either be called directly or if the build file does not have a
2160    target for 'clean' and clean is specified CPMake will call this method.
2161    @since 1.2
2162*/

2163    public void autoClean()
2164            throws CPMakeException
2165        {
2166        Vector delFiles = new Vector();
2167        Iterator it;
2168        Set targets = new HashSet();
2169        Set phonies = new HashSet();
2170        Rule rule;
2171        String JavaDoc target;
2172        File file;
2173        
2174        it = m_rules.iterator();
2175        while (it.hasNext())
2176            {
2177            rule = (Rule)it.next();
2178            target = null;
2179            
2180            if (rule instanceof PhonyRule)
2181                {
2182                target = ((PhonyRule)rule).getTarget();
2183                phonies.add(target);
2184                }
2185            else if (rule instanceof ExplicitRule)
2186                {
2187                target = ((ExplicitRule)rule).getTarget();
2188                targets.add(target);
2189                }
2190                
2191            if (target != null)
2192                {
2193                getTargets(targets, phonies, target, rule);
2194                target = null;
2195                }
2196            }
2197            
2198        it = targets.iterator();
2199        while (it.hasNext())
2200            {
2201            target = (String JavaDoc)it.next();
2202            //System.out.println("Target="+target);
2203
if (!isInCleanDir(fullPath(target)))
2204                delFiles.add(target);
2205            }
2206            
2207        it = delFiles.iterator();
2208        while (it.hasNext())
2209            {
2210            target = (String JavaDoc)it.next();
2211            //System.out.println("Dels="+target);
2212
file = new File(m_workingDir, target);
2213            if (file.exists())
2214                {
2215                System.out.println("Removing "+target);
2216                file.delete();
2217                }
2218            }
2219        
2220        it = m_autoCleanDirs.iterator();
2221        while (it.hasNext())
2222            {
2223            target = (String JavaDoc)it.next();
2224            //System.out.println("Dir="+target);
2225
file = new File(target);
2226            if (file.exists())
2227                {
2228                System.out.println("Cleaning "+target);
2229                deltree(target);
2230                }
2231            }
2232        
2233        }
2234
2235//-------------------------------------------------------------------
2236
/**
2237    Combines two String arrays into one.
2238    @since 1.2
2239*/

2240    public static String JavaDoc[] combine(String JavaDoc[] arr1, String JavaDoc[] arr2)
2241        {
2242        String JavaDoc[] ret = new String JavaDoc[arr1.length + arr2.length];
2243        
2244        System.arraycopy(arr1, 0, ret, 0, arr1.length);
2245        System.arraycopy(arr2, 0, ret, arr1.length, arr2.length);
2246        
2247        return (ret);
2248        }
2249        
2250//-------------------------------------------------------------------
2251
/**
2252    Returns the working directory for this instance of CPMake. The working
2253    directory is defined to be the directory where the build file is located.
2254    @since 1.2
2255*/

2256    public File getWorkingDirectory()
2257        {
2258        return (m_workingDir);
2259        }
2260
2261//-------------------------------------------------------------------
2262
/**
2263    Sets variables in script namespace. This can be used, when calling CPMake
2264    recursivly, to pass variables from one instance to the other.
2265    @since 1.2
2266*/

2267    public void setObject(String JavaDoc name, Object JavaDoc obj)
2268        {
2269        m_scriptObjects.put(name, obj);
2270        }
2271        
2272//-------------------------------------------------------------------
2273
/**
2274*/

2275    private static final Class JavaDoc[] parameters = new Class JavaDoc[] {URL.class};
2276    public void addClassPath(String JavaDoc path)
2277            throws CPMakeException
2278        {
2279        URLClassLoader sysloader = (URLClassLoader)ClassLoader.getSystemClassLoader();
2280        Class JavaDoc sysclass = URLClassLoader.class;
2281        
2282        try
2283            {
2284            Method method = sysclass.getDeclaredMethod("addURL",parameters);
2285            method.setAccessible(true);
2286            method.invoke(sysloader,new Object JavaDoc[]{ new File(path).toURL() });
2287            }
2288        catch (Throwable JavaDoc t)
2289            {
2290            t.printStackTrace();
2291            throw new CPMakeException("Error, could not add URL to system classloader", -1);
2292            }
2293        }
2294    }
2295        
2296
Popular Tags