internal/cli/build/build.go

Summary

Maintainability
A
3 hrs
Test Coverage
package build

import (
    "archive/zip"
    "bytes"
    "fmt"
    "io"
    "os"
    "sort"

    "github.com/dustin/go-humanize"
    "github.com/pkg/errors"
    "github.com/tj/go/term"
    "github.com/tj/kingpin"

    "github.com/apex/up/internal/cli/root"
    "github.com/apex/up/internal/colors"
    "github.com/apex/up/internal/stats"
    "github.com/apex/up/internal/util"
)

func init() {
    cmd := root.Command("build", "Build zip file.")
    cmd.Example(`up build`, "Build archive and save to ./out.zip")
    cmd.Example(`up build > /tmp/out.zip`, "Build archive and output to file via stdout.")
    cmd.Example(`up build --size`, "Build archive and list files by size.")

    stage := cmd.Flag("stage", "Target stage name.").Short('s').Default("staging").String()
    size := cmd.Flag("size", "Show zip contents size information.").Bool()

    cmd.Action(func(_ *kingpin.ParseContext) error {
        defer util.Pad()()

        _, p, err := root.Init()
        if err != nil {
            return errors.Wrap(err, "initializing")
        }

        stats.Track("Build", nil)

        if err := p.Init(*stage); err != nil {
            return errors.Wrap(err, "initializing")
        }

        if err := p.Build(true); err != nil {
            return errors.Wrap(err, "building")
        }

        r, err := p.Zip()
        if err != nil {
            return errors.Wrap(err, "zip")
        }

        var out io.Writer
        var buf bytes.Buffer

        switch {
        default:
            out = os.Stdout
        case *size:
            out = &buf
        case term.IsTerminal(os.Stdout.Fd()):
            f, err := os.Create("out.zip")
            if err != nil {
                return errors.Wrap(err, "creating zip")
            }
            defer f.Close()
            out = f
        }

        if _, err := io.Copy(out, r); err != nil {
            return errors.Wrap(err, "copying")
        }

        if *size {
            z, err := zip.NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
            if err != nil {
                return errors.Wrap(err, "opening zip")
            }

            files := z.File

            sort.Slice(files, func(i int, j int) bool {
                a := files[i]
                b := files[j]
                return a.UncompressedSize64 > b.UncompressedSize64
            })

            fmt.Printf("\n")
            for _, f := range files {
                size := humanize.Bytes(f.UncompressedSize64)
                fmt.Printf("  %10s %s\n", size, colors.Purple(f.Name))
            }
        }

        return err
    })
}