Skip to content
This repository was archived by the owner on Jul 8, 2025. It is now read-only.
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
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ ktor = "3.2.1"
logback = "1.5.18"
modelix-core = "15.4.2"
modelix-mps-plugins = "0.11.1"
modelix-openapi = "1.3.0"

[libraries]
auth0-jwt = { group = "com.auth0", name = "java-jwt", version = "4.5.0" }
Expand Down Expand Up @@ -36,9 +37,11 @@ ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-conte
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }
ktor-server-auth = { group = "io.ktor", name = "ktor-server-auth", version.ref = "ktor" }
ktor-server-call-logging = { group = "io.ktor", name = "ktor-server-call-logging", version.ref = "ktor" }
ktor-server-content-negotiation = { group = "io.ktor", name = "ktor-server-content-negotiation", version.ref = "ktor" }
ktor-server-core = { group = "io.ktor", name = "ktor-server-core", version.ref = "ktor" }
ktor-server-cors = { group = "io.ktor", name = "ktor-server-cors", version.ref = "ktor" }
ktor-server-data-conversion = { group = "io.ktor", name = "ktor-server-data-conversion", version.ref = "ktor" }
ktor-server-html-builder = { group = "io.ktor", name = "ktor-server-html-builder", version.ref = "ktor" }
ktor-server-netty = { group = "io.ktor", name = "ktor-server-netty", version.ref = "ktor" }
ktor-server-status-pages = { group = "io.ktor", name = "ktor-server-status-pages", version.ref = "ktor" }
Expand All @@ -54,6 +57,7 @@ zt-zip = { group = "org.zeroturnaround", name = "zt-zip", version = "1.17" }
modelix-syncPlugin3 = { group = "org.modelix.mps", name = "mps-sync-plugin3", version.ref = "modelix-core" }
modelix-mpsPlugins-generator = { group = "org.modelix.mps", name = "generator-execution-plugin", version.ref = "modelix-mps-plugins" }
modelix-mpsPlugins-diff = { group = "org.modelix.mps", name = "diff-plugin", version.ref = "modelix-mps-plugins" }
modelix-api-server-stubs = { group = "org.modelix", name = "api-server-stubs-ktor", version.ref = "modelix-openapi" }

