Fix versions parsing
diff --git a/src/main/kotlin/io/bazel/kotlin/generate/WriteKotlincCapabilities.kt b/src/main/kotlin/io/bazel/kotlin/generate/WriteKotlincCapabilities.kt
index 01309bf..1985ddf 100644
--- a/src/main/kotlin/io/bazel/kotlin/generate/WriteKotlincCapabilities.kt
+++ b/src/main/kotlin/io/bazel/kotlin/generate/WriteKotlincCapabilities.kt
@@ -11,6 +11,9 @@
 import java.time.Year
 import kotlin.io.path.exists
 import kotlin.io.path.writeText
+import kotlin.jvm.java
+import kotlin.streams.asSequence
+import kotlin.streams.toList
 
 /**
  * Generates a list of kotlinc flags from the K2JVMCompilerArguments on the classpath.
@@ -37,25 +40,37 @@
           System.getenv(it.groups[1]?.value)
         }
       }
-      ?: error("--out is required")
-
-    FileSystems.getDefault()
-      .getPath("$capabilitiesDirectory/$capabilitiesName")
-      .apply {
+      ?.run(FileSystems.getDefault()::getPath)
+      ?.apply {
         if (!parent.exists()) {
           Files.createDirectories(parent)
         }
-        writeText(
-          getArguments(K2JVMCompilerArguments::class.java)
-            .filterNot(KotlincCapability::shouldSuppress)
-            .asCapabilities()
-            .asCapabilitiesBzl().toString(),
-          StandardCharsets.UTF_8,
+      }
+      ?: error("--out is required")
+
+    capabilitiesDirectory.resolve(capabilitiesName).writeText(
+      getArguments(K2JVMCompilerArguments::class.java)
+        .filterNot(KotlincCapability::shouldSuppress)
+        .asCapabilities()
+        .asCapabilitiesBzl()
+        .toString(),
+      StandardCharsets.UTF_8,
+    )
+
+    capabilitiesDirectory.resolve("templates.bzl").writeText(
+      BzlDoc {
+        assignment(
+          "TEMPLATES",
+          list(
+            *Files.list(capabilitiesDirectory)
+              .filter { it.fileName.toString().startsWith("capabilities_") }
+              .map { "Label(${it.fileName.bzlQuote()})" }
+              .sorted()
+              .toArray(::arrayOfNulls),
+          ),
         )
-      }
-      .let {
-        println("Wrote to $it")
-      }
+      }.toString(),
+    )
   }
 
   /** Options that are either confusing, useless, or unexpected to be set outside the worker. */
@@ -167,6 +182,16 @@
         .joinToString(",\n", prefix = "{\n", postfix = "\n${indent.decrement()}}")
         .run(map)
     }
+
+    fun list(vararg items: String) = ValueBlock { indent, map ->
+      items
+        .joinToString(
+            separator = ",\n",
+            prefix = "[\n",
+            postfix = "\n${indent.decrement()}]",
+        ) { "$indent$it" }
+        .run(map)
+    }
   }
 
   private fun getArguments(klass: Class<*>): Sequence<KotlincCapability> = sequence {
@@ -258,8 +283,9 @@
     abstract fun convert(value: String?): String?
   }
 
-  private fun String.bzlQuote(): String {
-    val quote = "\"".repeat(if ("\n" in this || "\"" in this) 3 else 1)
-    return quote + this + quote
+  private fun Any.bzlQuote(): String {
+    var asString = toString()
+    val quote = "\"".repeat(if ("\n" in asString || "\"" in asString) 3 else 1)
+    return quote + asString + quote
   }
 }
diff --git a/src/main/starlark/core/repositories/compiler.bzl b/src/main/starlark/core/repositories/compiler.bzl
index 9d9cac6..7a43bd4 100644
--- a/src/main/starlark/core/repositories/compiler.bzl
+++ b/src/main/starlark/core/repositories/compiler.bzl
@@ -2,6 +2,9 @@
 Defines kotlin compiler repositories.
 """
 
+load("@bazel_skylib//lib:versions.bzl", "versions")
+load("//src/main/starlark/core/repositories/kotlin:templates.bzl", "TEMPLATES")
+
 def _kotlin_compiler_impl(repository_ctx):
     attr = repository_ctx.attr
     repository_ctx.download_and_extract(
@@ -37,7 +40,7 @@
     )
     template = _get_capability_template(
         attr.compiler_version,
-        repository_ctx.path(attr._capability_templates_dir).readdir(),
+        [repository_ctx.path(ct) for ct in attr._capability_templates],
     )
     repository_ctx.template(
         "capabilities.bzl",
@@ -48,27 +51,31 @@
 def _parse_version(basename):
     if "capabilities" not in basename:
         return None
-    return basename.split(".")[0].split("_")[1]
+    version_string = basename[len("capabilities_"):basename.find(".bzl")]
+    if version_string == "legacy":
+        return (0, 0, 0)
+    return versions.parse(version_string)
 
 def _get_capability_template(compiler_version, templates):
     version_index = {}
-
+    target = versions.parse(compiler_version)
     for template in templates:
         version = _parse_version(template.basename)
         if not version:
             continue
-        if compiler_version.startswith(version):
+
+        if target == version:
             return template
         version_index[version] = template
 
     last_version = sorted(version_index.keys(), reverse = True)[0]
 
     # After latest version, chosen by major revision
-    if int(compiler_version.split(".")[0]) >= int(last_version):
+    if target[0] >= last_version[0]:
         return version_index[last_version]
 
     # Legacy
-    return templates["legacy"]
+    return version_index[(0, 0, 0)]
 
 kotlin_capabilities_repository = repository_rule(
     implementation = _kotlin_capabilities_impl,
@@ -79,12 +86,9 @@
         "compiler_version": attr.string(
             doc = "compiler version",
         ),
-        "_capability_templates_dir": attr.label(
-            doc = "Compiler capability templates location. " +
-                  "Since repository rules do not resolve Label to a " +
-                  "Target, and glob is not available, this is a Label that " +
-                  "can be resolved to a directory via repository_ctx.path.",
-            default = "//src/main/starlark/core/repositories:kotlin",
+        "_capability_templates": attr.label_list(
+            doc = "List of compiler capability templates.",
+            default = TEMPLATES,
         ),
         "_template": attr.label(
             doc = "repository build file template",
diff --git a/src/main/starlark/core/repositories/kotlin/templates.bzl b/src/main/starlark/core/repositories/kotlin/templates.bzl
new file mode 100644
index 0000000..e731225
--- /dev/null
+++ b/src/main/starlark/core/repositories/kotlin/templates.bzl
@@ -0,0 +1,26 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# DO NOT EDIT: generated by bazel run //src/main/kotlin/io/bazel/kotlin/generate:kotlin_release_options
+TEMPLATES = [
+  Label("capabilities_1.4.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_1.5.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_1.6.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_1.7.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_1.8.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_1.9.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_2.0.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_2.1.bzl.com_github_jetbrains_kotlin.bazel"),
+  Label("capabilities_legacy.bzl.com_github_jetbrains_kotlin.bazel")
+]
\ No newline at end of file