Skip to content

Commit

Permalink
Add connection between session host and plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaelldi committed Nov 25, 2023
1 parent 82023a1 commit 92129d9
Show file tree
Hide file tree
Showing 20 changed files with 1,177 additions and 61 deletions.
1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions .run/Generate Protocol.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Generate Protocol" type="GradleRunConfiguration" factoryName="Gradle">
<ExternalSystemSettings>
<option name="executionName"/>
<option name="externalProjectPath" value="$PROJECT_DIR$"/>
<option name="externalSystemIdString" value="GRADLE"/>
<option name="scriptParameters" value=""/>
<option name="taskDescriptions">
<list/>
</option>
<option name="taskNames">
<list>
<option value="rdgen"/>
</list>
</option>
<option name="vmOptions" value=""/>
</ExternalSystemSettings>
<GradleScriptDebugEnabled>true</GradleScriptDebugEnabled>
<method v="2"/>
</configuration>
</component>
61 changes: 56 additions & 5 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ plugins {
alias(libs.plugins.gradleIntelliJPlugin) // Gradle IntelliJ Plugin
alias(libs.plugins.changelog) // Gradle Changelog Plugin
alias(libs.plugins.qodana) // Gradle Qodana Plugin
alias(libs.plugins.rdgen)
}

group = properties("pluginGroup").get()
version = properties("pluginVersion").get()

val rdLibDirectory: () -> File = { file("${tasks.setupDependencies.get().idea.get().classes}/lib/rd") }
extra["rdLibDirectory"] = rdLibDirectory

