1package mirrors
2
3import (
4	"io/ioutil"
5	"sort"
6	"strings"
7
8	"gopkg.in/yaml.v2"
9)
10
11// Mirrors contains global mirrors to local configuration
12type Mirrors struct {
13
14	// Repos contains repo mirror configuration
15	Repos MirrorRepos `yaml:"repos"`
16}
17
18// Marshal converts a Mirror instance to YAML
19func (ov *Mirrors) Marshal() ([]byte, error) {
20	yml, err := yaml.Marshal(&ov)
21	if err != nil {
22		return []byte{}, err
23	}
24	return yml, nil
25}
26
27// WriteFile writes an mirrors.yaml file
28//
29// This is a convenience function that marshals the YAML and then writes it to
30// the given file. If the file exists, it will be clobbered.
31func (ov *Mirrors) WriteFile(opath string) error {
32	o, err := ov.Marshal()
33	if err != nil {
34		return err
35	}
36	return ioutil.WriteFile(opath, o, 0666)
37}
38
39// ReadMirrorsFile loads the contents of an mirrors.yaml file.
40func ReadMirrorsFile(opath string) (*Mirrors, error) {
41	yml, err := ioutil.ReadFile(opath)
42	if err != nil {
43		return nil, err
44	}
45	ov, err := FromYaml(yml)
46	if err != nil {
47		return nil, err
48	}
49	return ov, nil
50}
51
52// FromYaml returns an instance of Mirrors from YAML
53func FromYaml(yml []byte) (*Mirrors, error) {
54	ov := &Mirrors{}
55	err := yaml.Unmarshal([]byte(yml), &ov)
56	return ov, err
57}
58
59// MarshalYAML is a hook for gopkg.in/yaml.v2.
60// It sorts mirror repos lexicographically for reproducibility.
61func (ov *Mirrors) MarshalYAML() (interface{}, error) {
62
63	sort.Sort(ov.Repos)
64
65	return ov, nil
66}
67
68// MirrorRepos is a slice of Mirror pointers
69type MirrorRepos []*MirrorRepo
70
71// Len returns the length of the MirrorRepos. This is needed for sorting with
72// the sort package.
73func (o MirrorRepos) Len() int {
74	return len(o)
75}
76
77// Less is needed for the sort interface. It compares two MirrorRepos based on
78// their original value.
79func (o MirrorRepos) Less(i, j int) bool {
80
81	// Names are normalized to lowercase because case affects sorting order. For
82	// example, Masterminds comes before kylelemons. Making them lowercase
83	// causes kylelemons to come first which is what is expected.
84	return strings.ToLower(o[i].Original) < strings.ToLower(o[j].Original)
85}
86
87// Swap is needed for the sort interface. It swaps the position of two
88// MirrorRepos.
89func (o MirrorRepos) Swap(i, j int) {
90	o[i], o[j] = o[j], o[i]
91}
92
93// MirrorRepo represents a single repo mirror
94type MirrorRepo struct {
95	Original string `yaml:"original"`
96	Repo     string `yaml:"repo"`
97	Vcs      string `yaml:"vcs,omitempty"`
98}
99