github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/cmd/go/internal/list/list.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package list implements the ``go list'' command.
     6  package list
     7  
     8  import (
     9  	"bufio"
    10  	"encoding/json"
    11  	"io"
    12  	"os"
    13  	"strings"
    14  	"text/template"
    15  
    16  	"cmd/go/internal/base"
    17  	"cmd/go/internal/cfg"
    18  	"cmd/go/internal/load"
    19  	"cmd/go/internal/work"
    20  )
    21  
    22  var CmdList = &base.Command{
    23  	UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
    24  	Short:     "list packages",
    25  	Long: `
    26  List lists the packages named by the import paths, one per line.
    27  
    28  The default output shows the package import path:
    29  
    30      bytes
    31      encoding/json
    32      github.com/gorilla/mux
    33      golang.org/x/net/html
    34  
    35  The -f flag specifies an alternate format for the list, using the
    36  syntax of package template.  The default output is equivalent to -f
    37  '{{.ImportPath}}'. The struct being passed to the template is:
    38  
    39      type Package struct {
    40          Dir           string // directory containing package sources
    41          ImportPath    string // import path of package in dir
    42          ImportComment string // path in import comment on package statement
    43          Name          string // package name
    44          Doc           string // package documentation string
    45          Target        string // install path
    46          Shlib         string // the shared library that contains this package (only set when -linkshared)
    47          Goroot        bool   // is this package in the Go root?
    48          Standard      bool   // is this package part of the standard Go library?
    49          Stale         bool   // would 'go install' do anything for this package?
    50          StaleReason   string // explanation for Stale==true
    51          Root          string // Go root or Go path dir containing this package
    52          ConflictDir   string // this directory shadows Dir in $GOPATH
    53          BinaryOnly    bool   // binary-only package: cannot be recompiled from sources
    54  
    55          // Source files
    56          GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
    57          CgoFiles       []string // .go sources files that import "C"
    58          IgnoredGoFiles []string // .go sources ignored due to build constraints
    59          CFiles         []string // .c source files
    60          CXXFiles       []string // .cc, .cxx and .cpp source files
    61          MFiles         []string // .m source files
    62          HFiles         []string // .h, .hh, .hpp and .hxx source files
    63          FFiles         []string // .f, .F, .for and .f90 Fortran source files
    64          SFiles         []string // .s source files
    65          SwigFiles      []string // .swig files
    66          SwigCXXFiles   []string // .swigcxx files
    67          SysoFiles      []string // .syso object files to add to archive
    68          TestGoFiles    []string // _test.go files in package
    69          XTestGoFiles   []string // _test.go files outside package
    70  
    71          // Cgo directives
    72          CgoCFLAGS    []string // cgo: flags for C compiler
    73          CgoCPPFLAGS  []string // cgo: flags for C preprocessor
    74          CgoCXXFLAGS  []string // cgo: flags for C++ compiler
    75          CgoFFLAGS    []string // cgo: flags for Fortran compiler
    76          CgoLDFLAGS   []string // cgo: flags for linker
    77          CgoPkgConfig []string // cgo: pkg-config names
    78  
    79          // Dependency information
    80          Imports      []string // import paths used by this package
    81          Deps         []string // all (recursively) imported dependencies
    82          TestImports  []string // imports from TestGoFiles
    83          XTestImports []string // imports from XTestGoFiles
    84  
    85          // Error information
    86          Incomplete bool            // this package or a dependency has an error
    87          Error      *PackageError   // error loading package
    88          DepsErrors []*PackageError // errors loading dependencies
    89      }
    90  
    91  Packages stored in vendor directories report an ImportPath that includes the
    92  path to the vendor directory (for example, "d/vendor/p" instead of "p"),
    93  so that the ImportPath uniquely identifies a given copy of a package.
    94  The Imports, Deps, TestImports, and XTestImports lists also contain these
    95  expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
    96  
    97  The error information, if any, is
    98  
    99      type PackageError struct {
   100          ImportStack   []string // shortest path from package named on command line to this one
   101          Pos           string   // position of error (if present, file:line:col)
   102          Err           string   // the error itself
   103      }
   104  
   105  The template function "join" calls strings.Join.
   106  
   107  The template function "context" returns the build context, defined as:
   108  
   109  	type Context struct {
   110  		GOARCH        string   // target architecture
   111  		GOOS          string   // target operating system
   112  		GOROOT        string   // Go root
   113  		GOPATH        string   // Go path
   114  		CgoEnabled    bool     // whether cgo can be used
   115  		UseAllFiles   bool     // use files regardless of +build lines, file names
   116  		Compiler      string   // compiler to assume when computing target paths
   117  		BuildTags     []string // build constraints to match in +build lines
   118  		ReleaseTags   []string // releases the current release is compatible with
   119  		InstallSuffix string   // suffix to use in the name of the install dir
   120  	}
   121  
   122  For more information about the meaning of these fields see the documentation
   123  for the go/build package's Context type.
   124  
   125  The -json flag causes the package data to be printed in JSON format
   126  instead of using the template format.
   127  
   128  The -e flag changes the handling of erroneous packages, those that
   129  cannot be found or are malformed.  By default, the list command
   130  prints an error to standard error for each erroneous package and
   131  omits the packages from consideration during the usual printing.
   132  With the -e flag, the list command never prints errors to standard
   133  error and instead processes the erroneous packages with the usual
   134  printing.  Erroneous packages will have a non-empty ImportPath and
   135  a non-nil Error field; other information may or may not be missing
   136  (zeroed).
   137  
   138  For more about build flags, see 'go help build'.
   139  
   140  For more about specifying packages, see 'go help packages'.
   141  	`,
   142  }
   143  
   144  func init() {
   145  	CmdList.Run = runList // break init cycle
   146  	work.AddBuildFlags(CmdList)
   147  }
   148  
   149  var listE = CmdList.Flag.Bool("e", false, "")
   150  var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "")
   151  var listJson = CmdList.Flag.Bool("json", false, "")
   152  var nl = []byte{'\n'}
   153  
   154  func runList(cmd *base.Command, args []string) {
   155  	work.BuildModeInit()
   156  	out := newTrackingWriter(os.Stdout)
   157  	defer out.w.Flush()
   158  
   159  	var do func(*load.PackagePublic)
   160  	if *listJson {
   161  		do = func(p *load.PackagePublic) {
   162  			b, err := json.MarshalIndent(p, "", "\t")
   163  			if err != nil {
   164  				out.Flush()
   165  				base.Fatalf("%s", err)
   166  			}
   167  			out.Write(b)
   168  			out.Write(nl)
   169  		}
   170  	} else {
   171  		var cachedCtxt *Context
   172  		context := func() *Context {
   173  			if cachedCtxt == nil {
   174  				cachedCtxt = newContext(&cfg.BuildContext)
   175  			}
   176  			return cachedCtxt
   177  		}
   178  		fm := template.FuncMap{
   179  			"join":    strings.Join,
   180  			"context": context,
   181  		}
   182  		tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
   183  		if err != nil {
   184  			base.Fatalf("%s", err)
   185  		}
   186  		do = func(p *load.PackagePublic) {
   187  			if err := tmpl.Execute(out, p); err != nil {
   188  				out.Flush()
   189  				base.Fatalf("%s", err)
   190  			}
   191  			if out.NeedNL() {
   192  				out.Write(nl)
   193  			}
   194  		}
   195  	}
   196  
   197  	loadpkgs := load.Packages
   198  	if *listE {
   199  		loadpkgs = load.PackagesAndErrors
   200  	}
   201  
   202  	for _, pkg := range loadpkgs(args) {
   203  		// Show vendor-expanded paths in listing
   204  		pkg.TestImports = pkg.Vendored(pkg.TestImports)
   205  		pkg.XTestImports = pkg.Vendored(pkg.XTestImports)
   206  
   207  		do(&pkg.PackagePublic)
   208  	}
   209  }
   210  
   211  // TrackingWriter tracks the last byte written on every write so
   212  // we can avoid printing a newline if one was already written or
   213  // if there is no output at all.
   214  type TrackingWriter struct {
   215  	w    *bufio.Writer
   216  	last byte
   217  }
   218  
   219  func newTrackingWriter(w io.Writer) *TrackingWriter {
   220  	return &TrackingWriter{
   221  		w:    bufio.NewWriter(w),
   222  		last: '\n',
   223  	}
   224  }
   225  
   226  func (t *TrackingWriter) Write(p []byte) (n int, err error) {
   227  	n, err = t.w.Write(p)
   228  	if n > 0 {
   229  		t.last = p[n-1]
   230  	}
   231  	return
   232  }
   233  
   234  func (t *TrackingWriter) Flush() {
   235  	t.w.Flush()
   236  }
   237  
   238  func (t *TrackingWriter) NeedNL() bool {
   239  	return t.last != '\n'
   240  }