diff --git a/cmd/featuretags/featuretags.go b/cmd/featuretags/featuretags.go index c97d66c47..5213fda4c 100644 --- a/cmd/featuretags/featuretags.go +++ b/cmd/featuretags/featuretags.go @@ -35,16 +35,14 @@ func main() { return } - var keep = map[string]bool{} + var keep = map[featuretags.FeatureTag]bool{} for t := range strings.SplitSeq(*add, ",") { if t != "" { - keep[t] = true + keep[featuretags.FeatureTag(t)] = true } } var tags []string - if keep["cli"] { - // The "cli" --add value is special in that it's a build tag - // that adds something, rather than removes something. + if keep[featuretags.CLI] { tags = append(tags, "ts_include_cli") } if *min { @@ -52,22 +50,24 @@ func main() { if f == "" { continue } - if !keep[f] { - tags = append(tags, "ts_omit_"+f) + if !keep[f] && f.IsOmittable() { + tags = append(tags, f.OmitTag()) } } } - for f := range strings.SplitSeq(*remove, ",") { - if f == "" { + for v := range strings.SplitSeq(*remove, ",") { + if v == "" { continue } + f := featuretags.FeatureTag(v) if _, ok := features[f]; !ok { log.Fatalf("unknown feature %q in --remove", f) } - tags = append(tags, "ts_omit_"+f) + tags = append(tags, f.OmitTag()) } + slices.Sort(tags) + tags = slices.Compact(tags) if len(tags) != 0 { fmt.Println(strings.Join(tags, ",")) } - } diff --git a/cmd/omitsize/omitsize.go b/cmd/omitsize/omitsize.go index bce072973..841f3ab9e 100644 --- a/cmd/omitsize/omitsize.go +++ b/cmd/omitsize/omitsize.go @@ -23,6 +23,8 @@ import ( var ( cacheDir = flag.String("cachedir", "", "if non-empty, use this directory to store cached size results to speed up subsequent runs. The tool does not consider the git status when deciding whether to use the cache. It's on you to nuke it between runs if the tree changed.") features = flag.String("features", "", "comma-separated list of features to consider, with or without the ts_omit_ prefix") + + showRemovals = flag.Bool("show-removals", false, "if true, show a table of sizes removing one feature at a time from the full set") ) func main() { @@ -31,7 +33,9 @@ func main() { var all []string if *features == "" { for k := range featuretags.Features { - all = append(all, "ts_omit_"+k) + if k.IsOmittable() { + all = append(all, k.OmitTag()) + } } } else { for v := range strings.SplitSeq(*features, ",") { @@ -49,27 +53,30 @@ func main() { baseC := measure("tailscale") baseBoth := measure("tailscaled", "ts_include_cli") - fmt.Printf("(a) starting with everything and removing a feature...\n\n") - - fmt.Printf("%9s %9s %9s\n", "tailscaled", "tailscale", "combined (linux/amd64)") - fmt.Printf("%9d %9d %9d\n", baseD, baseC, baseBoth) - minD := measure("tailscaled", all...) minC := measure("tailscale", all...) minBoth := measure("tailscaled", append(slices.Clone(all), "ts_include_cli")...) - fmt.Printf("-%8d -%8d -%8d omit-all\n", baseD-minD, baseC-minC, baseBoth-minBoth) - for _, t := range all { - sizeD := measure("tailscaled", t) - sizeC := measure("tailscale", t) - sizeBoth := measure("tailscaled", append([]string{t}, "ts_include_cli")...) - saveD := max(baseD-sizeD, 0) - saveC := max(baseC-sizeC, 0) - saveBoth := max(baseBoth-sizeBoth, 0) - fmt.Printf("-%8d -%8d -%8d %s\n", saveD, saveC, saveBoth, t) + if *showRemovals { + fmt.Printf("Starting with everything and removing a feature...\n\n") + + fmt.Printf("%9s %9s %9s\n", "tailscaled", "tailscale", "combined (linux/amd64)") + fmt.Printf("%9d %9d %9d\n", baseD, baseC, baseBoth) + + fmt.Printf("-%8d -%8d -%8d omit-all\n", baseD-minD, baseC-minC, baseBoth-minBoth) + + for _, t := range all { + sizeD := measure("tailscaled", t) + sizeC := measure("tailscale", t) + sizeBoth := measure("tailscaled", append([]string{t}, "ts_include_cli")...) + saveD := max(baseD-sizeD, 0) + saveC := max(baseC-sizeC, 0) + saveBoth := max(baseBoth-sizeBoth, 0) + fmt.Printf("-%8d -%8d -%8d %s\n", saveD, saveC, saveBoth, t) + } } - fmt.Printf("\n(b) or, starting at minimal and adding one feature back...\n") + fmt.Printf("\nStarting at a minimal binary and adding one feature back...\n") fmt.Printf("%9s %9s %9s\n", "tailscaled", "tailscale", "combined (linux/amd64)") fmt.Printf("%9d %9d %9d omitting everything\n", minD, minC, minBoth) for _, t := range all { diff --git a/feature/featuretags/featuretags.go b/feature/featuretags/featuretags.go index 00ad0b4c2..87bc22fc6 100644 --- a/feature/featuretags/featuretags.go +++ b/feature/featuretags/featuretags.go @@ -4,7 +4,37 @@ // The featuretags package is a registry of all the ts_omit-able build tags. package featuretags -var Features = map[string]string{ +// CLI is a special feature in the [Features] map that works opposite +// from the others: it is opt-in, rather than opt-out, having a different +// build tag format. +const CLI FeatureTag = "cli" + +// FeatureTag names a Tailscale feature that can be selectively added or removed +// via build tags. +type FeatureTag string + +// IsOmittable reports whether this feature tag is one that can be +// omitted via a ts_omit_ build tag. +func (ft FeatureTag) IsOmittable() bool { + switch ft { + case CLI: + return false + } + return true +} + +// OmitTag returns the ts_omit_ build tag for this feature tag. +// It panics if the feature tag is not omitable. +func (ft FeatureTag) OmitTag() string { + if !ft.IsOmittable() { + panic("not omitable: " + string(ft)) + } + return "ts_omit_" + string(ft) +} + +// Features are the known Tailscale features that can be selectively included or +// excluded via build tags, and a description of each. +var Features = map[FeatureTag]string{ "aws": "AWS integration", "bird": "Bird BGP integration", "capture": "Packet capture", @@ -21,7 +51,6 @@ var Features = map[string]string{ "taildrop": "Taildrop (file sending) support", "tailnetlock": "Tailnet Lock support", "tap": "Experimental Layer 2 (ethernet) support", - "tka": "Tailnet Lock (TKA) support", "tpm": "TPM support", "wakeonlan": "Wake-on-LAN support", "webclient": "Web client support",