github.com/golang/dep@v0.5.4/internal/importers/glide/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 glide
     6  
     7  import (
     8  	"bytes"
     9  	"io/ioutil"
    10  	"log"
    11  	"os"
    12  	"path"
    13  	"path/filepath"
    14  
    15  	"github.com/golang/dep"
    16  	"github.com/golang/dep/gps"
    17  	"github.com/golang/dep/internal/fs"
    18  	"github.com/golang/dep/internal/importers/base"
    19  	"github.com/pkg/errors"
    20  	"gopkg.in/yaml.v2"
    21  )
    22  
    23  const glideYamlName = "glide.yaml"
    24  const glideLockName = "glide.lock"
    25  
    26  // Importer imports glide configuration into the dep configuration format.
    27  type Importer struct {
    28  	*base.Importer
    29  	glideConfig glideYaml
    30  	glideLock   glideLock
    31  	lockFound   bool
    32  }
    33  
    34  // NewImporter for glide.
    35  func NewImporter(logger *log.Logger, verbose bool, sm gps.SourceManager) *Importer {
    36  	return &Importer{Importer: base.NewImporter(logger, verbose, sm)}
    37  }
    38  
    39  type glideYaml struct {
    40  	Name        string         `yaml:"package"`
    41  	Ignores     []string       `yaml:"ignore"`
    42  	ExcludeDirs []string       `yaml:"excludeDirs"`
    43  	Imports     []glidePackage `yaml:"import"`
    44  	TestImports []glidePackage `yaml:"testImport"`
    45  }
    46  
    47  type glideLock struct {
    48  	Imports     []glideLockedPackage `yaml:"imports"`
    49  	TestImports []glideLockedPackage `yaml:"testImports"`
    50  }
    51  
    52  type glidePackage struct {
    53  	Name       string `yaml:"package"`
    54  	Reference  string `yaml:"version"` // could contain a semver, tag or branch
    55  	Repository string `yaml:"repo"`
    56  
    57  	// Unsupported fields that we will warn if used
    58  	Subpackages []string `yaml:"subpackages"`
    59  	OS          string   `yaml:"os"`
    60  	Arch        string   `yaml:"arch"`
    61  }
    62  
    63  type glideLockedPackage struct {
    64  	Name       string `yaml:"name"`
    65  	Revision   string `yaml:"version"`
    66  	Repository string `yaml:"repo"`
    67  }
    68  
    69  // Name of the importer.
    70  func (g *Importer) Name() string {
    71  	return "glide"
    72  }
    73  
    74  // HasDepMetadata checks if a directory contains config that the importer can handle.
    75  func (g *Importer) HasDepMetadata(dir string) bool {
    76  	// Only require glide.yaml, the lock is optional
    77  	y := filepath.Join(dir, glideYamlName)
    78  	if _, err := os.Stat(y); err != nil {
    79  		return false
    80  	}
    81  
    82  	return true
    83  }
    84  
    85  // Import the config found in the directory.
    86  func (g *Importer) Import(dir string, pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock, error) {
    87  	err := g.load(dir)
    88  	if err != nil {
    89  		return nil, nil, err
    90  	}
    91  
    92  	m, l := g.convert(pr)
    93  	return m, l, nil
    94  }
    95  
    96  // load the glide configuration files. Failure to load `glide.yaml` is considered
    97  // unrecoverable and an error is returned for it. But if there is any error while trying
    98  // to load the lock file, only a warning is logged.
    99  func (g *Importer) load(projectDir string) error {
   100  	g.Logger.Println("Detected glide configuration files...")
   101  	y := filepath.Join(projectDir, glideYamlName)
   102  	if g.Verbose {
   103  		g.Logger.Printf("  Loading %s", y)
   104  	}
   105  	yb, err := ioutil.ReadFile(y)
   106  	if err != nil {
   107  		return errors.Wrapf(err, "unable to read %s", y)
   108  	}
   109  	err = yaml.Unmarshal(yb, &g.glideConfig)
   110  	if err != nil {
   111  		return errors.Wrapf(err, "unable to parse %s", y)
   112  	}
   113  
   114  	l := filepath.Join(projectDir, glideLockName)
   115  	if exists, _ := fs.IsRegular(l); exists {
   116  		if g.Verbose {
   117  			g.Logger.Printf("  Loading %s", l)
   118  		}
   119  		lb, err := ioutil.ReadFile(l)
   120  		if err != nil {
   121  			g.Logger.Printf("  Warning: Ignoring lock file. Unable to read %s: %s\n", l, err)
   122  			return nil
   123  		}
   124  		lock := glideLock{}
   125  		err = yaml.Unmarshal(lb, &lock)
   126  		if err != nil {
   127  			g.Logger.Printf("  Warning: Ignoring lock file. Unable to parse %s: %s\n", l, err)
   128  			return nil
   129  		}
   130  		g.lockFound = true
   131  		g.glideLock = lock
   132  	}
   133  
   134  	return nil
   135  }
   136  
   137  // convert the glide configuration files into dep configuration files.
   138  func (g *Importer) convert(pr gps.ProjectRoot) (*dep.Manifest, *dep.Lock) {
   139  	projectName := string(pr)
   140  
   141  	task := bytes.NewBufferString("Converting from glide.yaml")
   142  	if g.lockFound {
   143  		task.WriteString(" and glide.lock")
   144  	}
   145  	task.WriteString("...")
   146  	g.Logger.Println(task)
   147  
   148  	numPkgs := len(g.glideConfig.Imports) + len(g.glideConfig.TestImports) + len(g.glideLock.Imports) + len(g.glideLock.TestImports)
   149  	packages := make([]base.ImportedPackage, 0, numPkgs)
   150  
   151  	// Constraints
   152  	for _, pkg := range append(g.glideConfig.Imports, g.glideConfig.TestImports...) {
   153  		// Validate
   154  		if pkg.Name == "" {
   155  			g.Logger.Println(
   156  				"  Warning: Skipping project. Invalid glide configuration, Name is required",
   157  			)
   158  			continue
   159  		}
   160  
   161  		// Warn
   162  		if g.Verbose {
   163  			if pkg.OS != "" {
   164  				g.Logger.Printf("  The %s package specified an os, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291.\n", pkg.Name)
   165  			}
   166  			if pkg.Arch != "" {
   167  				g.Logger.Printf("  The %s package specified an arch, but that isn't supported by dep yet, and will be ignored. See https://github.com/golang/dep/issues/291.\n", pkg.Name)
   168  			}
   169  		}
   170  
   171  		ip := base.ImportedPackage{
   172  			Name:           pkg.Name,
   173  			Source:         pkg.Repository,
   174  			ConstraintHint: pkg.Reference,
   175  		}
   176  		packages = append(packages, ip)
   177  	}
   178  
   179  	// Locks
   180  	for _, pkg := range append(g.glideLock.Imports, g.glideLock.TestImports...) {
   181  		// Validate
   182  		if pkg.Name == "" {
   183  			g.Logger.Println("  Warning: Skipping project. Invalid glide lock, Name is required")
   184  			continue
   185  		}
   186  
   187  		ip := base.ImportedPackage{
   188  			Name:     pkg.Name,
   189  			Source:   pkg.Repository,
   190  			LockHint: pkg.Revision,
   191  		}
   192  		packages = append(packages, ip)
   193  	}
   194  
   195  	g.ImportPackages(packages, false)
   196  
   197  	// Ignores
   198  	g.Manifest.Ignored = append(g.Manifest.Ignored, g.glideConfig.Ignores...)
   199  	if len(g.glideConfig.ExcludeDirs) > 0 {
   200  		if g.glideConfig.Name != "" && g.glideConfig.Name != projectName {
   201  			g.Logger.Printf("  Glide thinks the package is '%s' but dep thinks it is '%s', using dep's value.\n", g.glideConfig.Name, projectName)
   202  		}
   203  
   204  		for _, dir := range g.glideConfig.ExcludeDirs {
   205  			pkg := path.Join(projectName, dir)
   206  			g.Manifest.Ignored = append(g.Manifest.Ignored, pkg)
   207  		}
   208  	}
   209  
   210  	return g.Manifest, g.Lock
   211  }