diff --git a/package/buildinfo/build_info.go b/package/buildinfo/build_info.go new file mode 100644 index 00000000..10296b7d --- /dev/null +++ b/package/buildinfo/build_info.go @@ -0,0 +1,150 @@ +package buildinfo + +import ( + "fmt" + "strings" +) + +var Version string +var BuildTime string +var Builder string +var BuildOS string +var Custom string + +type FlagSet struct { + flgs map[string]string +} + +// Load loads all build flags targeted with -ldflags and +// returns a FlagSet for retrieving flags later +func Load() FlagSet { + f := FlagSet{flgs: make(map[string]string)} + + f.flgs["v"] = Version + f.flgs["bt"] = BuildTime + f.flgs["b"] = Builder + f.flgs["bOS"] = BuildOS + f.flgs["c"] = Custom + + return f +} + +func buildAll(first bool, all, k, v string) string { + switch k { + case "v": + k = "Version" + case "b": + k = "Builder" + case "bt": + k = "Build Time" + case "bOS": + k = "Build OS" + case "c": + k = "Custom" + } + + if first { + all = fmt.Sprintf("%s %s=%s", all, strings.TrimSpace(k), strings.TrimSpace(v)) + } else { + all = fmt.Sprintf("%s, %s=%s", all, strings.TrimSpace(k), strings.TrimSpace(v)) + } + + return all +} + +// All returns all the set buildinfo flags in f as a string, following +// the pattern "All set build info flags by key/value pairs: k=v" where +// k is the specific flag set and v is the value assigned to k. This method +// does not comma-separate Custom buildinfo flags. To return a string with +// comma-separated Custom buildinfo flags, use AllSeparated() +func (f FlagSet) All() string { + all := "All set build info flags by key/value pairs:" + + first := true + for k, v := range f.flgs { + if k == "" { + continue + } + + all = buildAll(first, all, k, v) + + if first { + first = false + } + } + + return all +} + +// AllSeparated returns all the set buildinfo flags in f as a string, following +// the pattern "All set build info flags by key/value pairs: k=v" where +// k is the specific flag set and v is the value assigned to k. This method +// comma-separates Custom buildinfo flags. To return a string without Custom +// buildinfo flags being comma-separated, use All() +func (f FlagSet) AllSeparated() string { + all := "All set build info flags by key/value pairs:" + + first := true + for k, v := range f.flgs { + switch k { + case "": + continue + case "c": + split := strings.Split(v, ",") + for _, val := range split { + kv := strings.Split(val, "=") + key := strings.TrimSpace(kv[0]) + value := strings.TrimSpace(kv[1]) + all = buildAll(first, all, key, value) + } + default: + all = buildAll(first, all, k, v) + } + if first { + first = false + } + } + + return all +} + +// Version returns the value set for the Version buildinfo flag +func (f FlagSet) Version() string { + return f.flgs["v"] +} + +// BuildTime returns the value set for the BuildTime buildinfo flag +func (f FlagSet) BuildTime() string { + return f.flgs["bt"] +} + +// Builder returns the value set for the Builder buildinfo flag +func (f FlagSet) Builder() string { + return f.flgs["b"] +} + +// BuildOS returns the value set for the BuildOS buildinfo flag +func (f FlagSet) BuildOS() string { + return f.flgs["bOS"] +} + +// Custom returns a map of Custom buildinfo flags with the values +// split on commas, and then each split into a key/value pair on "=" +// and stored into the returned map. If no Custom buildinfo flags +// were set, then this method returns nil +func (f FlagSet) Custom() map[string]string { + if _, ok := f.flgs["c"]; !ok { + return nil + } + + cv := make(map[string]string) + + c := strings.Split(f.flgs["c"], ",") + + for _, custom := range c { + kv := strings.Split(custom, "=") + cv[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1]) + } + + return cv +} diff --git a/package/buildinfo/build_info_test.go b/package/buildinfo/build_info_test.go new file mode 100644 index 00000000..341eda7e --- /dev/null +++ b/package/buildinfo/build_info_test.go @@ -0,0 +1,94 @@ +package buildinfo + +import ( + "github.com/livebud/bud/internal/is" + "testing" + "time" +) + +func TestLoad(t *testing.T) { + Version = "1" + BuildTime = time.RFC3339 + Builder = "test builder" + BuildOS = "Darwin" + Custom = "key1=value1,key2=value2,key3=value3" + TestCustom := make(map[string]string) + TestCustom["key1"] = "value1" + TestCustom["key2"] = "value2" + TestCustom["key3"] = "value3" + + flags := Load() + + is := is.New(t) + is.Equal(5, len(flags.flgs)) + is.Equal(Version, flags.Version()) + is.Equal(BuildTime, flags.BuildTime()) + is.Equal(Builder, flags.Builder()) + for k, v := range flags.Custom() { + is.Equal(TestCustom[k], v) + } +} + +func TestLoad_SpacesInCustom(t *testing.T) { + Version = "1" + BuildTime = time.RFC3339 + Builder = "test builder" + BuildOS = "Darwin" + Custom = "key1=value1, key2= value2,key3 =value3 " + TestCustom := make(map[string]string) + TestCustom["key1"] = "value1" + TestCustom["key2"] = "value2" + TestCustom["key3"] = "value3" + + flags := Load() + + is := is.New(t) + is.Equal(Version, flags.Version()) + is.Equal(BuildTime, flags.BuildTime()) + is.Equal(Builder, flags.Builder()) + for k, v := range flags.Custom() { + is.Equal(TestCustom[k], v) + } +} + +func TestAll(t *testing.T) { + Version = "1" + BuildTime = time.RFC3339 + Builder = "test builder" + BuildOS = "Darwin" + Custom = "key1=value1,key2=value2,key3=value3 " + TestCustom := make(map[string]string) + TestCustom["key1"] = "value1" + TestCustom["key2"] = "value2" + TestCustom["key3"] = "value3" + + flags := Load() + + expected := "All set build info flags by key/value pairs: Version=1, Build Time=2006-01-02T15:04:05Z07:00, Builder=test builder, Build OS=Darwin, Custom=key1=value1,key2=value2,key3=value3" + all := flags.All() + + is := is.New(t) + + is.Equal(len(expected), len(all)) +} + +func TestAllSeparated(t *testing.T) { + Version = "1" + BuildTime = time.RFC3339 + Builder = "test builder" + BuildOS = "Darwin" + Custom = "key1=value1,key2=value2,key3=value3 " + TestCustom := make(map[string]string) + TestCustom["key1"] = "value1" + TestCustom["key2"] = "value2" + TestCustom["key3"] = "value3" + + flags := Load() + + expected := "All set build info flags by key/value pairs: Version=1, Build Time=2006-01-02T15:04:05Z07:00, Builder=test builder, Build OS=Darwin, key1=value1, key2=value2, key3=value3" + all := flags.AllSeparated() + + is := is.New(t) + + is.Equal(len(expected), len(all)) +}