mirror of
				https://github.com/kata-containers/kata-containers.git
				synced 2025-10-31 01:13:02 +00:00 
			
		
		
		
	Move the tool as a dependency for static checks migration. Fixes #8187 Signed-off-by: Bin Liu <bin@hyper.sh> Signed-off-by: Chelsea Mafrica <chelsea.e.mafrica@intel.com> Signed-off-by: Gabriela Cervantes <gabriela.cervantes.tellez@intel.com> Signed-off-by: Ganesh Maharaj Mahalingam <ganesh.mahalingam@intel.com> Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com> Signed-off-by: Julio Montes <julio.montes@intel.com>
		
			
				
	
	
		
			349 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			349 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //
 | |
| // Copyright (c) 2019 Intel Corporation
 | |
| //
 | |
| // SPDX-License-Identifier: Apache-2.0
 | |
| //
 | |
| 
 | |
| package main
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/sirupsen/logrus"
 | |
| 	"github.com/urfave/cli"
 | |
| )
 | |
| 
 | |
| type DataToShow int
 | |
| 
 | |
| const (
 | |
| 	// Character used (after an optional filename) before a heading ID.
 | |
| 	anchorPrefix = "#"
 | |
| 
 | |
| 	// Character used to signify an "absolute link path" which should
 | |
| 	// expand to the value of the document root.
 | |
| 	absoluteLinkPrefix = "/"
 | |
| 
 | |
| 	showLinks    DataToShow = iota
 | |
| 	showHeadings DataToShow = iota
 | |
| 
 | |
| 	textFormat          = "text"
 | |
| 	tsvFormat           = "tsv"
 | |
| 	defaultOutputFormat = textFormat
 | |
| 	defaultSeparator    = "\t"
 | |
| )
 | |
| 
 | |
| var (
 | |
| 	// set by the build
 | |
| 	name    = ""
 | |
| 	version = ""
 | |
| 	commit  = ""
 | |
| 
 | |
| 	strict = false
 | |
| 
 | |
| 	// list entry character to use when generating TOCs
 | |
| 	listPrefix = "*"
 | |
| 
 | |
| 	logger *logrus.Entry
 | |
| 
 | |
| 	errNeedFile = errors.New("need markdown file")
 | |
| )
 | |
| 
 | |
| // Black Friday sometimes chokes on markdown (I know!!), so record how many
 | |
| // extra headings we found.
 | |
| var extraHeadings int
 | |
| 
 | |
| // Root directory used to handle "absolute link paths" that start with a slash
 | |
| // to denote the "top directory", like this:
 | |
| //
 | |
| // [Foo](/absolute-link.md)
 | |
| var docRoot string
 | |
| 
 | |
| var notes = fmt.Sprintf(`
 | |
| 
 | |
| NOTES:
 | |
| 
 | |
| - The document root is used to handle markdown references that begin with %q,
 | |
|   denoting that the path that follows is an "absolute path" from the specified
 | |
|   document root path.
 | |
| 
 | |
| - The order the document nodes are parsed internally is not known to
 | |
|   this program. This means that if multiple errors exist in the document,
 | |
|   running this tool multiple times will error one *one* of the errors, but not
 | |
|   necessarily the same one as last time.
 | |
| 
 | |
| LIMITATIONS:
 | |
| 
 | |
| - The default document root only works if this tool is run from the top-level
 | |
|   of a repository.
 | |
| 
 | |
| `, absoluteLinkPrefix)
 | |
| 
 | |
| var formatFlag = cli.StringFlag{
 | |
| 	Name:  "format",
 | |
| 	Usage: "display in specified format ('help' to show all)",
 | |
| 	Value: defaultOutputFormat,
 | |
| }
 | |
| 
 | |
| var separatorFlag = cli.StringFlag{
 | |
| 	Name:  "separator",
 | |
| 	Usage: fmt.Sprintf("use the specified separator character (%s format only)", tsvFormat),
 | |
| 	Value: defaultSeparator,
 | |
| }
 | |
| 
 | |
| var noHeaderFlag = cli.BoolFlag{
 | |
| 	Name:  "no-header",
 | |
| 	Usage: "disable display of header (if format supports one)",
 | |
| }
 | |
