You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tutorial-tasks-filesets-properties.html 30 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. <html>
  2. <head>
  3. <title>Tutorial: Tasks using Properties & Filesets</title>
  4. <meta name="author" content="Jan Matrne">
  5. <style type="text/css">
  6. <!--
  7. .code { background: #EFEFEF; margin-top: }
  8. .output { color: #FFFFFF; background: #837A67; }
  9. -->
  10. </style>
  11. </head>
  12. <body>
  13. <h1>Tutorial: Tasks using Properties & Filesets</h1>
  14. <p>After reading the tutorial about <a href="tutorial-writing-tasks.html">writing
  15. tasks</a> this tutorial explains how to get and set properties and how to use
  16. nested filesets and paths.</p>
  17. <h2>Content</h2>
  18. <p><ul>
  19. <li><a href="#s">s</a></li>
  20. </ul></p>
  21. <a name="goal"/>
  22. <h2>The goal</h2>
  23. <p>The goal is to write a task, which searchs in a path for a file and saves the
  24. location of that file in a property.</p>
  25. <a name="buildenvironment"/>
  26. <h2>Build environment</h2>
  27. <p>We can use the buildfile from the other tutorial and modify it a little bit.
  28. Thats the advantage of using properties - we can reuse nearly the whole script. :-)</p>
  29. <pre class="code">
  30. &lt;?xml version="1.0" encoding="ISO-8859-1"?>
  31. &lt;project name="<b>FindTask</b>" basedir="." default="test">
  32. ...
  33. &lt;target name="use.init" description="Taskdef the <b>Find</b>-Task" depends="jar">
  34. &lt;taskdef name="<b>find</b>" classname="<b>Find</b>" classpath="${ant.project.name}.jar"/>
  35. &lt;/target>
  36. <b>&lt;!-- the other use.* targets are deleted --&gt;</b>
  37. ...
  38. &lt;/project>
  39. </pre>
  40. <a name="propertyaccess"/>
  41. <h2>Property access</h2>
  42. <p>Our first step is to set a property to a value and print the value of property. So our scenario
  43. would be
  44. <pre class="code">
  45. &lt;find property="test" value="test-value"/>
  46. &lt;find print="test"/>
  47. </pre>
  48. ok, can be rewritten with the core tasks
  49. <pre class="code">
  50. &lt;property name="test" value="test-value"/>
  51. &lt;echo message="${test}"/>
  52. </pre>
  53. but I have to start on known ground :-)</p>
  54. <p>So what to do? Handling three attributes (property, value, print) and an execute. Because this
  55. is only an introduction example I dont do much checking:
  56. <pre class="code">
  57. import org.apache.tools.ant.BuildException;
  58. public class Find extends Task {
  59. private String property;
  60. private String value;
  61. private String print;
  62. public void setProperty(String property) {
  63. this.property = property;
  64. }
  65. // setter for value and print
  66. public void execute() {
  67. if (print != null) {
  68. String propValue = <b>getProject().getProperty(print)</b>;
  69. log(propValue);
  70. } else {
  71. if (property == null) throw new BuildException("property not set");
  72. if (value == null) throw new BuildException("value not set");
  73. <b>getProject().setNewProperty(property, value)</b>;
  74. }
  75. }
  76. }
  77. </pre>
  78. As said in the other tutorial, the property access is done via Project instance.
  79. This instance we get via the public <tt>getProject()</tt> method which we inherit from
  80. <tt>Task</tt> (more precise from ProjectComponent). Reading a property is done via
  81. <tt>getProperty(<i>propertyname</i>)</tt> (very simple, isnt it?). This property returns
  82. the value (String) or <i>null</i> if not set.<br>
  83. Setting a property is ... not really difficult, but there is more than one setter. You can
  84. use the <tt>setProperty()</tt> method which will do the job like expected. But there is
  85. a golden rule in Ant: <i>properties are immutable</i>. And this method sets the property
  86. to the specified value - whether it has a value before that or not. So we use another
  87. way. <tt>setNewProperty()</tt> sets the property only if there is no property with that
  88. name. Otherwise a message is logged.</p>
  89. <p><i>(by the way: a short word to ants "namespaces" (dont
  90. be confused with xml namespaces which will be also introduces in the future (1.6 or 1.7):
  91. an &lt;antcall> creates a new space for property names. All properties from the caller
  92. are passed to the callee, but the callee can set its own properties without notice by the
  93. caller.)</i></p>
  94. <p>There are some other setter, too (but I havent used them, so I cant say something
  95. to them, sorry :-)</p>
  96. <p>After putting our two line example from above into a target names <tt>use.simple</tt>
  97. we can call that from our testcase:
  98. <pre class="code">
  99. import org.apache.tools.ant.BuildFileTest;
  100. public class FindTest extends BuildFileTest {
  101. public FindTest(String name) {
  102. super(name);
  103. }
  104. public void setUp() {
  105. configureProject("build.xml");
  106. }
  107. public void testSimple() {
  108. <b>expectLog("use.simple", "test-value");</b>
  109. }
  110. }
  111. </pre>
  112. and all works fine.</p>
  113. <a name="filesets"/>
  114. <h2>Using filesets</h2>
  115. <p>Ant provides a common way of bundling files: the fileset. Because you are reading
  116. this tutorial I think you know them and I dont have to spend more explanations about
  117. their usage in buildfiles. Our goal is to search a file in path. And on this step the
  118. path is simply a fileset (or more precise: a collection of filesets). So our usage
  119. would be
  120. <pre class="code">
  121. &lt;find file="ant.jar" location="location.ant-jar">
  122. &lt;fileset dir="${ant.home}" includes="**/*.jar"/>
  123. &lt;/find>
  124. </pre>
  125. </p>
  126. <p>What do we need? A task with two attributes (file, location) and nested
  127. filesets. Because we had attribute handling already in the example above and the handling
  128. of nested elements is described in the other tutorial the code should be very easy:
  129. <pre class="code">
  130. public class Find extends Task {
  131. private String file;
  132. private String location;
  133. private Vector filesets = new Vector();
  134. public void setFile(String file) {
  135. this.file = file;
  136. }
  137. public void setLocation(String location) {
  138. this.location = location;
  139. }
  140. public void addFileset(FileSet fileset) {
  141. filesets.add(fileset);
  142. }
  143. public void execute() {
  144. }
  145. }
  146. </pre>
  147. Ok - that task wouldnt do very much, but we can use it in the described manner without
  148. failure. On next step we have to implement the execute method. And before that we will
  149. implement the appropriate testcases (TDD - test driven development).</p>
  150. <p>In the other tutorial we have reused the already written targets of our buildfile.
  151. Now we will configure most of the testcases via java code (sometimes its much easier
  152. to write a target than doing it via java coding). What can be tested?<ul>
  153. <li>not valid configured task (missing file, missing location, missing fileset)</li>
  154. <li>dont find a present file</li>
  155. <li>behaviour if file cant be found</li>
  156. </ul>
  157. Maybe you find some more testcases. But this is enough for now.<br>
  158. For each of these points we create a <tt>testXX</tt> method.</p>
  159. <pre class="code">
  160. public class FindTest extends BuildFileTest {
  161. ... // constructor, setUp as above
  162. public void testMissingFile() {
  163. <b>Find find = new Find();</b>
  164. try {
  165. <b>find.execute();</b>
  166. fail("No 'no-file'-exception thrown.");
  167. } catch (Exception e) {
  168. // exception expected
  169. String expected = "file not set";
  170. assertEquals("Wrong exception message.", expected, e.getMessage());
  171. }
  172. }
  173. public void testMissingLocation() {
  174. Find find = new Find();
  175. <b>find.setFile("ant.jar");</b>
  176. try {
  177. find.execute();
  178. fail("No 'no-location'-exception thrown.");
  179. } catch (Exception e) {
  180. ... // similar to testMissingFile()
  181. }
  182. }
  183. public void testMissingFileset() {
  184. Find find = new Find();
  185. find.setFile("ant.jar");
  186. find.setLocation("location.ant-jar");
  187. try {
  188. find.execute();
  189. fail("No 'no-fileset'-exception thrown.");
  190. } catch (Exception e) {
  191. ... // similar to testMissingFile()
  192. }
  193. }
  194. public void testFileNotPresent() {
  195. executeTarget("testFileNotPresent");
  196. String result = getProject().getProperty("location.ant-jar");
  197. assertNull("Property set to wrong value.", result);
  198. }
  199. public void testFilePresent() {
  200. executeTarget("testFilePresent");
  201. String result = getProject().getProperty("location.ant-jar");
  202. assertNotNull("Property not set.", result);
  203. assertTrue("Wrong file found.", result.endsWith("ant.jar"));
  204. }
  205. }
  206. </pre>
  207. <p>If we run this test class all test cases (except <i>testFileNotPresent</i>) fail. No we
  208. can implement our task, so that these test cases will pass.</p>
  209. <pre class="code">
  210. protected void validate() {
  211. if (file==null) throw new BuildException("file not set");
  212. if (location==null) throw new BuildException("location not set");
  213. if (filesets.size()&lt;1) throw new BuildException("fileset not set");
  214. }
  215. public void execute() {
  216. validate(); // 1
  217. String foundLocation = null;
  218. for(Iterator itFSets = filesets.iterator(); itFSets.hasNext(); ) { // 2
  219. FileSet fs = (FileSet)itFSets.next();
  220. DirectoryScanner ds = fs.getDirectoryScanner(getProject()); // 3
  221. String[] includedFiles = ds.getIncludedFiles();
  222. for(int i=0; i&lt;includedFiles.length; i++) {
  223. String filename = includedFiles[i].replace('\\','/'); // 4
  224. filename = filename.substring(filename.lastIndexOf("/")+1);
  225. if (foundLocation==null && file.equals(filename)) {
  226. File base = ds.getBasedir(); // 5
  227. File found = new File(base, includedFiles[i]);
  228. foundLocation = found.getAbsolutePath();
  229. }
  230. }
  231. }
  232. if (foundLocation!=null) // 6
  233. getProject().setNewProperty(location, foundLocation);
  234. }
  235. </pre>
  236. <p>On <b>//1</b> we check the prerequisites for our task. Doing that in a <tt>validate</tt>-method
  237. is a common way, because we separate the prerequisites from the real work. On <b>//2</b> we iterate
  238. over all nested filesets. We we dont want to handle multiple filesets, the <tt>addFileset()</tt>
  239. method has to reject the further calls. We can get the result of fileset via its DirectoryScanner
  240. like done <b>//3</b>. After that we create a plattform independend String representation of
  241. the file path (<b>//4</b>, can be done in other ways of course). We have to do the <tt>replace()</tt>,
  242. because we work with a simple string comparison. Ant itself is platform independant and can
  243. therefore run on filesystems with slash (/, e.g. Linux) or backslash (\, e.g. Windows) as
  244. path separator. Therefore we have to unify that. If we found our file we create an absolute
  245. path representation on <b>//5</b>, so that we can use that information without knowing the basedir.
  246. (This is very important on use with multiple filesets, because they can have different basedirs
  247. and the return value of the directory scanner is relative to its basedir.) Finally we store the
  248. location of the file as property, if we had found one (<b>//6</b>).</p>
  249. <p>Ok, much more easier in this simple case would be to add the <i>file</i> as additional
  250. <i>include</i> element to all filesets. But I wanted to show how to handle complex situations
  251. whithout being complex :-)</p>
  252. <p>The test case uses the ant property <i>ant.home</i> as reference. This property is set by the
  253. <tt>Launcher</tt> class which starts ant. We can use that property in our buildfiles as a build-in
  254. property (see [XXX]). But if we create a new ant environment we have to set that value for our own.
  255. And we use the &lt;junit&lt; task in fork-mode. Therefore we have do modify our buildfile:
  256. <pre class="code">
  257. &lt;target name="junit" description="Runs the unit tests" depends="jar">
  258. &lt;delete dir="${junit.out.dir.xml}" />
  259. &lt;mkdir dir="${junit.out.dir.xml}" />
  260. &lt;junit printsummary="yes" haltonfailure="no">
  261. &lt;classpath refid="classpath.test"/>
  262. <b>&lt;sysproperty key="ant.home" value="${ant.home}"/></b>
  263. &lt;formatter type="xml"/>
  264. &lt;batchtest fork="yes" todir="${junit.out.dir.xml}">
  265. &lt;fileset dir="${src.dir}" includes="**/*Test.java"/>
  266. &lt;/batchtest>
  267. &lt;/junit>
  268. &lt;/target>
  269. </pre>
  270. <a name="path"/>
  271. <h2>Using nested paths</h2>
  272. <p>A task providing support for filesets is a very comfortable one. But there is another
  273. possibility of bundling files: the &lt;path>. Fileset are easy if the files are all under
  274. a common base directory. But if this is not the case you have a problem. Another disadvantage
  275. is its speed: if you have only a few files in a huge directory structure, why not use a
  276. &lt;fileset> instead? &lt;path>s combines these datatypes in that way that a path contains
  277. other paths, filesets, dirsets and filelists. This is way <a href="">Ant-Contribs [XXX]</a>
  278. &lt;foreach> task is modified to support paths instead of filesets. So we want that, too.</p>
  279. <p>Changing from fileset to path support is very easy:</p>
  280. <pre class="code">
  281. <i><b>Change java code from:</b></i>
  282. private Vector filesets = new Vector();
  283. public void addFileset(FileSet fileset) {
  284. filesets.add(fileset);
  285. }
  286. <i><b>to:</b></i>
  287. private Vector paths = new Vector(); *1
  288. public void add<b>Path</b>(<b>Path</b> path) { *2
  289. paths.add(path);
  290. }
  291. <i><b>and build file from:</b></i>
  292. &lt;find file="ant.jar" location="location.ant-jar">
  293. &lt;fileset dir="${ant.home}" includes="**/*.jar"/>
  294. &lt;/find>
  295. <i><b>to:</b></i>
  296. &lt;find file="ant.jar" location="location.ant-jar">
  297. <b>&lt;path></b> *3
  298. &lt;fileset dir="${ant.home}" includes="**/*.jar"/>
  299. &lt;/path>
  300. &lt;/find>
  301. </pre>
  302. <p>On <b>*1</b> we rename only the vector. Its just for better reading the source. On <b>*2</b>
  303. we have to provide the right method: an add<i>Name</i>(<i>Type</i> t). Therefore replace the
  304. fileset with path here. Finally we have to modify our buildfile on <b>*3</b> because our task
  305. dont support nested filesets any longer. So we wrap the fileset inside a path.</p>
  306. <p>And now we modify the testcase. Oh, not very much to do :-) Renaming the <tt>testMissingFileset()</tt>
  307. (not really a <i>must-be</i> but better its named like the think it does) and update the
  308. <i>expected</i>-String in that method (now a <tt>path not set</tt> message is expected). The more complex
  309. test cases base on the buildscript. So the targets <tt>testFileNotPresent</tt> and <tt>testFilePresent</tt> have to be
  310. modified in the manner described above.</p>
  311. <p>The test are finished. Now we have to adapt the task implementation. The easiest modification is
  312. in the <tt>validate()</tt> method where we change le last line to <tt>if (paths.size()&lt;1) throw new
  313. BuildException("path not set");</tt>. In the <tt>execute()</tt> method we have a liitle more work.
  314. ... mmmh ... in reality its lesser work, because the Path class does a the whole DirectoryScanner-handling
  315. and creating absolute paths stuff for us. So the execute method is just:</p>
  316. <pre class="code">
  317. public void execute() {
  318. validate();
  319. String foundLocation = null;
  320. for(Iterator itPaths = paths.iterator(); itPaths.hasNext(); ) {
  321. Path path = (<b>Path</b>)itPaths.next(); // 1
  322. String[] includedFiles = <b>path.list()</b>; // 2
  323. for(int i=0; i&lt;includedFiles.length; i++) {
  324. String filename = includedFiles[i].replace('\\','/');
  325. filename = filename.substring(filename.lastIndexOf("/")+1);
  326. if (foundLocation==null && file.equals(filename)) {
  327. <b>foundLocation = includedFiles[i];</b> // 3
  328. }
  329. }
  330. }
  331. if (foundLocation!=null)
  332. getProject().setNewProperty(location, foundLocation);
  333. }
  334. </pre>
  335. <p>Of course we have to do the typecase to Path on <b>//1</b>. On <b>//2</b> and <b>//3</b>
  336. we see that the Path class does the work for us: no DirectoryScanner (was at 2) and no
  337. creating of the absolute path (was at 3).</p>
  338. <a name="returning-list"/>
  339. <h2>Returning a list</h2>
  340. <p>So far so good. But could a file be on more than one place in the path? - Of course.<br>
  341. And would it be good to get all of them? - It depends on ...<p>
  342. <p>In this section we will extend that task to support returning a list of all files.
  343. Lists as property values are not supported by Ant natively. So we have to see how other
  344. tasks use lists. The most famous task using lists is Ant-Contribs &lt;foreach>. All list
  345. elements are concatenated and separated with a customizable separator (default ',').</p>
  346. <p>So we do the following:</p>
  347. <pre class="code">
  348. &lt;find ... <b>delimiter=""</b>/> ... &lt;/find>
  349. </pre>
  350. <p>If the delimiter is set we will return all found files as list with that delimiter.</p>
  351. <p>Therefore we have to<ul>
  352. <li>provide a new attribute</li>
  353. <li>collect more than the first file</li>
  354. <li>delete duplicates</li>
  355. <li>create the list if necessary</li>
  356. <li>return that list</li>
  357. </ul></p>
  358. <p>So we add as testcase:</p>
  359. <pre class="code">
  360. <b><i>in the buildfile:</i></b>
  361. &lt;target name="test.init">
  362. &lt;mkdir dir="test1/dir11/dir111"/> *1
  363. &lt;mkdir dir="test1/dir11/dir112"/>
  364. ...
  365. &lt;touch file="test1/dir11/dir111/test"/>
  366. &lt;touch file="test1/dir11/dir111/not"/>
  367. ...
  368. &lt;touch file="test1/dir13/dir131/not2"/>
  369. &lt;touch file="test1/dir13/dir132/test"/>
  370. &lt;touch file="test1/dir13/dir132/not"/>
  371. &lt;touch file="test1/dir13/dir132/not2"/>
  372. &lt;mkdir dir="test2"/>
  373. &lt;copy todir="test2"> *2
  374. &lt;fileset dir="test1"/>
  375. &lt;/copy>
  376. &lt;/target>
  377. &lt;target name="testMultipleFiles" depends="use.init,<b>test.init</b>"> *3
  378. &lt;find file="test" location="location.test" <b>delimiter=";"</b>>
  379. &lt;path>
  380. &lt;fileset dir="test1"/>
  381. &lt;fileset dir="test2"/>
  382. &lt;/path>
  383. &lt;/find>
  384. &lt;delete> *4
  385. &lt;fileset dir="test1"/>
  386. &lt;fileset dir="test2"/>
  387. &lt;/delete>
  388. &lt;/target>
  389. <b><i>in the test class:</i></b>
  390. public void testMultipleFiles() {
  391. executeTarget("testMultipleFiles");
  392. String result = getProject().getProperty("location.test");
  393. assertNotNull("Property not set.", result);
  394. assertTrue("Only one file found.", result.indexOf(";") &gt; -1);
  395. }
  396. </pre>
  397. <p>Now we need a directory structure where we CAN find files with the same
  398. name in different directories. Because we cant sure to have one we create
  399. one on <b>*1, *2</b>. And of course we clean up that on <b>*4</b>. The creation
  400. can be done inside our test target or in a separate one, which will be better
  401. for reuse later (<b>*3</b>).
  402. <p>The task implementation is modified as followed:</p>
  403. <pre class="code">
  404. private Vector foundFiles = new Vector();
  405. ...
  406. private String delimiter = null;
  407. ...
  408. public void setDelimiter(String delim) {
  409. delimiter = delim;
  410. }
  411. ...
  412. public void execute() {
  413. validate();
  414. // find all files
  415. for(Iterator itPaths = paths.iterator(); itPaths.hasNext(); ) {
  416. Path path = (Path)itPaths.next();
  417. String[] includedFiles = path.list();
  418. for(int i=0; i&lt;includedFiles.length; i++) {
  419. String filename = includedFiles[i].replace('\\','/');
  420. filename = filename.substring(filename.lastIndexOf("/")+1);
  421. if (file.equals(filename) && <b>!foundFiles.contains(includedFiles[i]</b>)) { // 1
  422. foundFiles.add(includedFiles[i]);
  423. }
  424. }
  425. }
  426. // create the return value (list/single)
  427. String rv = null;
  428. if (foundFiles.size() &gt; 0) { // 2
  429. if (delimiter==null) {
  430. // only the first
  431. rv = (String)foundFiles.elementAt(0);
  432. } else {
  433. // create list
  434. StringBuffer list = new StringBuffer();
  435. for(Iterator it=foundFiles.iterator(); it.hasNext(); ) { // 3
  436. list.append(it.next());
  437. if (<b>it.hasNext()</b>) list.append(delimiter); // 4
  438. }
  439. rv = list.toString();
  440. }
  441. }
  442. // create the property
  443. if (rv!=null)
  444. getProject().setNewProperty(location, rv);
  445. }
  446. </pre>
  447. <p>The algorithm does: finding all files, creating the return value depending on the users
  448. wish, returning the value as property. On <b>//1</b> we eliminates the duplicates. <b>//2</b>
  449. ensures that we create the return value only if we have found one file. On <b>//3</b> we
  450. iterate over all found files and <b>//4</b> ensures that the last entry has no trailing
  451. delimiter.</p>
  452. <p>Ok, first searching for all files and then returning only the first one ... You can
  453. tune the performance of your own :-)</p>
  454. <a name="documentation"/>
  455. <h2>Documentation</h2>
  456. <p>A task is useless if the only who is able to code the buildfile is the task developer
  457. (and he only the next few weeks :-). So documentation is also very important. In which
  458. form you do that depends on your favourite. But inside Ant there is a common format and
  459. it has advantages if you use that: all task users know that form, this form is requested if
  460. you decide to contribute your task. So we will doc our task in that form.</p>
  461. <p>If you have a look at the manual page of the <a href="">java [XXX]</a> task you will see<ul>
  462. <li>it is plain html</li>
  463. <li>starts with the name</li>
  464. <li>has sections: description, parameters, nested elements, (maybe return codes) and (most
  465. important :-) examples</li>
  466. <li>parameters are listed in a table with columns for attribute name, its description and whether
  467. its required (if you add a feature after an Ant release, provide a <tt>since Ant xx</tt>
  468. statement when its introduced)</li>
  469. <li>describe the nested elements (since-statement if necessary)</li>
  470. <li>provide one or more useful examples; first code then description</li>
  471. </ul>
  472. As a template we have:
  473. <pre class="code">
  474. &lt;html>
  475. &lt;head>
  476. &lt;meta http-equiv="Content-Language" content="en-us">
  477. &lt;title> <b>Taskname</b> Task&lt;/title>
  478. &lt;/head>
  479. &lt;body>
  480. &lt;h2>&lt;a name="<i>taskname</i>"><b>Taskname</b>&lt;/a>&lt;/h2>
  481. &lt;h3>Description&lt;/h3>
  482. &lt;p> <b>Describe the task.</b>&lt;/p>
  483. &lt;h3>Parameters&lt;/h3>
  484. &lt;table border="1" cellpadding="2" cellspacing="0">
  485. &lt;tr>
  486. &lt;td valign="top">&lt;b>Attribute&lt;/b>&lt;/td>
  487. &lt;td valign="top">&lt;b>Description&lt;/b>&lt;/td>
  488. &lt;td align="center" valign="top">&lt;b>Required&lt;/b>&lt;/td>
  489. &lt;/tr>
  490. <b>do this html row for each attribute (including inherited attributes)</b>
  491. &lt;tr>
  492. &lt;td valign="top">classname&lt;/td>
  493. &lt;td valign="top">the Java class to execute.&lt;/td>
  494. &lt;td align="center" valign="top">Either jar or classname&lt;/td>
  495. &lt;/tr>
  496. &lt;/table>
  497. &lt;h3>Parameters specified as nested elements&lt;/h3>
  498. <b>Describe each nested element (including inherited)</b>
  499. &lt;h4><b>your nested element</b>&lt;/h4>
  500. &lt;p> <b>description</b> &lt;/p>
  501. &lt;p>&lt;em>since Ant 1.6&lt;/em>.&lt;/p>
  502. &lt;h3>Examples&lt;/h3>
  503. &lt;pre>
  504. <b>A code sample; dont forget to escape the &lt; of the tags with &amp;lt;</b>
  505. &lt;/pre>
  506. <b>what should that example do?</b>
  507. &lt;/body>
  508. &lt;/html>
  509. </pre>
  510. <p>For our task we have <a href="">that [XXX]</a>:</p>
  511. <pre class="code">
  512. &lt;html>
  513. &lt;head>
  514. &lt;meta http-equiv="Content-Language" content="en-us">
  515. &lt;title> Find Task&lt;/title>
  516. &lt;/head>
  517. &lt;body>
  518. &lt;h2>&lt;a name="find">Find&lt;/a>&lt;/h2>
  519. &lt;h3>Description&lt;/h3>
  520. &lt;p>Searchs in a given path for a file and returns the absolute to it as property.
  521. If delimiter is set this task returns all found locations.&lt;/p>
  522. &lt;h3>Parameters&lt;/h3>
  523. &lt;table border="1" cellpadding="2" cellspacing="0">
  524. &lt;tr>
  525. &lt;td valign="top">&lt;b>Attribute&lt;/b>&lt;/td>
  526. &lt;td valign="top">&lt;b>Description&lt;/b>&lt;/td>
  527. &lt;td align="center" valign="top">&lt;b>Required&lt;/b>&lt;/td>
  528. &lt;/tr>
  529. &lt;tr>
  530. &lt;td valign="top">file&lt;/td>
  531. &lt;td valign="top">The name of the file to search.&lt;/td>
  532. &lt;td align="center" valign="top">yes&lt;/td>
  533. &lt;/tr>
  534. &lt;tr>
  535. &lt;td valign="top">location&lt;/td>
  536. &lt;td valign="top">The name of the property where to store the location&lt;/td>
  537. &lt;td align="center" valign="top">yes&lt;/td>
  538. &lt;/tr>
  539. &lt;tr>
  540. &lt;td valign="top">delimiter&lt;/td>
  541. &lt;td valign="top">A delimiter to use when returning the list&lt;/td>
  542. &lt;td align="center" valign="top">only if the list is required&lt;/td>
  543. &lt;/tr>
  544. &lt;/table>
  545. &lt;h3>Parameters specified as nested elements&lt;/h3>
  546. &lt;h4>path&lt;/h4>
  547. &lt;p>The path where to search the file.&lt;/p>
  548. &lt;h3>Examples&lt;/h3>
  549. &lt;pre>
  550. &lt;find file="ant.jar" location="loc">
  551. &lt;path>
  552. &lt;fileset dir="${ant.home}"/>
  553. &lt;path>
  554. &lt;/find>
  555. &lt;/pre>
  556. Searches in Ants home directory for a file &lt;i>ant.jar&lt;/i> and stores its location in
  557. property &lt;i>loc&lt;/i> (should be ANT_HOME/bin/ant.jar).
  558. &lt;pre>
  559. &lt;find file="ant.jar" location="loc" delimiter=";">
  560. &lt;path>
  561. &lt;fileset dir="C:/"/>
  562. &lt;path>
  563. &lt;/find>
  564. &lt;echo>ant.jar found in: ${loc}&lt;/echo>
  565. &lt;/pre>
  566. Searches in Windows C: drive for all &lt;i>ant.jar&lt;/i> and stores their locations in
  567. property &lt;i>loc&lt;/i> delimited with &lt;i>';'&lt;/i>. (should need a long time :-)
  568. After that it prints out the result (e.g. C:/ant-1.5.4/bin/ant.jar;C:/ant-1.6/bin/ant.jar).
  569. &lt;/body>
  570. &lt;/html>
  571. </pre>
  572. <a name="contribute"/>
  573. <h2>Contribute the new task</h2>
  574. If we decide to contribute our task, we should do some things:<ul>
  575. <li>is our task welcome? :-) Simply ask on the user list</li>
  576. <li>is the right package used? </li>
  577. <li>is the code conform to the styleguide?</li>
  578. <li>do all tests pass? </li>
  579. <li>does the code compile on JDK 1.2 (and passes all tests there)?</li>
  580. <li>code under Apache license</li>
  581. <li>create a patch file</li>
  582. <li>publishing that patch file</li>
  583. </ul>
  584. The <a href="">Ant Task Guidelines [XXX]</a> support additional information on that.</p>
  585. <p>Now we will check the "Checklist before submitting a new task" described in that guideline.
  586. <ul>
  587. <li>Java file begins with Apache copyright and license statement. <b><i>must do that</i></b></li>
  588. <li>Task does not depend on GPL or LGPL code. <b><i>ok</i></b></li>
  589. <li>Source code complies with style guidelines <b><i>have to check (checkstyle)</i></b></li>
  590. <li>Code compiles and runs on Java1.2 <b><i>have to try</i></b></li>
  591. <li>Member variables are private, and provide public accessor methods
  592. if access is actually needed. <b><i>have to check (checkstyle)</i></b></li>
  593. <li><i>Maybe</i> Task has failonerror attribute to control failure behaviour <b><i>hasnt</i></b></li>
  594. <li>New test cases written and succeed <b><i>passed on JDK 1.4, have to try on JDK 1.2</i></b></li>
  595. <li>Documentation page written <b><i>ok</i></b></li>
  596. <li>Example task declarations in the documentation tested. <b><i>ok (used in tests)</i></b></li>
  597. <li>Patch files generated using cvs diff -u <b><i>to do</i></b></li>
  598. <li>patch files include a patch to defaults.properties to register the
  599. tasks <b><i>to do</i></b></li>
  600. <li>patch files include a patch to coretasklist.html or
  601. optionaltasklist.html to link to the new task page <b><i>to do</i></b></li>
  602. <li>Message to dev contains [SUBMIT] and task name in subject <b><i>to do</i></b></li>
  603. <li>Message body contains a rationale for the task <b><i>to do</i></b></li>
  604. <li>Message attachments contain the required files -source, documentation,
  605. test and patches zipped up to escape the HTML filter. <b><i>to do</i></b></li>
  606. </ul>
  607. <h3>Package / Directories</h3>
  608. This task does not depend any external library. Therefore we can use this as
  609. a core task. This task contains only one class. So we can use the standardd package
  610. for core tasks: <tt>org.apache.tools.ant.taskdefs</tt>. Implementations are in the
  611. directory <tt>src/main</tt>, tests in <tt>src/testcases</tt> and buildfiles for
  612. tests in <tt>src/etc/testcases</tt>.
  613. <h3>Apache copyright and license statement</h3>
  614. <p>Simply copy the license text from one the other source from the Ant source tree. But
  615. ensure that the current year is used in the<tt> * Copyright (c) 2000-2003 The Apache Software
  616. Foundation. All rights reserved.</tt> lines.
  617. <h3>Checkstyle</h3>
  618. There are many things we have to ensure. Indentation with 4 spaces, blanks here and there, ...
  619. (all described in the <a href="">Ant Task Guidelines [XXX]</a> which includes the
  620. <a href="">Sun code style [XXX]</a>. Because there are so many things we would be happy
  621. to have a tool for do the checks. There is one: checkstyle. Checkstyle is available
  622. at <a href="">Sourceforge [XXX]</a> and Ant provides with the <tt>check.xml</tt> a buildfile
  623. which will do the job for us.
  624. <h3>Test on JDK 1.2</h3>
  625. <h3>Creating the diff</h3>
  626. <h3>Publish the task</h3>
  627. <br><br><br><br><br><br><br><br>
  628. - stichpunkte siehe ... manual
  629. - ist das richtige package gewhlt worden?
  630. - checkstyle
  631. - tests
  632. - dokumentation
  633. - jdk 1.2
  634. - patch erstellen
  635. - bugzilla / mailingliste
  636. <a name="resources"/>
  637. <h2>Resources</h2>
  638. -- text durchsehen
  639. &nbsp;&nbsp;[1] <a href="http://ant.apache.org/manual/using.html#built-in-props">http://ant.apache.org/manual/using.html#built-in-props</a><br/>
  640. <hr>
  641. <p align="center">Copyright &copy; 2003 Apache Software Foundation. All rights
  642. Reserved.</p>
  643. </body>
  644. </html>