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.
6package list
7
8import (
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
22var CmdList = &base.Command{
23	UsageLine: "list [-e] [-f format] [-json] [build flags] [packages]",
24	Short:     "list packages",
25	Long: `
26List lists the packages named by the import paths, one per line.
27
28The 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
35The -f flag specifies an alternate format for the list, using the
36syntax 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
91Packages stored in vendor directories report an ImportPath that includes the
92path to the vendor directory (for example, "d/vendor/p" instead of "p"),
93so that the ImportPath uniquely identifies a given copy of a package.
94The Imports, Deps, TestImports, and XTestImports lists also contain these
95expanded imports paths. See golang.org/s/go15vendor for more about vendoring.
96
97The 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
105The template function "join" calls strings.Join.
106
107The 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
122For more information about the meaning of these fields see the documentation
123for the go/build package's Context type.
124
125The -json flag causes the package data to be printed in JSON format
126instead of using the template format.
127
128The -e flag changes the handling of erroneous packages, those that
129cannot be found or are malformed. By default, the list command
130prints an error to standard error for each erroneous package and
131omits the packages from consideration during the usual printing.
132With the -e flag, the list command never prints errors to standard
133error and instead processes the erroneous packages with the usual
134printing. Erroneous packages will have a non-empty ImportPath and
135a non-nil Error field; other information may or may not be missing
136(zeroed).
137
138For more about build flags, see 'go help build'.
139
140For more about specifying packages, see 'go help packages'.
141	`,
142}
143
144func init() {
145	CmdList.Run = runList // break init cycle
146	work.AddBuildFlags(CmdList)
147}
148
149var listE = CmdList.Flag.Bool("e", false, "")
150var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "")
151var listJson = CmdList.Flag.Bool("json", false, "")
152var nl = []byte{'\n'}
153
154func runList(cmd *base.Command, args []string) {
155	work.BuildInit()
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	var pkgs []*load.Package
198	if *listE {
199		pkgs = load.PackagesAndErrors(args)
200	} else {
201		pkgs = load.Packages(args)
202	}
203
204	// Estimate whether staleness information is needed,
205	// since it's a little bit of work to compute.
206	needStale := *listJson || strings.Contains(*listFmt, ".Stale")
207	if needStale {
208		var b work.Builder
209		b.Init()
210		b.ComputeStaleOnly = true
211		a := &work.Action{}
212		// TODO: Use pkgsFilter?
213		for _, p := range pkgs {
214			a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
215		}
216		b.Do(a)
217	}
218
219	for _, pkg := range pkgs {
220		// Show vendor-expanded paths in listing
221		pkg.TestImports = pkg.Resolve(pkg.TestImports)
222		pkg.XTestImports = pkg.Resolve(pkg.XTestImports)
223
224		do(&pkg.PackagePublic)
225	}
226}
227
228// TrackingWriter tracks the last byte written on every write so
229// we can avoid printing a newline if one was already written or
230// if there is no output at all.
231type TrackingWriter struct {
232	w    *bufio.Writer
233	last byte
234}
235
236func newTrackingWriter(w io.Writer) *TrackingWriter {
237	return &TrackingWriter{
238		w:    bufio.NewWriter(w),
239		last: '\n',
240	}
241}
242
243func (t *TrackingWriter) Write(p []byte) (n int, err error) {
244	n, err = t.w.Write(p)
245	if n > 0 {
246		t.last = p[n-1]
247	}
248	return
249}
250
251func (t *TrackingWriter) Flush() {
252	t.w.Flush()
253}
254
255func (t *TrackingWriter) NeedNL() bool {
256	return t.last != '\n'
257}
258