ASF Bugzilla – Attachment 23624 Details for
Bug 47163
Contributed task: #include
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
"Include" ant task
Include.java (text/plain), 10.08 KB, created by
Ramon Casha
on 2009-05-07 06:27:36 UTC
(
hide
)
Description:
"Include" ant task
Filename:
MIME Type:
Creator:
Ramon Casha
Created:
2009-05-07 06:27:36 UTC
Size:
10.08 KB
patch
obsolete
>/* > * Licensed to the Apache Software Foundation (ASF) under one or more > * contributor license agreements. See the NOTICE file distributed with > * this work for additional information regarding copyright ownership. > * The ASF licenses this file to You under the Apache License, Version 2.0 > * (the "License"); you may not use this file except in compliance with > * the License. You may obtain a copy of the License at > * > * http://www.apache.org/licenses/LICENSE-2.0 > * > * Unless required by applicable law or agreed to in writing, software > * distributed under the License is distributed on an "AS IS" BASIS, > * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. > * See the License for the specific language governing permissions and > * limitations under the License. > * > */ > >package mt.rcasha.ant; > >import java.io.File; >import java.io.FileNotFoundException; >import java.io.FileReader; >import java.io.IOException; >import java.io.LineNumberReader; >import java.io.PrintWriter; >import java.util.ArrayList; >import java.util.HashMap; >import org.apache.tools.ant.BuildException; >import org.apache.tools.ant.DirectoryScanner; >import org.apache.tools.ant.Location; >import org.apache.tools.ant.taskdefs.MatchingTask; > > >/** > * Ant task to perform #include-like processing on Java files. > * > * <h2>Warnings</h2> > * <ol> > * <li>This task will MODIFY existing files, not create a new copy. > * </li> > * <li>The marked-out section will be replaced every time, so you should > * probably add a comment warning users not to modify it in the classes, > * but to modify the included files instead.</li> > * </ol> > * <h2>Introduction</h2> > * <p> > * The idea of this task is that it will scan source files for sections > * delimited by the following two lines:</p> > * <pre> > * //#include relative-file-name > * //#end > * </pre> > * <p> > * It will then read the specified file, and replace the contents between > * the two comments with the contents of that file. This allows the same > * chunk of code to be physically inserted into your file, and makes it easy > * to update that text in all files. > * </p> > * <h2>Rationale</h2> > * <p>Although in an ideal universe, you should no need to do this, since any > * repeated sections should be placed in an ancestor, unfortunately this is > * not always possible. I first encountered the need for this facility when I > * decided to extend the standard Swing controls and add some common properties > * to each one. The only way to do this was to insert a chunk of code (getters, > * setters etc) in every one of a large number of files. This utility was born > * from that requirement. > * </p> > * <h2>Usage</h2> > * <p>The ant task will search for the exact text "//#include " as the first non- > * whitespace characters at the start of the line. Whatever follows it, trimmed of spaces, > * is the file to be included, relative to the file containing the //#include code. > * It will then search for the exact text "//#end" as the first non- > * whitespace characters at the start of the line. All lines in between are replaced. > * This process is repeated from the line following the #end, so it will not process a #include > * within the included file. > * </p> > * <p> > * The task will only process the file if both codes are found, and if the file to be included > * is readable, and if the source file is writable. > * </p> > * <p> > * The ant task is a MatchingTask, so it takes parameters like srcdir, includes, includesfiles, > * excludes etc. > * </p> > * > * <h2>Example</h2> > * <h3>file: JHTextField.java</h3> > * <pre> > * public class JHTextField extends javax.swing.JTextField implements HelpSupport { >* >* // <editor-fold defaultstate="collapsed" desc=" Help Support "> >* <b>//#include help.inc</b> >* //=============================================================== >* // THIS SECTION IS INCLUDED FROM help.inc >* //=============================================================== >* private String helpID; >* >* /** >* * {@inheritDoc} >* * @javabean.property bound="true" preferred="true" >* * shortDescription="Help ID for this component. If null, the parent component's help is used." >* * / >* @Override >* public String getHelpID() { >* return helpID; >* } >* >* /** >* * {@inheritDoc} >* * / >* @Override >* public void setHelpID(String helpID) { >* String oldValue = this.helpID; >* this.helpID = helpID; >* firePropertyChange("helpID", oldValue, helpID); >* } >* >* <b>//#end</b> >* // </editor-fold> >* >* } > *</pre> > * > * <h3>file: help.inc</h3> > * <pre> > * //=============================================================== > * // THIS SECTION IS INCLUDED FROM help.inc > * //=============================================================== > * private String helpID; > * > * /** > * * {@inheritDoc} > * * @javabean.property bound="true" preferred="true" > * * shortDescription="Help ID for this component. If null, the parent component's help is used." > * * / > * @Override > * public String getHelpID() { > * return helpID; > * } > * > * /** > * * @inheritDoc} > * * / > * @Override > * public void setHelpID(String helpID) { > * String oldValue = this.helpID; > * this.helpID = helpID; > * firePropertyChange("helpID", oldValue, helpID); > * } > * </pre> > * > * > * @author Ramon Casha (rcasha at gmail dot com) > */ >public class Include extends MatchingTask { > > private static final String PREFIX = "//#"; > private static final String PREFIX_END = "//#end"; > private static final String PREFIX_INCLUDE = "//#include "; > > private String srcdir = "."; > > public void setSrcdir(String srcDir) { > this.srcdir = srcDir; > } > > > @Override > public void execute() throws BuildException { > // loop through all java files. > File basedir = new File(getProject().getBaseDir(), srcdir); > DirectoryScanner ds = getDirectoryScanner(basedir); > > for ( String fn : ds.getIncludedFiles() ) { > process(new File(basedir, fn)); > } > } > > private void process(File file) throws BuildException { > > // read the entire file. > LineNumberReader brr; > try { > brr = new LineNumberReader(new FileReader(file)); > } catch (FileNotFoundException ex) { > throw new BuildException(ex, new Location(file.getName())); > } > > ArrayList<String> lines = new ArrayList<String>(); > boolean needed = false; > while(true) { > String line; > try { > line = brr.readLine(); > } catch (IOException ex) { > throw new BuildException(ex, new Location(file.getName(), brr.getLineNumber(), 0)); > } > if(line == null) break; > if(line.trim().startsWith(PREFIX)) needed=true; > lines.add(line); > } > try { > brr.close(); > } catch (IOException ex) { > throw new BuildException(ex, new Location(file.getName())); > } > > // if no preprocessing codes were encountered, skip this file. > if(!needed) return; > > int end = 0; > while(true) { > // search for an include code. > int start = lineStartingWith(lines, end,PREFIX_INCLUDE); > // not found - exit the loop > if(start < 0) break; > // now search for the end code following the include code. > end = lineStartingWith(lines, start+1,PREFIX_END); > if(end < 0) { > throw new BuildException(PREFIX_END+" not found", new Location(file.getName(), start, 0)); > } > > // extract the filename to include. > String filename = lines.get(start).substring(PREFIX_INCLUDE.length()).trim(); > File inc = new File(file.getParentFile(), filename); > // remove all the lines between the include and end codes. > for (int i=0; i<end-(start+1); i++) { > lines.remove(start+1); > } > // add all the lines from the file to be included. > try { > lines.addAll(start + 1, readall(inc)); > } catch (IOException ex) { > throw new BuildException(inc.getAbsolutePath()+" read error", new Location(file.getName(), start, 0)); > } > } > > // write the file back. > try { > PrintWriter out = new PrintWriter(file); > for (String line : lines) { > out.println(line); > } > out.close(); > } catch (FileNotFoundException ex) { > throw new BuildException(ex, new Location(file.getName())); > } > } > > /** > * Find the first line which, when trimmed, starts with the given string. > * @param lines Lines to search in > * @param start Starting line, zero-based > * @param string String to search for. > * @return The first line (zero-based) or -1 if not found. > */ > private int lineStartingWith(ArrayList<String> lines, int start, String string) { > for ( int idx=start; idx<lines.size(); idx++) { > if(lines.get(idx).trim().startsWith(string)) { > return idx; > } > } > return -1; > } > > private HashMap<File,ArrayList<String>> cache = new HashMap<File, ArrayList<String>>(); > /** > * Read all lines from a file into a list. Uses caching for speed, since > * it's likely that each include file will appear in multiple sources. > * @param file File to read. > * @return All the lines as a list of strings. > * @throws java.io.IOException > */ > private ArrayList<String> readall(File file) throws IOException { > if(!cache.containsKey(file)) { > ArrayList<String> lines = new ArrayList<String>(); > LineNumberReader in = new LineNumberReader(new FileReader(file)); > while(true) { > String line; > line = in.readLine(); > if(line == null) break; > lines.add(line); > } > in.close(); > > cache.put(file, lines); > } > return cache.get(file); > } > >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 47163
: 23624