@@ -58,13 +58,6 @@ type Go struct {
5858 Syntax * Line
5959}
6060
61- // A Require is a single require statement.
62- type Require struct {
63- Mod module.Version
64- Indirect bool // has "// indirect" comment
65- Syntax * Line
66- }
67-
6861// An Exclude is a single exclude statement.
6962type Exclude struct {
7063 Mod module.Version
@@ -93,6 +86,93 @@ type VersionInterval struct {
9386 Low , High string
9487}
9588
89+ // A Require is a single require statement.
90+ type Require struct {
91+ Mod module.Version
92+ Indirect bool // has "// indirect" comment
93+ Syntax * Line
94+ }
95+
96+ func (r * Require ) markRemoved () {
97+ r .Syntax .markRemoved ()
98+ * r = Require {}
99+ }
100+
101+ func (r * Require ) setVersion (v string ) {
102+ r .Mod .Version = v
103+
104+ if line := r .Syntax ; len (line .Token ) > 0 {
105+ if line .InBlock {
106+ // If the line is preceded by an empty line, remove it; see
107+ // https://golang.org/issue/33779.
108+ if len (line .Comments .Before ) == 1 && len (line .Comments .Before [0 ].Token ) == 0 {
109+ line .Comments .Before = line .Comments .Before [:0 ]
110+ }
111+ if len (line .Token ) >= 2 { // example.com v1.2.3
112+ line .Token [1 ] = v
113+ }
114+ } else {
115+ if len (line .Token ) >= 3 { // require example.com v1.2.3
116+ line .Token [2 ] = v
117+ }
118+ }
119+ }
120+ }
121+
122+ // setIndirect sets line to have (or not have) a "// indirect" comment.
123+ func (r * Require ) setIndirect (indirect bool ) {
124+ r .Indirect = indirect
125+ line := r .Syntax
126+ if isIndirect (line ) == indirect {
127+ return
128+ }
129+ if indirect {
130+ // Adding comment.
131+ if len (line .Suffix ) == 0 {
132+ // New comment.
133+ line .Suffix = []Comment {{Token : "// indirect" , Suffix : true }}
134+ return
135+ }
136+
137+ com := & line .Suffix [0 ]
138+ text := strings .TrimSpace (strings .TrimPrefix (com .Token , string (slashSlash )))
139+ if text == "" {
140+ // Empty comment.
141+ com .Token = "// indirect"
142+ return
143+ }
144+
145+ // Insert at beginning of existing comment.
146+ com .Token = "// indirect; " + text
147+ return
148+ }
149+
150+ // Removing comment.
151+ f := strings .TrimSpace (strings .TrimPrefix (line .Suffix [0 ].Token , string (slashSlash )))
152+ if f == "indirect" {
153+ // Remove whole comment.
154+ line .Suffix = nil
155+ return
156+ }
157+
158+ // Remove comment prefix.
159+ com := & line .Suffix [0 ]
160+ i := strings .Index (com .Token , "indirect;" )
161+ com .Token = "//" + com .Token [i + len ("indirect;" ):]
162+ }
163+
164+ // isIndirect reports whether line has a "// indirect" comment,
165+ // meaning it is in go.mod only for its effect on indirect dependencies,
166+ // so that it can be dropped entirely once the effective version of the
167+ // indirect dependency reaches the given minimum version.
168+ func isIndirect (line * Line ) bool {
169+ if len (line .Suffix ) == 0 {
170+ return false
171+ }
172+ f := strings .Fields (strings .TrimPrefix (line .Suffix [0 ].Token , string (slashSlash )))
173+ return (len (f ) == 1 && f [0 ] == "indirect" || len (f ) > 1 && f [0 ] == "indirect;" )
174+ }
175+
96176func (f * File ) AddModuleStmt (path string ) error {
97177 if f .Syntax == nil {
98178 f .Syntax = new (FileSyntax )
@@ -476,58 +556,6 @@ func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) {
476556 }
477557}
478558
479- // isIndirect reports whether line has a "// indirect" comment,
480- // meaning it is in go.mod only for its effect on indirect dependencies,
481- // so that it can be dropped entirely once the effective version of the
482- // indirect dependency reaches the given minimum version.
483- func isIndirect (line * Line ) bool {
484- if len (line .Suffix ) == 0 {
485- return false
486- }
487- f := strings .Fields (strings .TrimPrefix (line .Suffix [0 ].Token , string (slashSlash )))
488- return (len (f ) == 1 && f [0 ] == "indirect" || len (f ) > 1 && f [0 ] == "indirect;" )
489- }
490-
491- // setIndirect sets line to have (or not have) a "// indirect" comment.
492- func setIndirect (line * Line , indirect bool ) {
493- if isIndirect (line ) == indirect {
494- return
495- }
496- if indirect {
497- // Adding comment.
498- if len (line .Suffix ) == 0 {
499- // New comment.
500- line .Suffix = []Comment {{Token : "// indirect" , Suffix : true }}
501- return
502- }
503-
504- com := & line .Suffix [0 ]
505- text := strings .TrimSpace (strings .TrimPrefix (com .Token , string (slashSlash )))
506- if text == "" {
507- // Empty comment.
508- com .Token = "// indirect"
509- return
510- }
511-
512- // Insert at beginning of existing comment.
513- com .Token = "// indirect; " + text
514- return
515- }
516-
517- // Removing comment.
518- f := strings .TrimSpace (strings .TrimPrefix (line .Suffix [0 ].Token , string (slashSlash )))
519- if f == "indirect" {
520- // Remove whole comment.
521- line .Suffix = nil
522- return
523- }
524-
525- // Remove comment prefix.
526- com := & line .Suffix [0 ]
527- i := strings .Index (com .Token , "indirect;" )
528- com .Token = "//" + com .Token [i + len ("indirect;" ):]
529- }
530-
531559// IsDirectoryPath reports whether the given path should be interpreted
532560// as a directory path. Just like on the go command line, relative paths
533561// and rooted paths are directory paths; the rest are module paths.
@@ -866,8 +894,12 @@ func (f *File) AddRequire(path, vers string) error {
866894// the last require block, regardless of any existing require lines for path.
867895func (f * File ) AddNewRequire (path , vers string , indirect bool ) {
868896 line := f .Syntax .addLine (nil , "require" , AutoQuote (path ), vers )
869- setIndirect (line , indirect )
870- f .Require = append (f .Require , & Require {module.Version {Path : path , Version : vers }, indirect , line })
897+ r := & Require {
898+ Mod : module.Version {Path : path , Version : vers },
899+ Syntax : line ,
900+ }
901+ r .setIndirect (indirect )
902+ f .Require = append (f .Require , r )
871903}
872904
873905// SetRequire updates the requirements of f to contain exactly req, preserving
@@ -885,49 +917,28 @@ func (f *File) AddNewRequire(path, vers string, indirect bool) {
885917// If any existing requirements may be removed, the caller should call Cleanup
886918// after all edits are complete.
887919func (f * File ) SetRequire (req []* Require ) {
888- need := make (map [string ]string )
889- indirect := make (map [string ]bool )
920+ type elem struct {
921+ version string
922+ indirect bool
923+ }
924+ need := make (map [string ]elem )
890925 for _ , r := range req {
891- if prev , dup := need [r .Mod .Path ]; dup && prev != r .Mod .Version {
892- panic (fmt .Errorf ("SetRequire called with conflicting versions for path %s (%s and %s)" , r .Mod .Path , prev , r .Mod .Version ))
926+ if prev , dup := need [r .Mod .Path ]; dup && prev . version != r .Mod .Version {
927+ panic (fmt .Errorf ("SetRequire called with conflicting versions for path %s (%s and %s)" , r .Mod .Path , prev . version , r .Mod .Version ))
893928 }
894- need [r .Mod .Path ] = r .Mod .Version
895- indirect [r .Mod .Path ] = r .Indirect
929+ need [r .Mod .Path ] = elem {r .Mod .Version , r .Indirect }
896930 }
897931
898932 // Update or delete the existing Require entries to preserve
899933 // only the first for each module path in req.
900934 for _ , r := range f .Require {
901- v , ok := need [r .Mod .Path ]
902- if ! ok {
903- // This line is redundant or its path is no longer required at all.
904- // Mark the requirement for deletion in Cleanup.
905- r .Syntax .markRemoved ()
906- * r = Require {}
907- }
908-
909- r .Mod .Version = v
910- r .Indirect = indirect [r .Mod .Path ]
911-
912- if line := r .Syntax ; line != nil && len (line .Token ) > 0 {
913- if line .InBlock {
914- // If the line is preceded by an empty line, remove it; see
915- // https://golang.org/issue/33779.
916- if len (line .Comments .Before ) == 1 && len (line .Comments .Before [0 ].Token ) == 0 {
917- line .Comments .Before = line .Comments .Before [:0 ]
918- }
919- if len (line .Token ) >= 2 { // example.com v1.2.3
920- line .Token [1 ] = v
921- }
922- } else {
923- if len (line .Token ) >= 3 { // require example.com v1.2.3
924- line .Token [2 ] = v
925- }
926- }
927-
928- setIndirect (line , r .Indirect )
935+ e , ok := need [r .Mod .Path ]
936+ if ok {
937+ r .setVersion (e .version )
938+ r .setIndirect (e .indirect )
939+ } else {
940+ r .markRemoved ()
929941 }
930-
931942 delete (need , r .Mod .Path )
932943 }
933944
@@ -936,8 +947,8 @@ func (f *File) SetRequire(req []*Require) {
936947 //
937948 // This step is nondeterministic, but the final result will be deterministic
938949 // because we will sort the block.
939- for path , vers := range need {
940- f .AddNewRequire (path , vers , indirect [ path ] )
950+ for path , e := range need {
951+ f .AddNewRequire (path , e . version , e . indirect )
941952 }
942953
943954 f .SortBlocks ()
0 commit comments