Merge pull request #234 from Masterminds/feat/more-cfg

Filling out the glide.yaml with more options and documentation
diff --git a/LICENSE b/LICENSE
index 5af85b0..f342051 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 Glide
 The Masterminds
-Copyright (C) 2014-2015, Matt Butcher and Matt Farina
+Copyright (C) 2014-2016, Matt Butcher and Matt Farina
 Copyright (C) 2015, Google
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
diff --git a/cfg/cfg.go b/cfg/cfg.go
index 52874d2..6204bad 100644
--- a/cfg/cfg.go
+++ b/cfg/cfg.go
@@ -1,2 +1,58 @@
 // Package cfg handles working with the Glide configuration files.
+//
+// The cfg package contains the ability to parse (unmarshal) and write (marshal)
+// glide.yaml and glide.lock files. These files contains the details about
+// projects managed by Glide.
+//
+// To convert yaml into a cfg.Config instance use the cfg.ConfigFromYaml function.
+// The yaml, typically in a glide.yaml file, has the following structure.
+//
+//     package: github.com/Masterminds/glide
+//     homepage: https://masterminds.github.io/glide
+//     license: MIT
+//     owners:
+//     - name: Matt Butcher
+//       email: technosophos@gmail.com
+//       homepage: http://technosophos.com
+//     - name: Matt Farina
+//       email: matt@mattfarina.com
+//       homepage: https://www.mattfarina.com
+//     ignore:
+//     - appengine
+//     import:
+//     - package: gopkg.in/yaml.v2
+//     - package: github.com/Masterminds/vcs
+//       version: ^1.2.0
+//       repo:    git@github.com:Masterminds/vcs
+//       vcs:     git
+//     - package: github.com/codegangsta/cli
+//     - package: github.com/Masterminds/semver
+//       version: ^1.0.0
+//
+// These elements are:
+// - package: The top level package is the location in the GOPATH. This is used
+//   for things such as making sure an import isn't also importing the top level
+//   package.
+// - homepage: To find the place where you can find details about the package or
+//   applications. For example, http://k8s.io
+// - license: The license is either an SPDX license string or the filepath to the
+//   license. This allows automation and consumers to easily identify the license.
+// - owners: The owners is a list of one or more owners for the project. This
+//   can be a person or organization and is useful for things like notifying the
+//   owners of a security issue without filing a public bug.
+// - ignore: A list of packages for Glide to ignore importing. These are package
+//   names to ignore rather than directories.
+// - import: A list of packages to import. Each package can include:
+//     - package: The name of the package to import and the only non-optional item.
+//     - version: A semantic version, semantic version range, branch, tag, or
+//       commit id to use.
+//     - repo: If the package name isn't the repo location or this is a private
+//       repository it can go here. The package will be checked out from the
+//       repo and put where the package name specifies. This allows using forks.
+//     - vcs: A VCS to use such as git, hg, bzr, or svn. This is only needed
+//       when the type cannot be detected from the name. For example, a repo
+//       ending in .git or on GitHub can be detected to be Git. For a repo on
+//       Bitbucket we can contact the API to discover the type.
+// - devImport: A list of development packages. Each package has the same details
+//   as those lised under import.
 package cfg
