0001: /*
0002: * A Mac OS X Jar Bundler Ant Task.
0003: *
0004: * Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
0005: *
0006: * This program is free software; you can redistribute it and/or modify it
0007: * under the terms of the GNU General Public License as published by the Free
0008: * Software Foundation; either version 2 of the License, or (at your option)
0009: * any later version.
0010: *
0011: * This program is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
0014: * more details.
0015: *
0016: * You should have received a copy of the GNU General Public License along with
0017: * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
0018: * Place - Suite 330, Boston, MA 02111-1307, USA.
0019: */
0020:
0021: package net.sourceforge.jarbundler;
0022:
0023: // This package's imports
0024: import net.sourceforge.jarbundler.AppBundleProperties;
0025: import net.sourceforge.jarbundler.DocumentType;
0026: import net.sourceforge.jarbundler.JavaProperty;
0027: import net.sourceforge.jarbundler.PropertyListWriter;
0028:
0029: // Java I/O
0030: import java.io.BufferedWriter;
0031: import java.io.BufferedReader;
0032: import java.io.File;
0033: import java.io.FileWriter;
0034: import java.io.FileReader;
0035: import java.io.IOException;
0036: import java.io.InputStream;
0037: import java.io.PrintWriter;
0038:
0039: // Java Utility
0040: import java.util.ArrayList;
0041: import java.util.HashSet;
0042: import java.util.Iterator;
0043: import java.util.List;
0044: import java.util.Set;
0045:
0046: // Apache Jakarta
0047: import org.apache.tools.ant.BuildException;
0048: import org.apache.tools.ant.FileScanner;
0049: import org.apache.tools.ant.Project;
0050: import org.apache.tools.ant.Task;
0051:
0052: import org.apache.tools.ant.types.FileList;
0053: import org.apache.tools.ant.types.FileSet;
0054: import org.apache.tools.ant.types.PatternSet;
0055:
0056: import org.apache.tools.ant.taskdefs.MatchingTask;
0057: import org.apache.tools.ant.taskdefs.Chmod;
0058: import org.apache.tools.ant.taskdefs.Delete;
0059:
0060: import org.apache.tools.ant.util.FileUtils;
0061:
0062: // Java language imports
0063: import java.lang.Boolean;
0064: import java.lang.Process;
0065: import java.lang.Runtime;
0066: import java.lang.String;
0067: import java.lang.System;
0068:
0069: /**
0070: * <p>
0071: * An ant task which creates a Mac OS X Application Bundle for a Java
0072: * application.
0073: * </p>
0074: *
0075: * <dl>
0076: * <dt>dir</dt>
0077: * <dd>The directory into which to put the new application bundle.</dd>
0078: * <dt>name</dt>
0079: * <dd>The name of the application bundle. Note that the maximum length of this
0080: * name is 16 characters, and it will be silently cropped if it is longer than
0081: * this.</dd>
0082: * <dt>mainclass</dt>
0083: * <dd>The main Java class to call when running the application.</dd>
0084: * </dl>
0085: *
0086: * <p>
0087: * One of the following three MUST be used:
0088: *
0089: * <ol>
0090: * <li>jars Space or comma-separated list of JAR files to include.; OR</li>
0091: * <li>One or more nested <jarfileset>s. These are normal ANT FileSets;
0092: * OR </li>
0093: * <li>One or more nested <jarfilelist>s. These are standard ANT
0094: * FileLists. </li>
0095: * </ol>
0096: *
0097: * <p>
0098: * Optional attributes:
0099: *
0100: * <p>
0101: * The following attributes are not required, but you can use them to override
0102: * default behavior.
0103: *
0104: * <dl>
0105: * <dt>verbose
0106: * <dd>If true, show more verbose output while running the task
0107: *
0108: * <dt>version
0109: * <dd>Version information about your application (e.g., "1.0")
0110: *
0111: * <dt>infostring
0112: * <dd>String to show in the "Get Info" dialog
0113: * </dl>
0114: *
0115: * These attributes control the fine-tuning of the "Mac OS X" look and feel.
0116: *
0117: * <dl>
0118: * <dt>arguments
0119: * <dd>Command line arguments. (no default)
0120: *
0121: * <dt>smalltabs
0122: * <dd>Use small tabs. (default "false") Deprecated under JVM 1.4.1
0123: *
0124: * <dt>antialiasedgraphics
0125: * <dd>Use anti-aliased graphics (default "false")
0126: *
0127: * <dt>antialiasedtext
0128: * <dd>Use anti-aliased text (default "false")
0129: *
0130: * <dt>bundleid
0131: * <dd>Unique identifier for this bundle, in the form of a Java package. No
0132: * default.
0133: *
0134: * <dt>buildnumber
0135: * <dd>Unique identifier for this build
0136: *
0137: * <dt>developmentregion
0138: * <dd>Development Region. Default "English".
0139: *
0140: * <dt>execs
0141: * <dd>Files to be copied into "Resources/MacOS" and made executable
0142: *
0143: * <dt>liveresize
0144: * <dd>Use "Live resizing" (default "false") Deprecated under JVM 1.4.1
0145: *
0146: *
0147: * <dt>growbox
0148: * <dd>Show growbox (default "true")
0149: *
0150: * <dt>growboxintrudes
0151: * <dd>Intruding growbox (default "false") Deprecated under JVM 1.4.1
0152: *
0153: * <dt>screenmenu
0154: * <dd>Put swing menu into Mac OS X menu bar.
0155: *
0156: * <dt>type
0157: * <dd>Bundle type (default "APPL")
0158: *
0159: * <dt>signature
0160: * <dd>Bundle Signature (default "????")
0161: *
0162: * <dt>stubfile
0163: * <dd>The Java Application Stub file to copy for your application (default
0164: * MacOS system stub file)
0165: * </dl>
0166: *
0167: * <p>
0168: * Rarely used optional attributes.
0169: * <dl>
0170: * <dt>chmod
0171: * <dd>Full path to the chmod command. This almost certainly does NOT need to
0172: * be set.
0173: * </dl>
0174: *
0175: * <p>
0176: * The task also supports nested <execfileset> and/or <execfilelist>
0177: * elements, and <resourcefileset> and/or <resourcefilelist>
0178: * elements, which are standard Ant FileSet and FileList elements. In the first
0179: * case, the referenced files are copied to the <code>Contents/MacOS</code>
0180: * directory and made executable, and in the second they are copied to the
0181: * <code>Contents/Resources</code> directory and not made executable. If you
0182: * winrces, note that in fact the files are installed in locations which have
0183: * the same relation to the <code>Contents/Resources</code> directory as the
0184: * files in the FileSet or FileList have to the 'dir' attribute. Thus in the
0185: * case:
0186: *
0187: * <pre>
0188: * <resourcefileset dir="builddir/architectures"
0189: * includes="ppc/*.jnilib"/>
0190: * </pre>
0191: *
0192: * <p>
0193: * the <code>*.jnilib</code> files will be installed in
0194: * <code>Contents/Resources/ppc</code>.
0195: *
0196: * <p>
0197: * The task supports a nested <javaproperty> element, which allows you to
0198: * specify further properties which are set for the JVM when the application is
0199: * launched. This takes a required <code>key</code> attribute, giving the
0200: * property key, plus an attribute giving the property value, which may be one
0201: * of <code>value</code>, giving the string value of the property,
0202: * <code>file</code>, setting the value of the property to be the absolute
0203: * path of the given file, or <code>path</code>, which sets the value to the
0204: * given path. If you are setting paths here, recall that, within the bundle,
0205: * <code>$APP_PACKAGE</code> is set to the root directory of the bundle (ie,
0206: * the path to the <code>foo.app</code> directory), and <code>$JAVAROOT</code>
0207: * to the directory <code>Contents/Resources/Java</code>.
0208: *
0209: * <p>
0210: * Minimum example:
0211: *
0212: * <pre>
0213: *
0214: * <jarbundler dir="release" name="Bar Project" mainclass="org.bar.Main"
0215: * jars="bin/Bar.jar" />
0216: * </pre>
0217: *
0218: * <p>
0219: * Using Filesets
0220: *
0221: * <pre>
0222: * <jarbundler dir="release" name="Bar Project" mainclass="org.bar.Main">
0223: * <jarfileset dir="bin">
0224: * <include name="*.jar" />
0225: * <exclude name="test.jar" />
0226: * </jarfileset>
0227: * <execfileset dir="execs">
0228: * <include name="**" />
0229: * </execfileset>
0230: * </jarbundler>
0231: * </pre>
0232: *
0233: * <p>
0234: * Much Longer example:
0235: * </p>
0236: *
0237: * <pre>
0238: * <jarbundler dir="release"
0239: * name="Foo Project"
0240: * mainclass="org.bar.Main"
0241: * version="1.0 b 1"
0242: * infostring="Foo Project (c) 2002"
0243: * type="APPL"
0244: * jars="bin/foo.jar bin/bar.jar"
0245: * execs="exec/foobar"
0246: * signature="????"
0247: * workingdirectory="temp"
0248: * icon="resources/foo.icns"
0249: * jvmversion="1.4.1+"
0250: * vmoptions="-Xmx256m"/>
0251: * </pre>
0252: *
0253: * http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/
0254: */
0255: public class JarBundler extends MatchingTask {
0256:
0257: private static final String DEFAULT_STUB = "/System/Library/Frameworks/JavaVM.framework/Versions/Current/Resources/MacOS/JavaApplicationStub";
0258:
0259: private static final String ABOUTMENU_KEY = "com.apple.mrj.application.apple.menu.about.name";
0260: private static final Set menuItems = new HashSet();
0261: private File mAppIcon;
0262:
0263: private File mRootDir;
0264:
0265: private final List mJavaFileLists = new ArrayList();
0266: private final List mJarFileSets = new ArrayList();
0267:
0268: private final List mExecFileLists = new ArrayList();
0269: private final List mExecFileSets = new ArrayList();
0270:
0271: private final List mResourceFileLists = new ArrayList();
0272: private final List mResourceFileSets = new ArrayList();
0273:
0274: private final List mJarFileLists = new ArrayList();
0275: private final List mJavaFileSets = new ArrayList();
0276:
0277: private final List mExtraClassPathFileLists = new ArrayList();
0278: private final List mExtraClassPathFileSets = new ArrayList();
0279:
0280: private final List mJarAttrs = new ArrayList();
0281:
0282: private final List mExecAttrs = new ArrayList();
0283:
0284: private final List mExtraClassPathAttrs = new ArrayList();
0285:
0286: private final List mHelpBooks = new ArrayList();
0287:
0288: private boolean mVerbose = false;
0289: private boolean mShowPlist = false;
0290:
0291: // Java properties used by Mac OS X Java applications
0292:
0293: private File mStubFile = new File(DEFAULT_STUB);
0294:
0295: private Boolean mAntiAliasedGraphics = null;
0296:
0297: private Boolean mAntiAliasedText = null;
0298:
0299: private Boolean mLiveResize = null;
0300:
0301: private Boolean mScreenMenuBar = null;
0302:
0303: private Boolean mGrowbox = null;
0304:
0305: private Boolean mGrowboxIntrudes = null;
0306:
0307: // The root of the application bundle
0308: private File bundleDir;
0309:
0310: // "Contents" directory
0311: private File mContentsDir;
0312:
0313: // "Contents/MacOS" directory
0314: private File mMacOsDir;
0315:
0316: // "Contents/Resources" directory
0317: private File mResourcesDir;
0318:
0319: // "Contents/Resources/Java" directory
0320: private File mJavaDir;
0321:
0322: // Full path to the 'chmod' command. Can be overridden
0323: // with the 'chmod' attribute. Won't cause any harm if
0324: // not set, or if this executable doesn't exist.
0325:
0326: private AppBundleProperties bundleProperties = new AppBundleProperties();
0327:
0328: // Ant file utilities
0329:
0330: private FileUtils mFileUtils = FileUtils.getFileUtils();
0331:
0332: /***************************************************************************
0333: * Retreive task attributes
0334: **************************************************************************/
0335:
0336: /**
0337: * Arguments to the
0338: *
0339: * @param s
0340: * The arguments to pass to the application being launched.
0341: */
0342: public void setArguments(String s) {
0343: bundleProperties.setArguments(s);
0344: }
0345:
0346: /**
0347: * Override the stub file path to build on non-MacOS platforms
0348: *
0349: * @param file
0350: * the path to the stub file
0351: */
0352: public void setStubFile(File file) {
0353: mStubFile = (file.exists()) ? file : new File(DEFAULT_STUB);
0354: bundleProperties.setCFBundleExecutable(file.getName());
0355: }
0356:
0357: /**
0358: * Setter for the "dir" attribute (required)
0359: */
0360: public void setDir(File f) {
0361: mRootDir = f;
0362: }
0363:
0364: /**
0365: * Setter for the "name" attribute (required) This attribute names the
0366: * output application bundle and asks as the CFBundleName if 'bundlename' is
0367: * not specified
0368: */
0369: public void setName(String s) {
0370: bundleProperties.setApplicationName(s);
0371: }
0372:
0373: /**
0374: * Setter for the "shortname" attribute (optional) This key identifies the
0375: * short name of the bundle. This name should be less than 16 characters
0376: * long and be suitable for displaying in the menu and the About box. The
0377: * name is (silently) cropped to this if necessary.
0378: */
0379: public void setShortName(String s) {
0380: bundleProperties.setCFBundleName(s);
0381: }
0382:
0383: /**
0384: * Setter for the "mainclass" attribute (required)
0385: */
0386: public void setMainClass(String s) {
0387: bundleProperties.setMainClass(s);
0388: }
0389:
0390: /**
0391: * Setter for the "WorkingDirectory" attribute (optional)
0392: */
0393: public void setWorkingDirectory(String s) {
0394: bundleProperties.setWorkingDirectory(s);
0395: }
0396:
0397: /**
0398: * Setter for the "icon" attribute (optional)
0399: */
0400:
0401: public void setIcon(File f) {
0402: mAppIcon = f;
0403: bundleProperties.setCFBundleIconFile(f.getName());
0404: }
0405:
0406: /**
0407: * Setter for the "bundleid" attribute (optional) This key specifies a
0408: * unique identifier string for the bundle. This identifier should be in the
0409: * form of a Java-style package name, for example com.mycompany.myapp. The
0410: * bundle identifier can be used to locate the bundle at runtime. The
0411: * preferences system uses this string to identify applications uniquely.
0412: *
0413: * No default.
0414: */
0415: public void setBundleid(String s) {
0416: bundleProperties.setCFBundleIdentifier(s);
0417: }
0418:
0419: /**
0420: * Setter for the "developmentregion" attribute(optional) Default "English".
0421: */
0422: public void setDevelopmentregion(String s) {
0423: bundleProperties.setCFBundleDevelopmentRegion(s);
0424: }
0425:
0426: /**
0427: * Setter for the "aboutmenuname" attribute (optional)
0428: */
0429: public void setAboutmenuname(String s) {
0430: bundleProperties.setCFBundleName(s);
0431: }
0432:
0433: /**
0434: * Setter for the "smalltabs" attribute (optional)
0435: */
0436: public void setSmallTabs(boolean b) {
0437: bundleProperties.addJavaProperty("com.apple.smallTabs",
0438: new Boolean(b).toString());
0439: }
0440:
0441: /**
0442: * Setter for the "vmoptions" attribute (optional)
0443: */
0444: public void setVmoptions(String s) {
0445: bundleProperties.setVMOptions(s);
0446: }
0447:
0448: /**
0449: * Setter for the "antialiasedgraphics" attribute (optional)
0450: */
0451: public void setAntialiasedgraphics(boolean b) {
0452: mAntiAliasedGraphics = new Boolean(b);
0453: }
0454:
0455: /**
0456: * Setter for the "antialiasedtext" attribute (optional)
0457: */
0458: public void setAntialiasedtext(boolean b) {
0459: mAntiAliasedText = new Boolean(b);
0460: }
0461:
0462: /**
0463: * Setter for the "screenmenu" attribute (optional)
0464: */
0465: public void setScreenmenu(boolean b) {
0466: mScreenMenuBar = new Boolean(b);
0467: }
0468:
0469: /**
0470: * Setter for the "growbox" attribute (optional)
0471: */
0472: public void setGrowbox(boolean b) {
0473: mGrowbox = new Boolean(b);
0474: }
0475:
0476: /**
0477: * Setter for the "growboxintrudes" attribute (optional)
0478: */
0479: public void setGrowboxintrudes(boolean b) {
0480: mGrowboxIntrudes = new Boolean(b);
0481: }
0482:
0483: /**
0484: * Setter for the "liveresize" attribute (optional)
0485: */
0486: public void setLiveresize(boolean b) {
0487: mLiveResize = new Boolean(b);
0488: }
0489:
0490: /**
0491: * Setter for the "type" attribute (optional)
0492: */
0493: public void setType(String s) {
0494: bundleProperties.setCFBundlePackageType(s);
0495: }
0496:
0497: /**
0498: * Setter for the "signature" attribute (optional)
0499: */
0500: public void setSignature(String s) {
0501: bundleProperties.setCFBundleSignature(s);
0502: }
0503:
0504: /**
0505: * Setter for the "jvmversion" attribute (optional)
0506: */
0507: public void setJvmversion(String s) {
0508: bundleProperties.setJVMVersion(s);
0509: }
0510:
0511: /**
0512: * Setter for the "infostring" attribute (optional) This key identifies a
0513: * human-readable plain text string displaying the copyright information for
0514: * the bundle. The Finder displays this information in the Info window of
0515: * the bundle. (This string was also known as the long version string in Mac
0516: * OS 9). The format of the key should be of the following format: "©
0517: * Great Software, Inc, 1999". You can localize this string by including it
0518: * in the InfoPlist.strings file of the appropriate .lproj directory.
0519: */
0520:
0521: public void setInfoString(String s) {
0522: bundleProperties.setCFBundleGetInfoString(s);
0523: }
0524:
0525: /**
0526: * Setter for the "shortinfostring" attribute (optional) This key identifies
0527: * the marketing version of the bundle. The marketing version is a string
0528: * that usually displays the major and minor version of the bundle. This
0529: * string is usually of the form n.n.n where n is a number. The first number
0530: * is the major version number of the bundle. The second and third numbers
0531: * are minor revision numbers. You may omit minor revision numbers as
0532: * appropriate. The value of this key is displayed in the default About box
0533: * for Cocoa applications.
0534: *
0535: * The value for this key differs from the value for "CFBundleVersion",
0536: * which identifies a specific build number. The CFBundleShortVersionString
0537: * value represents a more formal version that does not change with every
0538: * build.
0539: */
0540: public void setShortInfoString(String s) {
0541: setVersion(s);
0542: }
0543:
0544: /**
0545: * Setter for the "verbose" attribute (optional)
0546: */
0547: public void setVerbose(boolean verbose) {
0548: this .mVerbose = verbose;
0549: }
0550:
0551: public void setShowPlist(boolean showPlist) {
0552: this .mShowPlist = showPlist;
0553: }
0554:
0555: /**
0556: * Setter for the "buildnumber" attribute (optional) This key specifies the
0557: * exact build version of the bundle. This string is usually of the form
0558: * nn.n.nxnnn where n is a digit and x is a character from the set [abdf].
0559: * The first number is the major version number of the bundle and can
0560: * contain one or two digits to represent a number in the range 0-99. The
0561: * second and third numbers are minor revision numbers and must be a single
0562: * numeric digit. The fourth set of digits is the specific build number for
0563: * the release.
0564: *
0565: * You may omit minor revision and build number information as appropriate.
0566: * You may also omit major and minor revision information and specify only a
0567: * build number. For example, valid version numbers include: 1.0.1,
0568: * 1.2.1b10, 1.2d200, d125, 101, and 1.0.
0569: *
0570: * The value of this key typically changes between builds and is displayed
0571: * in the Cocoa About panel in parenthesis. To specify the version
0572: * information of a released bundle, use the CFBundleShortVersionString key.
0573: */
0574: public void setBuild(String s) {
0575: bundleProperties.setCFBundleVersion(s);
0576: }
0577:
0578: /**
0579: * Setter for the version attribute (optional). It is this property, not
0580: * CFBundleVersion, which should receive the `short' version string. See for
0581: * example
0582: * <http://developer.apple.com/documentation/MacOSX/Conceptual/BPRuntimeConfig/>
0583: */
0584: public void setVersion(String s) {
0585: bundleProperties.setCFBundleShortVersionString(s);
0586: }
0587:
0588: public void setHelpBookFolder(String s) {
0589: bundleProperties.setCFBundleHelpBookFolder(s);
0590: }
0591:
0592: public void setHelpBookName(String s) {
0593: bundleProperties.setCFBundleHelpBookName(s);
0594: }
0595:
0596: /**
0597: * Setter for the "jars" attribute (required if no "jarfileset" is present)
0598: */
0599: public void setJars(String s) {
0600: PatternSet patset = new PatternSet();
0601: patset.setIncludes(s);
0602:
0603: String[] jarNames = patset.getIncludePatterns(getProject());
0604:
0605: for (int i = 0; i < jarNames.length; i++)
0606: mJarAttrs.add(getProject().resolveFile(jarNames[i]));
0607: }
0608:
0609: /**
0610: * Setter for the "jar" attribute (required if no "jarfileset" is present)
0611: */
0612: public void setJar(File s) {
0613: mJarAttrs.add(s);
0614: }
0615:
0616: /**
0617: * Setter for the "execs" attribute (optional)
0618: */
0619: public void setExecs(String s) {
0620: PatternSet patset = new PatternSet();
0621: patset.setIncludes(s);
0622:
0623: String[] execNames = patset.getIncludePatterns(getProject());
0624:
0625: for (int i = 0; i < execNames.length; i++) {
0626: File f = new File(execNames[i]);
0627: mExecAttrs.add(f);
0628: }
0629: }
0630:
0631: /**
0632: * Setter for the "extraclasspath" attribute (optional)
0633: */
0634: public void setExtraclasspath(String s) {
0635: PatternSet patset = new PatternSet();
0636: patset.setIncludes(s);
0637:
0638: String[] cpNames = patset.getIncludePatterns(getProject());
0639:
0640: for (int i = 0; i < cpNames.length; i++) {
0641: File f = new File(cpNames[i]);
0642: mExtraClassPathAttrs.add(f);
0643: }
0644: }
0645:
0646: /**
0647: * Set the 'chmod' executable.
0648: */
0649: public void setChmod(String s) {
0650: log("The \"chmod\" attribute has deprecaited, using the ANT Chmod task internally");
0651: }
0652:
0653: /***************************************************************************
0654: * Nested tasks - derived from FileList and FileSet
0655: **************************************************************************/
0656:
0657: public void addJarfileset(FileSet fs) {
0658: mJarFileSets.add(fs);
0659: }
0660:
0661: public void addJarfilelist(FileList fl) {
0662: mJarFileLists.add(fl);
0663: }
0664:
0665: public void addExecfileset(FileSet fs) {
0666: mExecFileSets.add(fs);
0667: }
0668:
0669: public void addExecfilelist(FileList fl) {
0670: mExecFileLists.add(fl);
0671: }
0672:
0673: public void addResourcefileset(FileSet fs) {
0674: mResourceFileSets.add(fs);
0675: }
0676:
0677: public void addResourcefilelist(FileList fl) {
0678: mResourceFileLists.add(fl);
0679: }
0680:
0681: public void addJavafileset(FileSet fs) {
0682: mJavaFileSets.add(fs);
0683: }
0684:
0685: public void addJavafilelist(FileList fl) {
0686: mJavaFileLists.add(fl);
0687: }
0688:
0689: public void addExtraclasspathfileset(FileSet fs) {
0690: mExtraClassPathFileSets.add(fs);
0691: }
0692:
0693: public void addExtraclasspathfilelist(FileList fl) {
0694: mExtraClassPathFileLists.add(fl);
0695: }
0696:
0697: /***************************************************************************
0698: * Nested tasks - new tasks with custom attributes
0699: **************************************************************************/
0700:
0701: public void addConfiguredJavaProperty(JavaProperty javaProperty)
0702: throws BuildException {
0703:
0704: String name = javaProperty.getName();
0705: String value = javaProperty.getValue();
0706:
0707: if ((name == null) || (value == null))
0708: throw new BuildException(
0709: "'<javaproperty>' must have both 'name' and 'value' attibutes");
0710:
0711: bundleProperties.addJavaProperty(name, value);
0712: }
0713:
0714: public void addConfiguredDocumentType(DocumentType documentType)
0715: throws BuildException {
0716:
0717: String name = documentType.getName();
0718: String role = documentType.getRole();
0719: List osTypes = documentType.getOSTypes();
0720: List extensions = documentType.getExtensions();
0721: List mimeTypes = documentType.getMimeTypes();
0722:
0723: if ((name == null) || (role == null))
0724: throw new BuildException(
0725: "'<documenttype>' must have both a 'name' and a 'role' attibute");
0726:
0727: if ((osTypes.isEmpty()) && (extensions.isEmpty())
0728: && (mimeTypes.isEmpty()))
0729: throw new BuildException(
0730: "'<documenttype>' of \""
0731: + name
0732: + "\" must have 'osTypes' or 'extensions' or 'mimeTypes'");
0733:
0734: bundleProperties.addDocumentType(documentType);
0735: }
0736:
0737: public void addConfiguredService(Service service) {
0738:
0739: //if (service.getPortName() == null)
0740: // throw new BuildException("\"<service>\" must have a \"portName\" attribute");
0741:
0742: if (service.getMessage() == null)
0743: throw new BuildException(
0744: "\"<service>\" must have a \"message\" attribute");
0745:
0746: String menuItem = service.getMenuItem();
0747: if (menuItem == null)
0748: throw new BuildException(
0749: "\"<service>\" must have a \"menuItem\" attribute");
0750: if (!menuItems.add(menuItem))
0751: throw new BuildException(
0752: "\"<service>\" \"menuItem\" value must be unique");
0753:
0754: if (service.getSendTypes().isEmpty()
0755: && service.getReturnTypes().isEmpty())
0756: throw new BuildException(
0757: "\"<service>\" must have either a \"sendTypes\" attribute, a \"returnTypes\" attribute or both");
0758:
0759: String keyEquivalent = service.getKeyEquivalent();
0760: if ((keyEquivalent != null) && (1 != keyEquivalent.length()))
0761: throw new BuildException(
0762: "\"<service>\" \"keyEquivalent\" must be one character if present");
0763:
0764: String timeoutString = service.getTimeout();
0765: if (timeoutString != null) {
0766: long timeout = -1;
0767: try {
0768: timeout = Long.parseLong(timeoutString);
0769: } catch (NumberFormatException nfe) {
0770: throw new BuildException(
0771: "\"<service>\" \"timeout\" must be a positive integral number");
0772: }
0773: if (timeout < 0)
0774: throw new BuildException(
0775: "\"<service>\" \"timeout\" must not be negative");
0776: }
0777:
0778: bundleProperties.addService(service);
0779: }
0780:
0781: public void addConfiguredHelpBook(HelpBook helpBook) {
0782:
0783: // Validity check on 'foldername'
0784: if (helpBook.getFolderName() == null) {
0785: if (bundleProperties.getCFBundleHelpBookFolder() == null)
0786: throw new BuildException(
0787: "Either the '<helpbook>' attribute 'foldername' or the '<jarbundler>' attribute 'helpbookfolder' must be defined");
0788: helpBook.setFolderName(bundleProperties
0789: .getCFBundleHelpBookFolder());
0790: }
0791:
0792: // Validity check on 'title'
0793: if (helpBook.getName() == null) {
0794: if (bundleProperties.getCFBundleHelpBookName() == null)
0795: throw new BuildException(
0796: "Either the '<helpbook>' attribute 'name' or the '<jarbundler>' attribute 'helpbookname' must be defined");
0797: helpBook
0798: .setName(bundleProperties.getCFBundleHelpBookName());
0799: }
0800:
0801: // Make sure some file were selected...
0802: List fileLists = helpBook.getFileLists();
0803: List fileSets = helpBook.getFileSets();
0804:
0805: if (fileLists.isEmpty() && fileSets.isEmpty())
0806: throw new BuildException(
0807: "The '<helpbook>' task must have either "
0808: + "'<fileset>' or '<filelist>' nested tags");
0809:
0810: mHelpBooks.add(helpBook);
0811: }
0812:
0813: /***************************************************************************
0814: * Execute the task
0815: **************************************************************************/
0816:
0817: /**
0818: * The method executing the task
0819: */
0820:
0821: public void execute() throws BuildException {
0822:
0823: // Delete any existing Application bundle directory structure
0824:
0825: bundleDir = new File(mRootDir, bundleProperties
0826: .getApplicationName()
0827: + ".app");
0828:
0829: if (bundleDir.exists()) {
0830: Delete deleteTask = new Delete();
0831: deleteTask.setProject(getProject());
0832: deleteTask.setDir(bundleDir);
0833: deleteTask.execute();
0834: }
0835:
0836: // Validate - look for required attributes
0837: // ///////////////////////////////////////////
0838:
0839: if (mRootDir == null)
0840: throw new BuildException(
0841: "Required attribute \"dir\" is not set.");
0842:
0843: if (mJarAttrs.isEmpty() && mJarFileSets.isEmpty()
0844: && mJarFileLists.isEmpty())
0845: throw new BuildException(
0846: "Either the attribute \"jar\" must "
0847: + "be set, or one or more jarfilelists or "
0848: + "jarfilesets must be added.");
0849:
0850: if (!mJarAttrs.isEmpty()
0851: && (!mJarFileSets.isEmpty() || !mJarFileLists.isEmpty()))
0852: throw new BuildException(
0853: "Cannot set both the attribute "
0854: + "\"jars\" and use jar filesets/filelists. Use only one or the other.");
0855:
0856: if (bundleProperties.getApplicationName() == null)
0857: throw new BuildException(
0858: "Required attribute \"name\" is not set.");
0859:
0860: if (bundleProperties.getMainClass() == null)
0861: throw new BuildException(
0862: "Required attribute \"mainclass\" is not set.");
0863:
0864: // /////////////////////////////////////////////////////////////////////////////////////
0865:
0866: // Set up some Java properties
0867:
0868: // About Menu, deprecated under 1.4+
0869: if (useOldPropertyNames())
0870: bundleProperties.addJavaProperty(ABOUTMENU_KEY,
0871: bundleProperties.getCFBundleName());
0872:
0873: // Anti Aliased Graphics, renamed in 1.4+
0874: String antiAliasedProperty = useOldPropertyNames() ? "com.apple.macosx.AntiAliasedGraphicsOn"
0875: : "apple.awt.antialiasing";
0876:
0877: if (mAntiAliasedGraphics != null)
0878: bundleProperties.addJavaProperty(antiAliasedProperty,
0879: mAntiAliasedGraphics.toString());
0880:
0881: // Anti Aliased Text, renamed in 1.4+
0882: String antiAliasedTextProperty = useOldPropertyNames() ? "com.apple.macosx.AntiAliasedTextOn"
0883: : "apple.awt.textantialiasing";
0884:
0885: if (mAntiAliasedText != null)
0886: bundleProperties.addJavaProperty(antiAliasedTextProperty,
0887: mAntiAliasedText.toString());
0888:
0889: // Live Resize, deprecated under 1.4+
0890: if (useOldPropertyNames() && (mLiveResize != null))
0891: bundleProperties.addJavaProperty(
0892: "com.apple.mrj.application.live-resize",
0893: mLiveResize.toString());
0894:
0895: // Screen Menu Bar, renamed in 1.4+
0896: String screenMenuBarProperty = useOldPropertyNames() ? "com.apple.macos.useScreenMenuBar"
0897: : "apple.laf.useScreenMenuBar";
0898:
0899: if (mScreenMenuBar != null)
0900: bundleProperties.addJavaProperty(screenMenuBarProperty,
0901: mScreenMenuBar.toString());
0902:
0903: // Growbox, added with 1.4+
0904: if ((useOldPropertyNames() == false) && (mGrowbox != null))
0905: bundleProperties.addJavaProperty("apple.awt.showGrowBox",
0906: mGrowbox.toString());
0907:
0908: // Growbox Intrudes, deprecated under 1.4+
0909: if (useOldPropertyNames() && (mGrowboxIntrudes != null))
0910: bundleProperties.addJavaProperty(
0911: "com.apple.mrj.application.growbox.intrudes",
0912: mGrowboxIntrudes.toString());
0913:
0914: if (!mRootDir.exists()
0915: || (mRootDir.exists() && !mRootDir.isDirectory()))
0916: throw new BuildException(
0917: "Destination directory specified by \"dir\" "
0918: + "attribute must already exist.");
0919:
0920: if (bundleDir.exists())
0921: throw new BuildException("The directory/bundle \""
0922: + bundleDir.getName()
0923: + "\" already exists, cannot continue.");
0924:
0925: // Status message
0926: log("Creating application bundle: " + bundleDir);
0927:
0928: if (!bundleDir.mkdir())
0929: throw new BuildException("Unable to create bundle: "
0930: + bundleDir);
0931:
0932: // Make the Contents directory
0933: mContentsDir = new File(bundleDir, "Contents");
0934:
0935: if (!mContentsDir.mkdir())
0936: throw new BuildException("Unable to create directory "
0937: + mContentsDir);
0938:
0939: // Make the "MacOS" directory
0940: mMacOsDir = new File(mContentsDir, "MacOS");
0941:
0942: if (!mMacOsDir.mkdir())
0943: throw new BuildException("Unable to create directory "
0944: + mMacOsDir);
0945:
0946: // Make the Resources directory
0947: mResourcesDir = new File(mContentsDir, "Resources");
0948:
0949: if (!mResourcesDir.mkdir())
0950: throw new BuildException("Unable to create directory "
0951: + mResourcesDir);
0952:
0953: // Make the Resources/Java directory
0954: mJavaDir = new File(mResourcesDir, "Java");
0955:
0956: if (!mJavaDir.mkdir())
0957: throw new BuildException("Unable to create directory "
0958: + mJavaDir);
0959:
0960: // Copy icon file to resource dir. If no icon parameter
0961: // is supplied, the default icon will be used.
0962:
0963: if (mAppIcon != null) {
0964:
0965: try {
0966: File dest = new File(mResourcesDir, mAppIcon.getName());
0967:
0968: if (mVerbose)
0969: log("Copying application icon file to \""
0970: + bundlePath(dest) + "\"");
0971:
0972: mFileUtils.copyFile(mAppIcon, dest);
0973: } catch (IOException ex) {
0974: throw new BuildException("Cannot copy icon file: " + ex);
0975: }
0976: }
0977:
0978: // Copy document type icons, if any, to the resource dir
0979: try {
0980: Iterator itor = bundleProperties.getDocumentTypes()
0981: .iterator();
0982:
0983: while (itor.hasNext()) {
0984: DocumentType documentType = (DocumentType) itor.next();
0985: File iconFile = documentType.getIconFile();
0986: if (iconFile != null) {
0987: File dest = new File(mResourcesDir, iconFile
0988: .getName());
0989: if (mVerbose)
0990: log("Copying document icon file to \""
0991: + bundlePath(dest) + "\"");
0992: mFileUtils.copyFile(iconFile, dest);
0993: }
0994: }
0995: } catch (IOException ex) {
0996: throw new BuildException("Cannot copy document icon file: "
0997: + ex);
0998: }
0999:
1000: // Copy application jar(s) from the "jars" attribute (if any)
1001: processJarAttrs();
1002:
1003: // Copy application jar(s) from the nested jarfileset element(s)
1004: processJarFileSets();
1005:
1006: // Copy application jar(s) from the nested jarfilelist element(s)
1007: processJarFileLists();
1008:
1009: // Copy executable(s) from the "execs" attribute (if any)
1010: processExecAttrs();
1011:
1012: // Copy executable(s) from the nested execfileset element(s)
1013: processExecFileSets();
1014:
1015: // Copy executable(s) from the nested execfilelist element(s)
1016: processExecFileLists();
1017:
1018: // Copy resource(s) from the nested resourcefileset element(s)
1019: processResourceFileSets();
1020:
1021: // Copy resource(s) from the nested javafileset element(s)
1022: processJavaFileSets();
1023:
1024: // Copy resource(s) from the nested resourcefilelist element(s)
1025: processResourceFileLists();
1026:
1027: // Copy resource(s) from the nested javafilelist element(s)
1028: processJavaFileLists();
1029:
1030: // Add external classpath references from the extraclasspath attributes
1031: processExtraClassPathAttrs();
1032:
1033: // Add external classpath references from the nested
1034: // extraclasspathfileset element(s)
1035: processExtraClassPathFileSets();
1036:
1037: // Add external classpath references from the nested
1038: // extraclasspathfilelist attributes
1039: processExtraClassPathFileLists();
1040:
1041: // Copy HelpBooks into place
1042: copyHelpBooks();
1043:
1044: // Copy the JavaApplicationStub file from the Java system directory to
1045: // the MacOS directory
1046: copyApplicationStub();
1047:
1048: // Create the Info.plist file
1049: writeInfoPlist();
1050:
1051: // Create the PkgInfo file
1052: writePkgInfo();
1053:
1054: // Done!
1055: }
1056:
1057: /***************************************************************************
1058: * Private utility methods.
1059: **************************************************************************/
1060:
1061: private void setExecutable(File f) {
1062:
1063: Chmod chmodTask = new Chmod();
1064: chmodTask.setProject(getProject());
1065: chmodTask.setFile(f);
1066: chmodTask.setPerm("ugo+rx");
1067:
1068: if (mVerbose)
1069: log("Setting \"" + bundlePath(f) + "\" to executable");
1070:
1071: chmodTask.execute();
1072:
1073: }
1074:
1075: /**
1076: * Utility method to determine whether this app bundle is targeting a 1.3 or
1077: * 1.4 VM. The Mac OS X 1.3 VM uses different Java property names from the
1078: * 1.4 VM to hint at native Mac OS X look and feel options. For example, on
1079: * 1.3 the Java property to tell the VM to display Swing menu bars as screen
1080: * menus is "com.apple.macos.useScreenMenuBar". Under 1.4, it becomes
1081: * "apple.laf.useScreenMenuBar". Such is the price of progress, I suppose.
1082: *
1083: * Obviously, this logic may need refactoring in the future.
1084: */
1085:
1086: private boolean useOldPropertyNames() {
1087: return (bundleProperties.getJVMVersion().startsWith("1.3"));
1088: }
1089:
1090: private void processJarAttrs() throws BuildException {
1091:
1092: try {
1093:
1094: for (Iterator jarIter = mJarAttrs.iterator(); jarIter
1095: .hasNext();) {
1096: File src = (File) jarIter.next();
1097: File dest = new File(mJavaDir, src.getName());
1098:
1099: if (mVerbose)
1100: log("Copying JAR file to \"" + bundlePath(dest)
1101: + "\"");
1102:
1103: mFileUtils.copyFile(src, dest);
1104: bundleProperties.addToClassPath(dest.getName());
1105: }
1106: } catch (IOException ex) {
1107: throw new BuildException("Cannot copy jar file: " + ex);
1108: }
1109: }
1110:
1111: private void processJarFileSets() throws BuildException {
1112:
1113: for (Iterator jarIter = mJarFileSets.iterator(); jarIter
1114: .hasNext();) {
1115:
1116: FileSet fs = (FileSet) jarIter.next();
1117:
1118: Project p = fs.getProject();
1119: File srcDir = fs.getDir(p);
1120: FileScanner ds = fs.getDirectoryScanner(p);
1121: fs.setupDirectoryScanner(ds, p);
1122: ds.scan();
1123:
1124: String[] files = ds.getIncludedFiles();
1125:
1126: try {
1127:
1128: for (int i = 0; i < files.length; i++) {
1129: String fileName = files[i];
1130: File src = new File(srcDir, fileName);
1131: File dest = new File(mJavaDir, fileName);
1132:
1133: if (mVerbose)
1134: log("Copying JAR file to \"" + bundlePath(dest)
1135: + "\"");
1136:
1137: mFileUtils.copyFile(src, dest);
1138: bundleProperties.addToClassPath(fileName);
1139: }
1140:
1141: } catch (IOException ex) {
1142: throw new BuildException("Cannot copy jar file: " + ex);
1143: }
1144: }
1145: }
1146:
1147: private void processJarFileLists() throws BuildException {
1148:
1149: for (Iterator jarIter = mJarFileLists.iterator(); jarIter
1150: .hasNext();) {
1151: FileList fl = (FileList) jarIter.next();
1152: Project p = fl.getProject();
1153: File srcDir = fl.getDir(p);
1154: String[] files = fl.getFiles(p);
1155:
1156: try {
1157:
1158: for (int i = 0; i < files.length; i++) {
1159: String fileName = files[i];
1160: File src = new File(srcDir, fileName);
1161: File dest = new File(mJavaDir, fileName);
1162:
1163: if (mVerbose)
1164: log("Copying JAR file to \"" + bundlePath(dest)
1165: + "\"");
1166:
1167: mFileUtils.copyFile(src, dest);
1168: bundleProperties.addToClassPath(fileName);
1169: }
1170: } catch (IOException ex) {
1171: throw new BuildException("Cannot copy jar file: " + ex);
1172: }
1173: }
1174: }
1175:
1176: private void processExtraClassPathAttrs() throws BuildException {
1177:
1178: for (Iterator jarIter = mExtraClassPathAttrs.iterator(); jarIter
1179: .hasNext();) {
1180: File src = (File) jarIter.next();
1181: bundleProperties.addToExtraClassPath(src.getPath());
1182: }
1183: }
1184:
1185: private void processExtraClassPathFileSets() throws BuildException {
1186:
1187: for (Iterator jarIter = mExtraClassPathFileSets.iterator(); jarIter
1188: .hasNext();) {
1189: FileSet fs = (FileSet) jarIter.next();
1190: Project p = fs.getProject();
1191: File srcDir = fs.getDir(p);
1192: FileScanner ds = fs.getDirectoryScanner(p);
1193: fs.setupDirectoryScanner(ds, p);
1194: ds.scan();
1195:
1196: String[] files = ds.getIncludedFiles();
1197:
1198: for (int i = 0; i < files.length; i++) {
1199: File f = new File(srcDir, files[i]);
1200: bundleProperties.addToExtraClassPath(f.getPath());
1201: }
1202: }
1203: }
1204:
1205: private void processExtraClassPathFileLists() throws BuildException {
1206:
1207: for (Iterator jarIter = mExtraClassPathFileLists.iterator(); jarIter
1208: .hasNext();) {
1209: FileList fl = (FileList) jarIter.next();
1210: Project p = fl.getProject();
1211: File srcDir = fl.getDir(p);
1212: String[] files = fl.getFiles(p);
1213:
1214: for (int i = 0; i < files.length; i++) {
1215: File f = new File(srcDir, files[i]);
1216: bundleProperties.addToExtraClassPath(f.getPath());
1217: }
1218: }
1219: }
1220:
1221: private void processExecAttrs() throws BuildException {
1222:
1223: try {
1224:
1225: for (Iterator execIter = mExecAttrs.iterator(); execIter
1226: .hasNext();) {
1227: File src = (File) execIter.next();
1228: File dest = new File(mMacOsDir, src.getName());
1229:
1230: if (mVerbose)
1231: log("Copying exec file to \"" + bundlePath(dest)
1232: + "\"");
1233:
1234: mFileUtils.copyFile(src, dest);
1235: setExecutable(dest);
1236: }
1237: } catch (IOException ex) {
1238: throw new BuildException("Cannot copy exec file: " + ex);
1239: }
1240: }
1241:
1242: // Methods for copying FileSets into the application bundle ///////////////////////////////
1243:
1244: // Files for the Contents/MacOS directory
1245: private void processExecFileSets() {
1246: processCopyingFileSets(mExecFileSets, mMacOsDir, true);
1247: }
1248:
1249: // Files for the Contents/Resources directory
1250: private void processResourceFileSets() {
1251: processCopyingFileSets(mResourceFileSets, mResourcesDir, false);
1252: }
1253:
1254: // Files for the Contents/Resources/Java directory
1255: private void processJavaFileSets() {
1256: processCopyingFileSets(mJavaFileSets, mJavaDir, false);
1257: }
1258:
1259: private void processCopyingFileSets(List fileSets, File targetdir,
1260: boolean setExec) {
1261:
1262: for (Iterator execIter = fileSets.iterator(); execIter
1263: .hasNext();) {
1264: FileSet fs = (FileSet) execIter.next();
1265: Project p = fs.getProject();
1266: File srcDir = fs.getDir(p);
1267: FileScanner ds = fs.getDirectoryScanner(p);
1268: fs.setupDirectoryScanner(ds, p);
1269: ds.scan();
1270:
1271: String[] files = ds.getIncludedFiles();
1272:
1273: if (files.length == 0) {
1274: // this is probably an error -- warn about it
1275: System.err
1276: .println("WARNING: fileset for copying from directory "
1277: + srcDir + ": no files found");
1278: } else {
1279: try {
1280: for (int i = 0; i < files.length; i++) {
1281: String fileName = files[i];
1282: File src = new File(srcDir, fileName);
1283: File dest = new File(targetdir, fileName);
1284:
1285: if (mVerbose)
1286: log("Copying "
1287: + (setExec ? "exec" : "resource")
1288: + " file to \"" + bundlePath(dest)
1289: + "\"");
1290:
1291: mFileUtils.copyFile(src, dest);
1292: if (setExec)
1293: setExecutable(dest);
1294: }
1295: } catch (IOException ex) {
1296: throw new BuildException("Cannot copy file: " + ex);
1297: }
1298: }
1299: }
1300: }
1301:
1302: // Methods for copying FileLists into the application bundle /////////////////////////////
1303:
1304: // Files for the Contents/MacOS directory
1305: private void processExecFileLists() throws BuildException {
1306: processCopyingFileLists(mExecFileLists, mMacOsDir, true);
1307: }
1308:
1309: // Files for the Contents/Resources directory
1310: private void processResourceFileLists() throws BuildException {
1311: processCopyingFileLists(mResourceFileLists, mResourcesDir,
1312: false);
1313: }
1314:
1315: // Files for the Contents/Resources/Java directory
1316: private void processJavaFileLists() throws BuildException {
1317: processCopyingFileLists(mJavaFileLists, mJavaDir, false);
1318: }
1319:
1320: private void processCopyingFileLists(List fileLists,
1321: File targetDir, boolean setExec) throws BuildException {
1322:
1323: for (Iterator execIter = fileLists.iterator(); execIter
1324: .hasNext();) {
1325:
1326: FileList fl = (FileList) execIter.next();
1327: Project p = fl.getProject();
1328: File srcDir = fl.getDir(p);
1329: String[] files = fl.getFiles(p);
1330:
1331: if (files.length == 0) {
1332: // this is probably an error -- warn about it
1333: System.err
1334: .println("WARNING: filelist for copying from directory "
1335: + srcDir + ": no files found");
1336: } else {
1337: try {
1338: for (int i = 0; i < files.length; i++) {
1339: String fileName = files[i];
1340: File src = new File(srcDir, fileName);
1341: File dest = new File(targetDir, fileName);
1342:
1343: if (mVerbose)
1344: log("Copying "
1345: + (setExec ? "exec" : "resource")
1346: + " file to \"" + bundlePath(dest)
1347: + "\"");
1348:
1349: mFileUtils.copyFile(src, dest);
1350: if (setExec)
1351: setExecutable(dest);
1352: }
1353: } catch (IOException ex) {
1354: throw new BuildException("Cannot copy jar file: "
1355: + ex);
1356: }
1357: }
1358: }
1359: }
1360:
1361: private void copyHelpBooks() {
1362:
1363: for (Iterator itor = mHelpBooks.iterator(); itor.hasNext();) {
1364:
1365: HelpBook helpBook = (HelpBook) itor.next();
1366:
1367: String folderName = helpBook.getFolderName();
1368: String name = helpBook.getName();
1369: String locale = helpBook.getLocale();
1370:
1371: List fileLists = helpBook.getFileLists();
1372: List fileSets = helpBook.getFileSets();
1373:
1374: File helpBookDir = null;
1375:
1376: if (locale == null) {
1377:
1378: // Set the Bundle entries for a nonlocalized Help Book
1379: if (folderName != null)
1380: bundleProperties
1381: .setCFBundleHelpBookFolder(folderName);
1382:
1383: if (name != null)
1384: bundleProperties.setCFBundleHelpBookName(name);
1385:
1386: // The non-localized Help Book is top level "/Resources"
1387: helpBookDir = new File(mResourcesDir, folderName);
1388: helpBookDir.mkdir();
1389:
1390: if (mVerbose)
1391: log("Creating Help Book at \""
1392: + bundlePath(helpBookDir) + "\"");
1393:
1394: } else {
1395:
1396: // The localized Help Book is "/Resources/locale.lproj"
1397:
1398: File lproj = new File(mResourcesDir, locale + ".lproj");
1399: lproj.mkdir();
1400: helpBookDir = new File(lproj, folderName);
1401: helpBookDir.mkdir();
1402:
1403: if (mVerbose)
1404: log("Creating Help Book for \"" + locale
1405: + "\" at \"" + bundlePath(helpBookDir)
1406: + "\"");
1407:
1408: // Create a local file to override the Bundle settings
1409: File infoPList = new File(lproj, "InfoPlist.strings");
1410: PrintWriter writer = null;
1411: try {
1412: writer = new PrintWriter(new FileWriter(infoPList));
1413: writer.println("CFBundleHelpBookFolder = \""
1414: + folderName + "\";");
1415: writer.println("CFBundleHelpBookName = \"" + name
1416: + "\";");
1417: writer.println("CFBundleName = \""
1418: + bundleProperties.getCFBundleName()
1419: + "\";");
1420: } catch (IOException ioe) {
1421: throw new BuildException(
1422: "IOException in writing Help Book locale: "
1423: + locale);
1424: } finally {
1425: mFileUtils.close(writer);
1426: }
1427: }
1428:
1429: // Write the Help Book source files into the bundle
1430:
1431: processCopyingFileSets(fileSets, helpBookDir, false);
1432: processCopyingFileLists(fileLists, helpBookDir, false);
1433:
1434: }
1435: }
1436:
1437: // Copy the application stub into the bundle
1438: // /////////////////////////////////////////////
1439:
1440: private void copyApplicationStub() throws BuildException {
1441:
1442: File newStubFile = new File(mMacOsDir, bundleProperties
1443: .getCFBundleExecutable());
1444:
1445: if (mVerbose)
1446: log("Copying Java application stub to \""
1447: + bundlePath(newStubFile) + "\"");
1448:
1449: try {
1450: mFileUtils.copyFile(mStubFile, newStubFile);
1451: } catch (IOException ex) {
1452: throw new BuildException(
1453: "Cannot copy Java Application Stub: " + ex);
1454: }
1455:
1456: // Set the permissions on the stub file to executable
1457:
1458: setExecutable(newStubFile);
1459: }
1460:
1461: private void writeInfoPlist() throws BuildException {
1462: PropertyListWriter listWriter = new PropertyListWriter(
1463: bundleProperties);
1464: File infoPlist = new File(mContentsDir, "Info.plist");
1465:
1466: listWriter.writeFile(infoPlist);
1467:
1468: if (mVerbose)
1469: log("Creating \"" + bundlePath(infoPlist) + "\" file");
1470:
1471: if (mShowPlist) {
1472: try {
1473: BufferedReader in = new BufferedReader(new FileReader(
1474: infoPlist));
1475: String str;
1476: while ((str = in.readLine()) != null)
1477: log(str);
1478: in.close();
1479: } catch (IOException e) {
1480: throw new BuildException(e);
1481: }
1482: }
1483: }
1484:
1485: //
1486: // Write the PkgInfo file into the application bundle
1487: //
1488:
1489: private void writePkgInfo() throws BuildException {
1490: File pkgInfo = new File(mContentsDir, "PkgInfo");
1491: PrintWriter writer = null;
1492:
1493: try {
1494: writer = new PrintWriter(new BufferedWriter(new FileWriter(
1495: pkgInfo)));
1496: writer.print(bundleProperties.getCFBundlePackageType());
1497: writer.println(bundleProperties.getCFBundleSignature());
1498: writer.flush();
1499: } catch (IOException ex) {
1500: throw new BuildException("Cannot create PkgInfo file: "
1501: + ex);
1502: } finally {
1503: mFileUtils.close(writer);
1504: }
1505: }
1506:
1507: private String bundlePath(File bundleFile) {
1508:
1509: String rootPath = bundleDir.getAbsolutePath();
1510: String thisPath = bundleFile.getAbsolutePath();
1511:
1512: return thisPath.substring(rootPath.length());
1513:
1514: }
1515: }
|