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

     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 --- x
    10  #       |
    11  #       x_test --- y
    12  #
    13  # The module dependency graph of m is initially empty.
    14  # Modules x and y look like:
    15  #
    16  # x.1 (provides package x that imports y, but does not depend on module y)
    17  #
    18  # x.2-pre (no dependencies, but does not provide package x)
    19  #
    20  # y.1 (no dependencies, but provides package y)
    21  #
    22  # y.2 --- x.2-pre (provides package y)
    23  #
    24  #
    25  # When we resolve the missing import of y in x_test, we add y@latest — which is
    26  # y.2, not y.1 — as a new dependency. That upgrades to x to x.2-pre, which
    27  # removes package x (and also the need for module y). We can then safely remove
    28  # the dependency on module y, because nothing imports package y any more!
    29  #
    30  # We might be tempted to remove the dependency on module x for the same reason:
    31  # it no longer provides any imported package. However, that would cause 'go mod
    32  # tidy -e' to become unstable: with x.2-pre out of the way, we could once again
    33  # resolve the missing import of package x by re-adding x.1.
    34  
    35  cp go.mod go.mod.orig
    36  
    37  # 'go mod tidy' without -e should fail without modifying go.mod,
    38  # because it cannot resolve x and y simultaneously.
    39  ! go mod tidy
    40  
    41  cmp go.mod go.mod.orig
    42  
    43  stderr '^go: found example\.net/y in example\.net/y v0.2.0$'
    44  stderr '^go: finding module for package example\.net/x$'
    45  
    46  	# TODO: This error message should be clearer — it doesn't indicate why v0.2.0-pre is required.
    47  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$'
    48  
    49  
    50  # 'go mod tidy -e' should follow upgrades to try to resolve the modules that it
    51  # can, and then stop. When we resolve example.net/y, we upgrade to example.net/x
    52  # to v0.2.0-pre. At that version, package x no longer exists and no longer
    53  # imports package y, so the import of x should be left unsatisfied and the
    54  # existing dependency on example.net/x removed.
    55  #
    56  # TODO(bcmills): It would be ever better if we could keep the original
    57  # dependency on example.net/x v0.1.0, but I don't see a way to do that without
    58  # making the algorithm way too complicated. (We would have to detect that the
    59  # new dependency on example.net/y interferes with the package that caused us to
    60  # to add that dependency in the first place, and back out that part of the change
    61  # without also backing out any other needed changes.)
    62  
    63  go mod tidy -e
    64  cmp go.mod go.mod.tidye
    65  stderr '^go: found example\.net/y in example\.net/y v0.2.0$'
    66  
    67  	# TODO: This error message should be clearer — it doesn't indicate why v0.2.0-pre is required.
    68  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$'
    69  
    70  
    71  # Since we attempt to resolve the dependencies of package x whenever we add x itself,
    72  # this end state is stable.
    73  
    74  go mod tidy -e
    75  cmp go.mod go.mod.tidye
    76  
    77  
    78  # An explicit 'go get' with the correct versions should allow 'go mod tidy' to
    79  # succeed and remain stable. y.1 does not upgrade x, and can therefore be used
    80  # with it.
    81  
    82  go get example.net/x@v0.1.0 example.net/y@v0.1.0
    83  go mod tidy
    84  cmp go.mod go.mod.postget
    85  
    86  
    87  # The 'tidy' logic for a lazy main module is somewhat different from that for an
    88  # eager main module, but the overall behavior is the same.
    89  
    90  cp go.mod.orig go.mod
    91  go mod edit -go=1.17 go.mod
    92  go mod edit -go=1.17 go.mod.tidye
    93  
    94  go mod tidy -e
    95  cmp go.mod go.mod.tidye
    96  stderr '^go: found example\.net/y in example\.net/y v0.2.0$'
    97  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$'
    98  
    99  go get example.net/x@v0.1.0 example.net/y@v0.1.0
   100  go mod tidy
   101  cmp go.mod go.mod.postget-117
   102  
   103  
   104  -- go.mod --
   105  module example.net/m
   106  
   107  go 1.16
   108  
   109  replace (
   110  	example.net/x v0.1.0 => ./x1
   111  	example.net/x v0.2.0-pre => ./x2-pre
   112  	example.net/y v0.1.0 => ./y1
   113  	example.net/y v0.2.0 => ./y2
   114  )
   115  
   116  require (
   117  	example.net/x v0.1.0
   118  )
   119  -- go.mod.tidye --
   120  module example.net/m
   121  
   122  go 1.16
   123  
   124  replace (
   125  	example.net/x v0.1.0 => ./x1
   126  	example.net/x v0.2.0-pre => ./x2-pre
   127  	example.net/y v0.1.0 => ./y1
   128  	example.net/y v0.2.0 => ./y2
   129  )
   130  -- go.mod.postget --
   131  module example.net/m
   132  
   133  go 1.16
   134  
   135  replace (
   136  	example.net/x v0.1.0 => ./x1
   137  	example.net/x v0.2.0-pre => ./x2-pre
   138  	example.net/y v0.1.0 => ./y1
   139  	example.net/y v0.2.0 => ./y2
   140  )
   141  
   142  require (
   143  	example.net/x v0.1.0
   144  	example.net/y v0.1.0 // indirect
   145  )
   146  -- go.mod.postget-117 --
   147  module example.net/m
   148  
   149  go 1.17
   150  
   151  replace (
   152  	example.net/x v0.1.0 => ./x1
   153  	example.net/x v0.2.0-pre => ./x2-pre
   154  	example.net/y v0.1.0 => ./y1
   155  	example.net/y v0.2.0 => ./y2
   156  )
   157  
   158  require example.net/x v0.1.0
   159  
   160  require example.net/y v0.1.0 // indirect
   161  -- m.go --
   162  package m
   163  
   164  import _ "example.net/x"
   165  
   166  -- x1/go.mod --
   167  module example.net/x
   168  
   169  go 1.16
   170  -- x1/x.go --
   171  package x
   172  -- x1/x_test.go --
   173  package x
   174  
   175  import _ "example.net/y"
   176  
   177  -- x2-pre/go.mod --
   178  module example.net/x
   179  
   180  go 1.16
   181  -- x2-pre/README.txt --
   182  There is no package x here. Use example.com/x/subpkg instead.
   183  -- x2-pre/subpkg/subpkg.go --
   184  package subpkg  // import "example.net/x/subpkg"
   185  
   186  -- y1/go.mod --
   187  module example.net/y
   188  
   189  go 1.16
   190  -- y1/y.go --
   191  package y
   192  
   193  -- y2/go.mod --
   194  module example.net/y
   195  
   196  go 1.16
   197  
   198  require example.net/x v0.2.0-pre
   199  -- y2/y.go --
   200  package y
   201  
   202  import _ "example.net/x/subpkg"
   203  

View as plain text