this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

internal/buildattr: factor out from cue/load

This factors out the build attribute evaluation logic so that it
can be used from other places.

This does not change any behavior.

For #3180.

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: Id2a72d69695cb09118ead5c42fdb4c22feb66c76
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1197159
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+143 -103
+1 -1
cue/load/loader_common.go
··· 248 248 } 249 249 250 250 if !fp.c.AllCUEFiles { 251 - if err := shouldBuildFile(pf, fp.tagger); err != nil { 251 + if err := shouldBuildFile(pf, fp.tagger.tagIsSet); err != nil { 252 252 if !errors.Is(err, errExclude) { 253 253 fp.err = errors.Append(fp.err, err) 254 254 }
+2 -2
cue/load/search.go
··· 406 406 _err = err 407 407 return false 408 408 } 409 - if err := shouldBuildFile(f.Syntax, tg); err != nil { 409 + if err := shouldBuildFile(f.Syntax, tg.tagIsSet); err != nil { 410 410 // Later build logic should pick up and report the same error. 411 411 return true 412 412 } ··· 522 522 if err != nil { 523 523 return false 524 524 } 525 - if err := shouldBuildFile(f.Syntax, tg); err != nil { 525 + if err := shouldBuildFile(f.Syntax, tg.tagIsSet); err != nil { 526 526 // Later build logic should pick up and report the same error. 527 527 return true 528 528 }
+38 -100
cue/load/tags.go
··· 21 21 "os/user" 22 22 "runtime" 23 23 "strings" 24 + "sync" 24 25 "time" 25 26 26 27 "cuelang.org/go/cue" 27 28 "cuelang.org/go/cue/ast" 28 29 "cuelang.org/go/cue/build" 29 30 "cuelang.org/go/cue/errors" 30 - "cuelang.org/go/cue/parser" 31 31 "cuelang.org/go/cue/token" 32 32 "cuelang.org/go/internal" 33 + "cuelang.org/go/internal/buildattr" 33 34 "cuelang.org/go/internal/cli" 34 35 ) 35 36 36 37 type tagger struct { 37 - cfg *Config 38 + cfg *Config 39 + // tagMap holds true for all the tags in cfg.Tags that 40 + // are not associated with a value. 41 + tagMap map[string]bool 42 + // tags keeps a record of all the @tag attibutes found in files. 38 43 tags []*tag // tags found in files 39 - buildTags map[string]bool 40 44 replacements map[ast.Node]ast.Node 45 + 46 + // mu guards the usedTags map. 47 + mu sync.Mutex 48 + // usedTags keeps a record of all the tag attributes found in files. 49 + usedTags map[string]bool 41 50 } 42 51 43 52 func newTagger(c *Config) *tagger { 53 + tagMap := map[string]bool{} 54 + for _, t := range c.Tags { 55 + if !strings.ContainsRune(t, '=') { 56 + tagMap[t] = true 57 + } 58 + } 44 59 return &tagger{ 45 - cfg: c, 46 - buildTags: make(map[string]bool), 60 + cfg: c, 61 + tagMap: tagMap, 62 + usedTags: make(map[string]bool), 47 63 } 64 + } 65 + 66 + // tagIsSet reports whether the tag with the given key 67 + // is enabled. It also updates t.usedTags to 68 + // reflect that the tag has been seen. 69 + func (tg *tagger) tagIsSet(key string) bool { 70 + tg.mu.Lock() 71 + tg.usedTags[key] = true 72 + tg.mu.Unlock() 73 + return tg.tagMap[key] 48 74 } 49 75 50 76 // A TagVar represents an injection variable. ··· 266 292 // Parses command line args 267 293 for _, s := range tags { 268 294 p := strings.Index(s, "=") 269 - found := tg.buildTags[s] 295 + found := tg.usedTags[s] 270 296 if p > 0 { // key-value 271 297 for _, t := range tg.tags { 272 298 if t.key == s[:p] { ··· 327 353 return nil 328 354 } 329 355 330 - // shouldBuildFile determines whether a File should be included based on its 331 - // attributes. 332 - func shouldBuildFile(f *ast.File, tagger *tagger) errors.Error { 333 - tags := tagger.cfg.Tags 334 - 335 - a, errs := getBuildAttr(f) 336 - if errs != nil { 337 - return errs 338 - } 339 - if a == nil { 340 - return nil 341 - } 342 - 343 - _, body := a.Split() 344 - 345 - expr, err := parser.ParseExpr("", body) 356 + func shouldBuildFile(f *ast.File, tagIsSet func(key string) bool) errors.Error { 357 + ok, attr, err := buildattr.ShouldBuildFile(f, tagIsSet) 346 358 if err != nil { 347 - return errors.Promote(err, "") 359 + return err 348 360 } 349 - 350 - tagMap := map[string]bool{} 351 - for _, t := range tags { 352 - tagMap[t] = !strings.ContainsRune(t, '=') 353 - } 354 - 355 - c := checker{tags: tagMap, tagger: tagger} 356 - include := c.shouldInclude(expr) 357 - if c.err != nil { 358 - return c.err 359 - } 360 - if !include { 361 - return excludeError{errors.Newf(a.Pos(), "@if(%s) did not match", body)} 361 + if !ok { 362 + _, body := attr.Split() 363 + return excludeError{errors.Newf(attr.Pos(), "@if(%s) did not match", body)} 362 364 } 363 365 return nil 364 366 } 365 - 366 - func getBuildAttr(f *ast.File) (*ast.Attribute, errors.Error) { 367 - var a *ast.Attribute 368 - for _, d := range f.Decls { 369 - switch x := d.(type) { 370 - case *ast.Attribute: 371 - key, _ := x.Split() 372 - if key != "if" { 373 - continue 374 - } 375 - if a != nil { 376 - err := errors.Newf(d.Pos(), "multiple @if attributes") 377 - err = errors.Append(err, 378 - errors.Newf(a.Pos(), "previous declaration here")) 379 - return nil, err 380 - } 381 - a = x 382 - 383 - case *ast.Package: 384 - break 385 - } 386 - } 387 - return a, nil 388 - } 389 - 390 - type checker struct { 391 - tagger *tagger 392 - tags map[string]bool 393 - err errors.Error 394 - } 395 - 396 - func (c *checker) shouldInclude(expr ast.Expr) bool { 397 - switch x := expr.(type) { 398 - case *ast.Ident: 399 - c.tagger.buildTags[x.Name] = true 400 - return c.tags[x.Name] 401 - 402 - case *ast.BinaryExpr: 403 - switch x.Op { 404 - case token.LAND: 405 - return c.shouldInclude(x.X) && c.shouldInclude(x.Y) 406 - 407 - case token.LOR: 408 - return c.shouldInclude(x.X) || c.shouldInclude(x.Y) 409 - 410 - default: 411 - c.err = errors.Append(c.err, errors.Newf(token.NoPos, 412 - "invalid operator %v", x.Op)) 413 - return false 414 - } 415 - 416 - case *ast.UnaryExpr: 417 - if x.Op != token.NOT { 418 - c.err = errors.Append(c.err, errors.Newf(token.NoPos, 419 - "invalid operator %v", x.Op)) 420 - } 421 - return !c.shouldInclude(x.X) 422 - 423 - default: 424 - c.err = errors.Append(c.err, errors.Newf(token.NoPos, 425 - "invalid type %T in build attribute", expr)) 426 - return false 427 - } 428 - }
+102
internal/buildattr/buildattr.go
··· 1 + // Package buildattr implements support for interpreting the @if 2 + // build attributes in CUE files. 3 + package buildattr 4 + 5 + import ( 6 + "cuelang.org/go/cue/ast" 7 + "cuelang.org/go/cue/errors" 8 + "cuelang.org/go/cue/parser" 9 + "cuelang.org/go/cue/token" 10 + ) 11 + 12 + // ShouldBuildFile reports whether a File should be included based on its 13 + // attributes. It uses tagIsSet to determine whether a given attribute 14 + // key should be treated as set. 15 + // 16 + // It also returns the build attribute if one was found. 17 + func ShouldBuildFile(f *ast.File, tagIsSet func(key string) bool) (bool, *ast.Attribute, errors.Error) { 18 + a, err := getBuildAttr(f) 19 + if err != nil { 20 + return false, nil, err 21 + } 22 + if a == nil { 23 + return true, nil, nil 24 + } 25 + 26 + _, body := a.Split() 27 + 28 + expr, parseErr := parser.ParseExpr("", body) 29 + if parseErr != nil { 30 + return false, a, errors.Promote(parseErr, "") 31 + } 32 + 33 + include, err := shouldInclude(expr, tagIsSet) 34 + if err != nil { 35 + return false, a, err 36 + } 37 + return include, a, nil 38 + } 39 + 40 + func getBuildAttr(f *ast.File) (*ast.Attribute, errors.Error) { 41 + var a *ast.Attribute 42 + for _, d := range f.Decls { 43 + switch x := d.(type) { 44 + case *ast.Attribute: 45 + key, _ := x.Split() 46 + if key != "if" { 47 + continue 48 + } 49 + if a != nil { 50 + err := errors.Newf(d.Pos(), "multiple @if attributes") 51 + err = errors.Append(err, 52 + errors.Newf(a.Pos(), "previous declaration here")) 53 + return nil, err 54 + } 55 + a = x 56 + 57 + case *ast.Package: 58 + break 59 + } 60 + } 61 + return a, nil 62 + } 63 + 64 + func shouldInclude(expr ast.Expr, tagIsSet func(key string) bool) (bool, errors.Error) { 65 + switch x := expr.(type) { 66 + case *ast.Ident: 67 + return tagIsSet(x.Name), nil 68 + 69 + case *ast.BinaryExpr: 70 + switch x.Op { 71 + case token.LAND, token.LOR: 72 + a, err := shouldInclude(x.X, tagIsSet) 73 + if err != nil { 74 + return false, err 75 + } 76 + b, err := shouldInclude(x.Y, tagIsSet) 77 + if err != nil { 78 + return false, err 79 + } 80 + if x.Op == token.LAND { 81 + return a && b, nil 82 + } 83 + return a || b, nil 84 + 85 + default: 86 + return false, errors.Newf(token.NoPos, "invalid operator %v", x.Op) 87 + } 88 + 89 + case *ast.UnaryExpr: 90 + if x.Op != token.NOT { 91 + return false, errors.Newf(token.NoPos, "invalid operator %v", x.Op) 92 + } 93 + v, err := shouldInclude(x.X, tagIsSet) 94 + if err != nil { 95 + return false, err 96 + } 97 + return !v, nil 98 + 99 + default: 100 + return false, errors.Newf(token.NoPos, "invalid type %T in build attribute", expr) 101 + } 102 + }