blob: 43d56d3a8ea6e48cb0612f53920e4e9760de74ed [file] [log] [blame]
sam boyera9836df2016-10-18 04:39:371// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Miguel Molina0acfd382017-01-27 20:39:075package dep
sam boyera9836df2016-10-18 04:39:376
7import (
Dave Cheney9ea84892017-05-10 04:13:228 "bytes"
sam boyera9836df2016-10-18 04:39:379 "encoding/hex"
sam boyera9836df2016-10-18 04:39:3710 "io"
Jess Frazelle3e7c05f2016-12-05 21:30:3311 "sort"
sam boyera9836df2016-10-18 04:39:3712
Dave Cheney9ea84892017-05-10 04:13:2213 "github.com/golang/dep/internal/gps"
Carolyn Van Slyckd3135b82017-03-20 18:13:4814 "github.com/pelletier/go-toml"
Carolyn Van Slyckcfc2c942017-03-22 15:58:5015 "github.com/pkg/errors"
sam boyera9836df2016-10-18 04:39:3716)
17
Carolyn Van Slycke31a1862017-04-06 15:15:5418const LockName = "Gopkg.lock"
Miguel Molina0acfd382017-01-27 20:39:0719
20type Lock struct {
sam boyer75ac5692017-05-22 17:41:1321 SolveMeta SolveMeta
22 P []gps.LockedProject
sam boyer8be9bb62017-05-16 03:05:4523}
24
sam boyer75ac5692017-05-22 17:41:1325type SolveMeta struct {
sam boyer05c40eb2017-05-27 03:50:2926 InputsDigest []byte
sam boyer8be9bb62017-05-16 03:05:4527 AnalyzerName string
28 AnalyzerVersion int
sam boyer75ac5692017-05-22 17:41:1329 SolverName string
30 SolverVersion int
sam boyera9836df2016-10-18 04:39:3731}
32
33type rawLock struct {
sam boyer75ac5692017-05-22 17:41:1334 SolveMeta solveMeta `toml:"solve-meta"`
35 Projects []rawLockedProject `toml:"projects"`
sam boyera9836df2016-10-18 04:39:3736}
37
sam boyer75ac5692017-05-22 17:41:1338type solveMeta struct {
sam boyer00818792017-05-23 02:35:1839 InputsDigest string `toml:"inputs-digest"`
sam boyer75ac5692017-05-22 17:41:1340 AnalyzerName string `toml:"analyzer-name"`
41 AnalyzerVersion int `toml:"analyzer-version"`
42 SolverName string `toml:"solver-name"`
43 SolverVersion int `toml:"solver-version"`
sam boyera9836df2016-10-18 04:39:3744}
45
Carolyn Van Slyck28c23162017-03-21 19:53:5346type rawLockedProject struct {
Carolyn Van Slyckfb7c3fa2017-03-30 00:01:1647 Name string `toml:"name"`
48 Branch string `toml:"branch,omitempty"`
49 Revision string `toml:"revision"`
50 Version string `toml:"version,omitempty"`
51 Source string `toml:"source,omitempty"`
52 Packages []string `toml:"packages"`
sam boyera9836df2016-10-18 04:39:3753}
54
Miguel Molina0acfd382017-01-27 20:39:0755func readLock(r io.Reader) (*Lock, error) {
Carolyn Van Slyckfb7c3fa2017-03-30 00:01:1656 buf := &bytes.Buffer{}
57 _, err := buf.ReadFrom(r)
58 if err != nil {
59 return nil, errors.Wrap(err, "Unable to read byte stream")
60 }
61
62 raw := rawLock{}
63 err = toml.Unmarshal(buf.Bytes(), &raw)
sam boyera9836df2016-10-18 04:39:3764 if err != nil {
Carolyn Van Slyck28c23162017-03-21 19:53:5365 return nil, errors.Wrap(err, "Unable to parse the lock as TOML")
sam boyera9836df2016-10-18 04:39:3766 }
67
Carolyn Van Slyck28c23162017-03-21 19:53:5368 return fromRawLock(raw)
69}
70
71func fromRawLock(raw rawLock) (*Lock, error) {
72 var err error
73 l := &Lock{
74 P: make([]gps.LockedProject, len(raw.Projects)),
75 }
76
sam boyer05c40eb2017-05-27 03:50:2977 l.SolveMeta.InputsDigest, err = hex.DecodeString(raw.SolveMeta.InputsDigest)
sam boyera9836df2016-10-18 04:39:3778 if err != nil {
Carolyn Van Slyckcfc2c942017-03-22 15:58:5079 return nil, errors.Errorf("invalid hash digest in lock's memo field")
sam boyera9836df2016-10-18 04:39:3780 }
sam boyera9836df2016-10-18 04:39:3781
sam boyer75ac5692017-05-22 17:41:1382 l.SolveMeta.AnalyzerName = raw.SolveMeta.AnalyzerName
83 l.SolveMeta.AnalyzerVersion = raw.SolveMeta.AnalyzerVersion
84 l.SolveMeta.SolverName = raw.SolveMeta.SolverName
85 l.SolveMeta.SolverVersion = raw.SolveMeta.SolverVersion
sam boyer8be9bb62017-05-16 03:05:4586
Carolyn Van Slyck28c23162017-03-21 19:53:5387 for i, ld := range raw.Projects {
sam boyera9836df2016-10-18 04:39:3788 r := gps.Revision(ld.Revision)
89
Daniel Martídc6530b2017-01-24 21:48:1490 var v gps.Version = r
sam boyera9836df2016-10-18 04:39:3791 if ld.Version != "" {
92 if ld.Branch != "" {
Carolyn Van Slyckcfc2c942017-03-22 15:58:5093 return nil, errors.Errorf("lock file specified both a branch (%s) and version (%s) for %s", ld.Branch, ld.Version, ld.Name)
sam boyera9836df2016-10-18 04:39:3794 }
95 v = gps.NewVersion(ld.Version).Is(r)
96 } else if ld.Branch != "" {
97 v = gps.NewBranch(ld.Branch).Is(r)
98 } else if r == "" {
Carolyn Van Slyckcfc2c942017-03-22 15:58:5099 return nil, errors.Errorf("lock file has entry for %s, but specifies no branch or version", ld.Name)
sam boyera9836df2016-10-18 04:39:37100 }
101
102 id := gps.ProjectIdentifier{
103 ProjectRoot: gps.ProjectRoot(ld.Name),
Carolyn Van Slyck6ae77232017-03-07 19:47:13104 Source: ld.Source,
sam boyera9836df2016-10-18 04:39:37105 }
sam boyerf5699902016-10-18 05:18:18106 l.P[i] = gps.NewLockedProject(id, v, ld.Packages)
sam boyera9836df2016-10-18 04:39:37107 }
sam boyer8be9bb62017-05-16 03:05:45108
sam boyera9836df2016-10-18 04:39:37109 return l, nil
110}
111
Miguel Molina0acfd382017-01-27 20:39:07112func (l *Lock) InputHash() []byte {
sam boyer05c40eb2017-05-27 03:50:29113 return l.SolveMeta.InputsDigest
sam boyera9836df2016-10-18 04:39:37114}
115
Miguel Molina0acfd382017-01-27 20:39:07116func (l *Lock) Projects() []gps.LockedProject {
sam boyera9836df2016-10-18 04:39:37117 return l.P
118}
sam boyer881f3102016-11-30 05:17:59119
Carolyn Van Slyckd3135b82017-03-20 18:13:48120// toRaw converts the manifest into a representation suitable to write to the lock file
121func (l *Lock) toRaw() rawLock {
sam boyer881f3102016-11-30 05:17:59122 raw := rawLock{
sam boyer75ac5692017-05-22 17:41:13123 SolveMeta: solveMeta{
sam boyer05c40eb2017-05-27 03:50:29124 InputsDigest: hex.EncodeToString(l.SolveMeta.InputsDigest),
sam boyer75ac5692017-05-22 17:41:13125 AnalyzerName: l.SolveMeta.AnalyzerName,
126 AnalyzerVersion: l.SolveMeta.AnalyzerVersion,
127 SolverName: l.SolveMeta.SolverName,
128 SolverVersion: l.SolveMeta.SolverVersion,
sam boyer8be9bb62017-05-16 03:05:45129 },
Carolyn Van Slyck28c23162017-03-21 19:53:53130 Projects: make([]rawLockedProject, len(l.P)),
sam boyer881f3102016-11-30 05:17:59131 }
132
Miguel Molina0acfd382017-01-27 20:39:07133 sort.Sort(SortedLockedProjects(l.P))
sam boyer2c832bd2016-12-03 17:33:40134
sam boyer881f3102016-11-30 05:17:59135 for k, lp := range l.P {
136 id := lp.Ident()
Carolyn Van Slyck28c23162017-03-21 19:53:53137 ld := rawLockedProject{
Carolyn Van Slyck6ae77232017-03-07 19:47:13138 Name: string(id.ProjectRoot),
139 Source: id.Source,
140 Packages: lp.Packages(),
sam boyer881f3102016-11-30 05:17:59141 }
142
sam boyer166b6162016-11-30 16:50:57143 v := lp.Version()
Carolyn Van Slyck34bbce02017-04-11 15:38:50144 ld.Revision, ld.Branch, ld.Version = gps.VersionComponentStrings(v)
sam boyer166b6162016-11-30 16:50:57145
Carolyn Van Slyck28c23162017-03-21 19:53:53146 raw.Projects[k] = ld
sam boyer881f3102016-11-30 05:17:59147 }
148
sam boyerd1c74a82016-11-30 17:50:41149 // TODO sort output - #15
sam boyer20bf1022016-12-01 00:37:28150
Carolyn Van Slyckd3135b82017-03-20 18:13:48151 return raw
152}
153
Carolyn Van Slyck90657752017-04-02 20:20:21154func (l *Lock) MarshalTOML() ([]byte, error) {
Carolyn Van Slyckd3135b82017-03-20 18:13:48155 raw := l.toRaw()
Carolyn Van Slyckfb7c3fa2017-03-30 00:01:16156 result, err := toml.Marshal(raw)
Carolyn Van Slyck90657752017-04-02 20:20:21157 return result, errors.Wrap(err, "Unable to marshal lock to TOML string")
Carolyn Van Slyckd3135b82017-03-20 18:13:48158}
159
sam boyer20811362017-05-16 03:12:06160// LockFromSolution converts a gps.Solution to dep's representation of a lock.
sam boyer7b1fbdb2016-12-01 05:25:48161//
162// Data is defensively copied wherever necessary to ensure the resulting *lock
163// shares no memory with the original lock.
sam boyer20811362017-05-16 03:12:06164func LockFromSolution(in gps.Solution) *Lock {
sam boyer7b1fbdb2016-12-01 05:25:48165 h, p := in.InputHash(), in.Projects()
166
Miguel Molina0acfd382017-01-27 20:39:07167 l := &Lock{
sam boyer75ac5692017-05-22 17:41:13168 SolveMeta: SolveMeta{
sam boyer05c40eb2017-05-27 03:50:29169 InputsDigest: make([]byte, len(h)),
sam boyer8be9bb62017-05-16 03:05:45170 AnalyzerName: in.AnalyzerName(),
171 AnalyzerVersion: in.AnalyzerVersion(),
sam boyer75ac5692017-05-22 17:41:13172 SolverName: in.SolverName(),
173 SolverVersion: in.SolverVersion(),
sam boyer8be9bb62017-05-16 03:05:45174 },
175 P: make([]gps.LockedProject, len(p)),
sam boyer7b1fbdb2016-12-01 05:25:48176 }
177
sam boyer05c40eb2017-05-27 03:50:29178 copy(l.SolveMeta.InputsDigest, h)
sam boyer7b1fbdb2016-12-01 05:25:48179 copy(l.P, p)
180 return l
181}
sam boyer2c832bd2016-12-03 17:33:40182
Miguel Molina0acfd382017-01-27 20:39:07183type SortedLockedProjects []gps.LockedProject
sam boyer2c832bd2016-12-03 17:33:40184
Miguel Molina0acfd382017-01-27 20:39:07185func (s SortedLockedProjects) Len() int { return len(s) }
186func (s SortedLockedProjects) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
187func (s SortedLockedProjects) Less(i, j int) bool {
sam boyer2c832bd2016-12-03 17:33:40188 l, r := s[i].Ident(), s[j].Ident()
189
190 if l.ProjectRoot < r.ProjectRoot {
191 return true
192 }
193 if r.ProjectRoot < l.ProjectRoot {
194 return false
195 }
196
sam boyer5b2ff112017-01-04 02:19:24197 return l.Source < r.Source
sam boyer2c832bd2016-12-03 17:33:40198}