From f6e9d58d8b43fba9ffd235b468f4ef592e92ae80 Mon Sep 17 00:00:00 2001 From: Techatrix Date: Wed, 15 Jan 2025 18:14:15 +0100 Subject: [PATCH] disallow using Zig master/nightly with a tagged release of ZLS This change will not affect development builds of ZLS. --- build.zig | 16 ++- src/build_runner/BuildRunnerVersion.zig | 162 +++++++++++++++++++----- 2 files changed, 142 insertions(+), 36 deletions(-) diff --git a/build.zig b/build.zig index 68d4bdd16..86ad0a143 100644 --- a/build.zig +++ b/build.zig @@ -530,6 +530,7 @@ const Build = blk: { std.debug.assert(zls_version.pre == null or std.mem.eql(u8, zls_version.pre.?, "dev")); std.debug.assert(zls_version.build == null); const zls_version_is_tagged = zls_version.pre == null and zls_version.build == null; + const zls_version_simple: std.SemanticVersion = .{ .major = zls_version.major, .minor = zls_version.minor, .patch = 0 }; if (min_runtime_zig.order(min_build_zig) == .gt) { const message = std.fmt.comptimePrint( @@ -546,19 +547,28 @@ const Build = blk: { // check that the ZLS version and minimum build version make sense if (zls_version_is_tagged) { - if (zls_version.order(min_build_zig) != .eq) { + if (zls_version_simple.order(min_build_zig) != .eq) { const message = std.fmt.comptimePrint( \\A tagged release of ZLS should have the same tagged release of Zig as the minimum build requirement: \\ ZLS version: {[current_version]} \\ minimum Zig version: {[minimum_version]} \\ \\This is a developer error. Set `minimum_build_zig_version` in `build.zig` and `minimum_zig_version` in `build.zig.zon` to {[current_version]}. - , .{ .current_version = zls_version, .minimum_version = min_build_zig }); + , .{ .current_version = zls_version_simple, .minimum_version = min_build_zig }); + @compileError(message); + } + if (zls_version_simple.order(min_runtime_zig) != .eq) { + const message = std.fmt.comptimePrint( + \\A tagged release of ZLS should have the same tagged release of Zig as the minimum runtime version: + \\ ZLS version: {[current_version]} + \\ minimum Zig version: {[minimum_version]} + \\ + \\This is a developer error. Set `minimum_runtime_zig_version` in `build.zig` to `{[current_version]}`. + , .{ .current_version = zls_version_simple, .minimum_version = min_runtime_zig }); @compileError(message); } } else { const min_build_zig_simple: std.SemanticVersion = .{ .major = min_build_zig.major, .minor = min_build_zig.minor, .patch = 0 }; - const zls_version_simple: std.SemanticVersion = .{ .major = zls_version.major, .minor = zls_version.minor, .patch = 0 }; const min_zig_is_tagged = min_build_zig.build == null and min_build_zig.pre == null; if (!min_zig_is_tagged and zls_version_simple.order(min_build_zig_simple) != .eq) { const message = std.fmt.comptimePrint( diff --git a/src/build_runner/BuildRunnerVersion.zig b/src/build_runner/BuildRunnerVersion.zig index aaecb3a52..aa2deba60 100644 --- a/src/build_runner/BuildRunnerVersion.zig +++ b/src/build_runner/BuildRunnerVersion.zig @@ -15,8 +15,24 @@ pub const BuildRunnerVersion = enum { } pub fn selectBuildRunnerVersion(runtime_zig_version: std.SemanticVersion) ?BuildRunnerVersion { - const minimum_runtime_zig_version = comptime std.SemanticVersion.parse(build_options.minimum_runtime_zig_version_string) catch unreachable; - return selectVersionInternal(BuildRunnerVersion, minimum_runtime_zig_version, runtime_zig_version); + const is_zls_version_tagged = build_options.version.pre == null and build_options.version.build == null; + if (is_zls_version_tagged) { + // A ZLS release should not have a 'master.zig' build runner. + // To fix this, rename it to `${ZLS_VERSION}.zig` and remove all outdated version checks from it. + comptime std.debug.assert(!@hasField(BuildRunnerVersion, "master")); + } + + const min_runtime_zig_version = comptime std.SemanticVersion.parse(build_options.minimum_runtime_zig_version_string) catch unreachable; + return selectVersionInternal( + BuildRunnerVersion, + // If ZLS is a tagged release, it should not support development builds of the next release cycle. Example: + // - ZLS `0.13.0` with Zig `0.13.0` -> ok + // - ZLS `0.13.0` with Zig `0.14.0-dev` -> bad + // - ZLS `0.14.0-dev` with Zig `0.13.0` -> check `minimum_runtime_zig_version` + // - ZLS `0.14.0-dev` with Zig `0.14.0-dev` -> check `minimum_runtime_zig_version` + if (!is_zls_version_tagged) min_runtime_zig_version else null, + runtime_zig_version, + ); } pub fn getBuildRunnerFile(version: BuildRunnerVersion) [:0]const u8 { @@ -28,12 +44,15 @@ pub const BuildRunnerVersion = enum { fn selectVersionInternal( comptime AvailableVersion: type, - /// Only relevant when the ZLS version is a development build - comptime minimum_runtime_zig_version: std.SemanticVersion, + /// If set, a non-tagged `runtime_zig_version` must be at least the specified version. + /// If unset, a non-tagged `runtime_zig_version` will return `null`. + /// Will be ignored if the `runtime_zig_version` is a tagged release. + /// + /// Will be `null` iff ZLS is a tagged release. + comptime minimum_runtime_zig_version: ?std.SemanticVersion, runtime_zig_version: std.SemanticVersion, ) ?AvailableVersion { const runtime_zig_version_is_tagged = runtime_zig_version.build == null and runtime_zig_version.pre == null; - const minimum_runtime_zig_version_is_tagged = minimum_runtime_zig_version.build == null and minimum_runtime_zig_version.pre == null; const available_version_tags = comptime std.meta.tags(AvailableVersion); // `null` means master @@ -53,7 +72,6 @@ fn selectVersionInternal( comptime { std.debug.assert(available_version_tags.len != 0); std.debug.assert(available_version_tags.len == available_versions.len); - std.debug.assert(minimum_runtime_zig_version_is_tagged == !@hasField(AvailableVersion, "master")); } if (runtime_zig_version_is_tagged) { @@ -65,16 +83,25 @@ fn selectVersionInternal( } } return null; - } + } else if (minimum_runtime_zig_version) |min_runtime_zig_version| { + const min_runtime_zig_version_is_tagged = min_runtime_zig_version.build == null and min_runtime_zig_version.pre == null; + // There are two allowed states: + // - the minimum runtime zig version is a development build and a 'master' build runner is available + // - the minimum runtime zig version is a tagged release and no 'master' build runner is available + comptime std.debug.assert(min_runtime_zig_version_is_tagged == !@hasField(AvailableVersion, "master")); - switch (runtime_zig_version.order(available_versions[0] orelse minimum_runtime_zig_version)) { - .eq, .gt => return available_version_tags[0], - .lt => return null, + switch (runtime_zig_version.order(available_versions[0] orelse min_runtime_zig_version)) { + .eq, .gt => return available_version_tags[0], + .lt => return null, + } + } else { + comptime std.debug.assert(!@hasField(AvailableVersion, "master")); + return null; } } test selectVersionInternal { - @setEvalBranchQuota(6_000); + @setEvalBranchQuota(10_000); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const parse = std.SemanticVersion.parse; @@ -160,70 +187,94 @@ test selectVersionInternal { try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.11.0"), // minimum Zig version on master + null, + try parse("0.10.0"), // Zig version + )); + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + null, try parse("0.11.0-dev.1+aaaaaaaaa"), // Zig version )); try expectEqual(.@"0.11.0", selectVersionInternal( AvailableVersion, // available build runners - try parse("0.11.0"), // minimum Zig version on master + null, try parse("0.11.0"), // Zig version )); try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.11.0"), // minimum Zig version on master + null, try parse("0.12.0-dev.1+aaaaaaaaa"), // Zig version )); try expectEqual(.@"0.12.0", selectVersionInternal( AvailableVersion, // available build runners - try parse("0.11.0"), // minimum Zig version on master + null, try parse("0.12.0"), // Zig version )); - + try expectEqual(.@"0.12.0", selectVersionInternal( + AvailableVersion, // available build runners + null, + try parse("0.12.0"), // Zig version + )); + try expectEqual(.@"0.12.0", selectVersionInternal( + AvailableVersion, // available build runners + null, + try parse("0.12.1"), // Zig version + )); try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master - try parse("0.10.0"), // Zig version + null, + try parse("0.13.0-dev.1+aaaaaaaaa"), // Zig version )); try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master - try parse("0.11.0-dev.1+aaaaaaaaa"), // Zig version + null, + try parse("0.13.0"), // Zig version )); - try expectEqual(.@"0.11.0", selectVersionInternal( + } + + { + const AvailableVersion = enum { @"0.12.0" }; + + try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master - try parse("0.11.0"), // Zig version + try parse("0.12.0"), // minimum Zig version + try parse("0.11.0-dev.5+aaaaaaaaa"), // Zig version )); try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master - try parse("0.12.0-dev.1+aaaaaaaaa"), // Zig version + try parse("0.12.0"), // minimum Zig version + try parse("0.11.0"), // Zig version )); - try expectEqual(.@"0.12.0", selectVersionInternal( + try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master - try parse("0.12.0"), // Zig version + try parse("0.12.0"), // minimum Zig version + try parse("0.12.0-dev.5+aaaaaaaaa"), // Zig version )); try expectEqual(.@"0.12.0", selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master + try parse("0.12.0"), // minimum Zig version try parse("0.12.0"), // Zig version )); try expectEqual(.@"0.12.0", selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master + try parse("0.12.0"), // minimum Zig version try parse("0.12.1"), // Zig version )); try expectEqual(.@"0.12.0", selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master - try parse("0.13.0-dev.1+aaaaaaaaa"), // Zig version + try parse("0.12.0"), // minimum Zig version + try parse("0.13.0-dev.5+aaaaaaaaa"), // Zig version )); try expectEqual(null, selectVersionInternal( AvailableVersion, // available build runners - try parse("0.12.0"), // minimum Zig version on master + try parse("0.12.0"), // minimum Zig version try parse("0.13.0"), // Zig version )); + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.12.0"), // minimum Zig version + try parse("0.13.1"), // Zig version + )); } { @@ -280,4 +331,49 @@ test selectVersionInternal { try parse("0.13.1"), // Zig version )); } + + { + const AvailableVersion = enum { master }; + + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.12.0-dev.5+aaaaaaaaa"), // Zig version + )); + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.12.0"), // Zig version + )); + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.12.1"), // Zig version + )); + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.13.0-dev.4+aaaaaaaaa"), // Zig version + )); + try expectEqual(.master, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.13.0-dev.5+aaaaaaaaa"), // Zig version + )); + try expectEqual(.master, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.13.0-dev.10+aaaaaaaaa"), // Zig version + )); + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.13.0"), // Zig version + )); + try expectEqual(null, selectVersionInternal( + AvailableVersion, // available build runners + try parse("0.13.0-dev.5+aaaaaaaaa"), // minimum Zig version on master + try parse("0.13.1"), // Zig version + )); + } }