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] }