blob: b17158764411b0b1cf65eb25dd74ed9505758d73 [file] [log] [blame]
package cfg
import (
"fmt"
"path"
"reflect"
"strings"
"time"
"github.com/Masterminds/glide/util"
)
// lConfig1 is a legacy Config file.
type lConfig1 struct {
Name string `yaml:"package"`
Description string `json:"description,omitempty"`
Home string `yaml:"homepage,omitempty"`
License string `yaml:"license,omitempty"`
Owners Owners `yaml:"owners,omitempty"`
Ignore []string `yaml:"ignore,omitempty"`
Exclude []string `yaml:"excludeDirs,omitempty"`
Imports lDependencies1 `yaml:"import"`
DevImports lDependencies1 `yaml:"testImport,omitempty"`
}
func (c *lConfig1) UnmarshalYAML(unmarshal func(interface{}) error) error {
newConfig := &lcf1{}
if err := unmarshal(&newConfig); err != nil {
return err
}
c.Name = newConfig.Name
c.Description = newConfig.Description
c.Home = newConfig.Home
c.License = newConfig.License
c.Owners = newConfig.Owners
c.Ignore = newConfig.Ignore
c.Exclude = newConfig.Exclude
c.Imports = newConfig.Imports
c.DevImports = newConfig.DevImports
// Cleanup the Config object now that we have it.
err := c.DeDupe()
return err
}
func (c *lConfig1) Convert() (*Config, error) {
// This is probably already done, but do it just in case
err := c.DeDupe()
if err != nil {
return nil, err
}
// Pull over the easy values
c2 := &Config{
Name: c.Name,
Description: c.Description,
Home: c.Home,
License: c.License,
Owners: c.Owners,
Ignore: c.Ignore,
}
// _if_ the name is set, path-prepend it to exclude, and add that to ignore.
// Otherwise, we just skip excludes. Not that big a deal, since they're a
// root-only property anyway; the user can reasonably recreate.
if c.Name != "" {
for _, excl := range c.Exclude {
c.Ignore = append(c.Ignore, path.Join(c.Name, excl))
// The trailing * is interpreted by gps as an ignore on that and all
// child paths (or, soon - https://github.com/sdboyer/gps/issues/88)
c.Ignore = append(c.Ignore, path.Join(c.Name, excl, "*"))
}
}
// Quitting early on this might seem risky, but a) all possible errs
// _should_ have already been surfaced in the earlier DeDupe(), and b) there
// are no new errs introduced by the conversion itself, so this doesn't
// actually increase the surface area for failures vis-a-vis pre-gps glide.
c2.Imports, err = c.Imports.Convert()
if err != nil {
return nil, err
}
c2.DevImports, err = c.DevImports.Convert()
if err != nil {
return nil, err
}
return c2, nil
}
// DeDupe consolidates duplicate dependencies on a Config instance
func (c *lConfig1) DeDupe() error {
// Remove duplicates in the imports
var err error
c.Imports, err = c.Imports.DeDupe()
if err != nil {
return err
}
c.DevImports, err = c.DevImports.DeDupe()
if err != nil {
return err
}
// If the name on the config object is part of the imports remove it.
found := -1
for i, dep := range c.Imports {
if dep.Name == c.Name {
found = i
}
}
if found >= 0 {
c.Imports = append(c.Imports[:found], c.Imports[found+1:]...)
}
found = -1
for i, dep := range c.DevImports {
if dep.Name == c.Name {
found = i
}
}
if found >= 0 {
c.DevImports = append(c.DevImports[:found], c.DevImports[found+1:]...)
}
// If something is on the ignore list remove it from the imports.
for _, v := range c.Ignore {
found = -1
for k, d := range c.Imports {
if v == d.Name {
found = k
}
}
if found >= 0 {
c.Imports = append(c.Imports[:found], c.Imports[found+1:]...)
}
found = -1
for k, d := range c.DevImports {
if v == d.Name {
found = k
}
}
if found >= 0 {
c.DevImports = append(c.DevImports[:found], c.DevImports[found+1:]...)
}
}
return nil
}
// Legacy representation of a glide.yaml file.
type lcf1 struct {
Name string `yaml:"package"`
Description string `yaml:"description,omitempty"`
Home string `yaml:"homepage,omitempty"`
License string `yaml:"license,omitempty"`
Owners Owners `yaml:"owners,omitempty"`
Ignore []string `yaml:"ignore,omitempty"`
Exclude []string `yaml:"excludeDirs,omitempty"`
Imports lDependencies1 `yaml:"import"`
DevImports lDependencies1 `yaml:"testImport,omitempty"`
// these fields guarantee that this struct fails to unmarshal the new yamls
Compat int `yaml:"dependencies,omitempty"`
Compat2 int `yaml:"testDependencies,omitempty"`
}
type lDependencies1 []*lDependency1
func (ds lDependencies1) Convert() (Dependencies, error) {
dds, err := ds.DeDupe()
if err != nil {
return nil, err
}
var ds2 Dependencies
for _, d := range dds {
// If we have neither a repo nor a reference, then it's pointless to
// include this dep in the list (it will add no information to gps)
if d.Repository == "" && d.Reference == "" {
continue
}
d2 := &Dependency{
Name: d.Name,
Repository: d.Repository,
Version: d.Reference,
}
// TODO(sdboyer) d.Reference doesn't disambiguate between branches and
// tags. Check the version list (via source manager) to convert most
// sanely?
ds2 = append(ds2, d2)
}
return ds2, nil
}
// DeDupe cleans up duplicates on a list of dependencies.
func (d lDependencies1) DeDupe() (lDependencies1, error) {
checked := map[string]int{}
imports := make(lDependencies1, 0, 1)
i := 0
for _, dep := range d {
// The first time we encounter a dependency add it to the list
if val, ok := checked[dep.Name]; !ok {
checked[dep.Name] = i
imports = append(imports, dep)
i++
} else {
// In here we've encountered a dependency for the second time.
// Make sure the details are the same or return an error.
v := imports[val]
if dep.Reference != v.Reference {
return d, fmt.Errorf("Import %s repeated with different versions '%s' and '%s'", dep.Name, dep.Reference, v.Reference)
}
if dep.Repository != v.Repository || dep.VcsType != v.VcsType {
return d, fmt.Errorf("Import %s repeated with different Repository details", dep.Name)
}
if !reflect.DeepEqual(dep.Os, v.Os) || !reflect.DeepEqual(dep.Arch, v.Arch) {
return d, fmt.Errorf("Import %s repeated with different OS or Architecture filtering", dep.Name)
}
imports[checked[dep.Name]].Subpackages = stringArrayDeDupe(v.Subpackages, dep.Subpackages...)
}
}
return imports, nil
}
type lDependency1 struct {
Name string `yaml:"package"`
Reference string `yaml:"version,omitempty"`
Pin string `yaml:"-"`
Repository string `yaml:"repo,omitempty"`
VcsType string `yaml:"vcs,omitempty"`
Subpackages []string `yaml:"subpackages,omitempty"`
Arch []string `yaml:"arch,omitempty"`
Os []string `yaml:"os,omitempty"`
}
// Legacy unmarshaler for dependency component of yaml files
func (d *lDependency1) UnmarshalYAML(unmarshal func(interface{}) error) error {
newDep := &ldep1{}
err := unmarshal(newDep)
if err != nil {
return err
}
d.Name = newDep.Name
d.Reference = newDep.Reference
d.Repository = newDep.Repository
d.VcsType = newDep.VcsType
d.Subpackages = newDep.Subpackages
d.Arch = newDep.Arch
d.Os = newDep.Os
if d.Reference == "" && newDep.Ref != "" {
d.Reference = newDep.Ref
}
// Make sure only legitimate VCS are listed.
d.VcsType = filterVcsType(d.VcsType)
// Get the root name for the package
tn, subpkg := util.NormalizeName(d.Name)
d.Name = tn
if subpkg != "" {
d.Subpackages = append(d.Subpackages, subpkg)
}
// Older versions of Glide had a / prefix on subpackages in some cases.
// Here that's cleaned up. Someday we should be able to remove this.
for k, v := range d.Subpackages {
d.Subpackages[k] = strings.TrimPrefix(v, "/")
}
return nil
}
// Legacy representation of a dep constraint
type ldep1 struct {
Name string `yaml:"package"`
Reference string `yaml:"version,omitempty"`
Ref string `yaml:"ref,omitempty"`
Repository string `yaml:"repo,omitempty"`
VcsType string `yaml:"vcs,omitempty"`
Subpackages []string `yaml:"subpackages,omitempty"`
Arch []string `yaml:"arch,omitempty"`
Os []string `yaml:"os,omitempty"`
}
type lLockfile1 struct {
Hash string `yaml:"hash"`
Updated time.Time `yaml:"updated"`
Imports lLocks1 `yaml:"imports"`
DevImports lLocks1 `yaml:"testImports"` // TODO remove and fold in as prop
Compat int `yaml:"import,omitempty"`
Compat2 int `yaml:"testImport,omitempty"`
}
func (l *lLockfile1) Convert() *Lockfile {
return &Lockfile{
Hash: l.Hash,
Updated: l.Updated,
Imports: l.Imports.Convert(),
DevImports: l.DevImports.Convert(),
}
}
type lLocks1 []*lLock1
func (ll lLocks1) Convert() Locks {
var ll2 Locks
for _, l := range ll {
// If they have no rev, just drop them
if l.Version == "" {
continue
}
ll2 = append(ll2, &Lock{
Name: l.Name,
Repository: l.Repository,
Revision: l.Version,
})
}
return ll2
}
type lLock1 struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Repository string `yaml:"repo,omitempty"`
VcsType string `yaml:"vcs,omitempty"`
Subpackages []string `yaml:"subpackages,omitempty"`
Arch []string `yaml:"arch,omitempty"`
Os []string `yaml:"os,omitempty"`
}