diff --git a/cfg/config.go b/cfg/config.go
index cca4072..2aea716 100644
--- a/cfg/config.go
+++ b/cfg/config.go
@@ -14,18 +14,52 @@
 
 // Config is the top-level configuration object.
 type Config struct {
-	Name       string       `yaml:"package"`
-	Ignore     []string     `yaml:"ignore,omitempty"`
-	Imports    Dependencies `yaml:"import"`
+
+	// Name is the name of the package or application.
+	Name string `yaml:"package"`
+
+	// Description is a short description for a package, application, or library.
+	// This description is similar but different to a Go package description as
+	// it is for marketing and presentation purposes rather than technical ones.
+	Description string `json:"description,omitempty"`
+
+	// Home is a url to a website for the package.
+	Home string `yaml:"homepage,omitempty"`
+
+	// License provides either a SPDX license or a path to a file containing
+	// the license. For more information on SPDX see http://spdx.org/licenses/.
+	// When more than one license an SPDX expression can be used.
+	License string `yaml:"license,omitempty"`
+
+	// Owners is an array of owners for a project. See the Owner type for
+	// more detail. These can be one or more people, companies, or other
+	// organizations.
+	Owners Owners `yaml:"owners,omitempty"`
+
+	// Ignore contains a list of packages to ignore fetching. This is useful
+	// when walking the package tree (including packages of packages) to list
+	// those to skip.
+	Ignore []string `yaml:"ignore,omitempty"`
+
+	// Imports contains a list of all non-development imports for a project. For
+	// more detail on how these are captured see the Dependency type.
+	Imports Dependencies `yaml:"import"`
+
+	// DevImports contains the test or other development imports for a project.
+	// See the Dependency type for more details on how this is recorded.
 	DevImports Dependencies `yaml:"devimport,omitempty"`
 }
 
 // A transitive representation of a dependency for importing and exporting to yaml.
 type cf struct {
-	Name       string       `yaml:"package"`
-	Ignore     []string     `yaml:"ignore,omitempty"`
-	Imports    Dependencies `yaml:"import"`
-	DevImports Dependencies `yaml:"devimport,omitempty"`
+	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"`
+	Imports     Dependencies `yaml:"import"`
+	DevImports  Dependencies `yaml:"devimport,omitempty"`
 }
 
 // ConfigFromYaml returns an instance of Config from YAML
@@ -51,6 +85,10 @@
 		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.Imports = newConfig.Imports
 	c.DevImports = newConfig.DevImports
