Skip to content

Commit

Permalink
Implement initial "Run Configurations" support
Browse files Browse the repository at this point in the history
Fix PaddleProjectResolver, WIP with deps
Adjust icons and naming
  • Loading branch information
Oleg Smirnov committed May 24, 2022
1 parent d0006cd commit 42d1580
Show file tree
Hide file tree
Showing 21 changed files with 617 additions and 99 deletions.
2 changes: 1 addition & 1 deletion cli/src/main/kotlin/io/paddle/Application.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class Paddle(private val project: PaddleProject) : CliktCommand() {

current.execute(taskId)
} else {
project.execute(id = taskRoute)
project.execute(taskId = taskRoute)
}
} catch (e: Task.ActException) {
return
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/kotlin/io/paddle/project/PaddleProject.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ class PaddleProject internal constructor(val buildFile: File, val rootDir: File,
plugins.forEach { this.register(it) }
}

fun execute(id: String) {
val task = tasks.get(id) ?: run {
terminal.commands.stderr(CommandOutput.Command.Task(id, CommandOutput.Command.Task.Status.UNKNOWN))
fun execute(taskId: String) {
val task = tasks.get(taskId) ?: run {
terminal.commands.stderr(CommandOutput.Command.Task(taskId, CommandOutput.Command.Task.Status.UNKNOWN))
return
}
task.run()
Expand Down
21 changes: 20 additions & 1 deletion core/src/main/kotlin/io/paddle/project/PaddleProjectProvider.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.paddle.project

import io.paddle.project.extensions.descriptor
import java.io.File

/**
Expand All @@ -13,7 +14,7 @@ import java.io.File
* - There is a possibility to declare configurations for ALL subprojects at a time using `all` descriptor
* 5. Register plugins (extensions & tasks) for each project in the [rootDir]
*/
class PaddleProjectProvider private constructor(private val rootDir: File) {
class PaddleProjectProvider private constructor(val rootDir: File) {
companion object {
private val providersCache = HashMap<File, PaddleProjectProvider>()

Expand All @@ -40,4 +41,22 @@ class PaddleProjectProvider private constructor(private val rootDir: File) {
fun hasProjectsIn(dir: File): Boolean {
return index.hasProjectsIn(dir)
}

/**
* Suppose you have a directory called "example" with Paddle project named "example-paddle",
* and also some Paddle projects within its subdirectory "plugins", which is not a Paddle project itself.
* So the relative path to the plugin "etc" would be "example/plugins/etc",
* but the route (in terms of Paddle) is ":example-paddle:plugins:etc".
*/
fun getRouteToDir(dir: File): List<String> {
var currentDir = dir
val route = ArrayList<String>()
while (currentDir != rootDir) {
getProject(currentDir)
?.let { route.add(it.descriptor.name) }
?: route.add(currentDir.name)
currentDir = currentDir.parentFile
}
return route
}
}
9 changes: 5 additions & 4 deletions idea/src/main/kotlin/io/paddle/idea/PaddleManager.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package io.paddle.idea

import com.intellij.execution.configurations.SimpleJavaParameters
import com.intellij.icons.AllIcons
import com.intellij.openapi.externalSystem.*
import com.intellij.openapi.externalSystem.model.ProjectSystemId
import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver
import com.intellij.openapi.externalSystem.service.project.autoimport.CachingExternalSystemAutoImportAware
import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.externalSystem.util.ExternalSystemConstants
import com.intellij.openapi.fileChooser.FileChooserDescriptor
import com.intellij.openapi.options.Configurable
Expand All @@ -16,9 +16,10 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.Function
import icons.ExternalSystemIcons
import icons.PythonIcons
import io.paddle.idea.execution.PaddleTaskManager
import io.paddle.idea.project.PaddleAutoImportAware
import io.paddle.idea.project.PaddleProjectResolver
import io.paddle.idea.runner.PaddleTaskManager
import io.paddle.idea.settings.*
import io.paddle.idea.utils.isPaddle
import java.io.File
Expand Down Expand Up @@ -90,10 +91,10 @@ class PaddleManager : ExternalSystemManager<
override fun getExternalProjectDescriptor(): FileChooserDescriptor = FILE_CHOOSER_DESCRIPTOR

override fun getProjectRepresentationName(targetProjectPath: String, rootProjectPath: String?): String {
return "Paddle"
return ExternalSystemApiUtil.getProjectRepresentationName(targetProjectPath, rootProjectPath);
}

override fun getProjectIcon(): Icon = AllIcons.Nodes.IdeaProject
override fun getProjectIcon(): Icon = PythonIcons.Python.Python

override fun getTaskIcon(): Icon = ExternalSystemIcons.Task

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.paddle.idea.execution

import com.intellij.execution.configurations.RunConfiguration
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemBeforeRunTask
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemBeforeRunTaskProvider
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import icons.PythonIcons
import io.paddle.idea.PaddleManager
import javax.swing.Icon

class PaddleBeforeRunTaskProvider(project: Project) : ExternalSystemBeforeRunTaskProvider(PaddleManager.ID, project, ID), DumbAware {
companion object {
val ID = Key.create<ExternalSystemBeforeRunTask>("Paddle.BeforeRunTask")
}

override fun getIcon(): Icon {
return PythonIcons.Python.Python
}

override fun getTaskIcon(task: ExternalSystemBeforeRunTask?): Icon {
return PythonIcons.Python.Python
}

override fun createTask(runConfiguration: RunConfiguration): ExternalSystemBeforeRunTask {
return ExternalSystemBeforeRunTask(ID, PaddleManager.ID)
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,31 @@
package io.paddle.idea.runner
package io.paddle.idea.execution

import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.openapi.externalSystem.model.ProjectSystemId
import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemTaskConfigurationType
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
import com.intellij.openapi.project.Project
import io.paddle.idea.PaddleManager

class PaddleTaskConfigurationType : AbstractExternalSystemTaskConfigurationType(PaddleManager.ID) {
override fun getConfigurationFactoryId() = "Paddle"

override fun isDumbAware(): Boolean {
return true
}

override fun isEditableInDumbMode(): Boolean {
return true
class PaddleExternalTaskConfigurationType : AbstractExternalSystemTaskConfigurationType(PaddleManager.ID) {
companion object {
fun getInstance(): PaddleExternalTaskConfigurationType {
return ExternalSystemUtil.findConfigurationType(PaddleManager.ID) as PaddleExternalTaskConfigurationType
}
}

override fun doCreateConfiguration(
externalSystemId: ProjectSystemId,
project: Project,
factory: ConfigurationFactory,
name: String
): ExternalSystemRunConfiguration {
): PaddleRunConfiguration {
return PaddleRunConfiguration(project, factory, name)
}

companion object {
val instance: PaddleTaskConfigurationType
get() = ExternalSystemUtil.findConfigurationType(PaddleManager.ID) as PaddleTaskConfigurationType
}
override fun getConfigurationFactoryId(): String = "Paddle"

override fun isDumbAware(): Boolean = true

override fun isEditableInDumbMode(): Boolean = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package io.paddle.idea.execution

import com.intellij.build.BuildViewManager
import com.intellij.execution.executors.DefaultRunExecutor
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunConfiguration
import com.intellij.openapi.externalSystem.service.execution.ProgressExecutionMode
import com.intellij.openapi.externalSystem.task.TaskCallback
import com.intellij.openapi.externalSystem.util.ExternalSystemUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.UserDataHolderBase
import com.intellij.task.*
import io.paddle.idea.PaddleManager
import org.jetbrains.concurrency.AsyncPromise
import org.jetbrains.concurrency.Promise
import java.util.concurrent.atomic.AtomicInteger

@Suppress("UnstableApiUsage")
class PaddleProjectTaskRunner : ProjectTaskRunner() {
private val logger = Logger.getInstance(PaddleProjectTaskRunner::class.java)

override fun canRun(projectTask: ProjectTask): Boolean = true

override fun run(project: Project, context: ProjectTaskContext, vararg tasks: ProjectTask): Promise<Result> {
val resultPromise = AsyncPromise<Result>()
val executionSettingsBuilder = PaddleTasksExecutionSettingsBuilder(project, tasks.toList())
val rootProjectPath = project.basePath
?: return resultPromise.also {
logger.warn("Nothing will be run for: " + tasks.contentToString())
resultPromise.setResult(TaskRunnerResults.SUCCESS)
}
val settings = executionSettingsBuilder.build(rootProjectPath)
val userData = UserDataHolderBase()
userData.putUserData(ExternalSystemRunConfiguration.PROGRESS_LISTENER_KEY, BuildViewManager::class.java)

val errorCounter = AtomicInteger()

val taskCallback = object : TaskCallback {
override fun onSuccess() {
handle(true)
}

override fun onFailure() {
handle(false)
}

private fun handle(success: Boolean) {
val errors: Int = if (success) errorCounter.get() else errorCounter.incrementAndGet()
resultPromise.setResult(if (errors > 0) TaskRunnerResults.FAILURE else TaskRunnerResults.SUCCESS)
}
}

ExternalSystemUtil.runTask(
settings, DefaultRunExecutor.EXECUTOR_ID, project, PaddleManager.ID,
taskCallback, ProgressExecutionMode.IN_BACKGROUND_ASYNC, false, userData
)

return resultPromise
}
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package io.paddle.idea.runner
package io.paddle.idea.execution

import com.intellij.execution.Executor
import com.intellij.execution.configurations.ConfigurationFactory
Expand All @@ -9,10 +8,18 @@ import com.intellij.openapi.externalSystem.service.execution.ExternalSystemRunCo
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import io.paddle.idea.PaddleManager
import io.paddle.idea.execution.cmd.PaddleCommandLine
import org.jdom.Element
import java.util.*

class PaddleRunConfiguration(project: Project?, factory: ConfigurationFactory?, name: String?) :
ExternalSystemRunConfiguration(PaddleManager.ID, project, factory, name) {

init {
isDebugServerProcess = true
isReattachDebugProcess = true
}

var isDebugAllEnabled = false

override fun getState(executor: Executor, env: ExecutionEnvironment): RunProfileState? {
Expand All @@ -21,11 +28,29 @@ class PaddleRunConfiguration(project: Project?, factory: ConfigurationFactory?,
return super.getState(executor, env)
}

var rawCommandLine: String
get() {
val commandLine = StringJoiner(" ")
for (taskName in settings.taskNames) {
commandLine.add(taskName)
}
return commandLine.toString()
}
set(value) {
commandLine = PaddleCommandLine.parse(value)
}

var commandLine: PaddleCommandLine
get() = PaddleCommandLine.parse(rawCommandLine)
set(value) {
settings.taskNames = value.tasksAndArguments.toList()
}

override fun readExternal(element: Element) {
super.readExternal(element)
val child = element.getChild(DEBUG_FLAG_NAME)
if (child != null) {
setDebugServerProcess(java.lang.Boolean.valueOf(child.text))
isDebugServerProcess = java.lang.Boolean.valueOf(child.text)
}
val debugAll = element.getChild(DEBUG_ALL_NAME)
if (debugAll != null) {
Expand All @@ -40,17 +65,10 @@ class PaddleRunConfiguration(project: Project?, factory: ConfigurationFactory?,
element.addContent(debugAll)
}


companion object {
const val DEBUG_FLAG_NAME = "GradleScriptDebugEnabled"
const val DEBUG_FLAG_NAME = "PaddleScriptDebugEnabled"
const val DEBUG_ALL_NAME = "DebugAllEnabled"
val DEBUG_FLAG_KEY = Key.create<Boolean>("DEBUG_GRADLE_SCRIPT")
val DEBUG_FLAG_KEY = Key.create<Boolean>("DEBUG_PADDLE_SCRIPT")
val DEBUG_ALL_KEY = Key.create<Boolean>("DEBUG_ALL_TASKS")

}

init {
setDebugServerProcess(true)
setReattachDebugProcess(true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.paddle.idea.execution

import com.intellij.openapi.externalSystem.service.execution.configuration.*
import com.intellij.openapi.externalSystem.service.ui.project.path.ExternalSystemWorkingDirectoryInfo
import com.intellij.openapi.externalSystem.service.ui.project.path.WorkingDirectoryField
import com.intellij.openapi.project.Project
import io.paddle.idea.PaddleManager
import io.paddle.idea.execution.cmd.PaddleCommandLineInfo

class PaddleRunConfigurationExtension
: ExternalSystemReifiedRunConfigurationExtension<PaddleRunConfiguration>(PaddleRunConfiguration::class.java) {

override fun SettingsFragmentsContainer<PaddleRunConfiguration>.configureFragments(configuration: PaddleRunConfiguration) {
val project = configuration.project
addBeforeRunFragment(PaddleBeforeRunTaskProvider.ID)
val workingDirectoryField = addWorkingDirectoryFragment(project).component().component
addCommandLineFragment(project, workingDirectoryField)
}

private fun SettingsFragmentsContainer<PaddleRunConfiguration>.addWorkingDirectoryFragment(
project: Project
) = addWorkingDirectoryFragment(
project = project,
workingDirectoryInfo = ExternalSystemWorkingDirectoryInfo(project, PaddleManager.ID)
)

private fun SettingsFragmentsContainer<PaddleRunConfiguration>.addCommandLineFragment(
project: Project,
workingDirectoryField: WorkingDirectoryField
) = addCommandLineFragment(
project = project,
commandLineInfo = PaddleCommandLineInfo(project, workingDirectoryField),
getCommandLine = { rawCommandLine },
setCommandLine = { rawCommandLine = it }
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.paddle.idea.execution

import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.execution.configurations.RunConfiguration
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.settings.RunConfigurationImporter
import com.intellij.openapi.project.Project
import com.intellij.util.ObjectUtils

class PaddleRunConfigurationImporter : RunConfigurationImporter {
override fun canImport(typeName: String): Boolean = typeName == "paddle"

override fun getConfigurationFactory(): ConfigurationFactory = PaddleExternalTaskConfigurationType.getInstance().factory

override fun process(
project: Project,
runConfiguration: RunConfiguration,
cfg: MutableMap<String, Any>,
modelsProvider: IdeModifiableModelsProvider
) {
if (runConfiguration !is PaddleRunConfiguration) {
return
}

val settings = runConfiguration.settings

ObjectUtils.consumeIfCast(cfg["projectPath"], String::class.java) { settings.externalProjectPath = it }
ObjectUtils.consumeIfCast(cfg["taskNames"], List::class.java) { settings.taskNames = it as List<String> }
ObjectUtils.consumeIfCast(cfg["envs"], Map::class.java) { settings.env = it as Map<String, String> }
ObjectUtils.consumeIfCast(cfg["jvmArgs"], String::class.java) { settings.vmOptions = it }
ObjectUtils.consumeIfCast(cfg["scriptParameters"], String::class.java) { settings.scriptParameters = it }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.paddle.idea.execution

import com.intellij.execution.configurations.ConfigurationFactory
import com.intellij.openapi.externalSystem.service.execution.AbstractExternalSystemRunConfigurationProducer

class PaddleRuntimeConfigurationProducer : AbstractExternalSystemRunConfigurationProducer() {
override fun getConfigurationFactory(): ConfigurationFactory {
return PaddleExternalTaskConfigurationType.getInstance().factory
}
}
Loading

0 comments on commit 42d1580

Please sign in to comment.