blob: e5c3ac4c4660af84c136e33a4b97da610fac03a2 [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
Jordan Krage4e7f6522017-05-31 23:51:3718// LockName is the lock file name used by dep.
Carolyn Van Slycke31a1862017-04-06 15:15:5419const LockName = "Gopkg.lock"
Miguel Molina0acfd382017-01-27 20:39:0720
Jordan Krage4e7f6522017-05-31 23:51:3721// Lock holds lock file data and implements gps.Lock.
Miguel Molina0acfd382017-01-27 20:39:0722type Lock struct {
sam boyer75ac5692017-05-22 17:41:1323 SolveMeta SolveMeta
24 P []gps.LockedProject
sam boyer8be9bb62017-05-16 03:05:4525}
26
Jordan Krage4e7f6522017-05-31 23:51:3727// SolveMeta holds solver meta data.
sam boyer75ac5692017-05-22 17:41:1328type SolveMeta struct {
sam boyer05c40eb2017-05-27 03:50:2929 InputsDigest []byte
sam boyer8be9bb62017-05-16 03:05:4530 AnalyzerName string
31 AnalyzerVersion int
sam boyer75ac5692017-05-22 17:41:1332 SolverName string
33 SolverVersion int
sam boyera9836df2016-10-18 04:39:3734}
35
36type rawLock struct {
sam boyer75ac5692017-05-22 17:41:1337 SolveMeta solveMeta `toml:"solve-meta"`
38 Projects []rawLockedProject `toml:"projects"`
sam boyera9836df2016-10-18 04:39:3739}
40
sam boyer75ac5692017-05-22 17:41:1341type solveMeta struct {
sam boyer00818792017-05-23 02:35:1842 InputsDigest string `toml:"inputs-digest"`
sam boyer75ac5692017-05-22 17:41:1343 AnalyzerName string `toml:"analyzer-name"`
44 AnalyzerVersion int `toml:"analyzer-version"`
45 SolverName string `toml:"solver-name"`
46 SolverVersion int `toml:"solver-version"`
sam boyera9836df2016-10-18 04:39:3747}
48
Carolyn Van Slyck28c23162017-03-21 19:53:5349type rawLockedProject struct {
Carolyn Van Slyckfb7c3fa2017-03-30 00:01:1650 Name string `toml:"name"`
51 Branch string `toml:"branch,omitempty"`
52 Revision string `toml:"revision"`
53 Version string `toml:"version,omitempty"`
54 Source string `toml:"source,omitempty"`
55 Packages []string `toml:"packages"`
sam boyera9836df2016-10-18 04:39:3756}
57
Miguel Molina0acfd382017-01-27 20:39:0758func readLock(r io.Reader) (*Lock, error) {
Carolyn Van Slyckfb7c3fa2017-03-30 00:01:1659 buf := &bytes.Buffer{}
60 _, err := buf.ReadFrom(r)
61 if err != nil {
62 return nil, errors.Wrap(err, "Unable to read byte stream")
63 }
64
65 raw := rawLock{}
66 err = toml.Unmarshal(buf.Bytes(), &raw)
sam boyera9836df2016-10-18 04:39:3767 if err != nil {
Carolyn Van Slyck28c23162017-03-21 19:53:5368 return nil, errors.Wrap(err, "Unable to parse the lock as TOML")
sam boyera9836df2016-10-18 04:39:3769 }
70
Carolyn Van Slyck28c23162017-03-21 19:53:5371 return fromRawLock(raw)
72}
73
74func fromRawLock(raw rawLock) (*Lock, error) {
75 var err error
76 l := &Lock{
77 P: make([]gps.LockedProject, len(raw.Projects)),
78 }
79
sam boyer05c40eb2017-05-27 03:50:2980 l.SolveMeta.InputsDigest, err = hex.DecodeString(raw.SolveMeta.InputsDigest)
sam boyera9836df2016-10-18 04:39:3781 if err != nil {
Carolyn Van Slyckcfc2c942017-03-22 15:58:5082 return nil, errors.Errorf("invalid hash digest in lock's memo field")
sam boyera9836df2016-10-18 04:39:3783 }
sam boyera9836df2016-10-18 04:39:3784
sam boyer75ac5692017-05-22 17:41:1385 l.SolveMeta.AnalyzerName = raw.SolveMeta.AnalyzerName
86 l.SolveMeta.AnalyzerVersion = raw.SolveMeta.AnalyzerVersion
87 l.SolveMeta.SolverName = raw.SolveMeta.SolverName
88 l.SolveMeta.SolverVersion = raw.SolveMeta.SolverVersion
sam boyer8be9bb62017-05-16 03:05:4589
Carolyn Van Slyck28c23162017-03-21 19:53:5390 for i, ld := range raw.Projects {
sam boyera9836df2016-10-18 04:39:3791 r := gps.Revision(ld.Revision)
92
Daniel Martídc6530b2017-01-24 21:48:1493 var v gps.Version = r
sam boyera9836df2016-10-18 04:39:3794 if ld.Version != "" {
95 if ld.Branch != "" {
Carolyn Van Slyckcfc2c942017-03-22 15:58:5096 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:3797 }
Jordan Kragecb7df4a2017-06-14 14:44:5998 v = gps.NewVersion(ld.Version).Pair(r)
sam boyera9836df2016-10-18 04:39:3799 } else if ld.Branch != "" {
Jordan Kragecb7df4a2017-06-14 14:44:59100 v = gps.NewBranch(ld.Branch).Pair(r)
sam boyera9836df2016-10-18 04:39:37101 } else if r == "" {
Carolyn Van Slyckcfc2c942017-03-22 15:58:50102 return nil, errors.Errorf("lock file has entry for %s, but specifies no branch or version", ld.Name)
sam boyera9836df2016-10-18 04:39:37103 }
104
105 id := gps.ProjectIdentifier{
106 ProjectRoot: gps.ProjectRoot(ld.Name),
Carolyn Van Slyck6ae77232017-03-07 19:47:13107 Source: ld.Source,
sam boyera9836df2016-10-18 04:39:37108 }
sam boyerf5699902016-10-18 05:18:18109 l.P[i] = gps.NewLockedProject(id, v, ld.Packages)
sam boyera9836df2016-10-18 04:39:37110 }
sam boyer8be9bb62017-05-16 03:05:45111
sam boyera9836df2016-10-18 04:39:37112 return l, nil
113}
114
Jordan Krage4e7f6522017-05-31 23:51:37115// InputHash returns the hash of inputs which produced this lock data.
Miguel Molina0acfd382017-01-27 20:39:07116func (l *Lock) InputHash() []byte {
sam boyer05c40eb2017-05-27 03:50:29117 return l.SolveMeta.InputsDigest
sam boyera9836df2016-10-18 04:39:37118}
119
Jordan Krage4e7f6522017-05-31 23:51:37120// Projects returns the list of LockedProjects contained in the lock data.
Miguel Molina0acfd382017-01-27 20:39:07121func (l *Lock) Projects() []gps.LockedProject {
sam boyera9836df2016-10-18 04:39:37122 return l.P
123}
sam boyer881f3102016-11-30 05:17:59124
Carolyn Van Slyckd3135b82017-03-20 18:13:48125// toRaw converts the manifest into a representation suitable to write to the lock file
126func (l *Lock) toRaw() rawLock {
sam boyer881f3102016-11-30 05:17:59127 raw := rawLock{
sam boyer75ac5692017-05-22 17:41:13128 SolveMeta: solveMeta{
sam boyer05c40eb2017-05-27 03:50:29129 InputsDigest: hex.EncodeToString(l.SolveMeta.InputsDigest),
sam boyer75ac5692017-05-22 17:41:13130 AnalyzerName: l.SolveMeta.AnalyzerName,
131 AnalyzerVersion: l.SolveMeta.AnalyzerVersion,
132 SolverName: l.SolveMeta.SolverName,
133 SolverVersion: l.SolveMeta.SolverVersion,
sam boyer8be9bb62017-05-16 03:05:45134 },
Carolyn Van Slyck28c23162017-03-21 19:53:53135 Projects: make([]rawLockedProject, len(l.P)),
sam boyer881f3102016-11-30 05:17:59136 }
137
Miguel Molina0acfd382017-01-27 20:39:07138 sort.Sort(SortedLockedProjects(l.P))
sam boyer2c832bd2016-12-03 17:33:40139
sam boyer881f3102016-11-30 05:17:59140 for k, lp := range l.P {
141 id := lp.Ident()
Carolyn Van Slyck28c23162017-03-21 19:53:53142 ld := rawLockedProject{
Carolyn Van Slyck6ae77232017-03-07 19:47:13143 Name: string(id.ProjectRoot),
144 Source: id.Source,
145 Packages: lp.Packages(),
sam boyer881f3102016-11-30 05:17:59146 }
147
sam boyer166b6162016-11-30 16:50:57148 v := lp.Version()
Carolyn Van Slyck34bbce02017-04-11 15:38:50149 ld.Revision, ld.Branch, ld.Version = gps.VersionComponentStrings(v)
sam boyer166b6162016-11-30 16:50:57150
Carolyn Van Slyck28c23162017-03-21 19:53:53151 raw.Projects[k] = ld
sam boyer881f3102016-11-30 05:17:59152 }
153
Carolyn Van Slyckd3135b82017-03-20 18:13:48154 return raw
155}
156
Jordan Krage4e7f6522017-05-31 23:51:37157// MarshalTOML serializes this lock into TOML via an intermediate raw form.
Carolyn Van Slyck90657752017-04-02 20:20:21158func (l *Lock) MarshalTOML() ([]byte, error) {
Carolyn Van Slyckd3135b82017-03-20 18:13:48159 raw := l.toRaw()
Carolyn Van Slyckfb7c3fa2017-03-30 00:01:16160 result, err := toml.Marshal(raw)
Carolyn Van Slyck90657752017-04-02 20:20:21161 return result, errors.Wrap(err, "Unable to marshal lock to TOML string")
Carolyn Van Slyckd3135b82017-03-20 18:13:48162}
163
sam boyer20811362017-05-16 03:12:06164// LockFromSolution converts a gps.Solution to dep's representation of a lock.
sam boyer7b1fbdb2016-12-01 05:25:48165//
166// Data is defensively copied wherever necessary to ensure the resulting *lock
167// shares no memory with the original lock.
sam boyer20811362017-05-16 03:12:06168func LockFromSolution(in gps.Solution) *Lock {
sam boyer7b1fbdb2016-12-01 05:25:48169 h, p := in.InputHash(), in.Projects()
170
Miguel Molina0acfd382017-01-27 20:39:07171 l := &Lock{
sam boyer75ac5692017-05-22 17:41:13172 SolveMeta: SolveMeta{
sam boyer05c40eb2017-05-27 03:50:29173 InputsDigest: make([]byte, len(h)),
sam boyer8be9bb62017-05-16 03:05:45174 AnalyzerName: in.AnalyzerName(),
175 AnalyzerVersion: in.AnalyzerVersion(),
sam boyer75ac5692017-05-22 17:41:13176 SolverName: in.SolverName(),
177 SolverVersion: in.SolverVersion(),
sam boyer8be9bb62017-05-16 03:05:45178 },
179 P: make([]gps.LockedProject, len(p)),
sam boyer7b1fbdb2016-12-01 05:25:48180 }
181
sam boyer05c40eb2017-05-27 03:50:29182 copy(l.SolveMeta.InputsDigest, h)
sam boyer7b1fbdb2016-12-01 05:25:48183 copy(l.P, p)
184 return l
185}
sam boyer2c832bd2016-12-03 17:33:40186
Jordan Krage4e7f6522017-05-31 23:51:37187// SortedLockedProjects implements sort.Interface.
Miguel Molina0acfd382017-01-27 20:39:07188type SortedLockedProjects []gps.LockedProject
sam boyer2c832bd2016-12-03 17:33:40189
Miguel Molina0acfd382017-01-27 20:39:07190func (s SortedLockedProjects) Len() int { return len(s) }
191func (s SortedLockedProjects) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
192func (s SortedLockedProjects) Less(i, j int) bool {
sam boyer2c832bd2016-12-03 17:33:40193 l, r := s[i].Ident(), s[j].Ident()
194
195 if l.ProjectRoot < r.ProjectRoot {
196 return true
197 }
198 if r.ProjectRoot < l.ProjectRoot {
199 return false
200 }
201
sam boyer5b2ff112017-01-04 02:19:24202 return l.Source < r.Source
sam boyer2c832bd2016-12-03 17:33:40203}