Database reorganize, protocol version bump, migrations

This commit is contained in:
2026-08-26 23:13:47 +02:00
parent 7343300536
commit 4fdeafb73b
31 changed files with 1058 additions and 114 deletions
@@ -101,10 +101,11 @@ object CLI {
override fun nestedCommands(): Array<CliktCommand> = fromReflection()
sealed interface IProjectIdentification
sealed interface ILabelIdentification
sealed interface IVersionIdentification
sealed interface IBenchmarkIdentification
data class ProjectName(val user: String, val project: String) : IProjectIdentification
data class VersionName(val name: String): ILabelIdentification
data class ID(val id: Uuid) : IProjectIdentification, ILabelIdentification
data class Name(val name: String): IVersionIdentification, IBenchmarkIdentification
data class ID(val id: Uuid) : IProjectIdentification, IVersionIdentification, IBenchmarkIdentification
sealed interface IData<T> {
fun toList(): List<T>
@@ -184,12 +185,24 @@ object CLI {
override fun run() = ProjectHandlers.newVersion(name, color, parent.finder, meta)
}
@Suppress("unused")
class AddBenchmark : CliktCommand(name = "add-benchmark") {
val parent by requireObject<Project>()
val name by option("--name", help = "Set the version's name (*)")
override fun run() = ProjectHandlers.newBenchmark(name, parent.finder)
}
@Suppress("unused")
class AddData : CliktCommand(name = "add-data") {
val parent by requireObject<Project>()
val version by mutuallyExclusiveOptions<ILabelIdentification>(
val version by mutuallyExclusiveOptions<IVersionIdentification>(
option("--version-id", help = "Set the version by UUID.").convert { ID(Uuid.parse(it)) },
option("--version", help = "Set the version by name.").convert { VersionName(it) }
option("--version", help = "Set the version by name.").convert { Name(it) }
).single()
val benchmark by mutuallyExclusiveOptions<IBenchmarkIdentification>(
option("--benchmark-id", "--bench-id", help = "Set the benchmark by UUID.").convert { ID(Uuid.parse(it)) },
option("--benchmark", "--bench", help = "Set the benchmark by name.").convert { Name(it) }
).single()
val warmup by mutuallyExclusiveOptions<IData<Float>>(
option("--warmup", help = "Set warmup data directly.").float().split(",").transformAll { DirectData(it.flatten()) },
@@ -210,7 +223,7 @@ object CLI {
val input by option("--input", help = "Set the input used to benchmark")
val hardware by option("--hardware", "--hw", help = "Set the hardware on which the benchmark was run")
override fun run() = ProjectHandlers.newData(parent.finder, version, warmup, measurement, unit, input, hardware)
override fun run() = ProjectHandlers.newData(parent.finder, benchmark, version, warmup, measurement, unit, input, hardware)
}
}
@@ -1,6 +1,7 @@
package com.jaytux.phoebench.clients.cli
import com.jaytux.phoebench.clients.cli.CLI.Commands.Project.ProjectName
import com.jaytux.phoebench.common.BenchmarkRequest
import com.jaytux.phoebench.common.Either
import com.jaytux.phoebench.common.EmptyRequest
import com.jaytux.phoebench.common.EntryRequest
@@ -29,6 +30,7 @@ object ProjectHandlers {
Client.callRoute(Routes.home, EmptyRequest())
}.fold({ err ->
System.err.println("Could not get projects list: ${err.msg}")
exitProcess(-1)
}) {
System.err.println("Logged in as ${it.username}")
(it.ownProjects + it.publicProjects).toSet().sortedBy { p -> p.name }.forEach { project ->
@@ -65,18 +67,22 @@ object ProjectHandlers {
}
}.fold({
System.err.println("Failed to get project details: ${it.msg}")
exitProcess(-1)
}) {
println("Project ${it.owner.name}/${it.name} [${it.id}]:")
println("${it.usedLabels.size} versions:")
it.usedLabels.forEach { v ->
println("${it.versions.size} versions:")
it.versions.forEach { v ->
println(" - [${v.id}] VERSION ${v.name} (with color ${v.color}); metadata: ${v.meta}")
}
val map = it.usedLabels.associateBy { l -> l.id }
val map = it.versions.associateBy { l -> l.id }
println("\n${it.entries.size} entries:")
it.entries.forEach { e ->
println(" - [${e.id}] ENTRY versioned ${map[e.labelId]?.name ?: "<invalid version>"} at ${e.timestamp.fmt()} " +
"(${e.warmups.size} warmup data points, ${e.measurements.size} measurement data points; in ${e.unit.disp})")
println("\n${it.benchmarks.size} benchmarks:")
it.benchmarks.forEach { b ->
println(" - [${b.id}] ${b.name} with ${b.entries.size} entries:")
b.entries.forEach { e ->
println(" - [${e.id}] ENTRY versioned ${map[e.versionId]?.name ?: "<invalid version>"} at ${e.timestamp.fmt()} " +
"(${e.warmups.size} warmup data points, ${e.measurements.size} measurement data points; in ${e.unit.disp})")
}
}
}
}
@@ -87,6 +93,7 @@ object ProjectHandlers {
Client.callRoute(Routes.Project.new, ProjectRequest(useName, isPublic))
}.fold({
System.err.println("Failed to create project '$useName': ${it.msg}")
exitProcess(-1)
}) {
println("Project ${it.owner.name}/${it.name} [${it.id}] created.")
}
@@ -111,8 +118,25 @@ object ProjectHandlers {
}
}.fold({
System.err.println("Could not create version: ${it.msg}")
exitProcess(-1)
}) {
println("Label ${it.name} (${it.color}) [${it.id}] created.")
println("Version ${it.name} (${it.color}) [${it.id}] created.")
}
}
fun newBenchmark(name: String?, project: CLI.Commands.Project.IProjectIdentification?) {
val id = ensureProjectIdentification(project)
val useName = name.maybePrompt("version name") { it }
tryAuthenticated {
id.toId().bind { projectId ->
Client.callRoute(Routes.Benchmark.new, BenchmarkRequest(useName, projectId))
}
}.fold({
System.err.println("Could not create benchmark: ${it.msg}")
exitProcess(-1)
}) {
println("Benchmark ${it.name} [${it.id}] created.")
}
}
@@ -129,14 +153,18 @@ object ProjectHandlers {
fun newData(
project: CLI.Commands.Project.IProjectIdentification?,
label: CLI.Commands.Project.ILabelIdentification?,
benchmark: CLI.Commands.Project.IBenchmarkIdentification?,
label: CLI.Commands.Project.IVersionIdentification?,
warmup: CLI.Commands.Project.IData<Float>?,
measurement: CLI.Commands.Project.IData<Float>?,
unit: TimeUnit?, input: String?, hardware: String?
) {
val projectId = ensureProjectIdentification(project)
val versionId = label.maybePrompt("version name") {
CLI.Commands.Project.VersionName(it)
CLI.Commands.Project.Name(it)
}
val benchmarkId = benchmark.maybePrompt("benchmark name") {
CLI.Commands.Project.Name(it)
}
val warmupData = warmup.ensure("warmup").toList()
val measureData = measurement.ensure("measurements").toList()
@@ -160,19 +188,30 @@ object ProjectHandlers {
tryAuthenticated {
projectId.toId().bind { pId ->
when(versionId) {
is CLI.Commands.Project.ID -> versionId.id.value()
is CLI.Commands.Project.VersionName -> Client.callRoute(Routes.Project.get, pId).bind {
it.usedLabels.firstOrNull { l -> l.name == versionId.name }?.id?.value()
?: ErrorResponse("Version ${versionId.name} does not exist in this project.").error()
Client.callRoute(Routes.Project.get, pId).bind { p ->
when (versionId) {
is CLI.Commands.Project.ID -> versionId.id.value()
is CLI.Commands.Project.Name -> p.versions.firstOrNull { l -> l.name == versionId.name }?.id?.value()
?: ErrorResponse("Version ${versionId.name} does not exist in this project.").error()
}.bind { vId ->
when (benchmarkId) {
is CLI.Commands.Project.ID -> benchmarkId.id.value()
is CLI.Commands.Project.Name -> p.benchmarks.firstOrNull { b -> b.name == benchmarkId.name }?.id?.value()
?: ErrorResponse("Benchmark ${benchmarkId.name} does not exist in this project.").error()
}.map { it to vId }
}
}.map { pId to it }
}.bind { (pId, vId) ->
}
}.bind { (bId, vId) ->
Client.callRoute(Routes.Entry.new, EntryRequest(
vId, Clock.System.now(), pId,
vId, Clock.System.now(), bId,
warmupData, measureData, timeUnit, useInput, useHardware
))
}
}.fold({
System.err.println("Failed to add data: ${it.msg}")
exitProcess(-1)
}) {
println("Data added successfully.")
}
}
}