| 
 | |
| func init() {
 | |
| 	logger = logrus.WithFields(logrus.Fields{
 | |
| 		"name":    name,
 | |
| 		"source":  "check-markdown",
 | |
| 		"version": version,
 | |
| 		"commit":  commit,
 | |
| 		"pid":     os.Getpid(),
 | |
| 	})
 | |
| 
 | |
| 	logger.Logger.Formatter = &logrus.TextFormatter{
 | |
| 		TimestampFormat: time.RFC3339Nano,
 | |
| 		//DisableColors:   true,
 | |
| 	}
 | |
| 
 | |
| 	// Write to stdout to avoid upsetting CI systems that consider stderr
 | |
| 	// writes as indicating an error.
 | |
| 	logger.Logger.Out = os.Stdout
 | |
| }
 | |
| 
 | |
| func handleLogging(c *cli.Context) {
 | |
| 	logLevel := logrus.InfoLevel
 | |
| 
 | |
| 	if c.GlobalBool("debug") {
 | |
| 		logLevel = logrus.DebugLevel
 | |
| 	}
 | |
| 
 | |
| 	logger.Logger.SetLevel(logLevel)
 | |
| }
 | |
| 
 | |
| func handleDoc(c *cli.Context, createTOC bool) error {
 | |
| 	handleLogging(c)
 | |
| 
 | |
| 	if c.NArg() == 0 {
 | |
| 		return errNeedFile
 | |
| 	}
 | |
| 
 | |
| 	fileName := c.Args().First()
 | |
| 	if fileName == "" {
 | |
| 		return errNeedFile
 | |
| 	}
 | |
| 
 | |
| 	singleDocOnly := c.GlobalBool("single-doc-only")
 | |
| 
 | |
| 	doc := newDoc(fileName, logger)
 | |
| 	doc.ShowTOC = createTOC
 | |
| 
 | |
| 	if createTOC {
 | |
| 		// Only makes sense to generate a single TOC!
 | |
| 		singleDocOnly = true
 | |
| 	}
 | |
| 
 | |
| 	// Parse the main document first
 | |
| 	err := doc.parse()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if singleDocOnly && len(docs) > 1 {
 | |
| 		doc.Logger.Debug("Not checking referenced files at user request")
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// Now handle all other docs that the main doc references.
 | |
| 	// This requires care to avoid recursion.
 | |
| 	for {
 | |
| 		count := len(docs)
 | |
| 		parsed := 0
 | |
| 		for _, doc := range docs {
 | |
| 			if doc.Parsed {
 | |
| 				// Document has already been handled
 | |
| 				parsed++
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			if err := doc.parse(); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if parsed == count {
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	err = handleIntraDocLinks()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	if !createTOC {
 | |
| 		doc.Logger.Info("Checked file")
 | |
| 		doc.showStats()
 | |
| 	}
 | |
| 
 | |
| 	count := len(docs)
 | |
| 
 | |
| 	if count > 1 {
 | |
| 		// Update to ignore main document
 | |
| 		count--
 | |
| 
 | |
| 		doc.Logger.WithField("reference-document-count", count).Info("Checked referenced files")
 | |
| 
 | |
| 		for _, d := range docs {
 | |
| 			if d.Name == doc.Name {
 | |
| 				// Ignore main document
 | |
| 				continue
 | |
| 			}
 | |
| 
 | |
| 			fmt.Printf("\t%q\n", d.Name)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Highlight blackfriday deficiencies
 | |
| 	if !doc.ShowTOC && extraHeadings > 0 {
 | |
| 		doc.Logger.WithField("extra-heading-count", extraHeadings).Debug("Found extra headings")
 | |
| 	}
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // commonListHandler is used to handle all list operations.
 | |
| func commonListHandler(context *cli.Context, what DataToShow) error {
 | |
| 	handleLogging(context)
 | |
| 
 | |
| 	handlers := NewDisplayHandlers(context.String("separator"), context.Bool("no-header"))
 | |
| 
 | |
| 	format := context.String("format")
 | |
| 	if format == "help" {
 | |
| 		availableFormats := handlers.Get()
 | |
| 
 | |
| 		for _, format := range availableFormats {
 | |
| 			fmt.Fprintf(outputFile, "%s\n", format)
 | |
| 		}
 | |
| 
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	handler := handlers.find(format)
 | |
| 	if handler == nil {
 | |
| 		return fmt.Errorf("no handler for format %q", format)
 | |
| 	}
 | |
| 
 | |
| 	if context.NArg() == 0 {
 | |
| 		return errNeedFile
 | |
| 	}
 | |
| 
 | |
| 	file := context.Args().Get(0)
 | |
| 
 | |
| 	return show(file, logger, handler, what)
 | |
| }
 | |
| 
 | |
| func realMain() error {
 | |
| 	cwd, err := os.Getwd()
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	docRoot = cwd
 | |
| 
 | |
| 	cli.VersionPrinter = func(c *cli.Context) {
 | |
| 		fmt.Fprintln(os.Stdout, c.App.Version)
 | |
| 	}
 | |
| 
 | |
| 	cli.AppHelpTemplate = fmt.Sprintf(`%s%s`, cli.AppHelpTemplate, notes)
 | |
| 
 | |
| 	app := cli.NewApp()
 | |
| 	app.Name = name
 | |
| 	app.Version = fmt.Sprintf("%s %s (commit %v)", name, version, commit)
 | |
| 	app.Description = "Tool to check GitHub-Flavoured Markdown (GFM) format documents"
 | |
| 	app.Usage = app.Description
 | |
| 	app.UsageText = fmt.Sprintf("%s [options] file ...", app.Name)
 | |
| 	app.Flags = []cli.Flag{
 | |
| 		cli.BoolFlag{
 | |
| 			Name:  "debug, d",
 | |
| 			Usage: "display debug information",
 | |
| 		},
 | |
| 		cli.StringFlag{
 | |
| 			Name:  "doc-root, r",
 | |
| 			Usage: "specify document root",
 | |
| 			Value: docRoot,
 | |
| 		},
 | |
| 		cli.BoolFlag{
 | |
| 			Name:  "single-doc-only, o",
 | |
| 			Usage: "only check primary (specified) document",
 | |
| 		},
 | |
| 		cli.BoolFlag{
 | |
| 			Name:  "strict, s",
 | |
| 			Usage: "enable strict mode",
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	app.Commands = []cli.Command{
 | |
| 		{
 | |
| 			Name:        "check",
 | |
| 			Usage:       "perform tests on the specified document",
 | |
| 			Description: "Exit code denotes success",
 | |
| 			Action: func(c *cli.Context) error {
 | |
| 				return handleDoc(c, false)
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name:  "toc",
 | |
| 			Usage: "display a markdown Table of Contents",
 | |
| 			Action: func(c *cli.Context) error {
 | |
| 				return handleDoc(c, true)
 | |
| 			},
 | |
| 		},
 | |
| 		{
 | |
| 			Name:  "list",
 | |
| 			Usage: "display particular parts of the document",
 | |
| 			Subcommands: []cli.Command{
 | |
| 				{
 | |
| 					Name:  "headings",
 | |
| 					Usage: "display headings",
 | |
| 					Flags: []cli.Flag{
 | |
| 						formatFlag,
 | |
| 						noHeaderFlag,
 | |
| 						separatorFlag,
 | |
| 					},
 | |
| 					Action: func(c *cli.Context) error {
 | |
| 						return commonListHandler(c, showHeadings)
 | |
| 					},
 | |
| 				},
 | |
| 				{
 | |
| 					Name:  "links",
 | |
| 					Usage: "display links",
 | |
| 					Flags: []cli.Flag{
 | |
| 						formatFlag,
 | |
| 						noHeaderFlag,
 | |
| 						separatorFlag,
 | |
| 					},
 | |
| 					Action: func(c *cli.Context) error {
 | |
| 						return commonListHandler(c, showLinks)
 | |
| 					},
 | |
| 				},
 | |
| 			},
 | |
| 		},
 | |
| 	}
 | |
| 
 | |
| 	return app.Run(os.Args)
 | |
| }
 | |
| 
 | |
| func main() {
 | |
| 	err := realMain()
 | |
| 	if err != nil {
 | |
| 		logger.Fatalf("%v", err)
 | |
| 	}
 | |
| }
 |