From 77c231943b2be4862163dcc175693bad4dcb8112 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 10 Sep 2026 09:31:26 +0900 Subject: [PATCH 1/5] Accept --version and -V Probing an unknown rb with --version is how a caller identifies the build it got, and answering that with usage and a non-zero exit reads as a broken binary rather than as an old one. Co-Authored-By: Claude Opus 5 --- README.md | 12 +++++++----- src/rbmanager/Program.cs | 6 +++++- tests/rbmanager.Tests/CliE2eTests.cs | 9 ++++++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 7631478..06f032a 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ rb uninstall remove an installed ruby rb msvc run a command with the MSVC build env applied rb msvc enable [shell] print the MSVC build env to eval (cmd|powershell) rb msvc --list list installed Visual Studio C++ toolchains -rb version print the rbmanager version +rb version print the rbmanager version (also --version, -V) ``` rb is a bare exe; `setup` copies it to @@ -64,10 +64,12 @@ version, and `msvc --list` shows what is installed. Apart from `msvc` operations are spelled as flags. `version` identifies the running binary, in cargo's shape, as in -`rbmanager 0.1.0 (9a1b2c3 2026-07-28)`. The version is the release tag -the build came from, or the number in `rbmanager.csproj` between -releases. The commit and date are stamped in at build time, and are -omitted when there is no git checkout to read them from. +`rbmanager 0.1.0 (9a1b2c3 2026-07-28)`. `--version` and `-V` print the +same line, so probing an unknown rb never lands in usage. The version +is the release tag the build came from, or the number in +`rbmanager.csproj` between releases. The commit and date are stamped in +at build time, and are omitted when there is no git checkout to read +them from. The official mswin packages deliberately do not bundle vcruntime140.dll (https://bugs.ruby-lang.org/issues/22180) and expect diff --git a/src/rbmanager/Program.cs b/src/rbmanager/Program.cs index 08ec49e..c8cdbc2 100644 --- a/src/rbmanager/Program.cs +++ b/src/rbmanager/Program.cs @@ -30,7 +30,10 @@ private static async Task Main(string[] args) ["list"] => List(), ["use", var name] => Use(name), ["uninstall", var name] => Uninstall(name), - ["version"] => Version(), + // The flag spellings answer too: probing a tool with + // --version is how a caller identifies the build it got, + // and falling to usage there reads as a broken binary. + ["version" or "--version" or "-V"] => Version(), // Everything after `msvc` belongs to Msvc's own parser: it // owns one reserved word (`enable`) and passes the rest // through as the user's command line. @@ -62,6 +65,7 @@ msvc enable [shell] print the MSVC build env to eval (cmd|powershell) msvc --list list installed Visual Studio C++ toolchains (msvc and msvc enable accept --vsver ) version print the rbmanager version + (also --version, -V) """); return 2; } diff --git a/tests/rbmanager.Tests/CliE2eTests.cs b/tests/rbmanager.Tests/CliE2eTests.cs index 980a845..5be0c56 100644 --- a/tests/rbmanager.Tests/CliE2eTests.cs +++ b/tests/rbmanager.Tests/CliE2eTests.cs @@ -58,11 +58,14 @@ public void FailingCommand_ErrorToStderr_Exit1_EmptyStdout() Assert.StartsWith("rb: ", r.Err); } - [Fact] // case 88 - public void Version_OneLine_Exit0() + [Theory] // cases 88, 118: the flag spellings print the same line + [InlineData("version")] + [InlineData("--version")] + [InlineData("-V")] + public void Version_OneLine_Exit0(string spelling) { using var sb = new E2eSandbox(); - RbResult r = sb.Run("version"); + RbResult r = sb.Run(spelling); Assert.Equal(0, r.ExitCode); string line = Assert.Single(Lines(r.Out)); From d15bdfff14227dd64c85831d3c61e53de12d5787 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 10 Sep 2026 09:34:01 +0900 Subject: [PATCH 2/5] Add rb list --remote The binary index is the only way to learn what can be installed, and so far a caller had to fetch and parse index.json to see it. The output is the counterpart of `rb list`: name, channel, and the tags `install` takes, newest first. Co-Authored-By: Claude Opus 5 --- README.md | 7 ++ src/rbmanager/BinaryIndex.cs | 31 ++++--- src/rbmanager/Program.cs | 23 ++++++ tests/rbmanager.Tests/BinaryIndexTests.cs | 32 ++++++++ tests/rbmanager.Tests/CliE2eTests.cs | 8 ++ tests/rbmanager.Tests/ListRemoteTests.cs | 98 +++++++++++++++++++++++ 6 files changed, 190 insertions(+), 9 deletions(-) create mode 100644 tests/rbmanager.Tests/ListRemoteTests.cs diff --git a/README.md b/README.md index 06f032a..5cd4319 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ rather than after the tool. rbmanager remains the product name. rb setup [--yes] copy rb onto PATH and set up the VC++ runtime rb install install a ruby binary package rb list list installed rubies +rb list --remote list the builds the binary index offers rb use switch the active ruby rb uninstall remove an installed ruby rb msvc run a command with the MSVC build env applied @@ -52,6 +53,12 @@ verified against the sha256 recorded in the index. An unsigned build (all dev snapshots are unsigned) installs with a warning. A zip path or URL skips the index and installs directly. +`list --remote` prints what the index currently offers for this +platform, newest first: the package name, the channel, and the tags +`install` accepts for it. It is the counterpart of `list`, which shows +what is installed, and it exists so that nothing outside rbmanager has +to fetch and interpret the feed. + `msvc` activates an installed Visual Studio (or Build Tools) MSVC toolchain for building C extension gems and runs the rest of the command line under it, as in `rb msvc gem install nokogiri`; diff --git a/src/rbmanager/BinaryIndex.cs b/src/rbmanager/BinaryIndex.cs index f563f09..e45bf5b 100644 --- a/src/rbmanager/BinaryIndex.cs +++ b/src/rbmanager/BinaryIndex.cs @@ -22,7 +22,13 @@ internal static class BinaryIndex ? url : DefaultUrl; - public static async Task Resolve(string query) + public static async Task Resolve(string query) => + Pick(await FetchAll(), query) ?? throw new InvalidOperationException( + $"no binary package matches '{query}' in the index"); + + public static async Task Available() => Available(await FetchAll()); + + private static async Task> FetchAll() { var page = new Uri(Url, UriKind.Absolute); var builds = new List(); @@ -33,8 +39,7 @@ public static async Task Resolve(string query) if (index.Next is null) break; page = new Uri(page, index.Next); } - return Pick(builds, query) ?? throw new InvalidOperationException( - $"no binary package matches '{query}' in the index"); + return builds; } private static async Task Fetch(Uri uri) @@ -56,17 +61,25 @@ internal static IndexPage Parse(string json) // The newest match wins regardless of feed order: series tags like // "4.0" sit on every 4.0.x release, and dev tags like "4.1-dev" on - // every snapshot of the series. Ordering by version, then reissue - // revision (SIGNING.md in ruby/actions), then commit date keeps this - // consistent with Program.Resolve's revision handling for installed - // rubies. + // every snapshot of the series. internal static Build? Pick(IEnumerable builds, string query) => builds .Where(b => b.Platform == Platform) .Where(b => b.Tags.Contains(query, StringComparer.OrdinalIgnoreCase) || string.Equals(b.Name, query, StringComparison.OrdinalIgnoreCase)) - .MaxBy(b => (NumericVersion(b.Version), b.Revision ?? 0, - b.CommitDate ?? b.PublishedAt ?? "", b.Commit ?? "")); + .MaxBy(Rank); + + // Everything installable here, newest first. Same order Pick resolves + // in, so a tag always installs the topmost line carrying it. + internal static Build[] Available(IEnumerable builds) => + builds.Where(b => b.Platform == Platform).OrderByDescending(Rank).ToArray(); + + // Version, then reissue revision (SIGNING.md in ruby/actions), then + // commit date, which keeps this consistent with Program.Resolve's + // revision handling for installed rubies. + private static (Version, int, string, string) Rank(Build b) => + (NumericVersion(b.Version), b.Revision ?? 0, + b.CommitDate ?? b.PublishedAt ?? "", b.Commit ?? ""); // The numeric prefix of `version` ("4.1.0dev" and "4.1.0-rc1" both // compare as 4.1.0). Channel suffixes never decide between two diff --git a/src/rbmanager/Program.cs b/src/rbmanager/Program.cs index c8cdbc2..4b063bf 100644 --- a/src/rbmanager/Program.cs +++ b/src/rbmanager/Program.cs @@ -28,6 +28,7 @@ private static async Task Main(string[] args) ["setup", "--yes" or "-y"] => await Setup(assumeYes: true), ["install", var source] => await Install(source), ["list"] => List(), + ["list", "--remote"] => await ListRemote(), ["use", var name] => Use(name), ["uninstall", var name] => Uninstall(name), // The flag spellings answer too: probing a tool with @@ -58,6 +59,7 @@ setup [--yes] copy rb onto PATH and set up the VC++ runtime install install a ruby binary package resolved from the binary index, or from a zip file or URL list list installed rubies + list --remote list the builds the binary index offers use switch the active ruby uninstall remove an installed ruby msvc run a command with the MSVC build env applied @@ -182,6 +184,27 @@ internal static int List() return 0; } + // The index side of `list`: what this rb can install, so a caller + // never has to fetch and interpret the feed itself. The tags are the + // arguments `install` takes, so they carry the line; the name is what + // the install ends up called. + internal static async Task ListRemote() + { + Build[] builds = await BinaryIndex.Available(); + if (builds.Length == 0) + { + Console.Error.WriteLine( + $"rb: the binary index offers no {BinaryIndex.Platform} builds"); + return 0; + } + int name = builds.Max(b => b.Name.Length); + int channel = builds.Max(b => b.Channel.Length); + foreach (Build b in builds) + Console.WriteLine($"{b.Name.PadRight(name)} {b.Channel.PadRight(channel)} " + + string.Join(", ", b.Tags)); + return 0; + } + internal static int Use(string query) { SwitchTo(Resolve(query)); diff --git a/tests/rbmanager.Tests/BinaryIndexTests.cs b/tests/rbmanager.Tests/BinaryIndexTests.cs index d76068c..7ca579b 100644 --- a/tests/rbmanager.Tests/BinaryIndexTests.cs +++ b/tests/rbmanager.Tests/BinaryIndexTests.cs @@ -158,6 +158,38 @@ public void Pick_ExactName_Resolves() Assert.Equal(b.Name, BinaryIndex.Pick([b], "RUBY-4.0.5-X64-MSWIN64_140")!.Name); } + [Fact] // case 119: the order `rb list --remote` prints, newest first + public void Available_NewestFirst() + { + Build[] builds = + [ + Make("ruby-4.0.4-x64-mswin64_140", "4.0.4", tags: ["4.0.4", "4.0"]), + Make("ruby-4.0.5-x64-mswin64_140", "4.0.5", revision: 0, tags: ["4.0.5-0"]), + Make("ruby-4.0.5-1-x64-mswin64_140", "4.0.5", revision: 1, tags: ["4.0.5-1"]), + ]; + + Assert.Equal( + [ + "ruby-4.0.5-1-x64-mswin64_140", + "ruby-4.0.5-x64-mswin64_140", + "ruby-4.0.4-x64-mswin64_140", + ], + BinaryIndex.Available(builds).Select(b => b.Name).ToArray()); + } + + [Fact] // case 120: builds this rb cannot install are not offered + public void Available_ForeignPlatform_Filtered() + { + Build[] builds = + [ + Make("ruby-4.0.5-arm64-mswin64_140", "4.0.5", platform: "arm64-mswin64_140"), + Make("ruby-4.0.5-x64-mswin64_140", "4.0.5"), + ]; + + Build b = Assert.Single(BinaryIndex.Available(builds)); + Assert.Equal("ruby-4.0.5-x64-mswin64_140", b.Name); + } + [Fact] // case 107 public void Pick_NoMatch_ReturnsNull() { diff --git a/tests/rbmanager.Tests/CliE2eTests.cs b/tests/rbmanager.Tests/CliE2eTests.cs index 5be0c56..9065487 100644 --- a/tests/rbmanager.Tests/CliE2eTests.cs +++ b/tests/rbmanager.Tests/CliE2eTests.cs @@ -48,6 +48,14 @@ public void MissingRequiredArgument_Usage_Exit2(params string[] command) Assert.Contains("usage: rb ", r.Out); } + [Fact] // case 124: --remote is the only flag `list` takes + public void ListWithUnknownFlag_Usage_Exit2() + { + using var sb = new E2eSandbox(); + Assert.Equal(2, sb.Run("list", "--online").ExitCode); + Assert.Equal(2, sb.Run("list", "--remote", "extra").ExitCode); + } + [Fact] // case 37 public void FailingCommand_ErrorToStderr_Exit1_EmptyStdout() { diff --git a/tests/rbmanager.Tests/ListRemoteTests.cs b/tests/rbmanager.Tests/ListRemoteTests.cs new file mode 100644 index 0000000..0681a53 --- /dev/null +++ b/tests/rbmanager.Tests/ListRemoteTests.cs @@ -0,0 +1,98 @@ +using RbManager.Tests.Support; + +namespace RbManager.Tests; + +// `rb list --remote`: the index rendered as columns, with the feed +// redirected to a local file via RBMANAGER_INDEX_URL. Serial (env vars + +// console). +[Trait("Category", "Integration")] +[Collection(Serial.Name)] +public class ListRemoteTests +{ + private const string Dev = "ruby-4.1.0dev-20260821-0123456789-x64-mswin64_140"; + private const string Rel = "ruby-4.0.5-x64-mswin64_140"; + + private static string BuildJson(string name, string version, string channel, + string[] tags, string platform = BinaryIndex.Platform, string? commitDate = null) => $$""" + { + "name": "{{name}}", + "version": "{{version}}", + "channel": "{{channel}}", + "revision": null, + "tags": [{{string.Join(", ", tags.Select(t => $"\"{t}\""))}}], + "platform": "{{platform}}", + "url": "https://example.invalid/{{name}}.zip", + "sha256": "{{new string('0', 64)}}", + "size": 1, + "commit": null, + "commit_date": {{(commitDate is null ? "null" : $"\"{commitDate}\"")}}, + "published_at": null, + "signed": false + } + """; + + private static void WriteIndex(RbSandbox sb, EnvScope env, params string[] builds) + { + string path = Path.Combine(sb.Root, "_index", "index.json"); + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + File.WriteAllText(path, $$""" + {"schema": 1, "next": null, "builds": [{{string.Join(",", builds)}}]} + """); + env.Set("RBMANAGER_INDEX_URL", path); + } + + [Fact] // case 121: name, channel and the tags `install` accepts + public async Task ListsBuildsNewestFirstInColumns() + { + using var sb = new RbSandbox(); + using var cap = new ConsoleCapture(); + using var env = new EnvScope(); + WriteIndex(sb, env, + BuildJson(Rel, "4.0.5", "release", ["4.0.5", "4.0", "4"]), + BuildJson(Dev, "4.1.0dev", "dev", ["ruby-dev", "4.1-dev"], + commitDate: "2026-08-21")); + + int rc = await Program.ListRemote(); + + Assert.Equal(0, rc); + Assert.Equal( + [ + $"{Dev} dev ruby-dev, 4.1-dev", + $"{Rel} release 4.0.5, 4.0, 4", + ], + cap.OutLines); + } + + [Fact] // case 122: an index with nothing for this platform is not an error + public async Task NoBuildsForThePlatform_NotesOnStderr_Exit0() + { + using var sb = new RbSandbox(); + using var cap = new ConsoleCapture(); + using var env = new EnvScope(); + WriteIndex(sb, env, + BuildJson("ruby-4.0.5-arm64-mswin64_140", "4.0.5", "release", ["4.0.5"], + platform: "arm64-mswin64_140")); + + int rc = await Program.ListRemote(); + + Assert.Equal(0, rc); + Assert.Equal("", cap.Out); + Assert.Contains($"no {BinaryIndex.Platform} builds", cap.Err); + } + + [Fact] // case 123: an index this rb does not understand fails here too + public async Task UnsupportedSchema_Throws() + { + using var sb = new RbSandbox(); + using var cap = new ConsoleCapture(); + using var env = new EnvScope(); + string path = Path.Combine(sb.Root, "_index", "index.json"); + Directory.CreateDirectory(Path.GetDirectoryName(path)!); + File.WriteAllText(path, """{"schema": 2, "next": null, "builds": []}"""); + env.Set("RBMANAGER_INDEX_URL", path); + + var ex = await Assert.ThrowsAsync(Program.ListRemote); + + Assert.Contains("schema 2", ex.Message); + } +} From 65cd0f7391207cf4454916c3c35103fd5ef3323d Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 10 Sep 2026 09:35:34 +0900 Subject: [PATCH 3/5] Name the running rb in the index schema error The schema number is the only channel the feed has for telling an old rb that it is old, and "upgrade rb" left the reader to work out which rb had answered and where a newer one comes from. Co-Authored-By: Claude Opus 5 --- README.md | 6 ++++++ src/rbmanager/BinaryIndex.cs | 7 ++++++- src/rbmanager/Program.cs | 2 ++ tests/rbmanager.Tests/BinaryIndexTests.cs | 5 +++-- tests/rbmanager.Tests/InstallFromIndexTests.cs | 2 +- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5cd4319..25cb11b 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,12 @@ platform, newest first: the package name, the channel, and the tags what is installed, and it exists so that nothing outside rbmanager has to fetch and interpret the feed. +The feed's `schema` number is how an index that has moved on tells an +old rb so. Every command that reads the index (`install`, +`list --remote`) fails on an unknown schema with the running version +and , which is the one +signal rb can give about its own age. + `msvc` activates an installed Visual Studio (or Build Tools) MSVC toolchain for building C extension gems and runs the rest of the command line under it, as in `rb msvc gem install nokogiri`; diff --git a/src/rbmanager/BinaryIndex.cs b/src/rbmanager/BinaryIndex.cs index e45bf5b..706a6a6 100644 --- a/src/rbmanager/BinaryIndex.cs +++ b/src/rbmanager/BinaryIndex.cs @@ -53,9 +53,14 @@ internal static IndexPage Parse(string json) { IndexPage page = JsonSerializer.Deserialize(json, IndexJsonContext.Default.IndexPage) ?? throw new InvalidOperationException("the binary index is empty"); + // The schema number is the only channel the feed has for telling + // an old rb that it is old, so the message names the running + // build and where a newer one comes from instead of leaving the + // reader to work out which rb answered. if (page.Schema != 1) throw new InvalidOperationException( - $"the binary index has schema {page.Schema}, which this rb does not understand; upgrade rb"); + $"{Program.SelfVersion()} does not understand schema {page.Schema} " + + $"of the binary index. Upgrade from {Program.ReleasesUrl}"); return page; } diff --git a/src/rbmanager/Program.cs b/src/rbmanager/Program.cs index 4b063bf..8d580dd 100644 --- a/src/rbmanager/Program.cs +++ b/src/rbmanager/Program.cs @@ -18,6 +18,8 @@ internal static class Program private static string Rubies => Path.Combine(Root, "rubies"); private static string Current => Path.Combine(Root, "current"); + internal const string ReleasesUrl = "https://github.com/ruby/rbmanager/releases"; + private static async Task Main(string[] args) { try diff --git a/tests/rbmanager.Tests/BinaryIndexTests.cs b/tests/rbmanager.Tests/BinaryIndexTests.cs index 7ca579b..8654aef 100644 --- a/tests/rbmanager.Tests/BinaryIndexTests.cs +++ b/tests/rbmanager.Tests/BinaryIndexTests.cs @@ -68,13 +68,14 @@ public void Parse_PublishedShape_PopulatesEveryKey() Assert.False(b.Signed); } - [Fact] // case 100 + [Fact] // case 100: an rb older than the feed names itself and the remedy public void Parse_UnsupportedSchema_Throws() { var ex = Assert.Throws( () => BinaryIndex.Parse("""{"schema": 2, "next": null, "builds": []}""")); Assert.Contains("schema 2", ex.Message); - Assert.Contains("upgrade rb", ex.Message); + Assert.StartsWith(Program.SelfVersion(), ex.Message); + Assert.Contains(Program.ReleasesUrl, ex.Message); } [Fact] // case 101: a series tag sits on every release of the series diff --git a/tests/rbmanager.Tests/InstallFromIndexTests.cs b/tests/rbmanager.Tests/InstallFromIndexTests.cs index f628a29..0eab05e 100644 --- a/tests/rbmanager.Tests/InstallFromIndexTests.cs +++ b/tests/rbmanager.Tests/InstallFromIndexTests.cs @@ -156,7 +156,7 @@ public async Task InstallNewerSchema_Throws() var ex = await Assert.ThrowsAsync( () => Program.Install("4.1-dev")); - Assert.Contains("upgrade rb", ex.Message); + Assert.Contains(Program.ReleasesUrl, ex.Message); } [Fact] // case 116 From aaf8518e04729c648a717c2be53d7e39e1f60d79 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 10 Sep 2026 09:36:10 +0900 Subject: [PATCH 4/5] Record the new cases in the test plan Co-Authored-By: Claude Opus 5 --- docs/test-plan.md | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/docs/test-plan.md b/docs/test-plan.md index cae1e7f..407a958 100644 --- a/docs/test-plan.md +++ b/docs/test-plan.md @@ -417,6 +417,8 @@ values are whatever the build stamped in and the tests pin the shape. 88. (E2E) `rb version` → exit 0 and one line matching `rbmanager ( )`, the parenthetical optional. +118. (E2E) `rb --version` and `rb -V` print that same line and exit 0, + so probing an unknown rb never lands in usage. 89. (Unit) `FormatVersion` with all three present → the full cargo-shaped line. 90. (Unit) `FormatVersion` with the commit, the date, or both missing → @@ -450,8 +452,8 @@ Unit (`BinaryIndexTests`): 99. `Parse` on a page in the published feed's shape → every key of the build populated, including the snake_case `commit_date` / `published_at` mappings. -100. `Parse` with `schema: 2` → error naming the schema and telling the - user to upgrade rb. +100. `Parse` with `schema: 2` → error naming the schema, the running + `SelfVersion`, and the releases page to upgrade from. 101. A series tag (`4.0`, `4`) sits on every release of the series → the highest version wins, in either feed order. 102. Two revisions of one version → the higher revision wins, in either @@ -478,7 +480,7 @@ Integration (`InstallFromIndexTests`, Serial): 113. A non-null `next` chains to the following page (relative to the feed URL). 114. `RBMANAGER_INDEX_URL` accepts a `file://` URL. -115. `schema: 2` in the feed → the upgrade-rb error, nothing installed. +115. `schema: 2` in the feed → the upgrade error, nothing installed. 116. No matching build → `no binary package matches '' in the index`. 117. A missing zip path (`.zip` suffix or path separator) fails as a missing file and never falls through to index resolution. @@ -490,6 +492,30 @@ Network (`BinaryIndexNetworkTests`, `Category=Network`, gated on `x64-mswin64_140` build with a well-formed sha256 and a cache.ruby-lang.org URL. +### 4.14 Program + BinaryIndex: `rb list --remote` + +The same feed and the same `RBMANAGER_INDEX_URL` seam as 4.13, rendered +instead of installed: one line per build for this platform, newest +first, in the order `Pick` resolves. + +Unit (`BinaryIndexTests`): + +119. `Available` orders newest first, version before revision. +120. `Available` drops builds of other platforms. + +Integration (`ListRemoteTests`, Serial): + +121. Name, channel and the `install` tags, newest first, in aligned + columns. +122. An index with nothing for this platform → empty stdout, a note on + stderr, exit 0. +123. `schema: 2` fails here as it does on install. + +E2E (`CliE2eTests`): + +124. `--remote` is the only flag `list` takes, and it takes no + argument; anything else is usage and exit 2. + ## 5. Execution plan Phased so each phase leaves the tree green. From 4cae45fec929bee6136bfb4d9dfe28e56ef0c068 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 10 Sep 2026 09:38:37 +0900 Subject: [PATCH 5/5] Tighten the comments on the new commands Co-Authored-By: Claude Opus 5 --- src/rbmanager/BinaryIndex.cs | 4 +--- src/rbmanager/Program.cs | 13 ++++++------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/rbmanager/BinaryIndex.cs b/src/rbmanager/BinaryIndex.cs index 706a6a6..2376e5f 100644 --- a/src/rbmanager/BinaryIndex.cs +++ b/src/rbmanager/BinaryIndex.cs @@ -54,9 +54,7 @@ internal static IndexPage Parse(string json) IndexPage page = JsonSerializer.Deserialize(json, IndexJsonContext.Default.IndexPage) ?? throw new InvalidOperationException("the binary index is empty"); // The schema number is the only channel the feed has for telling - // an old rb that it is old, so the message names the running - // build and where a newer one comes from instead of leaving the - // reader to work out which rb answered. + // an old rb that it is old. if (page.Schema != 1) throw new InvalidOperationException( $"{Program.SelfVersion()} does not understand schema {page.Schema} " + diff --git a/src/rbmanager/Program.cs b/src/rbmanager/Program.cs index 8d580dd..0195de0 100644 --- a/src/rbmanager/Program.cs +++ b/src/rbmanager/Program.cs @@ -33,9 +33,9 @@ private static async Task Main(string[] args) ["list", "--remote"] => await ListRemote(), ["use", var name] => Use(name), ["uninstall", var name] => Uninstall(name), - // The flag spellings answer too: probing a tool with - // --version is how a caller identifies the build it got, - // and falling to usage there reads as a broken binary. + // Probing a tool with --version is how a caller identifies + // the build it got, so answering with usage reads as a + // broken binary rather than as an old one. ["version" or "--version" or "-V"] => Version(), // Everything after `msvc` belongs to Msvc's own parser: it // owns one reserved word (`enable`) and passes the rest @@ -186,10 +186,9 @@ internal static int List() return 0; } - // The index side of `list`: what this rb can install, so a caller - // never has to fetch and interpret the feed itself. The tags are the - // arguments `install` takes, so they carry the line; the name is what - // the install ends up called. + // The index side of `list`, so that finding a build never requires + // fetching and interpreting the feed. The tags are the arguments + // `install` takes, which is why they carry the line. internal static async Task ListRemote() { Build[] builds = await BinaryIndex.Available();