Added option to specify custom Gradle installation directory for builds (closes #49)

This commit is contained in:
Akash Yadav
2022-06-17 15:26:57 +05:30
parent fbe077fd63
commit 222fa49ee1
10 changed files with 123 additions and 15 deletions
+3
View File
@@ -141,7 +141,10 @@
<entry key="..\:/Users/Akash Yadav/AndroidStudioProjects/android-ide/app/src/main/res/layout/layout_widget_item.xml" value="0.264" />
<entry key="..\:/Users/Akash Yadav/AndroidStudioProjects/android-ide/app/src/main/res/menu/menu_designer_widgets.xml" value="0.20854700854700856" />
<entry key="..\:/itsaky/.gradle/caches/transforms-3/e4862cae80f8754ca1a451ad3e00b14c/transformed/jetified-editor-0.10.11/res/drawable/round_select_all_20.xml" value="0.1305" />
<entry key="app/src/main/res/drawable/ic_gradle.xml" value="0.3265" />
<entry key="app/src/main/res/drawable/ic_language_gradle.xml" value="0.3265" />
<entry key="app/src/main/res/layout/activity_download.xml" value="0.35572916666666665" />
<entry key="app/src/main/res/layout/layout_dialog_text_input.xml" value="0.35572916666666665" />
</map>
</option>
</component>
Binary file not shown.
@@ -30,18 +30,24 @@ import com.blankj.utilcode.util.FileUtils;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.itsaky.androidide.R;
import com.itsaky.androidide.app.BaseApplication;
import com.itsaky.androidide.databinding.LayoutDialogTextInputBinding;
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
import com.itsaky.androidide.tasks.TaskExecutor;
import com.itsaky.androidide.utils.DialogUtils;
import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.ILogger;
import java.io.File;
import java.util.Objects;
public class BuildPreferences extends BasePreferenceFragment
implements Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener {
public static final String KEY_GRADLE_COMMANDS = "idepref_build_gradleCommands";
public static final String KEY_GRADLE_CLEAR_CACHE = "idepref_build_gradleClearCache";
public static final String KEY_CUSTOM_GRADLE_INSTALLATION =
"idepref_build_customGradleInstallation";
private static final ILogger LOG = ILogger.newInstance("BuildPreferences");
private ProgressSheet progressSheet;
@@ -52,6 +58,7 @@ public class BuildPreferences extends BasePreferenceFragment
final var screen = getPreferenceScreen();
final var categoryGradle = new PreferenceCategory(getContext());
final var customCommands = new Preference(getContext());
final var customInstallation = new Preference(getContext());
final var clearCache = new Preference(getContext());
screen.addPreference(categoryGradle);
@@ -61,6 +68,11 @@ public class BuildPreferences extends BasePreferenceFragment
customCommands.setTitle(R.string.idepref_build_customgradlecommands_title);
customCommands.setSummary(R.string.idepref_build_customgradlecommands_summary);
customInstallation.setKey(KEY_CUSTOM_GRADLE_INSTALLATION);
customInstallation.setIcon(R.drawable.ic_gradle);
customInstallation.setTitle(getString(R.string.idepref_title_customGradleInstallation));
customInstallation.setSummary(getString(R.string.idepref_msg_customGradleInstallation));
clearCache.setKey(KEY_GRADLE_CLEAR_CACHE);
clearCache.setIcon(R.drawable.ic_delete);
clearCache.setTitle(R.string.idepref_build_clearCache_title);
@@ -68,6 +80,7 @@ public class BuildPreferences extends BasePreferenceFragment
categoryGradle.setTitle(R.string.gradle);
categoryGradle.addPreference(customCommands);
categoryGradle.addPreference(customInstallation);
categoryGradle.addPreference(clearCache);
// Works only for Android 11
@@ -86,16 +99,23 @@ public class BuildPreferences extends BasePreferenceFragment
setPreferenceScreen(screen);
customCommands.setOnPreferenceClickListener(this);
customInstallation.setOnPreferenceClickListener(this);
clearCache.setOnPreferenceClickListener(this);
}
@Override
public boolean onPreferenceClick(Preference p1) {
final String key = p1.getKey();
if (key.equals(KEY_GRADLE_COMMANDS)) {
showGradleCommandsDialog();
} else if (key.equals(KEY_GRADLE_CLEAR_CACHE)) {
showClearCacheDialog();
switch (key) {
case KEY_GRADLE_COMMANDS:
showGradleCommandsDialog();
break;
case KEY_GRADLE_CLEAR_CACHE:
showClearCacheDialog();
break;
case KEY_CUSTOM_GRADLE_INSTALLATION:
changeGradleDist();
break;
}
return true;
}
@@ -106,10 +126,33 @@ public class BuildPreferences extends BasePreferenceFragment
if (KEY_TP_FIX.equals(key)) {
getPrefManager().putBoolean(KEY_TP_FIX, ((boolean) newValue));
}
return true;
}
private void changeGradleDist() {
final var builder = DialogUtils.newMaterialDialogBuilder(getContext());
final var binding = LayoutDialogTextInputBinding.inflate(getLayoutInflater());
binding.name.setStartIconDrawable(R.drawable.ic_gradle);
binding.name.setHint(R.string.msg_gradle_installation_path);
binding.name.setHelperText(getString(R.string.msg_gradle_installation_input_help));
binding.name.setCounterEnabled(false);
Objects.requireNonNull(binding.name.getEditText())
.setText(getPrefManager().getString(KEY_CUSTOM_GRADLE_INSTALLATION, ""));
builder
.setTitle(R.string.idepref_title_customGradleInstallation)
.setView(binding.getRoot())
.setPositiveButton(
android.R.string.ok,
(dialogInterface, i) -> {
final var path =
Objects.requireNonNull(binding.name.getEditText()).getText().toString().trim();
getPrefManager().putString(KEY_CUSTOM_GRADLE_INSTALLATION, path);
})
.setNegativeButton(
android.R.string.cancel, (dialogInterface, i) -> dialogInterface.dismiss())
.show();
}
private void showGradleCommandsDialog() {
final String[] labels = {
"--stacktrace",
@@ -40,11 +40,13 @@ import com.itsaky.androidide.BuildConfig;
import com.itsaky.androidide.R;
import com.itsaky.androidide.app.BaseApplication;
import com.itsaky.androidide.app.StudioApp;
import com.itsaky.androidide.fragments.preferences.BuildPreferences;
import com.itsaky.androidide.managers.PreferenceManager;
import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.projects.ProjectManager;
import com.itsaky.androidide.shell.CommonProcessExecutor;
import com.itsaky.androidide.shell.ProcessStreamsHolder;
import com.itsaky.androidide.tooling.api.IProject;
import com.itsaky.androidide.tooling.api.IToolingApiClient;
import com.itsaky.androidide.tooling.api.IToolingApiServer;
import com.itsaky.androidide.tooling.api.messages.InitializeProjectMessage;
@@ -54,7 +56,6 @@ import com.itsaky.androidide.tooling.api.messages.result.BuildResult;
import com.itsaky.androidide.tooling.api.messages.result.GradleWrapperCheckResult;
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult;
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult;
import com.itsaky.androidide.tooling.api.IProject;
import com.itsaky.androidide.tooling.api.util.ToolingApiLauncher;
import com.itsaky.androidide.tooling.events.ProgressEvent;
import com.itsaky.androidide.utils.Environment;
@@ -298,7 +299,7 @@ public class GradleBuildService extends Service implements BuildService, IToolin
isBuildInProgress = true;
return server
.initialize(new InitializeProjectMessage(rootDir))
.initialize(new InitializeProjectMessage(rootDir, getGradleInstallationPath()))
.thenApply(this::markBuildAsFinished);
}
@@ -315,10 +316,14 @@ public class GradleBuildService extends Service implements BuildService, IToolin
isBuildInProgress = true;
return server
.executeTasks(new TaskExecutionMessage(":", Arrays.asList(tasks)))
.executeTasks(new TaskExecutionMessage(":", Arrays.asList(tasks), getGradleInstallationPath()))
.thenApply(this::markBuildAsFinished);
}
private String getGradleInstallationPath() {
return StudioApp.getInstance().getPrefManager().getString(BuildPreferences.KEY_CUSTOM_GRADLE_INSTALLATION, "");
}
@NonNull
@Override
public CompletableFuture<TaskExecutionResult> executeProjectTasks(
@@ -333,7 +338,7 @@ public class GradleBuildService extends Service implements BuildService, IToolin
isBuildInProgress = true;
return server
.executeTasks(new TaskExecutionMessage(projectPath, Arrays.asList(tasks)))
.executeTasks(new TaskExecutionMessage(projectPath, Arrays.asList(tasks), getGradleInstallationPath()))
.thenApply(this::markBuildAsFinished);
}
@@ -393,27 +398,33 @@ public class GradleBuildService extends Service implements BuildService, IToolin
return null;
}
return new EventListener() {
return new EventListener() {
@SuppressWarnings("ConstantConditions")
@Override
public void prepareBuild() {
ThreadUtils.runOnUiThread(listener::prepareBuild);
}
@SuppressWarnings("ConstantConditions")
@Override
public void onBuildSuccessful(@NonNull List<String> tasks) {
ThreadUtils.runOnUiThread(() -> listener.onBuildSuccessful(tasks));
}
@SuppressWarnings("ConstantConditions")
@Override
public void onProgressEvent(@NonNull ProgressEvent event) {
ThreadUtils.runOnUiThread(() -> listener.onProgressEvent(event));
}
@SuppressWarnings("ConstantConditions")
@Override
public void onBuildFailed(@NonNull List<String> tasks) {
ThreadUtils.runOnUiThread(() -> listener.onBuildFailed(tasks));
}
@SuppressWarnings("ConstantConditions")
@Override
public void onOutput(String line) {
ThreadUtils.runOnUiThread(() -> listener.onOutput(line));
+25
View File
@@ -0,0 +1,25 @@
<!--
~ 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/>.
-->
<vector android:height="24dp" android:viewportHeight="64"
android:viewportWidth="64" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#fff" android:fillType="evenOdd" android:pathData="M62.848,28.42c1.429,-3.342 1.403,-6.614 0.513,-9.218C62.278,15.997 57.831,11.805 56.404,13.465c-0.185,0.231 -2.743,-0.068 -3.157,0.484 -0.599,0.804 -0.253,1.061 0.046,1.335 0.898,0.804 3.203,1.682 4.216,4.401 0.438,1.152 1.451,3.85 -0.299,5.462 -2.005,1.821 -4.24,2.235 -13.412,-6.29 -9.753,-9.103 -22.905,-5.39 -27.238,-3.963 -4.355,1.451 -6.336,2.88 -4.632,6.246 2.327,4.562 1.567,3.157 3.824,6.913 3.593,5.989 11.453,-2.765 11.453,-2.765 -5.852,8.826 -10.876,6.682 -12.811,3.617 -1.711,-2.789 -3.089,-5.989 -3.089,-5.989C-3.517,28.283 0.493,51.897 0.493,51.897l7.358,0c1.889,-8.687 8.595,-8.364 9.747,0l5.623,0c4.962,-16.983 15.6,0 15.6,0l6.331,0c0,-9.055 -0.945,-12.466 3.688,-13.09 7.928,-1.083 11.613,-4.791 14.011,-10.369z"/>
<path android:fillColor="#fff" android:fillType="evenOdd" android:pathData="M63.978,22.269a23.015,23.015 0,0 0,-3.963 0.691c-0.046,0.046 -0.068,0.092 -0.115,0.161 -0.577,0.645 -1.29,1.29 -2.122,1.636a2.105,2.105 0,0 1,-0.323 0.161c-0.068,0.068 -0.137,0.161 -0.231,0.231 -2.005,1.821 -4.425,2.235 -13.412,-6.29 -9.678,-9.172 -22.881,-5.37 -27.238,-3.941s-6.336,2.858 -4.632,6.222c2.327,4.562 1.567,3.157 3.824,6.913 3.593,5.989 11.453,-2.765 11.453,-2.765 -5.852,8.826 -10.876,6.682 -12.811,3.617 -1.711,-2.789 -3.089,-5.989 -3.089,-5.989C-3.517,28.283 0.493,51.897 0.493,51.897l7.358,0c1.889,-8.687 8.595,-8.364 9.747,0l5.623,0c4.962,-16.983 15.6,0 15.6,0l6.331,0c0,-9.055 -0.945,-12.466 3.688,-13.09 7.905,-1.083 11.591,-4.771 13.987,-10.369 0.945,-2.142 1.266,-4.24 1.152,-6.153z"/>
<path android:fillColor="#000" android:fillType="evenOdd" android:pathData="M37.201,24.643l7.973,2.65c-0.253,1.221 -2.535,3.572 -5.484,2.581 -3.871,-1.29 -2.489,-5.231 -2.489,-5.231z"/>
<path android:fillColor="#fff" android:fillType="evenOdd" android:pathData="M39.056,27.324a1.982,2.051 83.938,1 0,4.079 -0.433a1.982,2.051 83.938,1 0,-4.079 0.433z"/>
<path android:fillColor="#fff" android:fillType="evenOdd" android:pathData="M53.324,15.287c0.253,0.231 0.577,0.438 0.898,0.645 1.543,-1.266 3.525,-1.244 5.185,-1.934 -1.497,-1.383 -3.85,-2.442 -4.608,-1.543 -0.185,0.231 -1.105,0.945 -1.54,1.497 -0.599,0.804 -0.253,1.061 0.046,1.335z"/>
</vector>
+4
View File
@@ -383,4 +383,8 @@
<string name="idepref_title_tpFix">JDK 11 tag pointers fix</string>
<string name="idepref_msg_tpFix">Set LD_PRELOAD to libhook.so to fix tag pointers issue for JDK 11 in Android 11 [DEPRECATED - Prefer using JDK 17].</string>
<string name="idepref_title_customGradleInstallation">Custom Gradle installation</string>
<string name="idepref_msg_customGradleInstallation">Specify a custom Gradle installation to use for build. This OVERRIDES the version specified in gradle-wrapper.properties.</string>
<string name="msg_gradle_installation_path">Gradle installation path</string>
<string name="msg_gradle_installation_input_help">Leave empty to use Gradle wrapper.</string>
</resources>
@@ -43,8 +43,6 @@ import com.itsaky.androidide.tooling.impl.progress.ForwardingProgressListener
import com.itsaky.androidide.tooling.impl.util.ProjectReader
import com.itsaky.androidide.tooling.impl.util.StopWatch
import com.itsaky.androidide.utils.ILogger
import java.io.File
import java.util.concurrent.*
import org.eclipse.lsp4j.jsonrpc.CompletableFutures
import org.gradle.tooling.BuildCancelledException
import org.gradle.tooling.BuildException
@@ -54,6 +52,8 @@ import org.gradle.tooling.GradleConnector
import org.gradle.tooling.UnsupportedVersionException
import org.gradle.tooling.exceptions.UnsupportedBuildArgumentException
import org.gradle.tooling.exceptions.UnsupportedOperationConfigurationException
import java.io.File
import java.util.concurrent.*
/**
* Implementation for the Gradle Tooling API server.
@@ -92,6 +92,7 @@ internal class ToolingApiServerImpl(private val forwardingProject: InternalForwa
val stopWatch = StopWatch("Connection to project")
this.connector =
GradleConnector.newConnector().forProjectDirectory(File(params.directory))
setupConnectorForGradleInstallation(this.connector!!, params.gradleInstallation)
stopWatch.lap("Connector created")
if (this.connector == null) {
@@ -153,7 +154,10 @@ internal class ToolingApiServerImpl(private val forwardingProject: InternalForwa
this.project!!.findByPath(projectPath).get()
?: return@computeAsync TaskExecutionResult(false, PROJECT_NOT_FOUND)
val connection = this.connector!!.forProjectDirectory(project.projectDir).connect()
this.connector!!.forProjectDirectory(project.projectDir)
setupConnectorForGradleInstallation(this.connector!!, message.gradleInstallation)
val connection = this.connector!!.connect()
val builder = connection.newBuild()
builder.addProgressListener(ForwardingProgressListener())
@@ -183,6 +187,23 @@ internal class ToolingApiServerImpl(private val forwardingProject: InternalForwa
}
}
private fun setupConnectorForGradleInstallation(
connector: GradleConnector,
gradleDistribution: String?
) {
if (gradleDistribution != null && gradleDistribution.isNotBlank()) {
val file = File(gradleDistribution)
if (file.exists() && file.isDirectory) {
log.info("Using Gradle installation:", file.canonicalPath)
connector.useInstallation(file)
} else {
log.error("Specified Gradle installation does not exist:", gradleDistribution)
}
} else {
log.info("Using Gradle wrapper for build...")
}
}
private fun notifyBuildFailure(tasks: List<String>) {
if (client != null) {
client!!.onBuildFailed(BuildResult((tasks)))
@@ -22,4 +22,4 @@ package com.itsaky.androidide.tooling.api.messages
*
* @author Akash Yadav
*/
data class InitializeProjectMessage(val directory: String)
data class InitializeProjectMessage(val directory: String, val gradleInstallation: String = "")
@@ -23,5 +23,6 @@ package com.itsaky.androidide.tooling.api.messages
*/
data class TaskExecutionMessage(
val projectPath: String?,
val tasks: List<String>
val tasks: List<String>,
val gradleInstallation: String = ""
)