From d636c731f53a52c1cf25f3e7bddcf2dc77711921 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Sat, 25 Jan 2025 14:45:05 +0100 Subject: [PATCH] usage, completion: assume executable is always lowercase When running on a case-insensitive platform / filesystem, the user can invoke the executable using any case (e.g., "bUiLdX"). In situations where buildx is running standalone, we use os.Args to determine the name of the executable, and this information is used by Cobra to print "Usage" output as well as generating the shell-completion scripts. Unfortunately, neither [os.Executable] nor [os.Stat] provide information about the actual name of the executable, and the "correct" solution would be to use [os.File.Readdirnames], which is a rather heavy hammer to use just for this. This patch assumes the executable to be named lowercase, regardless of how it's invoked, on macOS and Windows (usually case-insensitive platforms). It's worth noting that there's a corner-case to this corner-case; both Windows and macOS can be configured to use a case-sensitive filesystem (on Windows, this can be configured per-Directory). If that is the case, and the executable is not lowercase, the generated shell-completion script will be invalid. Let's assume that's not the case, and that the user did not rename the executable to anything uppercase. Before this patch: ./bin/build/bUiLdX --help | head -n 5 Extended build capabilities with BuildKit Usage: bUiLdX bUiLdX [command] ./bin/build/bUiLdX completion bash | head -n 3 # bash completion V2 for bUiLdX -*- shell-script -*- __bUiLdX_debug() With this patch applied: ./bin/build/bUiLdX --help | head -n 5 Extended build capabilities with BuildKit Usage: buildx buildx [command] ./bin/build/bUiLdX completion bash | head -n 3 # bash completion V2 for buildx -*- shell-script -*- __buildx_debug() [os.Executable]: https://pkg.go.dev/os#Executable [os.Stat]: https://pkg.go.dev/os#Stat [os.File.Readdirnames]: https://pkg.go.dev/os#File.Readdirnames Signed-off-by: Sebastiaan van Stijn --- cmd/buildx/main.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/cmd/buildx/main.go b/cmd/buildx/main.go index 61f3f630988..66cee52dce6 100644 --- a/cmd/buildx/main.go +++ b/cmd/buildx/main.go @@ -5,6 +5,8 @@ import ( "fmt" "os" "path/filepath" + "runtime" + "strings" "github.com/docker/buildx/commands" controllererrors "github.com/docker/buildx/controller/errdefs" @@ -43,6 +45,30 @@ func runStandalone(cmd *command.DockerCli) error { defer flushMetrics(cmd) executable := os.Args[0] + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + // Note that we're cutting some corners here. The intent here + // is for both "usage" and shell-completion scripts to use the + // name of the executable with its actual (lower, upper) case. + // However, on case-insensitive platforms, the user can invoke + // the executable using any case (e.g., "bUiLdX"). + // + // Unfortunately, neither [os.Executable] nor [os.Stat] provide + // this information, and the "correct" solution would be to use + // [os.File.Readdirnames], which is a rather heavy hammer to use + // just for this. + // + // So, on macOS and Windows (usually case-insensitive platforms) + // we assume the executable is always lower-case, but it's worth + // noting that there's a corner-case to this corner-case; both + // Windows and macOS can be configured to use a case-sensitive + // filesystem (on Windows, this can be configured per-Directory). + // If that is the case, and the executable is not lowercase, the + // generated shell-completion script will be invalid. + // + // Let's assume that's not the case, and that the user did not + // rename the executable to anything uppercase. + executable = strings.ToLower(executable) + } rootCmd := commands.NewRootCmd(filepath.Base(executable), false, cmd) return rootCmd.Execute() }