...

Text file src/cmd/go/testdata/script/mod_tidy_convergence_loop.txt

Documentation: cmd/go/testdata/script

     1# This test demonstrates a simple case in which 'go mod tidy' may resolve a
     2# missing package, only to remove that package when resolving its dependencies.
     3#
     4# If we naively iterate 'go mod tidy' until the dependency graph converges, this
     5# scenario may fail to converge.
     6
     7# The import graph used in this test looks like:
     8#
     9# m --- w
    10# |
    11# + --- x
    12# |
    13# + --- y
    14# |
    15# + --- z
    16#
    17# The module dependency graph of m initially contains w.1 (and, by extension,
    18# y.2-pre and z.2-pre). This is an arbitrary point in the cycle of possible
    19# configurations.
    20#
    21# w.1 requires y.2-pre and z.2-pre
    22# x.1 requires z.2-pre and w.2-pre
    23# y.1 requires w.2-pre and x.2-pre
    24# z.1 requires x.2-pre and y.2-pre
    25#
    26# At each point, exactly one missing package can be resolved by adding a
    27# dependency on the .1 release of the module that provides that package.
    28# However, adding that dependency causes the module providing another package to
    29# roll over from its .1 release to its .2-pre release, which removes the
    30# package. Once the package is removed, 'go mod tidy -e' no longer sees the
    31# module as relevant to the main module, and will happily remove the existing
    32# dependency on it.
    33#
    34# The cycle is of length 4 so that at every step only one package can be
    35# resolved. This is important because it prevents the iteration from ever
    36# reaching a state in which every package is simultaneously over-upgraded — such
    37# a state is stable and does not exhibit failure to converge.
    38
    39cp go.mod go.mod.orig
    40
    41# 'go mod tidy' without -e should fail without modifying go.mod,
    42# because it cannot resolve x, y, and z simultaneously.
    43! go mod tidy
    44
    45cmp go.mod go.mod.orig
    46
    47stderr '^go: finding module for package example\.net/w$'
    48stderr '^go: finding module for package example\.net/x$'
    49stderr -count=2 '^go: finding module for package example\.net/y$'
    50stderr -count=2 '^go: finding module for package example\.net/z$'
    51stderr '^go: found example\.net/x in example\.net/x v0.1.0$'
    52
    53	# TODO: These error messages should be clearer — it doesn't indicate why v0.2.0-pre is required.
    54stderr '^go: example\.net/m imports\n\texample\.net/w: package example\.net/w provided by example\.net/w at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
    55stderr '^go: example\.net/m imports\n\texample\.net/y: package example\.net/y provided by example\.net/y at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
    56stderr '^go: example\.net/m imports\n\texample\.net/z: package example\.net/z provided by example\.net/z at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
    57
    58
    59# 'go mod tidy -e' should preserve all of the upgrades to modules that could
    60# provide the missing packages but don't. That would at least explain why they
    61# are missing, and why no individual module can be upgraded in order to satisfy
    62# a missing import.
    63#
    64# TODO(bcmills): Today, it doesn't preserve those upgrades, and instead advances
    65# the state by one through the cycle of semi-tidy states.
    66
    67go mod tidy -e
    68
    69cmp go.mod go.mod.tidye1
    70
    71stderr '^go: finding module for package example\.net/w$'
    72stderr '^go: finding module for package example\.net/x$'
    73stderr -count=2 '^go: finding module for package example\.net/y$'
    74stderr -count=2 '^go: finding module for package example\.net/z$'
    75stderr '^go: found example\.net/x in example\.net/x v0.1.0$'
    76
    77stderr '^go: example\.net/m imports\n\texample\.net/w: package example\.net/w provided by example\.net/w at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
    78stderr '^go: example\.net/m imports\n\texample\.net/y: package example\.net/y provided by example\.net/y at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
    79stderr '^go: example\.net/m imports\n\texample\.net/z: package example\.net/z provided by example\.net/z at latest version v0\.1\.0 but not at required version v0\.2\.0-pre$'
    80
    81
    82go mod tidy -e
    83cmp go.mod go.mod.tidye2
    84
    85go mod tidy -e
    86cmp go.mod go.mod.tidye3
    87
    88go mod tidy -e
    89cmp go.mod go.mod.orig
    90
    91
    92# If we upgrade away all of the packages simultaneously, the resulting tidy
    93# state converges at "no dependencies", because simultaneously adding all of the
    94# packages simultaneously over-upgrades all of the dependencies, and 'go mod
    95# tidy' treats "no package can be added" as a terminal state.
    96
    97go get example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre
    98go mod tidy -e
    99cmp go.mod go.mod.postget
   100go mod tidy -e
   101cmp go.mod go.mod.postget
   102
   103
   104# The 'tidy' logic for a lazy main module requires more iterations to converge,
   105# because it is willing to drop dependencies on non-root modules that do not
   106# otherwise provide imported packages.
   107#
   108# On the first iteration, it adds x.1 as a root, which upgrades z and w,
   109# dropping w.1's requirement on y. w.1 was initially a root, so the upgraded
   110# w.2-pre is retained as a root.
   111#
   112# On the second iteration, it adds y.1 as a root, which upgrades w and x,
   113# dropping x.1's requirement on z. x.1 was added as a root in the previous step,
   114# so the upgraded x.2-pre is retained as a root.
   115#
   116# On the third iteration, it adds z.1 as a root, which upgrades x and y.
   117# x and y were already roots (from the previous steps), so their upgraded versions
   118# are retained (not dropped) and the iteration stops.
   119#
   120# At that point, we have z.1 as a root providing package z,
   121# and w, x, and y have all been upgraded to no longer provide any packages.
   122# So only z is retained as a new root.
   123#
   124# (From the above, we can see that in a lazy module we still cycle through the
   125# same possible root states, but in a different order from the eager case.)
   126#
   127# TODO(bcmills): if we retained the upgrades on w, x, and y (since they are
   128# lexical prefixes for unresolved packages w, x, and y, respectively), then 'go
   129# mod tidy -e' itself would become stable and no longer cycle through states.
   130
   131cp go.mod.orig go.mod
   132go mod edit -go=1.17 go.mod
   133cp go.mod go.mod.117
   134go mod edit -go=1.17 go.mod.tidye1
   135go mod edit -go=1.17 go.mod.tidye2
   136go mod edit -go=1.17 go.mod.tidye3
   137go mod edit -go=1.17 go.mod.postget
   138
   139go list -m all
   140
   141go mod tidy -e
   142cmp go.mod go.mod.tidye3
   143
   144go mod tidy -e
   145cmp go.mod go.mod.tidye2
   146
   147go mod tidy -e
   148cmp go.mod go.mod.tidye1
   149
   150go mod tidy -e
   151cmp go.mod go.mod.117
   152
   153
   154# As in the eager case, for the lazy module the fully-upgraded dependency graph
   155# becomes empty, and the empty graph is stable.
   156
   157go get example.net/w@v0.2.0-pre example.net/x@v0.2.0-pre example.net/y@v0.2.0-pre example.net/z@v0.2.0-pre
   158go mod tidy -e
   159cmp go.mod go.mod.postget
   160go mod tidy -e
   161cmp go.mod go.mod.postget
   162
   163
   164-- m.go --
   165package m
   166
   167import (
   168	_ "example.net/w"
   169	_ "example.net/x"
   170	_ "example.net/y"
   171	_ "example.net/z"
   172)
   173
   174-- go.mod --
   175module example.net/m
   176
   177go 1.16
   178
   179replace (
   180	example.net/w v0.1.0 => ./w1
   181	example.net/w v0.2.0-pre => ./w2-pre
   182	example.net/x v0.1.0 => ./x1
   183	example.net/x v0.2.0-pre => ./x2-pre
   184	example.net/y v0.1.0 => ./y1
   185	example.net/y v0.2.0-pre => ./y2-pre
   186	example.net/z v0.1.0 => ./z1
   187	example.net/z v0.2.0-pre => ./z2-pre
   188)
   189
   190require example.net/w v0.1.0
   191-- go.mod.tidye1 --
   192module example.net/m
   193
   194go 1.16
   195
   196replace (
   197	example.net/w v0.1.0 => ./w1
   198	example.net/w v0.2.0-pre => ./w2-pre
   199	example.net/x v0.1.0 => ./x1
   200	example.net/x v0.2.0-pre => ./x2-pre
   201	example.net/y v0.1.0 => ./y1
   202	example.net/y v0.2.0-pre => ./y2-pre
   203	example.net/z v0.1.0 => ./z1
   204	example.net/z v0.2.0-pre => ./z2-pre
   205)
   206
   207require example.net/x v0.1.0
   208-- go.mod.tidye2 --
   209module example.net/m
   210
   211go 1.16
   212
   213replace (
   214	example.net/w v0.1.0 => ./w1
   215	example.net/w v0.2.0-pre => ./w2-pre
   216	example.net/x v0.1.0 => ./x1
   217	example.net/x v0.2.0-pre => ./x2-pre
   218	example.net/y v0.1.0 => ./y1
   219	example.net/y v0.2.0-pre => ./y2-pre
   220	example.net/z v0.1.0 => ./z1
   221	example.net/z v0.2.0-pre => ./z2-pre
   222)
   223
   224require example.net/y v0.1.0
   225-- go.mod.tidye3 --
   226module example.net/m
   227
   228go 1.16
   229
   230replace (
   231	example.net/w v0.1.0 => ./w1
   232	example.net/w v0.2.0-pre => ./w2-pre
   233	example.net/x v0.1.0 => ./x1
   234	example.net/x v0.2.0-pre => ./x2-pre
   235	example.net/y v0.1.0 => ./y1
   236	example.net/y v0.2.0-pre => ./y2-pre
   237	example.net/z v0.1.0 => ./z1
   238	example.net/z v0.2.0-pre => ./z2-pre
   239)
   240
   241require example.net/z v0.1.0
   242-- go.mod.postget --
   243module example.net/m
   244
   245go 1.16
   246
   247replace (
   248	example.net/w v0.1.0 => ./w1
   249	example.net/w v0.2.0-pre => ./w2-pre
   250	example.net/x v0.1.0 => ./x1
   251	example.net/x v0.2.0-pre => ./x2-pre
   252	example.net/y v0.1.0 => ./y1
   253	example.net/y v0.2.0-pre => ./y2-pre
   254	example.net/z v0.1.0 => ./z1
   255	example.net/z v0.2.0-pre => ./z2-pre
   256)
   257-- w1/go.mod --
   258module example.net/w
   259
   260go 1.16
   261
   262require (
   263	example.net/y v0.2.0-pre
   264	example.net/z v0.2.0-pre
   265)
   266-- w1/w.go --
   267package w
   268-- w2-pre/go.mod --
   269module example.net/w
   270
   271go 1.16
   272-- w2-pre/README.txt --
   273Package w has been removed.
   274
   275-- x1/go.mod --
   276module example.net/x
   277
   278go 1.16
   279
   280require (
   281	example.net/z v0.2.0-pre
   282	example.net/w v0.2.0-pre
   283)
   284-- x1/x.go --
   285package x
   286-- x2-pre/go.mod --
   287module example.net/x
   288
   289go 1.16
   290-- x2-pre/README.txt --
   291Package x has been removed.
   292
   293-- y1/go.mod --
   294module example.net/y
   295
   296go 1.16
   297
   298require (
   299	example.net/w v0.2.0-pre
   300	example.net/x v0.2.0-pre
   301)
   302-- y1/y.go --
   303package y
   304
   305-- y2-pre/go.mod --
   306module example.net/y
   307
   308go 1.16
   309-- y2-pre/README.txt --
   310Package y has been removed.
   311
   312-- z1/go.mod --
   313module example.net/z
   314
   315go 1.16
   316
   317require (
   318	example.net/x v0.2.0-pre
   319	example.net/y v0.2.0-pre
   320)
   321-- z1/z.go --
   322package z
   323
   324-- z2-pre/go.mod --
   325module example.net/z
   326
   327go 1.16
   328-- z2-pre/README.txt --
   329Package z has been removed.

View as plain text