Skip to content

Commit

Permalink
Allow checking path conflicts from a child AST node
Browse files Browse the repository at this point in the history
  • Loading branch information
sqyang94 committed Oct 30, 2024
1 parent 6af5e79 commit 1b59732
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 3 deletions.
9 changes: 9 additions & 0 deletions ast/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ type Compiler struct {
maxErrs int
sorted []string // list of sorted module names
pathExists func([]string) (bool, error)
pathConflictCheckRoots []string
after map[string][]CompilerStageDefinition
metrics metrics.Metrics
capabilities *Capabilities // user-supplied capabilities
Expand Down Expand Up @@ -383,6 +384,14 @@ func (c *Compiler) WithPathConflictsCheck(fn func([]string) (bool, error)) *Comp
return c
}

// WithPathConflictsCheckRoot enables checking path conflicts from the specified root instead
// of the top root node. This would enable optimizting path conflict checks during bundle
// activation if a bundle already defines its own root paths.
func (c *Compiler) WithPathConflictsCheckRoot(rootPaths []string) *Compiler {
c.pathConflictCheckRoots = rootPaths
return c
}

// WithStageAfter registers a stage to run during compilation after
// the named stage.
func (c *Compiler) WithStageAfter(after string, stage CompilerStageDefinition) *Compiler {
Expand Down
5 changes: 4 additions & 1 deletion ast/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,9 @@ bar.baz contains "quz" if true`,
"mod8.rego": `package badrules.complete_partial
p := 1
p[r] := 2 if { r := "foo" }`,

"mod9.rego": `package anotherbadrules.dataoverlap
p { true }`,
})

c.WithPathConflictsCheck(func(path []string) (bool, error) {
Expand All @@ -1963,7 +1966,7 @@ p[r] := 2 if { r := "foo" }`,
return false, fmt.Errorf("unexpected error")
}
return false, nil
})
}).WithPathConflictsCheckRoot([]string{"badrules"})

compileStages(c, c.checkRuleConflicts)

Expand Down
32 changes: 30 additions & 2 deletions ast/conflicts.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,36 @@ func CheckPathConflicts(c *Compiler, exists func([]string) (bool, error)) Errors
return nil
}

for _, node := range root.Children {
errs = append(errs, checkDocumentConflicts(node, exists, nil)...)
if len(c.pathConflictCheckRoots) == 0 {
for _, child := range root.Children {
errs = append(errs, checkDocumentConflicts(child, exists, nil)...)
}
return errs
}

for _, rootPath := range c.pathConflictCheckRoots {
// traverse AST from `path` to go to the new root
paths := strings.Split(rootPath, "/")
node := root
nodeNotFound := false
for _, key := range paths {
child := node.Child(String(key))
if child == nil {
nodeNotFound = true
break
}
node = child
}

if nodeNotFound {
// could not find the node from the AST (e.g. `path` is from a data file)
// then no conflict is possible
continue
}

for _, child := range node.Children {
errs = append(errs, checkDocumentConflicts(child, exists, paths)...)
}
}

return errs
Expand Down
4 changes: 4 additions & 0 deletions plugins/bundle/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,10 @@ func (p *Plugin) activate(ctx context.Context, name string, b *bundle.Bundle, is
compiler = compiler.WithPathConflictsCheck(storage.NonEmpty(ctx, p.manager.Store, txn)).
WithEnablePrintStatements(p.manager.EnablePrintStatements())

if b.Manifest.Roots != nil {
compiler = compiler.WithPathConflictsCheckRoot(*b.Manifest.Roots)
}

var activateErr error

opts := &bundle.ActivateOpts{
Expand Down

0 comments on commit 1b59732

Please sign in to comment.