@@ -87,7 +87,24 @@ func (f *File) AddComment(text string) {
87
87
88
88
type VersionFixer func (path , version string ) (string , error )
89
89
90
+ // Parse parses the data, reported in errors as being from file,
91
+ // into a File struct. It applies fix, if non-nil, to canonicalize all module versions found.
90
92
func Parse (file string , data []byte , fix VersionFixer ) (* File , error ) {
93
+ return parseToFile (file , data , fix , true )
94
+ }
95
+
96
+ // ParseLax is like Parse but ignores unknown statements.
97
+ // It is used when parsing go.mod files other than the main module,
98
+ // under the theory that most statement types we add in the future will
99
+ // only apply in the main module, like exclude and replace,
100
+ // and so we get better gradual deployments if old go commands
101
+ // simply ignore those statements when found in go.mod files
102
+ // in dependencies.
103
+ func ParseLax (file string , data []byte , fix VersionFixer ) (* File , error ) {
104
+ return parseToFile (file , data , fix , false )
105
+ }
106
+
107
+ func parseToFile (file string , data []byte , fix VersionFixer , strict bool ) (* File , error ) {
91
108
fs , err := parse (file , data )
92
109
if err != nil {
93
110
return nil , err
@@ -100,20 +117,24 @@ func Parse(file string, data []byte, fix VersionFixer) (*File, error) {
100
117
for _ , x := range fs .Stmt {
101
118
switch x := x .(type ) {
102
119
case * Line :
103
- f .add (& errs , x , x .Token [0 ], x .Token [1 :], fix )
120
+ f .add (& errs , x , x .Token [0 ], x .Token [1 :], fix , strict )
104
121
105
122
case * LineBlock :
106
123
if len (x .Token ) > 1 {
107
- fmt .Fprintf (& errs , "%s:%d: unknown block type: %s\n " , file , x .Start .Line , strings .Join (x .Token , " " ))
124
+ if strict {
125
+ fmt .Fprintf (& errs , "%s:%d: unknown block type: %s\n " , file , x .Start .Line , strings .Join (x .Token , " " ))
126
+ }
108
127
continue
109
128
}
110
129
switch x .Token [0 ] {
111
130
default :
112
- fmt .Fprintf (& errs , "%s:%d: unknown block type: %s\n " , file , x .Start .Line , strings .Join (x .Token , " " ))
131
+ if strict {
132
+ fmt .Fprintf (& errs , "%s:%d: unknown block type: %s\n " , file , x .Start .Line , strings .Join (x .Token , " " ))
133
+ }
113
134
continue
114
135
case "module" , "require" , "exclude" , "replace" :
115
136
for _ , l := range x .Line {
116
- f .add (& errs , l , x .Token [0 ], l .Token , fix )
137
+ f .add (& errs , l , x .Token [0 ], l .Token , fix , strict )
117
138
}
118
139
}
119
140
}
@@ -125,15 +146,20 @@ func Parse(file string, data []byte, fix VersionFixer) (*File, error) {
125
146
return f , nil
126
147
}
127
148
128
- func (f * File ) add (errs * bytes.Buffer , line * Line , verb string , args []string , fix VersionFixer ) {
129
- // TODO: We should pass in a flag saying whether this module is a dependency.
130
- // If so, we should ignore all unknown directives and not attempt to parse
149
+ func (f * File ) add (errs * bytes.Buffer , line * Line , verb string , args []string , fix VersionFixer , strict bool ) {
150
+ // If strict is false, this module is a dependency.
151
+ // We ignore all unknown directives and do not attempt to parse
131
152
// replace and exclude either. They don't matter, and it will work better for
132
- // forward compatibility if we can depend on modules that have local changes.
153
+ // forward compatibility if we can depend on modules that have unknown
154
+ // statements (presumed relevant only when acting as the main module).
155
+ if ! strict && verb != "module" && verb != "require" {
156
+ return
157
+ }
133
158
134
159
switch verb {
135
160
default :
136
161
fmt .Fprintf (errs , "%s:%d: unknown directive: %s\n " , f .Syntax .Name , line .Start .Line , verb )
162
+
137
163
case "module" :
138
164
if f .Module != nil {
139
165
fmt .Fprintf (errs , "%s:%d: repeated module statement\n " , f .Syntax .Name , line .Start .Line )
0 commit comments