diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b315b5c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +# Everything in this repository is consumed on Linux: deploy/bootstrap.sh is embedded +# verbatim by bootstrap_asset.go and piped into `bash -s`, the Dockerfiles and entrypoints +# are read inside the images, and the operator ships YAML. Without eol=lf a Windows +# checkout under core.autocrlf=true hands all of them CRs. +* text=auto eol=lf + +# The gradle wrappers' Windows launchers are the one thing that wants CRLF. +*.bat text eol=crlf diff --git a/bootstrap_asset_test.go b/bootstrap_asset_test.go index b54c803..78914f8 100644 --- a/bootstrap_asset_test.go +++ b/bootstrap_asset_test.go @@ -73,9 +73,15 @@ func TestLobbyLuckPermsWiringIsConsistent(t *testing.T) { // default it can inherit — and nothing else in the install would notice it missing. The failure // surfaces only when a legacy player joins, on a host that installed cleanly. func TestBootstrapPinsViaBlockConnectionsOff(t *testing.T) { - // go:embed takes the working tree verbatim, and this repository pins no eol attribute, so - // a Windows checkout embeds CRLF. Only the assertion spanning a line break below cares. - script := strings.ReplaceAll(BootstrapScript(), "\r\n", "\n") + // go:embed takes the working tree verbatim, so the eol attribute is what keeps a Windows + // checkout from compiling CRs into the installer. Assert it rather than normalizing them + // away: the only assertion that would otherwise notice is the one spanning a line break + // below, and it would report a missing pin instead of the line endings. + script := BootstrapScript() + if strings.Contains(script, "\r\n") { + t.Fatal("embedded bootstrap.sh has CRLF line endings; .gitattributes pins *.sh to LF " + + "and this script is piped into `bash -s` on a Linux host") + } const key = "serverside-blockconnections" if !strings.Contains(script, key+": false") { diff --git a/cmd/felis/version.go b/cmd/felis/version.go index f3e983c..7654327 100644 --- a/cmd/felis/version.go +++ b/cmd/felis/version.go @@ -1,66 +1,66 @@ -package main - -import ( - "fmt" - "io" - "runtime" - "runtime/debug" -) - -// version is the build stamp injected at link time via -// -// -ldflags "-X main.version=v1.2.3" (release channel: the tag verbatim) -// -ldflags "-X main.version=v1.2.3+g1a2b3c4" (dev channel: tag + build metadata) -// -// deploy/bootstrap.sh computes it per install channel (FELIS_VERSION_BOOTSTRAP): -// the release channel stamps the resolved tag verbatim (v1.2.3), the dev channel -// stamps "+g". It stays "dev" for an un-stamped local -// `go build`, where ReadBuildInfo below still surfaces the vcs revision. -// -// NOT `git describe`, for two reasons that both bite. Its "--g" form -// puts the distance in the PRERELEASE field, which sorts BELOW the bare tag, so a -// dev build ahead of v1.2.3 would compare as older than v1.2.3 and `felis update` -// would propose "upgrading" onto the release it already contains — hence "+", which -// is build metadata and ignored for ordering. And bootstrap's primary clone is -// --depth 1, which carries no tags, so describe would fall back to a bare SHA that -// updates.Parse rejects outright. -var version = "dev" - -// cmdVersion prints the build stamp. It takes no flags and never touches the -// cluster, so it is safe to run as any user (unlike setup/breakGlass). -func cmdVersion(args []string, stdout, stderr io.Writer) int { - fmt.Fprintf(stdout, "felis %s\n", resolvedVersion()) - fmt.Fprintf(stdout, " go: %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH) - if rev, ok := vcsRevision(); ok { - fmt.Fprintf(stdout, " revision: %s\n", rev) - } - return 0 -} - -// resolvedVersion prefers the ldflag stamp, then the module version recorded by -// `go install`, and only reports "unknown" when neither is present. -func resolvedVersion() string { - if version != "" { - return version - } - if bi, ok := debug.ReadBuildInfo(); ok && bi.Main.Version != "" { - return bi.Main.Version - } - return "unknown" -} - -// vcsRevision returns the git commit the binary was built from when the build -// carried VCS stamping (local `go build` in a checkout; the docker build strips -// .git, so there the ldflag version carries the identity instead). -func vcsRevision() (string, bool) { - bi, ok := debug.ReadBuildInfo() - if !ok { - return "", false - } - for _, s := range bi.Settings { - if s.Key == "vcs.revision" && s.Value != "" { - return s.Value, true - } - } - return "", false -} +package main + +import ( + "fmt" + "io" + "runtime" + "runtime/debug" +) + +// version is the build stamp injected at link time via +// +// -ldflags "-X main.version=v1.2.3" (release channel: the tag verbatim) +// -ldflags "-X main.version=v1.2.3+g1a2b3c4" (dev channel: tag + build metadata) +// +// deploy/bootstrap.sh computes it per install channel (FELIS_VERSION_BOOTSTRAP): +// the release channel stamps the resolved tag verbatim (v1.2.3), the dev channel +// stamps "+g". It stays "dev" for an un-stamped local +// `go build`, where ReadBuildInfo below still surfaces the vcs revision. +// +// NOT `git describe`, for two reasons that both bite. Its "--g" form +// puts the distance in the PRERELEASE field, which sorts BELOW the bare tag, so a +// dev build ahead of v1.2.3 would compare as older than v1.2.3 and `felis update` +// would propose "upgrading" onto the release it already contains — hence "+", which +// is build metadata and ignored for ordering. And bootstrap's primary clone is +// --depth 1, which carries no tags, so describe would fall back to a bare SHA that +// updates.Parse rejects outright. +var version = "dev" + +// cmdVersion prints the build stamp. It takes no flags and never touches the +// cluster, so it is safe to run as any user (unlike setup/breakGlass). +func cmdVersion(args []string, stdout, stderr io.Writer) int { + fmt.Fprintf(stdout, "felis %s\n", resolvedVersion()) + fmt.Fprintf(stdout, " go: %s %s/%s\n", runtime.Version(), runtime.GOOS, runtime.GOARCH) + if rev, ok := vcsRevision(); ok { + fmt.Fprintf(stdout, " revision: %s\n", rev) + } + return 0 +} + +// resolvedVersion prefers the ldflag stamp, then the module version recorded by +// `go install`, and only reports "unknown" when neither is present. +func resolvedVersion() string { + if version != "" { + return version + } + if bi, ok := debug.ReadBuildInfo(); ok && bi.Main.Version != "" { + return bi.Main.Version + } + return "unknown" +} + +// vcsRevision returns the git commit the binary was built from when the build +// carried VCS stamping (local `go build` in a checkout; the docker build strips +// .git, so there the ldflag version carries the identity instead). +func vcsRevision() (string, bool) { + bi, ok := debug.ReadBuildInfo() + if !ok { + return "", false + } + for _, s := range bi.Settings { + if s.Key == "vcs.revision" && s.Value != "" { + return s.Value, true + } + } + return "", false +}