Skip to content

Commit

Permalink
update print to include lint subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
daghack committed Mar 20, 2024
1 parent 793cb68 commit 0ed1a23
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 0 deletions.
5 changes: 5 additions & 0 deletions frontend/dockerfile/builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/moby/buildkit/frontend/dockerui"
"github.com/moby/buildkit/frontend/gateway/client"
gwpb "github.com/moby/buildkit/frontend/gateway/pb"
"github.com/moby/buildkit/frontend/subrequests/lint"
"github.com/moby/buildkit/frontend/subrequests/outline"
"github.com/moby/buildkit/frontend/subrequests/targets"
"github.com/moby/buildkit/solver/errdefs"
Expand Down Expand Up @@ -85,6 +86,10 @@ func Build(ctx context.Context, c client.Client) (_ *client.Result, err error) {
ListTargets: func(ctx context.Context) (*targets.List, error) {
return dockerfile2llb.ListTargets(ctx, src.Data)
},
Lint: func(ctx context.Context) (*lint.LintResults, error) {
warnings, err := dockerfile2llb.DockerfileLint(ctx, src.Data, convertOpt)
return &lint.LintResults{Warnings: warnings}, err
},
}); err != nil {
return nil, err
} else if ok {
Expand Down
30 changes: 30 additions & 0 deletions frontend/dockerfile/dockerfile2llb/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/moby/buildkit/frontend/dockerfile/parser"
"github.com/moby/buildkit/frontend/dockerfile/shell"
"github.com/moby/buildkit/frontend/dockerui"
"github.com/moby/buildkit/frontend/subrequests/lint"
"github.com/moby/buildkit/frontend/subrequests/outline"
"github.com/moby/buildkit/frontend/subrequests/targets"
"github.com/moby/buildkit/identity"
Expand Down Expand Up @@ -110,6 +111,35 @@ func Dockefile2Outline(ctx context.Context, dt []byte, opt ConvertOpt) (*outline
return &o, nil
}

func DockerfileLint(ctx context.Context, dt []byte, opt ConvertOpt) ([]lint.Warning, error) {
warnings := []lint.Warning{}
sourceData := strings.Split(string(opt.SourceMap.Data), "\n")
opt.Warn = func(short, url string, detail [][]byte, location []parser.Range) {
var rulename, ruledetail string
if strings.HasPrefix(short, "Lint Rule ") {
rulename = strings.TrimPrefix(short, "Lint Rule ")
ruleParts := strings.Split(rulename, ":")
rulename = ruleParts[0]
ruledetail = ruleParts[1]
rulename = strings.Trim(rulename, "'")
} else {
return
}
warnings = append(warnings, lint.Warning{
RuleName: rulename,
Detail: ruledetail,
Filename: opt.SourceMap.Filename,
Source: sourceData[location[0].Start.Line-1 : location[0].End.Line],
StartLine: location[0].Start.Line,
})
}
_, err := toDispatchState(ctx, dt, opt)
if err != nil {
return nil, err
}
return warnings, nil
}

func ListTargets(ctx context.Context, dt []byte) (*targets.List, error) {
dockerfile, err := parser.Parse(bytes.NewReader(dt))
if err != nil {
Expand Down
14 changes: 14 additions & 0 deletions frontend/dockerui/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/frontend/subrequests"
"github.com/moby/buildkit/frontend/subrequests/lint"
"github.com/moby/buildkit/frontend/subrequests/outline"
"github.com/moby/buildkit/frontend/subrequests/targets"
"github.com/moby/buildkit/solver/errdefs"
Expand All @@ -19,6 +20,7 @@ const (
type RequestHandler struct {
Outline func(context.Context) (*outline.Outline, error)
ListTargets func(context.Context) (*targets.List, error)
Lint func(context.Context) (*lint.LintResults, error)
AllowOther bool
}

Expand Down Expand Up @@ -55,6 +57,18 @@ func (bc *Client) HandleSubrequest(ctx context.Context, h RequestHandler) (*clie
res, err := targets.ToResult()
return res, true, err
}
case lint.SubrequestLintDefinition.Name:
if f := h.Lint; f != nil {
warnings, err := f(ctx)
if err != nil {
return nil, false, err
}
if warnings == nil {
return nil, true, nil
}
res, err := warnings.ToResult()
return res, true, err
}
}
if h.AllowOther {
return nil, false, nil
Expand Down
105 changes: 105 additions & 0 deletions frontend/subrequests/lint/lint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package lint

import (
"bytes"
"encoding/json"
"fmt"
"io"
"sort"
"text/tabwriter"

"github.com/moby/buildkit/frontend/gateway/client"
"github.com/moby/buildkit/frontend/subrequests"
)

const RequestLint = "frontend.lint"

var SubrequestLintDefinition = subrequests.Request{
Name: RequestLint,
Version: "1.0.0",
Type: subrequests.TypeRPC,
Description: "Lint a Dockerfile",
Opts: []subrequests.Named{},
Metadata: []subrequests.Named{
{Name: "result.json"},
{Name: "result.txt"},
},
}

type Warning struct {
RuleName string `json:"rule_name"`
Detail string `json:"detail"`
Filename string `json:"filename"`
Source []string `json:"source"`
StartLine int `json:"start_line"`
}

type LintResults struct {
Warnings []Warning `json:"warnings"`
}

func (warns LintResults) ToResult() (*client.Result, error) {
res := client.NewResult()
dt, err := json.MarshalIndent(warns, "", " ")
if err != nil {
return nil, err
}
res.AddMeta("result.json", dt)

b := bytes.NewBuffer(nil)
if err := PrintLintViolations(dt, b); err != nil {
return nil, err
}
res.AddMeta("result.txt", b.Bytes())

res.AddMeta("version", []byte(SubrequestLintDefinition.Version))
return res, nil
}

func PrintLintViolations(dt []byte, w io.Writer) error {
var warnings LintResults

if err := json.Unmarshal(dt, &warnings); err != nil {
return err
}

// Group warnings by start line
lintWarnings := make(map[string][]Warning)
lintWarningRules := []string{}
for _, warning := range warnings.Warnings {
if _, ok := lintWarnings[warning.RuleName]; !ok {
lintWarningRules = append(lintWarningRules, warning.RuleName)
lintWarnings[warning.RuleName] = []Warning{}
}
lintWarnings[warning.RuleName] = append(lintWarnings[warning.RuleName], warning)
}
sort.Strings(lintWarningRules)

// Sort Warnings by filename and start line
//sort.Slice(warnings.Warnings, func(i, j int) bool {
// if warnings.Warnings[i].Filename == warnings.Warnings[j].Filename {
// return warnings.Warnings[i].StartLine < warnings.Warnings[j].StartLine
// }
// return warnings.Warnings[i].Filename < warnings.Warnings[j].Filename
//})

tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)
// #TODO print the warnings in a human readable format
//for _, warning := range warnings.Warnings {
// fmt.Fprintf(tw, "%s:%d\n\t%s\n", warning.Filename, warning.StartLine, warning.Short)
//}
for _, rule := range lintWarningRules {
fmt.Fprintf(tw, "Lint Rule %s\n", rule)
for _, warning := range lintWarnings[rule] {
fmt.Fprintf(tw, "\t%s:%d\n", warning.Filename, warning.StartLine)
fmt.Fprintf(tw, "\t%s\n", warning.Detail)
for offset, source := range warning.Source {
fmt.Fprintf(tw, "\t\t%d\t|\t%s\n", warning.StartLine+offset, source)
}
fmt.Fprintln(tw)
}
fmt.Fprintln(tw)
}

return tw.Flush()
}

0 comments on commit 0ed1a23

Please sign in to comment.