forked from Masterminds/glide
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lock.go
201 lines (171 loc) · 4.67 KB
/
lock.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package cfg
import (
"crypto/sha256"
"io/ioutil"
"sort"
"strings"
"time"
"gopkg.in/yaml.v2"
)
// Lockfile represents a glide.lock file.
type Lockfile struct {
Hash string `yaml:"hash"`
Updated time.Time `yaml:"updated"`
Imports Locks `yaml:"imports"`
DevImports Locks `yaml:"testImports"`
}
// LockfileFromYaml returns an instance of Lockfile from YAML
func LockfileFromYaml(yml []byte) (*Lockfile, error) {
lock := &Lockfile{}
err := yaml.Unmarshal([]byte(yml), &lock)
return lock, err
}
// Marshal converts a Config instance to YAML
func (lf *Lockfile) Marshal() ([]byte, error) {
yml, err := yaml.Marshal(&lf)
if err != nil {
return []byte{}, err
}
return yml, nil
}
// WriteFile writes a Glide lock file.
//
// This is a convenience function that marshals the YAML and then writes it to
// the given file. If the file exists, it will be clobbered.
func (lf *Lockfile) WriteFile(lockpath string) error {
o, err := lf.Marshal()
if err != nil {
return err
}
return ioutil.WriteFile(lockpath, o, 0666)
}
// Clone returns a clone of Lockfile
func (lf *Lockfile) Clone() *Lockfile {
n := &Lockfile{}
n.Hash = lf.Hash
n.Updated = lf.Updated
n.Imports = lf.Imports.Clone()
n.DevImports = lf.DevImports.Clone()
return n
}
// Fingerprint returns a hash of the contents minus the date. This allows for
// two lockfiles to be compared irrespective of their updated times.
func (lf *Lockfile) Fingerprint() ([32]byte, error) {
c := lf.Clone()
c.Updated = time.Time{} // Set the time to be the nil equivalent
sort.Sort(c.Imports)
sort.Sort(c.DevImports)
yml, err := c.Marshal()
if err != nil {
return [32]byte{}, err
}
return sha256.Sum256(yml), nil
}
// ReadLockFile loads the contents of a glide.lock file.
func ReadLockFile(lockpath string) (*Lockfile, error) {
yml, err := ioutil.ReadFile(lockpath)
if err != nil {
return nil, err
}
lock, err := LockfileFromYaml(yml)
if err != nil {
return nil, err
}
return lock, nil
}
// Locks is a slice of locked dependencies.
type Locks []*Lock
// Clone returns a Clone of Locks.
func (l Locks) Clone() Locks {
n := make(Locks, 0, len(l))
for _, v := range l {
n = append(n, v.Clone())
}
return n
}
// Len returns the length of the Locks. This is needed for sorting with
// the sort package.
func (l Locks) Len() int {
return len(l)
}
// Less is needed for the sort interface. It compares two locks based on
// their name.
func (l Locks) Less(i, j int) bool {
// Names are normalized to lowercase because case affects sorting order. For
// example, Masterminds comes before kylelemons. Making them lowercase
// causes kylelemons to come first which is what is expected.
return strings.ToLower(l[i].Name) < strings.ToLower(l[j].Name)
}
// Swap is needed for the sort interface. It swaps the position of two
// locks.
func (l Locks) Swap(i, j int) {
l[i], l[j] = l[j], l[i]
}
// Lock represents an individual locked dependency.
type Lock struct {
Name string `yaml:"name"`
Version string `yaml:"version"`
Repository string `yaml:"repo,omitempty"`
VcsType string `yaml:"vcs,omitempty"`
Subpackages []string `yaml:"subpackages,omitempty"`
Arch []string `yaml:"arch,omitempty"`
Os []string `yaml:"os,omitempty"`
}
// Clone creates a clone of a Lock.
func (l *Lock) Clone() *Lock {
return &Lock{
Name: l.Name,
Version: l.Version,
Repository: l.Repository,
VcsType: l.VcsType,
Subpackages: l.Subpackages,
Arch: l.Arch,
Os: l.Os,
}
}
// LockFromDependency converts a Dependency to a Lock
func LockFromDependency(dep *Dependency) *Lock {
return &Lock{
Name: dep.Name,
Version: dep.Pin,
Repository: dep.Repository,
VcsType: dep.VcsType,
Subpackages: dep.Subpackages,
Arch: dep.Arch,
Os: dep.Os,
}
}
// NewLockfile is used to create an instance of Lockfile.
func NewLockfile(ds, tds Dependencies, hash string) *Lockfile {
lf := &Lockfile{
Hash: hash,
Updated: time.Now(),
Imports: make([]*Lock, len(ds)),
DevImports: make([]*Lock, len(tds)),
}
for i := 0; i < len(ds); i++ {
lf.Imports[i] = LockFromDependency(ds[i])
}
sort.Sort(lf.Imports)
for i := 0; i < len(tds); i++ {
lf.DevImports[i] = LockFromDependency(tds[i])
}
sort.Sort(lf.DevImports)
return lf
}
// LockfileFromMap takes a map of dependencies and generates a lock Lockfile instance.
func LockfileFromMap(ds map[string]*Dependency, hash string) *Lockfile {
lf := &Lockfile{
Hash: hash,
Updated: time.Now(),
Imports: make([]*Lock, len(ds)),
}
i := 0
for name, dep := range ds {
lf.Imports[i] = LockFromDependency(dep)
lf.Imports[i].Name = name
i++
}
sort.Sort(lf.Imports)
return lf
}