diff --git a/app/src/main/assets/data/common/tooling-api-all.jar b/app/src/main/assets/data/common/tooling-api-all.jar index 876d7500b..ef347c45f 100644 Binary files a/app/src/main/assets/data/common/tooling-api-all.jar and b/app/src/main/assets/data/common/tooling-api-all.jar differ diff --git a/build-tools/tooling-api-impl/build.gradle b/build-tools/tooling-api-impl/build.gradle index 6bf937672..5949f68eb 100644 --- a/build-tools/tooling-api-impl/build.gradle +++ b/build-tools/tooling-api-impl/build.gradle @@ -86,13 +86,4 @@ compileTestKotlin { kotlinOptions { jvmTarget = "11" } -} - -test { - doFirst { - systemProperty "test.android.home", System.getenv ("ANDROID_HOME") -// jvmArgs '--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED' - } - - println jvmArgs } \ No newline at end of file diff --git a/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/Main.java b/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/Main.java index cd9a61f34..cead3b9cd 100644 --- a/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/Main.java +++ b/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/Main.java @@ -37,7 +37,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; public class Main { - public static final String SUPPORTED_AGP_VERSION = "@AGP_VERSION@"; + public static final String MIN_SUPPORTED_AGP_VERSION = "@AGP_VERSION@"; private static final ILogger LOG = newInstance("ToolingApiMain"); public static IToolingApiClient client; public static Future future; diff --git a/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java b/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java index 46cf8e2fe..a72546723 100644 --- a/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java +++ b/build-tools/tooling-api-impl/src/main/java/com/itsaky/androidide/tooling/impl/util/ProjectReader.java @@ -199,13 +199,14 @@ public class ProjectReader { return null; } - if (!versions.getAgp().equals(Main.SUPPORTED_AGP_VERSION)) { + if (versions.getAgp().compareTo(Main.MIN_SUPPORTED_AGP_VERSION) < 0) { throw new UnsupportedOperationException( "Android Gradle Plugin version " + versions.getAgp() - + " is not supported by AndroidIDE. Please use version " - + Main.SUPPORTED_AGP_VERSION - + " to build this project."); + + " is not supported by AndroidIDE. " + + "Please update your project to use at least v" + + Main.MIN_SUPPORTED_AGP_VERSION + + " of Android Gradle Plugin to build this project."); } final var basicAndroid = controller.findModel(gradle, BasicAndroidProject.class); @@ -213,7 +214,7 @@ public class ProjectReader { System.err.println("Fetching project model..."); final var android = controller.findModel(gradle, AndroidProject.class); final var module = buildAndroidModuleProject(gradle, android, basicAndroid.getProjectType()); - module.setBootClassPaths (basicAndroid.getBootClasspath()); + module.setBootClassPaths(basicAndroid.getBootClasspath()); module.setMainSourceSet( basicAndroid.getMainSourceSet() == null ? null diff --git a/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt b/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt index cd06999ae..735bf5bf1 100644 --- a/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt +++ b/build-tools/tooling-api-impl/src/test/java/com/itsaky/androidide/tooling/impl/ToolingApiImplTest.kt @@ -46,136 +46,153 @@ import org.junit.runners.JUnit4 @RunWith(JUnit4::class) class ToolingApiImplTest { + private val log = ILogger.newInstance(javaClass.simpleName) + + @Test + fun testProjectInit() { + val client = TestClient() + val (server, project) = launchServer(client) + + server.initialize(InitializeProjectMessage(getTestProject().absolutePath)).get() + + verifyProjectProps(project, server) + } + + private fun verifyProjectProps(project: IProject, server: IToolingApiServer) { + assertThat(project).isNotNull() + assertThat(project.type.get()).isEqualTo(IProject.Type.Gradle) + // As the returned project is just a proxy, + // project instanceOf IdeGradleProject will always return false + + val isInitialized = server.isServerInitialized().get() + assertThat(isInitialized).isTrue() + + val app = project.findByPath(":app").get() + assertThat(app).isNotNull() + assertThat(app).isInstanceOf(IdeAndroidModule::class.java) + + assertThat((app as IdeAndroidModule).javaCompileOptions).isNotNull() + assertThat(app.javaCompileOptions.sourceCompatibility).isEqualTo("11") + assertThat(app.javaCompileOptions.targetCompatibility).isEqualTo("11") + assertThat(app.javaCompileOptions.isCoreLibraryDesugaringEnabled).isFalse() + + assertThat(app.projectType).isEqualTo(APPLICATION) + assertThat(app.packageName).isEqualTo("com.itsaky.test.app") + + assertThat(app.viewBindingOptions).isNotNull() + assertThat(app.viewBindingOptions!!.isEnabled).isTrue() + + // There are always more than 100 tasks in an android module + // Also, the tasks must contain the user defined tasks + assertThat(app.tasks.size).isAtLeast(100) + assertThat(app.tasks.first { it.path == "${app.projectPath}:thisIsATestTask" }).isNotNull() + + // This is not expected to be filled. Instead debugLibraries must be filled + @Suppress("DEPRECATION") assertThat(app.variantDependencies).isEmpty() + + assertThat(app.debugLibraries).isNotEmpty() + // At least one project library + assertThat(app.debugLibraries.filter { it.type == PROJECT }).isNotEmpty() + + val javaLibrary = project.findByPath(":java-library").get() + assertThat(javaLibrary).isNotNull() + assertThat(javaLibrary).isInstanceOf(IdeJavaModule::class.java) + + assertThat(project.findByPath(":does-not-exist").get()).isNull() + } + + private fun launchServer(client: IToolingApiClient): Pair { + val builder = + ProcessBuilder( + "java", + "--add-opens", + "java.base/java.lang=ALL-UNNAMED", + "--add-opens", + "java.base/java.util=ALL-UNNAMED", + "--add-opens", + "java.base/java.io=ALL-UNNAMED", + "-jar", + "./build/libs/tooling-api-all.jar" + ) + val androidHome = findAndroidHome() + println("ANDROID_HOME=$androidHome") + builder.environment()["ANDROID_SDK_ROOT"] = androidHome + builder.environment()["ANDROID_HOME"] = androidHome + val proc = builder.start() + + Thread(Reader(proc.errorStream)).start() + val launcher = ToolingApiLauncher.newClientLauncher(client, proc.inputStream, proc.outputStream) + + launcher.startListening() + + return launcher.remoteProxy as IToolingApiServer to launcher.remoteProxy as IProject + } + + private fun findAndroidHome(): String { + var androidHome = System.getenv("ANDROID_HOME") + if (androidHome != null && androidHome.isNotBlank()) { + return androidHome + } + + androidHome = System.getenv("ANDROID_SDK_ROOT") + if (androidHome != null && androidHome.isNotBlank()) { + return androidHome + } + + val os = System.getProperty("os.name") + val home = System.getProperty("user.home") + return if (os.contains("Linux")) { + "$home/Android/Sdk" + } else { + "$home\\AppData\\Local\\Android\\Sdk" + } + } + + private class TestClient : IToolingApiClient { private val log = ILogger.newInstance(javaClass.simpleName) - - @Test - fun testProjectInit() { - val client = TestClient() - val (server, project) = launchServer(client) - - server.initialize(InitializeProjectMessage(getTestProject().absolutePath)).get() - - verifyProjectProps(project, server) + override fun logMessage(line: LogLine) { + log.log(line.priority, line.formattedTagAndMessage()) } - private fun verifyProjectProps(project: IProject, server: IToolingApiServer) { - assertThat(project).isNotNull() - assertThat(project.type.get()).isEqualTo(IProject.Type.Gradle) - // As the returned project is just a proxy, - // project instanceOf IdeGradleProject will always return false - - val isInitialized = server.isServerInitialized().get() - assertThat(isInitialized).isTrue() - - val app = project.findByPath(":app").get() - assertThat(app).isNotNull() - assertThat(app).isInstanceOf(IdeAndroidModule::class.java) - - assertThat((app as IdeAndroidModule).javaCompileOptions).isNotNull() - assertThat(app.javaCompileOptions.sourceCompatibility).isEqualTo("11") - assertThat(app.javaCompileOptions.targetCompatibility).isEqualTo("11") - assertThat(app.javaCompileOptions.isCoreLibraryDesugaringEnabled).isFalse() - - assertThat(app.projectType).isEqualTo(APPLICATION) - assertThat(app.packageName).isEqualTo("com.itsaky.test.app") - - assertThat(app.viewBindingOptions).isNotNull() - assertThat(app.viewBindingOptions!!.isEnabled).isTrue() - - // There are always more than 100 tasks in an android module - // Also, the tasks must contain the user defined tasks - assertThat(app.tasks.size).isAtLeast(100) - assertThat(app.tasks.first { it.path == "${app.projectPath}:thisIsATestTask" }).isNotNull() - - // This is not expected to be filled. Instead debugLibraries must be filled - @Suppress("DEPRECATION") assertThat(app.variantDependencies).isEmpty() - - assertThat(app.debugLibraries).isNotEmpty() - // At least one project library - assertThat(app.debugLibraries.filter { it.type == PROJECT }).isNotEmpty() - - val javaLibrary = project.findByPath(":java-library").get() - assertThat(javaLibrary).isNotNull() - assertThat(javaLibrary).isInstanceOf(IdeJavaModule::class.java) - - assertThat(project.findByPath(":does-not-exist").get()).isNull() + override fun logOutput(line: String) { + log.debug(line.trim()) } - private fun launchServer(client: IToolingApiClient): Pair { - val builder = - ProcessBuilder( - "java", - "--add-opens", - "java.base/java.lang=ALL-UNNAMED", - "--add-opens", - "java.base/java.util=ALL-UNNAMED", - "--add-opens", - "java.base/java.io=ALL-UNNAMED", - "-jar", - "./build/libs/tooling-api-all.jar") - val androidHome = findAndroidHome() - builder.environment()["ANDROID_SDK_ROOT"] = androidHome - builder.environment()["ANDROID_HOME"] = androidHome - val proc = builder.start() + override fun prepareBuild() {} + override fun onBuildSuccessful(result: BuildResult) {} + override fun onBuildFailed(result: BuildResult) {} - Thread(Reader(proc.errorStream)).start() - val launcher = - ToolingApiLauncher.newClientLauncher(client, proc.inputStream, proc.outputStream) + override fun onProgressEvent(event: ProgressEvent) {} - launcher.startListening() - - return launcher.remoteProxy as IToolingApiServer to launcher.remoteProxy as IProject + override fun getBuildArguments(): CompletableFuture> { + return CompletableFuture.completedFuture(listOf("--stacktrace", "--info")) } - private fun findAndroidHome(): String { - return System.getProperty("test.android.home") - } + override fun checkGradleWrapperAvailability(): CompletableFuture = + CompletableFuture.completedFuture(GradleWrapperCheckResult(true)) + } - private class TestClient : IToolingApiClient { - private val log = ILogger.newInstance(javaClass.simpleName) - override fun logMessage(line: LogLine) { - log.log(line.priority, line.formattedTagAndMessage()) + private class Reader(val input: InputStream) : Runnable { + private val log = ILogger.newInstance(javaClass.simpleName) + override fun run() { + try { + val reader = BufferedReader(InputStreamReader(input)) + var line = reader.readLine() + while (line != null) { + log.debug(line) + line = reader.readLine() } - - override fun logOutput(line: String) { - log.debug(line.trim()) - } - - override fun prepareBuild() {} - override fun onBuildSuccessful(result: BuildResult) {} - override fun onBuildFailed(result: BuildResult) {} - - override fun onProgressEvent(event: ProgressEvent) {} - - override fun getBuildArguments(): CompletableFuture> { - return CompletableFuture.completedFuture(emptyList()) - } - - override fun checkGradleWrapperAvailability(): CompletableFuture = - CompletableFuture.completedFuture(GradleWrapperCheckResult(true)) + } catch (error: Throwable) { + log.error(error) + } } + } - private class Reader(val input: InputStream) : Runnable { - private val log = ILogger.newInstance(javaClass.simpleName) - override fun run() { - try { - val reader = BufferedReader(InputStreamReader(input)) - var line = reader.readLine() - while (line != null) { - log.debug(line) - line = reader.readLine() - } - } catch (error: Throwable) { - log.error(error) - } - } - } + fun Any.getTestProject(): File = File("./src/test/test-project") - fun Any.getTestProject(): File = File("./src/test/test-project") - - fun Any.asJson(): String { - val builder = GsonBuilder() - ToolingApiLauncher.configureGson(builder) - return builder.create().toJson(this) - } + fun Any.asJson(): String { + val builder = GsonBuilder() + ToolingApiLauncher.configureGson(builder) + return builder.create().toJson(this) + } } diff --git a/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar b/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar index d4dd7187d..6390b993a 100644 Binary files a/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar and b/build-tools/tooling-api-impl/src/test/test-home/.androidide/init/model.jar differ diff --git a/build-tools/tooling-api-impl/src/test/test-project/build.gradle b/build-tools/tooling-api-impl/src/test/test-project/build.gradle index 2915e4b8c..84d631988 100644 --- a/build-tools/tooling-api-impl/src/test/test-project/build.gradle +++ b/build-tools/tooling-api-impl/src/test/test-project/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - build_gradle_version = '7.2.0' + build_gradle_version = '7.4.0-alpha05' } project.ext { @@ -14,10 +14,6 @@ buildscript { } repositories { - maven { url 'https://maven.aliyun.com/repository/public/' } - maven { url 'https://maven.aliyun.com/repository/google/' } - maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' } - maven { url "https://clojars.org/repo/" } google() mavenLocal() mavenCentral() @@ -29,10 +25,6 @@ buildscript { } allprojects { repositories { - maven { url 'https://maven.aliyun.com/repository/public/' } - maven { url 'https://maven.aliyun.com/repository/google/' } - maven { url 'https://maven.aliyun.com/repository/gradle-plugin/' } - maven { url "https://clojars.org/repo/" } mavenLocal() mavenCentral() google() diff --git a/build-tools/tooling-api-impl/src/test/test-project/gradle/wrapper/gradle-wrapper.properties b/build-tools/tooling-api-impl/src/test/test-project/gradle/wrapper/gradle-wrapper.properties index 863880123..cee90b37d 100644 --- a/build-tools/tooling-api-impl/src/test/test-project/gradle/wrapper/gradle-wrapper.properties +++ b/build-tools/tooling-api-impl/src/test/test-project/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-rc-1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/build-tools/tooling-api-impl/src/test/test-project/gradlew b/build-tools/tooling-api-impl/src/test/test-project/gradlew old mode 100644 new mode 100755