[bundles]
ktor-client = [
Expand Down Expand Up @@ -85,3 +89,4 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
shadow = { id = "com.github.johnrengelman.shadow", version = "8.1.1" }
jib = { id = "com.google.cloud.tools.jib", version = "3.4.5" }
openapi-generator = {id = "org.openapi.generator", version = "7.12.0"}
2 changes: 1 addition & 1 deletion workspace-client-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ plugins {
group = "org.modelix.mps"

kotlin {
jvmToolchain(17)
jvmToolchain(11)
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ package org.modelix.workspace.client
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.startup.StartupActivity
import io.github.oshai.kotlinlogging.KotlinLogging
import org.modelix.model.lazy.RepositoryId
import org.modelix.mps.sync3.IModelSyncService

private val LOG = KotlinLogging.logger { }

class WorkspaceClientStartupActivity : StartupActivity {
override fun runActivity(project: Project) {
println("### Workspace client loaded for project: ${project.name}")
Expand All @@ -18,16 +15,21 @@ class WorkspaceClientStartupActivity : StartupActivity {

val syncEnabled: Boolean = getEnvOrLog("WORKSPACE_MODEL_SYNC_ENABLED") == "true"
if (syncEnabled) {
println("model sync is enabled")
val modelUri: String? = getEnvOrLog("MODEL_URI")
val repoId: String? = getEnvOrLog("REPOSITORY_ID")
val repoId: RepositoryId? = getEnvOrLog("REPOSITORY_ID")?.let { RepositoryId(it) }
val branchName: String? = getEnvOrLog("REPOSITORY_BRANCH")
val jwt: String? = getEnvOrLog("INITIAL_JWT_TOKEN")
println("model server: $modelUri")
println("repository: $repoId")
println("branch: $branchName")
println("JWT: $jwt")
if (modelUri != null && repoId != null) {
val connection = IModelSyncService.getInstance(project).addServer(modelUri)
val connection = IModelSyncService.getInstance(project).addServer(modelUri, repositoryId = repoId)
if (jwt != null) {
connection.setTokenProvider { jwt }
}
connection.bind(RepositoryId(repoId).getBranchReference(branchName))
connection.bind(repoId.getBranchReference(branchName))
}
}
}
Expand All @@ -36,7 +38,7 @@ class WorkspaceClientStartupActivity : StartupActivity {
private fun getEnvOrLog(name: String): String? {
val value = System.getenv(name)
if (value == null) {
LOG.warn { "Environment variable $name is not set." }
println("Environment variable $name is not set.")
}
return value
}
17 changes: 7 additions & 10 deletions workspace-job/src/main/kotlin/org/modelix/workspace/job/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,17 @@ import io.ktor.http.appendPathSegments
import io.ktor.http.takeFrom
import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.runBlocking
import org.modelix.workspaces.Workspace
import org.modelix.workspaces.WorkspaceBuildStatus
import org.modelix.workspaces.WorkspaceHash
import org.modelix.workspaces.withHash
import org.modelix.workspaces.WorkspaceConfigForBuild
import java.util.UUID
import kotlin.time.Duration.Companion.minutes

private val LOG = mu.KotlinLogging.logger("main")

fun main(args: Array<String>) {
try {
val workspaceId = propertyOrEnv("modelix.workspace.id")
?: throw RuntimeException("modelix.workspace.id not specified")
val workspaceHash = propertyOrEnv("modelix.workspace.hash")?.let { WorkspaceHash(it) }
?: throw RuntimeException("modelix.workspace.id not specified")
val buildTaskId = propertyOrEnv("modelix.workspace.task.id")?.let { UUID.fromString(it) }
?: throw RuntimeException("modelix.workspace.task.id not specified")

var serverUrl = propertyOrEnv("modelix.workspace.server") ?: "http://workspace-manager:28104/"
serverUrl = serverUrl.trimEnd('/')
Expand All @@ -61,14 +58,14 @@ fun main(args: Array<String>) {

runBlocking {
printNewJobStatus(WorkspaceBuildStatus.Running)
val workspace: Workspace = httpClient.get {
val workspace: WorkspaceConfigForBuild = httpClient.get {
url {
takeFrom(serverUrl)
appendPathSegments(workspaceHash.hash)
appendPathSegments("modelix", "workspaces", "tasks", buildTaskId.toString(), "config")
parameter("decryptCredentials", "true")
}
}.body()
val job = WorkspaceBuildJob(workspace.withHash(workspaceHash), httpClient, serverUrl)
val job = WorkspaceBuildJob(workspace, httpClient, serverUrl)
job.buildWorkspace()
// job.status = if (job.status == WorkspaceBuildStatus.FailedBuild) WorkspaceBuildStatus.ZipSuccessful else WorkspaceBuildStatus.AllSuccessful
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ import org.apache.commons.io.FileUtils
import org.apache.maven.shared.invoker.DefaultInvocationRequest
import org.apache.maven.shared.invoker.DefaultInvoker
import org.apache.maven.shared.invoker.InvocationOutputHandler
import org.modelix.workspaces.Workspace
import org.modelix.workspaces.WorkspaceConfigForBuild
import org.zeroturnaround.zip.ZipUtil
import java.io.File
import java.util.*
import java.util.Properties

class MavenDownloader(val workspace: Workspace, val workspaceDir: File) {
class MavenDownloader(val workspace: WorkspaceConfigForBuild, val workspaceDir: File) {

fun downloadAndCopyFromMaven(coordinates: String, outputHandler: ((String) -> Unit)? = null): File {
if (workspace.mavenRepositories.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,12 @@
package org.modelix.workspace.job

import io.ktor.client.HttpClient
import io.ktor.client.plugins.timeout
import io.ktor.client.request.get
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.bodyAsChannel
import io.ktor.http.HttpStatusCode
import io.ktor.http.appendPathSegments
import io.ktor.http.takeFrom
import io.ktor.util.cio.writeChannel
import io.ktor.utils.io.copyTo
import io.ktor.utils.io.jvm.javaio.toInputStream
import org.modelix.buildtools.BuildScriptGenerator
import org.modelix.buildtools.DependencyGraph
import org.modelix.buildtools.FoundModule
Expand All @@ -39,13 +35,11 @@ import org.modelix.buildtools.PublicationDependencyGraph
import org.modelix.buildtools.SourceModuleOwner
import org.modelix.buildtools.newChild
import org.modelix.buildtools.xmlToString
import org.modelix.workspaces.UploadId
import org.modelix.workspaces.Workspace
import org.modelix.workspaces.WorkspaceAndHash
import org.modelix.workspaces.InternalWorkspaceConfig
import org.modelix.workspaces.WorkspaceBuildStatus
import org.modelix.workspaces.WorkspaceConfigForBuild
import org.modelix.workspaces.WorkspaceProgressItems
import org.w3c.dom.Document
import org.zeroturnaround.zip.ZipUtil
import java.io.File
import java.nio.file.Path
import javax.xml.parsers.DocumentBuilderFactory
Expand All @@ -54,9 +48,8 @@ import kotlin.io.path.deleteExisting
import kotlin.io.path.isRegularFile
import kotlin.io.path.name
import kotlin.io.path.walk
import kotlin.time.Duration.Companion.minutes

class WorkspaceBuildJob(val workspace: WorkspaceAndHash, val httpClient: HttpClient, val serverUrl: String) {
class WorkspaceBuildJob(val workspace: WorkspaceConfigForBuild, val httpClient: HttpClient, val serverUrl: String) {
private val workspaceDir = File(".").canonicalFile
val progressItems = WorkspaceProgressItems()

Expand All @@ -71,21 +64,22 @@ class WorkspaceBuildJob(val workspace: WorkspaceAndHash, val httpClient: HttpCli
}

private suspend fun copyUploads(): List<File> {
return workspace.uploads.map { UploadId(it) }.map { uploadId ->
LOG.info { "Copying upload $uploadId" }
val uploadFolder = workspaceDir.resolve("uploads/${uploadId.id}")
val data = httpClient.get {
url {
takeFrom(serverUrl)
appendPathSegments("uploads", uploadId.id)
}
timeout {
requestTimeoutMillis = 2.minutes.inWholeMilliseconds
}
}.bodyAsChannel()
ZipUtil.unpack(data.toInputStream(), uploadFolder)
uploadFolder
}
return emptyList()
// return workspace.uploads.map { UploadId(it) }.map { uploadId ->
// LOG.info { "Copying upload $uploadId" }
// val uploadFolder = workspaceDir.resolve("uploads/${uploadId.id}")
// val data = httpClient.get {
// url {
// takeFrom(serverUrl)
// appendPathSegments("uploads", uploadId.id)
// }
// timeout {
// requestTimeoutMillis = 2.minutes.inWholeMilliseconds
// }
// }.bodyAsChannel()
// ZipUtil.unpack(data.toInputStream(), uploadFolder)
// uploadFolder
// }
}

private fun cloneGitRepositories(): List<File> {
Expand All @@ -98,9 +92,9 @@ class WorkspaceBuildJob(val workspace: WorkspaceAndHash, val httpClient: HttpCli
}

private fun copyMavenDependencies(): List<File> {
return workspace.mavenDependencies.map { mavenDep ->
return workspace.mavenArtifacts.map { mavenDep ->
LOG.info { "Resolving $mavenDep" }
MavenDownloader(workspace.workspace, workspaceDir).downloadAndCopyFromMaven(mavenDep) { println(it) }
MavenDownloader(workspace, workspaceDir).downloadAndCopyFromMaven(mavenDep) { println(it) }
}
}

Expand All @@ -126,7 +120,7 @@ class WorkspaceBuildJob(val workspace: WorkspaceAndHash, val httpClient: HttpCli
buildScriptGenerator = BuildScriptGenerator(
modulesMiner,
ignoredModules = workspace.ignoredModules.map { ModuleId(it) }.toSet(),
additionalGenerationDependencies = workspace.workspace.additionalGenerationDependenciesAsMap(),
additionalGenerationDependencies = workspace.additionalGenerationDependenciesAsMap(),
)
runSafely {
modulesXml = xmlToString(buildModulesXml(buildScriptGenerator.modulesMiner.getModules()))
Expand All @@ -141,7 +135,7 @@ class WorkspaceBuildJob(val workspace: WorkspaceAndHash, val httpClient: HttpCli
progressItems.build.deleteUnusedModules.execute {
// to reduce the required memory include only those modules in the zip that are actually used
val resolver = ModuleResolver(modulesMiner.getModules(), workspace.ignoredModules.map { ModuleId(it) }.toSet(), true)
val graph = PublicationDependencyGraph(resolver, workspace.workspace.additionalGenerationDependenciesAsMap())
val graph = PublicationDependencyGraph(resolver, workspace.additionalGenerationDependenciesAsMap())
graph.load(modulesMiner.getModules().getModules().values)
val sourceModules: Set<ModuleId> = modulesMiner.getModules().getModules()
.filter { it.value.owner is SourceModuleOwner }.keys -
Expand Down Expand Up @@ -239,7 +233,7 @@ class WorkspaceBuildJob(val workspace: WorkspaceAndHash, val httpClient: HttpCli
}
}

private fun Workspace.additionalGenerationDependenciesAsMap(): Map<ModuleId, Set<ModuleId>> {
private fun InternalWorkspaceConfig.additionalGenerationDependenciesAsMap(): Map<ModuleId, Set<ModuleId>> {
return additionalGenerationDependencies
.groupBy { ModuleId(it.from) }
.mapValues { it.value.map { ModuleId(it.to) }.toSet() }
Expand All @@ -259,3 +253,9 @@ suspend fun HttpClient.downloadFile(file: File, url: String) {
data.copyTo(file.writeChannel())
}
}

fun WorkspaceConfigForBuild.additionalGenerationDependenciesAsMap() = additionalGenerationDependencies
.map { ModuleId(it.first) to ModuleId(it.second) }
.groupBy { it.first }
.mapValues { it.value.map { it.second }.toSet() }
.toMap()
2 changes: 2 additions & 0 deletions workspace-manager/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ dependencies {
implementation(libs.logback.classic)
implementation(libs.maven.invoker)
implementation(libs.modelix.authorization)
implementation(libs.ktor.server.call.logging)
implementation(libs.modelix.model.client)
implementation(libs.modelix.model.server) {
isTransitive = false
}
implementation(libs.zt.zip)
implementation(project(":gitui"))
implementation(project(":workspaces"))
implementation(libs.modelix.api.server.stubs)
mpsPlugins(libs.bundles.modelix.mpsPlugins.all)
mpsPlugins(project(":workspace-client-plugin", configuration = "archives"))
runtimeOnly(libs.slf4j.simple)
Expand Down
Loading
Loading