Automatically Link/Import Gradle Project after unzipping

Hello,

I’m creating a GeneratorNewProjectWizardBuilderAdapter to create project templates in the new Project menu.

Below is my createProject override.

override fun createProject(name: String?, path: String?): Project? {
    return super.createProject(name, path)?.let { project ->
      val rootFile: VirtualFile? = project.guessProjectDir()

      val baseFile = rootFile!!.toIoFile()
      ApplicationManager.getApplication().invokeLater {
        WriteAction.run<Throwable> {
          unzipTemplateFile(
              getTemplateZipFilePath(TemplateType.Starter),
              baseFile,
              wizard.group,
              wizard.artifact)
        }
        openActivityFileAndSync(project, wizard.group, wizard.artifact)
      }

      project
    }
  }

  private fun openActivityFileAndSync(project: Project, group: String, artifact: String) {
    val projectRootPath = project.projectFilePath ?: return
    linkAndRefreshGradleProject(projectRootPath, project)
  }

This is how I am generating files from zip:

private fun unzipTemplateFile(
      resourcePath: String,
      rootFile: File,
      group: String,
      artifact: String
  ) {

    PluginLogger.instance.info(Tag, "Trying Path Resource: $resourcePath")

    val url =
        MyProjectBuilderAdapter::class.java.classLoader?.getResourceAsStream(resourcePath)

    ZipInputStream(url).use { zipInputStream ->
      generateSequence { zipInputStream.nextEntry }
          .filterNot { it.isDirectory }
          .forEach {
            val fileName = processTemplateFileName(it.name, group, artifact)
            val file = File(rootFile, fileName)
            file.parentFile?.mkdirs()
            if (fileName.endsWith(".xml") ||
                fileName.endsWith(".kt") ||
                fileName.endsWith(".kts")) {
              val fileContent =
                  InputStreamReader(zipInputStream, StandardCharsets.UTF_8)
                      .readText()
                      .replace(TEMPLATE_GROUP_NAME, group)
                      .replace(TEMPLATE_ARTIFACT_NAME, artifact)
              file.writeText(fileContent)
            } else {
              val byteArray = zipInputStream.readAllBytes()
              FileOutputStream(file).use { outputStream -> outputStream.write(byteArray) }
            }
          }
    }
  }

1-2 seconds after creating the project with template, I see the link helper.
Clicking this will open the Gradle ToolWindow, and then clicking DownloadSources will initiate the gradle processing of the project.

I had hoped that “linkAndRefreshGradleProject” would be the thing I could use here, but I get the error “Gradle script file ‘~/StudioProjects/untitled39/.idea/misc.xml’ not found”.

How can I link gradle and initiate a sync after pulling files from zip in the invokeLater block?

Gonna reply here for whoever comes after.
There ended up being two fixes.
1.
Replace ApplicationManager.getApplication().invokeLater with EdtInvocationManager.invokeLaterIfNeeded { WriteAction.run<Throwable> {
Reason:
My plugin supports both AS 2024.3 and 2024.1.
On 2024.3 the createProject() function is run on a background thread (BGT)
and on 2024.1 it was run on the main thread (EDT).

On 2024.1, calling invokeLater{} ended up changing the execution order, and the gradle settings files were not added in time for whatever automatic system scans to link the gradle project.

If it is not possible to have the files in time, it seems like
org.jetbrains.plugins.gradle.service.project.open.linkAndRefreshGradleProject()
should have been the solution. But when I ran it on my project I received an error that some .xml file didn’t exist. After digging into the Intellij source code I backed out this code that works to link the gradle project and start a sync.

    ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID)
        .linkProject(
            GradleDefaultProjectSettings.createProjectSettings(
                Paths.get(project.basePath!!).toCanonicalPath()))
    ExternalSystemUtil.refreshProject(
        project,
        GradleConstants.SYSTEM_ID,
        project.basePath!!,
        false,
        ProgressExecutionMode.IN_BACKGROUND_ASYNC)