cmd/cmd.go

Summary

Maintainability
A
0 mins
Test Coverage
F
33%
// Copyright (c) 2019-2022 Wibowo Arindrarto <contact@arindrarto.dev>
// SPDX-License-Identifier: BSD-3-Clause

// Package cmd provides the command line interface for the
// https://godoc.org/github.com/bow/wf/wait package.
package cmd

import (
    "fmt"
    "os"
    "time"

    "github.com/spf13/cobra"

    "github.com/bow/wf/wait"
)

const (
    name = "wf"
    desc = "Wait until TCP server(s) are ready to accept connections"
)

var (
    // These are meant to be overidden at built time using ldflags -X.
    buildTime = "?"
    version   = "dev"
    gitCommit = "?"
)

// Execute peforms the actual CLI argument parsing and launches the wait operation.
func Execute() error {
    var (
        waitTimeout     time.Duration
        defaultPollFreq time.Duration
        isQuiet         bool

        ver = fmt.Sprintf("%s (build time: %s, commit: %s)", version, buildTime, gitCommit)
    )

    cmd := &cobra.Command{
        Use:                   name + " [FLAGS] ADDRESS...",
        Short:                 desc,
        Version:               ver,
        DisableFlagsInUseLine: true,
        SilenceErrors:         true,

        Args: func(cmd *cobra.Command, args []string) error {
            if len(args) < 1 {
                return fmt.Errorf("at least one address must be specified")
            }
            return nil
        },

        Run: func(cmd *cobra.Command, args []string) {
            var rawAddrs []string
            if dashIdx := cmd.ArgsLenAtDash(); dashIdx == -1 {
                rawAddrs = args
            } else {
                rawAddrs = args[:dashIdx]
            }
            exitCode := run(rawAddrs, waitTimeout, defaultPollFreq, isQuiet)
            if exitCode != 0 {
                os.Exit(exitCode) // nolint: revive
            }
        },
    }

    flagSet := cmd.Flags()
    flagSet.SortFlags = false
    flagSet.DurationVarP(&waitTimeout, "timeout", "t", 5*time.Second, "set wait timeout")
    flagSet.DurationVarP(
        &defaultPollFreq,
        "poll-freq",
        "f",
        500*time.Millisecond,
        "set connection poll frequency",
    )
    flagSet.BoolVarP(&isQuiet, "quiet", "q", false, "suppress waiting messages")

    return cmd.Execute()
}

// run calls the actual function for waiting.
func run(
    rawAddrs []string,
    waitTimeout, defaultPollFreq time.Duration,
    isQuiet bool,
) int {

    specs, err := wait.ParseTCPSpecs(rawAddrs, defaultPollFreq)
    if err != nil {
        fmt.Printf("%7s: %s\n", "ERROR", err)
        return 1
    }

    var (
        msg       wait.Message
        showMsg   = func(wait.Message) {}
        showFinal = func(wait.Message) {}
    )
    if !isQuiet {
        showMsg = func(msg wait.Message) {
            var disp string

            switch msg.Status() {
            case wait.Start:
                disp = fmt.Sprintf("%7s: %s for %s", "waiting", msg.Target(), waitTimeout)
            case wait.Ready:
                disp = fmt.Sprintf(
                    "%7s: %s in %s",
                    wait.Ready,
                    msg.Target(),
                    fmtElapsedTime(msg.ElapsedTime()),
                )
            case wait.Failed:
                disp = fmt.Sprintf("%7s: %s", wait.Failed, msg.Err())
            }

            fmt.Println(disp)
        }
        showFinal = func(msg wait.Message) {
            fmt.Printf("%7s: all ready in %s\n", "OK", fmtElapsedTime(msg.ElapsedTime()))
        }
    }

    for msg = range wait.AllTCP(specs, waitTimeout) {
        showMsg(msg)
        if err := msg.Err(); err != nil {
            return 1
        }
    }
    showFinal(msg)

    return 0
}