golang.org/x/tools/gopls@v0.15.3/internal/cmd/info.go (about)

     1  // Copyright 2019 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 cmd
     6  
     7  // This file defines the help, bug, version, api-json, licenses commands.
     8  
     9  import (
    10  	"bytes"
    11  	"context"
    12  	"encoding/json"
    13  	"flag"
    14  	"fmt"
    15  	"net/url"
    16  	"os"
    17  	"sort"
    18  	"strings"
    19  
    20  	"golang.org/x/tools/gopls/internal/debug"
    21  	"golang.org/x/tools/gopls/internal/filecache"
    22  	"golang.org/x/tools/gopls/internal/settings"
    23  	"golang.org/x/tools/gopls/internal/util/browser"
    24  	goplsbug "golang.org/x/tools/gopls/internal/util/bug"
    25  	"golang.org/x/tools/internal/tool"
    26  )
    27  
    28  // help implements the help command.
    29  type help struct {
    30  	app *Application
    31  }
    32  
    33  func (h *help) Name() string      { return "help" }
    34  func (h *help) Parent() string    { return h.app.Name() }
    35  func (h *help) Usage() string     { return "" }
    36  func (h *help) ShortHelp() string { return "print usage information for subcommands" }
    37  func (h *help) DetailedHelp(f *flag.FlagSet) {
    38  	fmt.Fprint(f.Output(), `
    39  
    40  Examples:
    41  $ gopls help                         # main gopls help message
    42  $ gopls help remote                  # help on 'remote' command
    43  $ gopls help remote sessions         # help on 'remote sessions' subcommand
    44  `)
    45  	printFlagDefaults(f)
    46  }
    47  
    48  // Run prints help information about a subcommand.
    49  func (h *help) Run(ctx context.Context, args ...string) error {
    50  	find := func(cmds []tool.Application, name string) tool.Application {
    51  		for _, cmd := range cmds {
    52  			if cmd.Name() == name {
    53  				return cmd
    54  			}
    55  		}
    56  		return nil
    57  	}
    58  
    59  	// Find the subcommand denoted by args (empty => h.app).
    60  	var cmd tool.Application = h.app
    61  	for i, arg := range args {
    62  		cmd = find(getSubcommands(cmd), arg)
    63  		if cmd == nil {
    64  			return tool.CommandLineErrorf(
    65  				"no such subcommand: %s", strings.Join(args[:i+1], " "))
    66  		}
    67  	}
    68  
    69  	// 'gopls help cmd subcmd' is equivalent to 'gopls cmd subcmd -h'.
    70  	// The flag package prints the usage information (defined by tool.Run)
    71  	// when it sees the -h flag.
    72  	fs := flag.NewFlagSet(cmd.Name(), flag.ExitOnError)
    73  	return tool.Run(ctx, fs, h.app, append(args[:len(args):len(args)], "-h"))
    74  }
    75  
    76  // version implements the version command.
    77  type version struct {
    78  	JSON bool `flag:"json" help:"outputs in json format."`
    79  
    80  	app *Application
    81  }
    82  
    83  func (v *version) Name() string      { return "version" }
    84  func (v *version) Parent() string    { return v.app.Name() }
    85  func (v *version) Usage() string     { return "" }
    86  func (v *version) ShortHelp() string { return "print the gopls version information" }
    87  func (v *version) DetailedHelp(f *flag.FlagSet) {
    88  	fmt.Fprint(f.Output(), ``)
    89  	printFlagDefaults(f)
    90  }
    91  
    92  // Run prints version information to stdout.
    93  func (v *version) Run(ctx context.Context, args ...string) error {
    94  	var mode = debug.PlainText
    95  	if v.JSON {
    96  		mode = debug.JSON
    97  	}
    98  
    99  	return debug.PrintVersionInfo(ctx, os.Stdout, v.app.verbose(), mode)
   100  }
   101  
   102  // bug implements the bug command.
   103  type bug struct {
   104  	app *Application
   105  }
   106  
   107  func (b *bug) Name() string      { return "bug" }
   108  func (b *bug) Parent() string    { return b.app.Name() }
   109  func (b *bug) Usage() string     { return "" }
   110  func (b *bug) ShortHelp() string { return "report a bug in gopls" }
   111  func (b *bug) DetailedHelp(f *flag.FlagSet) {
   112  	fmt.Fprint(f.Output(), ``)
   113  	printFlagDefaults(f)
   114  }
   115  
   116  const goplsBugPrefix = "x/tools/gopls: <DESCRIBE THE PROBLEM>"
   117  const goplsBugHeader = `ATTENTION: Please answer these questions BEFORE submitting your issue. Thanks!
   118  
   119  #### What did you do?
   120  If possible, provide a recipe for reproducing the error.
   121  A complete runnable program is good.
   122  A link on play.golang.org is better.
   123  A failing unit test is the best.
   124  
   125  #### What did you expect to see?
   126  
   127  
   128  #### What did you see instead?
   129  
   130  
   131  `
   132  
   133  // Run collects some basic information and then prepares an issue ready to
   134  // be reported.
   135  func (b *bug) Run(ctx context.Context, args ...string) error {
   136  	// This undocumented environment variable allows
   137  	// the cmd integration test (and maintainers) to
   138  	// trigger a call to bug.Report.
   139  	if msg := os.Getenv("TEST_GOPLS_BUG"); msg != "" {
   140  		filecache.Start() // register bug handler
   141  		goplsbug.Report(msg)
   142  		return nil
   143  	}
   144  
   145  	// Enumerate bug reports, grouped and sorted.
   146  	_, reports := filecache.BugReports()
   147  	sort.Slice(reports, func(i, j int) bool {
   148  		x, y := reports[i], reports[i]
   149  		if x.Key != y.Key {
   150  			return x.Key < y.Key // ascending key order
   151  		}
   152  		return y.AtTime.Before(x.AtTime) // most recent first
   153  	})
   154  	keyDenom := make(map[string]int) // key is "file:line"
   155  	for _, report := range reports {
   156  		keyDenom[report.Key]++
   157  	}
   158  
   159  	// Privacy: the content of 'public' will be posted to GitHub
   160  	// to populate an issue textarea. Even though the user must
   161  	// submit the form to share the information with the world,
   162  	// merely populating the form causes us to share the
   163  	// information with GitHub itself.
   164  	//
   165  	// For that reason, we cannot write private information to
   166  	// public, such as bug reports, which may quote source code.
   167  	public := &bytes.Buffer{}
   168  	fmt.Fprint(public, goplsBugHeader)
   169  	if len(reports) > 0 {
   170  		fmt.Fprintf(public, "#### Internal errors\n\n")
   171  		fmt.Fprintf(public, "Gopls detected %d internal errors, %d distinct:\n",
   172  			len(reports), len(keyDenom))
   173  		for key, denom := range keyDenom {
   174  			fmt.Fprintf(public, "- %s (%d)\n", key, denom)
   175  		}
   176  		fmt.Fprintf(public, "\nPlease copy the full information printed by `gopls bug` here, if you are comfortable sharing it.\n\n")
   177  	}
   178  	debug.PrintVersionInfo(ctx, public, true, debug.Markdown)
   179  	body := public.String()
   180  	title := strings.Join(args, " ")
   181  	if !strings.HasPrefix(title, goplsBugPrefix) {
   182  		title = goplsBugPrefix + title
   183  	}
   184  	if !browser.Open("https://github.com/golang/go/issues/new?title=" + url.QueryEscape(title) + "&body=" + url.QueryEscape(body)) {
   185  		fmt.Print("Please file a new issue at golang.org/issue/new using this template:\n\n")
   186  		fmt.Print(body)
   187  	}
   188  
   189  	// Print bug reports to stdout (not GitHub).
   190  	keyNum := make(map[string]int)
   191  	for _, report := range reports {
   192  		fmt.Printf("-- %v -- \n", report.AtTime)
   193  
   194  		// Append seq number (e.g. " (1/2)") for repeated keys.
   195  		var seq string
   196  		if denom := keyDenom[report.Key]; denom > 1 {
   197  			keyNum[report.Key]++
   198  			seq = fmt.Sprintf(" (%d/%d)", keyNum[report.Key], denom)
   199  		}
   200  
   201  		// Privacy:
   202  		// - File and Stack may contain the name of the user that built gopls.
   203  		// - Description may contain names of the user's packages/files/symbols.
   204  		fmt.Printf("%s:%d: %s%s\n\n", report.File, report.Line, report.Description, seq)
   205  		fmt.Printf("%s\n\n", report.Stack)
   206  	}
   207  	if len(reports) > 0 {
   208  		fmt.Printf("Please copy the above information into the GitHub issue, if you are comfortable sharing it.\n")
   209  	}
   210  
   211  	return nil
   212  }
   213  
   214  type apiJSON struct {
   215  	app *Application
   216  }
   217  
   218  func (j *apiJSON) Name() string      { return "api-json" }
   219  func (j *apiJSON) Parent() string    { return j.app.Name() }
   220  func (j *apiJSON) Usage() string     { return "" }
   221  func (j *apiJSON) ShortHelp() string { return "print JSON describing gopls API" }
   222  func (j *apiJSON) DetailedHelp(f *flag.FlagSet) {
   223  	fmt.Fprint(f.Output(), ``)
   224  	printFlagDefaults(f)
   225  }
   226  
   227  func (j *apiJSON) Run(ctx context.Context, args ...string) error {
   228  	js, err := json.MarshalIndent(settings.GeneratedAPIJSON, "", "\t")
   229  	if err != nil {
   230  		return err
   231  	}
   232  	fmt.Fprint(os.Stdout, string(js))
   233  	return nil
   234  }
   235  
   236  type licenses struct {
   237  	app *Application
   238  }
   239  
   240  func (l *licenses) Name() string      { return "licenses" }
   241  func (l *licenses) Parent() string    { return l.app.Name() }
   242  func (l *licenses) Usage() string     { return "" }
   243  func (l *licenses) ShortHelp() string { return "print licenses of included software" }
   244  func (l *licenses) DetailedHelp(f *flag.FlagSet) {
   245  	fmt.Fprint(f.Output(), ``)
   246  	printFlagDefaults(f)
   247  }
   248  
   249  const licensePreamble = `
   250  gopls is made available under the following BSD-style license:
   251  
   252  Copyright (c) 2009 The Go Authors. All rights reserved.
   253  
   254  Redistribution and use in source and binary forms, with or without
   255  modification, are permitted provided that the following conditions are
   256  met:
   257  
   258     * Redistributions of source code must retain the above copyright
   259  notice, this list of conditions and the following disclaimer.
   260     * Redistributions in binary form must reproduce the above
   261  copyright notice, this list of conditions and the following disclaimer
   262  in the documentation and/or other materials provided with the
   263  distribution.
   264     * Neither the name of Google Inc. nor the names of its
   265  contributors may be used to endorse or promote products derived from
   266  this software without specific prior written permission.
   267  
   268  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   269  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   270  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   271  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   272  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   273  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   274  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   275  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   276  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   277  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   278  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   279  
   280  gopls implements the LSP specification, which is made available under the following license:
   281  
   282  Copyright (c) Microsoft Corporation
   283  
   284  All rights reserved.
   285  
   286  MIT License
   287  
   288  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
   289  files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
   290  modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
   291  is furnished to do so, subject to the following conditions:
   292  
   293  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
   294  
   295  THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   296  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
   297  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
   298  OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   299  
   300  gopls also includes software made available under these licenses:
   301  `
   302  
   303  func (l *licenses) Run(ctx context.Context, args ...string) error {
   304  	opts := settings.DefaultOptions(l.app.options)
   305  	txt := licensePreamble
   306  	if opts.LicensesText == "" {
   307  		txt += "(development gopls, license information not available)"
   308  	} else {
   309  		txt += opts.LicensesText
   310  	}
   311  	fmt.Fprint(os.Stdout, txt)
   312  	return nil
   313  }