golang.org/x/tools/gopls@v0.15.3/api-diff/api_diff.go (about)

     1  // Copyright 2021 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  //go:build go1.18
     6  // +build go1.18
     7  
     8  package main
     9  
    10  import (
    11  	"bytes"
    12  	"encoding/json"
    13  	"flag"
    14  	"fmt"
    15  	"log"
    16  	"os"
    17  	"os/exec"
    18  
    19  	"github.com/google/go-cmp/cmp"
    20  	"golang.org/x/tools/gopls/internal/settings"
    21  )
    22  
    23  const usage = `api-diff <previous version> [<current version>]
    24  
    25  Compare the API of two gopls versions. If the second argument is provided, it
    26  will be used as the new version to compare against. Otherwise, compare against
    27  the current API.
    28  `
    29  
    30  func main() {
    31  	flag.Parse()
    32  
    33  	if flag.NArg() < 1 || flag.NArg() > 2 {
    34  		fmt.Fprint(os.Stderr, usage)
    35  		os.Exit(2)
    36  	}
    37  
    38  	oldVer := flag.Arg(0)
    39  	newVer := ""
    40  	if flag.NArg() == 2 {
    41  		newVer = flag.Arg(1)
    42  	}
    43  
    44  	apiDiff, err := diffAPI(oldVer, newVer)
    45  	if err != nil {
    46  		log.Fatal(err)
    47  	}
    48  	fmt.Println("\n" + apiDiff)
    49  }
    50  
    51  func diffAPI(oldVer, newVer string) (string, error) {
    52  	previousAPI, err := loadAPI(oldVer)
    53  	if err != nil {
    54  		return "", fmt.Errorf("loading %s: %v", oldVer, err)
    55  	}
    56  	var currentAPI *settings.APIJSON
    57  	if newVer == "" {
    58  		currentAPI = settings.GeneratedAPIJSON
    59  	} else {
    60  		var err error
    61  		currentAPI, err = loadAPI(newVer)
    62  		if err != nil {
    63  			return "", fmt.Errorf("loading %s: %v", newVer, err)
    64  		}
    65  	}
    66  
    67  	return cmp.Diff(previousAPI, currentAPI), nil
    68  }
    69  
    70  func loadAPI(version string) (*settings.APIJSON, error) {
    71  	ver := fmt.Sprintf("golang.org/x/tools/gopls@%s", version)
    72  	cmd := exec.Command("go", "run", ver, "api-json")
    73  
    74  	stdout := &bytes.Buffer{}
    75  	stderr := &bytes.Buffer{}
    76  	cmd.Stdout = stdout
    77  	cmd.Stderr = stderr
    78  
    79  	if err := cmd.Run(); err != nil {
    80  		return nil, fmt.Errorf("go run failed: %v; stderr:\n%s", err, stderr)
    81  	}
    82  	apiJson := &settings.APIJSON{}
    83  	if err := json.Unmarshal(stdout.Bytes(), apiJson); err != nil {
    84  		return nil, fmt.Errorf("unmarshal: %v", err)
    85  	}
    86  	return apiJson, nil
    87  }