// Configure project's dependencies
repositories {
mavenCentral()
Expand Down Expand Up @@ -63,22 +67,64 @@ tasks {
gradleVersion = properties("gradleVersion").get()
}

configure<com.jetbrains.rd.generator.gradle.RdGenExtension> {
val modelDir = projectDir.resolve("protocol/src/main/kotlin/model/sessionHost")
val pluginSourcePath = projectDir.resolve("src")
val ktOutput = pluginSourcePath.resolve("main/kotlin/com/github/rafaelldi/aspireplugin/generated")
val csOutput = pluginSourcePath.resolve("dotnet/aspire-session-host/Generated")

verbose = true
classpath({
rdLibDirectory().resolve("rider-model.jar").canonicalPath
})
sources(modelDir)
hashFolder = "$rootDir/build/rdgen/rider"
packages = "model.sessionHost"

generator {
language = "kotlin"
transform = "asis"
root = "model.sessionHost.AspireSessionHostRoot"
directory = ktOutput.canonicalPath
}

generator {
language = "csharp"
transform = "reversed"
root = "model.sessionHost.AspireSessionHostRoot"
directory = csOutput.canonicalPath
}
}

val dotnetBuildConfiguration = properties("dotnetBuildConfiguration").get()
val compileDotNet by registering {
doLast {
exec {
executable("dotnet")
args("build", "-c", dotnetBuildConfiguration, "aspire-plugin.sln")
args("build", "-c", dotnetBuildConfiguration, "/clp:ErrorsOnly", "aspire-plugin.sln")
}
}
}
val publishSessionHost by registering {
dependsOn(compileDotNet)
doLast {
exec {
executable("dotnet")
args(
"publish",
"src/dotnet/aspire-session-host/aspire-session-host.csproj",
"--configuration", dotnetBuildConfiguration
)
}
}
}

buildPlugin {
dependsOn(compileDotNet)
dependsOn(publishSessionHost)
}

prepareSandbox {
dependsOn(compileDotNet)
dependsOn(publishSessionHost)

val outputFolder = file("$projectDir/src/dotnet/aspire-plugin/bin/$dotnetBuildConfiguration")
val dllFiles = listOf(
Expand All @@ -96,6 +142,10 @@ tasks {
if (!file.exists()) throw RuntimeException("File \"$file\" does not exist")
}
}

from("$projectDir/src/dotnet/aspire-session-host/bin/$dotnetBuildConfiguration/publish") {
into("${rootProject.name}/aspire-session-host")
}
}

runPluginVerifier {
Expand All @@ -114,7 +164,7 @@ tasks {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"

with (it.lines()) {
with(it.lines()) {
if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
}
Expand Down Expand Up @@ -157,6 +207,7 @@ tasks {
// The pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
// Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
// https://plugins.jetbrains.com/docs/intellij/deployment.html#specifying-a-release-channel
channels = properties("pluginVersion").map { listOf(it.split('-').getOrElse(1) { "default" }.split('.').first()) }
channels =
properties("pluginVersion").map { listOf(it.split('-').getOrElse(1) { "default" }.split('.').first()) }
}
}
3 changes: 3 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ kotlin = "1.9.21"
changelog = "2.2.0"
gradleIntelliJPlugin = "1.16.0"
qodana = "0.1.13"
rdgen = "2023.3.2"
# https://search.maven.org/artifact/com.jetbrains.rd/rd-gen

[libraries]
annotations = { group = "org.jetbrains", name = "annotations", version.ref = "annotations" }
Expand All @@ -16,3 +18,4 @@ changelog = { id = "org.jetbrains.changelog", version.ref = "changelog" }
gradleIntelliJPlugin = { id = "org.jetbrains.intellij", version.ref = "gradleIntelliJPlugin" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
qodana = { id = "org.jetbrains.qodana", version.ref = "qodana" }
rdgen = { id = "com.jetbrains.rdgen", version.ref = "rdgen" }
18 changes: 18 additions & 0 deletions protocol/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
plugins {
id("org.jetbrains.kotlin.jvm")
}

val rdLibDirectory: () -> File by rootProject.extra

repositories {
maven { setUrl("https://cache-redirector.jetbrains.com/maven-central") }
flatDir {
dir(rdLibDirectory())
}
}

dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib")
implementation(group = "", name = "rd-gen")
implementation(group = "", name = "rider-model")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package model.sessionHost

import com.jetbrains.rd.generator.nova.*
import com.jetbrains.rd.generator.nova.PredefinedType.*
import com.jetbrains.rd.generator.nova.csharp.CSharp50Generator
import com.jetbrains.rd.generator.nova.kotlin.Kotlin11Generator

object AspireSessionHostRoot : Root() {
init {
setting(Kotlin11Generator.Namespace, "com.github.rafaelldi.aspireplugin.generated")
setting(CSharp50Generator.Namespace, "AspireSessionHost.Generated")
}
}

@Suppress("unused")
object AspireSessionHostModel : Ext(AspireSessionHostRoot) {
private val EnvironmentVariableModel = structdef {
field("key", string)
field("value", string)
}

private val SessionModel = structdef {
field("projectPath", string)
field("debug", bool)
field("envs", array(EnvironmentVariableModel).nullable)
field("args", array(string).nullable)
}

init {
map("sessions", string, SessionModel)
}
}
18 changes: 18 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
pluginManagement {
repositories {
maven { setUrl("https://cache-redirector.jetbrains.com/plugins.gradle.org") }
}
resolutionStrategy {
eachPlugin {
when(requested.id.name) {
"rdgen" -> {
useModule("com.jetbrains.rd:rd-gen:${requested.version}")
}
}
}
}
}

plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
}


rootProject.name = "aspire-plugin"

include(":protocol")
79 changes: 79 additions & 0 deletions src/dotnet/aspire-session-host/Connection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using AspireSessionHost.Generated;
using JetBrains.Collections.Viewable;
using JetBrains.Lifetimes;
using JetBrains.Rd;
using JetBrains.Rd.Impl;

namespace AspireSessionHost;

internal class Connection : IDisposable
{
private readonly LifetimeDefinition _lifetimeDef = new();
private readonly Lifetime _lifetime;
private readonly IScheduler _scheduler;
private readonly IProtocol _protocol;
private readonly Task<AspireSessionHostModel> _model;

internal Connection(int port)
{
_lifetime = _lifetimeDef.Lifetime;
_scheduler = SingleThreadScheduler.RunOnSeparateThread(_lifetime, "AspireSessionHost Protocol Connection");
var wire = new SocketWire.Client(_lifetime, _scheduler, port);
_protocol = new Protocol(
"AspireSessionHost Protocol",
new Serializers(),
new Identities(IdKind.Client),
_scheduler,
wire,
_lifetime
);
_model = InitializeModelAsync();
}

private Task<AspireSessionHostModel> InitializeModelAsync()
{
var tcs = new TaskCompletionSource<AspireSessionHostModel>();
_scheduler.Queue(() =>
{
try
{
tcs.SetResult(new AspireSessionHostModel(_lifetime, _protocol));
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
return tcs.Task;
}

internal async Task<T> DoWithModel<T>(Func<AspireSessionHostModel, T> action)
{
var model = await _model;
var tcs = new TaskCompletionSource<T>();
_scheduler.Queue(() =>
{
try
{
tcs.SetResult(action(model));
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
return await tcs.Task;
}

internal Task DoWithModel(Action<AspireSessionHostModel> action) =>
DoWithModel(model =>
{
action(model);
return 0;
});

public void Dispose()
{
_lifetimeDef.Terminate();
}
}
Loading

0 comments on commit 92129d9

Please sign in to comment.