blob: 1372c1d6ee4bfe1d16ca8643a51cf4c5574d976a [file] [log] [blame]
package dependency
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"github.com/Masterminds/glide/cfg"
"github.com/Masterminds/glide/gb"
"github.com/Masterminds/glide/godep"
"github.com/Masterminds/glide/gom"
"github.com/Masterminds/glide/gpm"
gpath "github.com/Masterminds/glide/path"
"github.com/Masterminds/semver"
"github.com/sdboyer/gps"
)
type notApplicable struct{}
func (notApplicable) Error() string {
return ""
}
// Analyzer implements gps.ProjectAnalyzer. We inject the Analyzer into a
// gps.SourceManager, and it reports manifest and lock information to the
// SourceManager on request.
type Analyzer struct{}
func (a Analyzer) Info() (name string, version *semver.Version) {
name = "glide"
version, _ = semver.NewVersion("0.0.1")
return
}
func (a Analyzer) DeriveManifestAndLock(root string, pn gps.ProjectRoot) (gps.Manifest, gps.Lock, error) {
// this check should be unnecessary, but keeping it for now as a canary
if _, err := os.Lstat(root); err != nil {
return nil, nil, fmt.Errorf("No directory exists at %s; cannot produce ProjectInfo", root)
}
m, l, err := a.lookForGlide(root)
if err == nil {
// TODO verify project name is same as what SourceManager passed in?
return m, l, nil
} else if _, ok := err.(notApplicable); !ok {
return nil, nil, err
}
// The happy path of finding a glide manifest and/or lock file failed. Now,
// we begin our descent: we must attempt to divine just exactly *which*
// circle of hell we're in.
// Try godep first
m, l, err = a.lookForGodep(root)
if err == nil {
return m, l, nil
} else if _, ok := err.(notApplicable); !ok {
return nil, nil, err
}
// Next, gpm
m, l, err = a.lookForGPM(root)
if err == nil {
return m, l, nil
} else if _, ok := err.(notApplicable); !ok {
return nil, nil, err
}
// Next, gb
m, l, err = a.lookForGb(root)
if err == nil {
return m, l, nil
} else if _, ok := err.(notApplicable); !ok {
return nil, nil, err
}
// Next, gom
m, l, err = a.lookForGom(root)
if err == nil {
return m, l, nil
} else if _, ok := err.(notApplicable); !ok {
return nil, nil, err
}
// If none of our parsers matched, but none had actual errors, then we just
// go hands-off; gps itself will do the source analysis and use the Any
// constraint for all discovered package.
return nil, nil, nil
}
func (a Analyzer) lookForGlide(root string) (gps.Manifest, gps.Lock, error) {
mpath := filepath.Join(root, gpath.GlideFile)
if _, err := os.Lstat(mpath); err != nil {
return nil, nil, notApplicable{}
}
// Manifest found, so from here on, we're locked in - a returned error will
// make it back to the SourceManager
yml, err := ioutil.ReadFile(mpath)
if err != nil {
return nil, nil, fmt.Errorf("Error while reading glide manifest data: %s", root)
}
// We don't care here if it's legacy
m, _, err := cfg.ConfigFromYaml(yml)
if err != nil {
return nil, nil, fmt.Errorf("Error while parsing glide manifest data: %s", root)
}
// Manifest found, read, and parsed - we're on the happy path. Whether we
// find a lock or not, we will produce a valid result back to the
// SourceManager.
lpath := filepath.Join(root, gpath.LockFile)
if _, err := os.Lstat(lpath); err != nil {
return m, nil, nil
}
yml, err = ioutil.ReadFile(lpath)
if err != nil {
return m, nil, nil
}
// Again, legacy doesn't matter here
l, _, err := cfg.LockfileFromYaml(yml)
if err != nil {
return m, nil, nil
}
return m, l, nil
}
func (a Analyzer) lookForGodep(root string) (gps.Manifest, gps.Lock, error) {
if !godep.Has(root) {
return nil, nil, notApplicable{}
}
d, l, err := godep.AsMetadataPair(root)
if err != nil {
return nil, nil, err
}
return &cfg.Config{Name: root, Imports: d}, l, nil
}
func (a Analyzer) lookForGPM(root string) (gps.Manifest, gps.Lock, error) {
if !gpm.Has(root) {
return nil, nil, notApplicable{}
}
d, l, err := gpm.AsMetadataPair(root)
if err != nil {
return nil, nil, err
}
return &cfg.Config{Name: root, Imports: d}, l, nil
}
func (a Analyzer) lookForGb(root string) (gps.Manifest, gps.Lock, error) {
if !gpm.Has(root) {
return nil, nil, notApplicable{}
}
d, l, err := gb.AsMetadataPair(root)
if err != nil {
return nil, nil, err
}
return &cfg.Config{Name: root, Imports: d}, l, nil
}
func (a Analyzer) lookForGom(root string) (gps.Manifest, gps.Lock, error) {
if !gpm.Has(root) {
return nil, nil, notApplicable{}
}
return gom.AsMetadataPair(root)
}