blob: a33601d0536d066cdb5c319bce34df8a83c435be [file] [log] [blame]
package gom
import (
"errors"
"os"
"path/filepath"
"github.com/Masterminds/glide/cfg"
"github.com/Masterminds/glide/msg"
gpath "github.com/Masterminds/glide/path"
"github.com/Masterminds/glide/util"
"github.com/sdboyer/gps"
)
// Has returns true if this dir has a Gomfile.
func Has(dir string) bool {
path := filepath.Join(dir, "Gomfile")
fi, err := os.Stat(path)
return err == nil && !fi.IsDir()
}
// Parse parses a Gomfile.
func Parse(dir string) ([]*cfg.Dependency, error) {
path := filepath.Join(dir, "Gomfile")
if fi, err := os.Stat(path); err != nil || fi.IsDir() {
return []*cfg.Dependency{}, nil
}
msg.Info("Found Gomfile in %s", gpath.StripBasepath(dir))
msg.Info("--> Parsing Gomfile metadata...")
buf := []*cfg.Dependency{}
goms, err := parseGomfile(path)
if err != nil {
return []*cfg.Dependency{}, err
}
for _, gom := range goms {
// Do we need to skip this dependency?
if val, ok := gom.options["skipdep"]; ok && val.(string) == "true" {
continue
}
// Check for custom cloning command
if _, ok := gom.options["command"]; ok {
return []*cfg.Dependency{}, errors.New("Glide does not support custom Gomfile commands")
}
// Check for groups/environments
if val, ok := gom.options["group"]; ok {
groups := toStringSlice(val)
if !stringsContain(groups, "development") && !stringsContain(groups, "production") {
// right now we only support development and production
msg.Info("Skipping dependency '%s' because it isn't in the development or production group", gom.name)
continue
}
}
pkg, _ := util.NormalizeName(gom.name)
dep := &cfg.Dependency{
Name: pkg,
}
// Check for a specific revision
if val, ok := gom.options["commit"]; ok {
dep.Version = val.(string)
}
if val, ok := gom.options["tag"]; ok {
dep.Version = val.(string)
}
if val, ok := gom.options["branch"]; ok {
dep.Branch = val.(string)
}
buf = append(buf, dep)
}
return buf, nil
}
// AsMetadataPair attempts to extract manifest and lock data from gom metadata.
func AsMetadataPair(dir string) (gps.Manifest, gps.Lock, error) {
path := filepath.Join(dir, "Gomfile")
if _, err := os.Stat(path); err != nil {
return nil, nil, err
}
goms, err := parseGomfile(path)
if err != nil {
return nil, nil, err
}
var l gps.SimpleLock
m := gps.SimpleManifest{}
for _, gom := range goms {
// Do we need to skip this dependency?
if val, ok := gom.options["skipdep"]; ok && val.(string) == "true" {
continue
}
// Check for custom cloning command
if _, ok := gom.options["command"]; ok {
return nil, nil, errors.New("Glide does not support custom Gomfile commands")
}
// Check for groups/environments
if val, ok := gom.options["group"]; ok {
groups := toStringSlice(val)
if !stringsContain(groups, "development") && !stringsContain(groups, "production") {
// right now we only support development and production
continue
}
}
pkg, _ := util.NormalizeName(gom.name)
dep := gps.ProjectConstraint{
Ident: gps.ProjectIdentifier{
ProjectRoot: gps.ProjectRoot(pkg),
},
}
// Our order of preference for things to put in the manifest are
// - Semver
// - Version
// - Branch
// - Revision
var v gps.UnpairedVersion
if val, ok := gom.options["tag"]; ok {
body := val.(string)
v = gps.NewVersion(body)
c, err := gps.NewSemverConstraint(body)
if err != nil {
c = gps.NewVersion(body)
}
dep.Constraint = c
} else if val, ok := gom.options["branch"]; ok {
body := val.(string)
v = gps.NewBranch(body)
dep.Constraint = gps.NewBranch(body)
}
id := gps.ProjectIdentifier{
ProjectRoot: gps.ProjectRoot(dir),
}
var version gps.Version
if val, ok := gom.options["commit"]; ok {
body := val.(string)
if v != nil {
version = v.Is(gps.Revision(body))
} else {
// As with the other third-party system integrations, we're
// going to choose not to put revisions into a manifest, even
// though gom has a lot more information than most and the
// argument could be made for it.
dep.Constraint = gps.Any()
version = gps.Revision(body)
}
} else if v != nil {
// This is kinda uncomfortable - lock w/no immut - but OK
version = v
}
l = append(l, gps.NewLockedProject(id, version, nil))
// TODO We ignore GOOS, GOARCH for now
}
return m, l, nil
}
func stringsContain(v []string, key string) bool {
for _, s := range v {
if s == key {
return true
}
}
return false
}
func toStringSlice(v interface{}) []string {
if v, ok := v.(string); ok {
return []string{v}
}
if v, ok := v.([]string); ok {
return v
}
return []string{}
}