github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/core/chaincode/platforms/golang/list.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package golang
     8  
     9  import (
    10  	"context"
    11  	"encoding/json"
    12  	"fmt"
    13  	"io"
    14  	"os"
    15  	"os/exec"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/pkg/errors"
    20  )
    21  
    22  const listTimeout = 3 * time.Minute
    23  
    24  const packageListFormat = `
    25  {{- if eq .Goroot false -}}
    26  {
    27      "import_path": "{{ .ImportPath }}",
    28      "incomplete": {{ .Incomplete }},
    29      "dir": "{{ .Dir }}",
    30      "go_files" : [{{ range $i, $file := .GoFiles  }}{{ if $i }}, {{ end }}"{{ $file }}"{{end}}],
    31      "c_files":   [{{ range $i, $file := .CFiles   }}{{ if $i }}, {{ end }}"{{ $file }}"{{end}}],
    32      "cgo_files": [{{ range $i, $file := .CgoFiles }}{{ if $i }}, {{ end }}"{{ $file }}"{{end}}],
    33      "h_files":   [{{ range $i, $file := .HFiles   }}{{ if $i }}, {{ end }}"{{ $file }}"{{end}}],
    34      "s_files":   [{{ range $i, $file := .SFiles   }}{{ if $i }}, {{ end }}"{{ $file }}"{{end}}],
    35      "ignored_go_files": [{{ range $i, $file := .IgnoredGoFiles }}{{ if $i }}, {{ end }}"{{ $file }}"{{end}}]
    36  }
    37  {{- end -}}`
    38  
    39  type PackageInfo struct {
    40  	ImportPath     string   `json:"import_path,omitempty"`
    41  	Dir            string   `json:"dir,omitempty"`
    42  	GoFiles        []string `json:"go_files,omitempty"`
    43  	CFiles         []string `json:"c_files,omitempty"`
    44  	CgoFiles       []string `json:"cgo_files,omitempty"`
    45  	HFiles         []string `json:"h_files,omitempty"`
    46  	SFiles         []string `json:"s_files,omitempty"`
    47  	IgnoredGoFiles []string `json:"ignored_go_files,omitempty"`
    48  	Incomplete     bool     `json:"incomplete,omitempty"`
    49  }
    50  
    51  func (p PackageInfo) Files() []string {
    52  	var files []string
    53  	files = append(files, p.GoFiles...)
    54  	files = append(files, p.CFiles...)
    55  	files = append(files, p.CgoFiles...)
    56  	files = append(files, p.HFiles...)
    57  	files = append(files, p.SFiles...)
    58  	files = append(files, p.IgnoredGoFiles...)
    59  	return files
    60  }
    61  
    62  // gopathDependencyPackageInfo extracts dependency information for
    63  // specified package.
    64  func gopathDependencyPackageInfo(goos, goarch, pkg string) ([]PackageInfo, error) {
    65  	ctx, cancel := context.WithTimeout(context.Background(), listTimeout)
    66  	defer cancel()
    67  
    68  	cmd := exec.CommandContext(ctx, "go", "list", "-deps", "-f", packageListFormat, pkg)
    69  	cmd.Env = append(os.Environ(), "GOOS="+goos, "GOARCH="+goarch)
    70  
    71  	stdout, err := cmd.StdoutPipe()
    72  	if err != nil {
    73  		return nil, wrapExitErr(err, "'go list -deps' failed")
    74  	}
    75  	decoder := json.NewDecoder(stdout)
    76  
    77  	err = cmd.Start()
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  
    82  	var list []PackageInfo
    83  	for {
    84  		var packageInfo PackageInfo
    85  		err := decoder.Decode(&packageInfo)
    86  		if err == io.EOF {
    87  			break
    88  		}
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  		if packageInfo.Incomplete {
    93  			return nil, fmt.Errorf("failed to calculate dependencies: incomplete package: %s", packageInfo.ImportPath)
    94  		}
    95  
    96  		list = append(list, packageInfo)
    97  	}
    98  
    99  	err = cmd.Wait()
   100  	if err != nil {
   101  		return nil, errors.Wrapf(err, "listing deps for pacakge %s failed", pkg)
   102  	}
   103  
   104  	return list, nil
   105  }
   106  
   107  func wrapExitErr(err error, message string) error {
   108  	if ee, ok := err.(*exec.ExitError); ok {
   109  		return errors.Wrapf(err, message+" with: %s", strings.TrimRight(string(ee.Stderr), "\n\r\t"))
   110  	}
   111  	return errors.Wrap(err, message)
   112  }
   113  
   114  const moduleListFormat = `{
   115      "dir": "{{ .Module.Dir }}",
   116      "gomod": "{{ .Module.GoMod }}",
   117      "import_path": "{{ .ImportPath }}",
   118      "module_path": "{{ .Module.Path }}"
   119  }`
   120  
   121  type ModuleInfo struct {
   122  	Dir        string `json:"dir,omitempty"`
   123  	ImportPath string `json:"import_path,omitempty"`
   124  	ModulePath string `json:"module_path,omitempty"`
   125  	GoMod      string `json:"gomod,omitempty"`
   126  }
   127  
   128  // listModuleInfo extracts module information for the curent working directory.
   129  func listModuleInfo(extraEnv ...string) (*ModuleInfo, error) {
   130  	ctx, cancel := context.WithTimeout(context.Background(), listTimeout)
   131  	defer cancel()
   132  
   133  	cmd := exec.CommandContext(ctx, "go", "list", "-f", moduleListFormat, ".")
   134  	cmd.Env = append(os.Environ(), "GO111MODULE=on")
   135  	cmd.Env = append(cmd.Env, extraEnv...)
   136  
   137  	output, err := cmd.Output()
   138  	if err != nil {
   139  		return nil, wrapExitErr(err, "'go list' failed")
   140  	}
   141  
   142  	var moduleInfo ModuleInfo
   143  	if err := json.Unmarshal(output, &moduleInfo); err != nil {
   144  		return nil, errors.Wrap(err, "failed to unmarshal output from 'go list'")
   145  	}
   146  
   147  	return &moduleInfo, nil
   148  }