diff --git a/base.go b/base.go index 2a29174..b834b33 100644 --- a/base.go +++ b/base.go @@ -1,5 +1,7 @@ package version +import "strings" + const ( unknownVersion = "(devel)" unknownProperty = "N/A" @@ -14,3 +16,73 @@ var ( commitDate = unknownProperty dirtyBuild = unknownProperty ) + +// A Struct for Version Fields +type Field uint16 + +const ( + FieldMeta Field = 1 << iota + FieldVersion + FieldGitCommit + FieldBuildDate + FieldCommitDate + FieldDirtyBuild + FieldGoVersion + FieldCompiler + FieldPlatform + FieldExtraFields + + typeRevMaxKey +) + +// common presets +const ( + AllFields Field = GoRuntimeFields | VCSFields | FieldMeta | FieldVersion | FieldExtraFields + GoRuntimeFields = FieldGoVersion | FieldCompiler | FieldPlatform + VCSFields = FieldGitCommit | FieldBuildDate | FieldCommitDate | FieldDirtyBuild +) + +// Returns the string value for a Field struct +func (f Field) String() string { + if f >= typeRevMaxKey { + return "unknown" + } + + switch f { + case FieldVersion: + return "Version" + case FieldGitCommit: + return "GitCommit" + case FieldBuildDate: + return "BuildDate" + case FieldCommitDate: + return "CommitDate" + case FieldDirtyBuild: + return "DirtyBuild" + case FieldGoVersion: + return "GoVersion" + case FieldCompiler: + return "Compiler" + case FieldPlatform: + return "Platform" + case FieldMeta: + return "Meta" + case FieldExtraFields: + return "ExtraFields" + case AllFields: + return "AllFields" + case GoRuntimeFields: + return "GoRuntimeFields" + case VCSFields: + return "VCSFields" + } + + // Print Multiple Fields + var fields []string + for key := FieldMeta; key < typeRevMaxKey; key <<= 1 { + if f&key != 0 { + fields = append(fields, key.String()) + } + } + return strings.Join(fields, " | ") +} diff --git a/printer/opts.go b/printer/opts.go index b1f7498..94c1f49 100644 --- a/printer/opts.go +++ b/printer/opts.go @@ -7,6 +7,7 @@ import ( "gopkg.in/yaml.v3" + "go.szostok.io/version" "go.szostok.io/version/style" "go.szostok.io/version/upgrade" ) @@ -32,6 +33,7 @@ type ( PrettyOptions []PrettyOption PostHookFunc PostHookFunc UpgradeNotice *upgrade.GitHubDetector + ExcludedField version.Field } // PrettyOption provides an option to set a Pretty printer options. @@ -248,3 +250,28 @@ func parseConfigFile(fileName string) (*CustomPrettyStyle, error) { cfg: styles, }, err } + +// ExcludedFields provides an option to store the version fields that are excluded by the user +type ExcludedFields struct { + Fields version.Field +} + +// ApplyToContainerOption sets a given option for Container. +func (c *ExcludedFields) ApplyToContainerOption(cfg *ContainerOptions) { + cfg.ExcludedField = c.Fields +} + +// WithOmitUnset excludes version fields that have not been set. +// version fields with the values `N/A` or `(devel)“ will be excluded +func WithOmitUnset() *ExcludedFields { + return &ExcludedFields{ + Fields: version.UnsetFields(), + } +} + +// WithExcludedFields sets the excluded fields for a Container. +func WithExlcudedFields(field version.Field) *ExcludedFields { + return &ExcludedFields{ + Fields: field, + } +} diff --git a/printer/printer.go b/printer/printer.go index 6f574dc..93ae4e7 100644 --- a/printer/printer.go +++ b/printer/printer.go @@ -27,6 +27,7 @@ type Container struct { printers map[OutputFormat]Printer postHookFunc PostHookFunc upgradeNotice *upgrade.GitHubDetector + excludedField version.Field } // New returns a new Container instance. @@ -46,6 +47,7 @@ func New(options ...ContainerOption) *Container { output: PrettyFormat, postHookFunc: opts.PostHookFunc, upgradeNotice: opts.UpgradeNotice, + excludedField: opts.ExcludedField, } } @@ -60,9 +62,9 @@ func (r *Container) OutputFormat() OutputFormat { } // Print prints Info object in a requested format. -// It's just a syntax sugar for PrintInfo(w, version.Get()). +// It's just a syntax sugar for PrintInfo(w, version.GetInfo(excludedFields)). func (r *Container) Print(w io.Writer) error { - return r.PrintInfo(w, version.Get()) + return r.PrintInfo(w, version.GetInfo(r.excludedField)) } // PrintInfo prints a given Info object in a requested format. diff --git a/version.go b/version.go index 04a42b5..6a22993 100644 --- a/version.go +++ b/version.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "os" + "reflect" "runtime" "runtime/debug" "strconv" @@ -132,6 +133,39 @@ func Get() *Info { } } +// GetInfo returns an `Info` struct. The excluded fields are set to their default values +func GetInfo(excludedFields Field) *Info { + updatedInfo := Get() + for key := FieldMeta; key < typeRevMaxKey; key <<= 1 { + if excludedFields&key != 0 { + setToDefault(updatedInfo, key.String()) + } + } + + return updatedInfo +} + +// UnsetFields returns version Fields that have not been set +func UnsetFields() Field { + info := Get() + var fields Field + for key := FieldMeta; key < typeRevMaxKey; key <<= 1 { + fieldValue := reflect.ValueOf(info).Elem().FieldByName(key.String()).String() + if fieldValue == unknownProperty || fieldValue == unknownVersion { + fields |= key + } + } + return fields +} + +// setToDefault sets a given field in an Info struct to its default value +func setToDefault(info *Info, fieldName string) { + reflectValue := reflect.ValueOf(info).Elem() + fieldValue := reflectValue.FieldByName(fieldName) + defaultValue := reflect.Zero(fieldValue.Type()) + fieldValue.Set(defaultValue) +} + // collectFromBuildInfo tries to set the build information embedded in the running binary via Go module. // It doesn't override data if were already set by Go -ldflags. func collectFromBuildInfo() {