This repository has been archived by the owner on Feb 3, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 22
/
manifest.go
182 lines (160 loc) · 5.7 KB
/
manifest.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
package gps
// Manifest represents manifest-type data for a project at a particular version.
// That means dependency constraints, both for normal dependencies and for
// tests. The constraints expressed in a manifest determine the set of versions that
// are acceptable to try for a given project.
//
// Expressing a constraint in a manifest does not guarantee that a particular
// dependency will be present. It only guarantees that if packages in the
// project specified by the dependency are discovered through static analysis of
// the (transitive) import graph, then they will conform to the constraint.
//
// This does entail that manifests can express constraints on projects they do
// not themselves import. This is by design, but its implications are complex.
// See the gps docs for more information: https://github.com/sdboyer/gps/wiki
type Manifest interface {
// Returns a list of project-level constraints.
DependencyConstraints() ProjectConstraints
// Returns a list of constraints applicable to test imports.
//
// These are applied only when tests are incorporated. Typically, that
// will only be for root manifests.
TestDependencyConstraints() ProjectConstraints
}
// RootManifest extends Manifest to add special controls over solving that are
// only afforded to the root project.
type RootManifest interface {
Manifest
// Overrides returns a list of ProjectConstraints that will unconditionally
// supercede any ProjectConstraint declarations made in either the root
// manifest, or in any dependency's manifest.
//
// Overrides are a special control afforded only to root manifests. Tool
// users should be encouraged to use them only as a last resort; they do not
// "play well with others" (that is their express goal), and overreliance on
// them can harm the ecosystem as a whole.
Overrides() ProjectConstraints
// IgnoredPackages returns a set of import paths to ignore. These import
// paths can be within the root project, or part of other projects. Ignoring
// a package means that both it and its (unique) imports will be disregarded
// by all relevant solver operations.
//
// It is an error to include a package in both the ignored and required
// sets.
IgnoredPackages() map[string]bool
// RequiredPackages returns a set of import paths to require. These packages
// are required to be present in any solution. The list can include main
// packages.
//
// It is meaningless to specify packages that are within the
// PackageTree of the ProjectRoot (though not an error, because the
// RootManifest itself does not report a ProjectRoot).
//
// It is an error to include a package in both the ignored and required
// sets.
RequiredPackages() map[string]bool
}
// SimpleManifest is a helper for tools to enumerate manifest data. It's
// generally intended for ephemeral manifests, such as those Analyzers create on
// the fly for projects with no manifest metadata, or metadata through a foreign
// tool's idioms.
type SimpleManifest struct {
Deps, TestDeps ProjectConstraints
}
var _ Manifest = SimpleManifest{}
// DependencyConstraints returns the project's dependencies.
func (m SimpleManifest) DependencyConstraints() ProjectConstraints {
return m.Deps
}
// TestDependencyConstraints returns the project's test dependencies.
func (m SimpleManifest) TestDependencyConstraints() ProjectConstraints {
return m.TestDeps
}
// simpleRootManifest exists so that we have a safe value to swap into solver
// params when a nil Manifest is provided.
//
// Also, for tests.
type simpleRootManifest struct {
c, tc, ovr ProjectConstraints
ig, req map[string]bool
}
func (m simpleRootManifest) DependencyConstraints() ProjectConstraints {
return m.c
}
func (m simpleRootManifest) TestDependencyConstraints() ProjectConstraints {
return m.tc
}
func (m simpleRootManifest) Overrides() ProjectConstraints {
return m.ovr
}
func (m simpleRootManifest) IgnoredPackages() map[string]bool {
return m.ig
}
func (m simpleRootManifest) RequiredPackages() map[string]bool {
return m.req
}
func (m simpleRootManifest) dup() simpleRootManifest {
m2 := simpleRootManifest{
c: make(ProjectConstraints, len(m.c)),
tc: make(ProjectConstraints, len(m.tc)),
ovr: make(ProjectConstraints, len(m.ovr)),
ig: make(map[string]bool, len(m.ig)),
req: make(map[string]bool, len(m.req)),
}
for k, v := range m.c {
m2.c[k] = v
}
for k, v := range m.tc {
m2.tc[k] = v
}
for k, v := range m.ovr {
m2.ovr[k] = v
}
for k, v := range m.ig {
m2.ig[k] = v
}
for k, v := range m.req {
m2.req[k] = v
}
return m2
}
// prepManifest ensures a manifest is prepared and safe for use by the solver.
// This is mostly about ensuring that no outside routine can modify the manifest
// while the solver is in-flight, but it also filters out any empty
// ProjectProperties.
//
// This is achieved by copying the manifest's data into a new SimpleManifest.
func prepManifest(m Manifest) SimpleManifest {
if m == nil {
return SimpleManifest{}
}
deps := m.DependencyConstraints()
ddeps := m.TestDependencyConstraints()
rm := SimpleManifest{
Deps: make(ProjectConstraints, len(deps)),
TestDeps: make(ProjectConstraints, len(ddeps)),
}
for k, d := range deps {
// A zero-value ProjectProperties is equivalent to one with an
// anyConstraint{} in terms of how the solver will treat it. However, we
// normalize between these two by omitting such instances entirely, as
// it negates some possibility for false mismatches in input hashing.
if d.Constraint == nil {
if d.Source == "" {
continue
}
d.Constraint = anyConstraint{}
}
rm.Deps[k] = d
}
for k, d := range ddeps {
if d.Constraint == nil {
if d.Source == "" {
continue
}
d.Constraint = anyConstraint{}
}
rm.TestDeps[k] = d
}
return rm
}