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