github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/nogo/check/main.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Binary check is the nogo entrypoint.
    16  package main
    17  
    18  import (
    19  	"encoding/json"
    20  	"flag"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"log"
    24  	"os"
    25  
    26  	"github.com/SagerNet/gvisor/tools/nogo"
    27  	"github.com/SagerNet/gvisor/tools/worker"
    28  )
    29  
    30  var (
    31  	packageFile    = flag.String("package", "", "package configuration file (in JSON format)")
    32  	stdlibFile     = flag.String("stdlib", "", "stdlib configuration file (in JSON format)")
    33  	findingsOutput = flag.String("findings", "", "output file (or stdout, if not specified)")
    34  	factsOutput    = flag.String("facts", "", "output file for facts (optional)")
    35  )
    36  
    37  func loadConfig(file string, config interface{}) interface{} {
    38  	// Load the configuration.
    39  	f, err := os.Open(file)
    40  	if err != nil {
    41  		log.Fatalf("unable to open configuration %q: %v", file, err)
    42  	}
    43  	defer f.Close()
    44  	dec := json.NewDecoder(f)
    45  	dec.DisallowUnknownFields()
    46  	if err := dec.Decode(config); err != nil {
    47  		log.Fatalf("unable to decode configuration: %v", err)
    48  	}
    49  	return config
    50  }
    51  
    52  func main() {
    53  	worker.Work(run)
    54  }
    55  
    56  func run([]string) int {
    57  	var (
    58  		findings []nogo.Finding
    59  		factData []byte
    60  		err      error
    61  	)
    62  
    63  	// Check & load the configuration.
    64  	if *packageFile != "" && *stdlibFile != "" {
    65  		fmt.Fprintf(os.Stderr, "unable to perform stdlib and package analysis; provide only one!")
    66  		return 1
    67  	}
    68  
    69  	// Run the configuration.
    70  	if *stdlibFile != "" {
    71  		// Perform stdlib analysis.
    72  		c := loadConfig(*stdlibFile, new(nogo.StdlibConfig)).(*nogo.StdlibConfig)
    73  		findings, factData, err = nogo.CheckStdlib(c, nogo.AllAnalyzers)
    74  	} else if *packageFile != "" {
    75  		// Perform standard analysis.
    76  		c := loadConfig(*packageFile, new(nogo.PackageConfig)).(*nogo.PackageConfig)
    77  		findings, factData, err = nogo.CheckPackage(c, nogo.AllAnalyzers, nil)
    78  	} else {
    79  		fmt.Fprintf(os.Stderr, "please provide at least one of package or stdlib!")
    80  		return 1
    81  	}
    82  
    83  	// Check that analysis was successful.
    84  	if err != nil {
    85  		fmt.Fprintf(os.Stderr, "error performing analysis: %v", err)
    86  		return 1
    87  	}
    88  
    89  	// Save facts.
    90  	if *factsOutput != "" {
    91  		if err := ioutil.WriteFile(*factsOutput, factData, 0644); err != nil {
    92  			fmt.Fprintf(os.Stderr, "error saving findings to %q: %v", *factsOutput, err)
    93  			return 1
    94  		}
    95  	}
    96  
    97  	// Write all findings.
    98  	if *findingsOutput != "" {
    99  		w, err := os.OpenFile(*findingsOutput, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
   100  		if err != nil {
   101  			fmt.Fprintf(os.Stderr, "error opening output file %q: %v", *findingsOutput, err)
   102  			return 1
   103  		}
   104  		if err := nogo.WriteFindingsTo(w, findings, false /* json */); err != nil {
   105  			fmt.Fprintf(os.Stderr, "error writing findings to %q: %v", *findingsOutput, err)
   106  			return 1
   107  		}
   108  	} else {
   109  		for _, finding := range findings {
   110  			fmt.Fprintf(os.Stdout, "%s\n", finding.String())
   111  		}
   112  	}
   113  
   114  	return 0
   115  }