PageRenderTime 49ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/net/sourceforge/jarbundler/JarBundler.java

#
Java | 1480 lines | 713 code | 302 blank | 465 comment | 129 complexity | bedc7a7266063cda3d3cda1a7edc220a MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * A Mac OS X Jar Bundler Ant Task.
  3. *
  4. * Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the Free
  8. * Software Foundation; either version 2 of the License, or (at your option)
  9. * any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. * more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along with
  17. * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  18. * Place - Suite 330, Boston, MA 02111-1307, USA.
  19. */
  20. package net.sourceforge.jarbundler;
  21. // This package's imports
  22. import net.sourceforge.jarbundler.AppBundleProperties;
  23. import net.sourceforge.jarbundler.DocumentType;
  24. import net.sourceforge.jarbundler.JavaProperty;
  25. import net.sourceforge.jarbundler.PropertyListWriter;
  26. // Java I/O
  27. import java.io.BufferedWriter;
  28. import java.io.BufferedReader;
  29. import java.io.File;
  30. import java.io.FileWriter;
  31. import java.io.FileReader;
  32. import java.io.IOException;
  33. import java.io.InputStream;
  34. import java.io.PrintWriter;
  35. // Java Utility
  36. import java.util.ArrayList;
  37. import java.util.HashSet;
  38. import java.util.Iterator;
  39. import java.util.List;
  40. import java.util.Set;
  41. // Apache Jakarta
  42. import org.apache.tools.ant.BuildException;
  43. import org.apache.tools.ant.FileScanner;
  44. import org.apache.tools.ant.Project;
  45. import org.apache.tools.ant.Task;
  46. import org.apache.tools.ant.types.FileList;
  47. import org.apache.tools.ant.types.FileSet;
  48. import org.apache.tools.ant.types.PatternSet;
  49. import org.apache.tools.ant.taskdefs.MatchingTask;
  50. import org.apache.tools.ant.taskdefs.Chmod;
  51. import org.apache.tools.ant.taskdefs.Delete;
  52. import org.apache.tools.ant.util.FileUtils;
  53. // Java language imports
  54. import java.lang.Boolean;
  55. import java.lang.Process;
  56. import java.lang.Runtime;
  57. import java.lang.String;
  58. import java.lang.System;
  59. /**
  60. * <p>
  61. * An ant task which creates a Mac OS X Application Bundle for a Java
  62. * application.
  63. * </p>
  64. *
  65. * <dl>
  66. * <dt>dir</dt>
  67. * <dd>The directory into which to put the new application bundle.</dd>
  68. * <dt>name</dt>
  69. * <dd>The name of the application bundle. Note that the maximum length of this
  70. * name is 16 characters, and it will be silently cropped if it is longer than
  71. * this.</dd>
  72. * <dt>mainclass</dt>
  73. * <dd>The main Java class to call when running the application.</dd>
  74. * </dl>
  75. *
  76. * <p>
  77. * One of the following three MUST be used:
  78. *
  79. * <ol>
  80. * <li>jars Space or comma-separated list of JAR files to include.; OR</li>
  81. * <li>One or more nested &lt;jarfileset&gt;s. These are normal ANT FileSets;
  82. * OR </li>
  83. * <li>One or more nested &lt;jarfilelist&gt;s. These are standard ANT
  84. * FileLists. </li>
  85. * </ol>
  86. *
  87. * <p>
  88. * Optional attributes:
  89. *
  90. * <p>
  91. * The following attributes are not required, but you can use them to override
  92. * default behavior.
  93. *
  94. * <dl>
  95. * <dt>verbose
  96. * <dd>If true, show more verbose output while running the task
  97. *
  98. * <dt>version
  99. * <dd>Version information about your application (e.g., "1.0")
  100. *
  101. * <dt>infostring
  102. * <dd>String to show in the "Get Info" dialog
  103. * </dl>
  104. *
  105. * These attributes control the fine-tuning of the "Mac OS X" look and feel.
  106. *
  107. * <dl>
  108. * <dt>arguments
  109. * <dd>Command line arguments. (no default)
  110. *
  111. * <dt>smalltabs
  112. * <dd>Use small tabs. (default "false") Deprecated under JVM 1.4.1
  113. *
  114. * <dt>antialiasedgraphics
  115. * <dd>Use anti-aliased graphics (default "false")
  116. *
  117. * <dt>antialiasedtext
  118. * <dd>Use anti-aliased text (default "false")
  119. *
  120. * <dt>bundleid
  121. * <dd>Unique identifier for this bundle, in the form of a Java package. No
  122. * default.
  123. *
  124. * <dt>buildnumber
  125. * <dd>Unique identifier for this build
  126. *
  127. * <dt>developmentregion
  128. * <dd>Development Region. Default "English".
  129. *
  130. * <dt>execs
  131. * <dd>Files to be copied into "Resources/MacOS" and made executable
  132. *
  133. * <dt>liveresize
  134. * <dd>Use "Live resizing" (default "false") Deprecated under JVM 1.4.1
  135. *
  136. *
  137. * <dt>growbox
  138. * <dd>Show growbox (default "true")
  139. *
  140. * <dt>growboxintrudes
  141. * <dd>Intruding growbox (default "false") Deprecated under JVM 1.4.1
  142. *
  143. * <dt>screenmenu
  144. * <dd>Put swing menu into Mac OS X menu bar.
  145. *
  146. * <dt>type
  147. * <dd>Bundle type (default "APPL")
  148. *
  149. * <dt>signature
  150. * <dd>Bundle Signature (default "????")
  151. *
  152. * <dt>stubfile
  153. * <dd>The Java Application Stub file to copy for your application (default
  154. * MacOS system stub file)
  155. * </dl>
  156. *
  157. * <p>
  158. * Rarely used optional attributes.
  159. * <dl>
  160. * <dt>chmod
  161. * <dd>Full path to the chmod command. This almost certainly does NOT need to
  162. * be set.
  163. * </dl>
  164. *
  165. * <p>
  166. * The task also supports nested &lt;execfileset&gt; and/or &lt;execfilelist&gt;
  167. * elements, and &lt;resourcefileset&gt; and/or &lt;resourcefilelist&gt;
  168. * elements, which are standard Ant FileSet and FileList elements. In the first
  169. * case, the referenced files are copied to the <code>Contents/MacOS</code>
  170. * directory and made executable, and in the second they are copied to the
  171. * <code>Contents/Resources</code> directory and not made executable. If you
  172. * winrces, note that in fact the files are installed in locations which have
  173. * the same relation to the <code>Contents/Resources</code> directory as the
  174. * files in the FileSet or FileList have to the 'dir' attribute. Thus in the
  175. * case:
  176. *
  177. * <pre>
  178. * &lt;resourcefileset dir=&quot;builddir/architectures&quot;
  179. * includes=&quot;ppc/*.jnilib&quot;/&gt;
  180. * </pre>
  181. *
  182. * <p>
  183. * the <code>*.jnilib</code> files will be installed in
  184. * <code>Contents/Resources/ppc</code>.
  185. *
  186. * <p>
  187. * The task supports a nested &lt;javaproperty&gt; element, which allows you to
  188. * specify further properties which are set for the JVM when the application is
  189. * launched. This takes a required <code>key</code> attribute, giving the
  190. * property key, plus an attribute giving the property value, which may be one
  191. * of <code>value</code>, giving the string value of the property,
  192. * <code>file</code>, setting the value of the property to be the absolute
  193. * path of the given file, or <code>path</code>, which sets the value to the
  194. * given path. If you are setting paths here, recall that, within the bundle,
  195. * <code>$APP_PACKAGE</code> is set to the root directory of the bundle (ie,
  196. * the path to the <code>foo.app</code> directory), and <code>$JAVAROOT</code>
  197. * to the directory <code>Contents/Resources/Java</code>.
  198. *
  199. * <p>
  200. * Minimum example:
  201. *
  202. * <pre>
  203. *
  204. * &lt;jarbundler dir=&quot;release&quot; name=&quot;Bar Project&quot; mainclass=&quot;org.bar.Main&quot;
  205. * jars=&quot;bin/Bar.jar&quot; /&gt;
  206. * </pre>
  207. *
  208. * <p>
  209. * Using Filesets
  210. *
  211. * <pre>
  212. * &lt;jarbundler dir=&quot;release&quot; name=&quot;Bar Project&quot; mainclass=&quot;org.bar.Main&quot;&gt;
  213. * &lt;jarfileset dir=&quot;bin&quot;&gt;
  214. * &lt;include name=&quot;*.jar&quot; /&gt;
  215. * &lt;exclude name=&quot;test.jar&quot; /&gt;
  216. * &lt;/jarfileset&gt;
  217. * &lt;execfileset dir=&quot;execs&quot;&gt;
  218. * &lt;include name=&quot;**&quot; /&gt;
  219. * &lt;/execfileset&gt;
  220. * &lt;/jarbundler&gt;
  221. * </pre>
  222. *
  223. * <p>
  224. * Much Longer example:
  225. * </p>
  226. *
  227. * <pre>
  228. * &lt;jarbundler dir=&quot;release&quot;
  229. * name=&quot;Foo Project&quot;
  230. * mainclass=&quot;org.bar.Main&quot;
  231. * version=&quot;1.0 b 1&quot;
  232. * infostring=&quot;Foo Project (c) 2002&quot;
  233. * type=&quot;APPL&quot;
  234. * jars=&quot;bin/foo.jar bin/bar.jar&quot;
  235. * execs=&quot;exec/foobar&quot;
  236. * signature=&quot;????&quot;
  237. * workingdirectory=&quot;temp&quot;
  238. * icon=&quot;resources/foo.icns&quot;
  239. * jvmversion=&quot;1.4.1+&quot;
  240. * vmoptions=&quot;-Xmx256m&quot;/&gt;
  241. * </pre>
  242. *
  243. * http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/
  244. */
  245. public class JarBundler extends MatchingTask {
  246. private static final String DEFAULT_STUB = "/System/Library/Frameworks/JavaVM.framework/Versions/Current/Resources/MacOS/JavaApplicationStub";
  247. private static final String ABOUTMENU_KEY = "com.apple.mrj.application.apple.menu.about.name";
  248. private static final Set menuItems = new HashSet();
  249. private File mAppIcon;
  250. private File mRootDir;
  251. private final List mJavaFileLists = new ArrayList();
  252. private final List mJarFileSets = new ArrayList();
  253. private final List mExecFileLists = new ArrayList();
  254. private final List mExecFileSets = new ArrayList();
  255. private final List mResourceFileLists = new ArrayList();
  256. private final List mResourceFileSets = new ArrayList();
  257. private final List mJarFileLists = new ArrayList();
  258. private final List mJavaFileSets = new ArrayList();
  259. private final List mExtraClassPathFileLists = new ArrayList();
  260. private final List mExtraClassPathFileSets = new ArrayList();
  261. private final List mJarAttrs = new ArrayList();
  262. private final List mExecAttrs = new ArrayList();
  263. private final List mExtraClassPathAttrs = new ArrayList();
  264. private final List mHelpBooks = new ArrayList();
  265. private boolean mVerbose = false;
  266. private boolean mShowPlist = false;
  267. // Java properties used by Mac OS X Java applications
  268. private File mStubFile = new File(DEFAULT_STUB);
  269. private Boolean mAntiAliasedGraphics = null;
  270. private Boolean mAntiAliasedText = null;
  271. private Boolean mLiveResize = null;
  272. private Boolean mScreenMenuBar = null;
  273. private Boolean mGrowbox = null;
  274. private Boolean mGrowboxIntrudes = null;
  275. // The root of the application bundle
  276. private File bundleDir;
  277. // "Contents" directory
  278. private File mContentsDir;
  279. // "Contents/MacOS" directory
  280. private File mMacOsDir;
  281. // "Contents/Resources" directory
  282. private File mResourcesDir;
  283. // "Contents/Resources/Java" directory
  284. private File mJavaDir;
  285. // Full path to the 'chmod' command. Can be overridden
  286. // with the 'chmod' attribute. Won't cause any harm if
  287. // not set, or if this executable doesn't exist.
  288. private AppBundleProperties bundleProperties = new AppBundleProperties();
  289. // Ant file utilities
  290. private FileUtils mFileUtils = FileUtils.getFileUtils();
  291. /***************************************************************************
  292. * Retreive task attributes
  293. **************************************************************************/
  294. /**
  295. * Arguments to the
  296. *
  297. * @param s
  298. * The arguments to pass to the application being launched.
  299. */
  300. public void setArguments(String s) {
  301. bundleProperties.setArguments(s);
  302. }
  303. /**
  304. * Override the stub file path to build on non-MacOS platforms
  305. *
  306. * @param file
  307. * the path to the stub file
  308. */
  309. public void setStubFile(File file) {
  310. mStubFile = (file.exists()) ? file : new File(DEFAULT_STUB);
  311. bundleProperties.setCFBundleExecutable(file.getName());
  312. }
  313. /**
  314. * Setter for the "dir" attribute (required)
  315. */
  316. public void setDir(File f) {
  317. mRootDir = f;
  318. }
  319. /**
  320. * Setter for the "name" attribute (required) This attribute names the
  321. * output application bundle and asks as the CFBundleName if 'bundlename' is
  322. * not specified
  323. */
  324. public void setName(String s) {
  325. bundleProperties.setApplicationName(s);
  326. }
  327. /**
  328. * Setter for the "shortname" attribute (optional) This key identifies the
  329. * short name of the bundle. This name should be less than 16 characters
  330. * long and be suitable for displaying in the menu and the About box. The
  331. * name is (silently) cropped to this if necessary.
  332. */
  333. public void setShortName(String s) {
  334. bundleProperties.setCFBundleName(s);
  335. }
  336. /**
  337. * Setter for the "mainclass" attribute (required)
  338. */
  339. public void setMainClass(String s) {
  340. bundleProperties.setMainClass(s);
  341. }
  342. /**
  343. * Setter for the "WorkingDirectory" attribute (optional)
  344. */
  345. public void setWorkingDirectory(String s) {
  346. bundleProperties.setWorkingDirectory(s);
  347. }
  348. /**
  349. * Setter for the "icon" attribute (optional)
  350. */
  351. public void setIcon(File f) {
  352. mAppIcon = f;
  353. bundleProperties.setCFBundleIconFile(f.getName());
  354. }
  355. /**
  356. * Setter for the "bundleid" attribute (optional) This key specifies a
  357. * unique identifier string for the bundle. This identifier should be in the
  358. * form of a Java-style package name, for example com.mycompany.myapp. The
  359. * bundle identifier can be used to locate the bundle at runtime. The
  360. * preferences system uses this string to identify applications uniquely.
  361. *
  362. * No default.
  363. */
  364. public void setBundleid(String s) {
  365. bundleProperties.setCFBundleIdentifier(s);
  366. }
  367. /**
  368. * Setter for the "developmentregion" attribute(optional) Default "English".
  369. */
  370. public void setDevelopmentregion(String s) {
  371. bundleProperties.setCFBundleDevelopmentRegion(s);
  372. }
  373. /**
  374. * Setter for the "aboutmenuname" attribute (optional)
  375. */
  376. public void setAboutmenuname(String s) {
  377. bundleProperties.setCFBundleName(s);
  378. }
  379. /**
  380. * Setter for the "smalltabs" attribute (optional)
  381. */
  382. public void setSmallTabs(boolean b) {
  383. bundleProperties.addJavaProperty("com.apple.smallTabs", new Boolean(b)
  384. .toString());
  385. }
  386. /**
  387. * Setter for the "vmoptions" attribute (optional)
  388. */
  389. public void setVmoptions(String s) {
  390. bundleProperties.setVMOptions(s);
  391. }
  392. /**
  393. * Setter for the "antialiasedgraphics" attribute (optional)
  394. */
  395. public void setAntialiasedgraphics(boolean b) {
  396. mAntiAliasedGraphics = new Boolean(b);
  397. }
  398. /**
  399. * Setter for the "antialiasedtext" attribute (optional)
  400. */
  401. public void setAntialiasedtext(boolean b) {
  402. mAntiAliasedText = new Boolean(b);
  403. }
  404. /**
  405. * Setter for the "screenmenu" attribute (optional)
  406. */
  407. public void setScreenmenu(boolean b) {
  408. mScreenMenuBar = new Boolean(b);
  409. }
  410. /**
  411. * Setter for the "growbox" attribute (optional)
  412. */
  413. public void setGrowbox(boolean b) {
  414. mGrowbox = new Boolean(b);
  415. }
  416. /**
  417. * Setter for the "growboxintrudes" attribute (optional)
  418. */
  419. public void setGrowboxintrudes(boolean b) {
  420. mGrowboxIntrudes = new Boolean(b);
  421. }
  422. /**
  423. * Setter for the "liveresize" attribute (optional)
  424. */
  425. public void setLiveresize(boolean b) {
  426. mLiveResize = new Boolean(b);
  427. }
  428. /**
  429. * Setter for the "type" attribute (optional)
  430. */
  431. public void setType(String s) {
  432. bundleProperties.setCFBundlePackageType(s);
  433. }
  434. /**
  435. * Setter for the "signature" attribute (optional)
  436. */
  437. public void setSignature(String s) {
  438. bundleProperties.setCFBundleSignature(s);
  439. }
  440. /**
  441. * Setter for the "jvmversion" attribute (optional)
  442. */
  443. public void setJvmversion(String s) {
  444. bundleProperties.setJVMVersion(s);
  445. }
  446. /**
  447. * Setter for the "infostring" attribute (optional) This key identifies a
  448. * human-readable plain text string displaying the copyright information for
  449. * the bundle. The Finder displays this information in the Info window of
  450. * the bundle. (This string was also known as the long version string in Mac
  451. * OS 9). The format of the key should be of the following format: "&copy;
  452. * Great Software, Inc, 1999". You can localize this string by including it
  453. * in the InfoPlist.strings file of the appropriate .lproj directory.
  454. */
  455. public void setInfoString(String s) {
  456. bundleProperties.setCFBundleGetInfoString(s);
  457. }
  458. /**
  459. * Setter for the "shortinfostring" attribute (optional) This key identifies
  460. * the marketing version of the bundle. The marketing version is a string
  461. * that usually displays the major and minor version of the bundle. This
  462. * string is usually of the form n.n.n where n is a number. The first number
  463. * is the major version number of the bundle. The second and third numbers
  464. * are minor revision numbers. You may omit minor revision numbers as
  465. * appropriate. The value of this key is displayed in the default About box
  466. * for Cocoa applications.
  467. *
  468. * The value for this key differs from the value for "CFBundleVersion",
  469. * which identifies a specific build number. The CFBundleShortVersionString
  470. * value represents a more formal version that does not change with every
  471. * build.
  472. */
  473. public void setShortInfoString(String s) {
  474. setVersion(s);
  475. }
  476. /**
  477. * Setter for the "verbose" attribute (optional)
  478. */
  479. public void setVerbose(boolean verbose) {
  480. this.mVerbose = verbose;
  481. }
  482. public void setShowPlist(boolean showPlist) {
  483. this.mShowPlist = showPlist;
  484. }
  485. /**
  486. * Setter for the "buildnumber" attribute (optional) This key specifies the
  487. * exact build version of the bundle. This string is usually of the form
  488. * nn.n.nxnnn where n is a digit and x is a character from the set [abdf].
  489. * The first number is the major version number of the bundle and can
  490. * contain one or two digits to represent a number in the range 0-99. The
  491. * second and third numbers are minor revision numbers and must be a single
  492. * numeric digit. The fourth set of digits is the specific build number for
  493. * the release.
  494. *
  495. * You may omit minor revision and build number information as appropriate.
  496. * You may also omit major and minor revision information and specify only a
  497. * build number. For example, valid version numbers include: 1.0.1,
  498. * 1.2.1b10, 1.2d200, d125, 101, and 1.0.
  499. *
  500. * The value of this key typically changes between builds and is displayed
  501. * in the Cocoa About panel in parenthesis. To specify the version
  502. * information of a released bundle, use the CFBundleShortVersionString key.
  503. */
  504. public void setBuild(String s) {
  505. bundleProperties.setCFBundleVersion(s);
  506. }
  507. /**
  508. * Setter for the version attribute (optional). It is this property, not
  509. * CFBundleVersion, which should receive the `short' version string. See for
  510. * example
  511. * <http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/>
  512. */
  513. public void setVersion(String s) {
  514. bundleProperties.setCFBundleShortVersionString(s);
  515. }
  516. public void setHelpBookFolder(String s) {
  517. bundleProperties.setCFBundleHelpBookFolder(s);
  518. }
  519. public void setHelpBookName(String s) {
  520. bundleProperties.setCFBundleHelpBookName(s);
  521. }
  522. /**
  523. * Setter for the "jars" attribute (required if no "jarfileset" is present)
  524. */
  525. public void setJars(String s) {
  526. PatternSet patset = new PatternSet();
  527. patset.setIncludes(s);
  528. String[] jarNames = patset.getIncludePatterns(getProject());
  529. for (int i = 0; i < jarNames.length; i++)
  530. mJarAttrs.add(getProject().resolveFile(jarNames[i]));
  531. }
  532. /**
  533. * Setter for the "jar" attribute (required if no "jarfileset" is present)
  534. */
  535. public void setJar(File s) {
  536. mJarAttrs.add(s);
  537. }
  538. /**
  539. * Setter for the "execs" attribute (optional)
  540. */
  541. public void setExecs(String s) {
  542. PatternSet patset = new PatternSet();
  543. patset.setIncludes(s);
  544. String[] execNames = patset.getIncludePatterns(getProject());
  545. for (int i = 0; i < execNames.length; i++) {
  546. File f = new File(execNames[i]);
  547. mExecAttrs.add(f);
  548. }
  549. }
  550. /**
  551. * Setter for the "extraclasspath" attribute (optional)
  552. */
  553. public void setExtraclasspath(String s) {
  554. PatternSet patset = new PatternSet();
  555. patset.setIncludes(s);
  556. String[] cpNames = patset.getIncludePatterns(getProject());
  557. for (int i = 0; i < cpNames.length; i++) {
  558. File f = new File(cpNames[i]);
  559. mExtraClassPathAttrs.add(f);
  560. }
  561. }
  562. /**
  563. * Set the 'chmod' executable.
  564. */
  565. public void setChmod(String s) {
  566. log("The \"chmod\" attribute has deprecaited, using the ANT Chmod task internally");
  567. }
  568. /***************************************************************************
  569. * Nested tasks - derived from FileList and FileSet
  570. **************************************************************************/
  571. public void addJarfileset(FileSet fs) {
  572. mJarFileSets.add(fs);
  573. }
  574. public void addJarfilelist(FileList fl) {
  575. mJarFileLists.add(fl);
  576. }
  577. public void addExecfileset(FileSet fs) {
  578. mExecFileSets.add(fs);
  579. }
  580. public void addExecfilelist(FileList fl) {
  581. mExecFileLists.add(fl);
  582. }
  583. public void addResourcefileset(FileSet fs) {
  584. mResourceFileSets.add(fs);
  585. }
  586. public void addResourcefilelist(FileList fl) {
  587. mResourceFileLists.add(fl);
  588. }
  589. public void addJavafileset(FileSet fs) {
  590. mJavaFileSets.add(fs);
  591. }
  592. public void addJavafilelist(FileList fl) {
  593. mJavaFileLists.add(fl);
  594. }
  595. public void addExtraclasspathfileset(FileSet fs) {
  596. mExtraClassPathFileSets.add(fs);
  597. }
  598. public void addExtraclasspathfilelist(FileList fl) {
  599. mExtraClassPathFileLists.add(fl);
  600. }
  601. /***************************************************************************
  602. * Nested tasks - new tasks with custom attributes
  603. **************************************************************************/
  604. public void addConfiguredJavaProperty(JavaProperty javaProperty)
  605. throws BuildException {
  606. String name = javaProperty.getName();
  607. String value = javaProperty.getValue();
  608. if ((name == null) || (value == null))
  609. throw new BuildException(
  610. "'<javaproperty>' must have both 'name' and 'value' attibutes");
  611. bundleProperties.addJavaProperty(name, value);
  612. }
  613. public void addConfiguredDocumentType(DocumentType documentType) throws BuildException {
  614. String name = documentType.getName();
  615. String role = documentType.getRole();
  616. List osTypes = documentType.getOSTypes();
  617. List extensions = documentType.getExtensions();
  618. List mimeTypes = documentType.getMimeTypes();
  619. if ((name == null) || (role == null))
  620. throw new BuildException(
  621. "'<documenttype>' must have both a 'name' and a 'role' attibute");
  622. if ((osTypes.isEmpty()) && (extensions.isEmpty()) && (mimeTypes.isEmpty()))
  623. throw new BuildException(
  624. "'<documenttype>' of \""
  625. + name
  626. + "\" must have 'osTypes' or 'extensions' or 'mimeTypes'");
  627. bundleProperties.addDocumentType(documentType);
  628. }
  629. public void addConfiguredService(Service service) {
  630. //if (service.getPortName() == null)
  631. // throw new BuildException("\"<service>\" must have a \"portName\" attribute");
  632. if (service.getMessage() == null)
  633. throw new BuildException("\"<service>\" must have a \"message\" attribute");
  634. String menuItem = service.getMenuItem();
  635. if (menuItem == null)
  636. throw new BuildException("\"<service>\" must have a \"menuItem\" attribute");
  637. if (!menuItems.add(menuItem))
  638. throw new BuildException("\"<service>\" \"menuItem\" value must be unique");
  639. if (service.getSendTypes().isEmpty() && service.getReturnTypes().isEmpty())
  640. throw new BuildException("\"<service>\" must have either a \"sendTypes\" attribute, a \"returnTypes\" attribute or both");
  641. String keyEquivalent = service.getKeyEquivalent();
  642. if ((keyEquivalent != null) && (1 != keyEquivalent.length()))
  643. throw new BuildException("\"<service>\" \"keyEquivalent\" must be one character if present");
  644. String timeoutString = service.getTimeout();
  645. if (timeoutString != null) {
  646. long timeout = -1;
  647. try {
  648. timeout = Long.parseLong(timeoutString);
  649. } catch (NumberFormatException nfe) {
  650. throw new BuildException("\"<service>\" \"timeout\" must be a positive integral number");
  651. }
  652. if (timeout < 0)
  653. throw new BuildException("\"<service>\" \"timeout\" must not be negative");
  654. }
  655. bundleProperties.addService(service);
  656. }
  657. public void addConfiguredHelpBook(HelpBook helpBook) {
  658. // Validity check on 'foldername'
  659. if (helpBook.getFolderName() == null) {
  660. if (bundleProperties.getCFBundleHelpBookFolder() == null)
  661. throw new BuildException("Either the '<helpbook>' attribute 'foldername' or the '<jarbundler>' attribute 'helpbookfolder' must be defined");
  662. helpBook.setFolderName(bundleProperties.getCFBundleHelpBookFolder());
  663. }
  664. // Validity check on 'title'
  665. if (helpBook.getName() == null) {
  666. if (bundleProperties.getCFBundleHelpBookName() == null)
  667. throw new BuildException("Either the '<helpbook>' attribute 'name' or the '<jarbundler>' attribute 'helpbookname' must be defined");
  668. helpBook.setName(bundleProperties.getCFBundleHelpBookName());
  669. }
  670. // Make sure some file were selected...
  671. List fileLists = helpBook.getFileLists();
  672. List fileSets = helpBook.getFileSets();
  673. if ( fileLists.isEmpty() && fileSets.isEmpty() )
  674. throw new BuildException("The '<helpbook>' task must have either " +
  675. "'<fileset>' or '<filelist>' nested tags");
  676. mHelpBooks.add(helpBook);
  677. }
  678. /***************************************************************************
  679. * Execute the task
  680. **************************************************************************/
  681. /**
  682. * The method executing the task
  683. */
  684. public void execute() throws BuildException {
  685. // Delete any existing Application bundle directory structure
  686. bundleDir = new File(mRootDir, bundleProperties.getApplicationName() + ".app");
  687. if (bundleDir.exists()) {
  688. Delete deleteTask = new Delete();
  689. deleteTask.setProject(getProject());
  690. deleteTask.setDir(bundleDir);
  691. deleteTask.execute();
  692. }
  693. // Validate - look for required attributes
  694. // ///////////////////////////////////////////
  695. if (mRootDir == null)
  696. throw new BuildException("Required attribute \"dir\" is not set.");
  697. if (mJarAttrs.isEmpty() && mJarFileSets.isEmpty()
  698. && mJarFileLists.isEmpty())
  699. throw new BuildException("Either the attribute \"jar\" must "
  700. + "be set, or one or more jarfilelists or "
  701. + "jarfilesets must be added.");
  702. if (!mJarAttrs.isEmpty()
  703. && (!mJarFileSets.isEmpty() || !mJarFileLists.isEmpty()))
  704. throw new BuildException(
  705. "Cannot set both the attribute "
  706. + "\"jars\" and use jar filesets/filelists. Use only one or the other.");
  707. if (bundleProperties.getApplicationName() == null)
  708. throw new BuildException("Required attribute \"name\" is not set.");
  709. if (bundleProperties.getMainClass() == null)
  710. throw new BuildException(
  711. "Required attribute \"mainclass\" is not set.");
  712. // /////////////////////////////////////////////////////////////////////////////////////
  713. // Set up some Java properties
  714. // About Menu, deprecated under 1.4+
  715. if (useOldPropertyNames())
  716. bundleProperties.addJavaProperty(ABOUTMENU_KEY, bundleProperties
  717. .getCFBundleName());
  718. // Anti Aliased Graphics, renamed in 1.4+
  719. String antiAliasedProperty = useOldPropertyNames()
  720. ? "com.apple.macosx.AntiAliasedGraphicsOn"
  721. : "apple.awt.antialiasing";
  722. if (mAntiAliasedGraphics != null)
  723. bundleProperties.addJavaProperty(antiAliasedProperty,
  724. mAntiAliasedGraphics.toString());
  725. // Anti Aliased Text, renamed in 1.4+
  726. String antiAliasedTextProperty = useOldPropertyNames()
  727. ? "com.apple.macosx.AntiAliasedTextOn"
  728. : "apple.awt.textantialiasing";
  729. if (mAntiAliasedText != null)
  730. bundleProperties.addJavaProperty(antiAliasedTextProperty,
  731. mAntiAliasedText.toString());
  732. // Live Resize, deprecated under 1.4+
  733. if (useOldPropertyNames() && (mLiveResize != null))
  734. bundleProperties.addJavaProperty(
  735. "com.apple.mrj.application.live-resize", mLiveResize
  736. .toString());
  737. // Screen Menu Bar, renamed in 1.4+
  738. String screenMenuBarProperty = useOldPropertyNames()
  739. ? "com.apple.macos.useScreenMenuBar"
  740. : "apple.laf.useScreenMenuBar";
  741. if (mScreenMenuBar != null)
  742. bundleProperties.addJavaProperty(screenMenuBarProperty,
  743. mScreenMenuBar.toString());
  744. // Growbox, added with 1.4+
  745. if ((useOldPropertyNames() == false) && (mGrowbox != null))
  746. bundleProperties.addJavaProperty("apple.awt.showGrowBox", mGrowbox
  747. .toString());
  748. // Growbox Intrudes, deprecated under 1.4+
  749. if (useOldPropertyNames() && (mGrowboxIntrudes != null))
  750. bundleProperties.addJavaProperty(
  751. "com.apple.mrj.application.growbox.intrudes",
  752. mGrowboxIntrudes.toString());
  753. if (!mRootDir.exists()
  754. || (mRootDir.exists() && !mRootDir.isDirectory()))
  755. throw new BuildException(
  756. "Destination directory specified by \"dir\" "
  757. + "attribute must already exist.");
  758. if (bundleDir.exists())
  759. throw new BuildException("The directory/bundle \""
  760. + bundleDir.getName()
  761. + "\" already exists, cannot continue.");
  762. // Status message
  763. log("Creating application bundle: " + bundleDir);
  764. if (!bundleDir.mkdir())
  765. throw new BuildException("Unable to create bundle: " + bundleDir);
  766. // Make the Contents directory
  767. mContentsDir = new File(bundleDir, "Contents");
  768. if (!mContentsDir.mkdir())
  769. throw new BuildException("Unable to create directory "
  770. + mContentsDir);
  771. // Make the "MacOS" directory
  772. mMacOsDir = new File(mContentsDir, "MacOS");
  773. if (!mMacOsDir.mkdir())
  774. throw new BuildException("Unable to create directory " + mMacOsDir);
  775. // Make the Resources directory
  776. mResourcesDir = new File(mContentsDir, "Resources");
  777. if (!mResourcesDir.mkdir())
  778. throw new BuildException("Unable to create directory "
  779. + mResourcesDir);
  780. // Make the Resources/Java directory
  781. mJavaDir = new File(mResourcesDir, "Java");
  782. if (!mJavaDir.mkdir())
  783. throw new BuildException("Unable to create directory " + mJavaDir);
  784. // Copy icon file to resource dir. If no icon parameter
  785. // is supplied, the default icon will be used.
  786. if (mAppIcon != null) {
  787. try {
  788. File dest = new File(mResourcesDir, mAppIcon.getName());
  789. if(mVerbose)
  790. log("Copying application icon file to \"" + bundlePath(dest) + "\"");
  791. mFileUtils.copyFile(mAppIcon, dest);
  792. } catch (IOException ex) {
  793. throw new BuildException("Cannot copy icon file: " + ex);
  794. }
  795. }
  796. // Copy document type icons, if any, to the resource dir
  797. try {
  798. Iterator itor = bundleProperties.getDocumentTypes().iterator();
  799. while (itor.hasNext()) {
  800. DocumentType documentType = (DocumentType) itor.next();
  801. File iconFile = documentType.getIconFile();
  802. if (iconFile != null) {
  803. File dest = new File(mResourcesDir, iconFile.getName());
  804. if(mVerbose)
  805. log("Copying document icon file to \"" + bundlePath(dest) + "\"");
  806. mFileUtils.copyFile(iconFile, dest);
  807. }
  808. }
  809. } catch (IOException ex) {
  810. throw new BuildException("Cannot copy document icon file: " + ex);
  811. }
  812. // Copy application jar(s) from the "jars" attribute (if any)
  813. processJarAttrs();
  814. // Copy application jar(s) from the nested jarfileset element(s)
  815. processJarFileSets();
  816. // Copy application jar(s) from the nested jarfilelist element(s)
  817. processJarFileLists();
  818. // Copy executable(s) from the "execs" attribute (if any)
  819. processExecAttrs();
  820. // Copy executable(s) from the nested execfileset element(s)
  821. processExecFileSets();
  822. // Copy executable(s) from the nested execfilelist element(s)
  823. processExecFileLists();
  824. // Copy resource(s) from the nested resourcefileset element(s)
  825. processResourceFileSets();
  826. // Copy resource(s) from the nested javafileset element(s)
  827. processJavaFileSets();
  828. // Copy resource(s) from the nested resourcefilelist element(s)
  829. processResourceFileLists();
  830. // Copy resource(s) from the nested javafilelist element(s)
  831. processJavaFileLists();
  832. // Add external classpath references from the extraclasspath attributes
  833. processExtraClassPathAttrs();
  834. // Add external classpath references from the nested
  835. // extraclasspathfileset element(s)
  836. processExtraClassPathFileSets();
  837. // Add external classpath references from the nested
  838. // extraclasspathfilelist attributes
  839. processExtraClassPathFileLists();
  840. // Copy HelpBooks into place
  841. copyHelpBooks();
  842. // Copy the JavaApplicationStub file from the Java system directory to
  843. // the MacOS directory
  844. copyApplicationStub();
  845. // Create the Info.plist file
  846. writeInfoPlist();
  847. // Create the PkgInfo file
  848. writePkgInfo();
  849. // Done!
  850. }
  851. /***************************************************************************
  852. * Private utility methods.
  853. **************************************************************************/
  854. private void setExecutable(File f) {
  855. Chmod chmodTask = new Chmod();
  856. chmodTask.setProject(getProject());
  857. chmodTask.setFile(f);
  858. chmodTask.setPerm("ugo+rx");
  859. if (mVerbose)
  860. log("Setting \"" + bundlePath(f) + "\" to executable");
  861. chmodTask.execute();
  862. }
  863. /**
  864. * Utility method to determine whether this app bundle is targeting a 1.3 or
  865. * 1.4 VM. The Mac OS X 1.3 VM uses different Java property names from the
  866. * 1.4 VM to hint at native Mac OS X look and feel options. For example, on
  867. * 1.3 the Java property to tell the VM to display Swing menu bars as screen
  868. * menus is "com.apple.macos.useScreenMenuBar". Under 1.4, it becomes
  869. * "apple.laf.useScreenMenuBar". Such is the price of progress, I suppose.
  870. *
  871. * Obviously, this logic may need refactoring in the future.
  872. */
  873. private boolean useOldPropertyNames() {
  874. return (bundleProperties.getJVMVersion().startsWith("1.3"));
  875. }
  876. private void processJarAttrs() throws BuildException {
  877. try {
  878. for (Iterator jarIter = mJarAttrs.iterator(); jarIter.hasNext();) {
  879. File src = (File) jarIter.next();
  880. File dest = new File(mJavaDir, src.getName());
  881. if (mVerbose)
  882. log("Copying JAR file to \"" + bundlePath(dest) + "\"");
  883. mFileUtils.copyFile(src, dest);
  884. bundleProperties.addToClassPath(dest.getName());
  885. }
  886. } catch (IOException ex) {
  887. throw new BuildException("Cannot copy jar file: " + ex);
  888. }
  889. }
  890. private void processJarFileSets() throws BuildException {
  891. for (Iterator jarIter = mJarFileSets.iterator(); jarIter.hasNext();) {
  892. FileSet fs = (FileSet) jarIter.next();
  893. Project p = fs.getProject();
  894. File srcDir = fs.getDir(p);
  895. FileScanner ds = fs.getDirectoryScanner(p);
  896. fs.setupDirectoryScanner(ds, p);
  897. ds.scan();
  898. String[] files = ds.getIncludedFiles();
  899. try {
  900. for (int i = 0; i < files.length; i++) {
  901. String fileName = files[i];
  902. File src = new File(srcDir, fileName);
  903. File dest = new File(mJavaDir, fileName);
  904. if (mVerbose)
  905. log("Copying JAR file to \"" + bundlePath(dest) + "\"");
  906. mFileUtils.copyFile(src, dest);
  907. bundleProperties.addToClassPath(fileName);
  908. }
  909. } catch (IOException ex) {
  910. throw new BuildException("Cannot copy jar file: " + ex);
  911. }
  912. }
  913. }
  914. private void processJarFileLists() throws BuildException {
  915. for (Iterator jarIter = mJarFileLists.iterator(); jarIter.hasNext();) {
  916. FileList fl = (FileList) jarIter.next();
  917. Project p = fl.getProject();
  918. File srcDir = fl.getDir(p);
  919. String[] files = fl.getFiles(p);
  920. try {
  921. for (int i = 0; i < files.length; i++) {
  922. String fileName = files[i];
  923. File src = new File(srcDir, fileName);
  924. File dest = new File(mJavaDir, fileName);
  925. if (mVerbose)
  926. log("Copying JAR file to \"" + bundlePath(dest) + "\"");
  927. mFileUtils.copyFile(src, dest);
  928. bundleProperties.addToClassPath(fileName);
  929. }
  930. } catch (IOException ex) {
  931. throw new BuildException("Cannot copy jar file: " + ex);
  932. }
  933. }
  934. }
  935. private void processExtraClassPathAttrs() throws BuildException {
  936. for (Iterator jarIter = mExtraClassPathAttrs.iterator(); jarIter
  937. .hasNext();) {
  938. File src = (File) jarIter.next();
  939. bundleProperties.addToExtraClassPath(src.getPath());
  940. }
  941. }
  942. private void processExtraClassPathFileSets() throws BuildException {
  943. for (Iterator jarIter = mExtraClassPathFileSets.iterator(); jarIter
  944. .hasNext();) {
  945. FileSet fs = (FileSet) jarIter.next();
  946. Project p = fs.getProject();
  947. File srcDir = fs.getDir(p);
  948. FileScanner ds = fs.getDirectoryScanner(p);
  949. fs.setupDirectoryScanner(ds, p);
  950. ds.scan();
  951. String[] files = ds.getIncludedFiles();
  952. for (int i = 0; i < files.length; i++) {
  953. File f = new File(srcDir, files[i]);
  954. bundleProperties.addToExtraClassPath(f.getPath());
  955. }
  956. }
  957. }
  958. private void processExtraClassPathFileLists() throws BuildException {
  959. for (Iterator jarIter = mExtraClassPathFileLists.iterator(); jarIter
  960. .hasNext();) {
  961. FileList fl = (FileList) jarIter.next();
  962. Project p = fl.getProject();
  963. File srcDir = fl.getDir(p);
  964. String[] files = fl.getFiles(p);
  965. for (int i = 0; i < files.length; i++) {
  966. File f = new File(srcDir, files[i]);
  967. bundleProperties.addToExtraClassPath(f.getPath());
  968. }
  969. }
  970. }
  971. private void processExecAttrs() throws BuildException {
  972. try {
  973. for (Iterator execIter = mExecAttrs.iterator(); execIter.hasNext();) {
  974. File src = (File) execIter.next();
  975. File dest = new File(mMacOsDir, src.getName());
  976. if (mVerbose)
  977. log("Copying exec file to \"" + bundlePath(dest) + "\"");
  978. mFileUtils.copyFile(src, dest);
  979. setExecutable(dest);
  980. }
  981. } catch (IOException ex) {
  982. throw new BuildException("Cannot copy exec file: " + ex);
  983. }
  984. }
  985. // Methods for copying FileSets into the application bundle ///////////////////////////////
  986. // Files for the Contents/MacOS directory
  987. private void processExecFileSets() {
  988. processCopyingFileSets(mExecFileSets, mMacOsDir, true);
  989. }
  990. // Files for the Contents/Resources directory
  991. private void processResourceFileSets() {
  992. processCopyingFileSets(mResourceFileSets, mResourcesDir, false);
  993. }
  994. // Files for the Contents/Resources/Java directory
  995. private void processJavaFileSets() {
  996. processCopyingFileSets(mJavaFileSets, mJavaDir, false);
  997. }
  998. private void processCopyingFileSets(List fileSets, File targetdir, boolean setExec) {
  999. for (Iterator execIter = fileSets.iterator(); execIter.hasNext();) {
  1000. FileSet fs = (FileSet) execIter.next();
  1001. Project p = fs.getProject();
  1002. File srcDir = fs.getDir(p);
  1003. FileScanner ds = fs.getDirectoryScanner(p);
  1004. fs.setupDirectoryScanner(ds, p);
  1005. ds.scan();
  1006. String[] files = ds.getIncludedFiles();
  1007. if (files.length == 0) {
  1008. // this is probably an error -- warn about it
  1009. System.err
  1010. .println("WARNING: fileset for copying from directory "
  1011. + srcDir + ": no files found");
  1012. } else {
  1013. try {
  1014. for (int i = 0; i < files.length; i++) {
  1015. String fileName = files[i];
  1016. File src = new File(srcDir, fileName);
  1017. File dest = new File(targetdir, fileName);
  1018. if (mVerbose)
  1019. log("Copying "
  1020. + (setExec ? "exec" : "resource")
  1021. + " file to \"" + bundlePath(dest) +"\"");
  1022. mFileUtils.copyFile(src, dest);
  1023. if (setExec)
  1024. setExecutable(dest);
  1025. }
  1026. } catch (IOException ex) {
  1027. throw new BuildException("Cannot copy file: " + ex);
  1028. }
  1029. }
  1030. }
  1031. }
  1032. // Methods for copying FileLists into the application bundle /////////////////////////////
  1033. // Files for the Contents/MacOS directory
  1034. private void processExecFileLists() throws BuildException {
  1035. processCopyingFileLists(mExecFileLists, mMacOsDir, true);
  1036. }
  1037. // Files for the Contents/Resources directory
  1038. private void processResourceFileLists() throws BuildException {
  1039. processCopyingFileLists(mResourceFileLists, mResourcesDir, false);
  1040. }
  1041. // Files for the Contents/Resources/Java directory
  1042. private void processJavaFileLists() throws BuildException {
  1043. processCopyingFileLists(mJavaFileLists, mJavaDir, false);
  1044. }
  1045. private void processCopyingFileLists(List fileLists, File targetDir, boolean setExec) throws BuildException {
  1046. for (Iterator execIter = fileLists.iterator(); execIter.hasNext();) {
  1047. FileList fl = (FileList) execIter.next();
  1048. Project p = fl.getProject();
  1049. File srcDir = fl.getDir(p);
  1050. String[] files = fl.getFiles(p);
  1051. if (files.length == 0) {
  1052. // this is probably an error -- warn about it
  1053. System.err.println("WARNING: filelist for copying from directory "
  1054. + srcDir + ": no files found");
  1055. } else {
  1056. try {
  1057. for (int i = 0; i < files.length; i++) {
  1058. String fileName = files[i];
  1059. File src = new File(srcDir, fileName);
  1060. File dest = new File(targetDir, fileName);
  1061. if (mVerbose)
  1062. log("Copying "
  1063. + (setExec ? "exec" : "resource")
  1064. + " file to \"" + bundlePath(dest) +"\"");
  1065. mFileUtils.copyFile(src, dest);
  1066. if (setExec)
  1067. setExecutable(dest);
  1068. }
  1069. } catch (IOException ex) {
  1070. throw new BuildException("Cannot copy jar file: " + ex);
  1071. }
  1072. }
  1073. }
  1074. }
  1075. private void copyHelpBooks() {
  1076. for (Iterator itor = mHelpBooks.iterator(); itor.hasNext();) {
  1077. HelpBook helpBook = (HelpBook)itor.next();
  1078. String folderName = helpBook.getFolderName();
  1079. String name = helpBook.getName();
  1080. String locale = helpBook.getLocale();
  1081. List fileLists = helpBook.getFileLists();
  1082. List fileSets = helpBook.getFileSets();
  1083. File helpBookDir = null;
  1084. if (locale == null) {
  1085. // Set the Bundle entries for a nonlocalized Help Book
  1086. if (folderName != null)
  1087. bundleProperties.setCFBundleHelpBookFolder(folderName);
  1088. if (name != null)
  1089. bundleProperties.setCFBundleHelpBookName(name);
  1090. // The non-localized Help Book is top level "/Resources"
  1091. helpBookDir = new File(mResourcesDir, folderName);
  1092. helpBookDir.mkdir();
  1093. if(mVerbose)
  1094. log("Creating Help Book at \"" +
  1095. bundlePath(helpBookDir) + "\"");
  1096. } else {
  1097. // The localized Help Book is "/Resources/locale.lproj"
  1098. File lproj = new File(mResourcesDir, locale + ".lproj");
  1099. lproj.mkdir();
  1100. helpBookDir = new File(lproj, folderName);
  1101. helpBookDir.mkdir();
  1102. if(mVerbose)
  1103. log("Creating Help Book for \"" + locale +
  1104. "\" at \"" + bundlePath(helpBookDir) + "\"");
  1105. // Create a local file to override the Bundle settings
  1106. File infoPList = new File(lproj, "InfoPlist.strings");
  1107. PrintWriter writer = null;
  1108. try {
  1109. writer = new PrintWriter(new FileWriter(infoPList));
  1110. writer.println("CFBundleHelpBookFolder = \"" + folderName + "\";");
  1111. writer.println("CFBundleHelpBookName = \"" + name + "\";");
  1112. writer.println("CFBundleName = \"" + bundleProperties.getCFBundleName() + "\";");
  1113. } catch (IOException ioe) {
  1114. throw new BuildException("IOException in writing Help Book locale: " + locale);
  1115. } finally {
  1116. mFileUtils.close(writer);
  1117. }
  1118. }
  1119. // Write the Help Book source files into the bundle
  1120. processCopyingFileSets(fileSets, helpBookDir, false);
  1121. processCopyingFileLists(fileLists, helpBookDir, false);
  1122. }
  1123. }
  1124. // Copy the application stub into the bundle
  1125. // /////////////////////////////////////////////
  1126. private void copyApplicationStub() throws BuildException {
  1127. File newStubFile = new File(mMacOsDir, bundleProperties.getCFBundleExecutable());
  1128. if (mVerbose)
  1129. log("Copying Java application stub to \"" + bundlePath(newStubFile) + "\"");
  1130. try {
  1131. mFileUtils.copyFile(mStubFile, newStubFile);
  1132. } catch (IOException ex) {
  1133. throw new BuildException("Cannot copy Java Application Stub: " + ex);
  1134. }
  1135. // Set the permissions on the stub file to executable
  1136. setExecutable(newStubFile);
  1137. }
  1138. private void writeInfoPlist() throws BuildException {
  1139. PropertyListWriter listWriter = new PropertyListWriter(bundleProperties);
  1140. File infoPlist = new File(mContentsDir, "Info.plist");
  1141. listWriter.writeFile(infoPlist);
  1142. if (mVerbose)
  1143. log("Creating \"" + bundlePath(infoPlist) + "\" file");
  1144. if (mShowPlist) {
  1145. try {
  1146. BufferedReader in = new BufferedReader(new FileReader(infoPlist));
  1147. String str;
  1148. while ((str = in.readLine()) != null)
  1149. log(str);
  1150. in.close();
  1151. } catch (IOException e) {
  1152. throw new BuildException(e);
  1153. }
  1154. }
  1155. }
  1156. //
  1157. // Write the PkgInfo file into the application bundle
  1158. //
  1159. private void writePkgInfo() throws BuildException {
  1160. File pkgInfo = new File(mContentsDir, "PkgInfo");
  1161. PrintWriter writer = null;
  1162. try {
  1163. writer = new PrintWriter(new BufferedWriter(new FileWriter(pkgInfo)));
  1164. writer.print(bundleProperties.getCFBundlePackageType());
  1165. writer.println(bundleProperties.getCFBundleSignature());
  1166. writer.flush();
  1167. } catch (IOException ex) {
  1168. throw new BuildException("Cannot create PkgInfo file: " + ex);
  1169. } finally {
  1170. mFileUtils.close(writer);
  1171. }
  1172. }
  1173. private String bundlePath(File bundleFile) {
  1174. String rootPath = bundleDir.getAbsolutePath();
  1175. String thisPath = bundleFile.getAbsolutePath();
  1176. return thisPath.substring(rootPath.length());
  1177. }
  1178. }