aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/testdata/script/mod_tidy_convergence.txt
blob: 09c46f764bf06fd434f80454fa15f6eb2f2f53af (plain)
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
202
# This test demonstrates a simple case in which 'go mod tidy' may resolve a
# missing package, only to remove that package when resolving its dependencies.
#
# If we naively iterate 'go mod tidy' until the dependency graph converges, this
# scenario may fail to converge.

# The import graph used in this test looks like:
#
# m --- x
#       |
#       x_test --- y
#
# The module dependency graph of m is initially empty.
# Modules x and y look like:
#
# x.1 (provides package x that imports y, but does not depend on module y)
#
# x.2-pre (no dependencies, but does not provide package x)
#
# y.1 (no dependencies, but provides package y)
#
# y.2 --- x.2-pre (provides package y)
#
#
# When we resolve the missing import of y in x_test, we add y@latest — which is
# y.2, not y.1 — as a new dependency. That upgrades to x to x.2-pre, which
# removes package x (and also the need for module y). We can then safely remove
# the dependency on module y, because nothing imports package y any more!
#
# We might be tempted to remove the dependency on module x for the same reason:
# it no longer provides any imported package. However, that would cause 'go mod
# tidy -e' to become unstable: with x.2-pre out of the way, we could once again
# resolve the missing import of package x by re-adding x.1.

cp go.mod go.mod.orig

# 'go mod tidy' without -e should fail without modifying go.mod,
# because it cannot resolve x and y simultaneously.
! go mod tidy

cmp go.mod go.mod.orig

stderr '^go: found example\.net/y in example\.net/y v0.2.0$'
stderr '^go: finding module for package example\.net/x$'

	# TODO: This error message should be clearer — it doesn't indicate why v0.2.0-pre is required.
stderr '^example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'


# 'go mod tidy -e' should follow upgrades to try to resolve the modules that it
# can, and then stop. When we resolve example.net/y, we upgrade to example.net/x
# to v0.2.0-pre. At that version, package x no longer exists and no longer
# imports package y, so the import of x should be left unsatisfied and the
# existing dependency on example.net/x removed.
#
# TODO(bcmills): It would be ever better if we could keep the original
# dependency on example.net/x v0.1.0, but I don't see a way to do that without
# making the algorithm way too complicated. (We would have to detect that the
# new dependency on example.net/y interferes with the package that caused us to
# to add that dependency in the first place, and back out that part of the change
# without also backing out any other needed changes.)

go mod tidy -e
cmp go.mod go.mod.tidye
stderr '^go: found example\.net/y in example\.net/y v0.2.0$'

	# TODO: This error message should be clearer — it doesn't indicate why v0.2.0-pre is required.
stderr '^example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'


# Since we attempt to resolve the dependencies of package x whenever we add x itself,
# this end state is stable.

go mod tidy -e
cmp go.mod go.mod.tidye


# An explicit 'go get' with the correct versions should allow 'go mod tidy' to
# succeed and remain stable. y.1 does not upgrade x, and can therefore be used
# with it.

go get -d example.net/x@v0.1.0 example.net/y@v0.1.0
go mod tidy
cmp go.mod go.mod.postget


# The 'tidy' logic for a lazy main module is somewhat different from that for an
# eager main module, but the overall behavior is the same.

cp go.mod.orig go.mod
go mod edit -go=1.17 go.mod
go mod edit -go=1.17 go.mod.tidye

go mod tidy -e
cmp go.mod go.mod.tidye
stderr '^go: found example\.net/y in example\.net/y v0.2.0$'
stderr '^example\.net/m imports\n\texample\.net/x: package example\.net/x provided by example\.net/x at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'

go get -d example.net/x@v0.1.0 example.net/y@v0.1.0
go mod tidy
cmp go.mod go.mod.postget-117


-- go.mod --
module example.net/m

go 1.16

replace (
	example.net/x v0.1.0 => ./x1
	example.net/x v0.2.0-pre => ./x2-pre
	example.net/y v0.1.0 => ./y1
	example.net/y v0.2.0 => ./y2
)

require (
	example.net/x v0.1.0
)
-- go.mod.tidye --
module example.net/m

go 1.16

replace (
	example.net/x v0.1.0 => ./x1
	example.net/x v0.2.0-pre => ./x2-pre
	example.net/y v0.1.0 => ./y1
	example.net/y v0.2.0 => ./y2
)
-- go.mod.postget --
module example.net/m

go 1.16

replace (
	example.net/x v0.1.0 => ./x1
	example.net/x v0.2.0-pre => ./x2-pre
	example.net/y v0.1.0 => ./y1
	example.net/y v0.2.0 => ./y2
)

require (
	example.net/x v0.1.0
	example.net/y v0.1.0 // indirect
)
-- go.mod.postget-117 --
module example.net/m

go 1.17

replace (
	example.net/x v0.1.0 => ./x1
	example.net/x v0.2.0-pre => ./x2-pre
	example.net/y v0.1.0 => ./y1
	example.net/y v0.2.0 => ./y2
)

require example.net/x v0.1.0

require example.net/y v0.1.0 // indirect
-- m.go --
package m

import _ "example.net/x"

-- x1/go.mod --
module example.net/x

go 1.16
-- x1/x.go --
package x
-- x1/x_test.go --
package x

import _ "example.net/y"

-- x2-pre/go.mod --
module example.net/x

go 1.16
-- x2-pre/README.txt --
There is no package x here. Use example.com/x/subpkg instead.
-- x2-pre/subpkg/subpkg.go --
package subpkg  // import "example.net/x/subpkg"

-- y1/go.mod --
module example.net/y

go 1.16
-- y1/y.go --
package y

-- y2/go.mod --
module example.net/y

go 1.16

require example.net/x v0.2.0-pre
-- y2/y.go --
package y

import _ "example.net/x/subpkg"