github.com/golang/dep@v0.5.4/internal/importers/govendor/importer.go (about)

     1  // Copyright 2016 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 govendor
     6  
     7  import (
     8  	"encoding/json"
     9  	"io/ioutil"
    10  	"log"
    11  	"os"
    12  	"path"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/golang/dep"
    17  	"github.com/golang/dep/gps"
    18  	"github.com/golang/dep/internal/importers/base"
    19  	"github.com/pkg/errors"
    20  )
    21  
    22  const govendorDir = "vendor"
    23  const govendorName = "vendor.json"
    24  
    25  // Importer imports govendor configuration into the dep configuration format.
    26  type Importer struct {
    27  	*base.Importer
    28  
    29  	file govendorFile
    30  }
    31  
    32  // NewImporter for govendor.
    33  func NewImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *Importer {
    34  	return &Importer{Importer: base.NewImporter(logger, verbose, sm)}
    35  }
    36  
    37  // File is the structure of the vendor file.
    38  type govendorFile struct {
    39  	RootPath string // Import path of vendor folder
    40  	Ignore   string
    41  	Package  []*govendorPackage
    42  }
    43  
    44  // Package represents each package.
    45  type govendorPackage struct {
    46  	// See the vendor spec for definitions.
    47  	Origin   string
    48  	Path     string
    49  	Revision string
    50  	Version  string
    51  }
    52  
    53  // Name of the importer.
    54  func (g *Importer) Name() string {
    55  	return "govendor"
    56  }
    57  
    58  // HasDepMetadata checks if a directory contains config that the importer can handle.
    59  func (g *Importer) HasDepMetadata(dir string) bool {
    60  	y := filepath.Join(dir, govendorDir, govendorName)
    61  	if _, err := os.Stat(y); err != nil {
    62  		return false
    63  	}
    64  	return true
    65  }
    66  
    67  // Import the config found in the directory.
    68  func (g *Importer) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) {
    69  	err := g.load(dir)
    70  	if err != nil {
    71  		return nil, nil, err
    72  	}
    73  
    74  	m, l := g.convert(pr)
    75  	return m, l, nil
    76  }
    77  
    78  func (g *Importer) load(projectDir string) error {
    79  	g.Logger.Println("Detected govendor configuration file...")
    80  	v := filepath.Join(projectDir, govendorDir, govendorName)
    81  	if g.Verbose {
    82  		g.Logger.Printf("  Loading %s", v)
    83  	}
    84  	vb, err := ioutil.ReadFile(v)
    85  	if err != nil {
    86  		return errors.Wrapf(err, "unable to read %s", v)
    87  	}
    88  	err = json.Unmarshal(vb, &g.file)
    89  	if err != nil {
    90  		return errors.Wrapf(err, "unable to parse %s", v)
    91  	}
    92  	return nil
    93  }
    94  
    95  func (g *Importer) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock) {
    96  	g.Logger.Println("Converting from vendor.json...")
    97  
    98  	packages := make([]base.ImportedPackage, 0, len(g.file.Package))
    99  	for _, pkg := range g.file.Package {
   100  		// Path must not be empty
   101  		if pkg.Path == "" {
   102  			g.Logger.Println(
   103  				"  Warning: Skipping project. Invalid govendor configuration, Path is required",
   104  			)
   105  			continue
   106  		}
   107  
   108  		// There are valid govendor configs in the wild that don't have a revision set
   109  		// so we are not requiring it to be set during import
   110  
   111  		ip := base.ImportedPackage{
   112  			Name:     pkg.Path,
   113  			Source:   pkg.Origin,
   114  			LockHint: pkg.Revision,
   115  		}
   116  		packages = append(packages, ip)
   117  	}
   118  
   119  	g.ImportPackages(packages, true)
   120  
   121  	if len(g.file.Ignore) > 0 {
   122  		// Govendor has three use cases here
   123  		// 1. 'test' - special case for ignoring test files
   124  		// 2. build tags - any string without a slash (/) in it
   125  		// 3. path and path prefix - any string with a slash (/) in it.
   126  		//   The path case could be a full path or just a prefix.
   127  		// Dep doesn't support build tags right now: https://github.com/golang/dep/issues/120
   128  		for _, i := range strings.Split(g.file.Ignore, " ") {
   129  			if !strings.Contains(i, "/") {
   130  				g.Logger.Printf("  Govendor was configured to ignore the %s build tag, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291.", i)
   131  				continue
   132  			}
   133  
   134  			var ignorePattern string
   135  			_, err := g.SourceManager.DeduceProjectRoot(i)
   136  			if err == nil { // external package
   137  				ignorePattern = i
   138  			} else { // relative package path in the current project
   139  				ignorePattern = path.Join(string(pr), i)
   140  			}
   141  
   142  			// Convert to a a wildcard ignore
   143  			ignorePattern = strings.TrimRight(ignorePattern, "/")
   144  			ignorePattern += "*"
   145  
   146  			g.Manifest.Ignored = append(g.Manifest.Ignored, ignorePattern)
   147  		}
   148  	}
   149  
   150  	return g.Manifest, g.Lock
   151  }