Skip to content

Support for toolbox 2.6.0.38311 #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ jvmWrapper {
dependencies {
compileOnly(libs.bundles.toolbox.plugin.api)
implementation(libs.slf4j)
implementation(libs.tinylog)
implementation(libs.bundles.serialization)
implementation(libs.coroutines.core)
implementation(libs.okhttp)
Expand Down
12 changes: 5 additions & 7 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
[versions]
toolbox-plugin-api = "0.6.2.6.0.37447"
kotlin = "2.0.10"
coroutines = "1.7.3"
serialization = "1.5.0"
toolbox-plugin-api = "0.7.2.6.0.38311"
kotlin = "2.1.0"
coroutines = "1.10.1"
serialization = "1.8.0"
okhttp = "4.10.0"
slf4j = "2.0.3"
tinylog = "2.7.0"
dependency-license-report = "2.5"
marketplace-client = "2.0.38"
gradle-wrapper = "0.14.0"
exec = "1.12"
moshi = "1.15.1"
ksp = "2.0.10-1.0.24"
ksp = "2.1.0-1.0.29"
retrofit = "2.8.2"

[libraries]
Expand All @@ -24,7 +23,6 @@ serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-jso
serialization-json-okio = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json-okio", version.ref = "serialization" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
tinylog = {module = "org.tinylog:slf4j-tinylog", version.ref = "tinylog"}
exec = { module = "org.zeroturnaround:zt-exec", version.ref = "exec" }
moshi = { module = "com.squareup.moshi:moshi", version.ref = "moshi"}
moshi-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshi"}
Expand Down
18 changes: 8 additions & 10 deletions src/main/kotlin/com/coder/toolbox/CoderRemoteEnvironment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import com.jetbrains.toolbox.api.remoteDev.states.EnvironmentStateConsumer
import com.jetbrains.toolbox.api.ui.ToolboxUi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.concurrent.CompletableFuture

/**
* Represents an agent and workspace combination.
Expand All @@ -29,12 +28,12 @@ class CoderRemoteEnvironment(
private var workspace: Workspace,
private var agent: WorkspaceAgent,
private var cs: CoroutineScope,
) : AbstractRemoteProviderEnvironment() {
) : AbstractRemoteProviderEnvironment("${workspace.name}.${agent.name}") {
private var status = WorkspaceAndAgentStatus.from(workspace, agent)

private val ui: ToolboxUi = serviceLocator.getService(ToolboxUi::class.java)
override fun getId(): String = "${workspace.name}.${agent.name}"
override fun getName(): String = "${workspace.name}.${agent.name}"

override var name: String = "${workspace.name}.${agent.name}"

init {
actionsList.add(
Expand Down Expand Up @@ -105,12 +104,11 @@ class CoderRemoteEnvironment(
* The contents are provided by the SSH view provided by Toolbox, all we
* have to do is provide it a host name.
*/
override fun getContentsView(): CompletableFuture<EnvironmentContentsView> =
CompletableFuture.completedFuture(EnvironmentView(client.url, workspace, agent))
override suspend fun getContentsView(): EnvironmentContentsView = EnvironmentView(client.url, workspace, agent)

/**
* Does nothing. In theory we could do something like start the workspace
* when you click into the workspace but you would still need to press
* Does nothing. In theory, we could do something like start the workspace
* when you click into the workspace, but you would still need to press
* "connect" anyway before the content is populated so there does not seem
* to be much value.
*/
Expand Down Expand Up @@ -140,12 +138,12 @@ class CoderRemoteEnvironment(
if (other == null) return false
if (this === other) return true // Note the triple ===
if (other !is CoderRemoteEnvironment) return false
if (getId() != other.getId()) return false
if (id != other.id) return false
return true
}

/**
* Companion to equals, for sets.
*/
override fun hashCode(): Int = getId().hashCode()
override fun hashCode(): Int = id.hashCode()
}
28 changes: 15 additions & 13 deletions src/main/kotlin/com/coder/toolbox/CoderRemoteProvider.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.coder.toolbox

import com.coder.toolbox.cli.CoderCLIManager
import com.coder.toolbox.logger.CoderLoggerFactory
import com.coder.toolbox.sdk.CoderRestClient
import com.coder.toolbox.sdk.v2.models.WorkspaceStatus
import com.coder.toolbox.services.CoderSecretsService
Expand Down Expand Up @@ -34,7 +35,6 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import org.slf4j.LoggerFactory
import java.net.URI
import java.net.URL
import kotlin.coroutines.cancellation.CancellationException
Expand All @@ -43,8 +43,8 @@ import kotlin.time.Duration.Companion.seconds
class CoderRemoteProvider(
private val serviceLocator: ServiceLocator,
private val httpClient: OkHttpClient,
) : RemoteProvider {
private val logger = LoggerFactory.getLogger(javaClass)
) : RemoteProvider("Coder") {
private val logger = CoderLoggerFactory.getLogger(javaClass)

private val ui: ToolboxUi = serviceLocator.getService(ToolboxUi::class.java)
private val consumer: RemoteEnvironmentConsumer = serviceLocator.getService(RemoteEnvironmentConsumer::class.java)
Expand Down Expand Up @@ -185,18 +185,18 @@ class CoderRemoteProvider(
consumer.consumeEnvironments(emptyList(), true)
}

override fun getName(): String = "Coder"
override fun getSvgIcon(): SvgIcon =
override val svgIcon: SvgIcon =
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf())

override fun getNoEnvironmentsSvgIcon(): ByteArray =
this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf()
override val noEnvironmentsSvgIcon: SvgIcon? =
SvgIcon(this::class.java.getResourceAsStream("/icon.svg")?.readAllBytes() ?: byteArrayOf())

