github.com/kngu9/glide@v0.0.0-20160505135211-e73500c73591/action/create.go (about)

     1  package action
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/Masterminds/glide/cfg"
    10  	"github.com/Masterminds/glide/dependency"
    11  	"github.com/Masterminds/glide/gb"
    12  	"github.com/Masterminds/glide/godep"
    13  	"github.com/Masterminds/glide/gpm"
    14  	"github.com/Masterminds/glide/msg"
    15  	gpath "github.com/Masterminds/glide/path"
    16  	"github.com/Masterminds/glide/util"
    17  )
    18  
    19  // Create creates/initializes a new Glide repository.
    20  //
    21  // This will fail if a glide.yaml already exists.
    22  //
    23  // By default, this will scan the present source code directory for dependencies.
    24  //
    25  // If skipImport is set to true, this will not attempt to import from an existing
    26  // GPM, Godep, or GB project if one should exist. However, it will still attempt
    27  // to read the local source to determine required packages.
    28  func Create(base string, skipImport bool) {
    29  	glidefile := gpath.GlideFile
    30  	// Guard against overwrites.
    31  	guardYAML(glidefile)
    32  
    33  	// Guess deps
    34  	conf := guessDeps(base, skipImport)
    35  	// Write YAML
    36  	if err := conf.WriteFile(glidefile); err != nil {
    37  		msg.Die("Could not save %s: %s", glidefile, err)
    38  	}
    39  }
    40  
    41  // guardYAML fails if the given file already exists.
    42  //
    43  // This prevents an important file from being overwritten.
    44  func guardYAML(filename string) {
    45  	if _, err := os.Stat(filename); err == nil {
    46  		msg.Die("Cowardly refusing to overwrite existing YAML.")
    47  	}
    48  }
    49  
    50  // guessDeps attempts to resolve all of the dependencies for a given project.
    51  //
    52  // base is the directory to start with.
    53  // skipImport will skip running the automatic imports.
    54  //
    55  // FIXME: This function is likely a one-off that has a more standard alternative.
    56  // It's also long and could use a refactor.
    57  func guessDeps(base string, skipImport bool) *cfg.Config {
    58  	buildContext, err := util.GetBuildContext()
    59  	if err != nil {
    60  		msg.Die("Failed to build an import context: %s", err)
    61  	}
    62  	name := buildContext.PackageName(base)
    63  
    64  	msg.Info("Generating a YAML configuration file and guessing the dependencies")
    65  
    66  	config := new(cfg.Config)
    67  
    68  	// Get the name of the top level package
    69  	config.Name = name
    70  
    71  	// Import by looking at other package managers and looking over the
    72  	// entire directory structure.
    73  
    74  	// Attempt to import from other package managers.
    75  	if !skipImport {
    76  		msg.Info("Attempting to import from other package managers (use --skip-import to skip)")
    77  		deps := []*cfg.Dependency{}
    78  		absBase, err := filepath.Abs(base)
    79  		if err != nil {
    80  			msg.Die("Failed to resolve location of %s: %s", base, err)
    81  		}
    82  
    83  		if d, ok := guessImportGodep(absBase); ok {
    84  			msg.Info("Importing Godep configuration")
    85  			msg.Warn("Godep uses commit id versions. Consider using Semantic Versions with Glide")
    86  			deps = d
    87  		} else if d, ok := guessImportGPM(absBase); ok {
    88  			msg.Info("Importing GPM configuration")
    89  			deps = d
    90  		} else if d, ok := guessImportGB(absBase); ok {
    91  			msg.Info("Importing GB configuration")
    92  			deps = d
    93  		}
    94  
    95  		for _, i := range deps {
    96  			msg.Info("Found imported reference to %s\n", i.Name)
    97  			config.Imports = append(config.Imports, i)
    98  		}
    99  	}
   100  
   101  	// Resolve dependencies by looking at the tree.
   102  	r, err := dependency.NewResolver(base)
   103  	if err != nil {
   104  		msg.Die("Error creating a dependency resolver: %s", err)
   105  	}
   106  
   107  	h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
   108  	r.Handler = h
   109  
   110  	sortable, err := r.ResolveLocal(false)
   111  	if err != nil {
   112  		msg.Die("Error resolving local dependencies: %s", err)
   113  	}
   114  
   115  	sort.Strings(sortable)
   116  
   117  	vpath := r.VendorDir
   118  	if !strings.HasSuffix(vpath, "/") {
   119  		vpath = vpath + string(os.PathSeparator)
   120  	}
   121  
   122  	for _, pa := range sortable {
   123  		n := strings.TrimPrefix(pa, vpath)
   124  		root, subpkg := util.NormalizeName(n)
   125  
   126  		if !config.HasDependency(root) {
   127  			msg.Info("Found reference to %s\n", n)
   128  			d := &cfg.Dependency{
   129  				Name: root,
   130  			}
   131  			if len(subpkg) > 0 {
   132  				d.Subpackages = []string{subpkg}
   133  			}
   134  			config.Imports = append(config.Imports, d)
   135  		} else {
   136  			if len(subpkg) > 0 {
   137  				subpkg = strings.TrimPrefix(subpkg, "/")
   138  				d := config.Imports.Get(root)
   139  				if !d.HasSubpackage(subpkg) {
   140  					msg.Info("Adding sub-package %s to %s\n", subpkg, root)
   141  					d.Subpackages = append(d.Subpackages, subpkg)
   142  				}
   143  			}
   144  		}
   145  	}
   146  
   147  	return config
   148  }
   149  
   150  func guessImportGodep(dir string) ([]*cfg.Dependency, bool) {
   151  	d, err := godep.Parse(dir)
   152  	if err != nil || len(d) == 0 {
   153  		return []*cfg.Dependency{}, false
   154  	}
   155  
   156  	return d, true
   157  }
   158  
   159  func guessImportGPM(dir string) ([]*cfg.Dependency, bool) {
   160  	d, err := gpm.Parse(dir)
   161  	if err != nil || len(d) == 0 {
   162  		return []*cfg.Dependency{}, false
   163  	}
   164  
   165  	return d, true
   166  }
   167  
   168  func guessImportGB(dir string) ([]*cfg.Dependency, bool) {
   169  	d, err := gb.Parse(dir)
   170  	if err != nil || len(d) == 0 {
   171  		return []*cfg.Dependency{}, false
   172  	}
   173  
   174  	return d, true
   175  }