1 package com.imcode.ant.tasks;
2
3 import java.io.*;
4 import java.util.*;
5
6 import org.apache.tools.ant.*;
7 import org.apache.tools.ant.types.*;
8
9 public class Cat extends Task {
10
11 private File destFile = null;
12 private String orderBy = null;
13 private boolean filtering = false;
14 private boolean append = false;
15 private int verbosity = Project.MSG_VERBOSE;
16 private boolean forceOverwrite = false;
17
18 private Vector filesets = new Vector();
19 private Vector filterSets = new Vector();
20
21 private String ORDER_BY_PATH = "path";
22
23 private final static int BUFFER_SIZE = 32768;
24
25 /***
26 * Set the value of append.
27 *
28 * @param v Value to assign to append.
29 */
30 public void setAppend( boolean v ) {
31 this.append = v;
32 }
33
34 /***
35 * Sets the value of destFile
36 *
37 * @param argDestFile Value to assign to this.destFile
38 */
39 public void setDestFile( File argDestFile ) {
40 this.destFile = argDestFile;
41 }
42
43 /***
44 * Sets the value of orderBy
45 *
46 * @param argOrderBy Value to assign to this.orderBy
47 */
48 public void setOrderBy( String argOrderBy ) {
49 this.orderBy = argOrderBy;
50 }
51
52 /***
53 * Adds a set of files (nested fileset attribute).
54 */
55 public void addFileset( FileSet set ) {
56 filesets.addElement( set );
57 }
58
59 /***
60 * Used to force listing of all names of copied files.
61 */
62 public void setVerbose( boolean verbose ) {
63 if ( verbose ) {
64 this.verbosity = Project.MSG_INFO;
65 } else {
66 this.verbosity = Project.MSG_VERBOSE;
67 }
68 }
69
70 /***
71 * Sets filtering.
72 */
73 public void setFiltering( boolean filtering ) {
74 this.filtering = filtering;
75 }
76
77 /***
78 * Overwrite any existing destination file(s).
79 */
80 public void setOverwrite( boolean overwrite ) {
81 this.forceOverwrite = overwrite;
82 }
83
84 /***
85 * Create a nested filterset
86 */
87 public FilterSet createFilterSet() {
88 FilterSet filterSet = new FilterSet();
89 filterSets.addElement( filterSet );
90 return filterSet;
91 }
92
93 public void execute() throws BuildException {
94 validateAttributes();
95 doFileOperations();
96 }
97
98 /***
99 * Make sure all attributes are correct. *
100 */
101 private void validateAttributes() {
102 if ( filesets.size() == 0 ) {
103 throw new BuildException( "Specify at least one fileset." );
104 }
105
106 if ( destFile == null ) {
107 throw new BuildException( "Specify a destfile." );
108 }
109
110 if ( orderBy != null && !ORDER_BY_PATH.equalsIgnoreCase( orderBy ) ) {
111 throw new BuildException( "Specify a valid orderby ('path'), or none." );
112 }
113 }
114
115 /***
116 * Do whatever is necessary to open the destination file. *
117 */
118 private OutputStream openOutputStream() throws IOException {
119 File parent = new File( destFile.getParent() );
120 if ( !parent.exists() ) {
121 if ( !parent.mkdirs() ) {
122 log( "Unable to create directory " + parent.getAbsolutePath(), Project.MSG_ERR );
123 } else {
124 log( "Created directory " + parent.getAbsolutePath(), verbosity );
125 }
126 }
127
128 return new FileOutputStream( destFile.getPath(), append );
129
130 }
131
132 /***
133 * Do all fileoperations. *
134 */
135 private void doFileOperations() {
136 try {
137
138 List srcFiles = handleFileSets();
139
140 if ( srcFiles == null ) {
141 return;
142 }
143
144 FilterSetCollection filters = handleFilterSets();
145
146 log( "Concatenating " + srcFiles.size() + ( srcFiles.size() == 1
147 ? " file to "
148 : " files to " ) + destFile.getAbsolutePath() );
149
150 catFiles( srcFiles, filters );
151
152 } catch ( IOException ex ) {
153 throw new BuildException( ex );
154 }
155 }
156
157 /***
158 * Deal with the filesets *
159 */
160 private List handleFileSets() {
161 List srcFiles = new Vector();
162 boolean foundNewer = false;
163
164 for ( Iterator filesetsIterator = filesets.iterator(); filesetsIterator.hasNext(); ) {
165 FileSet fs = (FileSet)filesetsIterator.next();
166 DirectoryScanner ds = fs.getDirectoryScanner( project );
167 File baseDir = fs.getDir( project );
168
169
170 String[] srcFilesArray = ds.getIncludedFiles();
171
172
173 if ( ORDER_BY_PATH.equalsIgnoreCase( orderBy ) ) {
174 Arrays.sort( srcFilesArray );
175 }
176
177 long destModified = destFile.lastModified();
178
179
180 for ( int j = 0; j < srcFilesArray.length; ++j ) {
181 File srcFile = new File( baseDir, srcFilesArray[j] );
182 if ( srcFile.equals( destFile ) ) {
183 log( "Skipping self-concatenation of " + srcFile, verbosity );
184 } else {
185
186 if ( !foundNewer && srcFile.lastModified() > destModified ) {
187 foundNewer = true;
188 }
189 srcFiles.add( srcFile );
190 }
191 }
192 }
193
194
195 if ( !forceOverwrite && !foundNewer ) {
196 srcFiles = null;
197 }
198
199 return srcFiles;
200 }
201
202 /***
203 * Handle the filtersets. *
204 */
205 private FilterSetCollection handleFilterSets() {
206
207 FilterSetCollection executionFilters = new FilterSetCollection();
208 if ( filtering ) {
209 executionFilters.addFilterSet( project.getGlobalFilterSet() );
210 }
211 for ( Enumeration filterEnum = filterSets.elements(); filterEnum.hasMoreElements(); ) {
212 executionFilters.addFilterSet( (FilterSet)filterEnum.nextElement() );
213 }
214 return executionFilters;
215 }
216
217 /***
218 * Cat through all files *
219 */
220 private void catFiles( List srcFiles, FilterSetCollection filters ) throws IOException {
221 OutputStream out = openOutputStream();
222
223
224 for ( Iterator srcFilesIterator = srcFiles.iterator(); srcFilesIterator.hasNext(); ) {
225
226 File srcFile = (File)srcFilesIterator.next();
227 log( "Concatenating " + srcFile + " to " + destFile, verbosity );
228
229 FileInputStream in = new FileInputStream( srcFile );
230 catStream( in, out, filters );
231 in.close();
232 }
233 out.close();
234 }
235
236 /***
237 * Cat one file/stream *
238 */
239 private void catStream( InputStream in, OutputStream out, FilterSetCollection filters ) throws IOException {
240 if ( filters != null && filters.hasFilters() ) {
241
242 BufferedReader input = new BufferedReader( new InputStreamReader( in ) );
243 BufferedWriter output = new BufferedWriter( new OutputStreamWriter( out ) );
244
245 for ( String newline, line = input.readLine(); line != null; line = input.readLine() ) {
246 if ( line.length() == 0 ) {
247 output.newLine();
248 } else {
249 newline = filters.replaceTokens( line );
250 output.write( newline );
251 output.newLine();
252 }
253 }
254 output.flush();
255
256 } else {
257
258 int read;
259 byte[] buffer = new byte[BUFFER_SIZE];
260 while ( -1 != ( read = in.read( buffer, 0, BUFFER_SIZE ) ) ) {
261 out.write( buffer, 0, read );
262 }
263
264 }
265 }
266 }