cmd/vulnreport: add lint

Functionality for linting a vulnerability report is moved to
cmd/vulnreport from cmd/linter.

Change-Id: I5ada6c66db10cd9711fe8c801a646e2df3fbd972
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/369479
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/cmd/linter/main.go b/cmd/linter/main.go
deleted file mode 100644
index 2c70d70..0000000
--- a/cmd/linter/main.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Command linter provides a tool for linting individual reports.
-package main
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-
-	"golang.org/x/vuln/internal/report"
-	"gopkg.in/yaml.v2"
-)
-
-func main() {
-	if len(os.Args) != 2 {
-		fmt.Fprintln(os.Stderr, "only expect a single argument")
-		os.Exit(1)
-	}
-
-	content, err := ioutil.ReadFile(os.Args[1])
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "unable to read %q: %s\n", os.Args[1], err)
-		os.Exit(1)
-	}
-
-	var vuln report.Report
-	err = yaml.UnmarshalStrict(content, &vuln)
-	if err != nil {
-		fmt.Fprintf(os.Stderr, "unable to parse %q: %s\n", os.Args[1], err)
-		os.Exit(1)
-	}
-
-	if lints := vuln.Lint(); len(lints) > 0 {
-		fmt.Fprintf(os.Stderr, "invalid vulnerability file %q:\n", os.Args[1])
-		for _, lint := range lints {
-			fmt.Fprintf(os.Stderr, "\t%s\n", lint)
-		}
-		os.Exit(1)
-	}
-}
diff --git a/cmd/vulnreport/main.go b/cmd/vulnreport/main.go
index b4470ba..e9bca08 100644
--- a/cmd/vulnreport/main.go
+++ b/cmd/vulnreport/main.go
@@ -9,10 +9,15 @@
 import (
 	"flag"
 	"fmt"
+	"io/ioutil"
 	"log"
+	"strings"
+
 	"os"
 
 	"golang.org/x/vuln/internal/derrors"
+	"golang.org/x/vuln/internal/report"
+	"gopkg.in/yaml.v2"
 )
 
 func main() {
@@ -37,7 +42,9 @@
 			log.Fatal(err)
 		}
 	case "lint":
-		log.Fatalf("not implemented")
+		if err := lint(filename); err != nil {
+			log.Fatal(err)
+		}
 	default:
 		flag.Usage()
 		log.Fatalf("unsupported command: %q", cmd)
@@ -66,3 +73,22 @@
     -
 `), 0644)
 }
+
+func lint(filename string) (err error) {
+	defer derrors.Wrap(&err, "lint(%q)", filename)
+	content, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return fmt.Errorf("ioutil.ReadFile: %v", err)
+	}
+
+	var vuln report.Report
+	err = yaml.UnmarshalStrict(content, &vuln)
+	if err != nil {
+		return fmt.Errorf("yaml.UnmarshalStrict: %v", err)
+	}
+
+	if lints := vuln.Lint(); len(lints) > 0 {
+		return fmt.Errorf("vuln.Lint returned errors:\n\t %s", strings.Join(lints, "\n\t"))
+	}
+	return nil
+}