...

Source file src/pkg/cmd/go/internal/list/list.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 list implements the ``go list'' command.
     6	package list
     7	
     8	import (
     9		"bufio"
    10		"bytes"
    11		"encoding/json"
    12		"io"
    13		"os"
    14		"sort"
    15		"strings"
    16		"text/template"
    17	
    18		"cmd/go/internal/base"
    19		"cmd/go/internal/cache"
    20		"cmd/go/internal/cfg"
    21		"cmd/go/internal/load"
    22		"cmd/go/internal/modload"
    23		"cmd/go/internal/str"
    24		"cmd/go/internal/work"
    25	)
    26	
    27	var CmdList = &base.Command{
    28		// Note: -f -json -m are listed explicitly because they are the most common list flags.
    29		// Do not send CLs removing them because they're covered by [list flags].
    30		UsageLine: "go list [-f format] [-json] [-m] [list flags] [build flags] [packages]",
    31		Short:     "list packages or modules",
    32		Long: `
    33	List lists the named packages, one per line.
    34	The most commonly-used flags are -f and -json, which control the form
    35	of the output printed for each package. Other list flags, documented below,
    36	control more specific details.
    37	
    38	The default output shows the package import path:
    39	
    40	    bytes
    41	    encoding/json
    42	    github.com/gorilla/mux
    43	    golang.org/x/net/html
    44	
    45	The -f flag specifies an alternate format for the list, using the
    46	syntax of package template. The default output is equivalent
    47	to -f '{{.ImportPath}}'. The struct being passed to the template is:
    48	
    49	    type Package struct {
    50	        Dir           string   // directory containing package sources
    51	        ImportPath    string   // import path of package in dir
    52	        ImportComment string   // path in import comment on package statement
    53	        Name          string   // package name
    54	        Doc           string   // package documentation string
    55	        Target        string   // install path
    56	        Shlib         string   // the shared library that contains this package (only set when -linkshared)
    57	        Goroot        bool     // is this package in the Go root?
    58	        Standard      bool     // is this package part of the standard Go library?
    59	        Stale         bool     // would 'go install' do anything for this package?
    60	        StaleReason   string   // explanation for Stale==true
    61	        Root          string   // Go root or Go path dir containing this package
    62	        ConflictDir   string   // this directory shadows Dir in $GOPATH
    63	        BinaryOnly    bool     // binary-only package (no longer supported)
    64	        ForTest       string   // package is only for use in named test
    65	        Export        string   // file containing export data (when using -export)
    66	        Module        *Module  // info about package's containing module, if any (can be nil)
    67	        Match         []string // command-line patterns matching this package
    68	        DepOnly       bool     // package is only a dependency, not explicitly listed
    69	
    70	        // Source files
    71	        GoFiles         []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
    72	        CgoFiles        []string // .go source files that import "C"
    73	        CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
    74	        IgnoredGoFiles  []string // .go source files ignored due to build constraints
    75	        CFiles          []string // .c source files
    76	        CXXFiles        []string // .cc, .cxx and .cpp source files
    77	        MFiles          []string // .m source files
    78	        HFiles          []string // .h, .hh, .hpp and .hxx source files
    79	        FFiles          []string // .f, .F, .for and .f90 Fortran source files
    80	        SFiles          []string // .s source files
    81	        SwigFiles       []string // .swig files
    82	        SwigCXXFiles    []string // .swigcxx files
    83	        SysoFiles       []string // .syso object files to add to archive
    84	        TestGoFiles     []string // _test.go files in package
    85	        XTestGoFiles    []string // _test.go files outside package
    86	
    87	        // Cgo directives
    88	        CgoCFLAGS    []string // cgo: flags for C compiler
    89	        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
    90	        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
    91	        CgoFFLAGS    []string // cgo: flags for Fortran compiler
    92	        CgoLDFLAGS   []string // cgo: flags for linker
    93	        CgoPkgConfig []string // cgo: pkg-config names
    94	
    95	        // Dependency information
    96	        Imports      []string          // import paths used by this package
    97	        ImportMap    map[string]string // map from source import to ImportPath (identity entries omitted)
    98	        Deps         []string          // all (recursively) imported dependencies
    99	        TestImports  []string          // imports from TestGoFiles
   100	        XTestImports []string          // imports from XTestGoFiles
   101	
   102	        // Error information
   103	        Incomplete bool            // this package or a dependency has an error
   104	        Error      *PackageError   // error loading package
   105	        DepsErrors []*PackageError // errors loading dependencies
   106	    }
   107	
   108	Packages stored in vendor directories report an ImportPath that includes the
   109	path to the vendor directory (for example, "d/vendor/p" instead of "p"),
   110	so that the ImportPath uniquely identifies a given copy of a package.
   111	The Imports, Deps, TestImports, and XTestImports lists also contain these
   112	expanded import paths. See golang.org/s/go15vendor for more about vendoring.
   113	
   114	The error information, if any, is
   115	
   116	    type PackageError struct {
   117	        ImportStack   []string // shortest path from package named on command line to this one
   118	        Pos           string   // position of error (if present, file:line:col)
   119	        Err           string   // the error itself
   120	    }
   121	
   122	The module information is a Module struct, defined in the discussion
   123	of list -m below.
   124	
   125	The template function "join" calls strings.Join.
   126	
   127	The template function "context" returns the build context, defined as:
   128	
   129	    type Context struct {
   130	        GOARCH        string   // target architecture
   131	        GOOS          string   // target operating system
   132	        GOROOT        string   // Go root
   133	        GOPATH        string   // Go path
   134	        CgoEnabled    bool     // whether cgo can be used
   135	        UseAllFiles   bool     // use files regardless of +build lines, file names
   136	        Compiler      string   // compiler to assume when computing target paths
   137	        BuildTags     []string // build constraints to match in +build lines
   138	        ReleaseTags   []string // releases the current release is compatible with
   139	        InstallSuffix string   // suffix to use in the name of the install dir
   140	    }
   141	
   142	For more information about the meaning of these fields see the documentation
   143	for the go/build package's Context type.
   144	
   145	The -json flag causes the package data to be printed in JSON format
   146	instead of using the template format.
   147	
   148	The -compiled flag causes list to set CompiledGoFiles to the Go source
   149	files presented to the compiler. Typically this means that it repeats
   150	the files listed in GoFiles and then also adds the Go code generated
   151	by processing CgoFiles and SwigFiles. The Imports list contains the
   152	union of all imports from both GoFiles and CompiledGoFiles.
   153	
   154	The -deps flag causes list to iterate over not just the named packages
   155	but also all their dependencies. It visits them in a depth-first post-order
   156	traversal, so that a package is listed only after all its dependencies.
   157	Packages not explicitly listed on the command line will have the DepOnly
   158	field set to true.
   159	
   160	The -e flag changes the handling of erroneous packages, those that
   161	cannot be found or are malformed. By default, the list command
   162	prints an error to standard error for each erroneous package and
   163	omits the packages from consideration during the usual printing.
   164	With the -e flag, the list command never prints errors to standard
   165	error and instead processes the erroneous packages with the usual
   166	printing. Erroneous packages will have a non-empty ImportPath and
   167	a non-nil Error field; other information may or may not be missing
   168	(zeroed).
   169	
   170	The -export flag causes list to set the Export field to the name of a
   171	file containing up-to-date export information for the given package.
   172	
   173	The -find flag causes list to identify the named packages but not
   174	resolve their dependencies: the Imports and Deps lists will be empty.
   175	
   176	The -test flag causes list to report not only the named packages
   177	but also their test binaries (for packages with tests), to convey to
   178	source code analysis tools exactly how test binaries are constructed.
   179	The reported import path for a test binary is the import path of
   180	the package followed by a ".test" suffix, as in "math/rand.test".
   181	When building a test, it is sometimes necessary to rebuild certain
   182	dependencies specially for that test (most commonly the tested
   183	package itself). The reported import path of a package recompiled
   184	for a particular test binary is followed by a space and the name of
   185	the test binary in brackets, as in "math/rand [math/rand.test]"
   186	or "regexp [sort.test]". The ForTest field is also set to the name
   187	of the package being tested ("math/rand" or "sort" in the previous
   188	examples).
   189	
   190	The Dir, Target, Shlib, Root, ConflictDir, and Export file paths
   191	are all absolute paths.
   192	
   193	By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir
   194	(that is, paths relative to Dir, not absolute paths).
   195	The generated files added when using the -compiled and -test flags
   196	are absolute paths referring to cached copies of generated Go source files.
   197	Although they are Go source files, the paths may not end in ".go".
   198	
   199	The -m flag causes list to list modules instead of packages.
   200	
   201	When listing modules, the -f flag still specifies a format template
   202	applied to a Go struct, but now a Module struct:
   203	
   204	    type Module struct {
   205	        Path      string       // module path
   206	        Version   string       // module version
   207	        Versions  []string     // available module versions (with -versions)
   208	        Replace   *Module      // replaced by this module
   209	        Time      *time.Time   // time version was created
   210	        Update    *Module      // available update, if any (with -u)
   211	        Main      bool         // is this the main module?
   212	        Indirect  bool         // is this module only an indirect dependency of main module?
   213	        Dir       string       // directory holding files for this module, if any
   214	        GoMod     string       // path to go.mod file for this module, if any
   215	        GoVersion string       // go version used in module
   216	        Error     *ModuleError // error loading module
   217	    }
   218	
   219	    type ModuleError struct {
   220	        Err string // the error itself
   221	    }
   222	
   223	The default output is to print the module path and then
   224	information about the version and replacement if any.
   225	For example, 'go list -m all' might print:
   226	
   227	    my/main/module
   228	    golang.org/x/text v0.3.0 => /tmp/text
   229	    rsc.io/pdf v0.1.1
   230	
   231	The Module struct has a String method that formats this
   232	line of output, so that the default format is equivalent
   233	to -f '{{.String}}'.
   234	
   235	Note that when a module has been replaced, its Replace field
   236	describes the replacement module, and its Dir field is set to
   237	the replacement's source code, if present. (That is, if Replace
   238	is non-nil, then Dir is set to Replace.Dir, with no access to
   239	the replaced source code.)
   240	
   241	The -u flag adds information about available upgrades.
   242	When the latest version of a given module is newer than
   243	the current one, list -u sets the Module's Update field
   244	to information about the newer module.
   245	The Module's String method indicates an available upgrade by
   246	formatting the newer version in brackets after the current version.
   247	For example, 'go list -m -u all' might print:
   248	
   249	    my/main/module
   250	    golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
   251	    rsc.io/pdf v0.1.1 [v0.1.2]
   252	
   253	(For tools, 'go list -m -u -json all' may be more convenient to parse.)
   254	
   255	The -versions flag causes list to set the Module's Versions field
   256	to a list of all known versions of that module, ordered according
   257	to semantic versioning, earliest to latest. The flag also changes
   258	the default output format to display the module path followed by the
   259	space-separated version list.
   260	
   261	The arguments to list -m are interpreted as a list of modules, not packages.
   262	The main module is the module containing the current directory.
   263	The active modules are the main module and its dependencies.
   264	With no arguments, list -m shows the main module.
   265	With arguments, list -m shows the modules specified by the arguments.
   266	Any of the active modules can be specified by its module path.
   267	The special pattern "all" specifies all the active modules, first the main
   268	module and then dependencies sorted by module path.
   269	A pattern containing "..." specifies the active modules whose
   270	module paths match the pattern.
   271	A query of the form path@version specifies the result of that query,
   272	which is not limited to active modules.
   273	See 'go help modules' for more about module queries.
   274	
   275	The template function "module" takes a single string argument
   276	that must be a module path or query and returns the specified
   277	module as a Module struct. If an error occurs, the result will
   278	be a Module struct with a non-nil Error field.
   279	
   280	For more about build flags, see 'go help build'.
   281	
   282	For more about specifying packages, see 'go help packages'.
   283	
   284	For more about modules, see 'go help modules'.
   285		`,
   286	}
   287	
   288	func init() {
   289		CmdList.Run = runList // break init cycle
   290		work.AddBuildFlags(CmdList)
   291	}
   292	
   293	var (
   294		listCompiled = CmdList.Flag.Bool("compiled", false, "")
   295		listDeps     = CmdList.Flag.Bool("deps", false, "")
   296		listE        = CmdList.Flag.Bool("e", false, "")
   297		listExport   = CmdList.Flag.Bool("export", false, "")
   298		listFmt      = CmdList.Flag.String("f", "", "")
   299		listFind     = CmdList.Flag.Bool("find", false, "")
   300		listJson     = CmdList.Flag.Bool("json", false, "")
   301		listM        = CmdList.Flag.Bool("m", false, "")
   302		listU        = CmdList.Flag.Bool("u", false, "")
   303		listTest     = CmdList.Flag.Bool("test", false, "")
   304		listVersions = CmdList.Flag.Bool("versions", false, "")
   305	)
   306	
   307	var nl = []byte{'\n'}
   308	
   309	func runList(cmd *base.Command, args []string) {
   310		modload.LoadTests = *listTest
   311		work.BuildInit()
   312		out := newTrackingWriter(os.Stdout)
   313		defer out.w.Flush()
   314	
   315		if *listFmt == "" {
   316			if *listM {
   317				*listFmt = "{{.String}}"
   318				if *listVersions {
   319					*listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}`
   320				}
   321			} else {
   322				*listFmt = "{{.ImportPath}}"
   323			}
   324		}
   325	
   326		var do func(interface{})
   327		if *listJson {
   328			do = func(x interface{}) {
   329				b, err := json.MarshalIndent(x, "", "\t")
   330				if err != nil {
   331					out.Flush()
   332					base.Fatalf("%s", err)
   333				}
   334				out.Write(b)
   335				out.Write(nl)
   336			}
   337		} else {
   338			var cachedCtxt *Context
   339			context := func() *Context {
   340				if cachedCtxt == nil {
   341					cachedCtxt = newContext(&cfg.BuildContext)
   342				}
   343				return cachedCtxt
   344			}
   345			fm := template.FuncMap{
   346				"join":    strings.Join,
   347				"context": context,
   348				"module":  modload.ModuleInfo,
   349			}
   350			tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt)
   351			if err != nil {
   352				base.Fatalf("%s", err)
   353			}
   354			do = func(x interface{}) {
   355				if err := tmpl.Execute(out, x); err != nil {
   356					out.Flush()
   357					base.Fatalf("%s", err)
   358				}
   359				if out.NeedNL() {
   360					out.Write(nl)
   361				}
   362			}
   363		}
   364	
   365		if *listM {
   366			// Module mode.
   367			if *listCompiled {
   368				base.Fatalf("go list -compiled cannot be used with -m")
   369			}
   370			if *listDeps {
   371				// TODO(rsc): Could make this mean something with -m.
   372				base.Fatalf("go list -deps cannot be used with -m")
   373			}
   374			if *listExport {
   375				base.Fatalf("go list -export cannot be used with -m")
   376			}
   377			if *listFind {
   378				base.Fatalf("go list -find cannot be used with -m")
   379			}
   380			if *listTest {
   381				base.Fatalf("go list -test cannot be used with -m")
   382			}
   383	
   384			if modload.Init(); !modload.Enabled() {
   385				base.Fatalf("go list -m: not using modules")
   386			}
   387			modload.LoadBuildList()
   388	
   389			mods := modload.ListModules(args, *listU, *listVersions)
   390			if !*listE {
   391				for _, m := range mods {
   392					if m.Error != nil {
   393						base.Errorf("go list -m: %v", m.Error.Err)
   394					}
   395				}
   396				base.ExitIfErrors()
   397			}
   398			for _, m := range mods {
   399				do(m)
   400			}
   401			return
   402		}
   403	
   404		// Package mode (not -m).
   405		if *listU {
   406			base.Fatalf("go list -u can only be used with -m")
   407		}
   408		if *listVersions {
   409			base.Fatalf("go list -versions can only be used with -m")
   410		}
   411	
   412		// These pairings make no sense.
   413		if *listFind && *listDeps {
   414			base.Fatalf("go list -deps cannot be used with -find")
   415		}
   416		if *listFind && *listTest {
   417			base.Fatalf("go list -test cannot be used with -find")
   418		}
   419	
   420		load.IgnoreImports = *listFind
   421		var pkgs []*load.Package
   422		if *listE {
   423			pkgs = load.PackagesAndErrors(args)
   424		} else {
   425			pkgs = load.Packages(args)
   426		}
   427	
   428		if cache.Default() == nil {
   429			// These flags return file names pointing into the build cache,
   430			// so the build cache must exist.
   431			if *listCompiled {
   432				base.Fatalf("go list -compiled requires build cache")
   433			}
   434			if *listExport {
   435				base.Fatalf("go list -export requires build cache")
   436			}
   437			if *listTest {
   438				base.Fatalf("go list -test requires build cache")
   439			}
   440		}
   441	
   442		if *listTest {
   443			c := cache.Default()
   444			// Add test binaries to packages to be listed.
   445			for _, p := range pkgs {
   446				if p.Error != nil {
   447					continue
   448				}
   449				if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 {
   450					var pmain, ptest, pxtest *load.Package
   451					var err error
   452					if *listE {
   453						pmain, ptest, pxtest = load.TestPackagesAndErrors(p, nil)
   454					} else {
   455						pmain, ptest, pxtest, err = load.TestPackagesFor(p, nil)
   456						if err != nil {
   457							base.Errorf("can't load test package: %s", err)
   458						}
   459					}
   460					if pmain != nil {
   461						pkgs = append(pkgs, pmain)
   462						data := *pmain.Internal.TestmainGo
   463						h := cache.NewHash("testmain")
   464						h.Write([]byte("testmain\n"))
   465						h.Write(data)
   466						out, _, err := c.Put(h.Sum(), bytes.NewReader(data))
   467						if err != nil {
   468							base.Fatalf("%s", err)
   469						}
   470						pmain.GoFiles[0] = c.OutputFile(out)
   471					}
   472					if ptest != nil && ptest != p {
   473						pkgs = append(pkgs, ptest)
   474					}
   475					if pxtest != nil {
   476						pkgs = append(pkgs, pxtest)
   477					}
   478				}
   479			}
   480		}
   481	
   482		// Remember which packages are named on the command line.
   483		cmdline := make(map[*load.Package]bool)
   484		for _, p := range pkgs {
   485			cmdline[p] = true
   486		}
   487	
   488		if *listDeps {
   489			// Note: This changes the order of the listed packages
   490			// from "as written on the command line" to
   491			// "a depth-first post-order traversal".
   492			// (The dependency exploration order for a given node
   493			// is alphabetical, same as listed in .Deps.)
   494			// Note that -deps is applied after -test,
   495			// so that you only get descriptions of tests for the things named
   496			// explicitly on the command line, not for all dependencies.
   497			pkgs = load.PackageList(pkgs)
   498		}
   499	
   500		// Do we need to run a build to gather information?
   501		needStale := *listJson || strings.Contains(*listFmt, ".Stale")
   502		if needStale || *listExport || *listCompiled {
   503			var b work.Builder
   504			b.Init()
   505			b.IsCmdList = true
   506			b.NeedExport = *listExport
   507			b.NeedCompiledGoFiles = *listCompiled
   508			a := &work.Action{}
   509			// TODO: Use pkgsFilter?
   510			for _, p := range pkgs {
   511				if len(p.GoFiles)+len(p.CgoFiles) > 0 {
   512					a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p))
   513				}
   514			}
   515			b.Do(a)
   516		}
   517	
   518		for _, p := range pkgs {
   519			// Show vendor-expanded paths in listing
   520			p.TestImports = p.Resolve(p.TestImports)
   521			p.XTestImports = p.Resolve(p.XTestImports)
   522			p.DepOnly = !cmdline[p]
   523	
   524			if *listCompiled {
   525				p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports)
   526			}
   527		}
   528	
   529		if *listTest {
   530			all := pkgs
   531			if !*listDeps {
   532				all = load.PackageList(pkgs)
   533			}
   534			// Update import paths to distinguish the real package p
   535			// from p recompiled for q.test.
   536			// This must happen only once the build code is done
   537			// looking at import paths, because it will get very confused
   538			// if it sees these.
   539			old := make(map[string]string)
   540			for _, p := range all {
   541				if p.ForTest != "" {
   542					new := p.ImportPath + " [" + p.ForTest + ".test]"
   543					old[new] = p.ImportPath
   544					p.ImportPath = new
   545				}
   546				p.DepOnly = !cmdline[p]
   547			}
   548			// Update import path lists to use new strings.
   549			m := make(map[string]string)
   550			for _, p := range all {
   551				for _, p1 := range p.Internal.Imports {
   552					if p1.ForTest != "" {
   553						m[old[p1.ImportPath]] = p1.ImportPath
   554					}
   555				}
   556				for i, old := range p.Imports {
   557					if new := m[old]; new != "" {
   558						p.Imports[i] = new
   559					}
   560				}
   561				for old := range m {
   562					delete(m, old)
   563				}
   564			}
   565			// Recompute deps lists using new strings, from the leaves up.
   566			for _, p := range all {
   567				deps := make(map[string]bool)
   568				for _, p1 := range p.Internal.Imports {
   569					deps[p1.ImportPath] = true
   570					for _, d := range p1.Deps {
   571						deps[d] = true
   572					}
   573				}
   574				p.Deps = make([]string, 0, len(deps))
   575				for d := range deps {
   576					p.Deps = append(p.Deps, d)
   577				}
   578				sort.Strings(p.Deps)
   579			}
   580		}
   581	
   582		// Record non-identity import mappings in p.ImportMap.
   583		for _, p := range pkgs {
   584			for i, srcPath := range p.Internal.RawImports {
   585				path := p.Imports[i]
   586				if path != srcPath {
   587					if p.ImportMap == nil {
   588						p.ImportMap = make(map[string]string)
   589					}
   590					p.ImportMap[srcPath] = path
   591				}
   592			}
   593		}
   594	
   595		for _, p := range pkgs {
   596			do(&p.PackagePublic)
   597		}
   598	}
   599	
   600	// TrackingWriter tracks the last byte written on every write so
   601	// we can avoid printing a newline if one was already written or
   602	// if there is no output at all.
   603	type TrackingWriter struct {
   604		w    *bufio.Writer
   605		last byte
   606	}
   607	
   608	func newTrackingWriter(w io.Writer) *TrackingWriter {
   609		return &TrackingWriter{
   610			w:    bufio.NewWriter(w),
   611			last: '\n',
   612		}
   613	}
   614	
   615	func (t *TrackingWriter) Write(p []byte) (n int, err error) {
   616		n, err = t.w.Write(p)
   617		if n > 0 {
   618			t.last = p[n-1]
   619		}
   620		return
   621	}
   622	
   623	func (t *TrackingWriter) Flush() {
   624		t.w.Flush()
   625	}
   626	
   627	func (t *TrackingWriter) NeedNL() bool {
   628		return t.last != '\n'
   629	}
   630	

View as plain text