zabio3/godolint

View on GitHub
cmd/cli.go

Summary

Maintainability
A
0 mins
Test Coverage
// Package cmd provides command line tool to analyzer dockerfile.
package cmd

import (
    "flag"
    "fmt"
    "io"
    "os"
    "sort"

    "github.com/moby/buildkit/frontend/dockerfile/parser"

    "github.com/zabio3/godolint/linter"
)

// Exit codes are int values that represent an exit code for a particular error.
const (
    ExitCodeOK = iota
    ExitCodeParseFlagsError
    ExitCodeNoExistError
    ExitCodeFileError
    ExitCodeAstParseError
    ExitCodeLintCheckError
)

const name = "godolint"

const version = "1.0.1"

const usage = `godolint - Dockerfile linter written in Golang

Usage: godolint [--ignore RULECODE]
  Lint Dockerfile for errors and best practices

Available options:
  --ignore RULECODE    A rule to ignore. If present, the ignore list in the
            config file is ignored

  --help    -h    Print this help message and exit.
  --version    -v    Print the version information
`

// CLI represents CLI interface.
type CLI struct {
    OutStream, ErrStream io.Writer
}

type sliceString []string

func (ss *sliceString) String() string {
    return fmt.Sprintf("%s", *ss)
}

func (ss *sliceString) Set(value string) error {
    *ss = append(*ss, value)
    return nil
}

// Run it takes Dockerfile as an argument and applies it to analyzer to standard output.
func (cli *CLI) Run(args []string) int {
    var ignoreRules sliceString
    var isVersion bool

    flags := flag.NewFlagSet(name, flag.ContinueOnError)
    flags.Usage = func() {
        fmt.Fprint(cli.OutStream, usage)
    }

    flags.Var(&ignoreRules, "ignore", "Set ignore strings")
    flags.BoolVar(&isVersion, "version", false, "version")
    flags.BoolVar(&isVersion, "v", false, "version")

    if err := flags.Parse(args[1:]); err != nil {
        fmt.Fprint(cli.ErrStream, err)
        return ExitCodeParseFlagsError
    }

    if isVersion {
        fmt.Fprintf(cli.OutStream, "godolint version %v\n", version)
        return ExitCodeOK
    }

    length := len(args)
    // The Dockerfile to be analyzed must be the last.
    if length < 2 {
        fmt.Fprintf(cli.ErrStream, "Please provide a Dockerfile\n")
        return ExitCodeNoExistError
    }

    file := args[length-1]
    f, err := os.Open(file)
    if err != nil {
        fmt.Fprint(cli.ErrStream, err)
        return ExitCodeFileError
    }

    r, err := parser.Parse(f)
    if err != nil {
        fmt.Fprint(cli.ErrStream, err)
        return ExitCodeAstParseError
    }

    analyzer := linter.NewAnalyzer(ignoreRules)
    rst, err := analyzer.Run(r.AST)
    if err != nil {
        fmt.Fprint(cli.ErrStream, err)
        return ExitCodeLintCheckError
    }

    rst = sort.StringSlice(rst)
    var output string
    for i := range rst {
        // ends of each strings have "\n"
        output = output + rst[i]
    }
    fmt.Fprint(cli.OutStream, output)
    return ExitCodeOK
}