diff --git a/sdk/daml-lf/BUILD.bazel b/sdk/daml-lf/BUILD.bazel index 235260223445..88bcf7ff0abb 100644 --- a/sdk/daml-lf/BUILD.bazel +++ b/sdk/daml-lf/BUILD.bazel @@ -30,10 +30,10 @@ genrule( srcs = ["@maven//:com_daml_daml_lf_language_2_13"], outs = ["daml-lf-versions-generated.json"], cmd = """ - # Extract the specific file by its name inside the zip - $(location @bazel_tools//tools/zip:zipper) x $(SRCS) -d $(RULEDIR) daml-lf-versions.json + # Extract the dto file from the jar + $(location @bazel_tools//tools/zip:zipper) x $(SRCS) -d $(RULEDIR) daml-lf-versions-dto.json # Rename it to match our declared output - mv $(RULEDIR)/daml-lf-versions.json $@ + mv $(RULEDIR)/daml-lf-versions-dto.json $@ """, tools = ["@bazel_tools//tools/zip:zipper"], visibility = ["//visibility:private"], diff --git a/sdk/daml-lf/daml-lf-versions.json b/sdk/daml-lf/daml-lf-versions.json index 7237a004cb8f..ff3974e59796 100644 --- a/sdk/daml-lf/daml-lf-versions.json +++ b/sdk/daml-lf/daml-lf-versions.json @@ -1,45 +1,241 @@ { "explicitVersions" : [ - "2.3-rc1", - "2.1", - "2.dev", - "2.3-rc1", - "2.2" + { + "major" : 2, + "minor" : { + "Staging" : { + "version" : 3, + "revision" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Dev" : { + + } + } + }, + { + "major" : 2, + "minor" : { + "Staging" : { + "version" : 3, + "revision" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + } ], "namedVersions" : { - "defaultLfVersion" : "2.2", - "devLfVersion" : "2.dev", - "latestStableLfVersion" : "2.2", - "stagingLfVersion" : "2.3-rc1" + "defaultLfVersion" : { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + }, + "devLfVersion" : { + "major" : 2, + "minor" : { + "Dev" : { + + } + } + }, + "latestStableLfVersion" : { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + }, + "stagingLfVersion" : { + "major" : 2, + "minor" : { + "Staging" : { + "version" : 3, + "revision" : 1 + } + } + } }, "versionLists" : { "compilerOutputLfVersions" : [ - "2.1", - "2.2", - "2.3-rc1", - "2.dev" + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + }, + { + "major" : 2, + "minor" : { + "Staging" : { + "version" : 3, + "revision" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Dev" : { + + } + } + } ], "allLfVersions" : [ - "2.1", - "2.2", - "2.3-rc1", - "2.dev" + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + }, + { + "major" : 2, + "minor" : { + "Staging" : { + "version" : 3, + "revision" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Dev" : { + + } + } + } ], "stableLfVersions" : [ - "2.1", - "2.2" + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + } ], "compilerInputLfVersions" : [ - "2.1", - "2.2", - "2.3-rc1", - "2.dev" + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + }, + { + "major" : 2, + "minor" : { + "Staging" : { + "version" : 3, + "revision" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Dev" : { + + } + } + } ], "compilerLfVersions" : [ - "2.1", - "2.2", - "2.3-rc1", - "2.dev" + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Stable" : { + "version" : 2 + } + } + }, + { + "major" : 2, + "minor" : { + "Staging" : { + "version" : 3, + "revision" : 1 + } + } + }, + { + "major" : 2, + "minor" : { + "Dev" : { + + } + } + } ] } -} +} \ No newline at end of file diff --git a/sdk/daml-lf/daml-lf.bzl b/sdk/daml-lf/daml-lf.bzl index 0fb8a5d156e2..5912ad214e86 100644 --- a/sdk/daml-lf/daml-lf.bzl +++ b/sdk/daml-lf/daml-lf.bzl @@ -14,33 +14,30 @@ def _camel_to_upper_snake(text): result += char return result.upper() -def _parse_version(v_str): +def _parse_version(v): """ - Parses a version string according to specific rules: - - "2.dev" -> status="dev", minor="dev" - - "2.n-rcm" -> status="staging", minor="n", revision="m" - - "2.n" -> status="stable", minor="n" + Parses a structured version dict from the JSON: + - {"major": 2, "minor": {"Dev": {}}} -> status="dev" + - {"major": 2, "minor": {"Staging": {"version": 3, "revision": 1}}} -> status="staging" + - {"major": 2, "minor": {"Stable": {"version": 1}}} -> status="stable" """ - parts = v_str.split(".") - major = parts[0] - remainder = parts[1] # "dev", "1", "3-rc1" + major = str(v["major"]) + minor_map = v["minor"] - if "dev" in remainder: + if "Dev" in minor_map: return struct( - dotted = v_str, - mangled_java = "{}_{}".format(major, "dev"), - mangled_damlc = "{}{}".format(major, "dev"), + dotted = "{}.dev".format(major), + mangled_java = "{}_dev".format(major), + mangled_damlc = "{}dev".format(major), major = major, minor = "dev", status = "dev", ) - if "-rc" in remainder: - # split "3-rc1" into "3" and "1" - rc_parts = remainder.split("-rc") - minor = rc_parts[0] - revision = rc_parts[1] - + elif "Staging" in minor_map: + info = minor_map["Staging"] + minor = str(info["version"]) + revision = str(info["revision"]) return struct( dotted = "{}.{}-staging".format(major, minor), mangled_java = "{}_{}_staging".format(major, minor), @@ -51,14 +48,18 @@ def _parse_version(v_str): status = "staging", ) - return struct( - dotted = v_str, - mangled_java = "{}_{}".format(major, remainder), - mangled_damlc = "{}{}".format(major, remainder), - major = major, - minor = remainder, - status = "stable", - ) + elif "Stable" in minor_map: + minor = str(minor_map["Stable"]["version"]) + return struct( + dotted = "{}.{}".format(major, minor), + mangled_java = "{}_{}".format(major, minor), + mangled_damlc = "{}{}".format(major, minor), + major = major, + minor = minor, + status = "stable", + ) + + fail("Unknown minor version format: {}".format(minor_map)) def _build_versions_struct(): """ @@ -67,20 +68,21 @@ def _build_versions_struct(): """ fields = {} - for val in sorted(DATA["explicitVersions"]): + # explicitVersions is now a list of dicts; deduplicate by mangled_java key + for val in DATA["explicitVersions"]: version_obj = _parse_version(val) field_name = version_obj.mangled_java fields[field_name] = version_obj - for key, val in sorted(DATA["namedVersions"].items()): + for key, val in DATA["namedVersions"].items(): field_name = _camel_to_upper_snake(key) version_obj = _parse_version(val) fields[field_name] = version_obj - for key, val_list in sorted(DATA["versionLists"].items()): + for key, val_list in DATA["versionLists"].items(): field_name = _camel_to_upper_snake(key) - # Parse every string in the list into a struct + # Parse every dict in the list into a struct fields[field_name] = [_parse_version(v) for v in val_list] return struct(**fields) diff --git a/sdk/daml-lf/generate_haskell_versions.py b/sdk/daml-lf/generate_haskell_versions.py index f1ee9c4d6996..e79c764eff72 100644 --- a/sdk/daml-lf/generate_haskell_versions.py +++ b/sdk/daml-lf/generate_haskell_versions.py @@ -3,22 +3,59 @@ import json import sys -import re ### NOTE: THIS FILE HAS BEEN GENERATED BY GEMINI AND AS OF NOW DOES ITS JOB. IT ### MAY WELL DO THINGS SUBOPTIMALLY. IF REQUIREMENTS CHANGE, IT IS RECOMMENDED ### TO REPLACE THE FILE VERSUS TRYING TO UNDERSTAND AND ALTER WHAT THE SCRIPT IS ### DOING. +# --- Helpers for structured version dicts --- + +def parse_version_dict(v): + """ + Parse a structured version dict into (var_name, base_v, haskell_constructor, revision_or_none). + Supports: + {"major": 2, "minor": {"Dev": {}}} + {"major": 2, "minor": {"Stable": {"version": N}}} + {"major": 2, "minor": {"Staging": {"version": N, "revision": M}}} + """ + major = v["major"] + minor_map = v["minor"] + if "Dev" in minor_map: + return f"version{major}_dev", f"{major}.dev", "PointDev", None + elif "Staging" in minor_map: + info = minor_map["Staging"] + minor = info["version"] + rev = info["revision"] + return f"version{major}_{minor}", f"{major}.{minor}", f"PointStaging {minor}", rev + elif "Stable" in minor_map: + minor = minor_map["Stable"]["version"] + return f"version{major}_{minor}", f"{major}.{minor}", f"PointStable {minor}", None + raise ValueError(f"Unknown minor version format: {minor_map}") + +def version_sort_key(v): + """Sort key for structured version dicts.""" + minor_map = v["minor"] + if "Dev" in minor_map: + return (v["major"], 999999) + elif "Staging" in minor_map: + return (v["major"], minor_map["Staging"]["version"]) + elif "Stable" in minor_map: + return (v["major"], minor_map["Stable"]["version"]) + else: + return (v["major"], 0) + +def version_to_key(v): + """Convert a structured version dict to a hashable lookup key.""" + _, base_v, _, _ = parse_version_dict(v) + return base_v + # --- Generators -def generate_haskell_list(name, docstring, version_strings, lookup_map): +def generate_haskell_list(name, docstring, version_dicts, lookup_map): """Generates a Haskell list definition with deduplication.""" - # 1. Resolve all strings to their Haskell variable names - # e.g. ["2.3-rc1", "2.3-rc2"] -> ["version2_3", "version2_3"] - raw_refs = [lookup_map[v] for v in version_strings] + raw_refs = [lookup_map[version_to_key(v)] for v in version_dicts] - # 2. Deduplicate while preserving order unique_refs = [] seen = set() for ref in raw_refs: @@ -32,9 +69,9 @@ def generate_haskell_list(name, docstring, version_strings, lookup_map): f"{name} = [{', '.join(unique_refs)}]\n", ] -def generate_haskell_singleton(name, docstring, version_string, lookup_map): +def generate_haskell_singleton(name, docstring, version_dict, lookup_map): """Generates a Haskell singleton definition (alias).""" - ref = lookup_map[version_string] + ref = lookup_map[version_to_key(version_dict)] return [ f"-- | {docstring}", f"{name} :: Version", @@ -61,62 +98,20 @@ def main(input_json_path, output_hs_path): staging_revisions = set() raw_versions = data.get("explicitVersions", []) + raw_versions.sort(key=version_sort_key) + + for v in raw_versions: + var_name, base_v, haskell_constructor, rev = parse_version_dict(v) + + if rev is not None: + staging_revisions.add(rev) - def sort_key(v): - if v == "2.dev": return (2, 999999) # Dev is largest - # Split 2.12-rc1 into [2, 12, rc1] - parts = re.split(r'[.-]', v) - major = int(parts[0]) - minor = int(parts[1]) if parts[1].isdigit() else 0 - return (major, minor) - - raw_versions.sort(key=sort_key) - - for v_str in raw_versions: - var_name = "" - constructor = "" - base_v = "" # To be used for comments and lookup keys - - if v_str == "2.dev": - var_name = "version2_dev" - constructor = "PointDev" - base_v = "2.dev" - - elif "-rc" in v_str: - # Staging: 2.3-rc1 - match = re.search(r"2\.(\d+)-rc(\d+)", v_str) - if match: - minor = match.group(1) - rev = int(match.group(2)) - - staging_revisions.add(rev) - - var_name = f"version2_{minor}" - base_v = f"2.{minor}" - - constructor = f"PointStaging {minor}" - - else: - # Stable: 2.1 - match = re.search(r"2\.(\d+)", v_str) - if match: - minor = match.group(1) - var_name = f"version2_{minor}" - base_v = f"2.{minor}" - constructor = f"PointStable {minor}" - - # Map "2.3-rc1" -> "version2_3" - version_lookup[v_str] = var_name - - # Also map the base "2.3" -> "version2_3" - # This ensures if json has ["2.3"] (short form) it still works - if base_v: - version_lookup[base_v] = var_name + version_lookup[base_v] = var_name if var_name not in generated_vars: output.append(f"-- | Daml-LF version {base_v}") output.append(f"{var_name} :: Version") - output.append(f"{var_name} = Version V2 ({constructor})\n") + output.append(f"{var_name} = Version V2 ({haskell_constructor})\n") generated_vars.add(var_name) sorted_revisions = sorted(list(staging_revisions)) @@ -134,9 +129,9 @@ def sort_key(v): named_versions = data.get("namedVersions", {}) for alias_name in sorted(named_versions.keys()): - v_str = named_versions[alias_name] + v_dict = named_versions[alias_name] docstring = f"The {alias_name}." - output.extend(generate_haskell_singleton(alias_name, docstring, v_str, version_lookup)) + output.extend(generate_haskell_singleton(alias_name, docstring, v_dict, version_lookup)) with open(output_hs_path, 'w') as f: f.write("\n".join(output))