/**
* TODO@JB: It would be nice to show "loading workspaces" at first but it
* appears to be only called once.
*/
override fun getNoEnvironmentsDescription(): String = "No workspaces yet"
override val noEnvironmentsDescription: String? = "No workspaces yet"


/**
* TODO@JB: Supposedly, setting this to false causes the new environment
Expand All @@ -205,7 +205,7 @@ class CoderRemoteProvider(
* this changes it would be nice to have a new spot to show the
* URL.
*/
override fun canCreateNewEnvironments(): Boolean = false
override val canCreateNewEnvironments: Boolean = false

/**
* Just displays the deployment URL at the moment, but we could use this as
Expand All @@ -216,7 +216,7 @@ class CoderRemoteProvider(
/**
* We always show a list of environments.
*/
override fun isSingleEnvironment(): Boolean = false
override val isSingleEnvironment: Boolean = false

/**
* TODO: Possibly a good idea to start/stop polling based on visibility, at
Expand All @@ -241,9 +241,11 @@ class CoderRemoteProvider(
*/
override fun handleUri(uri: URI) {
val params = uri.toQueryParameters()
val name = linkHandler.handle(params)
// TODO@JB: Now what? How do we actually connect this workspace?
logger.debug("External request for {}: {}", name, uri)
coroutineScope.launch {
val name = linkHandler.handle(params)
// TODO@JB: Now what? How do we actually connect this workspace?
logger.debug("External request for {}: {}", name, uri)
}
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/main/kotlin/com/coder/toolbox/CoderToolboxExtension.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.coder.toolbox

import com.coder.toolbox.logger.CoderLoggerFactory
import com.jetbrains.toolbox.api.core.ServiceLocator
import com.jetbrains.toolbox.api.core.diagnostics.Logger
import com.jetbrains.toolbox.api.remoteDev.RemoteDevExtension
import com.jetbrains.toolbox.api.remoteDev.RemoteProvider
import okhttp3.OkHttpClient
Expand All @@ -11,6 +13,9 @@ import okhttp3.OkHttpClient
class CoderToolboxExtension : RemoteDevExtension {
// All services must be passed in here and threaded as necessary.
override fun createRemoteProviderPluginInstance(serviceLocator: ServiceLocator): RemoteProvider {
// initialize logger factory
CoderLoggerFactory.tLogger = serviceLocator.getService(Logger::class.java)

return CoderRemoteProvider(
serviceLocator,
OkHttpClient(),
Expand Down
8 changes: 4 additions & 4 deletions src/main/kotlin/com/coder/toolbox/browser/BrowserUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import org.zeroturnaround.exec.ProcessExecutor

class BrowserUtil {
companion object {
fun browse(url: String, errorHandler: (BrowserException) -> Unit) {
suspend fun browse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
val os = getOS()
if (os == null) {
errorHandler(BrowserException("Failed to open the URL because we can't detect the OS"))
Expand All @@ -19,7 +19,7 @@ class BrowserUtil {
}
}

private fun linuxBrowse(url: String, errorHandler: (BrowserException) -> Unit) {
private suspend fun linuxBrowse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
try {
if (OS.LINUX.getDesktopEnvironment()?.uppercase()?.contains("GNOME") == true) {
exec("gnome-open", url)
Expand All @@ -36,15 +36,15 @@ class BrowserUtil {
}
}

private fun macBrowse(url: String, errorHandler: (BrowserException) -> Unit) {
private suspend fun macBrowse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
try {
exec("open", url)
} catch (e: Exception) {
errorHandler(BrowserException("Failed to open URL because an error was encountered.", e))
}
}

private fun windowsBrowse(url: String, errorHandler: (BrowserException) -> Unit) {
private suspend fun windowsBrowse(url: String, errorHandler: suspend (BrowserException) -> Unit) {
try {
exec("cmd", "start \"$url\"")
} catch (e: Exception) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/kotlin/com/coder/toolbox/cli/CoderCLIManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.coder.toolbox.cli
import com.coder.toolbox.cli.ex.MissingVersionException
import com.coder.toolbox.cli.ex.ResponseException
import com.coder.toolbox.cli.ex.SSHConfigFormatException
import com.coder.toolbox.logger.CoderLoggerFactory
import com.coder.toolbox.settings.CoderSettings
import com.coder.toolbox.settings.CoderSettingsState
import com.coder.toolbox.util.CoderHostnameVerifier
Expand All @@ -20,7 +21,6 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.squareup.moshi.JsonDataException
import com.squareup.moshi.Moshi
import org.slf4j.LoggerFactory
import org.zeroturnaround.exec.ProcessExecutor
import java.io.EOFException
import java.io.FileInputStream
Expand Down Expand Up @@ -126,7 +126,7 @@ class CoderCLIManager(
// manager to download to the data directory instead.
forceDownloadToData: Boolean = false,
) {
private val logger = LoggerFactory.getLogger(javaClass)
private val logger = CoderLoggerFactory.getLogger(javaClass)

val remoteBinaryURL: URL = settings.binSource(deploymentURL)
val localBinaryPath: Path = settings.binPath(deploymentURL, forceDownloadToData)
Expand Down
12 changes: 12 additions & 0 deletions src/main/kotlin/com/coder/toolbox/logger/CoderLoggerFactory.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.coder.toolbox.logger

import org.slf4j.ILoggerFactory
import org.slf4j.Logger
import com.jetbrains.toolbox.api.core.diagnostics.Logger as ToolboxLogger

object CoderLoggerFactory : ILoggerFactory {
var tLogger: ToolboxLogger? = null

fun getLogger(clazz: Class<Any>): Logger = getLogger(clazz.name)
override fun getLogger(clazzName: String): Logger = LoggerImpl(clazzName, tLogger)
}
Loading