Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/thermidor/build/tasks/InstallTask.java


1   package com.thermidor.build.tasks;
2   import org.apache.tools.ant.*;
3   import org.apache.tools.ant.taskdefs.*;
4   import org.apache.tools.ant.types.*;
5   import java.io.*;
6   import gnu.regexp.*;
7   import java.util.*;
8   /** goeff mitchell about an hour. Technical intrvew phone adrian after 
9    * @author Edward Turnock
10   * @version 1.0
11   */
12  public class InstallTask extends Task{
13    /**
14     * Constant for the backup mode <i>none</i>.
15     */
16    public static final int NONE=0;
17    /**
18     * Constant for the backup mode <i>numbered</i>.
19     */
20    public static final int NUMBERED=1;
21    /**
22     * Constant for the backup mode <i>existing</i>.
23     */
24    public static final int EXISTING=2;
25    /**
26     * Constant for the backup mode <i>simple</i>.
27     */
28    public static final int SIMPLE=3;
29    /**
30     * String identitier of the backup mode <i>none</i>.
31     */
32    public static final String STR_NONE="none";
33    /**
34     * String identitier of the backup mode <i>numbered</i>.
35     */
36    public static final String STR_NUMBERED="numbered";
37    /**
38     * String identitier of the backup mode <i>existing</i>.
39     */
40    public static final String STR_EXISTING="existing";
41    /**
42     * String identitier of the backup mode <i>simple</i>.
43     */
44    public static final String STR_SIMPLE="simple";
45    /**
46     * The list of supported backup modes.
47     */
48    public static final String[] BACKUPS= {
49      STR_NONE,
50      STR_NUMBERED,
51      STR_EXISTING,
52      STR_SIMPLE
53    };
54    /**
55     * The ant enumerated attribute that will be used to constrain the available
56     * backup modes.
57     */
58    public static class BackupMode extends EnumeratedAttribute {
59      /**
60       * Return the available backup mode names.
61       * @return the backup modes.
62       */
63      public String[] getValues() {
64        return BACKUPS;
65      }
66    }
67    /**
68     * The sed based regular expression 
69     * <code>^\(.*\.\)~\([[:digit:]]\+\)~$</code> that will be used to find
70     * numbered backups.
71     */
72    public static final String BACKUP_REGEXP=
73      "^\\(.*\\.\\)~\\([[:digit:]]\\+\\)~$";
74    /**
75     * The BackupFilenameFilter is used to retrieve all numbered backups of a
76     * particular filename.
77     * @author Edward Turnock
78     * @version 1.0
79     */
80    public static class BackupFilenameFilter implements FilenameFilter {
81      /**
82       * The regexp object that will be use in the filtering.
83       */
84      private RE _regexp;
85      /**
86       * The file name for which backups should be found.
87       */
88      private String _fileName;
89      /**
90       * Construct a new instance of a BackupFilenameFilter for the specified
91       * filename.
92       * @param fileName the name of the file for which backups should be found.
93       * @throws IOException is raised if the regexp could not be constructed.
94       */
95      public BackupFilenameFilter(String fileName) throws IOException {
96        _fileName=fileName;
97        try {
98          _regexp=new RE(BACKUP_REGEXP,0,RESyntax.RE_SYNTAX_SED);
99        }
100       catch(REException ree) {
101         throw new IOException("could not construct BackupFileNameFilter invalid regexp");
102       }
103     }
104     /**
105      * Should the specified file be included in the list.
106      * @param dir the directory that the filename filter is working in.
107      * @param name the name of the file to check.
108      * @return true if the specified file name was a backup of the name that
109      * this instance was constructed with, otherwise return false.
110      */
111     public boolean accept(File dir,String name) {
112       boolean retval=false;
113       REMatch match=_regexp.getMatch(name);
114       if(match!=null) {
115         String back=null;
116         int numStart=match.getStartIndex(1);
117         int numEnd=match.getEndIndex(1);
118         back=name.substring(numStart,numEnd);
119         retval=name.equals(back);
120       }
121       return retval;
122     }
123     /**
124      * This utility operation is provided to allow the backup number to be 
125      * retrieved from the name of a file that has been basked up under the 
126      * numbered backup scheme.
127      * @param name the name of a backup file.
128      * @return the numberof the backup.
129      */
130     public int backupNumber(String name) {
131       int retval=1;
132       REMatch match=_regexp.getMatch(name);
133       int numStart=match.getStartIndex(2);
134       int numEnd=match.getEndIndex(2);
135       retval=Integer.parseInt(name.substring(numStart,numEnd));
136       return retval;
137     }
138   }
139   /**
140    * The ManFilenameFilter is used to select all of the manpages in a
141    * particular directory. This is acchieved by accepting files based on the
142    * numbered section suffix.
143    */
144   public static class ManFilenameFilter implements FilenameFilter {
145     /**
146      * The manual section that we what to fileter file names for.
147      */
148     private String _section=null;
149     /**
150      * Construct a new ManFilenameFilter instance that will be used to retrieve
151      * man pages that belong to the specified manual section.
152      * @param section the section of the manual.
153      */
154     public ManFilenameFilter(String section) {
155       _section="."+section;
156     }
157     /**
158      * The name will be accepted if it does not correspond to a directory
159      * and its suffix is consistent with the manual section mane that the 
160      * filter was constructed with.
161      * @param dir the directory that the filename filter is working in.
162      * @param name the name of the file to check.
163      * @return true if the specified file belongs to the manual section that 
164      * this instance was contructed with, otherwise return false.
165      */
166     public boolean accept(File dir, String name) {
167       boolean retval=false;
168       File temp = new File(dir,name);
169       if(!temp.isDirectory()) {
170         retval = name.endsWith(_section);
171       }
172       return retval;
173     }
174   }
175   /**
176    * Directory name for manual section 1, <i>man1</i>
177    */
178   public static String STR_MAN_1="man1";
179   /**
180    * Directory name for manual section 2, <i>man2</i>
181    */
182   public static String STR_MAN_2="man2";
183   /**
184    * Directory name for manual section 3, <i>man3</i>
185    */
186   public static String STR_MAN_3="man3";
187   /**
188    * Directory name for manual section 4, <i>man4</i>
189    */
190   public static String STR_MAN_4="man4";
191   /**
192    * Directory name for manual section 5, <i>man5</i>
193    */
194   public static String STR_MAN_5="man5";
195   /**
196    * Directory name for manual section 6, <i>man6</i>
197    */
198   public static String STR_MAN_6="man6";
199   /**
200    * Directory name for manual section 7, <i>man7</i>
201    */
202   public static String STR_MAN_7="man7";
203   /**
204    * Directory name for manual section 8, <i>man8</i>
205    */
206   public static String STR_MAN_8="man8";
207   /**
208    * Directory name for manual section n, <i>mann</i>
209    */
210   public static String STR_MAN_n="mann";
211   /**
212    * The internal list of available manual directories.
213    */
214   private static final String[] MAN_DIRS={
215     STR_MAN_1,
216     STR_MAN_2,
217     STR_MAN_3,
218     STR_MAN_4,
219     STR_MAN_5,
220     STR_MAN_6,
221     STR_MAN_7,
222     STR_MAN_8,
223     STR_MAN_n
224   };
225   /**
226    * The MAN_TABLE hashtable is used to maintain the ManFilenameFilter for
227    * a given manula section aganst the name of the directory for that section.
228    */
229   private static Hashtable MAN_TABLE = new Hashtable();
230   /**
231    * Populate the MAN_TABLE with directory names and ManFilenameFilter's
232    */
233   static {
234     MAN_TABLE.put(STR_MAN_1,new ManFilenameFilter("1"));
235     MAN_TABLE.put(STR_MAN_2,new ManFilenameFilter("2"));
236     MAN_TABLE.put(STR_MAN_3,new ManFilenameFilter("3"));
237     MAN_TABLE.put(STR_MAN_4,new ManFilenameFilter("4"));
238     MAN_TABLE.put(STR_MAN_5,new ManFilenameFilter("5"));
239     MAN_TABLE.put(STR_MAN_6,new ManFilenameFilter("6"));
240     MAN_TABLE.put(STR_MAN_7,new ManFilenameFilter("7"));
241     MAN_TABLE.put(STR_MAN_8,new ManFilenameFilter("8"));
242     MAN_TABLE.put(STR_MAN_n,new ManFilenameFilter("n"));
243   }
244   /**
245    * The BACKUP_TABLE is used to maintain backup actions against there aliases.
246    * For example, STR_NUMBERED -> new BackupNumbered()
247    */
248   private static Hashtable BACKUP_TABLE = new Hashtable();
249   /**
250    * Populate the BACKUP_TABLE with backup alias action pairs.
251    */
252   static {
253     BACKUP_TABLE.put(STR_NONE,new BackupNone());
254     BACKUP_TABLE.put(STR_NUMBERED,new BackupNumbered());
255     BACKUP_TABLE.put(STR_EXISTING,new BackupExisting());
256     BACKUP_TABLE.put(STR_SIMPLE,new BackupSimple());
257   }
258   /**
259    * Retrieve the backup action for the specfied backup mode string.
260    * @param mode the backup mode that was selected.
261    * @return the backup action that corresponds to that mode.
262    * @throws BuildException is raised if the mode was not found.
263    */
264   protected static BackupAction getBackupAction(String mode) {
265     BackupAction retval = null;
266     retval=(BackupAction)BACKUP_TABLE.get(mode);
267     if(retval == null) {
268       throw new BuildException("unknown backup mode");
269     }
270     return retval;
271   }
272   /**
273    * The default backup suffix for simple backups. This is '~' the same suffix as used bu emacs and other GNU utilities.
274    */
275   public static String DEFAULT_SUFFIX="~";
276   /**
277    * Default and standard directory name for the bindir <i>bin</i>.
278    */
279   protected final static String BIN="bin";//_bindir//
280   /**
281    * Default and standard directory name for the docdir <i>doc</i>.
282    */
283   protected final static String DOC="doc";//_docdir//
284   /**
285    * Default and standard directory name for the sysconfdir <i>etc</i>.
286    */
287   protected final static String ETC="etc";//_sysconfdir//
288   /**
289    * Default and standard directory name for the libdir <i>lib</i>.
290    */
291   protected final static String LIB="lib";//_libdir//
292   /**
293    * Default and standard directory name for the sbindir <i>sbin</i>.
294    */
295   protected final static String SBIN="sbin";//_sbindir//
296   /**
297    * Default and standard directory name for the datadir <i>share</i>.
298    */
299   protected final static String SHARE="share";//_datadir//
300   /**
301    * Default and standard directory name for the localstatedir <i>var</i>.
302    */
303   protected final static String VAR="var";//_localstatedir//
304   /**
305    * Default and standard directory name for the root of the manual directory
306    * structure <i>man</i>.
307    */
308   protected final static String MAN="man";
309   /**
310    * The root of the direcotry structure from which the software should be
311    * installed.
312    */
313   private File _from=null;
314   /**
315    * The path prefix under which the software should be installed.
316    */
317   private File _prefix=null;
318   /**
319    * The <i>_bindir</i> directory will point the directory that executable
320    * components should be installed into. The default location for this is
321    * <code>${prefix}/bin</code>.
322    */
323   private File _bindir=null;
324   /**
325    * The <i>_sbindir</i> directory will point the directory that system 
326    * executable components should be installed into. The default location
327    * for this is
328    * <code>${prefix}/sbin</code>.
329    */
330   private File _sbindir=null;
331   /**
332    * The <i>_libdir</i> directory will point the directory that library
333    * components should be installed into. The default location
334    * for this is
335    * <code>${prefix}/lib</code>.
336    */
337   private File _libdir=null;
338   /**
339    * The <i>_datadir</i> directory will point the directory that shared but
340    * static application data and file components should be installed into. 
341    * The default location for this is
342    * <code>${prefix}/share</code>.
343    */
344   private File _datadir=null;
345   /**
346    * The <i>_sysconfdir</i> directory will point the directory where 
347    * system configuration files and data should be should be installed into. 
348    * The default location for this is
349    * <code>${prefix}/etc</code>.
350    */
351   private File _sysconfdir=null;
352   /**
353    * The <i>_localstatedir</i> directory will point the directory where 
354    * application runtime data should be should be installed into. 
355    * The default location for this is
356    * <code>${prefix}/var</code>.
357    */
358   private File _localstatedir=null;
359   /**
360    * The <i>_datadir</i> directory will point the directory that 
361    * documentation components should be installed into. 
362    * The default location for this is
363    * <code>${prefix}/doc</code>.
364    */
365   private File _docdir=null;
366   /**
367    * The <i>_mandir</i> directory will point the root directory that 
368    * manual page components should be installed into. 
369    * The default location for this is
370    * <code>${prefix}/man</code>.
371    */
372   private File _mandir=null;
373   /**
374    * The <b>Ant</b> target that should be executed before any of the software 
375    * components are installed.
376    */
377   private String _preInstallTarget=null;
378   /**
379    * The <b>Ant</b> target that should be executed after the software 
380    * components are installed.
381    */
382   private String _postInstallTarget=null;
383   /**
384    * The backup suffix that will actually be used the default value of this
385    * is defiend by <code>DEFAULT_SUFFIX</code>.
386    */
387   private String _suffix=DEFAULT_SUFFIX;
388   /**
389    * The backup mode that will be employed during the installation.
390    */
391   private BackupMode _backupMode=new BackupMode();
392   /**
393    * Set the default backup mode to <i>none</i>, <code>STR_NONE</code>.
394    */
395   {
396     _backupMode.setValue(STR_NONE);
397   }
398   /**
399    * The installation action for the <i>bindir</i>.
400    */
401   private Bin _bin=new Bin();
402   /**
403    * The installation action for the <i>docdir</i>.
404    */
405   private Doc _doc= new Doc();
406   /**
407    * The installation action for the <i>sysconfdir</i>.
408    */
409   private Etc _etc=new Etc();
410   /**
411    * The installation action for the <i>libdir</i>.
412    */
413   private Lib _lib=new Lib();
414   /**
415    * The installation action for the <i>datadir</i>.
416    */
417   private Share _share= new Share();
418   /**
419    * The installation action for the <i>sbindir</i>.
420    */
421   private Sbin _sbin=new Sbin();
422   /**
423    * The installation action for the <i>mandir</i> and its subdirectories.
424    */
425   private Man _man=new Man();
426   /**
427    * Copy the contents of a source file to a destintation file.
428    * @param src the ource file.
429    * @param dest the desitnation file.
430    * @throws IOException is raised if the file could not be copied.
431    */
432   private static void copyFileRaw(File src,File dest) throws IOException {
433     FileInputStream fis=new FileInputStream(src);
434     FileOutputStream  fos = new FileOutputStream(dest);
435     copy(fis,fos);
436     fos.flush();
437     fos.getFD().sync();
438     fos.close();
439   }
440   /**
441    * Copy the contents of the specified input stream <b>in</b> to the 
442    * specified output stream <b>out</b>
443    * @param in the input stream that contains the data
444    * @param out the output streamt hat the data should be written to.
445    * @throws IOException of the input stream could not be copied to the output
446    * stream.
447    */
448   private static  void copy(InputStream in, OutputStream out) throws IOException {
449     byte[] buffer = new byte[1024];
450     int bytesRead = in.read(buffer);
451     while(bytesRead != -1 ) {
452       out.write(buffer, 0, bytesRead);
453       bytesRead = in.read(buffer);            
454     }
455   }
456   /**
457    * The BackupAction class is an abstract action/command that should be 
458    * executed to make a backup of a file.
459    * @author Edward Turnock
460    * @version 1.0
461    */
462   public static abstract class BackupAction {
463     /**
464      * Backup the specified file, using the supplied suffix if it is applicable
465      * to the backup mode that this instance implements.
466      * @param file the file to backup
467      * @param suffix the backup suffix that should be used.
468      * @throws IOException is raised if the file could not be backed up.
469      */
470     public abstract void backup(File file,String suffix) throws IOException ;
471   }
472   /**
473    * BackupNone is the simplest implementation of backup, in that it simply 
474    * ignores the request to make a backup of the file.
475    * @author Edward Turnock
476    * @version 1.0
477    */
478   public static class BackupNone extends BackupAction {
479     /**
480      * Pretend to backup the specified file.
481      * @param file the file to backup
482      * @param suffix the backup suffix that should be used.
483      * @throws IOException is raised if the file could not be backed up.
484      */
485     public void backup(File file,String suffix) throws IOException {}    
486   }
487   /**
488    * Make numbered backups of the files that are to be replaced. This mode
489    * follows the same for as that employed by the GNU file utils. For example
490    * the first backup will be of the form 'build.xml.~1~'
491    * @author Edward Turnock
492    * @version 1.0
493    */
494   public static class BackupNumbered extends BackupAction {
495     /**
496      * The <i>numbered</i> backup mode.
497      * Backup the specified file using the numbering scheme. In this case the
498      * suffix will be ignored. The numbering scheme ignores missing backup 
499      * numbers and will always create a new backup that is  on higher than
500      * any in the directory.
501      * @param file the file to backup.
502      * @param suffix the suffix to use. In this cse the suffix will be ignored.
503      * @throws IOException is raised if the file could not be backed up.
504      */
505     public void backup(File file,String suffix) throws IOException {
506       if(file.exists()) {
507         if(suffix == null) {
508           suffix = DEFAULT_SUFFIX;
509         }
510         File backupFile;
511         BackupFilenameFilter filter=new BackupFilenameFilter(file.getName());
512         String[] list=file.getParentFile().list(filter);
513         int len=list.length;
514         int highest=0;
515         for(int cnt = 0; cnt < len; cnt++) {
516           int temp=filter.backupNumber(list[cnt]);
517           if(temp>highest) {
518             highest=temp;
519           }
520         }
521         highest++;
522         backupFile=new File(file.getPath()+DEFAULT_SUFFIX+highest+DEFAULT_SUFFIX);
523         copyFileRaw(file,backupFile);
524       }
525     }    
526   }
527   /**
528    * The <i>existing</i> backup mode. If the file to be installed already 
529    * exists, but doesnot have a backup then do a simple backup of that file. 
530    * If the file to be installed already has <i>numbered</i> backups 
531    * determine what the next backup number would be and create a new backup 
532    * with that number.
533    */
534   public static class BackupExisting extends BackupAction {
535     /**
536      * Make a backup of the specified file. The backup in this case will have 
537      * the same file name but with the supplied suffix.
538      * @param file the file to backup.
539      * @param duffix the suffix that should be used.
540      */
541     public void backup(File file,String suffix) throws IOException {
542       if(file.exists()) {
543         if(suffix == null) {
544           suffix = DEFAULT_SUFFIX;
545         }
546         BackupFilenameFilter filter=new BackupFilenameFilter(file.getName());
547         String[] list=file.getParentFile().list(filter);
548         File backupFile = null;
549         if(list.length == 0) {
550           backupFile = new File(file.getPath()+suffix);
551           copyFileRaw(file,backupFile);
552         }
553         else {
554           int len=list.length;
555           int highest=0;
556           for(int cnt = 0; cnt < len; cnt++) {
557             int temp=filter.backupNumber(list[cnt]);
558             if(temp>highest) {
559               highest=temp;
560             }
561           }
562           highest++;
563           backupFile=new File(file.getPath()+DEFAULT_SUFFIX+highest+DEFAULT_SUFFIX);
564           copyFileRaw(file,backupFile);
565         }
566       }
567     }    
568   }
569   /**
570    * The <i>simple</i> backup action. If the target file already exists, then
571    * make a single backup of it with the specified suffix. If the backup 
572    * already exists then it is written over.
573    * @author Edward Turnock
574    * @version 1.0
575    */
576   public static class BackupSimple extends BackupAction {
577     /**
578      * Make a backup of the specified file. The backup in this case will have 
579      * the same file name but with the supplied suffix.
580      * @param file the file to backup.
581      * @param duffix the suffix that should be used.
582      */
583     public void backup(File file,String suffix) throws IOException {
584       if(file.exists()) {
585         if(suffix == null) {
586           suffix = DEFAULT_SUFFIX;
587         }
588         File backupFile = new File(file.getPath()+suffix);
589         copyFileRaw(file,backupFile);
590       }
591     }    
592   }
593   /**
594    * The <code>Dir</code> class is an abstract action to perform the 
595    * installation of files to their appropriate target directories with the
596    * correct permissions, (if they apply on the underlying operating system).
597    * @author Edward Turnock
598    * @version 1.0
599    */
600   protected class Dir {
601     /**
602      * Copy a source file to a desintation file.
603      * @param src the source file.
604      * @param dest the destination file
605      * @param backupMode the backup mode that should be used to create backups
606      * of existing versions of the file.
607      * @param perm the permissions that the installed file should have.
608      */
609     protected void cp(File src,File dest,String backupMode,String suffix,String perm) {
610       if(!src.exists()) {
611         throw new BuildException("attempted to install non-existant file ["+src+"]");
612       }
613       File parent = dest.getParentFile();
614       if(parent != null && !parent.exists()) {
615         boolean result=parent.mkdirs();
616         if(!result) {
617           throw new BuildException("could not create destination directory ["+parent+"] check permisssions");
618         }
619       }
620       try {
621         getBackupAction(backupMode).backup(dest,suffix);
622         copyFileRaw(src,dest);
623       }
624       catch(IOException ioe) {
625         ioe.printStackTrace();
626         throw new BuildException("failed to copy file ["+src+"] with backup mode ["+backupMode+"]");
627       }
628       Chmod chmod = (Chmod)getProject().createTask("chmod");
629       chmod.setFile(dest);
630       chmod.setPerm(perm);
631       chmod.execute();
632     }
633     /**
634      * Find all the files in a tree that should be copied to a destination 
635      * directory.
636      * @param files the list of files that is to be collected.
637      * @param traversedDirs the direcotries that have been traversed.
638      * @param fromDir the root dir for the copy.
639      * @throws IOException is raised if an error prevented the list from being
640      * constructed correctly.
641      */
642     protected void findFiles(Vector files,Vector traversedDirs,File fromDir) throws IOException {
643       String[] list=fromDir.list();
644       int len= list.length;
645       for (int cnt =0;cnt < len;cnt++) {
646         File temp=new File(fromDir,list[cnt]);
647         if(temp.isDirectory()) {
648           if(traversedDirs.contains(temp.getCanonicalFile())) {
649             continue;
650           }
651           traversedDirs.addElement(temp.getCanonicalFile());
652           findFiles(files,traversedDirs,temp);
653         }
654         else {
655           files.add(temp);
656         }
657       }
658     }
659     /**
660      * Copy one direcotry to another.
661      * @param fromDir the source directory,
662      * @param toDuir the destination directory.
663      * @param perm the permissions that the installed files should have.
664      */
665     protected void copyTree(File fromDir,File toDir,String perm) {
666       try {
667         String fromDirStr=fromDir.getCanonicalFile().getPath();
668         int fds=fromDirStr.length();
669         if(!fromDirStr.endsWith(File.separator)) {
670           fds++;
671         }
672         if(!fromDir.exists()) {
673           return;
674         }
675         Vector files=new Vector();
676         Vector traversed=new Vector();
677         
678         findFiles(files,traversed,fromDir);
679         
680         Enumeration e = files.elements();
681         while(e.hasMoreElements()) {
682           File tp=((File)e.nextElement()).getCanonicalFile();
683           String tpstr=tp.getPath();
684           File dest=new File(toDir,tpstr.substring(fds));
685           cp(tp,dest,_backupMode.getValue(),_suffix,perm);
686         }
687       }
688       catch(IOException ioe) {
689         throw new BuildException("failed to copy tree ["+fromDir+"] with backup mode ["+_backupMode.getValue()+"]");
690       }
691     }
692   }
693   /**
694    * The bin installation action. This action assumes that there sould 
695    * be no subdirectories to <i>bindir</i> and will warn the user that it will
696    * not be installing those subdirectries.
697    * @author Edward Turnock
698    * @version 1.0
699    */
700   public class Bin extends Dir {
701     /**
702      * The permission that will be applied to all files installed in the 
703      * <i>bindir</i>, the default is <code>u=rwx,go=rx</code>.
704      */
705     private String _perm="u=rwx,go=rx";
706     /**
707      * Set the permission set for all files installed by this action.
708      * @param perm the permission set.
709      */
710     public void setPerm(String perm) {
711       _perm=perm;
712     }
713     /**
714      * Execute the installation of all files in the build output bin directory
715      * to the specifed <i>bindir</i>.
716      */
717     public void execute() {
718       File toDir=null;
719       if(_bindir==null) {
720         toDir=new File(_prefix,BIN);
721       }
722       else {
723         toDir = _bindir;
724       }
725       File fromDir=new File(_from,BIN);
726       if(!fromDir.exists()) {
727         return;
728       }
729       String[] list=fromDir.list();
730       int len= list.length;
731       for (int cnt =0;cnt < len;cnt++) {
732         File temp=new File(fromDir,list[cnt]);
733         if(temp.isDirectory()) {
734           getProject().log("Install does not support sub directories of bin",Project.MSG_WARN);
735           continue;
736           
737         }
738         File dest=new File(toDir,list[cnt]);
739         cp(temp,dest,_backupMode.getValue(),_suffix,_perm);
740       }
741     }
742   }
743   /**
744    * The <i>docdir</i> installation action.
745    * @author Edward Turnock
746    * @version 1.0
747    */
748   public class Doc extends Dir {
749     /**
750      * The permission that will be applied to all files installed in the 
751      * <i>docdir</i>, the default is <code>u=rw,go=r</code>.
752      */
753     private String _perm="u=rw,go=r";
754     /**
755      * Set the permission set for all files installed by this action.
756      * @param perm the permission set.
757      */
758     public void setPerm(String perm) {
759       _perm=perm;
760     }
761     /**
762      * Install the contents of the <b>doc</b> direcotry of the builds output,
763      * including all subdirecotries to the specfied <i>docdir</i> applying
764      * the appropriate permissions.
765      */
766     public void execute() {
767       File toDir=null;
768       if(_docdir==null) {
769         toDir=new File(_prefix,DOC);
770       }
771       else {
772         toDir = _docdir;
773       }
774       File fromDir=new File(_from,DOC);
775       copyTree(fromDir,toDir,_perm);
776     }
777   }
778   /**
779    * The <i>sysconfdir</i> isntallation action.
780    * @author Edward Turnock
781    * @version 1.0
782    */
783   public class Etc extends Dir {
784     /**
785      * The permission that will be applied to all files installed in the 
786      * <i>sysconfdir</i>, the default is <code>u=rw,go=r</code>.
787      */
788     private String _perm="u=rw,go=r";
789     /**
790      * Set the permission set for all files installed by this action.
791      * @param perm the permission set.
792      */
793     public void setPerm(String perm) {
794       _perm=perm;
795     }
796     /**
797      * Install the contents of the <b>etc</b> direcotry of the builds output,
798      * including all subdirecotries to the specfied <i>sysconfdir</i> applying
799      * the appropriate permissions.
800      */
801     public void execute() {
802       File toDir=null;
803       if(_sysconfdir==null) {
804         toDir=new File(_prefix,ETC);
805       }
806       else {
807         toDir = _sysconfdir;
808       }
809       File fromDir=new File(_from,ETC);
810       copyTree(fromDir,toDir,_perm);
811     }
812   }
813   /**
814    * The <i>libdir</i> installation action. 
815    * @author Edward Turnock
816    * @version 1.0
817    */
818   public class Lib extends Dir {
819     /**
820      * The permission that will be applied to all files installed in the 
821      * <i>libdir</i>, the default is <code>u=rwx,go=rx</code>.
822      */
823     private String _perm="u=rwx,go=rx";
824     /**
825      * Set the permission set for all files installed by this action.
826      * @param perm the permission set.
827      */
828     public void setPerm(String perm) {
829       _perm=perm;
830     }
831     /**
832      * Install the contents of the <b>lib</b> direcotry of the builds output,
833      * including all subdirecotries to the specfied <i>libdir</i> applying
834      * the appropriate permissions.
835      */
836     public void execute() {
837       File toDir=null;
838       if(_libdir==null) {
839         toDir=new File(_prefix,LIB);
840       }
841       else {
842         toDir = _libdir;
843       }
844       File fromDir=new File(_from,LIB);
845       copyTree(fromDir,toDir,_perm);
846     }
847   }
848   /**
849    * The system bin installation action. This action assumes that there sould 
850    * be no subdirectories to <i>sbindir</i> and will warn the user that it will
851    * not be installing those subdirectries.
852    * @author Edward Turnock
853    * @version 1.0
854    */
855   public class Sbin extends Dir {
856     /**
857      * The permission that will be applied to all files installed in the 
858      * sbindir, the default is <code>u=rwx,go=rx</code>.
859      */
860     private String _perm="u=rwx,go=rx";
861     /**
862      * Set the permission set for all files installed by this action.
863      * @param perm the permission set.
864      */
865     public void setPerm(String perm) {
866       _perm=perm;
867     }
868     /**
869      * Execute the installation of all files in the build output bin directory
870      * to the specifed <i>sbindir</i>.
871      */
872     public void execute() {
873       File toDir=null;
874       if(_sbindir==null) {
875         toDir=new File(_prefix,SBIN);
876       }
877       else {
878         toDir = _sbindir;
879       }
880       File fromDir=new File(_from,SBIN);
881       if(!fromDir.exists()) {
882         return;
883       }
884       String[] list=fromDir.list();
885       int len= list.length;
886       for (int cnt =0;cnt < len;cnt++) {
887         File temp=new File(fromDir,list[cnt]);
888         if(temp.isDirectory()) {
889           getProject().log("Install does not support sub directories of sbin",Project.MSG_WARN);
890           continue;
891           
892         }
893         File dest=new File(toDir,list[cnt]);
894         cp(temp,dest,_backupMode.getValue(),_suffix,_perm);
895       }
896     }
897   }
898   /**
899    * The manual page installation action. This action currently assumes that 
900    * all generated manpages will be output, prior to installation, into a 
901    * single directory <code>${out}/man</code>. The action will determine which
902    * section of the manual that they should be installed in bases on the 
903    * suffix of the file.
904    * @author Edward Turnock
905    * @version 1.0
906    */
907   protected class Man extends Dir {
908     /**
909      * The permissions that should be applied to all installed manual pages.
910      * By default this is <code>u=rw,go=r</code>.
911      */
912     private String _perm="u=rw,go=r";
913     /**
914      * Set the permission set for all files installed by this action.
915      * @param perm the permission set.
916      */
917     public void setPerm(String perm) {
918       _perm=perm;
919     }
920     /**
921      * Execute the installation of manual pages, backing up existing files 
922      * based on the backup mode employed by the installation task.
923      */
924     public void execute() {
925       File toDir=null;
926       if(_mandir == null) {
927         toDir = new File(_prefix,MAN);
928       }
929       else {
930         toDir = _mandir;
931       }
932       File fromDir=new File(_from,MAN);
933       if(!fromDir.exists()) {
934         return;
935       }
936       for(int cnt = 0 ; cnt < MAN_DIRS.length ; cnt++) {
937         String currentManDir=MAN_DIRS[cnt];
938         String[] results = fromDir.list
939           ((FilenameFilter)MAN_TABLE.get(currentManDir));
940         int len = 0;
941         if(results == null) {
942           len = 0;
943         }
944         else {
945           len = results.length;
946         }
947         if(results.length == 0) {
948           break;
949         }
950         File destDir = new File(toDir,currentManDir);
951         if(!destDir.exists()) {
952           boolean created = destDir.mkdirs();
953           if(!created) {
954             throw new BuildException("could not create man destination [" +
955                                      currentManDir + "]");
956           }
957         }
958         for(int cnt1 = 0; cnt1 < len ; cnt1++) {
959           File temp = new File(fromDir,results[cnt1]);
960           File tempDest = new File(destDir,results[cnt1]);
961           cp(temp,tempDest,_backupMode.getValue(),_suffix,_perm);
962         }
963       }
964     }
965   }
966   /**
967    * Install the content of the build output directory <b>share</b> to the
968    * specified <i>datadir</i>
969    */
970   protected class Share extends Dir {
971     /**
972      * The permissions that should be applied to all files installed in the 
973      * <i>datadir</i> by the installation process.
974      */
975     private String _perm="u=rw,go=r";
976     /**
977      * Set the permission set for all files installed by this action.
978      * @param perm the permission set.
979      */
980     public void setPerm(String perm) {
981       _perm=perm;
982     }
983     /**
984      * Install the contents of the <b>share</b> direcotry of the builds output,
985      * including all subdirecotries to the specfied <i>datadir</i> applying
986      * the appropriate permissions.
987      */
988     public void execute() {
989       File toDir=null;
990       if(_datadir==null) {
991         toDir=new File(_prefix,SHARE);
992       }
993       else {
994         toDir = _datadir;
995       }
996       File fromDir=new File(_from,SHARE);
997       copyTree(fromDir,toDir,_perm);
998     }
999   }
1000  /**
1001   * If the install task has been asked to make simple backups of files
1002   * that it will replace then the value of this parameter will be used.
1003   * @param backupSuffix the backup suffix
1004   */
1005  public void setBackupsuffix(String backupSuffix) {
1006    _suffix=backupSuffix;
1007  }
1008  /**
1009   * Set the backup mode that should be used.
1010   */
1011  public void setBackupmode(BackupMode backupMode) {
1012    _backupMode = backupMode;
1013  }
1014  /**
1015   * Set the documentation directory. This will override the default
1016   * <i>${prefix}/doc</i>.
1017   * @param docdir the documentation directory.
1018   */
1019  public void setDocdir(File docdir) {
1020    _docdir=docdir;
1021  }
1022  /**
1023   * Set ther root direcotry from which installation will take place.
1024   * @param from the root directory of the built software.
1025   */
1026  public void setFrom(File from) {
1027    _from = from;
1028  }
1029  public void setPrefix(File prefix) {
1030    _prefix=prefix;
1031  }
1032  /**
1033   * Set the bin directory. This will override the default
1034   * <i>${prefix}/bin</i>.
1035   * @param bindir the bin directory.
1036   */
1037  public void setBindir(File bindir) {
1038    _bindir=bindir;
1039  }  
1040  /**
1041   * Set the library directory. This will override the default
1042   * <i>${prefix}/lib</i>.
1043   * @param libdir the bin directory.
1044   */
1045  public void setLibdir(File libdir) {
1046    _libdir=libdir;
1047  }
1048  /**
1049   * Set the system bin directory. This will override the default
1050   * <i>${prefix}/sbin</i>.
1051   * @param sbindir the bin directory.
1052   */
1053  public void setSbindir(File sbindir) {
1054    _sbindir=sbindir;
1055  }
1056  /**
1057   * Set the shared data directory. This will override the default
1058   * <i>${prefix}/share</i>.
1059   * @param datadir the bin directory.
1060   */
1061  public void setDatadir(File datadir) {
1062    _datadir=datadir;
1063  }
1064  /**
1065   * Set the system configuration directory. This will override the default
1066   * <i>${prefix}/etc</i>.
1067   * @param sysconfdir the bin directory.
1068   */
1069  public void setSysconfdir(File sysconfdir) {
1070    _sysconfdir=sysconfdir;
1071  }
1072  /**
1073   * Set the root manual page directory. This will override the default
1074   * <i>${prefix}/man</i>.
1075   * @param mandir the bin directory.
1076   */
1077  public void setMandir(File mandir) {
1078    _mandir=mandir;
1079  }
1080  /**
1081   * Set the application data directory. This will override the default
1082   * <i>${prefix}/var</i>.
1083   * @param localstatedir the bin directory.
1084   */
1085  public void setLocalstatedir(File localstatedir) {
1086    _localstatedir=localstatedir;
1087  }
1088  /**
1089   * Set the <b>Ant</b> target that should be executed before installation.
1090   * @param target the target that should be executed.
1091   */
1092  public void setPreinstalltarget(String target) {
1093    _preInstallTarget=target;
1094  }
1095  /**
1096   * Set the <b>Ant</b> target that should be executed after installation.
1097   * @param target the target that should be executed.
1098   */
1099  public void setPostinstalltarget(String target) {
1100    _postInstallTarget=target;
1101  }
1102  /**
1103   * Execute the installation. If <b>preinstallationtarget</b> has been set 
1104   * then that target will be executed before each of the directories has 
1105   * been installed. if <b>postinstallationtarget</b> has been set then it 
1106   * will be executed after all of the installation steps have been executed.
1107   */
1108  public void execute() {
1109    if(_from == null) {
1110      throw new BuildException("'from' attribute must be set");
1111    }
1112    if(_prefix == null) {
1113      throw new BuildException("'prefix' attribute must be set");
1114    }
1115    //executePreinstall target
1116    if(_preInstallTarget!=null) {
1117      getProject().executeTarget(_preInstallTarget);
1118    }
1119    _bin.execute();
1120    _doc.execute();
1121    _etc.execute();
1122    _lib.execute();
1123    _share.execute();
1124    _sbin.execute();
1125    _man.execute();
1126    //executePostInstall target
1127    if(_postInstallTarget!=null) {
1128      getProject().executeTarget(_postInstallTarget);
1129    }
1130  }
1131  /**
1132   * Create the sub-tag and action for the <i>bindir</i>.
1133   * @return the Bin install action.
1134   */
1135  public Bin createBin() {
1136    return _bin;
1137  }
1138  /**
1139   * Create the sub-tag and action for the <i>docdir</i>.
1140   * @return the Doc install action.
1141   */
1142  public Doc createDoc() {
1143    return _doc;
1144  }
1145  /**
1146   * Create the sub-tag and action for the <i>sysconfdir</i>.
1147   * @return the Etc install action.
1148   */
1149  public Etc createEtc() {
1150    return _etc;
1151  }
1152  /**
1153   * Create the sub-tag and action for the <i>libdir</i>.
1154   * @return the Lib install action.
1155   */
1156  public Lib createLib() {
1157    return _lib;
1158  }
1159  /**
1160   * Create the sub-tag and action for the <i>datadir</i>.
1161   * @return the Share install action.
1162   */
1163  public Share createShare() {
1164    return _share;
1165  }
1166  /**
1167   * Create the sub-tag and action for the <i>sbindir</i>.
1168   * @return the Sbin install action.
1169   */
1170  public Sbin createSbin() {
1171    return _sbin;
1172  }
1173  /**
1174   * Create the sub-tag and action for the <i>mandir</i>.
1175   * @return the man install action.
1176   */
1177  public Man createMan() {
1178    return _man;
1179  }
1180}
1181
1182