fix: generate gradle wrapper with WrapperGenerator in 'generateGradleWrapper' task

This commit is contained in:
Akash Yadav
2024-01-03 15:32:39 +05:30
parent 79bb27225d
commit 5e5f8638c0
7 changed files with 802 additions and 29 deletions
+1
View File
@@ -44,5 +44,6 @@ dependencies {
implementation(libs.common.jkotlin)
implementation(libs.common.antlr4)
implementation(libs.google.gson)
implementation(libs.google.java.format)
}
@@ -23,9 +23,9 @@ import com.android.build.api.variant.AndroidComponentsExtension
import com.android.build.gradle.BaseExtension
import com.itsaky.androidide.plugins.tasks.AddAndroidJarToAssetsTask
import com.itsaky.androidide.plugins.tasks.AddFileToAssetsTask
import com.itsaky.androidide.plugins.tasks.SetupAapt2Task
import com.itsaky.androidide.plugins.tasks.GenerateInitScriptTask
import com.itsaky.androidide.plugins.tasks.GradleWrapperBuilderTask
import com.itsaky.androidide.plugins.tasks.GradleWrapperGeneratorTask
import com.itsaky.androidide.plugins.tasks.SetupAapt2Task
import com.itsaky.androidide.plugins.util.SdkUtils.getAndroidJar
import downloadVersion
import org.gradle.api.Plugin
@@ -51,8 +51,8 @@ class AndroidIDEAssetsPlugin : Plugin<Project> {
override fun apply(target: Project) {
target.run {
val wrapperBuilderTaskProvider = tasks.register("generateGradleWrapper",
GradleWrapperBuilderTask::class.java
val wrapperGeneratorTaskProvider = tasks.register("generateGradleWrapper",
GradleWrapperGeneratorTask::class.java
)
val androidComponentsExtension = extensions.getByType(AndroidComponentsExtension::class.java)
@@ -76,8 +76,8 @@ class AndroidIDEAssetsPlugin : Plugin<Project> {
val variantNameCapitalized = variant.name.capitalized()
variant.sources.assets?.addGeneratedSourceDirectory(wrapperBuilderTaskProvider,
GradleWrapperBuilderTask::outputDirectory)
variant.sources.assets?.addGeneratedSourceDirectory(wrapperGeneratorTaskProvider,
GradleWrapperGeneratorTask::outputDirectory)
variant.sources.assets?.addGeneratedSourceDirectory(addAndroidJarTaskProvider,
AddAndroidJarToAssetsTask::outputDirectory)
@@ -0,0 +1,118 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.itsaky.androidide.plugins.tasks;
import static org.gradle.api.tasks.wrapper.internal.DefaultWrapperVersionsResources.LATEST;
import static org.gradle.api.tasks.wrapper.internal.DefaultWrapperVersionsResources.NIGHTLY;
import static org.gradle.api.tasks.wrapper.internal.DefaultWrapperVersionsResources.RELEASE_CANDIDATE;
import static org.gradle.api.tasks.wrapper.internal.DefaultWrapperVersionsResources.RELEASE_NIGHTLY;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.Map;
import org.gradle.api.GradleException;
import org.gradle.api.resources.TextResource;
import org.gradle.api.tasks.wrapper.internal.DefaultWrapperVersionsResources;
import org.gradle.util.GradleVersion;
class GradleVersionResolver {
private TextResource latest;
private TextResource releaseCandidate;
private TextResource nightly;
private TextResource releaseNightly;
private GradleVersion gradleVersion;
private String gradleVersionString = GradleVersion.current().getVersion();
void setTextResources(TextResource latest, TextResource releaseCandidate, TextResource nightly,
TextResource releaseNightly) {
this.latest = latest;
this.releaseCandidate = releaseCandidate;
this.nightly = nightly;
this.releaseNightly = releaseNightly;
}
String resolve(String version) {
if (version == null) {
return GradleVersion.current().getVersion();
}
switch (version) {
case LATEST:
return getVersion(latest.asString(), version);
case NIGHTLY:
return getVersion(nightly.asString(), version);
case RELEASE_NIGHTLY:
return getVersion(releaseNightly.asString(), version);
case RELEASE_CANDIDATE:
return getVersion(releaseCandidate.asString(), version);
default:
return version;
}
}
static String getVersion(String json, String placeHolder) {
Type type = new TypeToken<Map<String, String>>() {
}.getType();
Map<String, String> map = new Gson().fromJson(json, type);
String version = map.get("version");
if (version == null) {
throw new GradleException(
"There is currently no version information available for '" + placeHolder + "'.");
}
return version;
}
static boolean isPlaceHolder(String version) {
return DefaultWrapperVersionsResources.PLACE_HOLDERS.contains(version);
}
GradleVersion getGradleVersion() {
if (gradleVersion == null) {
gradleVersion = GradleVersion.version(resolve(gradleVersionString));
}
return gradleVersion;
}
void setGradleVersionString(String gradleVersionString) {
if (!isPlaceHolder(gradleVersionString)) {
this.gradleVersion = GradleVersion.version(gradleVersionString);
}
if (this.gradleVersionString != gradleVersionString) {
this.gradleVersionString = gradleVersionString;
this.gradleVersion = null;
}
}
}
@@ -21,8 +21,8 @@ import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.OutputDirectory
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.wrapper.Wrapper
import java.io.File
import java.nio.charset.StandardCharsets
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
@@ -31,7 +31,7 @@ import java.util.zip.ZipOutputStream
*
* @author Akash Yadav
*/
abstract class GradleWrapperBuilderTask : DefaultTask() {
abstract class GradleWrapperGeneratorTask : DefaultTask() {
/**
* The output directory.
@@ -42,14 +42,6 @@ abstract class GradleWrapperBuilderTask : DefaultTask() {
companion object {
private const val GRADLE_VERSION = "7.4.2"
private val GRADLE_PROPERTIES_CONTENTS = """
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
""".trimIndent()
}
@TaskAction
@@ -63,24 +55,37 @@ abstract class GradleWrapperBuilderTask : DefaultTask() {
destFile.delete()
}
val stagingDir = File(outputDirectory, "staging")
if (stagingDir.exists()) {
stagingDir.deleteRecursively()
}
stagingDir.mkdirs()
// Generate the files
val generator = IDEWrapperGenerator()
generator.jarFile = File(stagingDir, "gradle/wrapper/gradle-wrapper.jar")
generator.scriptFile = File(stagingDir, "gradlew")
generator.gradleVersion = GRADLE_VERSION
generator.distributionType = Wrapper.DistributionType.BIN
generator.generate(project)
// Archive all generated files
ZipOutputStream(destFile.outputStream().buffered()).use { zipOut ->
// Add static files
for (file in arrayOf("gradlew", "gradlew.bat", "gradle/wrapper/gradle-wrapper.jar")) {
val fileIn = File(project.rootProject.rootDir, file)
val entry = ZipEntry(file)
zipOut.putNextEntry(entry)
fileIn.inputStream().buffered().use { fileInStream ->
fileInStream.transferTo(zipOut)
stagingDir.walk(direction = FileWalkDirection.TOP_DOWN)
.filter { it.isFile }
.forEach { file ->
val entry = ZipEntry(file.relativeTo(stagingDir).path)
zipOut.putNextEntry(entry)
file.inputStream().buffered().use { fileInStream ->
fileInStream.transferTo(zipOut)
}
}
}
zipOut.putNextEntry(ZipEntry("gradle/wrapper/gradle-wrapper.properties"))
zipOut.write(GRADLE_PROPERTIES_CONTENTS.toByteArray(charset = StandardCharsets.UTF_8))
zipOut.flush()
}
destFile.setLastModified(System.currentTimeMillis())
// finally, delete the staging directory
stagingDir.deleteRecursively()
}
}
@@ -0,0 +1,474 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
/*
* Copyright 2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.itsaky.androidide.plugins.tasks;
import com.itsaky.androidide.plugins.tasks.internal.WrapperDefaults;
import com.itsaky.androidide.plugins.tasks.internal.WrapperGenerator;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import javax.annotation.Nullable;
import javax.inject.Inject;
import kotlin.io.FilesKt;
import org.gradle.api.GradleException;
import org.gradle.api.Incubating;
import org.gradle.api.Project;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.internal.file.FileLookup;
import org.gradle.api.internal.file.FileOperations;
import org.gradle.api.internal.file.FileResolver;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.options.Option;
import org.gradle.api.tasks.options.OptionValues;
import org.gradle.api.tasks.wrapper.Wrapper.DistributionType;
import org.gradle.api.tasks.wrapper.Wrapper.PathBase;
import org.gradle.api.tasks.wrapper.WrapperVersionsResources;
import org.gradle.api.tasks.wrapper.internal.DefaultWrapperVersionsResources;
import org.gradle.util.GradleVersion;
import org.gradle.util.internal.GUtil;
import org.gradle.util.internal.WrapperDistributionUrlConverter;
import org.gradle.wrapper.Download;
import org.gradle.wrapper.Logger;
import org.gradle.wrapper.WrapperExecutor;
/**
* <p>Generates scripts (for *nix and windows) which allow you to build your project with Gradle,
* without having to install Gradle.
*
* <p>When a user executes a wrapper script the first time, the script downloads and installs the
* appropriate Gradle distribution and runs the build against this downloaded distribution. Any
* installed Gradle distribution is ignored when using the wrapper scripts.
*
* <p>The scripts generated by this task are intended to be committed to your version control
* system. This task also generates a small {@code gradle-wrapper.jar} bootstrap JAR file and
* properties file which should also be committed to your VCS. The scripts delegates to this JAR.
*/
public class IDEWrapperGenerator {
public static final String DEFAULT_DISTRIBUTION_PARENT_NAME = WrapperDefaults.DISTRIBUTION_PATH;
private File scriptFile = new File(WrapperDefaults.SCRIPT_PATH);
private File jarFile = new File(WrapperDefaults.JAR_FILE_PATH);
private String distributionPath = DEFAULT_DISTRIBUTION_PARENT_NAME;
private PathBase distributionBase = WrapperDefaults.DISTRIBUTION_BASE;
private String distributionUrl;
private String distributionSha256Sum;
private final GradleVersionResolver gradleVersionResolver = new GradleVersionResolver();
private DistributionType distributionType = WrapperDefaults.DISTRIBUTION_TYPE;
private String archivePath = WrapperDefaults.ARCHIVE_PATH;
private PathBase archiveBase = WrapperDefaults.ARCHIVE_BASE;
private final int networkTimeout = WrapperDefaults.NETWORK_TIMEOUT;
private boolean distributionUrlConfigured = false;
void generate(Project project) {
final var isOffline = project.getGradle().getStartParameter().isOffline();
File jarFileDestination = getJarFile();
File unixScript = getScriptFile();
File propertiesFile = getPropertiesFile();
Properties existingProperties =
propertiesFile.exists() ? GUtil.loadProperties(propertiesFile) : null;
checkProperties(existingProperties);
validateDistributionUrl(propertiesFile.getParentFile(), isOffline);
WrapperGenerator.generate(archiveBase, archivePath, distributionBase, distributionPath,
getDistributionSha256Sum(existingProperties), propertiesFile, jarFileDestination,
FilesKt.relativeTo(jarFileDestination, unixScript.getParentFile()).getPath(), unixScript, getBatchScript(), getDistributionUrl(),
getValidateDistributionUrl(), networkTimeout);
}
private void checkProperties(Properties existingProperties) {
String checksumProperty = existingProperties != null ? existingProperties.getProperty(
WrapperExecutor.DISTRIBUTION_SHA_256_SUM, null) : null;
if (!isCurrentVersion() && distributionSha256Sum == null && checksumProperty != null) {
throw new GradleException(
"gradle-wrapper.properties contains distributionSha256Sum property, but the wrapper configuration does not have one. Specify one in the wrapper task configuration or with the --gradle-distribution-sha256-sum task option");
}
}
private static final String DISTRIBUTION_URL_EXCEPTION_MESSAGE = "Test of distribution url %s failed. Please check the values set with --gradle-distribution-url and --gradle-version.";
private void validateDistributionUrl(File uriRoot, boolean isOffline) {
if (distributionUrlConfigured && getValidateDistributionUrl()) {
String url = getDistributionUrl();
URI uri = getDistributionUri(uriRoot, url);
if (uri.getScheme().equals("file")) {
if (!Files.exists(Paths.get(uri).toAbsolutePath())) {
throw new UncheckedIOException(String.format(DISTRIBUTION_URL_EXCEPTION_MESSAGE, url));
}
} else if (uri.getScheme().startsWith("http") && !isOffline) {
try {
new Download(new Logger(true), "gradlew", Download.UNKNOWN_VERSION).sendHeadRequest(uri);
} catch (Exception e) {
throw new UncheckedIOException(String.format(DISTRIBUTION_URL_EXCEPTION_MESSAGE, url), e);
}
}
}
}
private static URI getDistributionUri(File uriRoot, String url) {
try {
return WrapperDistributionUrlConverter.convertDistributionUrl(url, uriRoot);
} catch (URISyntaxException e) {
throw new GradleException("Distribution URL String cannot be parsed: " + url, e);
}
}
private String getDistributionSha256Sum(Properties existingProperties) {
if (distributionSha256Sum != null) {
return distributionSha256Sum;
} else if (isCurrentVersion() && existingProperties != null) {
return existingProperties.getProperty(WrapperExecutor.DISTRIBUTION_SHA_256_SUM, null);
} else {
return null;
}
}
private boolean isCurrentVersion() {
return GradleVersion.current().equals(gradleVersionResolver.getGradleVersion());
}
/**
* Returns the file to write the wrapper script to.
*/
public File getScriptFile() {
return scriptFile;
}
/**
* The file to write the wrapper script to.
*
* @since 4.0
*/
public void setScriptFile(File scriptFile) {
this.scriptFile = scriptFile;
}
/**
* Returns the file to write the wrapper batch script to.
*/
public File getBatchScript() {
return WrapperGenerator.getBatchScript(getScriptFile());
}
/**
* Returns the file to write the wrapper jar file to.
*/
public File getJarFile() {
return this.jarFile;
}
/**
* The file to write the wrapper jar file to.
*
* @since 4.0
*/
public void setJarFile(File jarFile) {
this.jarFile = jarFile;
}
/**
* Returns the file to write the wrapper properties to.
*/
public File getPropertiesFile() {
return WrapperGenerator.getPropertiesFile(getJarFile());
}
/**
* Returns the path where the gradle distributions needed by the wrapper are unzipped. The path is
* relative to the distribution base directory
*
* @see #setDistributionPath(String)
*/
public String getDistributionPath() {
return distributionPath;
}
/**
* Sets the path where the gradle distributions needed by the wrapper are unzipped. The path is
* relative to the distribution base directory
*
* @see #setDistributionPath(String)
*/
public void setDistributionPath(String distributionPath) {
this.distributionPath = distributionPath;
}
/**
* Set Wrapper versions resources.
*
* @since 8.1
*/
@Incubating
public void setWrapperVersionsResources(WrapperVersionsResources wrapperVersionsResources) {
DefaultWrapperVersionsResources defaultWrapperVersionsResources = (DefaultWrapperVersionsResources) wrapperVersionsResources;
gradleVersionResolver.setTextResources(defaultWrapperVersionsResources.getLatest(),
defaultWrapperVersionsResources.getReleaseCandidate(),
defaultWrapperVersionsResources.getNightly(),
defaultWrapperVersionsResources.getReleaseNightly());
}
/**
* Returns the gradle version for the wrapper.
*
* @throws GradleException if the label that can be provided via {@link #setGradleVersion(String)}
* can not be resolved at the moment. For example, there is not a
* `release-candidate` available at all times.
* @see #setGradleVersion(String)
*/
public String getGradleVersion() {
return gradleVersionResolver.getGradleVersion().getVersion();
}
/**
* The version of the gradle distribution required by the wrapper. This is usually the same
* version of Gradle you use for building your project. The following labels are allowed to
* specify a version: {@code latest}, {@code release-candidate}, {@code nightly}, and
* {@code release-nightly}
*
* <p>The resulting distribution url is validated before it is written to the
* gradle-wrapper.properties file.
*/
@Option(option = "gradle-version", description =
"The version of the Gradle distribution required by the wrapper. "
+ "The following labels are allowed: latest, release-candidate, nightly, and release-nightly.")
public void setGradleVersion(String gradleVersion) {
distributionUrlConfigured = true;
this.gradleVersionResolver.setGradleVersionString(gradleVersion);
}
/**
* Returns the type of the Gradle distribution to be used by the wrapper.
*
* @see #setDistributionType(DistributionType)
*/
public DistributionType getDistributionType() {
return distributionType;
}
/**
* The type of the Gradle distribution to be used by the wrapper. By default, this is
* {@link DistributionType#BIN}, which is the binary-only Gradle distribution without
* documentation.
*
* @see DistributionType
*/
@Option(option = "distribution-type", description = "The type of the Gradle distribution to be used by the wrapper.")
public void setDistributionType(DistributionType distributionType) {
this.distributionType = distributionType;
}
/**
* The list of available gradle distribution types.
*/
@OptionValues("distribution-type")
public List<DistributionType> getAvailableDistributionTypes() {
return Arrays.asList(DistributionType.values());
}
/**
* The URL to download the gradle distribution from.
*
* <p>If not set, the download URL is the default for the specified {@link #getGradleVersion()}.
*
* <p>If {@link #getGradleVersion()} is not set, will return null.
*
* <p>The wrapper downloads a certain distribution only once and caches it. If your distribution
* base is the project, you might submit the distribution to your version control system. That way
* no download is necessary at all. This might be in particular interesting, if you provide a
* custom gradle snapshot to the wrapper, because you don't need to provide a download server
* then.
*/
public String getDistributionUrl() {
if (distributionUrl != null) {
return distributionUrl;
}
return WrapperGenerator.getDistributionUrl(gradleVersionResolver.getGradleVersion(),
distributionType);
}
/**
* The URL to download the gradle distribution from.
*
* <p>If not set, the download URL is the default for the specified {@link #getGradleVersion()}.
*
* <p>If {@link #getGradleVersion()} is not set, will return null.
*
* <p>The wrapper downloads a certain distribution and caches it. If your distribution base is
* the project, you might submit the distribution to your version control system. That way no
* download is necessary at all. This might be in particular interesting, if you provide a custom
* gradle snapshot to the wrapper, because you don't need to provide a download server then.
*
* <p>The distribution url is validated before it is written to the gradle-wrapper.properties
* file.
*/
@Option(option = "gradle-distribution-url", description = "The URL to download the Gradle distribution from.")
public void setDistributionUrl(String url) {
distributionUrlConfigured = true;
this.distributionUrl = url;
}
/**
* The SHA-256 hash sum of the gradle distribution.
*
* <p>If not set, the hash sum of the gradle distribution is not verified.
*
* <p>The wrapper allows for verification of the downloaded Gradle distribution via SHA-256 hash
* sum comparison. This increases security against targeted attacks by preventing a
* man-in-the-middle attacker from tampering with the downloaded Gradle distribution.
*
* @since 4.5
*/
@Nullable
@Optional
public String getDistributionSha256Sum() {
return distributionSha256Sum;
}
/**
* The SHA-256 hash sum of the gradle distribution.
*
* <p>If not set, the hash sum of the gradle distribution is not verified.
*
* <p>The wrapper allows for verification of the downloaded Gradle distribution via SHA-256 hash
* sum comparison. This increases security against targeted attacks by preventing a
* man-in-the-middle attacker from tampering with the downloaded Gradle distribution.
*
* @since 4.5
*/
@Option(option = "gradle-distribution-sha256-sum", description = "The SHA-256 hash sum of the gradle distribution.")
public void setDistributionSha256Sum(@Nullable String distributionSha256Sum) {
this.distributionSha256Sum = distributionSha256Sum;
}
/**
* The distribution base specifies whether the unpacked wrapper distribution should be stored in
* the project or in the gradle user home dir.
*/
public PathBase getDistributionBase() {
return distributionBase;
}
/**
* The distribution base specifies whether the unpacked wrapper distribution should be stored in
* the project or in the gradle user home dir.
*/
public void setDistributionBase(PathBase distributionBase) {
this.distributionBase = distributionBase;
}
/**
* Returns the path where the gradle distributions archive should be saved (i.e. the parent dir).
* The path is relative to the archive base directory.
*/
public String getArchivePath() {
return archivePath;
}
/**
* Set's the path where the gradle distributions archive should be saved (i.e. the parent dir).
* The path is relative to the parent dir specified with {@link #getArchiveBase()}.
*/
public void setArchivePath(String archivePath) {
this.archivePath = archivePath;
}
/**
* The archive base specifies whether the unpacked wrapper distribution should be stored in the
* project or in the gradle user home dir.
*/
public PathBase getArchiveBase() {
return archiveBase;
}
/**
* The archive base specifies whether the unpacked wrapper distribution should be stored in the
* project or in the gradle user home dir.
*/
public void setArchiveBase(PathBase archiveBase) {
this.archiveBase = archiveBase;
}
/**
* The network timeout specifies how many ms to wait for when the wrapper is performing network
* operations, such as downloading the wrapper jar.
*
* @since 7.6
*/
@Incubating
@Optional
@Option(option = "network-timeout", description = "Timeout in ms to use when the wrapper is performing network operations.")
public Integer getNetworkTimeout() {
return networkTimeout;
}
/**
* Indicates if this task will validate the distribution url that has been configured.
*
* @return whether this task will validate the distribution url
* @since 8.2
*/
@Incubating
@Option(option = "validate-url", description = "Sets task to validate the configured distribution url.")
public Boolean getValidateDistributionUrl() {
return true;
}
@Inject
protected FileLookup getFileLookup() {
throw new UnsupportedOperationException();
}
}
@@ -0,0 +1,37 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.plugins.tasks.internal;
import org.gradle.api.NonNullApi;
import org.gradle.api.tasks.wrapper.Wrapper;
import org.gradle.wrapper.Install;
@NonNullApi
public class WrapperDefaults {
public static final String SCRIPT_PATH = "gradlew";
public static final String JAR_FILE_PATH = "gradle/wrapper/gradle-wrapper.jar";
public static final Wrapper.DistributionType DISTRIBUTION_TYPE = Wrapper.DistributionType.BIN;
public static final String DISTRIBUTION_PATH = Install.DEFAULT_DISTRIBUTION_PATH;
public static final Wrapper.PathBase DISTRIBUTION_BASE = Wrapper.PathBase.GRADLE_USER_HOME;
public static final String ARCHIVE_PATH = DISTRIBUTION_PATH;
public static final Wrapper.PathBase ARCHIVE_BASE = DISTRIBUTION_BASE;
public static final int NETWORK_TIMEOUT = 10000;
public static final boolean VALIDATE_DISTRIBUTION_URL = true;
}
@@ -0,0 +1,138 @@
/*
* This file is part of AndroidIDE.
*
* AndroidIDE 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 3 of the License, or
* (at your option) any later version.
*
* AndroidIDE 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 AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
*/
package com.itsaky.androidide.plugins.tasks.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import org.gradle.api.GradleException;
import org.gradle.api.NonNullApi;
import org.gradle.api.UncheckedIOException;
import org.gradle.api.internal.plugins.StartScriptGenerator;
import org.gradle.api.tasks.wrapper.Wrapper;
import org.gradle.api.tasks.wrapper.Wrapper.PathBase;
import org.gradle.internal.util.PropertiesUtils;
import org.gradle.util.GradleVersion;
import org.gradle.util.internal.DistributionLocator;
import org.gradle.util.internal.GFileUtils;
import org.gradle.wrapper.GradleWrapperMain;
import org.gradle.wrapper.WrapperExecutor;
import javax.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.nio.file.Files;
import java.util.Locale;
import java.util.Properties;
import static java.util.Collections.singletonList;
@NonNullApi
public class WrapperGenerator {
public static File getPropertiesFile(File jarFileDestination) {
return new File(jarFileDestination.getParentFile(), jarFileDestination.getName().replaceAll("\\.jar$", ".properties"));
}
public static File getBatchScript(File scriptFile) {
return new File(scriptFile.getParentFile(), scriptFile.getName().replaceFirst("(\\.[^\\.]+)?$", ".bat"));
}
public static String getDistributionUrl(GradleVersion gradleVersion, Wrapper.DistributionType distributionType) {
String distType = distributionType.name().toLowerCase(Locale.ENGLISH);
return new DistributionLocator().getDistributionFor(gradleVersion, distType).toASCIIString();
}
public static void generate(
PathBase archiveBase, String archivePath,
PathBase distributionBase, String distributionPath,
@Nullable String distributionSha256Sum,
File wrapperPropertiesOutputFile,
File wrapperJarOutputFile, String jarFileRelativePath,
File unixScript, File batchScript,
@Nullable String distributionUrl,
boolean validateDistributionUrl,
@Nullable Integer networkTimeout
) {
writeProperties(wrapperPropertiesOutputFile, distributionUrl, distributionSha256Sum, distributionBase, distributionPath, archiveBase, archivePath, networkTimeout, validateDistributionUrl);
writeWrapperJar(wrapperJarOutputFile);
writeScripts(jarFileRelativePath, unixScript, batchScript);
}
private static void writeProperties(
File propertiesFileDestination,
@Nullable String distributionUrl,
@Nullable String distributionSha256Sum,
PathBase distributionBase,
String distributionPath,
PathBase archiveBase,
String archivePath,
@Nullable Integer networkTimeout,
boolean validateDistributionUrl
) {
Properties wrapperProperties = new Properties();
wrapperProperties.put(WrapperExecutor.DISTRIBUTION_URL_PROPERTY, distributionUrl);
if (distributionSha256Sum != null) {
wrapperProperties.put(WrapperExecutor.DISTRIBUTION_SHA_256_SUM, distributionSha256Sum);
}
wrapperProperties.put(WrapperExecutor.DISTRIBUTION_BASE_PROPERTY, distributionBase.toString());
wrapperProperties.put(WrapperExecutor.DISTRIBUTION_PATH_PROPERTY, distributionPath);
wrapperProperties.put(WrapperExecutor.ZIP_STORE_BASE_PROPERTY, archiveBase.toString());
wrapperProperties.put(WrapperExecutor.ZIP_STORE_PATH_PROPERTY, archivePath);
if (networkTimeout != null) {
wrapperProperties.put(WrapperExecutor.NETWORK_TIMEOUT_PROPERTY, String.valueOf(networkTimeout));
}
wrapperProperties.put(WrapperExecutor.VALIDATE_DISTRIBUTION_URL, String.valueOf(validateDistributionUrl));
GFileUtils.parentMkdirs(propertiesFileDestination);
try {
PropertiesUtils.store(wrapperProperties, propertiesFileDestination);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private static void writeWrapperJar(File destination) {
URL jarFileSource = Wrapper.class.getResource("/gradle-wrapper.jar");
if (jarFileSource == null) {
throw new GradleException("Cannot locate wrapper JAR resource.");
}
try (InputStream in = jarFileSource.openStream(); OutputStream out = Files.newOutputStream(destination.toPath())) {
ByteStreams.copy(in, out);
} catch (IOException e) {
throw new UncheckedIOException("Failed to write wrapper JAR to " + destination, e);
}
}
private static void writeScripts(String jarFileRelativePath, File unixScript, File batchScript) {
StartScriptGenerator generator = new StartScriptGenerator();
generator.setApplicationName("Gradle");
generator.setMainClassName(GradleWrapperMain.class.getName());
generator.setClasspath(singletonList(jarFileRelativePath));
generator.setOptsEnvironmentVar("GRADLE_OPTS");
generator.setExitEnvironmentVar("GRADLE_EXIT_CONSOLE");
generator.setAppNameSystemProperty("org.gradle.appname");
generator.setScriptRelPath(unixScript.getName());
generator.setDefaultJvmOpts(ImmutableList.of("-Xmx64m", "-Xms64m"));
generator.generateUnixScript(unixScript);
generator.generateWindowsScript(batchScript);
}
}