github.com/s-urbaniak/glide@v0.0.0-20160527141859-5f5e941b1fc4/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  		guessImportDeps(base, config)
    77  	}
    78  
    79  	// Resolve dependencies by looking at the tree.
    80  	r, err := dependency.NewResolver(base)
    81  	if err != nil {
    82  		msg.Die("Error creating a dependency resolver: %s", err)
    83  	}
    84  
    85  	h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}}
    86  	r.Handler = h
    87  
    88  	sortable, err := r.ResolveLocal(false)
    89  	if err != nil {
    90  		msg.Die("Error resolving local dependencies: %s", err)
    91  	}
    92  
    93  	sort.Strings(sortable)
    94  
    95  	vpath := r.VendorDir
    96  	if !strings.HasSuffix(vpath, "/") {
    97  		vpath = vpath + string(os.PathSeparator)
    98  	}
    99  
   100  	for _, pa := range sortable {
   101  		n := strings.TrimPrefix(pa, vpath)
   102  		root, subpkg := util.NormalizeName(n)
   103  
   104  		if !config.HasDependency(root) {
   105  			msg.Info("Found reference to %s\n", n)
   106  			d := &cfg.Dependency{
   107  				Name: root,
   108  			}
   109  			if len(subpkg) > 0 {
   110  				d.Subpackages = []string{subpkg}
   111  			}
   112  			config.Imports = append(config.Imports, d)
   113  		} else {
   114  			if len(subpkg) > 0 {
   115  				subpkg = strings.TrimPrefix(subpkg, "/")
   116  				d := config.Imports.Get(root)
   117  				if !d.HasSubpackage(subpkg) {
   118  					msg.Info("Adding sub-package %s to %s\n", subpkg, root)
   119  					d.Subpackages = append(d.Subpackages, subpkg)
   120  				}
   121  			}
   122  		}
   123  	}
   124  
   125  	return config
   126  }
   127  
   128  func guessImportDeps(base string, config *cfg.Config) {
   129  	msg.Info("Attempting to import from other package managers (use --skip-import to skip)")
   130  	deps := []*cfg.Dependency{}
   131  	absBase, err := filepath.Abs(base)
   132  	if err != nil {
   133  		msg.Die("Failed to resolve location of %s: %s", base, err)
   134  	}
   135  
   136  	if d, ok := guessImportGodep(absBase); ok {
   137  		msg.Info("Importing Godep configuration")
   138  		msg.Warn("Godep uses commit id versions. Consider using Semantic Versions with Glide")
   139  		deps = d
   140  	} else if d, ok := guessImportGPM(absBase); ok {
   141  		msg.Info("Importing GPM configuration")
   142  		deps = d
   143  	} else if d, ok := guessImportGB(absBase); ok {
   144  		msg.Info("Importing GB configuration")
   145  		deps = d
   146  	}
   147  
   148  	for _, i := range deps {
   149  		msg.Info("Found imported reference to %s\n", i.Name)
   150  		config.Imports = append(config.Imports, i)
   151  	}
   152  }
   153  
   154  func guessImportGodep(dir string) ([]*cfg.Dependency, bool) {
   155  	d, err := godep.Parse(dir)
   156  	if err != nil || len(d) == 0 {
   157  		return []*cfg.Dependency{}, false
   158  	}
   159  
   160  	return d, true
   161  }
   162  
   163  func guessImportGPM(dir string) ([]*cfg.Dependency, bool) {
   164  	d, err := gpm.Parse(dir)
   165  	if err != nil || len(d) == 0 {
   166  		return []*cfg.Dependency{}, false
   167  	}
   168  
   169  	return d, true
   170  }
   171  
   172  func guessImportGB(dir string) ([]*cfg.Dependency, bool) {
   173  	d, err := gb.Parse(dir)
   174  	if err != nil || len(d) == 0 {
   175  		return []*cfg.Dependency{}, false
   176  	}
   177  
   178  	return d, true
   179  }