github.com/jd-ly/tools@v0.5.7/internal/lsp/debug/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 debug exports debug information for gopls.
     6  package debug
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	"io"
    12  	"runtime/debug"
    13  	"strings"
    14  )
    15  
    16  type PrintMode int
    17  
    18  const (
    19  	PlainText = PrintMode(iota)
    20  	Markdown
    21  	HTML
    22  )
    23  
    24  // Version is a manually-updated mechanism for tracking versions.
    25  var Version = "master"
    26  
    27  // ServerVersion is the format used by gopls to report its version to the
    28  // client. This format is structured so that the client can parse it easily.
    29  type ServerVersion struct {
    30  	Module
    31  	Deps []*Module `json:"deps,omitempty"`
    32  }
    33  
    34  type Module struct {
    35  	ModuleVersion
    36  	Replace *ModuleVersion `json:"replace,omitempty"`
    37  }
    38  
    39  type ModuleVersion struct {
    40  	Path    string `json:"path,omitempty"`
    41  	Version string `json:"version,omitempty"`
    42  	Sum     string `json:"sum,omitempty"`
    43  }
    44  
    45  // VersionInfo returns the build info for the gopls process. If it was not
    46  // built in module mode, we return a GOPATH-specific message with the
    47  // hardcoded version.
    48  func VersionInfo() *ServerVersion {
    49  	if info, ok := debug.ReadBuildInfo(); ok {
    50  		return getVersion(info)
    51  	}
    52  	path := "gopls, built in GOPATH mode"
    53  	return &ServerVersion{
    54  		Module: Module{
    55  			ModuleVersion: ModuleVersion{
    56  				Path:    path,
    57  				Version: Version,
    58  			},
    59  		},
    60  	}
    61  }
    62  
    63  func getVersion(info *debug.BuildInfo) *ServerVersion {
    64  	serverVersion := ServerVersion{
    65  		Module: Module{
    66  			ModuleVersion: ModuleVersion{
    67  				Path:    info.Main.Path,
    68  				Version: info.Main.Version,
    69  				Sum:     info.Main.Sum,
    70  			},
    71  		},
    72  	}
    73  	for _, d := range info.Deps {
    74  		m := &Module{
    75  			ModuleVersion: ModuleVersion{
    76  				Path:    d.Path,
    77  				Version: d.Version,
    78  				Sum:     d.Sum,
    79  			},
    80  		}
    81  		if d.Replace != nil {
    82  			m.Replace = &ModuleVersion{
    83  				Path:    d.Replace.Path,
    84  				Version: d.Replace.Version,
    85  			}
    86  		}
    87  		serverVersion.Deps = append(serverVersion.Deps, m)
    88  	}
    89  	return &serverVersion
    90  }
    91  
    92  // PrintServerInfo writes HTML debug info to w for the Instance.
    93  func (i *Instance) PrintServerInfo(ctx context.Context, w io.Writer) {
    94  	section(w, HTML, "Server Instance", func() {
    95  		fmt.Fprintf(w, "Start time: %v\n", i.StartTime)
    96  		fmt.Fprintf(w, "LogFile: %s\n", i.Logfile)
    97  		fmt.Fprintf(w, "Working directory: %s\n", i.Workdir)
    98  		fmt.Fprintf(w, "Address: %s\n", i.ServerAddress)
    99  		fmt.Fprintf(w, "Debug address: %s\n", i.DebugAddress)
   100  	})
   101  	PrintVersionInfo(ctx, w, true, HTML)
   102  	section(w, HTML, "Command Line", func() {
   103  		fmt.Fprintf(w, "<a href=/debug/pprof/cmdline>cmdline</a>")
   104  	})
   105  }
   106  
   107  // PrintVersionInfo writes version information to w, using the output format
   108  // specified by mode. verbose controls whether additional information is
   109  // written, including section headers.
   110  func PrintVersionInfo(ctx context.Context, w io.Writer, verbose bool, mode PrintMode) {
   111  	info := VersionInfo()
   112  	if !verbose {
   113  		printBuildInfo(w, info, false, mode)
   114  		return
   115  	}
   116  	section(w, mode, "Build info", func() {
   117  		printBuildInfo(w, info, true, mode)
   118  	})
   119  }
   120  
   121  func section(w io.Writer, mode PrintMode, title string, body func()) {
   122  	switch mode {
   123  	case PlainText:
   124  		fmt.Fprintln(w, title)
   125  		fmt.Fprintln(w, strings.Repeat("-", len(title)))
   126  		body()
   127  	case Markdown:
   128  		fmt.Fprintf(w, "#### %s\n\n```\n", title)
   129  		body()
   130  		fmt.Fprintf(w, "```\n")
   131  	case HTML:
   132  		fmt.Fprintf(w, "<h3>%s</h3>\n<pre>\n", title)
   133  		body()
   134  		fmt.Fprint(w, "</pre>\n")
   135  	}
   136  }
   137  
   138  func printBuildInfo(w io.Writer, info *ServerVersion, verbose bool, mode PrintMode) {
   139  	fmt.Fprintf(w, "%v %v\n", info.Path, Version)
   140  	printModuleInfo(w, &info.Module, mode)
   141  	if !verbose {
   142  		return
   143  	}
   144  	for _, dep := range info.Deps {
   145  		printModuleInfo(w, dep, mode)
   146  	}
   147  }
   148  
   149  func printModuleInfo(w io.Writer, m *Module, mode PrintMode) {
   150  	fmt.Fprintf(w, "    %s@%s", m.Path, m.Version)
   151  	if m.Sum != "" {
   152  		fmt.Fprintf(w, " %s", m.Sum)
   153  	}
   154  	if m.Replace != nil {
   155  		fmt.Fprintf(w, " => %v", m.Replace.Path)
   156  	}
   157  	fmt.Fprintf(w, "\n")
   158  }