override def actionPerformed()

in sbt/sbt-impl/src/org/jetbrains/sbt/actions/SbtGenerateManagedSourcesAction.scala [30:199]


  override def actionPerformed(e: AnActionEvent): Unit = {
    val project = e.getProject

    val task = new Task.Backgroundable(project, SbtBundle.message("sbt.generate.managed.sources.task.progress.title"), true) {
      override def run(indicator: ProgressIndicator): Unit = {
        val viewManager = project.getService(classOf[SyncViewManager])
        val taskId = ExternalSystemTaskId.create(SbtProjectSystem.Id, ExternalSystemTaskType.EXECUTE_TASK, project)
        val reporter = new GenerateManagedSourcesReporter()

        val settings = SbtExternalSystemManager.executionSettingsFor(project)
        val projectBasePath = Path.of(settings.realProjectPath)

        val descriptor = new DefaultBuildDescriptor(taskId, SbtBundle.message("sbt.generate.managed.sources.action.title"), projectBasePath.toString, System.currentTimeMillis())
        descriptor.setActivateToolWindowWhenAdded(false)
        descriptor.setActivateToolWindowWhenFailed(true)

        {
          val event = BuildEvents.getInstance().startBuild()
            .withBuildDescriptor(descriptor)
            .withMessage(SbtBundle.message("sbt.generate.managed.sources.action.title"))
            .build()
          viewManager.onEvent(taskId, event)
        }

        def reportFailure(@Nullable throwable: Throwable): Unit = {
          {
            val sbtOutput = reporter.outputLines.mkString(start = "", sep = System.lineSeparator(), end = System.lineSeparator())
            val event = BuildEvents.getInstance().output()
              .withId(taskId)
              .withMessage(sbtOutput)
              .withOutputType(ProcessOutputType.STDOUT)
              .build()
            viewManager.onEvent(taskId, event)
          }
          {
            val failureWord = SbtBundle.message("sbt.generate.managed.sources.task.result.failure")
            val failureMessage = SbtBundle.message("sbt.generate.managed.sources.task.result.failure.message")
            val failureResult = new FailureResultImpl(failureMessage, throwable)
            val events = BuildEvents.getInstance().finishBuild()
              .withStartBuildId(taskId)
              .withTime(System.currentTimeMillis())
              .withMessage(failureWord)
              .withResult(failureResult)
              .build()
            viewManager.onEvent(taskId, events)
          }
        }

        try {
          val launcher = SbtUtil.getLauncherJar(settings)

          val sbtVersion = SbtUtil.detectSbtVersion(projectBasePath, launcher)
          val sbtStructurePluginBinVersion = SbtUtil.structurePluginBinaryVersion(sbtVersion)
          val addPluginCommandSupported = SbtVersionCapabilities.isAddPluginCommandSupported(sbtVersion)

          if (!addPluginCommandSupported) {
            val notSupportedWord = SbtBundle.message("sbt.generate.managed.sources.action.not.supported")
            val notSupportedMessage = SbtBundle.message("sbt.generate.managed.sources.action.not.supported.message", sbtVersion.minor)
            val failureResult = new FailureResultImpl(notSupportedMessage)
            val finishEvent = BuildEvents.getInstance().finishBuild()
              .withStartBuildId(taskId)
              .withTime(System.currentTimeMillis())
              .withMessage(notSupportedWord)
              .withResult(failureResult)
              .build()
            viewManager.onEvent(taskId, finishEvent)
            return
          }

          val repoPath = SbtUtil.normalizePath(SbtUtil.getRepoDir)
          val pluginsSbt =
            raw"""resolvers += MavenCache("Scala Plugin Bundled Repository", file(raw"$repoPath"))
                 |
                 |addSbtPlugin("org.jetbrains.scala" % "sbt-structure-extractor" % "${BuildInfo.sbtStructureVersion}", "$sbtStructurePluginBinVersion")
                 |""".stripMargin

          val tmpPluginsSbtFile = Files.createTempFile("idea-gen-managed-sources", ".sbt")
          Files.writeString(tmpPluginsSbtFile, pluginsSbt)
          val setupOptions = Seq(s"-addPluginSbtFile=${tmpPluginsSbtFile.toRealPath()}")
          tmpPluginsSbtFile.toFile.deleteOnExit()

          val generateCommand = "show " + SbtUtil.sbtStructureGlobalCommand("ideaGenerateAllManagedSources", sbtVersion)
          val sbtResult = new SbtStructureDump().runSbt(
            indicator,
            projectBasePath,
            settings.vmExecutable.toPath,
            settings.vmOptions,
            settings.userSetEnvironment,
            launcher,
            settings.sbtOptions,
            setupOptions,
            generateCommand,
            SbtBundle.message("sbt.generate.managed.sources.task.progress.title"),
            settings.passParentEnvironment,
          )(using reporter)

          sbtResult match {
            case Success(buildMessages) if buildMessages.status == BuildMessages.Error => reportFailure(null)

            case Success(buildMessages) if buildMessages.status == BuildMessages.Canceled =>
              {
                val canceledMessage = SbtBundle.message("sbt.generate.managed.sources.task.result.canceled.message")
                val event = BuildEvents.getInstance().output()
                  .withId(taskId)
                  .withMessage(canceledMessage)
                  .withOutputType(ProcessOutputType.STDOUT)
                  .build()
                viewManager.onEvent(taskId, event)
              }
              {
                val canceledWord = SbtBundle.message("sbt.generate.managed.sources.task.result.canceled")
                val finishEvent = BuildEvents.getInstance().finishBuild()
                  .withStartBuildId(taskId)
                  .withTime(System.currentTimeMillis())
                  .withMessage(canceledWord)
                  .withResult(new SkippedResultImpl())
                  .build()
                viewManager.onEvent(taskId, finishEvent)
              }

            case Success(_) =>
              val lines = reporter.outputLines
              val containsErrors = lines.exists(_.startsWith("[error]"))

              if (containsErrors) {
                reportFailure(null)
              } else {
                try {
                  def realFile(path: Path): Boolean = Files.exists(path) && Files.isRegularFile(path)
                  val generatedSources = lines.collect { case s"[info] * $path" => path }
                    .flatMap(path => Try(Path.of(path).toRealPath()).filter(realFile).toOption)
                  val fileManager = VirtualFileManager.getInstance()
                  val virtualFiles = generatedSources.flatMap(p => Option(fileManager.refreshAndFindFileByNioPath(p)))
                  VfsUtil.markDirtyAndRefresh(false, false, true, virtualFiles*)

                  {
                    val output = lines.mkString(start = "", sep = System.lineSeparator(), end = System.lineSeparator())
                    val event = BuildEvents.getInstance().output()
                      .withId(taskId)
                      .withMessage(output)
                      .withOutputType(ProcessOutputType.STDOUT)
                      .build()
                    viewManager.onEvent(taskId, event)
                  }
                  {
                    val successEvent = BuildEvents.getInstance().finishBuild()
                      .withStartBuildId(taskId)
                      .withTime(System.currentTimeMillis())
                      .withMessage(SbtBundle.message("sbt.generate.managed.sources.task.result.success"))
                      .withResult(new SuccessResultImpl())
                      .build()
                    viewManager.onEvent(taskId, successEvent)
                  }
                } catch {
                  case NonFatal(t) => reportFailure(t)
                }
              }

            case Failure(exception) => reportFailure(exception)
          }
        } catch {
          case NonFatal(t) => reportFailure(t)
        }
      }
    }

    // Make sure all modified files are saved to disk before invoking sbt.
    FileDocumentManager.getInstance().saveAllDocuments()
    task.queue()
  }