From 88f20d488039dcf445748b0d19af492bd0d21997 Mon Sep 17 00:00:00 2001 From: Ben Meier Date: Fri, 10 May 2024 12:28:21 +0100 Subject: [PATCH] feat: added version and logging levels --- internal/logging/logging.go | 53 +++++++++++++++++++++++++++++++++++++ internal/version/version.go | 48 +++++++++++++++++++++++++++++++++ main.go | 31 +++++++++++++++++++++- 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 internal/logging/logging.go create mode 100644 internal/version/version.go diff --git a/internal/logging/logging.go b/internal/logging/logging.go new file mode 100644 index 0000000..fd9af9b --- /dev/null +++ b/internal/logging/logging.go @@ -0,0 +1,53 @@ +// Copyright 2024 Humanitec +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package logging + +import ( + "context" + "fmt" + "io" + "log/slog" + "sync" +) + +type SimpleHandler struct { + Writer io.Writer + Level slog.Leveler + + mu sync.Mutex +} + +func (h *SimpleHandler) Enabled(ctx context.Context, level slog.Level) bool { + return level >= h.Level.Level() +} + +func (h *SimpleHandler) Handle(ctx context.Context, record slog.Record) error { + h.mu.Lock() + defer h.mu.Unlock() + _, err := h.Writer.Write([]byte(fmt.Sprintf("%s: %s\n", record.Level.String(), record.Message))) + return err +} + +func (h *SimpleHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + // no support for attrs here + return h +} + +func (h *SimpleHandler) WithGroup(name string) slog.Handler { + // no support for attrs here + return h +} + +var _ slog.Handler = (*SimpleHandler)(nil) diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..6836a09 --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,48 @@ +// Copyright 2024 Humanitec +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package version + +import ( + "fmt" + "runtime/debug" +) + +var ( + Version string = "0.0.0" +) + +// BuildVersionString constructs a version string by looking at the build metadata injected at build time. +// This is particularly useful when score-compose is stilled from the go module using go install. +func BuildVersionString() string { + versionNumber, buildTime, gitSha, isDirtySuffix := Version, "local", "unknown", "" + if info, ok := debug.ReadBuildInfo(); ok { + if info.Main.Version != "" && info.Main.Version != "(devel)" { + versionNumber = info.Main.Version + } + for _, setting := range info.Settings { + switch setting.Key { + case "vcs.time": + buildTime = setting.Value + case "vcs.revision": + gitSha = setting.Value + case "vcs.modified": + if setting.Value == "true" { + isDirtySuffix = "-dirty" + } + } + } + } + return fmt.Sprintf("%s (build: %s, sha: %s%s)", versionNumber, buildTime, gitSha, isDirtySuffix) +} diff --git a/main.go b/main.go index e95a6f1..ee4225e 100644 --- a/main.go +++ b/main.go @@ -16,18 +16,47 @@ package main import ( "fmt" + "io" + "log/slog" "os" "github.com/spf13/cobra" + + "github.com/score-spec/score-k8s/internal/logging" + "github.com/score-spec/score-k8s/internal/version" ) var rootCmd = &cobra.Command{ - Use: "score-k8s", + Use: "score-k8s", + Short: "Score to Kubernetes manifest translator", + Long: `Score is a specification for defining environment agnostic configuration for cloud based workloads. +This tool produces a file of Kubernetes manifests from the Score specification.`, SilenceErrors: true, + + // This function always runs for all subcommands + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if q, _ := cmd.Flags().GetBool("quiet"); q { + slog.SetDefault(slog.New(&logging.SimpleHandler{Level: slog.LevelError, Writer: io.Discard})) + } else if v, _ := cmd.Flags().GetCount("verbose"); v == 0 { + slog.SetDefault(slog.New(&logging.SimpleHandler{Level: slog.LevelInfo, Writer: cmd.ErrOrStderr()})) + } else if v == 1 { + slog.SetDefault(slog.New(&logging.SimpleHandler{Level: slog.LevelDebug, Writer: cmd.ErrOrStderr()})) + } else if v == 2 { + slog.SetDefault(slog.New(slog.NewTextHandler(cmd.ErrOrStderr(), &slog.HandlerOptions{ + Level: slog.LevelDebug, AddSource: true, + }))) + } + return nil + }, } func init() { + rootCmd.Version = version.BuildVersionString() + rootCmd.SetVersionTemplate(`{{with .Name}}{{printf "%s " .}}{{end}}{{printf "%s" .Version}} +`) rootCmd.CompletionOptions = cobra.CompletionOptions{HiddenDefaultCmd: true} + rootCmd.PersistentFlags().Bool("quiet", false, "Mute any logging output") + rootCmd.PersistentFlags().CountP("verbose", "v", "Increase log verbosity and detail by specifying this flag one or more times") } func main() {