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

AntBuilder.java 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Eclipse Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/epl-v10.html
  8. *
  9. * Contributors:
  10. * Xerox/PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.internal.tools.ant.taskdefs;
  13. import java.io.File;
  14. import java.io.FileWriter;
  15. import java.io.IOException;
  16. import java.lang.reflect.Method;
  17. import java.net.URL;
  18. import java.net.URLClassLoader;
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.Collection;
  22. import java.util.HashMap;
  23. import java.util.Hashtable;
  24. import java.util.Iterator;
  25. import java.util.List;
  26. import java.util.Map;
  27. import org.apache.tools.ant.BuildException;
  28. import org.apache.tools.ant.Project;
  29. import org.apache.tools.ant.Target;
  30. import org.apache.tools.ant.Task;
  31. import org.apache.tools.ant.taskdefs.Copy;
  32. import org.apache.tools.ant.taskdefs.Javac;
  33. import org.apache.tools.ant.taskdefs.Zip;
  34. import org.apache.tools.ant.types.FileSet;
  35. import org.apache.tools.ant.types.Path;
  36. import org.apache.tools.ant.types.ZipFileSet;
  37. import org.aspectj.internal.tools.build.BuildSpec;
  38. import org.aspectj.internal.tools.build.Builder;
  39. import org.aspectj.internal.tools.build.Messager;
  40. import org.aspectj.internal.tools.build.Module;
  41. import org.aspectj.internal.tools.build.Result;
  42. import org.aspectj.internal.tools.build.Util;
  43. /**
  44. * Implement Builder in Ant.
  45. */
  46. public class AntBuilder extends Builder {
  47. private static final boolean FORCE_FORK_FOR_LIBRARIES = false;
  48. /**
  49. * Factory for a Builder.
  50. *
  51. * @param config the String configuration, where only substrings "verbose" and "useEclipseCompiles" are significant
  52. * @param project the owning Project for all tasks (not null)
  53. * @param tempDir the File path to a temporary dir for side effects (may be null)
  54. * @return a Builder for this project and configuration
  55. */
  56. public static Builder getBuilder(String config, Project project, File tempDir) {
  57. boolean useEclipseCompiles = false;
  58. boolean verbose = false;
  59. if (null != config) {
  60. if (-1 != config.indexOf("useEclipseCompiles")) {
  61. useEclipseCompiles = true;
  62. }
  63. if (-1 != config.indexOf("verbose")) {
  64. verbose = true;
  65. }
  66. }
  67. // Messager handler = new Messager(); // debugging
  68. Messager handler = new ProjectMessager(project);
  69. Builder result = new ProductBuilder(project, tempDir, useEclipseCompiles, handler);
  70. if (verbose) {
  71. result.setVerbose(true);
  72. }
  73. return result;
  74. }
  75. private static String resultToTargetName(Result result) {
  76. return result.getName();
  77. }
  78. /**
  79. * Ensure targets exist for this module and all antecedants, so topoSort can work.
  80. */
  81. private static void makeTargetsForResult(final Result result, final Hashtable<String,Target> targets) {
  82. final String resultTargetName = resultToTargetName(result);
  83. Target target = targets.get(resultTargetName);
  84. if (null == target) {
  85. // first add the target
  86. target = new Target();
  87. target.setName(resultTargetName);
  88. Result[] reqs = result.getRequired();
  89. StringBuffer depends = new StringBuffer();
  90. boolean first = true;
  91. for (int i = 0; i < reqs.length; i++) {
  92. Result reqResult = reqs[i];
  93. if (!first) {
  94. depends.append(",");
  95. } else {
  96. first = false;
  97. }
  98. depends.append(resultToTargetName(reqResult));
  99. }
  100. if (0 < depends.length()) {
  101. target.setDepends(depends.toString());
  102. }
  103. targets.put(resultTargetName, target);
  104. // then recursively add any required results
  105. for (int i = 0; i < reqs.length; i++) {
  106. Result reqResult = reqs[i];
  107. makeTargetsForResult(reqResult, targets);
  108. }
  109. }
  110. }
  111. private final Project project;
  112. protected AntBuilder(Project project, File tempDir, boolean useEclipseCompiles, Messager handler) {
  113. super(tempDir, useEclipseCompiles, handler);
  114. this.project = project;
  115. Util.iaxIfNull(project, "project");
  116. }
  117. /**
  118. * Initialize task with project and "ajbuild-" + name as name. (Using bm- prefix distinguishes these tasks from tasks found in
  119. * the build script.)
  120. *
  121. * @param task the Task to initialize - not null
  122. * @param name the String name suffix for the task
  123. * @return true unless some error
  124. */
  125. protected boolean setupTask(Task task, String name) {
  126. task.setProject(project);
  127. task.setTaskName("ajbuild-" + name);
  128. return true;
  129. }
  130. /**
  131. * Copy file, optionally filtering. (Filters set in project.)
  132. *
  133. * @param fromFile the readable File source to copy
  134. * @param toFile the writable File destination file
  135. * @param boolean filter if true, enable filtering
  136. * @see org.aspectj.internal.tools.build.Builder#copyFile(File, File, boolean)
  137. */
  138. @Override
  139. protected boolean copyFile(File fromFile, File toFile, boolean filter) {
  140. Copy copy = makeCopyTask(filter);
  141. copy.setFile(fromFile);
  142. copy.setTofile(toFile);
  143. executeTask(copy);
  144. return true;
  145. }
  146. /**
  147. * (Filters set in project.)
  148. *
  149. * @see org.aspectj.internal.tools.ant.taskdefs.Builder#copyFiles(File, File, String, String, boolean)
  150. */
  151. @Override
  152. protected boolean copyFiles(File fromDir, File toDir, String includes, String excludes, boolean filter) {
  153. Copy copy = makeCopyTask(filter);
  154. copy.setTodir(toDir);
  155. FileSet fileset = new FileSet();
  156. fileset.setDir(fromDir);
  157. if (null != includes) {
  158. fileset.setIncludes(includes);
  159. }
  160. if (null != excludes) {
  161. fileset.setExcludes(excludes);
  162. }
  163. copy.addFileset(fileset);
  164. executeTask(copy);
  165. return false;
  166. }
  167. protected void copyFileset(File toDir, FileSet fileSet, boolean filter) {
  168. Copy copy = makeCopyTask(filter);
  169. copy.addFileset(fileSet);
  170. copy.setTodir(toDir);
  171. executeTask(copy);
  172. }
  173. /**
  174. * @param filter if FILTER_ON, use filters
  175. */
  176. protected Copy makeCopyTask(boolean filter) {
  177. Copy copy = new Copy();
  178. setupTask(copy, "copy");
  179. if (FILTER_ON == filter) {
  180. copy.setFiltering(true);
  181. }
  182. return copy;
  183. }
  184. protected void dumpMinFile(Result result, File classesDir, List<String> errors) {
  185. String name = result.getName() + "-empty";
  186. File minFile = new File(classesDir, name);
  187. FileWriter fw = null;
  188. try {
  189. fw = new FileWriter(minFile);
  190. fw.write(name);
  191. } catch (IOException e) {
  192. errors.add("IOException writing " + name + " to " + minFile + ": " + Util.renderException(e));
  193. } finally {
  194. Util.close(fw);
  195. }
  196. }
  197. @Override
  198. protected boolean compile(Result result, File classesDir, boolean useExistingClasses, List<String> errors) {
  199. if (!classesDir.exists() && !classesDir.mkdirs()) {
  200. errors.add("compile - unable to create " + classesDir);
  201. return false;
  202. }
  203. if (useExistingClasses) {
  204. return true;
  205. }
  206. // -- source paths
  207. Path path = new Path(project);
  208. boolean hasSourceDirectories = false;
  209. boolean isJava5Compile = false;
  210. boolean isJava8Compile = false;
  211. for (File file: result.getSrcDirs()) {
  212. path.createPathElement().setLocation(file);
  213. if (!isJava5Compile
  214. && (Util.Constants.JAVA5_SRC.equals(file.getName()) ||
  215. Util.Constants.JAVA5_TESTSRC.equals(file.getName()) ||
  216. new File(file.getParent(), ".isJava5").exists())) {
  217. isJava5Compile = true;
  218. }
  219. if (new File(file.getParent(),".isJava8").exists()) {
  220. isJava8Compile = true;
  221. }
  222. if (!hasSourceDirectories) {
  223. hasSourceDirectories = true;
  224. }
  225. }
  226. if (!hasSourceDirectories) {
  227. return true; // nothing to compile - ok
  228. }
  229. // XXX test whether build.compiler property takes effect automatically
  230. // I suspect it requires the proper adapter setup.
  231. Javac javac = new Javac();
  232. setupTask(javac, "javac");
  233. javac.setIncludeantruntime(false);
  234. javac.setDestdir(classesDir);
  235. javac.setSrcdir(path);
  236. javac.setVerbose(verbose);
  237. path = null;
  238. // -- classpath
  239. Path classpath = new Path(project);
  240. boolean hasLibraries = setupClasspath(result, classpath);
  241. if (hasLibraries && FORCE_FORK_FOR_LIBRARIES) {
  242. javac.setFork(true); // otherwise never releases library jars
  243. // can we build under 1.4, but fork javac 1.5 compile?
  244. }
  245. // also fork if using 1.5?
  246. // -- set output directory
  247. classpath.createPathElement().setLocation(classesDir);
  248. javac.setClasspath(classpath);
  249. // misc
  250. javac.setDebug(true);
  251. if (isJava8Compile) {
  252. javac.setSource("1.8");
  253. javac.setTarget("1.8");
  254. } else if (isJava5Compile) {
  255. // *cough*
  256. javac.setSource("1.6");
  257. javac.setTarget("1.6");
  258. } else {
  259. javac.setTarget("1.1"); // 1.1 class files - Javac in 1.4 uses 1.4
  260. javac.setSource("1.3");
  261. }
  262. // compile
  263. boolean passed = false;
  264. BuildException failure = null;
  265. try {
  266. passed = executeTask(AspectJSupport.wrapIfNeeded(result, javac));
  267. } catch (BuildException e) {
  268. failure = e;
  269. } catch (Error e) {
  270. failure = new BuildException(e);
  271. } catch (RuntimeException e) {
  272. failure = new BuildException(e);
  273. } finally {
  274. if (!passed) {
  275. String args = "" + Arrays.asList(javac.getCurrentCompilerArgs());
  276. if ("[]".equals(args)) {
  277. args = "{" + result.toLongString() + "}";
  278. }
  279. String m = "BuildException compiling " + result.toLongString() + args
  280. + (null == failure ? "" : ": " + Util.renderException(failure));
  281. // debuglog System.err.println(m);
  282. errors.add(m);
  283. }
  284. javac.init(); // be nice to let go of classpath libraries...
  285. }
  286. return passed;
  287. }
  288. public boolean setupClasspath(Result result, Path classpath) { // XXX fix test access
  289. boolean hasLibraries = false;
  290. // required libraries
  291. for (Iterator iter = result.getLibJars().iterator(); iter.hasNext();) {
  292. File file = (File) iter.next();
  293. classpath.createPathElement().setLocation(file);
  294. if (!hasLibraries) {
  295. hasLibraries = true;
  296. }
  297. }
  298. // Westodo Kind kind = result.getKind();
  299. Result[] reqs = result.getRequired();
  300. // required modules and their exported libraries
  301. for (int i = 0; i < reqs.length; i++) {
  302. Result requiredResult = reqs[i];
  303. classpath.createPathElement().setLocation(requiredResult.getOutputFile());
  304. if (!hasLibraries) {
  305. hasLibraries = true;
  306. }
  307. // also put on classpath libraries exported from required module
  308. // XXX exported modules not supported
  309. for (Iterator iterator = requiredResult.getExportedLibJars().iterator(); iterator.hasNext();) {
  310. classpath.createPathElement().setLocation((File) iterator.next());
  311. }
  312. }
  313. return hasLibraries;
  314. }
  315. /**
  316. * Merge classes directory and any merge jars into module jar with any specified manifest file. META-INF directories are
  317. * excluded.
  318. */
  319. @Override
  320. protected boolean assemble(Result result, File classesDir, List<String> errors) {
  321. if (!buildingEnabled) {
  322. return false;
  323. }
  324. if (!result.outOfDate()) {
  325. return true;
  326. }
  327. // ---- zip result up
  328. Zip zip = new Zip();
  329. setupTask(zip, "zip");
  330. zip.setDestFile(result.getOutputFile());
  331. ZipFileSet zipfileset = null;
  332. // -- merge any resources in any of the src directories
  333. for (Iterator iter = result.getSrcDirs().iterator(); iter.hasNext();) {
  334. File srcDir = (File) iter.next();
  335. zipfileset = new ZipFileSet();
  336. zipfileset.setProject(project);
  337. zipfileset.setDir(srcDir);
  338. zipfileset.setIncludes(RESOURCE_PATTERN);
  339. zip.addZipfileset(zipfileset);
  340. }
  341. final Module module = result.getModule();
  342. File metaInfDir = new File(classesDir, "META-INF");
  343. Util.deleteContents(metaInfDir);
  344. // -- manifest
  345. File manifest = new File(module.moduleDir, module.name + ".mf.txt"); // XXXFileLiteral
  346. if (Util.canReadFile(manifest)) {
  347. if (Util.canReadDir(metaInfDir) || metaInfDir.mkdirs()) {
  348. // Jar spec requires a MANIFEST.MF not a manifest.mf
  349. copyFile(manifest, new File(metaInfDir, "MANIFEST.MF"), FILTER_ON); // XXXFileLiteral
  350. } else {
  351. errors.add("have manifest, but unable to create " + metaInfDir);
  352. return false;
  353. }
  354. }
  355. zipfileset = new ZipFileSet();
  356. zipfileset.setProject(project);
  357. zipfileset.setDir(classesDir);
  358. zipfileset.setIncludes("**/*");
  359. zip.addZipfileset(zipfileset);
  360. File[] contents = classesDir.listFiles();
  361. if ((null == contents) || (0 == contents.length)) {
  362. // *something* to zip up
  363. dumpMinFile(result, classesDir, errors);
  364. }
  365. try {
  366. handler.log("assemble " + module + " in " + result.getOutputFile());
  367. return executeTask(zip)
  368. // zip returns true when it doesn't create zipfile
  369. // because there are no entries to add, so verify done
  370. && Util.canReadFile(result.getOutputFile());
  371. } catch (BuildException e) {
  372. errors.add("BuildException zipping " + module + ": " + e.getMessage());
  373. return false;
  374. } finally {
  375. result.clearOutOfDate();
  376. }
  377. }
  378. /**
  379. * @see org.aspectj.internal.tools.build.Builder#buildAntecedants(Module)
  380. */
  381. @Override
  382. protected Result[] getAntecedantResults(Result moduleResult) {
  383. Hashtable<String,Target> targets = new Hashtable<String, Target>();
  384. makeTargetsForResult(moduleResult, targets);
  385. String targetName = resultToTargetName(moduleResult);
  386. // bug: doc says topoSort returns String, but returns Target
  387. Collection<Target> result = project.topoSort(targetName, targets);
  388. // fyi, we don't rely on topoSort to detect cycles - see buildAll
  389. int size = result.size();
  390. if (0 == result.size()) {
  391. return new Result[0];
  392. }
  393. ArrayList<String> toReturn = new ArrayList<String>();
  394. for (Iterator<Target> iter = result.iterator(); iter.hasNext();) {
  395. Target target = iter.next();
  396. String name = target.getName();
  397. if (null == name) {
  398. throw new Error("null name?");
  399. } else {
  400. toReturn.add(name);
  401. }
  402. }
  403. // topoSort always returns target name
  404. if ((1 == size) && targetName.equals(toReturn.get(0)) && !moduleResult.outOfDate()) {
  405. return new Result[0];
  406. }
  407. return Result.getResults(toReturn.toArray(new String[0]));
  408. }
  409. /**
  410. * Generate Module.assembledJar with merge of itself and all antecedants
  411. */
  412. @Override
  413. protected boolean assembleAll(Result result, Messager handler) {
  414. if (!buildingEnabled) {
  415. return false;
  416. }
  417. if (!result.outOfDate()) {
  418. return true;
  419. }
  420. Util.iaxIfNull(result, "result");
  421. Util.iaxIfNull(handler, "handler");
  422. if (!result.getKind().isAssembly()) {
  423. throw new IllegalStateException("not assembly: " + result);
  424. }
  425. // ---- zip result up
  426. Zip zip = new Zip();
  427. setupTask(zip, "zip");
  428. zip.setDestFile(result.getOutputFile());
  429. ZipFileSet zipfileset = null;
  430. final Module module = result.getModule();
  431. List<File> known = result.findJarRequirements();
  432. removeLibraryFilesToSkip(module, known);
  433. // -- merge any antecedents, less any manifest
  434. for (File jarFile: known) {
  435. zipfileset = new ZipFileSet();
  436. zipfileset.setProject(project);
  437. zipfileset.setSrc(jarFile);
  438. zipfileset.setIncludes("**/*");
  439. String name = jarFile.getName();
  440. name = name.substring(0, name.length() - 4); // ".jar".length()
  441. // required includes self - exclude manifest from others
  442. if (!module.name.equals(name)) {
  443. zipfileset.setExcludes("META-INF/MANIFEST.MF"); // XXXFileLiteral
  444. zipfileset.setExcludes("META-INF/manifest.mf");
  445. zipfileset.setExcludes("meta-inf/manifest.mf");
  446. zipfileset.setExcludes("meta-inf/MANIFEST.MF");
  447. }
  448. zip.addZipfileset(zipfileset);
  449. }
  450. try {
  451. handler.log("assembling all " + module + " in " + result.getOutputFile());
  452. if (verbose) {
  453. handler.log("knownAntecedants: " + known);
  454. }
  455. return executeTask(zip);
  456. } catch (BuildException e) {
  457. handler.logException("BuildException zipping " + module, e);
  458. return false;
  459. } finally {
  460. result.clearOutOfDate();
  461. }
  462. }
  463. /**
  464. * @see org.aspectj.internal.tools.ant.taskdefs.Builder#buildInstaller(BuildSpec, String)
  465. */
  466. @Override
  467. protected boolean buildInstaller(BuildSpec buildSpec, String targDirPath) {
  468. return false;
  469. }
  470. /** task.execute() and any advice */
  471. protected boolean executeTask(Task task) {
  472. if (!buildingEnabled) {
  473. return false;
  474. }
  475. task.execute();
  476. return true;
  477. }
  478. /**
  479. * Support for compiling basic AspectJ projects. Projects may only compile all (and only) their source directories; aspectpath,
  480. * inpath, etc. are not supported. To load the compiler, this assumes the user has either defined a project property
  481. * "aspectj.home" or that there exists <code>{module-dir}/lib/aspectj/lib/aspectj[tools|rt].jar</code>.
  482. */
  483. static class AspectJSupport {
  484. static final String AJCTASK = "org.aspectj.tools.ant.taskdefs.AjcTask";
  485. static final String ASPECTJRT_JAR_VARIABLE = "ASPECTJRT_LIB";
  486. static final String LIBASPECTJ_RPATH = "/lib/aspectj";
  487. static final Map nameToAspectjrtjar = new HashMap();
  488. static final String NONE = "NONE";
  489. /**
  490. * If this module should be compiled with AspectJ, return a task to do so.
  491. *
  492. * @param module the Module to compile
  493. * @param javac the Javac compile commands
  494. * @return javac or a Task to compile with AspectJ if needed
  495. */
  496. static Task wrapIfNeeded(Result result, Javac javac) {
  497. final Project project = javac.getProject();
  498. Path runtimeJar = null;
  499. final Module module = result.getModule();
  500. if (runtimeJarOnClasspath(result)) {
  501. // yes aspectjrt.jar on classpath
  502. } else if (result.getClasspathVariables().contains(ASPECTJRT_JAR_VARIABLE)) {
  503. // yes, in variables - find aspectjrt.jar to add to classpath
  504. runtimeJar = getAspectJLib(project, module, "aspectjrt.jar");
  505. } else {
  506. // no
  507. // System.out.println("javac " + result + " " + javac.getClasspath());
  508. return javac;
  509. }
  510. // System.out.println("aspectj " + result + " " + javac.getClasspath());
  511. Path aspectjtoolsJar = getAspectJLib(project, module, "aspectjtools.jar");
  512. return aspectJTask(javac, aspectjtoolsJar, runtimeJar);
  513. }
  514. /** @return true if aspectjrt.jar is on classpath */
  515. private static boolean runtimeJarOnClasspath(Result result) {
  516. for (File file: result.getLibJars()) {
  517. if ("aspectjrt.jar".equals(file.getName())) {
  518. return true;
  519. }
  520. }
  521. return false;
  522. }
  523. static Path getAspectJLib(Project project, Module module, String name) {
  524. Path result = null;
  525. String[] libDirNames = { "aspectj.home", "ASPECTJ_HOME", LIBASPECTJ_RPATH };
  526. String[] libDirs = new String[libDirNames.length];
  527. for (int i = 0; i < libDirNames.length; i++) {
  528. if (LIBASPECTJ_RPATH == libDirNames[i]) {
  529. libDirs[i] = module.getFullPath(LIBASPECTJ_RPATH);
  530. } else {
  531. libDirs[i] = project.getProperty(libDirNames[i]);
  532. }
  533. if (null != libDirs[i]) {
  534. libDirs[i] = Util.path(libDirs[i], "lib");
  535. result = new Path(project, Util.path(libDirs[i], name));
  536. String path = result.toString();
  537. if (new File(path).canRead()) {
  538. return result;
  539. }
  540. }
  541. }
  542. String m = "unable to find " + name + " in " + Arrays.asList(libDirs);
  543. throw new BuildException(m);
  544. }
  545. /**
  546. * Wrap AspectJ compiler as Task. Only works for javac-like source compilation of everything under srcDir. Written
  547. * reflectively to compile in the build module, which can't depend on the whole tree.
  548. *
  549. * @param javac the Javac specification
  550. * @param toolsJar the Path to the aspectjtools.jar
  551. * @param runtimeJar the Path to the aspectjrt.jar
  552. * @return javac or another Task invoking the AspectJ compiler
  553. */
  554. @SuppressWarnings("unchecked")
  555. static Task aspectJTask(Javac javac, Path toolsJar, Path runtimeJar) {
  556. Object task = null;
  557. String url = null;
  558. try {
  559. url = "file:" + toolsJar.toString().replace('\\', '/');
  560. URL[] cp = new URL[] { new URL(url) };
  561. ClassLoader parent = Task.class.getClassLoader();
  562. ClassLoader loader = new URLClassLoader(cp, parent);
  563. Class c = loader.loadClass(AJCTASK);
  564. task = c.newInstance();
  565. // Westodo Project project = javac.getProject();
  566. Method m = c.getMethod("setupAjc", new Class[] { Javac.class });
  567. m.invoke(task, new Object[] { javac });
  568. m = c.getMethod("setFork", new Class[] { boolean.class });
  569. m.invoke(task, new Object[] { Boolean.TRUE });
  570. m = c.getMethod("setForkclasspath", new Class[] { Path.class });
  571. m.invoke(task, new Object[] { toolsJar });
  572. m = c.getMethod("setSourceRoots", new Class[] { Path.class });
  573. m.invoke(task, new Object[] { javac.getSrcdir() });
  574. if (null != runtimeJar) {
  575. m = c.getMethod("setClasspath", new Class[] { Path.class });
  576. m.invoke(task, new Object[] { runtimeJar });
  577. }
  578. } catch (BuildException e) {
  579. throw e;
  580. } catch (Throwable t) {
  581. StringBuffer sb = new StringBuffer();
  582. sb.append("classpath=");
  583. sb.append(url);
  584. throw new BuildException(sb.toString(), t);
  585. }
  586. return (Task) task;
  587. }
  588. private AspectJSupport() {
  589. throw new Error("no instances");
  590. }
  591. }
  592. }
  593. // finally caught by failing to comply with proper ant initialization
  594. // /**
  595. // * Build a module that has a build script.
  596. // * @param buildSpec the module to build
  597. // * @param buildScript the script file
  598. // * @throws BuildException if build fails
  599. // */
  600. // private void buildByScript(BuildSpec buildSpec, File buildScript)
  601. // throws BuildException {
  602. // Ant ant = new Ant();
  603. // ant.setProject(getProject());
  604. // ant.setAntfile(buildScript.getAbsolutePath());
  605. // ant.setDescription("building module " + buildSpec.module);
  606. // ant.setDir(buildScript.getParentFile());
  607. // ant.setInheritAll(true);
  608. // ant.setInheritRefs(false);
  609. // ant.setLocation(getLocation());
  610. // ant.setOwningTarget(getOwningTarget());
  611. // // by convention, for build.xml, use module name to publish
  612. // ant.setTarget(buildSpec.module);
  613. // ant.setTaskName("ant");
  614. // loadAntProperties(ant, buildSpec);
  615. // ant.execute();
  616. // }
  617. //
  618. // /** override definitions */
  619. // private void loadAntProperties(Ant ant, BuildSpec buildSpec) {
  620. // Property property = ant.createProperty();
  621. // property.setName(BuildSpec.baseDir_NAME);
  622. // property.setFile(buildSpec.baseDir);
  623. // property = ant.createProperty();
  624. // property.setName(buildSpec.distDir_NAME);
  625. // property.setFile(buildSpec.distDir);
  626. // property = ant.createProperty();
  627. // property.setName(BuildSpec.tempDir_NAME);
  628. // property.setFile(buildSpec.tempDir);
  629. // property = ant.createProperty();
  630. // property.setName(BuildSpec.jarDir_NAME);
  631. // property.setFile(buildSpec.jarDir);
  632. // property = ant.createProperty();
  633. // property.setName(BuildSpec.stagingDir_NAME);
  634. // property.setFile(buildSpec.stagingDir);
  635. // }
  636. /**
  637. * Segregate product-building API's from module-building APIs for clarity. These are called by the superclass if the BuildSpec
  638. * warrants. XXX extremely brittle/arbitrary assumptions.
  639. *
  640. * @see BuildModule for assumptions
  641. */
  642. class ProductBuilder extends AntBuilder {
  643. private static String getProductInstallResourcesSrc(BuildSpec buildSpec) {
  644. final String resourcesName = "installer-resources"; // XXXFileLiteral
  645. File dir = buildSpec.productDir.getParentFile();
  646. if (null == dir) {
  647. return Util.path(new String[] { "..", "..", resourcesName });
  648. }
  649. dir = dir.getParentFile();
  650. if (null == dir) {
  651. return Util.path("..", resourcesName);
  652. } else {
  653. dir = new File(dir, resourcesName);
  654. return dir.getPath();
  655. }
  656. }
  657. private static String getProductInstallerFileName(BuildSpec buildSpec) { // XXXFileLiteral
  658. return "aspectj-" + buildSpec.productDir.getName() + "-" + Util.shortVersion(buildSpec.version) + ".jar";
  659. }
  660. /**
  661. * Calculate name of main, typically InitialCap, and hence installer class.
  662. *
  663. * @return $$installer$$.org.aspectj." + ProductName + "Installer"
  664. */
  665. private static String getProductInstallerMainClass(BuildSpec buildSpec) {
  666. String productName = buildSpec.productDir.getName();
  667. String initial = productName.substring(0, 1).toUpperCase();
  668. productName = initial + productName.substring(1);
  669. return "$installer$.org.aspectj." + productName + "Installer"; // XXXNameLiteral
  670. }
  671. /** @see Builder.getBuilder(String, Project, File) */
  672. ProductBuilder(Project project, File tempDir, boolean useEclipseCompiles, Messager handler) {
  673. super(project, tempDir, useEclipseCompiles, handler);
  674. }
  675. /**
  676. * Delegate for super.buildProduct(..) template method.
  677. */
  678. @Override
  679. protected boolean copyBinaries(BuildSpec buildSpec, File distDir, File targDir, String excludes) {
  680. Copy copy = makeCopyTask(false);
  681. copy.setTodir(targDir);
  682. FileSet fileset = new FileSet();
  683. fileset.setDir(distDir);
  684. fileset.setIncludes(Builder.BINARY_SOURCE_PATTERN);
  685. if (null != excludes) {
  686. fileset.setExcludes(excludes);
  687. }
  688. copy.addFileset(fileset);
  689. return executeTask(copy);
  690. }
  691. /**
  692. * Delegate for super.buildProduct(..) template method.
  693. */
  694. @Override
  695. protected boolean copyNonBinaries(BuildSpec buildSpec, File distDir, File targDir) {
  696. // filter-copy everything but the binaries
  697. Copy copy = makeCopyTask(true);
  698. copy.setTodir(targDir);
  699. Util.iaxIfNotCanReadDir(distDir, "product dist directory");
  700. FileSet fileset = new FileSet();
  701. fileset.setDir(distDir);
  702. fileset.setExcludes(Builder.BINARY_SOURCE_PATTERN);
  703. copy.addFileset(fileset);
  704. return executeTask(copy);
  705. }
  706. @Override
  707. protected boolean buildInstaller(BuildSpec buildSpec, String targDirPath) {
  708. if (buildSpec.verbose) {
  709. handler.log("creating installer for " + buildSpec);
  710. }
  711. AJInstaller installer = new AJInstaller();
  712. setupTask(installer, "installer");
  713. installer.setBasedir(targDirPath);
  714. // installer.setCompress();
  715. File installSrcDir = new File(buildSpec.productDir, "install"); // XXXFileLiteral
  716. Util.iaxIfNotCanReadDir(installSrcDir, "installSrcDir");
  717. installer.setHtmlSrc(installSrcDir.getPath());
  718. String resourcePath = getProductInstallResourcesSrc(buildSpec);
  719. File resourceSrcDir = new File(resourcePath);
  720. Util.iaxIfNotCanReadDir(resourceSrcDir, "resourceSrcDir");
  721. installer.setResourcesSrc(resourcePath);
  722. String name = getProductInstallerFileName(buildSpec);
  723. File outFile = new File(buildSpec.jarDir, name);
  724. installer.setZipfile(outFile.getPath());
  725. installer.setMainclass(getProductInstallerMainClass(buildSpec));
  726. installer.setInstallerclassjar(getBuildJar(buildSpec));
  727. return executeTask(installer);
  728. // -- test installer XXX
  729. // create text setup file
  730. // run installer with setup file
  731. // cleanup installed product
  732. }
  733. private String getBuildJar(BuildSpec buildSpec) {
  734. return buildSpec.baseDir.getPath() + "/lib/build/build.jar"; // XXX
  735. }
  736. // private Module moduleForReplaceFile(File replaceFile, Modules modules) {
  737. // String jarName = moduleAliasFor(replaceFile.getName().toLowerCase());
  738. // if (jarName.endsWith(".jar") || jarName.endsWith(".zip")) { // XXXFileLiteral
  739. // jarName = jarName.substring(0, jarName.length()-4);
  740. // } else {
  741. // throw new IllegalArgumentException("can only replace .[jar|zip]");
  742. // }
  743. // boolean assembleAll = jarName.endsWith("-all");
  744. // String name = (!assembleAll ? jarName : jarName.substring(0, jarName.length()-4));
  745. // return modules.getModule(name);
  746. // }
  747. //
  748. }
  749. class ProjectMessager extends Messager {
  750. private final Project project;
  751. public ProjectMessager(Project project) {
  752. Util.iaxIfNull(project, "project");
  753. this.project = project;
  754. }
  755. @Override
  756. public boolean log(String s) {
  757. project.log(s);
  758. return true;
  759. }
  760. @Override
  761. public boolean error(String s) {
  762. project.log(s, Project.MSG_ERR);
  763. return true;
  764. }
  765. @Override
  766. public boolean logException(String context, Throwable thrown) {
  767. project.log(context + Util.renderException(thrown), Project.MSG_ERR);
  768. return true;
  769. }
  770. }