@@ -64,8 +102,12 @@
 // MarshalYAML is a hook for gopkg.in/yaml.v2 in the marshaling process
 func (c *Config) MarshalYAML() (interface{}, error) {
 	newConfig := &cf{
-		Name:   c.Name,
-		Ignore: c.Ignore,
+		Name:        c.Name,
+		Description: c.Description,
+		Home:        c.Home,
+		License:     c.License,
+		Owners:      c.Owners,
+		Ignore:      c.Ignore,
 	}
 	i, err := c.Imports.Clone().DeDupe()
 	if err != nil {
@@ -116,6 +158,10 @@
 func (c *Config) Clone() *Config {
 	n := &Config{}
 	n.Name = c.Name
+	n.Description = c.Description
+	n.Home = c.Home
+	n.License = c.License
+	n.Owners = c.Owners.Clone()
 	n.Ignore = c.Ignore
 	n.Imports = c.Imports.Clone()
 	n.DevImports = c.DevImports.Clone()
@@ -408,6 +454,42 @@
 	return false
 }
 
+// Owners is a list of owners for a project.
+type Owners []*Owner
+
+// Clone performs a deep clone of Owners
+func (o Owners) Clone() Owners {
+	n := make(Owners, 0, 1)
+	for _, v := range o {
+		n = append(n, v.Clone())
+	}
+	return n
+}
+
+// Owner describes an owner of a package. This can be a person, company, or
+// other organization. This is useful if someone needs to contact the
+// owner of a package to address things like a security issue.
+type Owner struct {
+
+	// Name describes the name of an organization.
+	Name string `yaml:"name,omitempty"`
+
+	// Email is an email address to reach the owner at.
+	Email string `yaml:"email,omitempty"`
+
+	// Home is a url to a website for the owner.
+	Home string `yaml:"homepage,omitempty"`
+}
+
+// Clone creates a clone of a Dependency
+func (o *Owner) Clone() *Owner {
+	return &Owner{
+		Name:  o.Name,
+		Email: o.Email,
+		Home:  o.Home,
+	}
+}
+
 func stringArrayDeDupe(s []string, items ...string) []string {
 	for _, item := range items {
 		exists := false
diff --git a/cfg/config_test.go b/cfg/config_test.go
index 03ba08e..06ade6d 100644
--- a/cfg/config_test.go
+++ b/cfg/config_test.go
@@ -8,6 +8,13 @@
 
 var yml = `
 package: fake/testing
+description: foo bar baz
+homepage: https://example.com
+license: MIT
+owners:
+- name: foo
+  email: bar@example.com
+  homepage: https://example.com
 import:
   - package: github.com/kylelemons/go-gypsy
     subpackages:
@@ -45,6 +52,18 @@
 		t.Errorf("Inaccurate name found %s", cfg.Name)
 	}
 
+	if cfg.Description != "foo bar baz" {
+		t.Errorf("Inaccurate description found %s", cfg.Description)
+	}
+
+	if cfg.Home != "https://example.com" {
+		t.Errorf("Inaccurate homepage found %s", cfg.Home)
+	}
+
+	if cfg.License != "MIT" {
+		t.Errorf("Inaccurate license found %s", cfg.License)
+	}
+
 	found := false
 	found2 := false
 	for _, i := range cfg.Imports {
@@ -82,6 +101,9 @@
 	if cfg2.Name != "fake/testing" {
 		t.Error("Config cloning failed")
 	}
+	if cfg2.License != "MIT" {
+		t.Error("Config cloning failed to copy License")
+	}
 	cfg.Name = "foo"
 
 	if cfg.Name == cfg2.Name {
@@ -114,3 +136,43 @@
 		t.Error("HasDependency picking up dependency it shouldn't")
 	}
 }
+
+func TestOwners(t *testing.T) {
+	o := new(Owner)
+	o.Name = "foo"
+	o.Email = "foo@example.com"
+	o.Home = "https://foo.example.com"
+
+	o2 := o.Clone()
+	if o2.Name != o.Name || o2.Email != o.Email || o2.Home != o.Home {
+		t.Error("Unable to clone Owner")
+	}
+
+	o.Name = "Bar"
+	if o.Name == o2.Name {
+		t.Error("Owner clone is a pointer instead of a clone")
+	}
+
+	s := make(Owners, 0, 1)
+	s = append(s, o)
+	s2 := s.Clone()
+	o3 := s2[0]
+
+	o3.Name = "Qux"
+
+	if o3.Name == o.Name {
+		t.Error("Owners cloning isn't deep")
+	}
+
+	cfg := &Config{}
+	err := yaml.Unmarshal([]byte(yml), &cfg)
+	if err != nil {
+		t.Errorf("Unable to Unmarshal config yaml")
+	}
+
+	if cfg.Owners[0].Name != "foo" ||
+		cfg.Owners[0].Email != "bar@example.com" ||
+		cfg.Owners[0].Home != "https://example.com" {
+		t.Error("Unable to parse owners from yaml")
+	}
+}
diff --git a/glide.lock b/glide.lock
index 3ff76ad..ef461c7 100644
--- a/glide.lock
+++ b/glide.lock
@@ -1,12 +1,12 @@
-hash: 4cf59f8e61ae7034d3296c0c7528aaf8784800008814fb02410cbb3ea9b34175
-updated: 2016-01-21T11:19:37.465408253-05:00
+hash: 1d4d06656329894abc78c0ac256169337c947260b784fee7ed02a0e405c0f63b
+updated: 2016-01-28T11:15:09.190330904-05:00
 imports:
 - name: github.com/codegangsta/cli
   version: c31a7975863e7810c92e2e288a9ab074f9a88f29
 - name: github.com/Masterminds/semver
   version: 513f3dcb3ecfb1248831fb5cb06a23a3cd5935dc
 - name: github.com/Masterminds/vcs
-  version: eaee272c8fa4514e1572e182faecff5be20e792a
+  version: 4e0f9d754b04dbb4fc9a62aa5ef6bf22ee0937a8
 - name: gopkg.in/yaml.v2
   version: f7716cbe52baa25d2e9b0d0da546fcf909fc16b4
 devImports: []
diff --git a/glide.yaml b/glide.yaml
index 611d71c..09401c9 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -1,4 +1,13 @@
 package: github.com/Masterminds/glide
+homepage: https://github.com/Masterminds/glide
+license: MIT
+owners:
+- name: Matt Butcher
+  email: technosophos@gmail.com
+  homepage: http://technosophos.com/
+- name: Matt Farina
+  email: matt@mattfarina.com
+  homepage: https://www.mattfarina.com/
 import:
 - package: gopkg.in/yaml.v2
 - package: github.com/Masterminds/vcs