mirror of
https://github.com/processing/processing4.git
synced 2026-02-13 10:30:44 +01:00
Merge branch 'master' of https://github.com/processing/processing.git
This commit is contained in:
2
build/macosx/appbundler/.gitignore
vendored
Normal file
2
build/macosx/appbundler/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
bin
|
||||
|
||||
85
build/macosx/appbundler/README.md
Normal file
85
build/macosx/appbundler/README.md
Normal file
@@ -0,0 +1,85 @@
|
||||
appbundler
|
||||
=============
|
||||
|
||||
A fork of the [Java Application Bundler](https://svn.java.net/svn/appbundler~svn)
|
||||
with the following changes:
|
||||
|
||||
- The native binary is created as universal (32/64)
|
||||
- Fixes [icon not showing bug](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7159381) in `JavaAppLauncher`
|
||||
- Adds `LC_CTYPE` environment variable to the `Info.plist` file in order to fix an [issue with `File.exists()` in OpenJDK 7](http://java.net/jira/browse/MACOSX_PORT-165) **(Contributed by Steve Hannah)**
|
||||
- Allows to specify the name of the executable instead of using the default `"JavaAppLauncher"` **(contributed by Karl von Randow)**
|
||||
- Adds `classpathref` support to the `bundleapp` task
|
||||
- Adds support for `JVMArchs` and `LSArchitecturePriority` keys
|
||||
- Allows to specify a custom value for `CFBundleVersion`
|
||||
- Allows specifying registered file extensions using `CFBundleDocumentTypes`
|
||||
- Passes to the Java application a set of environment variables with the paths of
|
||||
the OSX special folders and whether the application is running in the
|
||||
sandbox (see below).
|
||||
|
||||
These are the environment variables passed to the JVM:
|
||||
|
||||
- `LibraryDirectory`
|
||||
- `DocumentsDirectory`
|
||||
- `CachesDirectory`
|
||||
- `ApplicationSupportDirectory`
|
||||
- `SandboxEnabled` (the String `true` or `false`)
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
<target name="bundle">
|
||||
<taskdef name="bundleapp"
|
||||
classpath="appbundler-1.0ea.jar"
|
||||
classname="com.oracle.appbundler.AppBundlerTask"/>
|
||||
|
||||
<bundleapp
|
||||
classpathref="runclasspathref"
|
||||
outputdirectory="${dist}"
|
||||
name="${bundle.name}"
|
||||
displayname="${bundle.displayname}"
|
||||
executableName="MyApp"
|
||||
identifier="com.company.product"
|
||||
shortversion="${version.public}"
|
||||
version="${version.internal}"
|
||||
icon="${bundle.icon}"
|
||||
mainclassname="Main"
|
||||
copyright="2012 Your Company"
|
||||
applicationCategory="public.app-category.finance">
|
||||
|
||||
<runtime dir="${runtime}/Contents/Home"/>
|
||||
|
||||
<arch name="x86_64"/>
|
||||
<arch name="i386"/>
|
||||
|
||||
<bundledocument extensions="png,jpg"
|
||||
icon="${bundle.icon}"
|
||||
name="Images"
|
||||
role="editor">
|
||||
</bundledocument>
|
||||
|
||||
<bundledocument extensions="pdf"
|
||||
icon="${bundle.icon}"
|
||||
name="PDF files"
|
||||
role="viewer">
|
||||
</bundledocument>
|
||||
|
||||
<bundledocument extensions="custom"
|
||||
icon="${bundle.icon}"
|
||||
name="Custom data"
|
||||
role="editor"
|
||||
isPackage="true">
|
||||
</bundledocument>
|
||||
|
||||
<!-- Workaround since the icon parameter for bundleapp doesn't work -->
|
||||
<option value="-Xdock:icon=Contents/Resources/${bundle.icon}"/>
|
||||
|
||||
<option value="-Dapple.laf.useScreenMenuBar=true"/>
|
||||
<option value="-Dcom.apple.macos.use-file-dialog-packages=true"/>
|
||||
<option value="-Dcom.apple.macos.useScreenMenuBar=true"/>
|
||||
<option value="-Dcom.apple.mrj.application.apple.menu.about.name=${bundle.name}"/>
|
||||
<option value="-Dcom.apple.smallTabs=true"/>
|
||||
<option value="-Dfile.encoding=UTF-8"/>
|
||||
|
||||
<option value="-Xmx1024M"/>
|
||||
</bundleapp>
|
||||
</target>
|
||||
3
build/macosx/appbundler/TODO
Normal file
3
build/macosx/appbundler/TODO
Normal file
@@ -0,0 +1,3 @@
|
||||
- Architectures should be automatically inferred from the embedded JVM
|
||||
- It makes more sense to take as input a JRE instead of taking a JDK and strip
|
||||
it until it becomes a JRE...
|
||||
176
build/macosx/appbundler/build.xml
Normal file
176
build/macosx/appbundler/build.xml
Normal file
@@ -0,0 +1,176 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
|
||||
This code is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License version 2 only, as
|
||||
published by the Free Software Foundation. Oracle designates this
|
||||
particular file as subject to the "Classpath" exception as provided
|
||||
by Oracle in the LICENSE file that accompanied this code.
|
||||
|
||||
This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
version 2 for more details (a copy is included in the LICENSE file that
|
||||
accompanied this code).
|
||||
|
||||
You should have received a copy of the GNU General Public License version
|
||||
2 along with this work; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
or visit www.oracle.com if you need additional information or have any
|
||||
questions.
|
||||
-->
|
||||
|
||||
<project name="appbundler" default="package">
|
||||
<property environment="env"/>
|
||||
|
||||
<!--
|
||||
<property file="build.properties"/>
|
||||
version=1.0ea
|
||||
-->
|
||||
<property name="arch64" value="-arch x86_64" />
|
||||
<property name="arch32" value="-arch i386" />
|
||||
<property name="archppc" value="-arch ppc" />
|
||||
<property name="cc" value="gcc" />
|
||||
|
||||
<property name="folder.src" value="src"/>
|
||||
<property name="folder.native" value="native"/>
|
||||
<property name="folder.bin" value="bin"/>
|
||||
<!-- <property name="folder.classes" value="${folder.bin}/classes"/>-->
|
||||
<property name="folder.classes" value="${folder.bin}"/>
|
||||
<property name="folder.res" value="res"/>
|
||||
|
||||
<!-- Compile target -->
|
||||
<target name="compile">
|
||||
<mkdir dir="${folder.classes}"/>
|
||||
<javac destDir="${folder.classes}"
|
||||
includejavaruntime="true"
|
||||
includeantruntime="true"
|
||||
deprecation="true"
|
||||
debug="true"
|
||||
encoding="UTF-8"
|
||||
failonerror="true">
|
||||
<src>
|
||||
<dirset dir=".">
|
||||
<include name="${folder.src}"/>
|
||||
</dirset>
|
||||
</src>
|
||||
<compilerarg line="-Xlint:all"/>
|
||||
<classpath>
|
||||
<dirset dir="${basedir}" includes="**/${folder.classes}"/>
|
||||
<fileset dir="." includes="lib/**/*.jar"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
<copy todir="${folder.classes}" includeEmptyDirs="false">
|
||||
<fileset dir="${folder.src}">
|
||||
<exclude name="**/*.java"/>
|
||||
<exclude name="**/package.html"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
|
||||
<exec executable="${cc}">
|
||||
<arg line="${arch64} ${arch32}"/>
|
||||
<arg value="-I"/>
|
||||
<arg value="${env.JAVA_HOME}/include"/>
|
||||
<arg value="-I"/>
|
||||
<arg value="${env.JAVA_HOME}/include/darwin"/>
|
||||
<arg value="-o"/>
|
||||
<arg value="${folder.classes}/com/oracle/appbundler/JavaAppLauncher"/>
|
||||
<arg value="-framework"/>
|
||||
<arg value="Cocoa"/>
|
||||
<arg value="-F"/>
|
||||
<arg value="${env.JAVA_HOME}/../.."/>
|
||||
<arg value="-isysroot"/>
|
||||
<arg value="/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk"/>
|
||||
<arg value="-mmacosx-version-min=10.7"/>
|
||||
<arg value="native/main.m"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Clean target -->
|
||||
<target name="clean">
|
||||
<delete dir="${folder.bin}"/>
|
||||
<delete dir="HelloWorld.app"/>
|
||||
<delete dir="SwingSet2.app"/>
|
||||
<delete dir="SwingSet2Plugin.app"/>
|
||||
</target>
|
||||
|
||||
<!-- Package target -->
|
||||
<target name="package" depends="compile">
|
||||
<zip destfile="${folder.classes}/com/oracle/appbundler/res.zip">
|
||||
<fileset dir="${folder.res}"/>
|
||||
</zip>
|
||||
|
||||
<jar destfile="../${ant.project.name}.jar" index="true">
|
||||
<manifest>
|
||||
<attribute name="Implementation-Vendor-Id" value="com.oracle"/>
|
||||
<attribute name="Implementation-Vendor" value="Oracle"/>
|
||||
<attribute name="Implementation-Title" value="App Bundler Ant Task"/>
|
||||
<attribute name="Implementation-Version" value="${version}"/>
|
||||
</manifest>
|
||||
<fileset dir="${folder.classes}"/>
|
||||
<fileset dir="${folder.bin}">
|
||||
<include name="JavaAppLauncher"/>
|
||||
<include name="*.zip"/>
|
||||
</fileset>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<!-- Test targets -->
|
||||
<target name="test" depends="package">
|
||||
<taskdef name="bundleapp" classname="com.oracle.appbundler.AppBundlerTask"
|
||||
classpath="${folder.bin}/${ant.project.name}.jar"/>
|
||||
|
||||
<bundleapp outputdirectory="."
|
||||
name="Test"
|
||||
displayname="Test"
|
||||
identifier="com.oracle.javafx.swing.Test"
|
||||
shortversion="1.0"
|
||||
applicationCategory="public.app-category.developer-tools"
|
||||
mainclassname="com/javafx/main/Main">
|
||||
<runtime dir="${env.JAVA_HOME}"/>
|
||||
<classpath file="${user.home}/bin/javafx-samples-2.2.0/SwingInterop.jar"/>
|
||||
<option value="-Dapple.laf.useScreenMenuBar=true"/>
|
||||
<argument value="foo=bar"/>
|
||||
</bundleapp>
|
||||
</target>
|
||||
|
||||
<target name="test-plugin" depends="package">
|
||||
<taskdef name="bundleapp" classname="com.oracle.appbundler.AppBundlerTask"
|
||||
classpath="${folder.bin}/${ant.project.name}.jar"/>
|
||||
|
||||
<bundleapp outputdirectory="."
|
||||
name="TestPlugin"
|
||||
displayname="Test (Plugin)"
|
||||
identifier="com.oracle.javafx.swing.TestPlugin"
|
||||
shortversion="1.0"
|
||||
applicationCategory="public.app-category.developer-tools"
|
||||
mainclassname="com/javafx/main/Main">
|
||||
<classpath file="${user.home}/bin/javafx-samples-2.2.0/SwingInterop.jar"/>
|
||||
<option value="-Dapple.laf.useScreenMenuBar=true"/>
|
||||
<argument value="foo=bar"/>
|
||||
</bundleapp>
|
||||
</target>
|
||||
|
||||
<!-- Trim whitespace target -->
|
||||
<target name="trim-whitespace">
|
||||
<fileset id="trimfiles" dir=".">
|
||||
<include name="**/*.h"/>
|
||||
<include name="**/*.html"/>
|
||||
<include name="**/*.java"/>
|
||||
<include name="**/*.m"/>
|
||||
<include name="**/*.strings"/>
|
||||
<include name="**/*.xml"/>
|
||||
</fileset>
|
||||
<replaceregexp match="[\t]" replace=" " flags="gm" byline="true">
|
||||
<fileset refid="trimfiles"/>
|
||||
</replaceregexp>
|
||||
<replaceregexp match="[\t ]+$" replace="" flags="gm" byline="true">
|
||||
<fileset refid="trimfiles"/>
|
||||
</replaceregexp>
|
||||
</target>
|
||||
</project>
|
||||
243
build/macosx/appbundler/native/main.m
Normal file
243
build/macosx/appbundler/native/main.m
Normal file
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <dlfcn.h>
|
||||
#include <jni.h>
|
||||
|
||||
#define JAVA_LAUNCH_ERROR "JavaLaunchError"
|
||||
|
||||
#define JVM_RUNTIME_KEY "JVMRuntime"
|
||||
#define WORKING_DIR "WorkingDirectory"
|
||||
#define JVM_MAIN_CLASS_NAME_KEY "JVMMainClassName"
|
||||
#define JVM_OPTIONS_KEY "JVMOptions"
|
||||
#define JVM_ARGUMENTS_KEY "JVMArguments"
|
||||
|
||||
#define JVM_RUN_PRIVILEGED "JVMRunPrivileged"
|
||||
|
||||
#define UNSPECIFIED_ERROR "An unknown error occurred."
|
||||
|
||||
#define APP_ROOT_PREFIX "$APP_ROOT"
|
||||
|
||||
#define LIBJLI_DYLIB "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/jli/libjli.dylib"
|
||||
|
||||
typedef int (JNICALL *JLI_Launch_t)(int argc, char ** argv,
|
||||
int jargc, const char** jargv,
|
||||
int appclassc, const char** appclassv,
|
||||
const char* fullversion,
|
||||
const char* dotversion,
|
||||
const char* pname,
|
||||
const char* lname,
|
||||
jboolean javaargs,
|
||||
jboolean cpwildcard,
|
||||
jboolean javaw,
|
||||
jint ergo);
|
||||
|
||||
int launch(char *);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
int result;
|
||||
@try {
|
||||
launch(argv[0]);
|
||||
result = 0;
|
||||
} @catch (NSException *exception) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setAlertStyle:NSCriticalAlertStyle];
|
||||
[alert setMessageText:[exception reason]];
|
||||
[alert runModal];
|
||||
|
||||
result = 1;
|
||||
}
|
||||
|
||||
[pool drain];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int launch(char *commandName) {
|
||||
// Get the main bundle
|
||||
NSBundle *mainBundle = [NSBundle mainBundle];
|
||||
|
||||
// Get the main bundle's info dictionary
|
||||
NSDictionary *infoDictionary = [mainBundle infoDictionary];
|
||||
|
||||
// Set the working directory based on config, defaulting to the user's home directory
|
||||
NSString *workingDir = [infoDictionary objectForKey:@WORKING_DIR];
|
||||
if (workingDir != nil) {
|
||||
workingDir = [workingDir stringByReplacingOccurrencesOfString:@APP_ROOT_PREFIX withString:[mainBundle bundlePath]];
|
||||
} else {
|
||||
workingDir = NSHomeDirectory();
|
||||
}
|
||||
|
||||
chdir([workingDir UTF8String]);
|
||||
|
||||
// execute privileged
|
||||
NSString *privileged = [infoDictionary objectForKey:@JVM_RUN_PRIVILEGED];
|
||||
if ( privileged != nil && getuid() != 0 ) {
|
||||
NSDictionary *error = [NSDictionary new];
|
||||
NSString *script = [NSString stringWithFormat:@"do shell script \"\\\"%@\\\" > /dev/null 2>&1 &\" with administrator privileges", [NSString stringWithCString:commandName encoding:NSASCIIStringEncoding]];
|
||||
NSAppleScript *appleScript = [[NSAppleScript new] initWithSource:script];
|
||||
if ([appleScript executeAndReturnError:&error]) {
|
||||
// This means we successfully elevated the application and can stop in here.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Locate the JLI_Launch() function
|
||||
NSString *runtime = [infoDictionary objectForKey:@JVM_RUNTIME_KEY];
|
||||
|
||||
const char *libjliPath = NULL;
|
||||
if (runtime != nil) {
|
||||
NSString *runtimePath = [[[NSBundle mainBundle] builtInPlugInsPath] stringByAppendingPathComponent:runtime];
|
||||
libjliPath = [[runtimePath stringByAppendingPathComponent:@"Contents/Home/jre/lib/jli/libjli.dylib"] fileSystemRepresentation];
|
||||
} else {
|
||||
libjliPath = LIBJLI_DYLIB;
|
||||
}
|
||||
|
||||
void *libJLI = dlopen(libjliPath, RTLD_LAZY);
|
||||
|
||||
JLI_Launch_t jli_LaunchFxnPtr = NULL;
|
||||
if (libJLI != NULL) {
|
||||
jli_LaunchFxnPtr = dlsym(libJLI, "JLI_Launch");
|
||||
}
|
||||
|
||||
if (jli_LaunchFxnPtr == NULL) {
|
||||
[[NSException exceptionWithName:@JAVA_LAUNCH_ERROR
|
||||
reason:NSLocalizedString(@"JRELoadError", @UNSPECIFIED_ERROR)
|
||||
userInfo:nil] raise];
|
||||
}
|
||||
|
||||
// Get the main class name
|
||||
NSString *mainClassName = [infoDictionary objectForKey:@JVM_MAIN_CLASS_NAME_KEY];
|
||||
if (mainClassName == nil) {
|
||||
[[NSException exceptionWithName:@JAVA_LAUNCH_ERROR
|
||||
reason:NSLocalizedString(@"MainClassNameRequired", @UNSPECIFIED_ERROR)
|
||||
userInfo:nil] raise];
|
||||
}
|
||||
|
||||
// Set the class path
|
||||
NSString *mainBundlePath = [mainBundle bundlePath];
|
||||
NSString *javaPath = [mainBundlePath stringByAppendingString:@"/Contents/Java"];
|
||||
NSMutableString *classPath = [NSMutableString stringWithFormat:@"-Djava.class.path=%@/Classes", javaPath];
|
||||
|
||||
NSFileManager *defaultFileManager = [NSFileManager defaultManager];
|
||||
NSArray *javaDirectoryContents = [defaultFileManager contentsOfDirectoryAtPath:javaPath error:nil];
|
||||
if (javaDirectoryContents == nil) {
|
||||
[[NSException exceptionWithName:@JAVA_LAUNCH_ERROR
|
||||
reason:NSLocalizedString(@"JavaDirectoryNotFound", @UNSPECIFIED_ERROR)
|
||||
userInfo:nil] raise];
|
||||
}
|
||||
|
||||
for (NSString *file in javaDirectoryContents) {
|
||||
if ([file hasSuffix:@".jar"]) {
|
||||
[classPath appendFormat:@":%@/%@", javaPath, file];
|
||||
}
|
||||
}
|
||||
|
||||
// Set the library path
|
||||
NSString *libraryPath = [NSString stringWithFormat:@"-Djava.library.path=%@/Contents/MacOS", mainBundlePath];
|
||||
|
||||
// Get the VM options
|
||||
NSArray *options = [infoDictionary objectForKey:@JVM_OPTIONS_KEY];
|
||||
if (options == nil) {
|
||||
options = [NSArray array];
|
||||
}
|
||||
|
||||
// Get the application arguments
|
||||
NSArray *arguments = [infoDictionary objectForKey:@JVM_ARGUMENTS_KEY];
|
||||
if (arguments == nil) {
|
||||
arguments = [NSArray array];
|
||||
}
|
||||
|
||||
// Set OSX special folders
|
||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
|
||||
NSUserDomainMask, YES);
|
||||
NSString *basePath = [paths objectAtIndex:0];
|
||||
NSString *libraryDirectory = [NSString stringWithFormat:@"-DLibraryDirectory=%@", basePath];
|
||||
|
||||
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
|
||||
NSUserDomainMask, YES);
|
||||
basePath = [paths objectAtIndex:0];
|
||||
NSString *documentsDirectory = [NSString stringWithFormat:@"-DDocumentsDirectory=%@", basePath];
|
||||
|
||||
paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory,
|
||||
NSUserDomainMask, YES);
|
||||
basePath = [paths objectAtIndex:0];
|
||||
NSString *applicationSupportDirectory = [NSString stringWithFormat:@"-DApplicationSupportDirectory=%@", basePath];
|
||||
|
||||
paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
|
||||
NSUserDomainMask, YES);
|
||||
basePath = [paths objectAtIndex:0];
|
||||
NSString *cachesDirectory = [NSString stringWithFormat:@"-DCachesDirectory=%@", basePath];
|
||||
|
||||
NSString *sandboxEnabled = @"true";
|
||||
if ([basePath rangeOfString:@"Containers"].location == NSNotFound) {
|
||||
sandboxEnabled = @"false";
|
||||
}
|
||||
NSString *sandboxEnabledVar = [NSString stringWithFormat:@"-DSandboxEnabled=%@", sandboxEnabled];
|
||||
|
||||
// Initialize the arguments to JLI_Launch()
|
||||
// +5 due to the special directories and the sandbox enabled property
|
||||
int argc = 1 + [options count] + 2 + [arguments count] + 1 + 5;
|
||||
char *argv[argc];
|
||||
|
||||
int i = 0;
|
||||
argv[i++] = commandName;
|
||||
argv[i++] = strdup([classPath UTF8String]);
|
||||
argv[i++] = strdup([libraryPath UTF8String]);
|
||||
argv[i++] = strdup([libraryDirectory UTF8String]);
|
||||
argv[i++] = strdup([documentsDirectory UTF8String]);
|
||||
argv[i++] = strdup([applicationSupportDirectory UTF8String]);
|
||||
argv[i++] = strdup([cachesDirectory UTF8String]);
|
||||
argv[i++] = strdup([sandboxEnabledVar UTF8String]);
|
||||
|
||||
for (NSString *option in options) {
|
||||
option = [option stringByReplacingOccurrencesOfString:@APP_ROOT_PREFIX withString:[mainBundle bundlePath]];
|
||||
argv[i++] = strdup([option UTF8String]);
|
||||
}
|
||||
|
||||
argv[i++] = strdup([mainClassName UTF8String]);
|
||||
|
||||
for (NSString *argument in arguments) {
|
||||
argument = [argument stringByReplacingOccurrencesOfString:@APP_ROOT_PREFIX withString:[mainBundle bundlePath]];
|
||||
argv[i++] = strdup([argument UTF8String]);
|
||||
}
|
||||
|
||||
// Invoke JLI_Launch()
|
||||
return jli_LaunchFxnPtr(argc, argv,
|
||||
0, NULL,
|
||||
0, NULL,
|
||||
"",
|
||||
"",
|
||||
"java",
|
||||
"java",
|
||||
FALSE,
|
||||
FALSE,
|
||||
FALSE,
|
||||
0);
|
||||
}
|
||||
3
build/macosx/appbundler/res/en.lproj/Localizable.strings
Normal file
3
build/macosx/appbundler/res/en.lproj/Localizable.strings
Normal file
@@ -0,0 +1,3 @@
|
||||
"JRELoadError" = "Unable to load Java Runtime Environment.";
|
||||
"MainClassNameRequired" = "Main class name is required.";
|
||||
"JavaDirectoryNotFound" = "Unable to enumerate Java directory contents.";
|
||||
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Copyright 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.oracle.appbundler;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.LinkOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
|
||||
import org.apache.tools.ant.BuildException;
|
||||
import org.apache.tools.ant.DirectoryScanner;
|
||||
import org.apache.tools.ant.Task;
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
import org.apache.tools.ant.types.Reference;
|
||||
import org.apache.tools.ant.types.resources.FileResource;
|
||||
|
||||
/**
|
||||
* App bundler Ant task.
|
||||
*/
|
||||
public class AppBundlerTask extends Task {
|
||||
// Output folder for generated bundle
|
||||
private File outputDirectory = null;
|
||||
|
||||
// General bundle properties
|
||||
private String name = null;
|
||||
private String displayName = null;
|
||||
private String identifier = null;
|
||||
private File icon = null;
|
||||
private String executableName = EXECUTABLE_NAME;
|
||||
|
||||
private String shortVersion = "1.0";
|
||||
private String version = "1.0";
|
||||
private String signature = "????";
|
||||
private String copyright = "";
|
||||
private String privileged = null;
|
||||
private String workingDirectory = null;
|
||||
|
||||
private String applicationCategory = null;
|
||||
|
||||
private boolean highResolutionCapable = true;
|
||||
|
||||
// JVM info properties
|
||||
private String mainClassName = null;
|
||||
private FileSet runtime = null;
|
||||
private ArrayList<FileSet> classPath = new ArrayList<>();
|
||||
private ArrayList<FileSet> libraryPath = new ArrayList<>();
|
||||
private ArrayList<String> options = new ArrayList<>();
|
||||
private ArrayList<String> arguments = new ArrayList<>();
|
||||
private ArrayList<String> architectures = new ArrayList<>();
|
||||
private ArrayList<BundleDocument> bundleDocuments = new ArrayList<>();
|
||||
|
||||
private Reference classPathRef;
|
||||
|
||||
private static final String EXECUTABLE_NAME = "JavaAppLauncher";
|
||||
private static final String DEFAULT_ICON_NAME = "GenericApp.icns";
|
||||
private static final String OS_TYPE_CODE = "APPL";
|
||||
|
||||
private static final String PLIST_DTD = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">";
|
||||
private static final String PLIST_TAG = "plist";
|
||||
private static final String PLIST_VERSION_ATTRIBUTE = "version";
|
||||
private static final String DICT_TAG = "dict";
|
||||
private static final String KEY_TAG = "key";
|
||||
private static final String ARRAY_TAG = "array";
|
||||
private static final String STRING_TAG = "string";
|
||||
|
||||
private static final int BUFFER_SIZE = 2048;
|
||||
|
||||
public void setOutputDirectory(File outputDirectory) {
|
||||
this.outputDirectory = outputDirectory;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public void setIcon(File icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public void setExecutableName(String executable) {
|
||||
this.executableName = executable;
|
||||
}
|
||||
|
||||
public void setShortVersion(String shortVersion) {
|
||||
this.shortVersion = shortVersion;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void setSignature(String signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public void setCopyright(String copyright) {
|
||||
this.copyright = copyright;
|
||||
}
|
||||
|
||||
public void setPrivileged(String privileged) {
|
||||
this.privileged = privileged;
|
||||
}
|
||||
|
||||
public void setWorkingDirectory(String workingDirectory) {
|
||||
this.workingDirectory = workingDirectory;
|
||||
}
|
||||
|
||||
public void setApplicationCategory(String applicationCategory) {
|
||||
this.applicationCategory = applicationCategory;
|
||||
}
|
||||
|
||||
public void setHighResolutionCapable(boolean highResolutionCapable) {
|
||||
this.highResolutionCapable = highResolutionCapable;
|
||||
}
|
||||
|
||||
public void setMainClassName(String mainClassName) {
|
||||
this.mainClassName = mainClassName;
|
||||
}
|
||||
|
||||
public void addConfiguredRuntime(FileSet runtime) throws BuildException {
|
||||
if (this.runtime != null) {
|
||||
throw new BuildException("Runtime already specified.");
|
||||
}
|
||||
|
||||
this.runtime = runtime;
|
||||
|
||||
runtime.appendIncludes(new String[] {
|
||||
"jre/",
|
||||
});
|
||||
|
||||
runtime.appendExcludes(new String[] {
|
||||
"bin/",
|
||||
"jre/bin/",
|
||||
"jre/lib/deploy/",
|
||||
"jre/lib/deploy.jar",
|
||||
"jre/lib/javaws.jar",
|
||||
"jre/lib/libdeploy.dylib",
|
||||
"jre/lib/libnpjp2.dylib",
|
||||
"jre/lib/plugin.jar",
|
||||
"jre/lib/security/javaws.policy"
|
||||
});
|
||||
}
|
||||
|
||||
public void setClasspathRef(Reference ref) {
|
||||
this.classPathRef = ref;
|
||||
}
|
||||
|
||||
public void addConfiguredClassPath(FileSet classPath) {
|
||||
this.classPath.add(classPath);
|
||||
}
|
||||
|
||||
public void addConfiguredLibraryPath(FileSet libraryPath) {
|
||||
this.libraryPath.add(libraryPath);
|
||||
}
|
||||
|
||||
public void addConfiguredBundleDocument(BundleDocument document) {
|
||||
this.bundleDocuments.add(document);
|
||||
}
|
||||
|
||||
public void addConfiguredOption(Option option) throws BuildException {
|
||||
String value = option.getValue();
|
||||
|
||||
if (value == null) {
|
||||
throw new BuildException("Value is required.");
|
||||
}
|
||||
|
||||
options.add(value);
|
||||
}
|
||||
|
||||
public void addConfiguredArgument(Argument argument) throws BuildException {
|
||||
String value = argument.getValue();
|
||||
|
||||
if (value == null) {
|
||||
throw new BuildException("Value is required.");
|
||||
}
|
||||
|
||||
arguments.add(value);
|
||||
}
|
||||
|
||||
public void addConfiguredArch(Architecture architecture) throws BuildException {
|
||||
String name = architecture.getName();
|
||||
|
||||
if (name == null) {
|
||||
throw new BuildException("Name is required.");
|
||||
}
|
||||
|
||||
architectures.add(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() throws BuildException {
|
||||
// Validate required properties
|
||||
if (outputDirectory == null) {
|
||||
throw new IllegalStateException("Output directory is required.");
|
||||
}
|
||||
|
||||
if (!outputDirectory.exists()) {
|
||||
throw new IllegalStateException("Output directory does not exist.");
|
||||
}
|
||||
|
||||
if (!outputDirectory.isDirectory()) {
|
||||
throw new IllegalStateException("Invalid output directory.");
|
||||
}
|
||||
|
||||
if (name == null) {
|
||||
throw new IllegalStateException("Name is required.");
|
||||
}
|
||||
|
||||
if (displayName == null) {
|
||||
throw new IllegalStateException("Display name is required.");
|
||||
}
|
||||
|
||||
if (identifier == null) {
|
||||
throw new IllegalStateException("Identifier is required.");
|
||||
}
|
||||
|
||||
if (icon != null) {
|
||||
if (!icon.exists()) {
|
||||
throw new IllegalStateException("Icon does not exist.");
|
||||
}
|
||||
|
||||
if (icon.isDirectory()) {
|
||||
throw new IllegalStateException("Invalid icon.");
|
||||
}
|
||||
}
|
||||
|
||||
if (shortVersion == null) {
|
||||
throw new IllegalStateException("Short version is required.");
|
||||
}
|
||||
|
||||
if (signature == null) {
|
||||
throw new IllegalStateException("Signature is required.");
|
||||
}
|
||||
|
||||
if (signature.length() != 4) {
|
||||
throw new IllegalStateException("Invalid signature.");
|
||||
}
|
||||
|
||||
if (copyright == null) {
|
||||
throw new IllegalStateException("Copyright is required.");
|
||||
}
|
||||
|
||||
if (mainClassName == null) {
|
||||
throw new IllegalStateException("Main class name is required.");
|
||||
}
|
||||
|
||||
// Create the app bundle
|
||||
try {
|
||||
System.out.println("Creating app bundle: " + name);
|
||||
|
||||
// Create directory structure
|
||||
File rootDirectory = new File(outputDirectory, name + ".app");
|
||||
delete(rootDirectory);
|
||||
rootDirectory.mkdir();
|
||||
|
||||
File contentsDirectory = new File(rootDirectory, "Contents");
|
||||
contentsDirectory.mkdir();
|
||||
|
||||
File macOSDirectory = new File(contentsDirectory, "MacOS");
|
||||
macOSDirectory.mkdir();
|
||||
|
||||
File javaDirectory = new File(contentsDirectory, "Java");
|
||||
javaDirectory.mkdir();
|
||||
|
||||
File plugInsDirectory = new File(contentsDirectory, "PlugIns");
|
||||
plugInsDirectory.mkdir();
|
||||
|
||||
File resourcesDirectory = new File(contentsDirectory, "Resources");
|
||||
resourcesDirectory.mkdir();
|
||||
|
||||
// Generate Info.plist
|
||||
File infoPlistFile = new File(contentsDirectory, "Info.plist");
|
||||
infoPlistFile.createNewFile();
|
||||
writeInfoPlist(infoPlistFile);
|
||||
|
||||
// Generate PkgInfo
|
||||
File pkgInfoFile = new File(contentsDirectory, "PkgInfo");
|
||||
pkgInfoFile.createNewFile();
|
||||
writePkgInfo(pkgInfoFile);
|
||||
|
||||
// Copy executable to MacOS folder
|
||||
File executableFile = new File(macOSDirectory, executableName);
|
||||
copy(getClass().getResource(EXECUTABLE_NAME), executableFile);
|
||||
|
||||
executableFile.setExecutable(true, false);
|
||||
|
||||
// Copy localized resources to Resources folder
|
||||
copyResources(resourcesDirectory);
|
||||
|
||||
// Copy runtime to PlugIns folder
|
||||
copyRuntime(plugInsDirectory);
|
||||
|
||||
// Copy class path entries to Java folder
|
||||
copyClassPathEntries(javaDirectory);
|
||||
|
||||
// Copy class path ref entries to Java folder
|
||||
copyClassPathRefEntries(javaDirectory);
|
||||
|
||||
// Copy library path entries to MacOS folder
|
||||
copyLibraryPathEntries(macOSDirectory);
|
||||
|
||||
// Copy icon to Resources folder
|
||||
copyIcon(resourcesDirectory);
|
||||
} catch (IOException exception) {
|
||||
throw new BuildException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyResources(File resourcesDirectory) throws IOException {
|
||||
// Unzip res.zip into resources directory
|
||||
InputStream inputStream = getClass().getResourceAsStream("res.zip");
|
||||
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
|
||||
|
||||
try {
|
||||
ZipEntry zipEntry = zipInputStream.getNextEntry();
|
||||
while (zipEntry != null) {
|
||||
File file = new File(resourcesDirectory, zipEntry.getName());
|
||||
|
||||
if (zipEntry.isDirectory()) {
|
||||
file.mkdir();
|
||||
} else {
|
||||
OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file), BUFFER_SIZE);
|
||||
|
||||
try {
|
||||
int b = zipInputStream.read();
|
||||
while (b != -1) {
|
||||
outputStream.write(b);
|
||||
b = zipInputStream.read();
|
||||
}
|
||||
|
||||
outputStream.flush();
|
||||
} finally {
|
||||
outputStream.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
zipEntry = zipInputStream.getNextEntry();
|
||||
}
|
||||
} finally {
|
||||
zipInputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void copyRuntime(File plugInsDirectory) throws IOException {
|
||||
if (runtime != null) {
|
||||
File runtimeHomeDirectory = runtime.getDir();
|
||||
File runtimeContentsDirectory = runtimeHomeDirectory.getParentFile();
|
||||
File runtimeDirectory = runtimeContentsDirectory.getParentFile();
|
||||
|
||||
// Create root plug-in directory
|
||||
File pluginDirectory = new File(plugInsDirectory, runtimeDirectory.getName());
|
||||
pluginDirectory.mkdir();
|
||||
|
||||
// Create Contents directory
|
||||
File pluginContentsDirectory = new File(pluginDirectory, runtimeContentsDirectory.getName());
|
||||
pluginContentsDirectory.mkdir();
|
||||
|
||||
// Copy MacOS directory
|
||||
File runtimeMacOSDirectory = new File(runtimeContentsDirectory, "MacOS");
|
||||
copy(runtimeMacOSDirectory, new File(pluginContentsDirectory, runtimeMacOSDirectory.getName()));
|
||||
|
||||
// Copy Info.plist file
|
||||
File runtimeInfoPlistFile = new File(runtimeContentsDirectory, "Info.plist");
|
||||
copy(runtimeInfoPlistFile, new File(pluginContentsDirectory, runtimeInfoPlistFile.getName()));
|
||||
|
||||
// Copy included contents of Home directory
|
||||
File pluginHomeDirectory = new File(pluginContentsDirectory, runtimeHomeDirectory.getName());
|
||||
|
||||
DirectoryScanner directoryScanner = runtime.getDirectoryScanner(getProject());
|
||||
String[] includedFiles = directoryScanner.getIncludedFiles();
|
||||
|
||||
for (int i = 0; i < includedFiles.length; i++) {
|
||||
String includedFile = includedFiles[i];
|
||||
File source = new File(runtimeHomeDirectory, includedFile);
|
||||
File destination = new File(pluginHomeDirectory, includedFile);
|
||||
copy(source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyClassPathRefEntries(File javaDirectory) throws IOException {
|
||||
if(classPathRef != null) {
|
||||
org.apache.tools.ant.types.Path classpath =
|
||||
(org.apache.tools.ant.types.Path) classPathRef.getReferencedObject(getProject());
|
||||
|
||||
Iterator<FileResource> iter = (Iterator<FileResource>)(Object)classpath.iterator();
|
||||
while(iter.hasNext()) {
|
||||
FileResource resource = iter.next();
|
||||
File source = resource.getFile();
|
||||
File destination = new File(javaDirectory, source.getName());
|
||||
copy(source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyClassPathEntries(File javaDirectory) throws IOException {
|
||||
for (FileSet fileSet : classPath) {
|
||||
File classPathDirectory = fileSet.getDir();
|
||||
DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
|
||||
String[] includedFiles = directoryScanner.getIncludedFiles();
|
||||
|
||||
for (int i = 0; i < includedFiles.length; i++) {
|
||||
String includedFile = includedFiles[i];
|
||||
File source = new File(classPathDirectory, includedFile);
|
||||
File destination = new File(javaDirectory, new File(includedFile).getName());
|
||||
copy(source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyLibraryPathEntries(File macOSDirectory) throws IOException {
|
||||
for (FileSet fileSet : libraryPath) {
|
||||
File libraryPathDirectory = fileSet.getDir();
|
||||
DirectoryScanner directoryScanner = fileSet.getDirectoryScanner(getProject());
|
||||
String[] includedFiles = directoryScanner.getIncludedFiles();
|
||||
|
||||
for (int i = 0; i < includedFiles.length; i++) {
|
||||
String includedFile = includedFiles[i];
|
||||
File source = new File(libraryPathDirectory, includedFile);
|
||||
File destination = new File(macOSDirectory, new File(includedFile).getName());
|
||||
copy(source, destination);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyIcon(File resourcesDirectory) throws IOException {
|
||||
if (icon == null) {
|
||||
copy(getClass().getResource(DEFAULT_ICON_NAME), new File(resourcesDirectory, DEFAULT_ICON_NAME));
|
||||
} else {
|
||||
copy(icon, new File(resourcesDirectory, icon.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeInfoPlist(File file) throws IOException {
|
||||
Writer out = new BufferedWriter(new FileWriter(file));
|
||||
XMLOutputFactory output = XMLOutputFactory.newInstance();
|
||||
|
||||
try {
|
||||
XMLStreamWriter xout = output.createXMLStreamWriter(out);
|
||||
|
||||
// Write XML declaration
|
||||
xout.writeStartDocument();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Write plist DTD declaration
|
||||
xout.writeDTD(PLIST_DTD);
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Begin root element
|
||||
xout.writeStartElement(PLIST_TAG);
|
||||
xout.writeAttribute(PLIST_VERSION_ATTRIBUTE, "1.0");
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Begin root dictionary
|
||||
xout.writeStartElement(DICT_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Write bundle properties
|
||||
writeProperty(xout, "CFBundleDevelopmentRegion", "English");
|
||||
writeProperty(xout, "CFBundleExecutable", executableName);
|
||||
writeProperty(xout, "CFBundleIconFile", (icon == null) ? DEFAULT_ICON_NAME : icon.getName());
|
||||
writeProperty(xout, "CFBundleIdentifier", identifier);
|
||||
writeProperty(xout, "CFBundleDisplayName", displayName);
|
||||
writeProperty(xout, "CFBundleInfoDictionaryVersion", "6.0");
|
||||
writeProperty(xout, "CFBundleName", name);
|
||||
writeProperty(xout, "CFBundlePackageType", OS_TYPE_CODE);
|
||||
writeProperty(xout, "CFBundleShortVersionString", shortVersion);
|
||||
writeProperty(xout, "CFBundleVersion", version);
|
||||
writeProperty(xout, "CFBundleSignature", signature);
|
||||
writeProperty(xout, "NSHumanReadableCopyright", copyright);
|
||||
|
||||
if (applicationCategory != null) {
|
||||
writeProperty(xout, "LSApplicationCategoryType", applicationCategory);
|
||||
}
|
||||
|
||||
if (highResolutionCapable) {
|
||||
writeKey(xout, "NSHighResolutionCapable");
|
||||
writeBoolean(xout, true);
|
||||
xout.writeCharacters("\n");
|
||||
}
|
||||
|
||||
// Write runtime
|
||||
if (runtime != null) {
|
||||
writeProperty(xout, "JVMRuntime", runtime.getDir().getParentFile().getParentFile().getName());
|
||||
}
|
||||
|
||||
if ( privileged != null ) {
|
||||
writeProperty(xout, "JVMRunPrivileged", privileged);
|
||||
}
|
||||
|
||||
if ( workingDirectory != null ) {
|
||||
writeProperty(xout, "WorkingDirectory", workingDirectory);
|
||||
}
|
||||
|
||||
// Write main class name
|
||||
writeProperty(xout, "JVMMainClassName", mainClassName);
|
||||
|
||||
|
||||
// Write CFBundleDocument entries
|
||||
writeKey(xout, "CFBundleDocumentTypes");
|
||||
|
||||
xout.writeStartElement(ARRAY_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
for(BundleDocument bundleDocument: bundleDocuments) {
|
||||
xout.writeStartElement(DICT_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
writeKey(xout, "CFBundleTypeExtensions");
|
||||
xout.writeStartElement(ARRAY_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
for(String extension : bundleDocument.getExtensions()) {
|
||||
writeString(xout, extension);
|
||||
}
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
if(bundleDocument.hasIcon()) {
|
||||
writeKey(xout, "CFBundleTypeIconFile");
|
||||
writeString(xout, bundleDocument.getIcon());
|
||||
}
|
||||
|
||||
writeKey(xout, "CFBundleTypeName");
|
||||
writeString(xout, bundleDocument.getName());
|
||||
|
||||
writeKey(xout, "CFBundleTypeRole");
|
||||
writeString(xout, bundleDocument.getRole());
|
||||
|
||||
writeKey(xout, "LSTypeIsPackage");
|
||||
writeBoolean(xout, bundleDocument.isPackage());
|
||||
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
}
|
||||
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Write architectures
|
||||
writeKey(xout, "LSArchitecturePriority");
|
||||
|
||||
xout.writeStartElement(ARRAY_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
for (String architecture : architectures) {
|
||||
writeString(xout, architecture);
|
||||
}
|
||||
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Write Environment
|
||||
writeKey(xout, "LSEnvironment");
|
||||
xout.writeStartElement(DICT_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
writeKey(xout, "LC_CTYPE");
|
||||
writeString(xout, "UTF-8");
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Write options
|
||||
writeKey(xout, "JVMOptions");
|
||||
|
||||
xout.writeStartElement(ARRAY_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
for (String option : options) {
|
||||
writeString(xout, option);
|
||||
}
|
||||
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Write arguments
|
||||
writeKey(xout, "JVMArguments");
|
||||
|
||||
xout.writeStartElement(ARRAY_TAG);
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
for (String argument : arguments) {
|
||||
writeString(xout, argument);
|
||||
}
|
||||
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// End root dictionary
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// End root element
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
// Close document
|
||||
xout.writeEndDocument();
|
||||
xout.writeCharacters("\n");
|
||||
|
||||
out.flush();
|
||||
} catch (XMLStreamException exception) {
|
||||
throw new IOException(exception);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeKey(XMLStreamWriter xout, String key) throws XMLStreamException {
|
||||
xout.writeStartElement(KEY_TAG);
|
||||
xout.writeCharacters(key);
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
}
|
||||
|
||||
private void writeString(XMLStreamWriter xout, String value) throws XMLStreamException {
|
||||
xout.writeStartElement(STRING_TAG);
|
||||
xout.writeCharacters(value);
|
||||
xout.writeEndElement();
|
||||
xout.writeCharacters("\n");
|
||||
}
|
||||
|
||||
private void writeBoolean(XMLStreamWriter xout, boolean value) throws XMLStreamException {
|
||||
xout.writeEmptyElement(value ? "true" : "false");
|
||||
}
|
||||
|
||||
private void writeProperty(XMLStreamWriter xout, String key, String value) throws XMLStreamException {
|
||||
writeKey(xout, key);
|
||||
writeString(xout, value);
|
||||
}
|
||||
|
||||
private void writePkgInfo(File file) throws IOException {
|
||||
Writer out = new BufferedWriter(new FileWriter(file));
|
||||
|
||||
try {
|
||||
out.write(OS_TYPE_CODE + signature);
|
||||
out.flush();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void delete(File file) throws IOException {
|
||||
Path filePath = file.toPath();
|
||||
|
||||
if (Files.exists(filePath, LinkOption.NOFOLLOW_LINKS)) {
|
||||
if (Files.isDirectory(filePath, LinkOption.NOFOLLOW_LINKS)) {
|
||||
File[] files = file.listFiles();
|
||||
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
delete(files[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Files.delete(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(URL location, File file) throws IOException {
|
||||
try (InputStream in = location.openStream()) {
|
||||
Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
}
|
||||
|
||||
private static void copy(File source, File destination) throws IOException {
|
||||
Path sourcePath = source.toPath();
|
||||
Path destinationPath = destination.toPath();
|
||||
|
||||
destination.getParentFile().mkdirs();
|
||||
|
||||
Files.copy(sourcePath, destinationPath, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS);
|
||||
|
||||
if (Files.isDirectory(sourcePath, LinkOption.NOFOLLOW_LINKS)) {
|
||||
String[] files = source.list();
|
||||
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
String file = files[i];
|
||||
copy(new File(source, file), new File(destination, file));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012, The Infinite Kind and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. The Infinite Kind designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by The Infinite Kind in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.oracle.appbundler;
|
||||
|
||||
/**
|
||||
* Class representing an architecture that will be written in the Info.plist file
|
||||
* to indicate which architectures the binary support.
|
||||
*/
|
||||
public class Architecture {
|
||||
private String name = null;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.oracle.appbundler;
|
||||
|
||||
/**
|
||||
* Class representing an argument that will be passed to the Java application
|
||||
* at startup.
|
||||
*/
|
||||
public class Argument {
|
||||
private String value = null;
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2012, The Infinite Kind and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. The Infinite Kind designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by The Infinite Kind in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.oracle.appbundler;
|
||||
|
||||
import java.io.File;
|
||||
import org.apache.tools.ant.BuildException;
|
||||
|
||||
|
||||
/**
|
||||
* Represent a CFBundleDocument.
|
||||
*/
|
||||
public class BundleDocument {
|
||||
private String name = "editor";
|
||||
private String role = "";
|
||||
private String icon = null;
|
||||
private String[] extensions;
|
||||
private boolean isPackage = false;
|
||||
|
||||
private String capitalizeFirst(String string) {
|
||||
char[] stringArray = string.toCharArray();
|
||||
stringArray[0] = Character.toUpperCase(stringArray[0]);
|
||||
return new String(stringArray);
|
||||
}
|
||||
|
||||
public void setExtensions(String extensionsList) {
|
||||
if(extensionsList == null) {
|
||||
throw new BuildException("Extensions can't be null");
|
||||
}
|
||||
|
||||
extensions = extensionsList.split(",");
|
||||
for (String extension : extensions) {
|
||||
extension.trim().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
public void setIcon(String icon) {
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setRole(String role) {
|
||||
this.role = capitalizeFirst(role);
|
||||
}
|
||||
|
||||
public void setIsPackage(String isPackageString) {
|
||||
if(isPackageString.trim().equalsIgnoreCase("true")) {
|
||||
this.isPackage = true;
|
||||
} else {
|
||||
this.isPackage = false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public String[] getExtensions() {
|
||||
return extensions;
|
||||
}
|
||||
|
||||
public boolean hasIcon() {
|
||||
return icon != null;
|
||||
}
|
||||
|
||||
public boolean isPackage() {
|
||||
return isPackage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder(getName());
|
||||
s.append(" ").append(getRole()).append(" ").append(getIcon()). append(" ");
|
||||
for(String extension : extensions) {
|
||||
s.append(extension).append(" ");
|
||||
}
|
||||
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package com.oracle.appbundler;
|
||||
|
||||
/**
|
||||
* Class representing an option that will be passed to the JVM at startup.
|
||||
*/
|
||||
public class Option {
|
||||
private String value = null;
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ X background color for present mode has no effect
|
||||
X https://github.com/processing/processing/issues/2071
|
||||
X https://github.com/processing/processing/pull/2072
|
||||
|
||||
_ Sort out blending differences with P2D/P3D
|
||||
_ https://github.com/processing/processing/issues/1844
|
||||
|
||||
high
|
||||
_ loadPixels doesn't set alpha value for pixels on Java2D
|
||||
|
||||
Reference in New Issue
Block a user