mirror of
https://github.com/Guardsquare/proguard.git
synced 2026-03-13 09:50:34 +08:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af475c65b4 | ||
|
|
8d7ddf898c | ||
|
|
f5f2f06334 | ||
|
|
aa43b9dc21 | ||
|
|
0d9ceb7451 | ||
|
|
1d28c11e36 | ||
|
|
b85b2cb201 | ||
|
|
0c95982828 | ||
|
|
38de2e42b2 | ||
|
|
76b2921738 | ||
|
|
7483ad32f4 | ||
|
|
20c99aa3e8 | ||
|
|
858bcd0eb5 | ||
|
|
1c421bf780 | ||
|
|
d4692c3835 | ||
|
|
712fd768ca | ||
|
|
c35913c3f2 | ||
|
|
5a8d50090a | ||
|
|
06c2d12f7a | ||
|
|
a7265a3536 | ||
|
|
7160a9e484 | ||
|
|
12c9c3f23e | ||
|
|
a02100cb93 | ||
|
|
38a0e498b9 | ||
|
|
f6b82b1478 | ||
|
|
789777ded5 | ||
|
|
e76e47953f | ||
|
|
836253f1da | ||
|
|
f92fc632b1 | ||
|
|
f5f04cbec5 | ||
|
|
ce2c8a8b5d | ||
|
|
0032aa037c | ||
|
|
0070bc9e80 | ||
|
|
6f3610bd7b | ||
|
|
813616d095 | ||
|
|
04123e8f9b | ||
|
|
7c153f8eec | ||
|
|
76cf000348 | ||
|
|
549e2cde2c | ||
|
|
f04ef27f66 | ||
|
|
bfdfa02f8c | ||
|
|
58eae9eed5 | ||
|
|
7429219cd2 | ||
|
|
8bb7cc0c4b | ||
|
|
9a7a97d1ca |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ build
|
||||
local.properties
|
||||
/lib/
|
||||
docs/html
|
||||
.kotlin
|
||||
|
||||
@@ -109,7 +109,7 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.1.0'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.5.0'
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -188,7 +188,7 @@ You can publish the artifacts to your local Maven repository using:
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions, issues and feature requests are welcome in both projects.
|
||||
Feel free to check the [issues](issues) page and the [contributing
|
||||
Feel free to check the [issues](https://github.com/Guardsquare/proguard/issues) page and the [contributing
|
||||
guide](CONTRIBUTING.md) if you would like to contribute.
|
||||
|
||||
## 📝 License
|
||||
|
||||
@@ -4,7 +4,6 @@ plugins {
|
||||
id 'maven-publish'
|
||||
id "org.jetbrains.kotlin.jvm" version "$kotlinVersion"
|
||||
id 'com.adarshr.test-logger' version '3.0.0'
|
||||
id 'de.jansauer.printcoverage' version '2.0.0'
|
||||
id 'jacoco'
|
||||
id "org.jlleitschuh.gradle.ktlint" version '10.2.1'
|
||||
}
|
||||
@@ -24,17 +23,17 @@ dependencies {
|
||||
implementation "com.google.code.gson:gson:${gsonVersion}"
|
||||
implementation 'org.apache.logging.log4j:log4j-api:2.19.0'
|
||||
implementation 'org.apache.logging.log4j:log4j-core:2.19.0'
|
||||
implementation 'org.json:json:20220924'
|
||||
implementation 'org.json:json:20231013'
|
||||
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
||||
testImplementation 'dev.zacsweers.kctfork:core:0.2.1'
|
||||
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.5.4' // for kotest framework
|
||||
testImplementation 'io.kotest:kotest-assertions-core-jvm:5.5.4' // for kotest core jvm assertions
|
||||
testImplementation 'io.kotest:kotest-property-jvm:5.5.4' // for kotest property test
|
||||
testImplementation 'io.mockk:mockk:1.13.2' // for mocking
|
||||
testImplementation 'dev.zacsweers.kctfork:core:0.5.0-alpha07'
|
||||
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.9.0' // for kotest framework
|
||||
testImplementation 'io.kotest:kotest-assertions-core-jvm:5.9.0' // for kotest core jvm assertions
|
||||
testImplementation 'io.kotest:kotest-property-jvm:5.9.0' // for kotest property test
|
||||
testImplementation 'io.mockk:mockk:1.13.11' // for mocking
|
||||
|
||||
testImplementation(testFixtures("com.guardsquare:proguard-core:9.0.8")) {
|
||||
testImplementation(testFixtures("com.guardsquare:proguard-core:${proguardCoreVersion}")) {
|
||||
exclude group: 'com.guardsquare', module: 'proguard-core'
|
||||
}
|
||||
}
|
||||
@@ -50,7 +49,7 @@ jar {
|
||||
// Early access automatic downloads are not yet supported:
|
||||
// https://github.com/gradle/gradle/issues/14814
|
||||
// But it will work if e.g. Java N-ea is pre-installed
|
||||
def javaVersionsForTest = 9..19
|
||||
def javaVersionsForTest = 9..22
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
@@ -64,8 +63,8 @@ task testAllJavaVersions() { testAllTask ->
|
||||
useJUnitPlatform()
|
||||
ignoreFailures = true
|
||||
|
||||
// The version of bytebuddy used by mockk only supports Java 20 experimentally so far
|
||||
if (version == 20) systemProperty 'net.bytebuddy.experimental', true
|
||||
// The version of bytebuddy used by mockk only supports Java 22 experimentally so far
|
||||
if (version >= 22) systemProperty 'net.bytebuddy.experimental', true
|
||||
|
||||
testAllTask.dependsOn(it)
|
||||
|
||||
@@ -86,9 +85,11 @@ jacocoTestReport {
|
||||
classDirectories.setFrom(classes)
|
||||
executionData.setFrom project.fileTree(dir: '.', include: '**/build/jacoco/*.exec')
|
||||
reports {
|
||||
xml.enabled true
|
||||
csv.enabled false
|
||||
html.destination file("${buildDir}/reports/coverage")
|
||||
xml.required = true
|
||||
csv.required = false
|
||||
}
|
||||
javaVersionsForTest.each { version ->
|
||||
mustRunAfter "testJava$version"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,9 +41,9 @@ public class ClassSpecification implements Cloneable
|
||||
public final String extendsAnnotationType;
|
||||
public final String extendsClassName;
|
||||
|
||||
public final List attributeNames = null;
|
||||
public List fieldSpecifications;
|
||||
public List methodSpecifications;
|
||||
public final List<String> attributeNames = null;
|
||||
public List<MemberSpecification> fieldSpecifications;
|
||||
public List<MemberSpecification> methodSpecifications;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,6 +116,11 @@ public class ConfigurationConstants
|
||||
public static final String DONT_PROCESS_KOTLIN_METADATA = "-dontprocesskotlinmetadata";
|
||||
public static final String OPTIMIZE_AGGRESSIVELY = "-optimizeaggressively";
|
||||
|
||||
public static final String ALWAYS_INLINE = "-alwaysinline";
|
||||
public static final String IDENTIFIER_NAME_STRING = "-identifiernamestring";
|
||||
public static final String MAXIMUM_REMOVED_ANDROID_LOG_LEVEL = "-maximumremovedandroidloglevel";
|
||||
|
||||
|
||||
public static final String ANY_FILE_KEYWORD = "**";
|
||||
|
||||
public static final String ANY_ATTRIBUTE_KEYWORD = "*";
|
||||
|
||||
@@ -20,13 +20,26 @@
|
||||
*/
|
||||
package proguard;
|
||||
|
||||
import proguard.classfile.*;
|
||||
import proguard.classfile.AccessConstants;
|
||||
import proguard.classfile.ClassConstants;
|
||||
import proguard.classfile.JavaAccessConstants;
|
||||
import proguard.classfile.JavaTypeConstants;
|
||||
import proguard.classfile.TypeConstants;
|
||||
import proguard.classfile.util.ClassUtil;
|
||||
import proguard.util.*;
|
||||
import proguard.util.ListUtil;
|
||||
import proguard.util.StringUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.LineNumberReader;
|
||||
import java.io.StringReader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
|
||||
/**
|
||||
@@ -139,9 +152,24 @@ public class ConfigurationParser implements AutoCloseable
|
||||
* @throws IOException if an IO error occurs while reading a configuration.
|
||||
*/
|
||||
public void parse(Configuration configuration)
|
||||
throws ParseException, IOException {
|
||||
parse(configuration, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses and returns the configuration.
|
||||
*
|
||||
* @param configuration the configuration that is updated as a side-effect.
|
||||
* @param unknownOptionHandler optional handler for unknown options; if null then a {@link ParseException}
|
||||
* is thrown when encountering an unknown option.
|
||||
* @throws ParseException if the any of the configuration settings contains
|
||||
* a syntax error.
|
||||
* @throws IOException if an IO error occurs while reading a configuration.
|
||||
*/
|
||||
public void parse(Configuration configuration, BiConsumer<String, String> unknownOptionHandler)
|
||||
throws ParseException, IOException
|
||||
{
|
||||
while (nextWord != null)
|
||||
parseWord: while (nextWord != null)
|
||||
{
|
||||
lastComments = reader.lastComments();
|
||||
|
||||
@@ -230,9 +258,20 @@ public class ConfigurationParser implements AutoCloseable
|
||||
else if (ConfigurationConstants.DUMP_OPTION .startsWith(nextWord)) configuration.dump = parseOptionalFile();
|
||||
else if (ConfigurationConstants.ADD_CONFIGURATION_DEBUGGING_OPTION .startsWith(nextWord)) configuration.addConfigurationDebugging = parseNoArgument(true);
|
||||
else if (ConfigurationConstants.OPTIMIZE_AGGRESSIVELY .startsWith(nextWord)) configuration.optimizeConservatively = parseNoArgument(false);
|
||||
else if (ConfigurationConstants.ALWAYS_INLINE .startsWith(nextWord)) parseUnsupportedR8Rules(ConfigurationConstants.ALWAYS_INLINE, true);
|
||||
else if (ConfigurationConstants.IDENTIFIER_NAME_STRING .startsWith(nextWord)) parseUnsupportedR8Rules(ConfigurationConstants.IDENTIFIER_NAME_STRING, true);
|
||||
else if (ConfigurationConstants.MAXIMUM_REMOVED_ANDROID_LOG_LEVEL .equals(nextWord)) parseMaximumRemovedAndroidLogLevel();
|
||||
else
|
||||
{
|
||||
throw new ParseException("Unknown option " + reader.locationDescription());
|
||||
if (unknownOptionHandler != null) {
|
||||
unknownOptionHandler.accept(nextWord, reader.lineLocationDescription());
|
||||
while (nextWord != null) {
|
||||
readNextWord();
|
||||
if (nextWord != null && nextWord.startsWith("-")) {
|
||||
continue parseWord;
|
||||
}
|
||||
}
|
||||
} else throw new ParseException("Unknown option " + reader.locationDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -850,7 +889,7 @@ public class ConfigurationParser implements AutoCloseable
|
||||
int requiredUnsetClassAccessFlags = 0;
|
||||
|
||||
// Parse the class annotations and access modifiers until the class keyword.
|
||||
while (!ConfigurationConstants.CLASS_KEYWORD.equals(nextWord))
|
||||
while (!ConfigurationConstants.CLASS_KEYWORD.equals(nextWord) && !configurationEnd(true))
|
||||
{
|
||||
// Strip the negating sign, if any.
|
||||
boolean negated =
|
||||
@@ -1104,12 +1143,25 @@ public class ConfigurationParser implements AutoCloseable
|
||||
// Parse the class member type and name part.
|
||||
|
||||
// Did we get a special wildcard?
|
||||
if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord) ||
|
||||
ConfigurationConstants.ANY_FIELD_KEYWORD .equals(nextWord) ||
|
||||
ConfigurationConstants.ANY_METHOD_KEYWORD .equals(nextWord))
|
||||
boolean isStar = ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord);
|
||||
boolean isFields = ConfigurationConstants.ANY_FIELD_KEYWORD.equals(nextWord);
|
||||
boolean isMethods = ConfigurationConstants.ANY_METHOD_KEYWORD.equals(nextWord);
|
||||
boolean isFieldsOrMethods = isFields || isMethods;
|
||||
|
||||
String type = nextWord;
|
||||
String typeLocation = reader.locationDescription();
|
||||
|
||||
// Try to read the class member name; we need to do this now so that we can check the nextWord
|
||||
// to see if we're parsing a wildcard type.
|
||||
readNextWord("class member name", false, false, false);
|
||||
|
||||
// Is it a wildcard star (short for all members) or is a type wildcard?
|
||||
boolean isReallyStar = isStar && ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord);
|
||||
|
||||
if (isFieldsOrMethods || isReallyStar)
|
||||
{
|
||||
// Act according to the type of wildcard.
|
||||
if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD.equals(nextWord))
|
||||
if (isStar)
|
||||
{
|
||||
checkFieldAccessFlags(requiredSetMemberAccessFlags,
|
||||
requiredUnsetMemberAccessFlags);
|
||||
@@ -1129,10 +1181,10 @@ public class ConfigurationParser implements AutoCloseable
|
||||
null,
|
||||
null));
|
||||
}
|
||||
else if (ConfigurationConstants.ANY_FIELD_KEYWORD.equals(nextWord))
|
||||
else if (isFields)
|
||||
{
|
||||
checkFieldAccessFlags(requiredSetMemberAccessFlags,
|
||||
requiredUnsetMemberAccessFlags);
|
||||
requiredUnsetMemberAccessFlags);
|
||||
|
||||
classSpecification.addField(
|
||||
new MemberSpecification(requiredSetMemberAccessFlags,
|
||||
@@ -1141,7 +1193,7 @@ public class ConfigurationParser implements AutoCloseable
|
||||
null,
|
||||
null));
|
||||
}
|
||||
else if (ConfigurationConstants.ANY_METHOD_KEYWORD.equals(nextWord))
|
||||
else if (isMethods)
|
||||
{
|
||||
checkMethodAccessFlags(requiredSetMemberAccessFlags,
|
||||
requiredUnsetMemberAccessFlags);
|
||||
@@ -1154,9 +1206,6 @@ public class ConfigurationParser implements AutoCloseable
|
||||
null));
|
||||
}
|
||||
|
||||
// We still have to read the closing separator.
|
||||
readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'");
|
||||
|
||||
if (!ConfigurationConstants.SEPARATOR_KEYWORD.equals(nextWord))
|
||||
{
|
||||
throw new ParseException("Expecting separator '" + ConfigurationConstants.SEPARATOR_KEYWORD +
|
||||
@@ -1165,37 +1214,37 @@ public class ConfigurationParser implements AutoCloseable
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure we have a proper type.
|
||||
checkJavaIdentifier("java type");
|
||||
String type = nextWord;
|
||||
String typeLocation = reader.locationDescription();
|
||||
|
||||
readNextWord("class member name");
|
||||
String name = nextWord;
|
||||
checkJavaIdentifier("java type", type, true);
|
||||
|
||||
// Did we get just one word before the opening parenthesis?
|
||||
if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(name))
|
||||
{
|
||||
// This must be a constructor then.
|
||||
// Make sure the type is a proper constructor name.
|
||||
if (!(type.equals(ClassConstants.METHOD_NAME_INIT) ||
|
||||
type.equals(externalClassName) ||
|
||||
type.equals(ClassUtil.externalShortClassName(externalClassName))))
|
||||
// This must be an initializer then.
|
||||
// Make sure the type is a proper initializer name.
|
||||
if (ClassUtil.isInitializer(type))
|
||||
{
|
||||
name = type; // This is either `<init>` or `<clinit>`.
|
||||
type = JavaTypeConstants.VOID;
|
||||
}
|
||||
else if (type.equals(externalClassName) ||
|
||||
type.equals(ClassUtil.externalShortClassName(externalClassName)))
|
||||
{
|
||||
name = ClassConstants.METHOD_NAME_INIT;
|
||||
type = JavaTypeConstants.VOID;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ParseException("Expecting type and name " +
|
||||
"instead of just '" + type +
|
||||
"' before " + reader.locationDescription());
|
||||
}
|
||||
|
||||
// Assign the fixed constructor type and name.
|
||||
type = JavaTypeConstants.VOID;
|
||||
name = ClassConstants.METHOD_NAME_INIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// It's not a constructor.
|
||||
// It's not an initializer.
|
||||
// Make sure we have a proper name.
|
||||
checkJavaIdentifier("class member name");
|
||||
checkNextWordIsJavaIdentifier("class member name");
|
||||
|
||||
// Read the opening parenthesis or the separating
|
||||
// semi-colon.
|
||||
@@ -1204,7 +1253,7 @@ public class ConfigurationParser implements AutoCloseable
|
||||
}
|
||||
|
||||
// Check if the type actually contains the use of generics.
|
||||
// Can not do it right away as we also support "<init>" as a type (see case above).
|
||||
// Can not do it right away as we also support "<init>" and "<clinit>" as a type (see case above).
|
||||
if (containsGenerics(type))
|
||||
{
|
||||
throw new ParseException("Generics are not allowed (erased) for java type" + typeLocation);
|
||||
@@ -1285,6 +1334,14 @@ public class ConfigurationParser implements AutoCloseable
|
||||
"' before " + reader.locationDescription());
|
||||
}
|
||||
|
||||
// Class initializers are not supposed to have any parameters.
|
||||
if (ClassConstants.METHOD_NAME_CLINIT.equals(name) &&
|
||||
ClassUtil.internalMethodParameterCount(descriptor) > 0)
|
||||
{
|
||||
throw new ParseException("Not expecting method parameters with initializer '" + ClassConstants.METHOD_NAME_CLINIT +
|
||||
"' before " + reader.locationDescription());
|
||||
}
|
||||
|
||||
// Read the separator after the closing parenthesis.
|
||||
readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'");
|
||||
|
||||
@@ -1613,7 +1670,7 @@ public class ConfigurationParser implements AutoCloseable
|
||||
{
|
||||
if (checkJavaIdentifiers)
|
||||
{
|
||||
checkJavaIdentifier("java type", allowGenerics);
|
||||
checkNextWordIsJavaIdentifier("java type", allowGenerics);
|
||||
}
|
||||
|
||||
if (replaceSystemProperties)
|
||||
@@ -1880,30 +1937,34 @@ public class ConfigurationParser implements AutoCloseable
|
||||
* Checks whether the given word is a valid Java identifier and throws
|
||||
* a ParseException if it isn't. Wildcard characters are accepted.
|
||||
*/
|
||||
private void checkJavaIdentifier(String expectedDescription)
|
||||
private void checkNextWordIsJavaIdentifier(String expectedDescription)
|
||||
throws ParseException
|
||||
{
|
||||
checkJavaIdentifier(expectedDescription, true);
|
||||
checkNextWordIsJavaIdentifier(expectedDescription, true);
|
||||
}
|
||||
|
||||
private void checkNextWordIsJavaIdentifier(String expectedDescription, boolean allowGenerics) throws ParseException
|
||||
{
|
||||
checkJavaIdentifier(expectedDescription, nextWord, allowGenerics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given word is a valid Java identifier and throws
|
||||
* a ParseException if it isn't. Wildcard characters are accepted.
|
||||
*/
|
||||
private void checkJavaIdentifier(String expectedDescription, boolean allowGenerics)
|
||||
throws ParseException
|
||||
private void checkJavaIdentifier(String expectedDescription, String identifier, boolean allowGenerics)
|
||||
throws ParseException
|
||||
{
|
||||
if (!isJavaIdentifier(nextWord))
|
||||
if (!isJavaIdentifier(identifier))
|
||||
{
|
||||
throw new ParseException("Expecting " + expectedDescription +
|
||||
" before " + reader.locationDescription());
|
||||
" before " + reader.locationDescription());
|
||||
}
|
||||
|
||||
if (!allowGenerics && containsGenerics(nextWord))
|
||||
if (!allowGenerics && containsGenerics(identifier))
|
||||
{
|
||||
throw new ParseException("Generics are not allowed (erased) in " + expectedDescription +
|
||||
" " + reader.locationDescription());
|
||||
" " + reader.locationDescription());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2018,6 +2079,34 @@ public class ConfigurationParser implements AutoCloseable
|
||||
}
|
||||
|
||||
|
||||
private void parseUnsupportedR8Rules(String option, boolean parseClassSpecification) throws IOException, ParseException
|
||||
{
|
||||
readNextWord();
|
||||
|
||||
if (parseClassSpecification)
|
||||
{
|
||||
parseClassSpecificationArguments();
|
||||
}
|
||||
|
||||
|
||||
warnUnsupportedR8Option(option);
|
||||
}
|
||||
|
||||
private void parseMaximumRemovedAndroidLogLevel() throws IOException, ParseException {
|
||||
parseIntegerArgument();
|
||||
if (!configurationEnd(true)) {
|
||||
parseClassSpecificationArguments();
|
||||
}
|
||||
|
||||
warnUnsupportedR8Option(ConfigurationConstants.MAXIMUM_REMOVED_ANDROID_LOG_LEVEL);
|
||||
}
|
||||
|
||||
private static void warnUnsupportedR8Option(String option) {
|
||||
System.out.println("Warning: The R8 option " + option + " is currently not supported by ProGuard.\n" +
|
||||
"This option will have no effect on the optimized artifact.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A main method for testing configuration parsing.
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,8 @@ public class ConfigurationWriter implements AutoCloseable
|
||||
|
||||
|
||||
private final PrintWriter writer;
|
||||
private File baseDir;
|
||||
private File configurationFile;
|
||||
private String baseDirName;
|
||||
|
||||
|
||||
/**
|
||||
@@ -60,7 +61,11 @@ public class ConfigurationWriter implements AutoCloseable
|
||||
{
|
||||
this(PrintWriterUtil.createPrintWriterOut(configurationFile));
|
||||
|
||||
baseDir = configurationFile.getParentFile();
|
||||
this.configurationFile = configurationFile;
|
||||
if (configurationFile.getParentFile() != null)
|
||||
{
|
||||
baseDirName = configurationFile.getParentFile().getAbsolutePath() + File.separator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +84,7 @@ public class ConfigurationWriter implements AutoCloseable
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
PrintWriterUtil.closePrintWriter(baseDir, writer);
|
||||
PrintWriterUtil.closePrintWriter(configurationFile, writer);
|
||||
}
|
||||
|
||||
|
||||
@@ -799,13 +804,9 @@ public class ConfigurationWriter implements AutoCloseable
|
||||
String fileName = file.getAbsolutePath();
|
||||
|
||||
// See if we can convert the file name into a relative file name.
|
||||
if (baseDir != null)
|
||||
if (baseDirName != null && fileName.startsWith(baseDirName))
|
||||
{
|
||||
String baseDirName = baseDir.getAbsolutePath() + File.separator;
|
||||
if (fileName.startsWith(baseDirName))
|
||||
{
|
||||
fileName = fileName.substring(baseDirName.length());
|
||||
}
|
||||
fileName = fileName.substring(baseDirName.length());
|
||||
}
|
||||
|
||||
return quotedString(fileName);
|
||||
@@ -819,6 +820,7 @@ public class ConfigurationWriter implements AutoCloseable
|
||||
{
|
||||
return string.length() == 0 ||
|
||||
string.indexOf(' ') >= 0 ||
|
||||
string.indexOf('#') >= 0 ||
|
||||
string.indexOf('@') >= 0 ||
|
||||
string.indexOf('{') >= 0 ||
|
||||
string.indexOf('}') >= 0 ||
|
||||
@@ -827,7 +829,7 @@ public class ConfigurationWriter implements AutoCloseable
|
||||
string.indexOf(':') >= 0 ||
|
||||
string.indexOf(';') >= 0 ||
|
||||
string.indexOf(',') >= 0 ? ("'" + string + "'") :
|
||||
( string );
|
||||
( string );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ import proguard.strip.KotlinAnnotationStripper;
|
||||
import proguard.util.ConstantMatcher;
|
||||
import proguard.util.ListParser;
|
||||
import proguard.util.NameParser;
|
||||
import proguard.util.PrintWriterUtil;
|
||||
import proguard.util.StringMatcher;
|
||||
import proguard.util.kotlin.KotlinUnsupportedVersionChecker;
|
||||
import proguard.util.kotlin.asserter.KotlinMetadataVerifier;
|
||||
@@ -297,9 +296,7 @@ public class ProGuard
|
||||
*/
|
||||
private void printConfiguration() throws IOException
|
||||
{
|
||||
PrintWriter pw = PrintWriterUtil.createPrintWriterOut(configuration.printConfiguration);
|
||||
|
||||
try (ConfigurationWriter configurationWriter = new ConfigurationWriter(pw))
|
||||
try (ConfigurationWriter configurationWriter = new ConfigurationWriter(configuration.printConfiguration))
|
||||
{
|
||||
configurationWriter.write(configuration);
|
||||
}
|
||||
|
||||
@@ -314,6 +314,12 @@ public class Backporter implements Pass
|
||||
appView.programClassPool.classesAccept(new ClassVersionSetter(targetClassVersion));
|
||||
}
|
||||
|
||||
// Backporting may introduce access issues, for example related to nest members/host.
|
||||
if (configuration.allowAccessModification)
|
||||
{
|
||||
appView.programClassPool.classesAccept(new AccessFixer());
|
||||
}
|
||||
|
||||
logger.info(" Number of converted string concatenations: {}", replacedStringConcatCounter.getCount());
|
||||
logger.info(" Number of converted lambda expressions: {}", lambdaExpressionCounter.getCount());
|
||||
logger.info(" Number of converted static interface methods: {}", staticInterfaceMethodCounter.getCount());
|
||||
|
||||
@@ -72,7 +72,7 @@ implements KotlinMetadataVisitor,
|
||||
kotlinClassKindMetadata.inlineClassUnderlyingPropertyTypeAccept(clazz, this);
|
||||
|
||||
kotlinClassKindMetadata.referencedClass.attributesAccept(annotationCounter.reset());
|
||||
kotlinClassKindMetadata.flags.common.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
kotlinClassKindMetadata.flags.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,28 +119,28 @@ implements KotlinMetadataVisitor,
|
||||
annotationCounter.reset()
|
||||
);
|
||||
|
||||
kotlinPropertyMetadata.flags.common.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
kotlinPropertyMetadata.flags.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
}
|
||||
else if (kotlinPropertyMetadata.referencedBackingField != null)
|
||||
{
|
||||
kotlinPropertyMetadata.referencedBackingField.accept(kotlinPropertyMetadata.referencedBackingFieldClass, annotationCounter);
|
||||
kotlinPropertyMetadata.flags.common.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
kotlinPropertyMetadata.flags.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
kotlinPropertyMetadata.flags.common.hasAnnotations = false;
|
||||
kotlinPropertyMetadata.flags.hasAnnotations = false;
|
||||
}
|
||||
|
||||
if (kotlinPropertyMetadata.flags.hasGetter && kotlinPropertyMetadata.referencedGetterMethod != null)
|
||||
if (kotlinPropertyMetadata.referencedGetterMethod != null)
|
||||
{
|
||||
kotlinPropertyMetadata.referencedGetterMethod.accept(clazz, annotationCounter.reset());
|
||||
kotlinPropertyMetadata.getterFlags.common.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
kotlinPropertyMetadata.getterFlags.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
}
|
||||
|
||||
if (kotlinPropertyMetadata.flags.hasSetter && kotlinPropertyMetadata.referencedSetterMethod != null)
|
||||
if (kotlinPropertyMetadata.flags.isVar && kotlinPropertyMetadata.referencedSetterMethod != null)
|
||||
{
|
||||
kotlinPropertyMetadata.referencedSetterMethod.accept(clazz, annotationCounter.reset());
|
||||
kotlinPropertyMetadata.setterFlags.common.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
kotlinPropertyMetadata.setterFlags.hasAnnotations = annotationCounter.getCount() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ implements KotlinMetadataVisitor,
|
||||
kotlinFunctionMetadata.returnTypeAccept( clazz, kotlinMetadata, this);
|
||||
|
||||
kotlinFunctionMetadata.referencedMethodAccept(annotationCounter.reset());
|
||||
kotlinFunctionMetadata.flags.common.hasAnnotations = annotationCounter.getCount() != 0;
|
||||
kotlinFunctionMetadata.flags.hasAnnotations = annotationCounter.getCount() != 0;
|
||||
}
|
||||
|
||||
// Implementations for KotlinConstructorVisitor.
|
||||
@@ -172,12 +172,12 @@ implements KotlinMetadataVisitor,
|
||||
if (kotlinClassKindMetadata.flags.isAnnotationClass)
|
||||
{
|
||||
//PROBBUG where are the annotations?
|
||||
kotlinConstructorMetadata.flags.common.hasAnnotations = false;
|
||||
kotlinConstructorMetadata.flags.hasAnnotations = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
kotlinConstructorMetadata.referencedMethodAccept(clazz, annotationCounter.reset());
|
||||
kotlinConstructorMetadata.flags.common.hasAnnotations = annotationCounter.getCount() != 0;
|
||||
kotlinConstructorMetadata.flags.hasAnnotations = annotationCounter.getCount() != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ implements KotlinMetadataVisitor,
|
||||
kotlinTypeAliasMetadata.expandedTypeAccept( clazz, kotlinDeclarationContainerMetadata, this);
|
||||
kotlinTypeAliasMetadata.versionRequirementAccept(clazz, kotlinDeclarationContainerMetadata, this);
|
||||
|
||||
kotlinTypeAliasMetadata.flags.common.hasAnnotations = !kotlinTypeAliasMetadata.annotations.isEmpty();
|
||||
kotlinTypeAliasMetadata.flags.hasAnnotations = !kotlinTypeAliasMetadata.annotations.isEmpty();
|
||||
}
|
||||
|
||||
// Implementations for KotlinTypeVisitor.
|
||||
@@ -202,8 +202,6 @@ implements KotlinMetadataVisitor,
|
||||
kotlinTypeMetadata.typeArgumentsAccept(clazz, this);
|
||||
kotlinTypeMetadata.upperBoundsAccept( clazz, this);
|
||||
kotlinTypeMetadata.abbreviationAccept( clazz, this);
|
||||
|
||||
kotlinTypeMetadata.flags.common.hasAnnotations = !kotlinTypeMetadata.annotations.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -213,7 +211,6 @@ implements KotlinMetadataVisitor,
|
||||
KotlinTypeMetadata kotlinTypeMetadata)
|
||||
{
|
||||
kotlinFunctionMetadata.referencedMethodAccept(this.annotationCounter.reset());
|
||||
kotlinTypeMetadata.flags.common.hasAnnotations = annotationCounter.getParameterAnnotationCount(0) > 0;
|
||||
}
|
||||
|
||||
// Implementations for KotlinTypeParameterVisitor.
|
||||
@@ -225,8 +222,6 @@ implements KotlinMetadataVisitor,
|
||||
public void visitAnyTypeParameter(Clazz clazz, KotlinTypeParameterMetadata kotlinTypeParameterMetadata)
|
||||
{
|
||||
kotlinTypeParameterMetadata.upperBoundsAccept(clazz, this);
|
||||
|
||||
kotlinTypeParameterMetadata.flags.common.hasAnnotations = !kotlinTypeParameterMetadata.annotations.isEmpty();
|
||||
}
|
||||
|
||||
// Implementations for KotlinValueParameterVisitor.
|
||||
@@ -242,10 +237,10 @@ implements KotlinMetadataVisitor,
|
||||
kotlinFunctionMetadata,
|
||||
this);
|
||||
|
||||
if (kotlinValueParameterMetadata.flags.common.hasAnnotations)
|
||||
if (kotlinValueParameterMetadata.flags.hasAnnotations)
|
||||
{
|
||||
kotlinFunctionMetadata.referencedMethodAccept(annotationCounter.reset());
|
||||
kotlinValueParameterMetadata.flags.common.hasAnnotations =
|
||||
kotlinValueParameterMetadata.flags.hasAnnotations =
|
||||
annotationCounter.getParameterAnnotationCount(kotlinValueParameterMetadata.index) > 0;
|
||||
}
|
||||
}
|
||||
@@ -261,12 +256,12 @@ implements KotlinMetadataVisitor,
|
||||
kotlinConstructorMetadata,
|
||||
this);
|
||||
|
||||
if (kotlinValueParameterMetadata.flags.common.hasAnnotations)
|
||||
if (kotlinValueParameterMetadata.flags.hasAnnotations)
|
||||
{
|
||||
if (!kotlinClassKindMetadata.flags.isAnnotationClass)
|
||||
{
|
||||
kotlinConstructorMetadata.referencedMethodAccept(clazz, annotationCounter.reset());
|
||||
kotlinValueParameterMetadata.flags.common.hasAnnotations =
|
||||
kotlinValueParameterMetadata.flags.hasAnnotations =
|
||||
annotationCounter.getParameterAnnotationCount(kotlinValueParameterMetadata.index) > 0;
|
||||
}
|
||||
}
|
||||
@@ -283,10 +278,10 @@ implements KotlinMetadataVisitor,
|
||||
kotlinPropertyMetadata,
|
||||
this);
|
||||
|
||||
if (kotlinValueParameterMetadata.flags.common.hasAnnotations)
|
||||
if (kotlinValueParameterMetadata.flags.hasAnnotations)
|
||||
{
|
||||
kotlinPropertyMetadata.referencedSetterMethod.accept(clazz, annotationCounter.reset());
|
||||
kotlinValueParameterMetadata.flags.common.hasAnnotations =
|
||||
kotlinValueParameterMetadata.flags.hasAnnotations =
|
||||
annotationCounter.getParameterAnnotationCount(kotlinValueParameterMetadata.index) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
* ProGuard -- shrinking, optimization, obfuscation, and preverification
|
||||
* of Java bytecode.
|
||||
*
|
||||
* Copyright (c) 2002-2020 Guardsquare NV
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
package proguard.io;
|
||||
|
||||
import kotlinx.metadata.KmAnnotation;
|
||||
import kotlinx.metadata.internal.metadata.jvm.deserialization.JvmMetadataVersion;
|
||||
import kotlinx.metadata.jvm.*;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import proguard.classfile.*;
|
||||
import proguard.classfile.util.ClassUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
public class KotlinModuleRewriter
|
||||
extends DataEntryCopier
|
||||
{
|
||||
private static final Logger logger = LogManager.getLogger(KotlinModuleRewriter.class);
|
||||
|
||||
private final ClassPool programClassPool;
|
||||
|
||||
|
||||
public KotlinModuleRewriter(ClassPool programClassPool, Charset charset, DataEntryWriter writer)
|
||||
{
|
||||
super(writer);
|
||||
this.programClassPool = programClassPool;
|
||||
}
|
||||
|
||||
|
||||
public void read(DataEntry dataEntry) throws IOException
|
||||
{
|
||||
super.read(dataEntry);
|
||||
}
|
||||
|
||||
|
||||
protected void copyData(InputStream inputStream, OutputStream outputStream) throws IOException
|
||||
{
|
||||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
|
||||
super.copyData(inputStream, byteStream);
|
||||
byte[] bytes = byteStream.toByteArray();
|
||||
KotlinModuleMetadata kotlinModuleMetadata = KotlinModuleMetadata.read(bytes);
|
||||
KmModule kmModule = kotlinModuleMetadata.toKmModule();
|
||||
|
||||
ModuleTransformer moduleTransformer = new ModuleTransformer();
|
||||
kmModule.accept(moduleTransformer);
|
||||
|
||||
KotlinModuleMetadata.Writer writer = new KotlinModuleMetadata.Writer();
|
||||
moduleTransformer.getResult().accept(writer);
|
||||
byte[] transformedBytes = writer.write(JvmMetadataVersion.INSTANCE.toArray()).getBytes();
|
||||
outputStream.write(transformedBytes);
|
||||
}
|
||||
|
||||
|
||||
private class PackageInformation
|
||||
{
|
||||
private final String fqName;
|
||||
private final List<String> fileFacades = new ArrayList<>();
|
||||
private final Map<String, String> multiFileClassParts = new HashMap<>();
|
||||
|
||||
|
||||
private PackageInformation(String fqName) {this.fqName = fqName;}
|
||||
|
||||
|
||||
public void addToModule(KmModule out)
|
||||
{
|
||||
out.visitPackageParts(fqName, fileFacades, multiFileClassParts);
|
||||
}
|
||||
}
|
||||
|
||||
private class ModuleTransformer extends KmModuleVisitor
|
||||
{
|
||||
private final Map<String, PackageInformation> newModuleInfo = new HashMap<>();
|
||||
|
||||
|
||||
private PackageInformation getPackageInformation(String fqName)
|
||||
{
|
||||
if (newModuleInfo.containsKey(fqName))
|
||||
{
|
||||
return newModuleInfo.get(fqName);
|
||||
}
|
||||
else
|
||||
{
|
||||
PackageInformation packageInformation = new PackageInformation(fqName);
|
||||
newModuleInfo.put(fqName, packageInformation);
|
||||
return packageInformation;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private PackageInformation getPackageInformation(Clazz clazz)
|
||||
{
|
||||
return getPackageInformation(ClassUtil.externalPackageName(ClassUtil.externalClassName(clazz.getName())));
|
||||
}
|
||||
|
||||
|
||||
public void visitPackageParts(String fqName, List<String> fileFacades, Map<String, String> multiFileClassParts)
|
||||
{
|
||||
for (String fileFacade : fileFacades)
|
||||
{
|
||||
Clazz newClass = programClassPool.getClass(fileFacade);
|
||||
|
||||
if (newClass == null)
|
||||
{
|
||||
// This can occur in the case of wrong input modules.
|
||||
// For instance the kotlin.reflect module declares facades which are actually absent.
|
||||
continue;
|
||||
}
|
||||
|
||||
getPackageInformation(newClass).fileFacades.add(newClass.getName());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : multiFileClassParts.entrySet())
|
||||
{
|
||||
Clazz keyClass = programClassPool.getClass(entry.getKey());
|
||||
Clazz valueClass = programClassPool.getClass(entry.getValue());
|
||||
|
||||
if (keyClass == null ||
|
||||
valueClass == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
getPackageInformation(keyClass).multiFileClassParts.put(keyClass .getName(),
|
||||
valueClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public KmModule getResult()
|
||||
{
|
||||
KmModule out = new KmModule();
|
||||
for (PackageInformation packageInformation : newModuleInfo.values())
|
||||
{
|
||||
packageInformation.addToModule(out);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
public void visitAnnotation(KmAnnotation annotation)
|
||||
{
|
||||
logger.error("Cannot handle annotations yet");
|
||||
}
|
||||
|
||||
|
||||
public void visitEnd() {}
|
||||
}
|
||||
}
|
||||
@@ -39,12 +39,16 @@ import proguard.classfile.kotlin.KotlinConstants;
|
||||
import proguard.classfile.kotlin.KotlinDeclarationContainerMetadata;
|
||||
import proguard.classfile.kotlin.KotlinFunctionMetadata;
|
||||
import proguard.classfile.kotlin.KotlinMetadata;
|
||||
import proguard.classfile.kotlin.KotlinPropertyMetadata;
|
||||
import proguard.classfile.kotlin.KotlinSyntheticClassKindMetadata;
|
||||
import proguard.classfile.kotlin.visitor.KotlinFunctionToDefaultMethodVisitor;
|
||||
import proguard.classfile.kotlin.visitor.KotlinFunctionToMethodVisitor;
|
||||
import proguard.classfile.kotlin.visitor.KotlinFunctionVisitor;
|
||||
import proguard.classfile.kotlin.visitor.KotlinMetadataVisitor;
|
||||
import proguard.classfile.kotlin.visitor.KotlinPropertyVisitor;
|
||||
import proguard.classfile.kotlin.visitor.MemberToKotlinPropertyVisitor;
|
||||
import proguard.classfile.kotlin.visitor.ReferencedKotlinMetadataVisitor;
|
||||
import proguard.classfile.kotlin.visitor.filter.KotlinClassFilter;
|
||||
import proguard.classfile.util.AllParameterVisitor;
|
||||
import proguard.classfile.visitor.AllMemberVisitor;
|
||||
import proguard.classfile.visitor.ClassAccessFilter;
|
||||
@@ -63,14 +67,20 @@ import proguard.classfile.visitor.MultiClassVisitor;
|
||||
import proguard.classfile.visitor.MultiMemberVisitor;
|
||||
import proguard.classfile.visitor.NamedMethodVisitor;
|
||||
import proguard.pass.Pass;
|
||||
import proguard.util.Processable;
|
||||
import proguard.util.ProcessingFlagSetter;
|
||||
import proguard.util.ProcessingFlags;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static proguard.util.ProcessingFlags.DONT_OBFUSCATE;
|
||||
import static proguard.util.ProcessingFlags.DONT_OPTIMIZE;
|
||||
import static proguard.util.ProcessingFlags.DONT_SHRINK;
|
||||
import static proguard.util.ProcessingFlags.DONT_SHRINK_OR_OPTIMIZE_OR_OBFUSCATE;
|
||||
import static proguard.util.ProcessingFlags.INJECTED;
|
||||
|
||||
/**
|
||||
@@ -124,6 +134,34 @@ public class Marker implements Pass
|
||||
new ProcessingFlagSetter(ProcessingFlags.DONT_SHRINK | ProcessingFlags.DONT_OPTIMIZE | ProcessingFlags.DONT_OBFUSCATE))));
|
||||
appView.programClassPool.classesAccept(classVisitor);
|
||||
appView.libraryClassPool.classesAccept(classVisitor);
|
||||
|
||||
// When a property is kept, make sure the getter, setter and backing field all have the same
|
||||
// keep flags.
|
||||
ClassVisitor propertyVisitor =
|
||||
new KotlinClassFilter(
|
||||
new AllMemberVisitor(
|
||||
new MemberToKotlinPropertyVisitor(
|
||||
new KotlinPropertyVisitor() {
|
||||
public void visitAnyProperty(Clazz clazz,
|
||||
KotlinDeclarationContainerMetadata kotlinDeclarationContainerMetadata,
|
||||
KotlinPropertyMetadata kotlinPropertyMetadata) {
|
||||
List<Processable> processables = Stream.of(kotlinPropertyMetadata.referencedBackingField,
|
||||
kotlinPropertyMetadata.referencedGetterMethod,
|
||||
kotlinPropertyMetadata.referencedSetterMethod)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
int flags = 0;
|
||||
for (Processable processable : processables) {
|
||||
flags |= processable.getProcessingFlags();
|
||||
}
|
||||
// Only copy the keep flags.
|
||||
int copiedFlags = flags & DONT_SHRINK_OR_OPTIMIZE_OR_OBFUSCATE;
|
||||
processables.forEach(p -> p.setProcessingFlags(p.getProcessingFlags() | copiedFlags));
|
||||
}
|
||||
})));
|
||||
appView.programClassPool.classesAccept(propertyVisitor);
|
||||
appView.libraryClassPool.classesAccept(propertyVisitor);
|
||||
|
||||
}
|
||||
|
||||
// Mark members that can be safely used for generalization,
|
||||
@@ -234,8 +272,7 @@ public class Marker implements Pass
|
||||
{
|
||||
// Program classes are always available and safe to generalize/specialize from/to.
|
||||
ClassVisitor isClassAvailableMarker =
|
||||
new AllMemberVisitor(
|
||||
new ProcessingFlagSetter(ProcessingFlags.IS_CLASS_AVAILABLE));
|
||||
new ProcessingFlagSetter(ProcessingFlags.IS_CLASS_AVAILABLE);
|
||||
|
||||
programClassPool.classesAccept(isClassAvailableMarker);
|
||||
|
||||
|
||||
@@ -21,26 +21,33 @@
|
||||
package proguard.obfuscate.kotlin;
|
||||
|
||||
import proguard.classfile.Clazz;
|
||||
import proguard.classfile.LibraryClass;
|
||||
import proguard.classfile.LibraryMember;
|
||||
import proguard.classfile.ProgramClass;
|
||||
import proguard.classfile.ProgramMember;
|
||||
import proguard.classfile.kotlin.KotlinClassKindMetadata;
|
||||
import proguard.classfile.kotlin.KotlinMetadata;
|
||||
import proguard.classfile.kotlin.visitor.KotlinMetadataVisitor;
|
||||
import proguard.classfile.visitor.AllFieldVisitor;
|
||||
import proguard.classfile.visitor.MemberVisitor;
|
||||
|
||||
import static proguard.classfile.util.ClassUtil.internalSimpleClassName;
|
||||
import static proguard.obfuscate.ClassObfuscator.newClassName;
|
||||
import static proguard.obfuscate.ClassObfuscator.setNewClassName;
|
||||
import static proguard.obfuscate.MemberObfuscator.newMemberName;
|
||||
import static proguard.obfuscate.MemberObfuscator.setFixedNewMemberName;
|
||||
import static proguard.util.ProcessingFlags.DONT_OBFUSCATE;
|
||||
|
||||
public class KotlinCompanionEqualizer
|
||||
implements KotlinMetadataVisitor
|
||||
{
|
||||
implements KotlinMetadataVisitor {
|
||||
|
||||
@Override
|
||||
public void visitAnyKotlinMetadata(Clazz clazz, KotlinMetadata kotlinMetadata) {}
|
||||
public void visitAnyKotlinMetadata(Clazz clazz, KotlinMetadata kotlinMetadata) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitKotlinClassMetadata(Clazz clazz, KotlinClassKindMetadata kotlinClassKindMetadata)
|
||||
{
|
||||
if (kotlinClassKindMetadata.companionObjectName != null)
|
||||
{
|
||||
public void visitKotlinClassMetadata(Clazz clazz, KotlinClassKindMetadata kotlinClassKindMetadata) {
|
||||
if (kotlinClassKindMetadata.companionObjectName != null) {
|
||||
String newCompanionClassName = newClassName(kotlinClassKindMetadata.referencedCompanionClass);
|
||||
|
||||
if (newCompanionClassName == null) return;
|
||||
@@ -50,13 +57,51 @@ implements KotlinMetadataVisitor
|
||||
// The Kotlin asserter will check the field name, so will throw the metadata away if
|
||||
// it wasn't named correctly.
|
||||
|
||||
if (newCompanionClassName.contains("$"))
|
||||
{
|
||||
// Set a fixed member name to make sure it gets priority when resolving naming conflicts and collecting
|
||||
// already used member names.
|
||||
setFixedNewMemberName(kotlinClassKindMetadata.referencedCompanionField,
|
||||
internalSimpleClassName(newCompanionClassName));
|
||||
if (newCompanionClassName.contains("$")) {
|
||||
if ((kotlinClassKindMetadata.referencedCompanionField.getProcessingFlags() & DONT_OBFUSCATE) != 0) {
|
||||
// The field is to be kept, so the class name should be kept as well.
|
||||
setNewClassName(kotlinClassKindMetadata.referencedCompanionClass,
|
||||
newClassName(kotlinClassKindMetadata.referencedClass) + "$" + kotlinClassKindMetadata.companionObjectName);
|
||||
} else {
|
||||
final String newCompanionSimpleClassName = internalSimpleClassName(newCompanionClassName);
|
||||
|
||||
// Check whether there is already a field with the same fixed new name in the hierarchy.
|
||||
ConflictingFieldChecker conflictingFieldChecker =
|
||||
new ConflictingFieldChecker(newCompanionSimpleClassName);
|
||||
clazz.hierarchyAccept(
|
||||
false, true, true, false, new AllFieldVisitor(conflictingFieldChecker));
|
||||
|
||||
// There is a field in the hierarchy with the same fixed name. Rename the companion
|
||||
// class and associated field to avoid the class being renamed inconsistently during
|
||||
// conflict resolution and causing runtime crashes.
|
||||
if (conflictingFieldChecker.isConflicting) {
|
||||
newCompanionClassName = newCompanionClassName + "_";
|
||||
setNewClassName(
|
||||
kotlinClassKindMetadata.referencedCompanionClass, newCompanionClassName);
|
||||
}
|
||||
// Set a fixed member name to make sure it gets priority when resolving naming conflicts and collecting
|
||||
// already used member names.
|
||||
setFixedNewMemberName(kotlinClassKindMetadata.referencedCompanionField,
|
||||
internalSimpleClassName(newCompanionClassName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private static class ConflictingFieldChecker implements MemberVisitor {
|
||||
|
||||
public boolean isConflicting = false;
|
||||
private String newCompanionSimpleClassName;
|
||||
|
||||
public ConflictingFieldChecker(String newCompanionSimpleClassName) {
|
||||
this.newCompanionSimpleClassName = newCompanionSimpleClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember) {}
|
||||
|
||||
@Override
|
||||
public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) {
|
||||
isConflicting |= newCompanionSimpleClassName.equals(newMemberName(programMember));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ implements MemberVisitor
|
||||
|
||||
if (valueClass != null &&
|
||||
valueClass.extendsOrImplements(ClassUtil.internalClassNameFromClassType(fieldType)) &&
|
||||
(programField.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
(valueClass.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
{
|
||||
logger.debug("MemberDescriptorSpecializer [{}.{} {}] -> {}",
|
||||
programClass.getName(),
|
||||
@@ -210,7 +210,7 @@ implements MemberVisitor
|
||||
|
||||
if (valueClass != null &&
|
||||
valueClass.extendsOrImplements(ClassUtil.internalClassNameFromClassType(parameterType)) &&
|
||||
(programMethod.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
(valueClass.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
{
|
||||
logger.debug("MemberDescriptorSpecializer [{}.{}{}]: parameter #{}: {} -> {}",
|
||||
programClass.getName(),
|
||||
|
||||
@@ -22,12 +22,22 @@ package proguard.optimize;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import proguard.classfile.*;
|
||||
import proguard.classfile.AccessConstants;
|
||||
import proguard.classfile.Clazz;
|
||||
import proguard.classfile.Field;
|
||||
import proguard.classfile.Member;
|
||||
import proguard.classfile.Method;
|
||||
import proguard.classfile.ProgramClass;
|
||||
import proguard.classfile.attribute.CodeAttribute;
|
||||
import proguard.classfile.constant.*;
|
||||
import proguard.classfile.constant.AnyMethodrefConstant;
|
||||
import proguard.classfile.constant.ClassConstant;
|
||||
import proguard.classfile.constant.FieldrefConstant;
|
||||
import proguard.classfile.constant.RefConstant;
|
||||
import proguard.classfile.constant.visitor.ConstantVisitor;
|
||||
import proguard.classfile.editor.*;
|
||||
import proguard.classfile.instruction.*;
|
||||
import proguard.classfile.editor.CodeAttributeEditor;
|
||||
import proguard.classfile.editor.ConstantPoolEditor;
|
||||
import proguard.classfile.instruction.ConstantInstruction;
|
||||
import proguard.classfile.instruction.Instruction;
|
||||
import proguard.classfile.instruction.visitor.InstructionVisitor;
|
||||
import proguard.classfile.visitor.ClassVisitor;
|
||||
import proguard.util.ProcessingFlags;
|
||||
@@ -200,7 +210,7 @@ implements InstructionVisitor,
|
||||
// DGD-486: Only generalize members which are always available. Partial replacement of a class that is not
|
||||
// available on all platforms may result in a VerifyError at runtime.
|
||||
if (referencedMember != null &&
|
||||
(referencedMember.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
(clazz.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
{
|
||||
clazz.constantPoolEntryAccept(refConstant.u2classIndex, this);
|
||||
|
||||
@@ -287,13 +297,14 @@ implements InstructionVisitor,
|
||||
// Otherwise, look in the super class itself.
|
||||
// Only consider public classes and methods, to avoid any
|
||||
// access problems.
|
||||
// Only consider classes that are marked as available.
|
||||
if (generalizedClass == null &&
|
||||
(superClass.getAccessFlags() & AccessConstants.PUBLIC) != 0)
|
||||
(superClass.getAccessFlags() & AccessConstants.PUBLIC) != 0 &&
|
||||
(superClass.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
{
|
||||
Method method = superClass.findMethod(memberName, memberType);
|
||||
if (method != null &&
|
||||
(method.getAccessFlags() & AccessConstants.PUBLIC) != 0 &&
|
||||
(method.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
(method.getAccessFlags() & AccessConstants.PUBLIC) != 0)
|
||||
{
|
||||
// Remember the generalized class and class member.
|
||||
generalizedClass = superClass;
|
||||
@@ -308,7 +319,7 @@ implements InstructionVisitor,
|
||||
Field field = clazz.findField(memberName, memberType);
|
||||
|
||||
if (field != null &&
|
||||
(field.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
(clazz.getProcessingFlags() & ProcessingFlags.IS_CLASS_AVAILABLE) != 0)
|
||||
{
|
||||
// Remember the generalized class and class member.
|
||||
generalizedClass = clazz;
|
||||
|
||||
@@ -124,6 +124,22 @@ implements MemberVisitor,
|
||||
-1L : -2L);
|
||||
}
|
||||
|
||||
if (programMethod.processingInfo instanceof ProgramMethodOptimizationInfo
|
||||
&& parameterSize >= 64) {
|
||||
int parameterSizesCummulative = 0;
|
||||
for (int index = 0; parameterSizesCummulative < 64; index++) {
|
||||
boolean isCategory2 =
|
||||
((ProgramMethodOptimizationInfo) programMethod.processingInfo).getParameterSize(index)
|
||||
== 2;
|
||||
if (parameterSizesCummulative == 63 && isCategory2) {
|
||||
markParameterUsed(programMethod, 63);
|
||||
}
|
||||
parameterSizesCummulative +=
|
||||
((ProgramMethodOptimizationInfo) programMethod.processingInfo)
|
||||
.getParameterSize(index);
|
||||
}
|
||||
}
|
||||
|
||||
// Is it a native method?
|
||||
if ((accessFlags & AccessConstants.NATIVE) != 0)
|
||||
{
|
||||
|
||||
@@ -652,6 +652,15 @@ implements AttributeVisitor,
|
||||
AccessConstants.STATIC |
|
||||
AccessConstants.FINAL)) != 0 &&
|
||||
|
||||
DEBUG("Interface?") &&
|
||||
|
||||
// Methods in interfaces should only very rarely be inlined
|
||||
// since this can potentially lead to other methods in the interface
|
||||
// needing broadened visibility, which can lead to either compilation errors
|
||||
// during output writing or various issues at runtime.
|
||||
((programClass.getAccessFlags() & AccessConstants.INTERFACE) == 0 ||
|
||||
canInlineMethodFromInterface(programClass, programMethod)) &&
|
||||
|
||||
DEBUG("Synchronized?") &&
|
||||
|
||||
// Only inline the method if it is not synchronized, etc.
|
||||
@@ -889,6 +898,17 @@ implements AttributeVisitor,
|
||||
returnChar == TypeConstants.SHORT;
|
||||
}
|
||||
|
||||
/**
|
||||
* We only inline methods from interfaces if both of these conditions hold:
|
||||
* - The class that references the method is the interface itself.
|
||||
* - The method is private.
|
||||
*/
|
||||
private boolean canInlineMethodFromInterface(ProgramClass sourceClass, ProgramMethod sourceMethod)
|
||||
{
|
||||
return
|
||||
sourceClass.equals(targetClass) &&
|
||||
(sourceMethod.getAccessFlags() & AccessConstants.PRIVATE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this method should be inlined. Subclasses can overwrite
|
||||
|
||||
@@ -1888,7 +1888,7 @@ implements ClassVisitor,
|
||||
markAsUsed(kotlinPropertyMetadata.setterParameters);
|
||||
markAsUsed(kotlinPropertyMetadata.type);
|
||||
|
||||
if (kotlinPropertyMetadata.flags.common.hasAnnotations &&
|
||||
if (kotlinPropertyMetadata.flags.hasAnnotations &&
|
||||
kotlinPropertyMetadata.syntheticMethodForAnnotations != null)
|
||||
{
|
||||
// Annotations are placed on a synthetic method (e.g. myProperty$annotations())
|
||||
@@ -1971,23 +1971,28 @@ implements ClassVisitor,
|
||||
{
|
||||
visitAnyFunction(clazz, kotlinDeclarationContainerMetadata, kotlinFunctionMetadata);
|
||||
|
||||
// Non-abstract functions in interfaces should have default implementations, so keep it if the
|
||||
// user kept the original function.
|
||||
if (isUsed(kotlinFunctionMetadata))
|
||||
{
|
||||
if (kotlinDeclarationContainerMetadata.k == KotlinConstants.METADATA_KIND_CLASS &&
|
||||
((KotlinClassKindMetadata)kotlinDeclarationContainerMetadata).flags.isInterface &&
|
||||
!kotlinFunctionMetadata.flags.modality.isAbstract &&
|
||||
(kotlinFunctionMetadata.referencedMethod.getProcessingFlags() & ProcessingFlags.DONT_SHRINK) != 0)
|
||||
{
|
||||
kotlinFunctionMetadata.referencedDefaultImplementationMethodAccept(
|
||||
new MultiMemberVisitor(
|
||||
ClassUsageMarker.this,
|
||||
new MemberToClassVisitor(ClassUsageMarker.this)
|
||||
)
|
||||
);
|
||||
}
|
||||
boolean isInterface =
|
||||
kotlinDeclarationContainerMetadata.k == KotlinConstants.METADATA_KIND_CLASS
|
||||
&& ((KotlinClassKindMetadata) kotlinDeclarationContainerMetadata).flags.isInterface
|
||||
&& !kotlinFunctionMetadata.flags.modality.isAbstract;
|
||||
|
||||
if (isUsed(kotlinFunctionMetadata)
|
||||
&& isInterface
|
||||
&& (kotlinFunctionMetadata.referencedMethod.getProcessingFlags()
|
||||
& ProcessingFlags.DONT_SHRINK)
|
||||
!= 0) {
|
||||
kotlinFunctionMetadata.referencedDefaultImplementationMethodAccept(
|
||||
new MultiMemberVisitor(
|
||||
ClassUsageMarker.this, new MemberToClassVisitor(ClassUsageMarker.this)));
|
||||
}
|
||||
|
||||
// If a default implementation is called directly,
|
||||
// the interface should be marked as used as well.
|
||||
if (kotlinFunctionMetadata.referencedDefaultImplementationMethod != null
|
||||
&& isInterface
|
||||
&& isUsed(kotlinFunctionMetadata.referencedDefaultImplementationMethod)) {
|
||||
kotlinFunctionMetadata.referencedMethodAccept(ClassUsageMarker.this);
|
||||
}
|
||||
}
|
||||
|
||||
// Implementations for KotlinTypeAliasVisitor.
|
||||
|
||||
@@ -184,7 +184,6 @@ implements KotlinMetadataVisitor,
|
||||
{
|
||||
kotlinPropertyMetadata.getterSignature = null;
|
||||
kotlinPropertyMetadata.referencedGetterMethod = null;
|
||||
kotlinPropertyMetadata.flags.hasGetter = false;
|
||||
}
|
||||
|
||||
if (shouldShrinkMetadata(kotlinPropertyMetadata.setterSignature,
|
||||
@@ -192,7 +191,7 @@ implements KotlinMetadataVisitor,
|
||||
{
|
||||
kotlinPropertyMetadata.setterSignature = null;
|
||||
kotlinPropertyMetadata.referencedSetterMethod = null;
|
||||
kotlinPropertyMetadata.flags.hasSetter = false;
|
||||
kotlinPropertyMetadata.flags.isVar = false;
|
||||
kotlinPropertyMetadata.setterParameters.clear();
|
||||
}
|
||||
|
||||
@@ -206,7 +205,7 @@ implements KotlinMetadataVisitor,
|
||||
kotlinPropertyMetadata.syntheticMethodForAnnotations = null;
|
||||
kotlinPropertyMetadata.referencedSyntheticMethodForAnnotations = null;
|
||||
kotlinPropertyMetadata.referencedSyntheticMethodClass = null;
|
||||
kotlinPropertyMetadata.flags.common.hasAnnotations = false;
|
||||
kotlinPropertyMetadata.flags.hasAnnotations = false;
|
||||
}
|
||||
|
||||
if (kotlinPropertyMetadata.syntheticMethodForDelegate != null &&
|
||||
|
||||
@@ -30,7 +30,7 @@ import proguard.classfile.util.kotlin.KotlinMetadataInitializer;
|
||||
import proguard.classfile.visitor.ClassVisitor;
|
||||
import proguard.pass.Pass;
|
||||
|
||||
import static proguard.classfile.util.kotlin.KotlinMetadataInitializer.MAX_SUPPORTED_VERSION;
|
||||
import static proguard.classfile.io.kotlin.KotlinMetadataWriter.LATEST_STABLE_SUPPORTED;
|
||||
import static proguard.classfile.util.kotlin.KotlinMetadataInitializer.isSupportedMetadataVersion;
|
||||
|
||||
/**
|
||||
@@ -72,7 +72,7 @@ public class KotlinUnsupportedVersionChecker implements Pass
|
||||
throw new RuntimeException(
|
||||
"Unsupported Kotlin metadata version found on class '" + clazz.getName() + "'." +
|
||||
System.lineSeparator() +
|
||||
"Kotlin versions up to " + MAX_SUPPORTED_VERSION.major + "." + MAX_SUPPORTED_VERSION.minor + " are supported.");
|
||||
"Kotlin versions up to " + LATEST_STABLE_SUPPORTED + " are supported.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -8,9 +8,14 @@
|
||||
package proguard
|
||||
|
||||
import io.kotest.core.spec.style.FreeSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import proguard.classfile.visitor.ClassPoolVisitor
|
||||
import proguard.classfile.visitor.ClassVisitor
|
||||
import proguard.classfile.visitor.MemberCounter
|
||||
import proguard.classfile.visitor.MemberVisitor
|
||||
import proguard.testutils.AssemblerSource
|
||||
import proguard.testutils.ClassPoolBuilder
|
||||
import proguard.testutils.JavaSource
|
||||
import testutils.asConfiguration
|
||||
@@ -106,4 +111,110 @@ class ClassSpecificationVisitorFactoryTest : FreeSpec({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a class with fields of different types" - {
|
||||
fun createFieldVisitor(config: String, fieldVisitor: MemberVisitor): ClassPoolVisitor =
|
||||
KeepClassSpecificationVisitorFactory(true, false, false).createClassPoolVisitor(
|
||||
config.asConfiguration().keep.first(), null, fieldVisitor, null, null
|
||||
)
|
||||
|
||||
val (programClassPool, _) = ClassPoolBuilder.fromSource(
|
||||
AssemblerSource(
|
||||
"ClassWithFields.jbc",
|
||||
"""
|
||||
public class ClassWithFields {
|
||||
java.lang.String myField;
|
||||
int myField;
|
||||
long myField;
|
||||
com.example.ClassInAPackage myField;
|
||||
java.lang.String[] myField;
|
||||
int[] myField;
|
||||
com.example.ClassInAPackage[] myField;
|
||||
ClassWithFields myField;
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
|
||||
"Then * should visit any non-primitive, non-array without package separator type fields" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createFieldVisitor("-keep class ClassWithFields { * myField; }", this))
|
||||
count shouldBe 1
|
||||
}
|
||||
}
|
||||
|
||||
"Then ** should visit any non-primitive, non-array separator type fields" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createFieldVisitor("-keep class ClassWithFields { ** myField; }", this))
|
||||
count shouldBe 3
|
||||
}
|
||||
}
|
||||
|
||||
"Then *** should visit all fields" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createFieldVisitor("-keep class ClassWithFields { *** myField; }", this))
|
||||
count shouldBe 8
|
||||
}
|
||||
}
|
||||
|
||||
"Then % should only visit primitive, non-array fields" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createFieldVisitor("-keep class ClassWithFields { % myField; }", this))
|
||||
count shouldBe 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a class with methods of different types" - {
|
||||
fun createMethodVisitor(config: String, methodVisitor: MemberVisitor): ClassPoolVisitor =
|
||||
KeepClassSpecificationVisitorFactory(true, false, false).createClassPoolVisitor(
|
||||
config.asConfiguration().keep.first(), null, null, methodVisitor, null
|
||||
)
|
||||
|
||||
val (programClassPool, _) = ClassPoolBuilder.fromSource(
|
||||
AssemblerSource(
|
||||
"ClassWithFields.jbc",
|
||||
"""
|
||||
public class ClassWithFields {
|
||||
public void myMethod(java.lang.String);
|
||||
public void myMethod(int);
|
||||
public void myMethod(long);
|
||||
public void myMethod(com.example.ClassInAPackage);
|
||||
public void myMethod(java.lang.String[]);
|
||||
public void myMethod(int[]);
|
||||
public void myMethod(com.example.ClassInAPackage[]);
|
||||
public void myMethod(ClassWithFields);
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
|
||||
"Then * should visit any non-primitive, non-array without package separator type methods" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createMethodVisitor("-keep class ClassWithFields { void myMethod(*); }", this))
|
||||
count shouldBe 1
|
||||
}
|
||||
}
|
||||
|
||||
"Then ** should visit any non-primitive, non-array separator type methods" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createMethodVisitor("-keep class ClassWithFields { void myMethod(**); }", this))
|
||||
count shouldBe 3
|
||||
}
|
||||
}
|
||||
|
||||
"Then *** should visit all methods" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createMethodVisitor("-keep class ClassWithFields { void myMethod(***); }", this))
|
||||
count shouldBe 8
|
||||
}
|
||||
}
|
||||
|
||||
"Then % should only visit primitive, non-array methods" {
|
||||
with(MemberCounter()) {
|
||||
programClassPool.accept(createMethodVisitor("-keep class ClassWithFields { void myMethod(%); }", this))
|
||||
count shouldBe 2
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -9,6 +9,13 @@ package proguard
|
||||
|
||||
import io.kotest.assertions.throwables.shouldThrow
|
||||
import io.kotest.core.spec.style.FreeSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import proguard.classfile.AccessConstants.PUBLIC
|
||||
import testutils.asConfiguration
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.PrintStream
|
||||
|
||||
/**
|
||||
* Some simple testcases to catch special cases when parsing the Configuration.
|
||||
@@ -57,6 +64,31 @@ class ConfigurationParserTest : FreeSpec({
|
||||
parseConfiguration("-keep class * { public protected <methods>; }")
|
||||
}
|
||||
|
||||
"Keep rule with ClassName should be valid" {
|
||||
val configuration = parseConfiguration("-keep class ClassName { ClassName(); }")
|
||||
val keep = configuration.keep.single().methodSpecifications.single()
|
||||
keep.name shouldBe "<init>"
|
||||
keep.descriptor shouldBe "()V"
|
||||
}
|
||||
|
||||
"Keep rule with ClassName and external class com.example.ClassName should be valid" {
|
||||
val configuration = parseConfiguration("-keep class com.example.ClassName { ClassName(); }")
|
||||
val keep = configuration.keep.single().methodSpecifications.single()
|
||||
keep.name shouldBe "<init>"
|
||||
keep.descriptor shouldBe "()V"
|
||||
}
|
||||
|
||||
"Keep rule with <clinit> should be valid" {
|
||||
val configuration = parseConfiguration("-keep class ** { <clinit>(); }")
|
||||
val keep = configuration.keep.single().methodSpecifications.single()
|
||||
keep.name shouldBe "<clinit>"
|
||||
keep.descriptor shouldBe "()V"
|
||||
}
|
||||
|
||||
"Keep rule with <clinit> and non-empty argument list should throw ParseException" {
|
||||
shouldThrow<ParseException> { parseConfiguration("-keep class * { void <clinit>(int) }") }
|
||||
}
|
||||
|
||||
"Keep rule with * member wildcard and return type should be valid" {
|
||||
parseConfiguration("-keep class * { java.lang.String *; }")
|
||||
}
|
||||
@@ -77,4 +109,323 @@ class ConfigurationParserTest : FreeSpec({
|
||||
shouldThrow<ParseException> { parseConfiguration("-keep class * { <methods>(); }") }
|
||||
}
|
||||
}
|
||||
|
||||
"A ParseException should be thrown with invalid annotation config at the end of the file" - {
|
||||
// This is a parse error without any further config after it.
|
||||
val configStr = ("-keep @MyAnnotation @ThisShouldBeInterfaceKeyword")
|
||||
|
||||
"Then the option should throw a ParseException" {
|
||||
shouldThrow<ParseException> {
|
||||
configStr.asConfiguration()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Testing -alwaysinline parsing" - {
|
||||
"Given an empty configuration" - {
|
||||
val savedPrintStream = System.out
|
||||
val customOutputStream = ByteArrayOutputStream()
|
||||
System.setOut(PrintStream(customOutputStream))
|
||||
|
||||
parseConfiguration("")
|
||||
|
||||
"The option does not print anything" {
|
||||
customOutputStream.toString() shouldContain ""
|
||||
System.setOut(savedPrintStream)
|
||||
}
|
||||
}
|
||||
|
||||
"Given a configuration with -alwaysinline" - {
|
||||
val savedPrintStream = System.out
|
||||
val customOutputStream = ByteArrayOutputStream()
|
||||
System.setOut(PrintStream(customOutputStream))
|
||||
|
||||
parseConfiguration(
|
||||
"""-alwaysinline class * {
|
||||
@org.chromium.build.annotations.AlwaysInline *;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
"The option prints out a warning" {
|
||||
customOutputStream.toString() shouldContain "Warning: The R8 option -alwaysinline is currently not supported by ProGuard.\n" +
|
||||
"This option will have no effect on the optimized artifact."
|
||||
System.setOut(savedPrintStream)
|
||||
}
|
||||
}
|
||||
|
||||
"Given a configuration with -alwaysinline with no class specification" - {
|
||||
"The parsing should throw an exception" {
|
||||
shouldThrow<ParseException> { parseConfiguration("-alwaysinline") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Testing -identifiernamestring parsing" - {
|
||||
"Given an empty configuration" - {
|
||||
val savedPrintStream = System.out
|
||||
val customOutputStream = ByteArrayOutputStream()
|
||||
System.setOut(PrintStream(customOutputStream))
|
||||
|
||||
parseConfiguration("")
|
||||
|
||||
"The option does not print anything" {
|
||||
customOutputStream.toString() shouldContain ""
|
||||
System.setOut(savedPrintStream)
|
||||
}
|
||||
}
|
||||
|
||||
"Given a configuration with -identifiernamestring" - {
|
||||
val savedPrintStream = System.out
|
||||
val customOutputStream = ByteArrayOutputStream()
|
||||
System.setOut(PrintStream(customOutputStream))
|
||||
|
||||
parseConfiguration(
|
||||
"""-identifiernamestring class * {
|
||||
@org.chromium.build.annotations.IdentifierNameString *;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
"The option prints out a warning" {
|
||||
customOutputStream.toString() shouldContain "Warning: The R8 option -identifiernamestring is currently not supported by ProGuard.\n" +
|
||||
"This option will have no effect on the optimized artifact."
|
||||
System.setOut(savedPrintStream)
|
||||
}
|
||||
}
|
||||
|
||||
"Given a configuration with -identifiernamestring with no class specification" - {
|
||||
"The parsing should throw an exception" {
|
||||
shouldThrow<ParseException> { parseConfiguration("-identifiernamestring") }
|
||||
}
|
||||
}
|
||||
}
|
||||
"Testing -maximumremovedandroidloglevel parsing" - {
|
||||
"Given an empty configuration" - {
|
||||
val savedPrintStream = System.out
|
||||
val customOutputStream = ByteArrayOutputStream()
|
||||
System.setOut(PrintStream(customOutputStream))
|
||||
|
||||
parseConfiguration("")
|
||||
|
||||
"The option does not print anything" {
|
||||
customOutputStream.toString() shouldContain ""
|
||||
System.setOut(savedPrintStream)
|
||||
}
|
||||
}
|
||||
|
||||
"Given a configuration with -maximumremovedandroidloglevel without a class specification" - {
|
||||
val savedPrintStream = System.out
|
||||
val customOutputStream = ByteArrayOutputStream()
|
||||
System.setOut(PrintStream(customOutputStream))
|
||||
|
||||
parseConfiguration("-maximumremovedandroidloglevel 1")
|
||||
|
||||
"The option prints out a warning" {
|
||||
customOutputStream.toString() shouldContain "Warning: The R8 option -maximumremovedandroidloglevel is currently not supported by ProGuard.\n" +
|
||||
"This option will have no effect on the optimized artifact."
|
||||
System.setOut(savedPrintStream)
|
||||
}
|
||||
}
|
||||
|
||||
"Given a configuration with -maximumremovedandroidloglevel with a class specification" - {
|
||||
val savedPrintStream = System.out
|
||||
val customOutputStream = ByteArrayOutputStream()
|
||||
System.setOut(PrintStream(customOutputStream))
|
||||
|
||||
parseConfiguration(
|
||||
"""
|
||||
-maximumremovedandroidloglevel 1 @org.chromium.build.annotations.DoNotStripLogs class ** {
|
||||
<methods>;
|
||||
}
|
||||
""".trimIndent(),
|
||||
)
|
||||
|
||||
"The option prints out a warning" {
|
||||
customOutputStream.toString() shouldContain "Warning: The R8 option -maximumremovedandroidloglevel is currently not supported by ProGuard.\n" +
|
||||
"This option will have no effect on the optimized artifact."
|
||||
System.setOut(savedPrintStream)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Wildcard type tests" - {
|
||||
class TestConfig(
|
||||
val configOption: String,
|
||||
classSpecificationConfig: String,
|
||||
private val classSpecificationGetter: Configuration.() -> List<ClassSpecification>?
|
||||
) {
|
||||
private val configuration: Configuration by lazy {
|
||||
"$configOption $classSpecificationConfig".asConfiguration()
|
||||
}
|
||||
val classSpecifications: List<ClassSpecification>? get() = classSpecificationGetter.invoke(configuration)
|
||||
}
|
||||
|
||||
fun generateTestCases(clSpec: String): List<TestConfig> = listOf(
|
||||
TestConfig("-keep", clSpec) { keep },
|
||||
TestConfig("-assumenosideeffects", clSpec) { assumeNoSideEffects },
|
||||
TestConfig("-assumenoexternalsideeffects", clSpec) { assumeNoExternalSideEffects },
|
||||
TestConfig("-assumenoescapingparameters", clSpec) { assumeNoEscapingParameters },
|
||||
TestConfig("-assumenoexternalreturnvalues", clSpec) { assumeNoExternalReturnValues },
|
||||
TestConfig("-assumevalues", clSpec) { assumeValues },
|
||||
)
|
||||
|
||||
"Test wildcard matches all methods and fields" {
|
||||
val testConfigurations = generateTestCases("class Foo { *; }") + generateTestCases("class Foo { <fields>; <methods>; }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications?.single()
|
||||
methodSpecification shouldNotBe null
|
||||
methodSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
methodSpecification?.name shouldBe null
|
||||
methodSpecification?.descriptor shouldBe null
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications?.single()
|
||||
fieldSpecification shouldNotBe null
|
||||
fieldSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
fieldSpecification?.name shouldBe null
|
||||
fieldSpecification?.descriptor shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
"Test wildcard method return type" {
|
||||
val testConfigurations = generateTestCases("class Foo { * bar(); }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications?.single()
|
||||
methodSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
methodSpecification?.name shouldBe "bar"
|
||||
methodSpecification?.descriptor shouldBe "()L*;"
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications
|
||||
fieldSpecification shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
"Test wildcard method return type with access modifier" {
|
||||
val testConfigurations = generateTestCases("class Foo { public * bar(); }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications?.single()
|
||||
methodSpecification?.requiredSetAccessFlags shouldBe PUBLIC
|
||||
methodSpecification?.name shouldBe "bar"
|
||||
methodSpecification?.descriptor shouldBe "()L*;"
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications
|
||||
fieldSpecification shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
"Test wildcard field type" {
|
||||
val testConfigurations = generateTestCases("class Foo { * bar; }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications
|
||||
methodSpecification shouldBe null
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications?.single()
|
||||
fieldSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
fieldSpecification?.name shouldBe "bar"
|
||||
fieldSpecification?.descriptor shouldBe "L*;"
|
||||
}
|
||||
}
|
||||
|
||||
"Test wildcard field type with access modifier" {
|
||||
val testConfigurations = generateTestCases("class Foo { public * bar; }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications
|
||||
methodSpecification shouldBe null
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications?.single()
|
||||
fieldSpecification?.requiredSetAccessFlags shouldBe PUBLIC
|
||||
fieldSpecification?.name shouldBe "bar"
|
||||
fieldSpecification?.descriptor shouldBe "L*;"
|
||||
}
|
||||
}
|
||||
|
||||
"Test all type wildcard field" {
|
||||
val testConfigurations = generateTestCases("class Foo { *** bar; }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications
|
||||
methodSpecification shouldBe null
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications?.single()
|
||||
fieldSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
fieldSpecification?.name shouldBe "bar"
|
||||
fieldSpecification?.descriptor shouldBe "L***;"
|
||||
}
|
||||
}
|
||||
|
||||
"Test all type wildcard field type with access modifier" {
|
||||
val testConfigurations = generateTestCases("class Foo { public *** bar; }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications
|
||||
methodSpecification shouldBe null
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications?.single()
|
||||
fieldSpecification?.requiredSetAccessFlags shouldBe PUBLIC
|
||||
fieldSpecification?.name shouldBe "bar"
|
||||
fieldSpecification?.descriptor shouldBe "L***;"
|
||||
}
|
||||
}
|
||||
|
||||
"Test all type wildcard method return type" {
|
||||
val testConfigurations = generateTestCases("class Foo { *** bar(); }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications?.single()
|
||||
methodSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
methodSpecification?.name shouldBe "bar"
|
||||
methodSpecification?.descriptor shouldBe "()L***;"
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications
|
||||
fieldSpecification shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
"Test all type wildcard method return type with access modifier" {
|
||||
val testConfigurations = generateTestCases("class Foo { public *** bar(); }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications?.single()
|
||||
methodSpecification?.requiredSetAccessFlags shouldBe PUBLIC
|
||||
methodSpecification?.name shouldBe "bar"
|
||||
methodSpecification?.descriptor shouldBe "()L***;"
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications
|
||||
fieldSpecification shouldBe null
|
||||
}
|
||||
}
|
||||
|
||||
"Test concrete wildcard field type" {
|
||||
val testConfigurations = generateTestCases("class Foo { java.lang.String bar; }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications
|
||||
methodSpecification shouldBe null
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications?.single()
|
||||
fieldSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
fieldSpecification?.name shouldBe "bar"
|
||||
fieldSpecification?.descriptor shouldBe "Ljava/lang/String;"
|
||||
}
|
||||
}
|
||||
|
||||
"Test concrete wildcard method return type" {
|
||||
val testConfigurations = generateTestCases("class Foo { java.lang.String bar(); }")
|
||||
|
||||
for (testConfig in testConfigurations) {
|
||||
val classSpecifications = testConfig.classSpecifications
|
||||
val methodSpecification = classSpecifications?.single()?.methodSpecifications?.single()
|
||||
methodSpecification?.requiredSetAccessFlags shouldBe 0
|
||||
methodSpecification?.name shouldBe "bar"
|
||||
methodSpecification?.descriptor shouldBe "()Ljava/lang/String;"
|
||||
val fieldSpecification = classSpecifications?.single()?.fieldSpecifications
|
||||
fieldSpecification shouldBe null
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
152
base/src/test/kotlin/proguard/ConfigurationWriterTest.kt
Normal file
152
base/src/test/kotlin/proguard/ConfigurationWriterTest.kt
Normal file
@@ -0,0 +1,152 @@
|
||||
package proguard
|
||||
|
||||
import io.kotest.core.spec.style.FreeSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
|
||||
/**
|
||||
* Test printing of the configuration (-printconfiguration option).
|
||||
*/
|
||||
class ConfigurationWriterTest : FreeSpec({
|
||||
val EOL = System.lineSeparator()
|
||||
fun printConfiguration(rules: String): String {
|
||||
val out = StringWriter()
|
||||
val configuration = Configuration()
|
||||
|
||||
ConfigurationParser(rules, "", null, System.getProperties()).use {
|
||||
it.parse(configuration)
|
||||
}
|
||||
|
||||
ConfigurationWriter(PrintWriter(out)).use {
|
||||
it.write(configuration)
|
||||
}
|
||||
|
||||
return out.toString().trim()
|
||||
}
|
||||
|
||||
"Keep rules tests" - {
|
||||
"Keep class constructor should be kept" {
|
||||
val rules = "-keep class * {$EOL <init>();$EOL}"
|
||||
val out = printConfiguration(rules)
|
||||
out shouldBe rules
|
||||
}
|
||||
|
||||
"Keep class initializer should be kept" {
|
||||
val rules = "-keep class * {$EOL <clinit>();$EOL}"
|
||||
val out = printConfiguration(rules)
|
||||
val expected = "-keep class * {$EOL void <clinit>();$EOL}"
|
||||
out shouldBe expected
|
||||
}
|
||||
|
||||
"Keep class initializer should respect allowobfuscation flag" {
|
||||
val rules = "-keep,allowobfuscation class ** extends com.example.A {$EOL <clinit>();$EOL}"
|
||||
val out = printConfiguration(rules)
|
||||
val expected = "-keep,allowobfuscation class ** extends com.example.A {$EOL void <clinit>();$EOL}"
|
||||
out shouldBe expected
|
||||
}
|
||||
}
|
||||
|
||||
"Hash character handling tests" - {
|
||||
"Option parameters with hash characters should be quoted" {
|
||||
printConfiguration("-keystorepassword '#tester'") shouldBe "-keystorepassword '#tester'"
|
||||
}
|
||||
|
||||
"Comments should not be quoted" {
|
||||
printConfiguration("# comment$EOL-keep class **") shouldBe "# comment$EOL-keep class **"
|
||||
}
|
||||
|
||||
"Hash characters in comments should not be quoted" {
|
||||
printConfiguration("# #comment$EOL-keep class **") shouldBe "# #comment$EOL-keep class **"
|
||||
}
|
||||
}
|
||||
|
||||
"Given a -dontnote rule specifying a class name" - {
|
||||
val rules = "-dontnote com.example.MyClass"
|
||||
|
||||
"When the rule is parsed and printed out again" - {
|
||||
val out = printConfiguration(rules)
|
||||
|
||||
"Then the printed rule should be the same as the given rule" {
|
||||
out shouldBe rules
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a -dontnote rule specifying a class name with wildcards" - {
|
||||
val rules = "-dontnote com.example.**"
|
||||
|
||||
"When the rule is parsed and printed out again" - {
|
||||
val out = printConfiguration(rules)
|
||||
|
||||
"Then the printed rule should be the same as the given rule" {
|
||||
out shouldBe rules
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a -addconfigurationdebugging rule" - {
|
||||
val rules = "-addconfigurationdebugging"
|
||||
|
||||
"When the rules are parsed and printed out again" - {
|
||||
val out = printConfiguration(rules)
|
||||
|
||||
"Then the rules should be present in the output" {
|
||||
out shouldContain rules
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given an -optimizeaggressively rule" - {
|
||||
val rules = "-optimizeaggressively"
|
||||
|
||||
"When the rule is parsed and printed out again" - {
|
||||
val out = printConfiguration(rules)
|
||||
|
||||
"Then the rule should be present in the output" {
|
||||
out shouldBe rules
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a -alwaysinline rule" - {
|
||||
val rules = "-alwaysinline class ** {*;}"
|
||||
|
||||
"When the rule is parsed and printed out again" - {
|
||||
val out = printConfiguration(rules)
|
||||
|
||||
"Then the rule should be not be present in the output" {
|
||||
out shouldBe ""
|
||||
}
|
||||
}
|
||||
|
||||
"When the rule does not exist it shouldn't be printed out" - {
|
||||
val out = printConfiguration("")
|
||||
|
||||
"Then the rule should not be present in the output" {
|
||||
out shouldBe ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a -identifiernamestring rule" - {
|
||||
val rules = "-identifiernamestring class ** {*;}"
|
||||
|
||||
"When the rule is parsed and printed out again" - {
|
||||
val out = printConfiguration(rules)
|
||||
|
||||
"Then the rule should be not be present in the output" {
|
||||
out shouldBe ""
|
||||
}
|
||||
}
|
||||
|
||||
"When the rule does not exist it shouldn't be printed out" - {
|
||||
val out = printConfiguration("")
|
||||
|
||||
"Then the rule should not be present in the output" {
|
||||
out shouldBe ""
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -3,6 +3,7 @@ package proguard.optimize
|
||||
import io.kotest.core.spec.style.FreeSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import proguard.classfile.AccessConstants
|
||||
import proguard.classfile.ClassPool
|
||||
import proguard.classfile.Clazz
|
||||
import proguard.classfile.Member
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor
|
||||
@@ -26,7 +27,67 @@ import proguard.util.ProcessingFlagSetter
|
||||
import proguard.util.ProcessingFlags.IS_CLASS_AVAILABLE
|
||||
|
||||
class MemberDescriptorSpecializerTest : FreeSpec({
|
||||
"Given a method with a more general parameter type than its use" - {
|
||||
|
||||
fun specializeMemberDescriptors(
|
||||
programClassPool: ClassPool,
|
||||
libraryClassPool: ClassPool,
|
||||
) {
|
||||
// Mark all program classes as available.
|
||||
programClassPool.classesAccept(ProcessingFlagSetter(IS_CLASS_AVAILABLE))
|
||||
|
||||
// Setup the OptimizationInfo on the classes
|
||||
val keepMarker = KeepMarker()
|
||||
libraryClassPool.classesAccept(keepMarker)
|
||||
libraryClassPool.classesAccept(AllMemberVisitor(keepMarker))
|
||||
|
||||
programClassPool.classesAccept(ProgramClassOptimizationInfoSetter())
|
||||
programClassPool.classesAccept(AllMemberVisitor(ProgramMemberOptimizationInfoSetter()))
|
||||
|
||||
// Create the optimization as in Optimizer
|
||||
val fillingOutValuesClassVisitor = ClassVisitorFactory {
|
||||
val valueFactory: ValueFactory = ParticularValueFactory()
|
||||
val storingInvocationUnit: InvocationUnit = StoringInvocationUnit(
|
||||
valueFactory,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
)
|
||||
ClassAccessFilter(
|
||||
0, AccessConstants.SYNTHETIC,
|
||||
AllMethodVisitor(
|
||||
AllAttributeVisitor(
|
||||
DebugAttributeVisitor(
|
||||
"Filling out fields, method parameters, and return values",
|
||||
PartialEvaluator(
|
||||
valueFactory, storingInvocationUnit,
|
||||
true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
programClassPool.classesAccept(fillingOutValuesClassVisitor.createClassVisitor())
|
||||
|
||||
// Specialize class member descriptors, based on partial evaluation.
|
||||
programClassPool.classesAccept(
|
||||
AllMemberVisitor(
|
||||
OptimizationInfoMemberFilter(
|
||||
MemberDescriptorSpecializer(
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"Given a method with a more general program class pool parameter type than its use" - {
|
||||
val (programClassPool, libraryClassPool) = ClassPoolBuilder.fromSource(
|
||||
JavaSource(
|
||||
"Test.java",
|
||||
@@ -48,60 +109,7 @@ class MemberDescriptorSpecializerTest : FreeSpec({
|
||||
)
|
||||
|
||||
"When specializing the member descriptors" - {
|
||||
|
||||
// Mark all members as available.
|
||||
programClassPool.classesAccept(AllMemberVisitor(ProcessingFlagSetter(IS_CLASS_AVAILABLE)))
|
||||
|
||||
// Setup the OptimizationInfo on the classes
|
||||
val keepMarker = KeepMarker()
|
||||
libraryClassPool.classesAccept(keepMarker)
|
||||
libraryClassPool.classesAccept(AllMemberVisitor(keepMarker))
|
||||
|
||||
programClassPool.classesAccept(ProgramClassOptimizationInfoSetter())
|
||||
programClassPool.classesAccept(AllMemberVisitor(ProgramMemberOptimizationInfoSetter()))
|
||||
|
||||
// Create the optimization as in Optimizer
|
||||
val fillingOutValuesClassVisitor = ClassVisitorFactory {
|
||||
val valueFactory: ValueFactory = ParticularValueFactory()
|
||||
val storingInvocationUnit: InvocationUnit = StoringInvocationUnit(
|
||||
valueFactory,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
)
|
||||
ClassAccessFilter(
|
||||
0, AccessConstants.SYNTHETIC,
|
||||
AllMethodVisitor(
|
||||
AllAttributeVisitor(
|
||||
DebugAttributeVisitor(
|
||||
"Filling out fields, method parameters, and return values",
|
||||
PartialEvaluator(
|
||||
valueFactory, storingInvocationUnit,
|
||||
true
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
programClassPool.classesAccept(fillingOutValuesClassVisitor.createClassVisitor())
|
||||
|
||||
// Specialize class member descriptors, based on partial evaluation.
|
||||
programClassPool.classesAccept(
|
||||
AllMemberVisitor(
|
||||
OptimizationInfoMemberFilter(
|
||||
MemberDescriptorSpecializer(
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
specializeMemberDescriptors(programClassPool, libraryClassPool)
|
||||
|
||||
"Then the member descriptor should be correctly specialised" {
|
||||
lateinit var memberDescriptor: String
|
||||
@@ -122,4 +130,87 @@ class MemberDescriptorSpecializerTest : FreeSpec({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a field with a more general program class pool parameter type than its use" - {
|
||||
val (programClassPool, libraryClassPool) = ClassPoolBuilder.fromSource(
|
||||
JavaSource(
|
||||
"Test.java",
|
||||
"""
|
||||
public class Test {
|
||||
static Bar myField = null;
|
||||
|
||||
public static void main(String[] args) {
|
||||
myField = new Foo();
|
||||
}
|
||||
}
|
||||
|
||||
class Bar { }
|
||||
|
||||
class Foo extends Bar { }
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
|
||||
"When specializing the member descriptors" - {
|
||||
specializeMemberDescriptors(programClassPool, libraryClassPool)
|
||||
|
||||
"Then the member descriptor should be correctly specialised" {
|
||||
lateinit var memberDescriptor: String
|
||||
programClassPool.classAccept(
|
||||
"Test",
|
||||
AllMemberVisitor(
|
||||
MemberNameFilter(
|
||||
"myField*",
|
||||
object : MemberVisitor {
|
||||
override fun visitAnyMember(clazz: Clazz, member: Member) {
|
||||
memberDescriptor = member.getDescriptor(clazz)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
memberDescriptor shouldBe "LFoo;"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a field with a more general library class pool parameter type than its use" - {
|
||||
val (programClassPool, libraryClassPool) = ClassPoolBuilder.fromSource(
|
||||
JavaSource(
|
||||
"Test.java",
|
||||
"""
|
||||
public class Test {
|
||||
static java.lang.Object myField = null;
|
||||
|
||||
public static void main(String[] args) {
|
||||
myField = new java.lang.StringBuffer();
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
|
||||
"When specializing the member descriptors" - {
|
||||
specializeMemberDescriptors(programClassPool, libraryClassPool)
|
||||
|
||||
"Then the member descriptor should be correctly specialised" {
|
||||
lateinit var memberDescriptor: String
|
||||
programClassPool.classAccept(
|
||||
"Test",
|
||||
AllMemberVisitor(
|
||||
MemberNameFilter(
|
||||
"myField*",
|
||||
object : MemberVisitor {
|
||||
override fun visitAnyMember(clazz: Clazz, member: Member) {
|
||||
memberDescriptor = member.getDescriptor(clazz)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
// Library classes are not marked as available by default. Therefore, they are not specialized.
|
||||
memberDescriptor shouldBe "Ljava/lang/Object;"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package proguard.optimize.peephole
|
||||
|
||||
import io.kotest.core.spec.IsolationMode
|
||||
import io.kotest.core.spec.style.FreeSpec
|
||||
import io.kotest.matchers.ints.shouldBeGreaterThan
|
||||
import proguard.classfile.Clazz
|
||||
import proguard.classfile.Method
|
||||
import proguard.classfile.ProgramClass
|
||||
import proguard.classfile.ProgramMethod
|
||||
import proguard.classfile.attribute.CodeAttribute
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor
|
||||
import proguard.classfile.visitor.AllMethodVisitor
|
||||
import proguard.classfile.visitor.ClassVisitor
|
||||
import proguard.classfile.visitor.MultiClassVisitor
|
||||
import proguard.optimize.info.ProgramClassOptimizationInfoSetter
|
||||
import proguard.optimize.info.ProgramMemberOptimizationInfoSetter
|
||||
import proguard.testutils.ClassPoolBuilder
|
||||
import proguard.testutils.JavaSource
|
||||
import testutils.RequiresJavaVersion
|
||||
|
||||
@RequiresJavaVersion(9)
|
||||
class MethodInlinerJava9Test : FreeSpec({
|
||||
isolationMode = IsolationMode.InstancePerTest
|
||||
|
||||
"Given a method calling a private method in the same interface" - {
|
||||
val (programClassPool, _) = ClassPoolBuilder.fromSource(
|
||||
JavaSource(
|
||||
"Foo.java",
|
||||
"""interface Foo {
|
||||
default void f1() {
|
||||
f2();
|
||||
}
|
||||
|
||||
private static void f2() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(System.currentTimeMillis());
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
}""",
|
||||
)
|
||||
)
|
||||
|
||||
val clazz = programClassPool.getClass("Foo") as ProgramClass
|
||||
val method = clazz.findMethod("f1", "()V") as ProgramMethod
|
||||
val codeAttr = method.attributes.filterIsInstance<CodeAttribute>()[0]
|
||||
|
||||
val lengthBefore = codeAttr.u4codeLength
|
||||
|
||||
// Initialize optimization info (used when inlining).
|
||||
val optimizationInfoInitializer: ClassVisitor = MultiClassVisitor(
|
||||
ProgramClassOptimizationInfoSetter(),
|
||||
AllMethodVisitor(
|
||||
ProgramMemberOptimizationInfoSetter()
|
||||
)
|
||||
)
|
||||
|
||||
programClassPool.classesAccept(optimizationInfoInitializer)
|
||||
|
||||
// Create a mock method inliner which always returns true.
|
||||
val methodInliner = object : MethodInliner(false, true, true) {
|
||||
override fun shouldInline(clazz: Clazz?, method: Method?, codeAttribute: CodeAttribute?): Boolean = true
|
||||
}
|
||||
|
||||
"Then the interface method is inlined" {
|
||||
programClassPool.classesAccept(
|
||||
AllMethodVisitor(
|
||||
AllAttributeVisitor(
|
||||
methodInliner
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val lengthAfter = codeAttr.u4codeLength
|
||||
|
||||
lengthAfter shouldBeGreaterThan lengthBefore
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -282,6 +282,60 @@ class MethodInlinerTest : FreeSpec({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"Given a method calling another non-private method in an interface" - {
|
||||
val (programClassPool, _) = ClassPoolBuilder.fromSource(
|
||||
JavaSource(
|
||||
"Foo.java",
|
||||
"""interface Foo {
|
||||
default void f1() {
|
||||
f2();
|
||||
}
|
||||
|
||||
static void f2() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(System.currentTimeMillis());
|
||||
System.out.println(sb.toString());
|
||||
}
|
||||
}"""
|
||||
)
|
||||
)
|
||||
|
||||
val clazz = programClassPool.getClass("Foo") as ProgramClass
|
||||
val method = clazz.findMethod("f1", "()V") as ProgramMethod
|
||||
val codeAttr = method.attributes.filterIsInstance<CodeAttribute>()[0]
|
||||
|
||||
val lengthBefore = codeAttr.u4codeLength
|
||||
|
||||
// Initialize optimization info (used when inlining).
|
||||
val optimizationInfoInitializer: ClassVisitor = MultiClassVisitor(
|
||||
ProgramClassOptimizationInfoSetter(),
|
||||
AllMethodVisitor(
|
||||
ProgramMemberOptimizationInfoSetter()
|
||||
)
|
||||
)
|
||||
|
||||
programClassPool.classesAccept(optimizationInfoInitializer)
|
||||
|
||||
// Create a mock method inliner which always returns true.
|
||||
val methodInliner = object : MethodInliner(false, true, true) {
|
||||
override fun shouldInline(clazz: Clazz?, method: Method?, codeAttribute: CodeAttribute?): Boolean = true
|
||||
}
|
||||
|
||||
"Then the interface method is not inlined" {
|
||||
programClassPool.classesAccept(
|
||||
AllMethodVisitor(
|
||||
AllAttributeVisitor(
|
||||
methodInliner
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val lengthAfter = codeAttr.u4codeLength
|
||||
|
||||
lengthAfter shouldBeExactly lengthBefore
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
private fun printProgramMethodInstructions(
|
||||
|
||||
@@ -10,11 +10,17 @@ import io.kotest.matchers.shouldNot
|
||||
import io.kotest.matchers.shouldNotBe
|
||||
import proguard.AppView
|
||||
import proguard.Configuration
|
||||
import proguard.classfile.Clazz
|
||||
import proguard.classfile.Member
|
||||
import proguard.classfile.attribute.annotation.visitor.AllElementValueVisitor
|
||||
import proguard.classfile.attribute.visitor.AllAttributeVisitor
|
||||
import proguard.classfile.kotlin.visitor.ReferencedKotlinMetadataVisitor
|
||||
import proguard.classfile.util.EnumFieldReferenceInitializer
|
||||
import proguard.classfile.visitor.AllMethodVisitor
|
||||
import proguard.classfile.visitor.MemberVisitor
|
||||
import proguard.classfile.visitor.MultiClassVisitor
|
||||
import proguard.classfile.visitor.NamedClassVisitor
|
||||
import proguard.classfile.visitor.NamedMethodVisitor
|
||||
import proguard.testutils.ClassPoolBuilder
|
||||
import proguard.testutils.JavaSource
|
||||
import proguard.testutils.KotlinSource
|
||||
@@ -212,4 +218,41 @@ class ClassUsageMarkerTest : StringSpec({
|
||||
programClassPool.classAccept("Test", MultiClassVisitor(classUsageMarker, AllMethodVisitor(classUsageMarker)))
|
||||
}
|
||||
}
|
||||
"Given a Kotlin interface with default method implementation" {
|
||||
val (programClassPool, _) = ClassPoolBuilder.fromSource(
|
||||
KotlinSource(
|
||||
"Interface.kt",
|
||||
"""
|
||||
package test;
|
||||
interface Interface {
|
||||
fun foo() : Int {
|
||||
return 42;
|
||||
}
|
||||
}
|
||||
""".trimIndent(),
|
||||
),
|
||||
)
|
||||
|
||||
// Necessary to force marking methods that are not actually used and have not been processed by the Marker.
|
||||
class CustomMarker(var marker: SimpleUsageMarker) : MemberVisitor {
|
||||
override fun visitAnyMember(clazz: Clazz, member: Member) {
|
||||
marker.markAsUsed(member)
|
||||
}
|
||||
}
|
||||
|
||||
val usageMarker = SimpleUsageMarker()
|
||||
val classUsageMarker = ClassUsageMarker(usageMarker)
|
||||
|
||||
// Mark the classes as used.
|
||||
programClassPool.classesAccept(classUsageMarker)
|
||||
|
||||
// Mark the default implementation as used.
|
||||
programClassPool.accept(NamedClassVisitor(NamedMethodVisitor("foo", null, CustomMarker(usageMarker)), "test/Interface\$DefaultImpls"))
|
||||
|
||||
// Process Kotlin metadata: this should cause the interface method to be kept as well.
|
||||
programClassPool.classesAccept(ReferencedKotlinMetadataVisitor(classUsageMarker))
|
||||
|
||||
val fooInterface = programClassPool.getClass("test/Interface").findMethod("foo", null)
|
||||
fooInterface should beMarkedWith(usageMarker)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
This page lists all available options for ProGuard, grouped logically.
|
||||
|
||||
!!! android R8
|
||||
R8, the default Android shrinker, is compatible with ProGuard keep rules.
|
||||
R8, the default Android shrinker, is compatible with ProGuard keep rules. Both ProGuard and R8 were designed for app optimization, and although they employ minimal obfuscation techniques, they are not security tools and do not harden applications effectively against reverse engineering and tampering.
|
||||
|
||||
[DexGuard](https://hubs.la/Q02yCV0F0) is a protection tool for Android apps that is backward compatible with R8, making it easy to upgrade your R8 configuration with multi-layered security protections to your unprotected mobile application. Learn more in our blog: [Android Security and Obfuscation Realities of R8](https://hubs.la/Q02yCTlt0).
|
||||
|
||||
## Input/Output Options {: #iooptions}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Welcome to the manual for **ProGuard** version 7.3 ([what's new?](releasenotes.md)).
|
||||
Welcome to the manual for **ProGuard** version 7.5 ([what's new?](releasenotes.md)).
|
||||
|
||||
ProGuard is an open-sourced Java class file shrinker, optimizer, obfuscator, and
|
||||
preverifier. As a result, ProGuard processed applications and libraries are smaller and faster.
|
||||
|
||||
@@ -1,3 +1,41 @@
|
||||
## Version 7.5.0
|
||||
|
||||
### Kotlin support
|
||||
|
||||
- Add support for Kotlin 2.0. (#376)
|
||||
|
||||
### Java support
|
||||
|
||||
- Add support for Java 22. (#387)
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Prevent unwanted name collision leading to missing methods in Kotlin DefaultImpls classes.
|
||||
- Prevent `ParseException` when consumer rules contain `-maximumremovedandroidloglevel` rules.
|
||||
|
||||
## Version 7.4.2
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Fix potential access issues when backporting.
|
||||
- Fix potential NoClassDefFoundError when using type specialization optimization. (#373)
|
||||
- Improve processing of Kotlin metadata flags to prevent unnecessary null checks for consumers of protected library artifacts.
|
||||
- Prevent potential `StackGeneralizationException` during optimization when processing methods with many arguments.
|
||||
|
||||
### Added
|
||||
|
||||
- `ProGuardTask` support for Gradle configuration cache. (#254)
|
||||
|
||||
## Version 7.4.1
|
||||
|
||||
### Bugfixes
|
||||
|
||||
- Fix inadvertent closing of System.out when printing configuration. (#365)
|
||||
|
||||
### Added
|
||||
|
||||
- Support for parsing of `<clinit>` methods without specifying the return type in class specifications.
|
||||
|
||||
## Version 7.4
|
||||
|
||||
### Java support
|
||||
@@ -11,9 +49,20 @@
|
||||
### Bugfixes
|
||||
|
||||
- Fix "NoClassDefFoundError: Failed resolution of: Lorg/apache/logging/log4j/LogManager" when using GSON optimization or `-addconfigurationdebugging`. (#326)
|
||||
- Don't drop Record attribute for records with no components. (proguard-core#118)
|
||||
- Fix potential duplication class when name obfuscating Kotlin multi-file facades.
|
||||
- Do not inline interface methods during optimization to avoid compilation errors during output writing due to an interface method being made package visible.
|
||||
|
||||
### Added
|
||||
|
||||
- Support parsing of wildcard `*` when used as a field type or method return type in class specifications.
|
||||
|
||||
## Version 7.3.2
|
||||
|
||||
### Java support
|
||||
|
||||
- Add support for Java 20. (#294)
|
||||
|
||||
### Improved
|
||||
|
||||
- Merge classes only when `-optimizeaggressively` is set.
|
||||
|
||||
@@ -7,12 +7,12 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.3.1'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.5.0'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.jetbrains.kotlin.jvm' version '1.8.0'
|
||||
id 'org.jetbrains.kotlin.jvm' version '2.0.0'
|
||||
id 'application'
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
6
examples/application-kotlin/gradlew
vendored
6
examples/application-kotlin/gradlew
vendored
@@ -205,6 +205,12 @@ set -- \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
|
||||
14
examples/application-kotlin/gradlew.bat
vendored
14
examples/application-kotlin/gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,7 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -2,11 +2,12 @@ import proguard.gradle.ProGuardTask
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.3.0'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.5.0'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +33,12 @@ dependencies {
|
||||
|
||||
ext.baseCoordinates = "${project.name}-${project.version}"
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(22)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('proguard', ProGuardTask) {
|
||||
configuration file('proguard.pro')
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
269
examples/application/gradlew
vendored
269
examples/application/gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,67 +17,101 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# 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
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# 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
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
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"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
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
|
||||
@@ -106,80 +140,95 @@ 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 or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
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, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# 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"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
178
examples/application/gradlew.bat
vendored
178
examples/application/gradlew.bat
vendored
@@ -1,89 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath("com.guardsquare:proguard-gradle:7.3.0")
|
||||
classpath("com.guardsquare:proguard-gradle:7.5.0")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
275
examples/gradle-kotlin-dsl/gradlew
vendored
275
examples/gradle-kotlin-dsl/gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,67 +17,101 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# 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
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# 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
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
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"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
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
|
||||
@@ -106,80 +140,101 @@ 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 or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
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, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# 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"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
14
examples/gradle-kotlin-dsl/gradlew.bat
vendored
14
examples/gradle-kotlin-dsl/gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,7 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -2,11 +2,12 @@ import proguard.gradle.ProGuardTask
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.guardsquare:proguard-gradle:7.3.0'
|
||||
classpath 'com.guardsquare:proguard-gradle:7.5.0'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
275
examples/spring-boot/gradlew
vendored
275
examples/spring-boot/gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,67 +17,101 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# 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
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# 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
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
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"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
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
|
||||
@@ -106,80 +140,101 @@ 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 or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
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, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# 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"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
14
examples/spring-boot/gradlew.bat
vendored
14
examples/spring-boot/gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,7 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -48,11 +48,12 @@ dependencies {
|
||||
exclude module: 'proguard-gradle'
|
||||
exclude module: 'proguard-base'
|
||||
}
|
||||
testImplementation 'io.kotest:kotest-runner-junit5-jvm:4.6.0' // for kotest framework
|
||||
testImplementation 'io.kotest:kotest-assertions-core-jvm:4.6.0' // for kotest core jvm assertions
|
||||
testImplementation 'io.kotest:kotest-property-jvm:4.6.0' // for kotest property test
|
||||
|
||||
testImplementation "io.mockk:mockk:1.12.0"
|
||||
testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.9.0' // for kotest framework
|
||||
testImplementation 'io.kotest:kotest-assertions-core-jvm:5.9.0' // for kotest core jvm assertions
|
||||
testImplementation 'io.kotest:kotest-property-jvm:5.9.0' // for kotest property test
|
||||
testImplementation 'io.mockk:mockk:1.13.11' // for mocking
|
||||
|
||||
testImplementation "commons-io:commons-io:2.8.0"
|
||||
|
||||
fatJar project(":base")
|
||||
|
||||
@@ -24,6 +24,7 @@ import groovy.lang.Closure;
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.file.*;
|
||||
import org.gradle.api.logging.*;
|
||||
import org.gradle.api.model.ObjectFactory;
|
||||
import org.gradle.api.tasks.*;
|
||||
import org.gradle.api.tasks.Optional;
|
||||
import org.gradle.util.GradleVersion;
|
||||
@@ -32,6 +33,7 @@ import proguard.classfile.*;
|
||||
import proguard.classfile.util.ClassUtil;
|
||||
import proguard.util.ListUtil;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
@@ -44,6 +46,11 @@ import java.util.*;
|
||||
@CacheableTask
|
||||
public abstract class ProGuardTask extends DefaultTask
|
||||
{
|
||||
@Inject
|
||||
protected abstract ObjectFactory getObjectFactory();
|
||||
@Inject
|
||||
protected abstract ProjectLayout getProjectLayout();
|
||||
|
||||
// Accumulated input and output, for the sake of Gradle's lazy file
|
||||
// resolution and lazy task execution.
|
||||
private final List inJarFiles = new ArrayList();
|
||||
@@ -63,16 +70,12 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
private ClassSpecification classSpecification;
|
||||
|
||||
public static final String DEFAULT_CONFIG_RESOURCE_PREFIX = "/lib";
|
||||
private final String resolvedConfigurationFileNamePrefix = getProject().file(DEFAULT_CONFIG_RESOURCE_PREFIX).toString();
|
||||
private final String resolvedConfigurationFileNamePrefix = getProjectLayout().files(DEFAULT_CONFIG_RESOURCE_PREFIX).getSingleFile().toString();
|
||||
|
||||
// INTERNAL USE ONLY - write extra data entries to this jar
|
||||
private File extraJar;
|
||||
|
||||
public ProGuardTask() {
|
||||
if (GradleVersion.current().compareTo(GradleVersion.version("7.4")) >= 0) {
|
||||
// This method was added in Gradle 7.4
|
||||
notCompatibleWithConfigurationCache("https://github.com/Guardsquare/proguard/issues/254");
|
||||
}
|
||||
}
|
||||
|
||||
// Gradle task inputs and outputs, because annotations on the List fields
|
||||
@@ -82,26 +85,26 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
@Classpath
|
||||
public FileCollection getInJarFileCollection()
|
||||
{
|
||||
return getProject().files(inJarFiles);
|
||||
return getProjectLayout().files(inJarFiles);
|
||||
}
|
||||
|
||||
@OutputFiles
|
||||
public FileCollection getOutJarFileCollection()
|
||||
{
|
||||
return getProject().files(outJarFiles);
|
||||
return getProjectLayout().files(outJarFiles);
|
||||
}
|
||||
|
||||
@Classpath
|
||||
public FileCollection getLibraryJarFileCollection()
|
||||
{
|
||||
return getProject().files(libraryJarFiles);
|
||||
return getProjectLayout().files(libraryJarFiles);
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
@PathSensitive(PathSensitivity.RELATIVE)
|
||||
public FileCollection getConfigurationFileCollection()
|
||||
{
|
||||
return getProject().files(configurationFiles);
|
||||
return getProjectLayout().files(configurationFiles);
|
||||
}
|
||||
|
||||
// Convenience methods to retrieve settings from outside the task.
|
||||
@@ -672,7 +675,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
public void printseeds(Object printSeeds)
|
||||
throws ParseException
|
||||
{
|
||||
configuration.printSeeds = getProject().file(printSeeds);
|
||||
configuration.printSeeds = getProjectLayout().files(printSeeds).getSingleFile();
|
||||
}
|
||||
|
||||
@Optional
|
||||
@@ -710,7 +713,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
public void printusage(Object printUsage)
|
||||
throws ParseException
|
||||
{
|
||||
configuration.printUsage = getProject().file(printUsage);
|
||||
configuration.printUsage = getProjectLayout().files(printUsage).getSingleFile();
|
||||
}
|
||||
|
||||
@Optional
|
||||
@@ -925,7 +928,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
public void printmapping(Object printMapping)
|
||||
throws ParseException
|
||||
{
|
||||
configuration.printMapping = getProject().file(printMapping);
|
||||
configuration.printMapping = getProjectLayout().files(printMapping).getSingleFile();
|
||||
}
|
||||
|
||||
@Optional
|
||||
@@ -937,7 +940,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
public void applymapping(Object applyMapping)
|
||||
throws ParseException
|
||||
{
|
||||
configuration.applyMapping = getProject().file(applyMapping);
|
||||
configuration.applyMapping = getProjectLayout().files(applyMapping).getSingleFile();
|
||||
}
|
||||
|
||||
public void obfuscationdictionary(Object obfuscationDictionary)
|
||||
@@ -1219,7 +1222,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
public void keystore(Object keyStore)
|
||||
{
|
||||
configuration.keyStores =
|
||||
extendList(configuration.keyStores, getProject().file(keyStore));
|
||||
extendList(configuration.keyStores, getProjectLayout().files(keyStore).getSingleFile());
|
||||
}
|
||||
|
||||
public void keystorepassword(String keyStorePassword)
|
||||
@@ -1321,7 +1324,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
throws ParseException
|
||||
{
|
||||
configuration.printConfiguration =
|
||||
getProject().file(printConfiguration);
|
||||
getProjectLayout().files(printConfiguration).getSingleFile();
|
||||
}
|
||||
|
||||
@Optional
|
||||
@@ -1346,7 +1349,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
public void dump(Object dump)
|
||||
throws ParseException
|
||||
{
|
||||
configuration.dump = getProject().file(dump);
|
||||
configuration.dump = getProjectLayout().files(dump).getSingleFile();
|
||||
}
|
||||
|
||||
@Optional
|
||||
@@ -1490,7 +1493,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
Object fileObject = configurationFiles.get(index);
|
||||
|
||||
ConfigurableFileCollection fileCollection =
|
||||
getProject().files(fileObject);
|
||||
getObjectFactory().fileCollection().from(fileObject);
|
||||
|
||||
// Parse the configuration as a collection of files.
|
||||
Iterator<File> files = fileCollection.iterator();
|
||||
@@ -1595,7 +1598,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
Map filterArgs,
|
||||
boolean output)
|
||||
{
|
||||
ConfigurableFileCollection fileCollection = getProject().files(files);
|
||||
ConfigurableFileCollection fileCollection = getObjectFactory().fileCollection().from(files);
|
||||
|
||||
if (classPath == null)
|
||||
{
|
||||
@@ -2299,7 +2302,7 @@ public abstract class ProGuardTask extends DefaultTask
|
||||
*/
|
||||
private URL url(Object fileObject) throws MalformedURLException
|
||||
{
|
||||
File file = getProject().file(fileObject);
|
||||
File file = getProjectLayout().files(fileObject).getSingleFile();
|
||||
return
|
||||
fileObject instanceof URL ? (URL)fileObject :
|
||||
fileObject instanceof String &&
|
||||
|
||||
@@ -46,6 +46,7 @@ class GradlePluginIntegrationTest : FreeSpec({
|
||||
.forwardOutput()
|
||||
.withArguments("proguard")
|
||||
.withPluginClasspath()
|
||||
.withGradleVersion("7.4")
|
||||
.withProjectDir(projectRoot)
|
||||
.build()
|
||||
|
||||
@@ -55,8 +56,6 @@ class GradlePluginIntegrationTest : FreeSpec({
|
||||
}
|
||||
}
|
||||
|
||||
// ProguardTask is still incompatible, but will not fail the build. Once the issue is resolved, this test will fail
|
||||
// and should be updated to demonstrate compatibility.
|
||||
"ProguardTask will not fail when configuration cache is used" - {
|
||||
val projectRoot = tempdir()
|
||||
val fixture = File(GradlePluginIntegrationTest::class.java.classLoader.getResource("application").path)
|
||||
@@ -76,13 +75,12 @@ class GradlePluginIntegrationTest : FreeSpec({
|
||||
|
||||
"Then the build was successful with configuration cache" {
|
||||
result.output shouldContain "SUCCESSFUL"
|
||||
// E.g., "Configuration cache entry discarded with 4 problems."
|
||||
result.output shouldContain "Configuration cache entry discarded with"
|
||||
result.output shouldContain "Configuration cache entry stored."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"gradle plugin can be configured via #configOption" - {
|
||||
"gradle plugin can be configured via #configOption" {
|
||||
include(testConfigOption("proguard"))
|
||||
include(testConfigOption("proguardWithConfigFile"))
|
||||
include(testConfigOption("proguardWithGeneratedConfigFile"))
|
||||
@@ -94,6 +92,7 @@ fun testConfigOption(task: String) = funSpec {
|
||||
GradleRunner.create()
|
||||
.forwardOutput()
|
||||
.withArguments(tasks.asList())
|
||||
.withGradleVersion("7.4")
|
||||
.withPluginClasspath()
|
||||
.withProjectDir(projectRoot)
|
||||
.build()
|
||||
|
||||
@@ -32,7 +32,7 @@ import testutils.TestPluginClasspath
|
||||
|
||||
class ProguardCacheRelocateabilityIntegrationTest : FreeSpec({
|
||||
|
||||
"proguard task can be relocated" - {
|
||||
"proguard task can be relocated" {
|
||||
val cacheDir = tempdir()
|
||||
val fixture = File(ProguardCacheRelocateabilityIntegrationTest::class.java.classLoader.getResource("spring-boot").path)
|
||||
|
||||
@@ -49,6 +49,7 @@ class ProguardCacheRelocateabilityIntegrationTest : FreeSpec({
|
||||
GradleRunner.create()
|
||||
.forwardOutput()
|
||||
.withArguments("proguard", "--build-cache")
|
||||
.withGradleVersion("7.4")
|
||||
.withPluginClasspath()
|
||||
.withProjectDir(originalDir)
|
||||
.build()
|
||||
@@ -56,6 +57,7 @@ class ProguardCacheRelocateabilityIntegrationTest : FreeSpec({
|
||||
val result2 = GradleRunner.create()
|
||||
.forwardOutput()
|
||||
.withArguments("proguard", "--build-cache")
|
||||
.withGradleVersion("7.4")
|
||||
.withPluginClasspath()
|
||||
.withProjectDir(relocatedDir)
|
||||
.build()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
proguardVersion = 7.4.0-beta01
|
||||
proguardVersion = 7.5.0
|
||||
|
||||
# The version of ProGuardCORE that sub-projects are built with
|
||||
proguardCoreVersion = 9.0.9
|
||||
proguardCoreVersion = 9.1.4
|
||||
gsonVersion = 2.9.0
|
||||
kotlinVersion = 1.7.20
|
||||
kotlinVersion = 2.0.0
|
||||
target = 1.8
|
||||
|
||||
# Optionally compile the WTK plugin.
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
275
gradlew
vendored
275
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -17,67 +17,101 @@
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# 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
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${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='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# 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
|
||||
;;
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
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"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
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
|
||||
@@ -106,80 +140,101 @@ 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 or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; 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=`expr $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" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
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, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# 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"
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
|
||||
14
gradlew.bat
vendored
14
gradlew.bat
vendored
@@ -14,7 +14,7 @@
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@@ -25,7 +25,7 @@
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -75,13 +75,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
@@ -116,7 +116,7 @@ public class FrameRemapper implements MappingProcessor
|
||||
if (fieldInfo.matches(originalType))
|
||||
{
|
||||
originalFieldFrames.add(new FrameInfo(fieldInfo.originalClassName,
|
||||
obfuscatedFrame.getSourceFile().equals("Unknown Source") ?
|
||||
"Unknown Source".equals(obfuscatedFrame.getSourceFile()) ?
|
||||
"Unknown Source" :
|
||||
sourceFileName(fieldInfo.originalClassName),
|
||||
obfuscatedFrame.getLineNumber(),
|
||||
@@ -186,7 +186,7 @@ public class FrameRemapper implements MappingProcessor
|
||||
}
|
||||
|
||||
originalMethodFrames.add(new FrameInfo(methodInfo.originalClassName,
|
||||
obfuscatedFrame.getSourceFile().equals("Unknown Source") ?
|
||||
"Unknown Source".equals(obfuscatedFrame.getSourceFile()) ?
|
||||
"Unknown Source" :
|
||||
sourceFileName(methodInfo.originalClassName),
|
||||
lineNumber,
|
||||
|
||||
@@ -2,7 +2,7 @@ pluginManagement {
|
||||
resolutionStrategy {
|
||||
eachPlugin {
|
||||
if (requested.id.id == 'com.github.johnrengelman.shadow') {
|
||||
useVersion '5.2.0'
|
||||
useVersion '8.1.1'
|
||||
}
|
||||
if (requested.id.id == 'io.github.gradle-nexus.publish-plugin') {
|
||||
useVersion '1.1.0'
|
||||
@@ -11,6 +11,10 @@ pluginManagement {
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
|
||||
}
|
||||
|
||||
rootProject.name = 'proguard'
|
||||
|
||||
include 'base'
|
||||
|
||||
Reference in New Issue
Block a user