github.com/sc0rp1us/gb@v0.4.1-0.20160319180011-4ba8cf1baa5a/vendor/manifest.go (about) 1 package vendor 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "os" 9 "reflect" 10 "sort" 11 ) 12 13 // gb-vendor manifest support 14 15 // Manifest describes the layout of $PROJECT/vendor/manifest. 16 type Manifest struct { 17 // Manifest version. Current manifest version is 0. 18 Version int `json:"version"` 19 20 // Depenencies is a list of vendored dependencies. 21 Dependencies []Dependency `json:"dependencies"` 22 } 23 24 // AddDependency adds a Dependency to the current Manifest. 25 // If the dependency exists already then it returns and error. 26 func (m *Manifest) AddDependency(dep Dependency) error { 27 if m.HasImportpath(dep.Importpath) { 28 return fmt.Errorf("already registered") 29 } 30 m.Dependencies = append(m.Dependencies, dep) 31 return nil 32 } 33 34 // RemoveDependency removes a Dependency from the current Manifest. 35 // If the dependency does not exist then it returns an error. 36 func (m *Manifest) RemoveDependency(dep Dependency) error { 37 for i, d := range m.Dependencies { 38 if reflect.DeepEqual(d, dep) { 39 m.Dependencies = append(m.Dependencies[:i], m.Dependencies[i+1:]...) 40 return nil 41 } 42 } 43 return fmt.Errorf("dependency does not exist") 44 } 45 46 // HasImportpath reports whether the Manifest contains the import path. 47 func (m *Manifest) HasImportpath(path string) bool { 48 _, err := m.GetDependencyForImportpath(path) 49 return err == nil 50 } 51 52 // GetDependencyForRepository return a dependency for specified URL 53 // If the dependency does not exist it returns an error 54 func (m *Manifest) GetDependencyForImportpath(path string) (Dependency, error) { 55 for _, d := range m.Dependencies { 56 if d.Importpath == path { 57 return d, nil 58 } 59 } 60 return Dependency{}, fmt.Errorf("dependency for %s does not exist", path) 61 } 62 63 // Dependency describes one vendored import path of code 64 // A Dependency is an Importpath sources from a Respository 65 // at Revision from Path. 66 type Dependency struct { 67 // Importpath is name by which this dependency is known. 68 Importpath string `json:"importpath"` 69 70 // Repository is the remote DVCS location that this 71 // dependency was fetched from. 72 Repository string `json:"repository"` 73 74 // Revision is the revision that describes the dependency's 75 // remote revision. 76 Revision string `json:"revision"` 77 78 // Branch is the branch the Revision was located on. 79 // Can be blank if not needed. 80 Branch string `json:"branch"` 81 82 // Path is the path inside the Repository where the 83 // dependency was fetched from. 84 Path string `json:"path,omitempty"` 85 } 86 87 // WriteManifest writes a Manifest to the path. If the manifest does 88 // not exist, it is created. If it does exist, it will be overwritten. 89 // If the manifest file is empty (0 dependencies) it will be deleted. 90 // The dependencies will be ordered by import path to reduce churn when making 91 // changes. 92 // TODO(dfc) write to temporary file and move atomically to avoid 93 // destroying a working vendorfile. 94 func WriteManifest(path string, m *Manifest) error { 95 if len(m.Dependencies) == 0 { 96 err := os.Remove(path) 97 if !os.IsNotExist(err) { 98 return err 99 } 100 return nil 101 } 102 103 f, err := os.Create(path) 104 if err != nil { 105 return err 106 } 107 if err := writeManifest(f, m); err != nil { 108 f.Close() 109 return err 110 } 111 return f.Close() 112 } 113 114 func writeManifest(w io.Writer, m *Manifest) error { 115 sort.Sort(byImportpath(m.Dependencies)) 116 buf, err := json.MarshalIndent(m, "", "\t") 117 if err != nil { 118 return err 119 } 120 _, err = io.Copy(w, bytes.NewReader(buf)) 121 return err 122 } 123 124 // ReadManifest reads a Manifest from path. If the Manifest is not 125 // found, a blank Manifest will be returned. 126 func ReadManifest(path string) (*Manifest, error) { 127 f, err := os.Open(path) 128 if err != nil { 129 if os.IsNotExist(err) { 130 return new(Manifest), nil 131 } 132 return nil, err 133 } 134 defer f.Close() 135 return readManifest(f) 136 } 137 138 func readManifest(r io.Reader) (*Manifest, error) { 139 var m Manifest 140 d := json.NewDecoder(r) 141 err := d.Decode(&m) 142 return &m, err 143 } 144 145 type byImportpath []Dependency 146 147 func (s byImportpath) Len() int { return len(s) } 148 func (s byImportpath) Less(i, j int) bool { return s[i].Importpath < s[j].Importpath } 149 func (s byImportpath) Swap(i, j int) { s[i], s[j] = s[j], s[i] }