init
This commit is contained in:
commit
bcd10b75d3
17 changed files with 1506 additions and 0 deletions
129
.clang-format
Normal file
129
.clang-format
Normal file
|
@ -0,0 +1,129 @@
|
|||
---
|
||||
AccessModifierOffset: 0
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: DontAlign
|
||||
AlignTrailingComments: false
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Empty
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
AttributeMacros: []
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BitFieldColonSpacing: After
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakAfterJavaFieldAnnotations: true
|
||||
#BreakArrays: false
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakInheritanceList: AfterColon
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 90
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false # wtf
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: Always
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros: ["BOOST_FOREACH"]
|
||||
IfMacros: []
|
||||
IncludeBlocks: Regroup
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: true
|
||||
IndentExternBlock: Indent
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: BeforeHash
|
||||
#IndentRequiresClause: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
#InsertBraces: false
|
||||
InsertTrailingCommas: Wrapped
|
||||
JavaScriptQuotes: Double
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
LambdaBodyIndentation: OuterScope
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
PackConstructorInitializers: NextLine
|
||||
PointerAlignment: Left
|
||||
QualifierAlignment: Left
|
||||
ReferenceAlignment: Left
|
||||
ReflowComments: true
|
||||
#RemoveSemicolon: true
|
||||
#RequiresClausePosition: OwnLine
|
||||
#RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Always
|
||||
SortIncludes: false
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceAroundPointerQualifiers: After
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeInheritanceColon: false
|
||||
SpaceBeforeParens: ControlStatementsExceptControlMacros
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: Never
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 0
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: c++20
|
||||
StatementAttributeLikeMacros: []
|
||||
StatementMacros: []
|
||||
TabWidth: 4
|
||||
TypenameMacros: []
|
||||
UseCRLF: false # wtf
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros: ["BOOST_PP_STRINGSIZE"]
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
.gradle
|
||||
.idea
|
||||
build
|
||||
gradle.properties
|
||||
bin
|
||||
.settings
|
||||
.classpath
|
||||
.project
|
54
build.gradle
Normal file
54
build.gradle
Normal file
|
@ -0,0 +1,54 @@
|
|||
plugins {
|
||||
id "java"
|
||||
id "groovy"
|
||||
id "java-gradle-plugin"
|
||||
id "com.gradle.plugin-publish" version "0.10.0"
|
||||
id "maven-publish"
|
||||
}
|
||||
|
||||
group "net.anvilcraft"
|
||||
version "0.1.0"
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile group: "junit", name: "junit", version: "4.12"
|
||||
implementation gradleApi()
|
||||
implementation "org.ow2.asm:asm:9.7.1"
|
||||
implementation "org.ow2.asm:asm-commons:9.7.1"
|
||||
implementation "commons-io:commons-io:2.7"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs = []
|
||||
}
|
||||
groovy {
|
||||
srcDirs = ["src/main/java" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pluginBundle {
|
||||
website = "https://git.tilera.org/Anvilcraft/gradlehaxe"
|
||||
vcsUrl = "https://git.tilera.org/Anvilcraft/gradlehaxe"
|
||||
tags = ["haxe"]
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
gradlehaxe {
|
||||
id = "net.anvilcraft.gradlehaxe"
|
||||
displayName = "GradleHaxe"
|
||||
description = "Haxe compatiblity for Gradle"
|
||||
implementationClass = "net.anvilcraft.gradlehaxe.BuilderPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
172
gradlew
vendored
Executable file
172
gradlew
vendored
Executable file
|
@ -0,0 +1,172 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
2
settings.gradle
Normal file
2
settings.gradle
Normal file
|
@ -0,0 +1,2 @@
|
|||
rootProject.name = 'modpackbuilder'
|
||||
|
56
src/main/java/net/anvilcraft/gradlehaxe/BuilderPlugin.java
Normal file
56
src/main/java/net/anvilcraft/gradlehaxe/BuilderPlugin.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
package net.anvilcraft.gradlehaxe;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.file.SourceDirectorySet;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.plugins.JavaBasePlugin;
|
||||
import org.gradle.api.plugins.internal.JvmPluginsHelper;
|
||||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
import org.gradle.api.tasks.TaskProvider;
|
||||
|
||||
import net.anvilcraft.gradlehaxe.compile.CompileHaxeTask;
|
||||
|
||||
public class BuilderPlugin implements Plugin<Project> {
|
||||
private final ObjectFactory objects;
|
||||
|
||||
@Inject
|
||||
public BuilderPlugin(ObjectFactory objects) {
|
||||
this.objects = objects;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Project proj) {
|
||||
proj.getPluginManager().apply(JavaBasePlugin.class);
|
||||
|
||||
proj.getExtensions().getByType(SourceSetContainer.class).all(ss -> {
|
||||
SourceDirectorySet haxeSrc
|
||||
= this.objects.sourceDirectorySet("haxe", ss.getName() + " Haxe Source.");
|
||||
haxeSrc.srcDir("src/" + ss.getName() + "/haxe");
|
||||
|
||||
ss.getExtensions().add("haxe", haxeSrc);
|
||||
|
||||
TaskProvider<CompileHaxeTask> taskProv = proj.getTasks().register(
|
||||
ss.getCompileTaskName("haxe"),
|
||||
CompileHaxeTask.class,
|
||||
task -> {
|
||||
task.setSource(haxeSrc);
|
||||
task.getSS().set(ss);
|
||||
task.getConventionMapping().map("classpath", ss::getCompileClasspath);
|
||||
}
|
||||
);
|
||||
JvmPluginsHelper.configureOutputDirectoryForSourceSet(
|
||||
ss, haxeSrc, proj, taskProv, taskProv.map(CompileHaxeTask::getOptions)
|
||||
);
|
||||
|
||||
proj.getTasks().named(ss.getClassesTaskName(), t -> t.dependsOn(taskProv));
|
||||
|
||||
proj.getTasks()
|
||||
.register("generateHXML_" + ss.getName(), GenerateHXMLTask.class);
|
||||
|
||||
ss.getExtensions().create("haxeopts", HaxeSourceSetExtension.class);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package net.anvilcraft.gradlehaxe;
|
||||
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.SourceSetContainer;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
|
||||
public abstract class GenerateHXMLTask extends DefaultTask {
|
||||
@TaskAction
|
||||
public void action() {
|
||||
String ssName = this.getName().replace("generateHXML_", "");
|
||||
SourceSet ss = this.getProject()
|
||||
.getExtensions()
|
||||
.getByType(SourceSetContainer.class)
|
||||
.getByName(ssName);
|
||||
|
||||
HaxeArguments args = new HaxeArguments(ss, this.getProject(), this.getTemporaryDir() + "/build.jar");
|
||||
|
||||
try (FileWriter fw = new FileWriter("build.hxml")) {
|
||||
args.writeHXML(fw);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
93
src/main/java/net/anvilcraft/gradlehaxe/HaxeArguments.java
Normal file
93
src/main/java/net/anvilcraft/gradlehaxe/HaxeArguments.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
package net.anvilcraft.gradlehaxe;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.gradle.api.JavaVersion;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.plugins.JavaPluginExtension;
|
||||
import org.gradle.api.provider.Provider;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion;
|
||||
import org.gradle.jvm.toolchain.JavaLauncher;
|
||||
import org.gradle.jvm.toolchain.JavaToolchainService;
|
||||
|
||||
public class HaxeArguments {
|
||||
public String outpath;
|
||||
public String classpath;
|
||||
public ArrayList<String> includedPackages = new ArrayList<>();
|
||||
public ArrayList<String> libs = new ArrayList<>();
|
||||
|
||||
public HaxeArguments(SourceSet ss, Project proj, String outpath) {
|
||||
this.classpath = "src/" + ss.getName() + "/haxe";
|
||||
this.outpath = outpath;
|
||||
|
||||
this.includedPackages.addAll(
|
||||
ss.getExtensions().getByType(HaxeSourceSetExtension.class).includedPackages
|
||||
);
|
||||
|
||||
ss.getCompileClasspath()
|
||||
.getFiles()
|
||||
.stream()
|
||||
.filter(f -> f.getPath().endsWith(".jar"))
|
||||
.map(File::getPath)
|
||||
.forEach(this.libs::add);
|
||||
;
|
||||
|
||||
JavaPluginExtension java
|
||||
= proj.getExtensions().getByType(JavaPluginExtension.class);
|
||||
|
||||
if (java.getTargetCompatibility() == JavaVersion.VERSION_1_8) {
|
||||
JavaToolchainService javaToolchain
|
||||
= proj.getExtensions().getByType(JavaToolchainService.class);
|
||||
|
||||
Provider<JavaLauncher> launcher = javaToolchain.launcherFor(
|
||||
spec -> spec.getLanguageVersion().set(JavaLanguageVersion.of(8))
|
||||
);
|
||||
|
||||
this.libs.add(
|
||||
launcher.get().getMetadata().getInstallationPath() + "/jre/lib/jce.jar"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeHXML(Writer w) throws IOException {
|
||||
w.write("-cp " + this.classpath + "\n");
|
||||
for (String p : this.includedPackages) {
|
||||
w.write("--macro \"include('" + p + "')\"\n");
|
||||
}
|
||||
w.write("--jvm " + this.outpath + "\n");
|
||||
w.write("\n");
|
||||
|
||||
for (String lib : this.libs) {
|
||||
w.write("--java-lib-extern " + lib + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
public String[] toCommand() {
|
||||
String[] ret
|
||||
= new String[this.includedPackages.size() * 2 + this.libs.size() * 2 + 5];
|
||||
int i = 0;
|
||||
|
||||
ret[i++] = "haxe";
|
||||
ret[i++] = "-cp";
|
||||
ret[i++] = this.classpath;
|
||||
ret[i++] = "--jvm";
|
||||
ret[i++] = this.outpath;
|
||||
|
||||
for (String p : this.includedPackages) {
|
||||
ret[i++] = "--macro";
|
||||
ret[i++] = "include('" + p + "')";
|
||||
}
|
||||
|
||||
for (String lib : this.libs) {
|
||||
ret[i++] = "--java-lib-extern";
|
||||
ret[i++] = lib;
|
||||
}
|
||||
|
||||
assert i == ret.length;
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package net.anvilcraft.gradlehaxe;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class HaxeSourceSetExtension {
|
||||
public final Set<String> includedPackages = new HashSet<>();
|
||||
public String remappedHaxePackageName = null;
|
||||
|
||||
public void includePackage(String pkg) {
|
||||
this.includedPackages.add(pkg);
|
||||
}
|
||||
|
||||
public void remapHaxePackage(String name) {
|
||||
this.remappedHaxePackageName = name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package net.anvilcraft.gradlehaxe.compile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.gradle.api.provider.Property;
|
||||
import org.gradle.api.tasks.SourceSet;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.api.tasks.compile.AbstractCompile;
|
||||
import org.gradle.api.tasks.compile.CompileOptions;
|
||||
import org.gradle.tooling.BuildException;
|
||||
|
||||
import net.anvilcraft.gradlehaxe.HaxeArguments;
|
||||
import net.anvilcraft.gradlehaxe.HaxeSourceSetExtension;
|
||||
import net.anvilcraft.gradlehaxe.util.JarRelocatorTask;
|
||||
import net.anvilcraft.gradlehaxe.util.RelocatingRemapper;
|
||||
import net.anvilcraft.gradlehaxe.util.Relocation;
|
||||
|
||||
public abstract class CompileHaxeTask extends AbstractCompile {
|
||||
public CompileOptions options;
|
||||
|
||||
public CompileHaxeTask() {
|
||||
this.options = this.getProject().getObjects().newInstance(
|
||||
CompileOptions.class, new Object[0]
|
||||
);
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
public void action() {
|
||||
String buildJar = this.getTemporaryDir() + "/build.jar";
|
||||
|
||||
HaxeArguments args
|
||||
= new HaxeArguments(this.getSS().get(), this.getProject(), buildJar);
|
||||
|
||||
try {
|
||||
Process proc = Runtime.getRuntime().exec(args.toCommand());
|
||||
if (proc.waitFor() != 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Haxe failed.\nstdout:\n");
|
||||
copyToSB(proc.getInputStream(), sb);
|
||||
sb.append("\nstderr:\n");
|
||||
copyToSB(proc.getErrorStream(), sb);
|
||||
|
||||
throw new BuildException(sb.toString(), null);
|
||||
}
|
||||
|
||||
Path dest = this.getDestinationDirectory().getAsFile().get().toPath();
|
||||
|
||||
// Delete, then re-create destination directory to remove potential excess classes.
|
||||
FileUtils.cleanDirectory(dest.toFile());
|
||||
|
||||
String relocatedHaxePkg = this.getSS()
|
||||
.get()
|
||||
.getExtensions()
|
||||
.getByType(HaxeSourceSetExtension.class)
|
||||
.remappedHaxePackageName;
|
||||
if (relocatedHaxePkg != null) {
|
||||
ArrayList<Relocation> relocations = new ArrayList<Relocation>();
|
||||
relocations.add(new Relocation("haxe", relocatedHaxePkg));
|
||||
|
||||
new JarRelocatorTask(
|
||||
new RelocatingRemapper(relocations),
|
||||
dest,
|
||||
new JarFile(buildJar)
|
||||
).processEntries();
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Property<SourceSet> getSS();
|
||||
|
||||
public CompileOptions getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
private void copyToSB(InputStream is, StringBuilder sb) throws IOException {
|
||||
byte[] buf = new byte[4096];
|
||||
int read;
|
||||
while ((read = is.read(buf)) > 0) {
|
||||
sb.append(new String(buf, 0, read));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.anvilcraft.gradlehaxe.util;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
/**
|
||||
* A task that copies {@link JarEntry jar entries} from a {@link JarFile jar input} to a
|
||||
* {@link JarOutputStream jar output}, applying the relocations defined by a
|
||||
* {@link RelocatingRemapper}.
|
||||
*/
|
||||
public class JarRelocatorTask {
|
||||
/**
|
||||
* META-INF/*.SF
|
||||
* META-INF/*.DSA
|
||||
* META-INF/*.RSA
|
||||
* META-INF/SIG-*
|
||||
*
|
||||
* <a
|
||||
* href="https://docs.oracle.com/en/java/javase/11/docs/specs/jar/jar.html#signed-jar-file">Specification</a>
|
||||
*/
|
||||
private static final Pattern SIGNATURE_FILE_PATTERN
|
||||
= Pattern.compile("META-INF/(?:[^/]+\\.(?:DSA|RSA|SF)|SIG-[^/]+)");
|
||||
|
||||
private final RelocatingRemapper remapper;
|
||||
private final Path dirOut;
|
||||
private final JarFile jarIn;
|
||||
|
||||
private final Set<String> resources = new HashSet<>();
|
||||
|
||||
public JarRelocatorTask(RelocatingRemapper remapper, Path dirOut, JarFile jarIn) {
|
||||
this.remapper = remapper;
|
||||
this.dirOut = dirOut;
|
||||
this.jarIn = jarIn;
|
||||
}
|
||||
|
||||
public void processEntries() throws IOException {
|
||||
for (Enumeration<JarEntry> entries = this.jarIn.entries();
|
||||
entries.hasMoreElements();) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
|
||||
// The 'INDEX.LIST' file is an optional file, containing information about the
|
||||
// packages defined in a jar. Instead of relocating the entries in it, we
|
||||
// delete it, since it is optional anyway.
|
||||
//
|
||||
// We don't process directory entries, and instead opt to recreate them when
|
||||
// adding classes/resources.
|
||||
String name = entry.getName();
|
||||
if (name.equals("META-INF/INDEX.LIST") || name.equals("META-INF/MANIFEST.MF")
|
||||
|| entry.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Signatures will become invalid after remapping, so we delete them to avoid
|
||||
// making the output useless
|
||||
if (SIGNATURE_FILE_PATTERN.matcher(name).matches()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try (InputStream entryIn = this.jarIn.getInputStream(entry)) {
|
||||
processEntry(entry, entryIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processEntry(JarEntry entry, InputStream entryIn) throws IOException {
|
||||
String name = entry.getName();
|
||||
String mappedName = this.remapper.map(name);
|
||||
|
||||
// ensure the parent directory structure exists for the entry.
|
||||
processDirectory(mappedName, true);
|
||||
|
||||
if (name.endsWith(".class")) {
|
||||
processClass(name, entryIn);
|
||||
} else if (!this.resources.contains(mappedName)) {
|
||||
processResource(mappedName, entryIn, entry.getTime());
|
||||
}
|
||||
}
|
||||
|
||||
private void processDirectory(String name, boolean parentsOnly) throws IOException {
|
||||
int index = name.lastIndexOf('/');
|
||||
if (index != -1) {
|
||||
String parentDirectory = name.substring(0, index);
|
||||
if (!this.resources.contains(parentDirectory)) {
|
||||
processDirectory(parentDirectory, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (parentsOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dirOut.resolve(name).toFile().mkdirs();
|
||||
this.resources.add(name);
|
||||
}
|
||||
|
||||
private void processResource(String name, InputStream entryIn, long lastModified)
|
||||
throws IOException {
|
||||
try (
|
||||
FileOutputStream fos
|
||||
= new FileOutputStream(this.dirOut.resolve(name).toFile())
|
||||
) {
|
||||
IOUtils.copy(entryIn, fos);
|
||||
}
|
||||
|
||||
this.resources.add(name);
|
||||
}
|
||||
|
||||
private void processClass(String name, InputStream entryIn) throws IOException {
|
||||
ClassReader classReader = new ClassReader(entryIn);
|
||||
ClassWriter classWriter = new ClassWriter(0);
|
||||
RelocatingClassVisitor classVisitor
|
||||
= new RelocatingClassVisitor(classWriter, this.remapper, name);
|
||||
|
||||
try {
|
||||
classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Error processing class " + name, e);
|
||||
}
|
||||
|
||||
byte[] renamedClass = classWriter.toByteArray();
|
||||
|
||||
// Need to take the .class off for remapping evaluation
|
||||
String mappedName = this.remapper.map(name.substring(0, name.indexOf('.')));
|
||||
|
||||
// Now we put it back on so the class file is written out with the right
|
||||
// extension.
|
||||
try (
|
||||
FileOutputStream fos
|
||||
= new FileOutputStream(this.dirOut.resolve(mappedName + ".class").toFile())
|
||||
) {
|
||||
fos.write(renamedClass);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.anvilcraft.gradlehaxe.util;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
|
||||
/**
|
||||
* A {@link ClassVisitor} that relocates types and names with a {@link
|
||||
* RelocatingRemapper}.
|
||||
*/
|
||||
final class RelocatingClassVisitor extends ClassRemapper {
|
||||
private final String packageName;
|
||||
|
||||
RelocatingClassVisitor(ClassWriter writer, RelocatingRemapper remapper, String name) {
|
||||
super(Opcodes.ASM9, writer, remapper);
|
||||
this.packageName = name.substring(0, name.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSource(String source, String debug) {
|
||||
if (source == null) {
|
||||
super.visitSource(null, debug);
|
||||
return;
|
||||
}
|
||||
|
||||
// visit source file name
|
||||
String name = this.packageName + source;
|
||||
String mappedName = super.remapper.map(name);
|
||||
String mappedFileName = mappedName.substring(mappedName.lastIndexOf('/') + 1);
|
||||
super.visitSource(mappedFileName, debug);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.anvilcraft.gradlehaxe.util;
|
||||
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Remaps class names and types using defined {@link Relocation} rules.
|
||||
*/
|
||||
public class RelocatingRemapper extends Remapper {
|
||||
private static final Pattern CLASS_PATTERN = Pattern.compile("(\\[*)?L(.+);");
|
||||
|
||||
// https://docs.oracle.com/javase/10/docs/specs/jar/jar.html#multi-release-jar-files
|
||||
private static final Pattern VERSION_PATTERN
|
||||
= Pattern.compile("^(META-INF/versions/\\d+/)(.*)$");
|
||||
|
||||
private final Collection<Relocation> rules;
|
||||
|
||||
public RelocatingRemapper(Collection<Relocation> rules) {
|
||||
this.rules = rules;
|
||||
}
|
||||
|
||||
public Collection<Relocation> getRules() {
|
||||
return this.rules;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String name) {
|
||||
String relocatedName = relocate(name, false);
|
||||
if (relocatedName != null) {
|
||||
return relocatedName;
|
||||
}
|
||||
return super.map(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object mapValue(Object object) {
|
||||
if (object instanceof String) {
|
||||
String relocatedName = relocate((String) object, true);
|
||||
if (relocatedName != null) {
|
||||
return relocatedName;
|
||||
}
|
||||
}
|
||||
return super.mapValue(object);
|
||||
}
|
||||
|
||||
private String relocate(String name, boolean isStringValue) {
|
||||
String prefix = "";
|
||||
String suffix = "";
|
||||
|
||||
if (isStringValue) {
|
||||
Matcher m = CLASS_PATTERN.matcher(name);
|
||||
if (m.matches()) {
|
||||
prefix = m.group(1) + "L";
|
||||
name = m.group(2);
|
||||
suffix = ";";
|
||||
}
|
||||
}
|
||||
|
||||
Matcher m = VERSION_PATTERN.matcher(name);
|
||||
if (m.matches()) {
|
||||
prefix = m.group(1);
|
||||
name = m.group(2);
|
||||
}
|
||||
|
||||
for (Relocation r : this.rules) {
|
||||
if (isStringValue && r.canRelocateClass(name)) {
|
||||
return prefix + r.relocateClass(name) + suffix;
|
||||
} else if (r.canRelocatePath(name)) {
|
||||
return prefix + r.relocatePath(name) + suffix;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
151
src/main/java/net/anvilcraft/gradlehaxe/util/Relocation.java
Normal file
151
src/main/java/net/anvilcraft/gradlehaxe/util/Relocation.java
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.anvilcraft.gradlehaxe.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A relocation rule
|
||||
*/
|
||||
public class Relocation {
|
||||
private final String pattern;
|
||||
private final String relocatedPattern;
|
||||
private final String pathPattern;
|
||||
private final String relocatedPathPattern;
|
||||
|
||||
private final Set<String> includes;
|
||||
private final Set<String> excludes;
|
||||
|
||||
/**
|
||||
* Creates a new relocation
|
||||
*
|
||||
* @param pattern the pattern to match
|
||||
* @param relocatedPattern the pattern to relocate to
|
||||
* @param includes a collection of patterns which this rule should specifically
|
||||
* include
|
||||
* @param excludes a collection of patterns which this rule should specifically
|
||||
* exclude
|
||||
*/
|
||||
public Relocation(
|
||||
String pattern,
|
||||
String relocatedPattern,
|
||||
Collection<String> includes,
|
||||
Collection<String> excludes
|
||||
) {
|
||||
this.pattern = pattern.replace('/', '.');
|
||||
this.pathPattern = pattern.replace('.', '/');
|
||||
this.relocatedPattern = relocatedPattern.replace('/', '.');
|
||||
this.relocatedPathPattern = relocatedPattern.replace('.', '/');
|
||||
|
||||
if (includes != null && !includes.isEmpty()) {
|
||||
this.includes = normalizePatterns(includes);
|
||||
this.includes.addAll(includes);
|
||||
} else {
|
||||
this.includes = null;
|
||||
}
|
||||
|
||||
if (excludes != null && !excludes.isEmpty()) {
|
||||
this.excludes = normalizePatterns(excludes);
|
||||
this.excludes.addAll(excludes);
|
||||
} else {
|
||||
this.excludes = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new relocation with no specific includes or excludes
|
||||
*
|
||||
* @param pattern the pattern to match
|
||||
* @param relocatedPattern the pattern to relocate to
|
||||
*/
|
||||
public Relocation(String pattern, String relocatedPattern) {
|
||||
this(
|
||||
pattern,
|
||||
relocatedPattern,
|
||||
Collections.<String>emptyList(),
|
||||
Collections.<String>emptyList()
|
||||
);
|
||||
}
|
||||
|
||||
private boolean isIncluded(String path) {
|
||||
if (this.includes == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String include : this.includes) {
|
||||
if (SelectorUtils.matchPath(include, path, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isExcluded(String path) {
|
||||
if (this.excludes == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (String exclude : this.excludes) {
|
||||
if (SelectorUtils.matchPath(exclude, path, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean canRelocatePath(String path) {
|
||||
if (path.endsWith(".class")) {
|
||||
path = path.substring(0, path.length() - 6);
|
||||
}
|
||||
|
||||
if (!isIncluded(path) || isExcluded(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path.startsWith(this.pathPattern)
|
||||
|| path.startsWith("/" + this.pathPattern);
|
||||
}
|
||||
|
||||
boolean canRelocateClass(String clazz) {
|
||||
return clazz.indexOf('/') == -1 && canRelocatePath(clazz.replace('.', '/'));
|
||||
}
|
||||
|
||||
String relocatePath(String path) {
|
||||
return path.replaceFirst(this.pathPattern, this.relocatedPathPattern);
|
||||
}
|
||||
|
||||
String relocateClass(String clazz) {
|
||||
return clazz.replaceFirst(this.pattern, this.relocatedPattern);
|
||||
}
|
||||
|
||||
private static Set<String> normalizePatterns(Collection<String> patterns) {
|
||||
Set<String> normalized = new LinkedHashSet<>();
|
||||
for (String pattern : patterns) {
|
||||
String classPattern = pattern.replace('.', '/');
|
||||
normalized.add(classPattern);
|
||||
if (classPattern.endsWith("/*")) {
|
||||
String packagePattern
|
||||
= classPattern.substring(0, classPattern.lastIndexOf('/'));
|
||||
normalized.add(packagePattern);
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
}
|
396
src/main/java/net/anvilcraft/gradlehaxe/util/SelectorUtils.java
Normal file
396
src/main/java/net/anvilcraft/gradlehaxe/util/SelectorUtils.java
Normal file
|
@ -0,0 +1,396 @@
|
|||
/*
|
||||
* The Apache Software License, Version 1.1
|
||||
*
|
||||
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. The end-user documentation included with the redistribution, if
|
||||
* any, must include the following acknowlegement:
|
||||
* "This product includes software developed by the
|
||||
* Apache Software Foundation (http://www.codehaus.org/)."
|
||||
* Alternately, this acknowlegement may appear in the software itself,
|
||||
* if and wherever such third-party acknowlegements normally appear.
|
||||
*
|
||||
* 4. The names "Ant" and "Apache Software
|
||||
* Foundation" must not be used to endorse or promote products derived
|
||||
* from this software without prior written permission. For written
|
||||
* permission, please contact codehaus@codehaus.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "Apache"
|
||||
* nor may "Apache" appear in their names without prior written
|
||||
* permission of the Apache Group.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This software consists of voluntary contributions made by many
|
||||
* individuals on behalf of the Apache Software Foundation. For more
|
||||
* information on the Apache Software Foundation, please see
|
||||
* <http://www.codehaus.org/>.
|
||||
*/
|
||||
|
||||
package net.anvilcraft.gradlehaxe.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* This is a stripped down version of org.codehaus.plexus.util.SelectorUtils for
|
||||
* use in {@link Relocation}.
|
||||
*
|
||||
* @author Arnout J. Kuiper <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
|
||||
* @author Magesh Umasankar
|
||||
* @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
|
||||
*/
|
||||
final class SelectorUtils {
|
||||
private static final String PATTERN_HANDLER_PREFIX = "[";
|
||||
private static final String PATTERN_HANDLER_SUFFIX = "]";
|
||||
private static final String REGEX_HANDLER_PREFIX = "%regex" + PATTERN_HANDLER_PREFIX;
|
||||
private static final String ANT_HANDLER_PREFIX = "%ant" + PATTERN_HANDLER_PREFIX;
|
||||
|
||||
private static boolean isAntPrefixedPattern(String pattern) {
|
||||
return pattern.length()
|
||||
> (ANT_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1)
|
||||
&& pattern.startsWith(ANT_HANDLER_PREFIX)
|
||||
&& pattern.endsWith(PATTERN_HANDLER_SUFFIX);
|
||||
}
|
||||
|
||||
// When str starts with a File.separator, pattern has to start with a File.separator.
|
||||
// When pattern starts with a File.separator, str has to start with a File.separator.
|
||||
private static boolean
|
||||
separatorPatternStartSlashMismatch(String pattern, String str, String separator) {
|
||||
return str.startsWith(separator) != pattern.startsWith(separator);
|
||||
}
|
||||
|
||||
public static boolean matchPath(String pattern, String str, boolean isCaseSensitive) {
|
||||
return matchPath(pattern, str, File.separator, isCaseSensitive);
|
||||
}
|
||||
|
||||
private static boolean
|
||||
matchPath(String pattern, String str, String separator, boolean isCaseSensitive) {
|
||||
if (isRegexPrefixedPattern(pattern)) {
|
||||
pattern = pattern.substring(
|
||||
REGEX_HANDLER_PREFIX.length(),
|
||||
pattern.length() - PATTERN_HANDLER_SUFFIX.length()
|
||||
);
|
||||
return str.matches(pattern);
|
||||
} else {
|
||||
if (isAntPrefixedPattern(pattern)) {
|
||||
pattern = pattern.substring(
|
||||
ANT_HANDLER_PREFIX.length(),
|
||||
pattern.length() - PATTERN_HANDLER_SUFFIX.length()
|
||||
);
|
||||
}
|
||||
return matchAntPathPattern(pattern, str, separator, isCaseSensitive);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isRegexPrefixedPattern(String pattern) {
|
||||
return pattern.length()
|
||||
> (REGEX_HANDLER_PREFIX.length() + PATTERN_HANDLER_SUFFIX.length() + 1)
|
||||
&& pattern.startsWith(REGEX_HANDLER_PREFIX)
|
||||
&& pattern.endsWith(PATTERN_HANDLER_SUFFIX);
|
||||
}
|
||||
|
||||
private static boolean matchAntPathPattern(
|
||||
String pattern, String str, String separator, boolean isCaseSensitive
|
||||
) {
|
||||
if (separatorPatternStartSlashMismatch(pattern, str, separator)) {
|
||||
return false;
|
||||
}
|
||||
String[] patDirs = tokenizePathToString(pattern, separator);
|
||||
String[] strDirs = tokenizePathToString(str, separator);
|
||||
return matchAntPathPattern(patDirs, strDirs, isCaseSensitive);
|
||||
}
|
||||
|
||||
private static boolean
|
||||
matchAntPathPattern(String[] patDirs, String[] strDirs, boolean isCaseSensitive) {
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = patDirs.length - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strDirs.length - 1;
|
||||
|
||||
// up to first '**'
|
||||
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
String patDir = patDirs[patIdxStart];
|
||||
if (patDir.equals("**")) {
|
||||
break;
|
||||
}
|
||||
if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) {
|
||||
return false;
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// String is exhausted
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (!patDirs[i].equals("**")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (patIdxStart > patIdxEnd) {
|
||||
// String not exhausted, but pattern is. Failure.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// up to last '**'
|
||||
while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
String patDir = patDirs[patIdxEnd];
|
||||
if (patDir.equals("**")) {
|
||||
break;
|
||||
}
|
||||
if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) {
|
||||
return false;
|
||||
}
|
||||
patIdxEnd--;
|
||||
strIdxEnd--;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// String is exhausted
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (!patDirs[i].equals("**")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
int patIdxTmp = -1;
|
||||
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
|
||||
if (patDirs[i].equals("**")) {
|
||||
patIdxTmp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (patIdxTmp == patIdxStart + 1) {
|
||||
// '**/**' situation, so skip one
|
||||
patIdxStart++;
|
||||
continue;
|
||||
}
|
||||
// Find the pattern between padIdxStart & padIdxTmp in str between
|
||||
// strIdxStart & strIdxEnd
|
||||
int patLength = (patIdxTmp - patIdxStart - 1);
|
||||
int strLength = (strIdxEnd - strIdxStart + 1);
|
||||
int foundIdx = -1;
|
||||
strLoop:
|
||||
for (int i = 0; i <= strLength - patLength; i++) {
|
||||
for (int j = 0; j < patLength; j++) {
|
||||
String subPat = patDirs[patIdxStart + j + 1];
|
||||
String subStr = strDirs[strIdxStart + i + j];
|
||||
if (!match(subPat, subStr, isCaseSensitive)) {
|
||||
continue strLoop;
|
||||
}
|
||||
}
|
||||
|
||||
foundIdx = strIdxStart + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (foundIdx == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
patIdxStart = patIdxTmp;
|
||||
strIdxStart = foundIdx + patLength;
|
||||
}
|
||||
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (!patDirs[i].equals("**")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean match(String pattern, String str, boolean isCaseSensitive) {
|
||||
char[] patArr = pattern.toCharArray();
|
||||
char[] strArr = str.toCharArray();
|
||||
return match(patArr, strArr, isCaseSensitive);
|
||||
}
|
||||
|
||||
private static boolean match(char[] patArr, char[] strArr, boolean isCaseSensitive) {
|
||||
int patIdxStart = 0;
|
||||
int patIdxEnd = patArr.length - 1;
|
||||
int strIdxStart = 0;
|
||||
int strIdxEnd = strArr.length - 1;
|
||||
char ch;
|
||||
|
||||
boolean containsStar = false;
|
||||
for (char aPatArr : patArr) {
|
||||
if (aPatArr == '*') {
|
||||
containsStar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containsStar) {
|
||||
// No '*'s, so we make a shortcut
|
||||
if (patIdxEnd != strIdxEnd) {
|
||||
return false; // Pattern and string do not have the same size
|
||||
}
|
||||
for (int i = 0; i <= patIdxEnd; i++) {
|
||||
ch = patArr[i];
|
||||
if (ch != '?' && !equals(ch, strArr[i], isCaseSensitive)) {
|
||||
return false; // Character mismatch
|
||||
}
|
||||
}
|
||||
return true; // String matches against pattern
|
||||
}
|
||||
|
||||
if (patIdxEnd == 0) {
|
||||
return true; // Pattern contains only '*', which matches anything
|
||||
}
|
||||
|
||||
// Process characters before first star
|
||||
while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
|
||||
if (ch != '?' && !equals(ch, strArr[strIdxStart], isCaseSensitive)) {
|
||||
return false; // Character mismatch
|
||||
}
|
||||
patIdxStart++;
|
||||
strIdxStart++;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// All characters in the string are used. Check if only '*'s are
|
||||
// left in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (patArr[i] != '*') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Process characters after last star
|
||||
while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
|
||||
if (ch != '?' && !equals(ch, strArr[strIdxEnd], isCaseSensitive)) {
|
||||
return false; // Character mismatch
|
||||
}
|
||||
patIdxEnd--;
|
||||
strIdxEnd--;
|
||||
}
|
||||
if (strIdxStart > strIdxEnd) {
|
||||
// All characters in the string are used. Check if only '*'s are
|
||||
// left in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (patArr[i] != '*') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// process pattern between stars. padIdxStart and patIdxEnd point
|
||||
// always to a '*'.
|
||||
while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
|
||||
int patIdxTmp = -1;
|
||||
for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
|
||||
if (patArr[i] == '*') {
|
||||
patIdxTmp = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (patIdxTmp == patIdxStart + 1) {
|
||||
// Two stars next to each other, skip the first one.
|
||||
patIdxStart++;
|
||||
continue;
|
||||
}
|
||||
// Find the pattern between padIdxStart & padIdxTmp in str between
|
||||
// strIdxStart & strIdxEnd
|
||||
int patLength = (patIdxTmp - patIdxStart - 1);
|
||||
int strLength = (strIdxEnd - strIdxStart + 1);
|
||||
int foundIdx = -1;
|
||||
strLoop:
|
||||
for (int i = 0; i <= strLength - patLength; i++) {
|
||||
for (int j = 0; j < patLength; j++) {
|
||||
ch = patArr[patIdxStart + j + 1];
|
||||
if (ch != '?'
|
||||
&& !equals(ch, strArr[strIdxStart + i + j], isCaseSensitive)) {
|
||||
continue strLoop;
|
||||
}
|
||||
}
|
||||
|
||||
foundIdx = strIdxStart + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (foundIdx == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
patIdxStart = patIdxTmp;
|
||||
strIdxStart = foundIdx + patLength;
|
||||
}
|
||||
|
||||
// All characters in the string are used. Check if only '*'s are left
|
||||
// in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for (int i = patIdxStart; i <= patIdxEnd; i++) {
|
||||
if (patArr[i] != '*') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether two characters are equal.
|
||||
*/
|
||||
private static boolean equals(char c1, char c2, boolean isCaseSensitive) {
|
||||
if (c1 == c2) {
|
||||
return true;
|
||||
}
|
||||
if (!isCaseSensitive) {
|
||||
// NOTE: Try both upper case and lower case as done by
|
||||
// String.equalsIgnoreCase()
|
||||
if (Character.toUpperCase(c1) == Character.toUpperCase(c2)
|
||||
|| Character.toLowerCase(c1) == Character.toLowerCase(c2)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String[] tokenizePathToString(String path, String separator) {
|
||||
List<String> ret = new ArrayList<String>();
|
||||
StringTokenizer st = new StringTokenizer(path, separator);
|
||||
while (st.hasMoreTokens()) {
|
||||
ret.add(st.nextToken());
|
||||
}
|
||||
return ret.toArray(new String[ret.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private Constructor
|
||||
*/
|
||||
private SelectorUtils() {}
|
||||
}
|
Loading…
Reference in a new issue