| package vendor |
| |
| import ( |
| "bytes" |
| "encoding/json" |
| "fmt" |
| "io" |
| "os" |
| "reflect" |
| "sort" |
| ) |
| |
| // gb-vendor manifest support |
| |
| // Manifest describes the layout of $PROJECT/vendor/manifest. |
| type Manifest struct { |
| // Manifest version. Current manifest version is 0. |
| Version int `json:"version"` |
| |
| // Depenencies is a list of vendored dependencies. |
| Dependencies []Dependency `json:"dependencies"` |
| } |
| |
| // AddDependency adds a Dependency to the current Manifest. |
| // If the dependency exists already then it returns and error. |
| func (m *Manifest) AddDependency(dep Dependency) error { |
| if m.HasImportpath(dep.Importpath) { |
| return fmt.Errorf("already registered") |
| } |
| m.Dependencies = append(m.Dependencies, dep) |
| return nil |
| } |
| |
| // RemoveDependency removes a Dependency from the current Manifest. |
| // If the dependency does not exist then it returns an error. |
| func (m *Manifest) RemoveDependency(dep Dependency) error { |
| for i, d := range m.Dependencies { |
| if reflect.DeepEqual(d, dep) { |
| m.Dependencies = append(m.Dependencies[:i], m.Dependencies[i+1:]...) |
| return nil |
| } |
| } |
| return fmt.Errorf("dependency does not exist") |
| } |
| |
| // HasImportpath reports whether the Manifest contains the import path. |
| func (m *Manifest) HasImportpath(path string) bool { |
| _, err := m.GetDependencyForImportpath(path) |
| return err == nil |
| } |
| |
| // GetDependencyForRepository return a dependency for specified URL |
| // If the dependency does not exist it returns an error |
| func (m *Manifest) GetDependencyForImportpath(path string) (Dependency, error) { |
| for _, d := range m.Dependencies { |
| if d.Importpath == path { |
| return d, nil |
| } |
| } |
| return Dependency{}, fmt.Errorf("dependency for %s does not exist", path) |
| } |
| |
| // Dependency describes one vendored import path of code |
| // A Dependency is an Importpath sources from a Respository |
| // at Revision from Path. |
| type Dependency struct { |
| // Importpath is name by which this dependency is known. |
| Importpath string `json:"importpath"` |
| |
| // Repository is the remote DVCS location that this |
| // dependency was fetched from. |
| Repository string `json:"repository"` |
| |
| // Revision is the revision that describes the dependency's |
| // remote revision. |
| Revision string `json:"revision"` |
| |
| // Branch is the branch the Revision was located on. |
| // Can be blank if not needed. |
| Branch string `json:"branch"` |
| |
| // Path is the path inside the Repository where the |
| // dependency was fetched from. |
| Path string `json:"path,omitempty"` |
| } |
| |
| // WriteManifest writes a Manifest to the path. If the manifest does |
| // not exist, it is created. If it does exist, it will be overwritten. |
| // If the manifest file is empty (0 dependencies) it will be deleted. |
| // The dependencies will be ordered by import path to reduce churn when making |
| // changes. |
| // TODO(dfc) write to temporary file and move atomically to avoid |
| // destroying a working vendorfile. |
| func WriteManifest(path string, m *Manifest) error { |
| if len(m.Dependencies) == 0 { |
| err := os.Remove(path) |
| if !os.IsNotExist(err) { |
| return err |
| } |
| return nil |
| } |
| |
| f, err := os.Create(path) |
| if err != nil { |
| return err |
| } |
| if err := writeManifest(f, m); err != nil { |
| f.Close() |
| return err |
| } |
| return f.Close() |
| } |
| |
| func writeManifest(w io.Writer, m *Manifest) error { |
| sort.Sort(byImportpath(m.Dependencies)) |
| buf, err := json.MarshalIndent(m, "", "\t") |
| if err != nil { |
| return err |
| } |
| _, err = io.Copy(w, bytes.NewReader(buf)) |
| return err |
| } |
| |
| // ReadManifest reads a Manifest from path. If the Manifest is not |
| // found, a blank Manifest will be returned. |
| func ReadManifest(path string) (*Manifest, error) { |
| f, err := os.Open(path) |
| if err != nil { |
| if os.IsNotExist(err) { |
| return new(Manifest), nil |
| } |
| return nil, err |
| } |
| defer f.Close() |
| return readManifest(f) |
| } |
| |
| func readManifest(r io.Reader) (*Manifest, error) { |
| var m Manifest |
| d := json.NewDecoder(r) |
| err := d.Decode(&m) |
| return &m, err |
| } |
| |
| type byImportpath []Dependency |
| |
| func (s byImportpath) Len() int { return len(s) } |
| func (s byImportpath) Less(i, j int) bool { return s[i].Importpath < s[j].Importpath } |
| func (s byImportpath) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |