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