1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.types;
  18. import java.io.File;
  19. import java.util.Enumeration;
  20. import java.util.Hashtable;
  21. import java.util.Stack;
  22. import java.util.Vector;
  23. import org.apache.tools.ant.BuildException;
  24. import org.apache.tools.ant.DirectoryScanner;
  25. import org.apache.tools.ant.FileScanner;
  26. import org.apache.tools.ant.Project;
  27. import org.apache.tools.ant.types.selectors.AndSelector;
  28. import org.apache.tools.ant.types.selectors.ContainsSelector;
  29. import org.apache.tools.ant.types.selectors.DateSelector;
  30. import org.apache.tools.ant.types.selectors.DependSelector;
  31. import org.apache.tools.ant.types.selectors.DepthSelector;
  32. import org.apache.tools.ant.types.selectors.ExtendSelector;
  33. import org.apache.tools.ant.types.selectors.FileSelector;
  34. import org.apache.tools.ant.types.selectors.DifferentSelector;
  35. import org.apache.tools.ant.types.selectors.FilenameSelector;
  36. import org.apache.tools.ant.types.selectors.TypeSelector;
  37. import org.apache.tools.ant.types.selectors.MajoritySelector;
  38. import org.apache.tools.ant.types.selectors.NoneSelector;
  39. import org.apache.tools.ant.types.selectors.NotSelector;
  40. import org.apache.tools.ant.types.selectors.OrSelector;
  41. import org.apache.tools.ant.types.selectors.PresentSelector;
  42. import org.apache.tools.ant.types.selectors.ContainsRegexpSelector;
  43. import org.apache.tools.ant.types.selectors.SelectSelector;
  44. import org.apache.tools.ant.types.selectors.SelectorContainer;
  45. import org.apache.tools.ant.types.selectors.SelectorScanner;
  46. import org.apache.tools.ant.types.selectors.SizeSelector;
  47. import org.apache.tools.ant.types.selectors.modifiedselector.ModifiedSelector;
  48. /**
  49. * Class that holds an implicit patternset and supports nested
  50. * patternsets and creates a DirectoryScanner using these patterns.
  51. *
  52. * <p>Common base class for DirSet and FileSet.</p>
  53. *
  54. */
  55. public abstract class AbstractFileSet extends DataType implements Cloneable,
  56. SelectorContainer {
  57. private PatternSet defaultPatterns = new PatternSet();
  58. private Vector additionalPatterns = new Vector();
  59. private Vector selectors = new Vector();
  60. private File dir;
  61. private boolean useDefaultExcludes = true;
  62. private boolean isCaseSensitive = true;
  63. private boolean followSymlinks = true;
  64. public AbstractFileSet() {
  65. super();
  66. }
  67. protected AbstractFileSet(AbstractFileSet fileset) {
  68. this.dir = fileset.dir;
  69. this.defaultPatterns = fileset.defaultPatterns;
  70. this.additionalPatterns = fileset.additionalPatterns;
  71. this.selectors = fileset.selectors;
  72. this.useDefaultExcludes = fileset.useDefaultExcludes;
  73. this.isCaseSensitive = fileset.isCaseSensitive;
  74. this.followSymlinks = fileset.followSymlinks;
  75. setProject(fileset.getProject());
  76. }
  77. /**
  78. * Makes this instance in effect a reference to another instance.
  79. *
  80. * <p>You must not set another attribute or nest elements inside
  81. * this element if you make it a reference.</p>
  82. */
  83. public void setRefid(Reference r) throws BuildException {
  84. if (dir != null || defaultPatterns.hasPatterns(getProject())) {
  85. throw tooManyAttributes();
  86. }
  87. if (!additionalPatterns.isEmpty()) {
  88. throw noChildrenAllowed();
  89. }
  90. if (!selectors.isEmpty()) {
  91. throw noChildrenAllowed();
  92. }
  93. super.setRefid(r);
  94. }
  95. /**
  96. * Sets the base-directory for this instance.
  97. */
  98. public void setDir(File dir) throws BuildException {
  99. if (isReference()) {
  100. throw tooManyAttributes();
  101. }
  102. this.dir = dir;
  103. }
  104. /**
  105. * Retrieves the base-directory for this instance.
  106. */
  107. public File getDir(Project p) {
  108. if (isReference()) {
  109. return getRef(p).getDir(p);
  110. }
  111. return dir;
  112. }
  113. /**
  114. * Creates a nested patternset.
  115. */
  116. public PatternSet createPatternSet() {
  117. if (isReference()) {
  118. throw noChildrenAllowed();
  119. }
  120. PatternSet patterns = new PatternSet();
  121. additionalPatterns.addElement(patterns);
  122. return patterns;
  123. }
  124. /**
  125. * add a name entry on the include list
  126. */
  127. public PatternSet.NameEntry createInclude() {
  128. if (isReference()) {
  129. throw noChildrenAllowed();
  130. }
  131. return defaultPatterns.createInclude();
  132. }
  133. /**
  134. * add a name entry on the include files list
  135. */
  136. public PatternSet.NameEntry createIncludesFile() {
  137. if (isReference()) {
  138. throw noChildrenAllowed();
  139. }
  140. return defaultPatterns.createIncludesFile();
  141. }
  142. /**
  143. * add a name entry on the exclude list
  144. */
  145. public PatternSet.NameEntry createExclude() {
  146. if (isReference()) {
  147. throw noChildrenAllowed();
  148. }
  149. return defaultPatterns.createExclude();
  150. }
  151. /**
  152. * add a name entry on the excludes files list
  153. */
  154. public PatternSet.NameEntry createExcludesFile() {
  155. if (isReference()) {
  156. throw noChildrenAllowed();
  157. }
  158. return defaultPatterns.createExcludesFile();
  159. }
  160. /**
  161. * Creates a single file fileset.
  162. */
  163. public void setFile(File file) {
  164. if (isReference()) {
  165. throw tooManyAttributes();
  166. }
  167. setDir(file.getParentFile());
  168. PatternSet.NameEntry include = createInclude();
  169. include.setName(file.getName());
  170. }
  171. /**
  172. * Appends <code>includes</code> to the current list of include
  173. * patterns.
  174. *
  175. * <p>Patterns may be separated by a comma or a space.</p>
  176. *
  177. * @param includes the string containing the include patterns
  178. */
  179. public void setIncludes(String includes) {
  180. if (isReference()) {
  181. throw tooManyAttributes();
  182. }
  183. defaultPatterns.setIncludes(includes);
  184. }
  185. /**
  186. * Appends <code>excludes</code> to the current list of exclude
  187. * patterns.
  188. *
  189. * <p>Patterns may be separated by a comma or a space.</p>
  190. *
  191. * @param excludes the string containing the exclude patterns
  192. */
  193. public void setExcludes(String excludes) {
  194. if (isReference()) {
  195. throw tooManyAttributes();
  196. }
  197. defaultPatterns.setExcludes(excludes);
  198. }
  199. /**
  200. * Sets the name of the file containing the includes patterns.
  201. *
  202. * @param incl The file to fetch the include patterns from.
  203. */
  204. public void setIncludesfile(File incl) throws BuildException {
  205. if (isReference()) {
  206. throw tooManyAttributes();
  207. }
  208. defaultPatterns.setIncludesfile(incl);
  209. }
  210. /**
  211. * Sets the name of the file containing the excludes patterns.
  212. *
  213. * @param excl The file to fetch the exclude patterns from.
  214. */
  215. public void setExcludesfile(File excl) throws BuildException {
  216. if (isReference()) {
  217. throw tooManyAttributes();
  218. }
  219. defaultPatterns.setExcludesfile(excl);
  220. }
  221. /**
  222. * Sets whether default exclusions should be used or not.
  223. *
  224. * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions
  225. * should be used, "false"|"off"|"no" when they
  226. * shouldn't be used.
  227. */
  228. public void setDefaultexcludes(boolean useDefaultExcludes) {
  229. if (isReference()) {
  230. throw tooManyAttributes();
  231. }
  232. this.useDefaultExcludes = useDefaultExcludes;
  233. }
  234. /**
  235. * Sets case sensitivity of the file system
  236. *
  237. * @param isCaseSensitive "true"|"on"|"yes" if file system is case
  238. * sensitive, "false"|"off"|"no" when not.
  239. */
  240. public void setCaseSensitive(boolean isCaseSensitive) {
  241. if (isReference()) {
  242. throw tooManyAttributes();
  243. }
  244. this.isCaseSensitive = isCaseSensitive;
  245. }
  246. /**
  247. * Sets whether or not symbolic links should be followed.
  248. *
  249. * @param followSymlinks whether or not symbolic links should be followed
  250. */
  251. public void setFollowSymlinks(boolean followSymlinks) {
  252. if (isReference()) {
  253. throw tooManyAttributes();
  254. }
  255. this.followSymlinks = followSymlinks;
  256. }
  257. /**
  258. * find out if the fileset wants to follow symbolic links
  259. *
  260. * @return flag indicating whether or not symbolic links should be followed
  261. *
  262. * @since ant 1.6
  263. */
  264. public boolean isFollowSymlinks() {
  265. if (isReference()) {
  266. return getRef(getProject()).isFollowSymlinks();
  267. } else {
  268. return followSymlinks;
  269. }
  270. }
  271. /**
  272. * sets the name used for this datatype instance.
  273. */
  274. protected String getDataTypeName() {
  275. // look up the types in project and see if they match this class
  276. Project project = getProject();
  277. if (project != null) {
  278. Hashtable typedefs = project.getDataTypeDefinitions();
  279. for (Enumeration e = typedefs.keys(); e.hasMoreElements();) {
  280. String typeName = (String) e.nextElement();
  281. Class typeClass = (Class) typedefs.get(typeName);
  282. if (typeClass == getClass()) {
  283. return typeName;
  284. }
  285. }
  286. }
  287. String classname = getClass().getName();
  288. int dotIndex = classname.lastIndexOf(".");
  289. if (dotIndex == -1) {
  290. return classname;
  291. }
  292. return classname.substring(dotIndex + 1);
  293. }
  294. /**
  295. * Returns the directory scanner needed to access the files to process.
  296. */
  297. public DirectoryScanner getDirectoryScanner(Project p) {
  298. if (isReference()) {
  299. return getRef(p).getDirectoryScanner(p);
  300. }
  301. if (dir == null) {
  302. throw new BuildException("No directory specified for "
  303. + getDataTypeName() + ".");
  304. }
  305. if (!dir.exists()) {
  306. throw new BuildException(dir.getAbsolutePath() + " not found.");
  307. }
  308. if (!dir.isDirectory()) {
  309. throw new BuildException(dir.getAbsolutePath()
  310. + " is not a directory.");
  311. }
  312. DirectoryScanner ds = new DirectoryScanner();
  313. setupDirectoryScanner(ds, p);
  314. ds.setFollowSymlinks(followSymlinks);
  315. ds.scan();
  316. return ds;
  317. }
  318. public void setupDirectoryScanner(FileScanner ds, Project p) {
  319. if (isReference()) {
  320. getRef(p).setupDirectoryScanner(ds, p);
  321. return;
  322. }
  323. if (ds == null) {
  324. throw new IllegalArgumentException("ds cannot be null");
  325. }
  326. ds.setBasedir(dir);
  327. final int count = additionalPatterns.size();
  328. for (int i = 0; i < count; i++) {
  329. Object o = additionalPatterns.elementAt(i);
  330. defaultPatterns.append((PatternSet) o, p);
  331. }
  332. p.log(getDataTypeName() + ": Setup scanner in dir " + dir
  333. + " with " + defaultPatterns, Project.MSG_DEBUG);
  334. ds.setIncludes(defaultPatterns.getIncludePatterns(p));
  335. ds.setExcludes(defaultPatterns.getExcludePatterns(p));
  336. if (ds instanceof SelectorScanner) {
  337. SelectorScanner ss = (SelectorScanner) ds;
  338. ss.setSelectors(getSelectors(p));
  339. }
  340. if (useDefaultExcludes) {
  341. ds.addDefaultExcludes();
  342. }
  343. ds.setCaseSensitive(isCaseSensitive);
  344. }
  345. /**
  346. * Performs the check for circular references and returns the
  347. * referenced FileSet.
  348. */
  349. protected AbstractFileSet getRef(Project p) {
  350. if (!isChecked()) {
  351. Stack stk = new Stack();
  352. stk.push(this);
  353. dieOnCircularReference(stk, p);
  354. }
  355. Object o = getRefid().getReferencedObject(p);
  356. if (!getClass().isAssignableFrom(o.getClass())) {
  357. String msg = getRefid().getRefId() + " doesn\'t denote a "
  358. + getDataTypeName();
  359. throw new BuildException(msg);
  360. } else {
  361. return (AbstractFileSet) o;
  362. }
  363. }
  364. // SelectorContainer methods
  365. /**
  366. * Indicates whether there are any selectors here.
  367. *
  368. * @return whether any selectors are in this container
  369. */
  370. public boolean hasSelectors() {
  371. if (isReference() && getProject() != null) {
  372. return getRef(getProject()).hasSelectors();
  373. }
  374. return !(selectors.isEmpty());
  375. }
  376. /**
  377. * Indicates whether there are any patterns here.
  378. *
  379. * @return whether any patterns are in this container
  380. */
  381. public boolean hasPatterns() {
  382. if (isReference() && getProject() != null) {
  383. return getRef(getProject()).hasPatterns();
  384. }
  385. if (defaultPatterns.hasPatterns(getProject())) {
  386. return true;
  387. }
  388. Enumeration e = additionalPatterns.elements();
  389. while (e.hasMoreElements()) {
  390. PatternSet ps = (PatternSet) e.nextElement();
  391. if (ps.hasPatterns(getProject())) {
  392. return true;
  393. }
  394. }
  395. return false;
  396. }
  397. /**
  398. * Gives the count of the number of selectors in this container
  399. *
  400. * @return the number of selectors in this container
  401. */
  402. public int selectorCount() {
  403. if (isReference() && getProject() != null) {
  404. return getRef(getProject()).selectorCount();
  405. }
  406. return selectors.size();
  407. }
  408. /**
  409. * Returns the set of selectors as an array.
  410. *
  411. * @return an array of selectors in this container
  412. */
  413. public FileSelector[] getSelectors(Project p) {
  414. if (isReference()) {
  415. return getRef(p).getSelectors(p);
  416. } else {
  417. FileSelector[] result = new FileSelector[selectors.size()];
  418. selectors.copyInto(result);
  419. return result;
  420. }
  421. }
  422. /**
  423. * Returns an enumerator for accessing the set of selectors.
  424. *
  425. * @return an enumerator that goes through each of the selectors
  426. */
  427. public Enumeration selectorElements() {
  428. if (isReference() && getProject() != null) {
  429. return getRef(getProject()).selectorElements();
  430. }
  431. return selectors.elements();
  432. }
  433. /**
  434. * Add a new selector into this container.
  435. *
  436. * @param selector the new selector to add
  437. */
  438. public void appendSelector(FileSelector selector) {
  439. if (isReference()) {
  440. throw noChildrenAllowed();
  441. }
  442. selectors.addElement(selector);
  443. }
  444. /* Methods below all add specific selectors */
  445. /**
  446. * add a "Select" selector entry on the selector list
  447. * @param selector the selector to add
  448. */
  449. public void addSelector(SelectSelector selector) {
  450. appendSelector(selector);
  451. }
  452. /**
  453. * add an "And" selector entry on the selector list
  454. * @param selector the selector to add
  455. */
  456. public void addAnd(AndSelector selector) {
  457. appendSelector(selector);
  458. }
  459. /**
  460. * add an "Or" selector entry on the selector list
  461. * @param selector the selector to add
  462. */
  463. public void addOr(OrSelector selector) {
  464. appendSelector(selector);
  465. }
  466. /**
  467. * add a "Not" selector entry on the selector list
  468. * @param selector the selector to add
  469. */
  470. public void addNot(NotSelector selector) {
  471. appendSelector(selector);
  472. }
  473. /**
  474. * add a "None" selector entry on the selector list
  475. * @param selector the selector to add
  476. */
  477. public void addNone(NoneSelector selector) {
  478. appendSelector(selector);
  479. }
  480. /**
  481. * add a majority selector entry on the selector list
  482. * @param selector the selector to add
  483. */
  484. public void addMajority(MajoritySelector selector) {
  485. appendSelector(selector);
  486. }
  487. /**
  488. * add a selector date entry on the selector list
  489. * @param selector the selector to add
  490. */
  491. public void addDate(DateSelector selector) {
  492. appendSelector(selector);
  493. }
  494. /**
  495. * add a selector size entry on the selector list
  496. * @param selector the selector to add
  497. */
  498. public void addSize(SizeSelector selector) {
  499. appendSelector(selector);
  500. }
  501. /**
  502. * add a DifferentSelector entry on the selector list
  503. * @param selector the selector to add
  504. */
  505. public void addDifferent(DifferentSelector selector) {
  506. appendSelector(selector);
  507. }
  508. /**
  509. * add a selector filename entry on the selector list
  510. * @param selector the selector to add
  511. */
  512. public void addFilename(FilenameSelector selector) {
  513. appendSelector(selector);
  514. }
  515. /**
  516. * add a selector type entry on the selector list
  517. * @param selector the selector to add
  518. */
  519. public void addType(TypeSelector selector) {
  520. appendSelector(selector);
  521. }
  522. /**
  523. * add an extended selector entry on the selector list
  524. * @param selector the selector to add
  525. */
  526. public void addCustom(ExtendSelector selector) {
  527. appendSelector(selector);
  528. }
  529. /**
  530. * add a contains selector entry on the selector list
  531. * @param selector the selector to add
  532. */
  533. public void addContains(ContainsSelector selector) {
  534. appendSelector(selector);
  535. }
  536. /**
  537. * add a present selector entry on the selector list
  538. * @param selector the selector to add
  539. */
  540. public void addPresent(PresentSelector selector) {
  541. appendSelector(selector);
  542. }
  543. /**
  544. * add a depth selector entry on the selector list
  545. * @param selector the selector to add
  546. */
  547. public void addDepth(DepthSelector selector) {
  548. appendSelector(selector);
  549. }
  550. /**
  551. * add a depends selector entry on the selector list
  552. * @param selector the selector to add
  553. */
  554. public void addDepend(DependSelector selector) {
  555. appendSelector(selector);
  556. }
  557. /**
  558. * add a regular expression selector entry on the selector list
  559. * @param selector the selector to add
  560. */
  561. public void addContainsRegexp(ContainsRegexpSelector selector) {
  562. appendSelector(selector);
  563. }
  564. /**
  565. * add the modified selector
  566. * @param selector the selector to add
  567. * @since ant 1.6
  568. */
  569. public void addModified(ModifiedSelector selector) {
  570. appendSelector(selector);
  571. }
  572. /**
  573. * add an arbitary selector
  574. * @param selector the selector to add
  575. * @since Ant 1.6
  576. */
  577. public void add(FileSelector selector) {
  578. appendSelector(selector);
  579. }
  580. /**
  581. * Returns included files as a list of semicolon-separated filenames
  582. *
  583. * @return String object with included filenames
  584. */
  585. public String toString() {
  586. DirectoryScanner ds = getDirectoryScanner(getProject());
  587. String[] files = ds.getIncludedFiles();
  588. StringBuffer sb = new StringBuffer();
  589. for (int i = 0; i < files.length; i++) {
  590. if (i > 0) {
  591. sb.append(';');
  592. }
  593. sb.append(files[i]);
  594. }
  595. return sb.toString();
  596. }
  597. /**
  598. * Creates a deep clone of this instance, except for the nested
  599. * selectors (the list of selectors is a shallow clone of this
  600. * instance's list).
  601. *
  602. * @since Ant 1.6
  603. */
  604. public Object clone() {
  605. if (isReference()) {
  606. return (getRef(getProject())).clone();
  607. } else {
  608. try {
  609. AbstractFileSet fs = (AbstractFileSet) super.clone();
  610. fs.defaultPatterns = (PatternSet) defaultPatterns.clone();
  611. fs.additionalPatterns = new Vector(additionalPatterns.size());
  612. Enumeration e = additionalPatterns.elements();
  613. while (e.hasMoreElements()) {
  614. fs.additionalPatterns
  615. .addElement(((PatternSet) e.nextElement()).clone());
  616. }
  617. fs.selectors = (Vector) fs.selectors.clone();
  618. return fs;
  619. } catch (CloneNotSupportedException e) {
  620. throw new BuildException(e);
  621. }
  622. }
  623. }
  624. }