| package cmd |
| |
| import ( |
| "github.com/Masterminds/cookoo" |
| "github.com/kylelemons/go-gypsy/yaml" |
| "fmt" |
| ) |
| |
| // ParseYaml parses the glide.yaml format and returns a Configuration object. |
| // |
| // Params: |
| // - filename (string): YAML filename as a string |
| // |
| // Context: |
| // - yaml.File: This puts the parsed YAML file into the context. |
| // |
| // Returns: |
| // - *Config: The configuration. |
| func ParseYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| fname := p.Get("filename", "glide.yaml").(string) |
| conf := new(Config) |
| f, err := yaml.ReadFile(fname) |
| if err != nil { |
| return nil, err |
| } |
| |
| c.Put("yaml.File", f) |
| |
| // Convenience: |
| top, ok := f.Root.(yaml.Map) |
| if !ok { |
| return nil, fmt.Errorf("Expected YAML root to be map, got %t", f.Root) |
| } |
| |
| vals := map[string]yaml.Node(top) |
| if name, ok := vals["package"]; ok { |
| //c.Put("cfg.package", name.(yaml.Scalar).String()) |
| conf.Name = name.(yaml.Scalar).String() |
| } else { |
| Warn("The 'package' directive is required in Glide YAML.\n") |
| } |
| |
| // Allow the user to override the behavior of `glide in`. |
| if incmd, ok := vals["incmd"]; ok { |
| conf.InCommand = incmd.(yaml.Scalar).String() |
| } |
| |
| conf.Imports = make([]*Dependency, 0, 1) |
| if imp, ok := vals["import"]; ok { |
| imports, ok := imp.(yaml.List) |
| |
| if ok { |
| for _, v := range imports { |
| pkg := v.(yaml.Map) |
| dep := Dependency { |
| Name: valOrEmpty("package", pkg), |
| Reference: valOrEmpty("ref", pkg), |
| VcsType: getVcsType(pkg), |
| Repository: valOrEmpty("repo", pkg), |
| Subpackages: subpkg("subpackages", pkg), |
| } |
| conf.Imports = append(conf.Imports, &dep) |
| } |
| } |
| } |
| |
| return conf, nil |
| } |
| |
| // WriteYaml writes a yaml.Node to the console as a string. |
| // |
| // Params: |
| // - yaml.Node: A yaml.Node to render. |
| func WriteYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| top := p.Get("yaml.Node", yaml.Scalar("nothing to print")).(yaml.Node) |
| |
| fmt.Print(yaml.Render(top)) |
| |
| return true, nil |
| } |
| |
| // Convert a Config object and a yaml.File to a single yaml.File. |
| func MergeToYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| root := c.Get("yaml.File", nil).(*yaml.File).Root |
| cfg := p.Get("conf", nil).(*Config) |
| |
| rootMap, ok := root.(yaml.Map) |
| if !ok { |
| return nil, fmt.Errorf("Expected root node to be a map.") |
| } |
| |
| rootMap["package"] = yaml.Scalar(cfg.Name) |
| if cfg.InCommand != "" { |
| rootMap["incmd"] = yaml.Scalar(cfg.InCommand) |
| } |
| |
| // Imports |
| imports := make([]yaml.Node, len(cfg.Imports)) |
| for i, imp := range cfg.Imports { |
| |
| if imp.VcsType == NoVCS { |
| imp.VcsType, _ = GuessVCS(imp) |
| } |
| |
| impmap := make(map[string]yaml.Node) |
| impmap["package"] = yaml.Scalar(imp.Name) |
| if imp.VcsType != NoVCS { |
| impmap["vcs"] = yaml.Scalar(vcsString(imp.VcsType)) |
| } |
| if imp.Reference != "" { |
| impmap["ref"] = yaml.Scalar(imp.Reference) |
| } |
| if imp.Repository != "" { |
| impmap["repo"] = yaml.Scalar(imp.Repository) |
| } |
| |
| if len(imp.Subpackages) > 0 { |
| subs := make([]yaml.Node, len(imp.Subpackages)) |
| for ii, sub := range imp.Subpackages { |
| subs[ii] = yaml.Scalar(sub) |
| } |
| impmap["subpackages"] = yaml.List(subs) |
| } |
| |
| imports[i] = yaml.Map(impmap) |
| } |
| |
| rootMap["import"] = yaml.List(imports) |
| |
| |
| return root, nil |
| } |
| |
| // AddDependencies adds a list of *Dependency objects to the given *Config. |
| // |
| // This is used to merge in packages from other sources or config files. |
| func AddDependencies(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { |
| deps := p.Get("dependencies", []*Dependency{}).([]*Dependency) |
| config := p.Get("conf", nil).(*Config) |
| |
| // Make a set of existing package names for quick comparison. |
| pkgSet := make(map[string]bool, len(config.Imports)) |
| for _, p := range config.Imports { |
| pkgSet[p.Name] = true |
| } |
| |
| // If a dep is not already present, add it. |
| for _, dep := range deps { |
| if _, ok := pkgSet[dep.Name]; ok { |
| Warn("Package %s is already in glide.yaml. Skipping.\n", dep.Name) |
| continue |
| } |
| config.Imports = append(config.Imports, dep) |
| } |
| |
| return true, nil |
| } |
| |
| func vcsString(vtype uint) string { |
| switch vtype { |
| case Git: |
| return "git" |
| case Hg: |
| return "hg" |
| case Bzr: |
| return "bzr" |
| case Svn: |
| return "svn" |
| default: |
| return "" |
| } |
| } |
| |
| func valOrEmpty(key string, store map[string]yaml.Node) string { |
| val, ok := store[key] |
| if !ok { |
| return "" |
| } |
| return val.(yaml.Scalar).String() |
| } |
| |
| func subpkg(key string, store map[string]yaml.Node) []string { |
| val, ok := store[key] |
| |
| subpackages := []string{} |
| if !ok { |
| return subpackages |
| } |
| |
| pkgs, ok := val.(yaml.List) |
| |
| if !ok { |
| |
| // Special case: Allow 'subpackages: justOne' |
| if one, ok := val.(yaml.Scalar); ok { |
| return []string{ one.String() } |
| } |
| |
| Warn("Expected list of subpackages.\n") |
| return subpackages |
| } |
| |
| |
| for _, pkg := range pkgs { |
| subpackages = append(subpackages, pkg.(yaml.Scalar).String()) |
| } |
| return subpackages |
| } |
| |
| func getVcsType(store map[string]yaml.Node) uint { |
| |
| val, ok := store["vcs"] |
| if !ok { |
| return NoVCS |
| } |
| |
| name := val.(yaml.Scalar).String() |
| |
| switch name { |
| case "git": |
| return Git |
| case "hg", "mercurial": |
| return Hg |
| case "bzr", "bazaar": |
| return Bzr |
| case "svn", "subversion": |
| return Svn |
| default: |
| return NoVCS |
| } |
| } |
| |
| // Config is the top-level configuration object. |
| type Config struct { |
| Name string |
| Imports []*Dependency |
| DevImports []*Dependency |
| // InCommand is the default shell command run to start a 'glide in' |
| // session. |
| InCommand string |
| } |
| |
| // Dependency describes a package that the present package depends upon. |
| type Dependency struct { |
| Name, Reference, Repository string |
| VcsType uint |
| Subpackages []string |
| } |