// local build script file, similar to a makefile or collection of bash scripts in other projects package main import ( "bufio" "bytes" "fmt" "io/ioutil" "log" "math" "os" "os/exec" "strings" "github.com/urfave/cli/v2" ) var packages = []string{"cli", "altsrc"} func main() { app := cli.NewApp() app.Name = "builder" app.Usage = "Generates a new urfave/cli build!" app.Commands = cli.Commands{ { Name: "vet", Action: VetActionFunc, }, { Name: "test", Action: TestActionFunc, }, { Name: "gfmrun", Action: GfmrunActionFunc, }, { Name: "toc", Action: TocActionFunc, }, { Name: "check-binary-size", Action: checkBinarySizeActionFunc, }, } err := app.Run(os.Args) if err != nil { log.Fatal(err) } } func runCmd(arg string, args ...string) error { cmd := exec.Command(arg, args...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr return cmd.Run() } func VetActionFunc(_ *cli.Context) error { return runCmd("go", "vet") } func TestActionFunc(c *cli.Context) error { for _, pkg := range packages { var packageName string if pkg == "cli" { packageName = "github.com/urfave/cli/v2" } else { packageName = fmt.Sprintf("github.com/urfave/cli/v2/%s", pkg) } coverProfile := fmt.Sprintf("--coverprofile=%s.coverprofile", pkg) err := runCmd("go", "test", "-v", coverProfile, packageName) if err != nil { return err } } return testCleanup() } func testCleanup() error { var out bytes.Buffer for _, pkg := range packages { file, err := os.Open(fmt.Sprintf("%s.coverprofile", pkg)) if err != nil { return err } b, err := ioutil.ReadAll(file) if err != nil { return err } out.Write(b) err = file.Close() if err != nil { return err } err = os.Remove(fmt.Sprintf("%s.coverprofile", pkg)) if err != nil { return err } } outFile, err := os.Create("coverage.txt") if err != nil { return err } _, err = out.WriteTo(outFile) if err != nil { return err } err = outFile.Close() if err != nil { return err } return nil } func GfmrunActionFunc(c *cli.Context) error { filename := c.Args().Get(0) if filename == "" { filename = "README.md" } file, err := os.Open(filename) if err != nil { return err } defer file.Close() var counter int scanner := bufio.NewScanner(file) for scanner.Scan() { if strings.Contains(scanner.Text(), "package main") { counter++ } } err = file.Close() if err != nil { return err } err = scanner.Err() if err != nil { return err } return runCmd("gfmrun", "-c", fmt.Sprint(counter), "-s", filename) } func TocActionFunc(c *cli.Context) error { filename := c.Args().Get(0) if filename == "" { filename = "README.md" } err := runCmd("markdown-toc", "-i", filename) if err != nil { return err } err = runCmd("git", "diff", "--exit-code") if err != nil { return err } return nil } func checkBinarySizeActionFunc(c *cli.Context) (err error) { const ( sourceFilePath = "./internal/example/example.go" builtFilePath = "./internal/example/built-example" ) // build example binary err = runCmd("go", "build", "-o", builtFilePath, sourceFilePath) if err != nil { return err } // get file into fileInfo, err := os.Stat(builtFilePath) if err != nil { return err } // get human readable size, in MB with one decimal place. // example output is: 35.2MB. // that output is much easier to reason about than the `35223432` // that you would see output without the rounding fileSize := fileInfo.Size() roundedFileSize := math.Round(float64(fileSize)/float64(1000000)*10) / 10 roundedFileSizeString := fmt.Sprintf("%.1fMB", roundedFileSize) // show the file size fmt.Println(fmt.Sprintf("current binary size is: %s", roundedFileSizeString)) return nil }