@@ -423,68 +423,12 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
423
423
}
424
424
425
425
case "replace" :
426
- arrow := 2
427
- if len (args ) >= 2 && args [1 ] == "=>" {
428
- arrow = 1
429
- }
430
- if len (args ) < arrow + 2 || len (args ) > arrow + 3 || args [arrow ] != "=>" {
431
- errorf ("usage: %s module/path [v1.2.3] => other/module v1.4\n \t or %s module/path [v1.2.3] => ../local/directory" , verb , verb )
432
- return
433
- }
434
- s , err := parseString (& args [0 ])
435
- if err != nil {
436
- errorf ("invalid quoted string: %v" , err )
437
- return
438
- }
439
- pathMajor , err := modulePathMajor (s )
440
- if err != nil {
441
- wrapModPathError (s , err )
442
- return
443
- }
444
- var v string
445
- if arrow == 2 {
446
- v , err = parseVersion (verb , s , & args [1 ], fix )
447
- if err != nil {
448
- wrapError (err )
449
- return
450
- }
451
- if err := module .CheckPathMajor (v , pathMajor ); err != nil {
452
- wrapModPathError (s , err )
453
- return
454
- }
455
- }
456
- ns , err := parseString (& args [arrow + 1 ])
457
- if err != nil {
458
- errorf ("invalid quoted string: %v" , err )
426
+ replace , wrappederr := parseReplace (f .Syntax .Name , line , verb , args , fix )
427
+ if wrappederr != nil {
428
+ * errs = append (* errs , * wrappederr )
459
429
return
460
430
}
461
- nv := ""
462
- if len (args ) == arrow + 2 {
463
- if ! IsDirectoryPath (ns ) {
464
- errorf ("replacement module without version must be directory path (rooted or starting with ./ or ../)" )
465
- return
466
- }
467
- if filepath .Separator == '/' && strings .Contains (ns , `\` ) {
468
- errorf ("replacement directory appears to be Windows path (on a non-windows system)" )
469
- return
470
- }
471
- }
472
- if len (args ) == arrow + 3 {
473
- nv , err = parseVersion (verb , ns , & args [arrow + 2 ], fix )
474
- if err != nil {
475
- wrapError (err )
476
- return
477
- }
478
- if IsDirectoryPath (ns ) {
479
- errorf ("replacement module directory path %q cannot have version" , ns )
480
- return
481
- }
482
- }
483
- f .Replace = append (f .Replace , & Replace {
484
- Old : module.Version {Path : s , Version : v },
485
- New : module.Version {Path : ns , Version : nv },
486
- Syntax : line ,
487
- })
431
+ f .Replace = append (f .Replace , replace )
488
432
489
433
case "retract" :
490
434
rationale := parseDirectiveComment (block , line )
@@ -515,6 +459,83 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
515
459
}
516
460
}
517
461
462
+ func parseReplace (filename string , line * Line , verb string , args []string , fix VersionFixer ) (* Replace , * Error ) {
463
+ wrapModPathError := func (modPath string , err error ) * Error {
464
+ return & Error {
465
+ Filename : filename ,
466
+ Pos : line .Start ,
467
+ ModPath : modPath ,
468
+ Verb : verb ,
469
+ Err : err ,
470
+ }
471
+ }
472
+ wrapError := func (err error ) * Error {
473
+ return & Error {
474
+ Filename : filename ,
475
+ Pos : line .Start ,
476
+ Err : err ,
477
+ }
478
+ }
479
+ errorf := func (format string , args ... interface {}) * Error {
480
+ return wrapError (fmt .Errorf (format , args ... ))
481
+ }
482
+
483
+ arrow := 2
484
+ if len (args ) >= 2 && args [1 ] == "=>" {
485
+ arrow = 1
486
+ }
487
+ if len (args ) < arrow + 2 || len (args ) > arrow + 3 || args [arrow ] != "=>" {
488
+ return nil , errorf ("usage: %s module/path [v1.2.3] => other/module v1.4\n \t or %s module/path [v1.2.3] => ../local/directory" , verb , verb )
489
+ }
490
+ s , err := parseString (& args [0 ])
491
+ if err != nil {
492
+ return nil , errorf ("invalid quoted string: %v" , err )
493
+ }
494
+ pathMajor , err := modulePathMajor (s )
495
+ if err != nil {
496
+ return nil , wrapModPathError (s , err )
497
+
498
+ }
499
+ var v string
500
+ if arrow == 2 {
501
+ v , err = parseVersion (verb , s , & args [1 ], fix )
502
+ if err != nil {
503
+ return nil , wrapError (err )
504
+ }
505
+ if err := module .CheckPathMajor (v , pathMajor ); err != nil {
506
+ return nil , wrapModPathError (s , err )
507
+ }
508
+ }
509
+ ns , err := parseString (& args [arrow + 1 ])
510
+ if err != nil {
511
+ return nil , errorf ("invalid quoted string: %v" , err )
512
+ }
513
+ nv := ""
514
+ if len (args ) == arrow + 2 {
515
+ if ! IsDirectoryPath (ns ) {
516
+ return nil , errorf ("replacement module without version must be directory path (rooted or starting with ./ or ../)" )
517
+ }
518
+ if filepath .Separator == '/' && strings .Contains (ns , `\` ) {
519
+ return nil , errorf ("replacement directory appears to be Windows path (on a non-windows system)" )
520
+ }
521
+ }
522
+ if len (args ) == arrow + 3 {
523
+ nv , err = parseVersion (verb , ns , & args [arrow + 2 ], fix )
524
+ if err != nil {
525
+ return nil , wrapError (err )
526
+ }
527
+ if IsDirectoryPath (ns ) {
528
+ return nil , errorf ("replacement module directory path %q cannot have version" , ns )
529
+
530
+ }
531
+ }
532
+ return & Replace {
533
+ Old : module.Version {Path : s , Version : v },
534
+ New : module.Version {Path : ns , Version : nv },
535
+ Syntax : line ,
536
+ }, nil
537
+ }
538
+
518
539
// fixRetract applies fix to each retract directive in f, appending any errors
519
540
// to errs.
520
541
//
@@ -556,6 +577,63 @@ func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) {
556
577
}
557
578
}
558
579
580
+ func (f * WorkFile ) add (errs * ErrorList , line * Line , verb string , args []string , fix VersionFixer ) {
581
+ wrapError := func (err error ) {
582
+ * errs = append (* errs , Error {
583
+ Filename : f .Syntax .Name ,
584
+ Pos : line .Start ,
585
+ Err : err ,
586
+ })
587
+ }
588
+ errorf := func (format string , args ... interface {}) {
589
+ wrapError (fmt .Errorf (format , args ... ))
590
+ }
591
+
592
+ switch verb {
593
+ default :
594
+ errorf ("unknown directive: %s" , verb )
595
+
596
+ case "go" :
597
+ if f .Go != nil {
598
+ errorf ("repeated go statement" )
599
+ return
600
+ }
601
+ if len (args ) != 1 {
602
+ errorf ("go directive expects exactly one argument" )
603
+ return
604
+ } else if ! GoVersionRE .MatchString (args [0 ]) {
605
+ errorf ("invalid go version '%s': must match format 1.23" , args [0 ])
606
+ return
607
+ }
608
+
609
+ f .Go = & Go {Syntax : line }
610
+ f .Go .Version = args [0 ]
611
+
612
+ case "directory" :
613
+ if len (args ) != 1 {
614
+ errorf ("usage: %s local/dir" , verb )
615
+ return
616
+ }
617
+ s , err := parseString (& args [0 ])
618
+ if err != nil {
619
+ errorf ("invalid quoted string: %v" , err )
620
+ return
621
+ }
622
+ f .Directory = append (f .Directory , & Directory {
623
+ Path : s ,
624
+ Syntax : line ,
625
+ })
626
+
627
+ case "replace" :
628
+ replace , wrappederr := parseReplace (f .Syntax .Name , line , verb , args , fix )
629
+ if wrappederr != nil {
630
+ * errs = append (* errs , * wrappederr )
631
+ return
632
+ }
633
+ f .Replace = append (f .Replace , replace )
634
+ }
635
+ }
636
+
559
637
// IsDirectoryPath reports whether the given path should be interpreted
560
638
// as a directory path. Just like on the go command line, relative paths
561
639
// and rooted paths are directory paths; the rest are module paths.
@@ -1165,6 +1243,10 @@ func (f *File) DropExclude(path, vers string) error {
1165
1243
}
1166
1244
1167
1245
func (f * File ) AddReplace (oldPath , oldVers , newPath , newVers string ) error {
1246
+ return addReplace (f .Syntax , & f .Replace , oldPath , oldVers , newPath , newVers )
1247
+ }
1248
+
1249
+ func addReplace (syntax * FileSyntax , replace * []* Replace , oldPath , oldVers , newPath , newVers string ) error {
1168
1250
need := true
1169
1251
old := module.Version {Path : oldPath , Version : oldVers }
1170
1252
new := module.Version {Path : newPath , Version : newVers }
@@ -1178,12 +1260,12 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
1178
1260
}
1179
1261
1180
1262
var hint * Line
1181
- for _ , r := range f . Replace {
1263
+ for _ , r := range * replace {
1182
1264
if r .Old .Path == oldPath && (oldVers == "" || r .Old .Version == oldVers ) {
1183
1265
if need {
1184
1266
// Found replacement for old; update to use new.
1185
1267
r .New = new
1186
- f . Syntax .updateLine (r .Syntax , tokens ... )
1268
+ syntax .updateLine (r .Syntax , tokens ... )
1187
1269
need = false
1188
1270
continue
1189
1271
}
@@ -1196,7 +1278,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
1196
1278
}
1197
1279
}
1198
1280
if need {
1199
- f . Replace = append (f . Replace , & Replace {Old : old , New : new , Syntax : f . Syntax .addLine (hint , tokens ... )})
1281
+ * replace = append (* replace , & Replace {Old : old , New : new , Syntax : syntax .addLine (hint , tokens ... )})
1200
1282
}
1201
1283
return nil
1202
1284
}
@@ -1282,49 +1364,55 @@ func (f *File) SortBlocks() {
1282
1364
// retract directives are not de-duplicated since comments are
1283
1365
// meaningful, and versions may be retracted multiple times.
1284
1366
func (f * File ) removeDups () {
1367
+ removeDups (f .Syntax , & f .Exclude , & f .Replace )
1368
+ }
1369
+
1370
+ func removeDups (syntax * FileSyntax , exclude * []* Exclude , replace * []* Replace ) {
1285
1371
kill := make (map [* Line ]bool )
1286
1372
1287
1373
// Remove duplicate excludes.
1288
- haveExclude := make (map [module.Version ]bool )
1289
- for _ , x := range f .Exclude {
1290
- if haveExclude [x .Mod ] {
1291
- kill [x .Syntax ] = true
1292
- continue
1374
+ if exclude != nil {
1375
+ haveExclude := make (map [module.Version ]bool )
1376
+ for _ , x := range * exclude {
1377
+ if haveExclude [x .Mod ] {
1378
+ kill [x .Syntax ] = true
1379
+ continue
1380
+ }
1381
+ haveExclude [x .Mod ] = true
1293
1382
}
1294
- haveExclude [x .Mod ] = true
1295
- }
1296
- var excl []* Exclude
1297
- for _ , x := range f .Exclude {
1298
- if ! kill [x .Syntax ] {
1299
- excl = append (excl , x )
1383
+ var excl []* Exclude
1384
+ for _ , x := range * exclude {
1385
+ if ! kill [x .Syntax ] {
1386
+ excl = append (excl , x )
1387
+ }
1300
1388
}
1389
+ * exclude = excl
1301
1390
}
1302
- f .Exclude = excl
1303
1391
1304
1392
// Remove duplicate replacements.
1305
1393
// Later replacements take priority over earlier ones.
1306
1394
haveReplace := make (map [module.Version ]bool )
1307
- for i := len (f . Replace ) - 1 ; i >= 0 ; i -- {
1308
- x := f . Replace [i ]
1395
+ for i := len (* replace ) - 1 ; i >= 0 ; i -- {
1396
+ x := ( * replace ) [i ]
1309
1397
if haveReplace [x .Old ] {
1310
1398
kill [x .Syntax ] = true
1311
1399
continue
1312
1400
}
1313
1401
haveReplace [x .Old ] = true
1314
1402
}
1315
1403
var repl []* Replace
1316
- for _ , x := range f . Replace {
1404
+ for _ , x := range * replace {
1317
1405
if ! kill [x .Syntax ] {
1318
1406
repl = append (repl , x )
1319
1407
}
1320
1408
}
1321
- f . Replace = repl
1409
+ * replace = repl
1322
1410
1323
1411
// Duplicate require and retract directives are not removed.
1324
1412
1325
1413
// Drop killed statements from the syntax tree.
1326
1414
var stmts []Expr
1327
- for _ , stmt := range f . Syntax .Stmt {
1415
+ for _ , stmt := range syntax .Stmt {
1328
1416
switch stmt := stmt .(type ) {
1329
1417
case * Line :
1330
1418
if kill [stmt ] {
@@ -1344,7 +1432,7 @@ func (f *File) removeDups() {
1344
1432
}
1345
1433
stmts = append (stmts , stmt )
1346
1434
}
1347
- f . Syntax .Stmt = stmts
1435
+ syntax .Stmt = stmts
1348
1436
}
1349
1437
1350
1438
// lineLess returns whether li should be sorted before lj. It sorts
0 commit comments