2024-04-18 15:13:16 +00:00
|
|
|
package validate
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
2024-07-31 13:42:23 +00:00
|
|
|
"strings"
|
2024-04-18 15:13:16 +00:00
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/databricks/cli/bundle"
|
|
|
|
"github.com/databricks/cli/libs/diag"
|
2024-07-23 17:20:11 +00:00
|
|
|
"github.com/databricks/cli/libs/dyn"
|
2024-04-18 15:13:16 +00:00
|
|
|
"github.com/databricks/cli/libs/fileset"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
)
|
|
|
|
|
|
|
|
func ValidateSyncPatterns() bundle.ReadOnlyMutator {
|
|
|
|
return &validateSyncPatterns{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type validateSyncPatterns struct {
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *validateSyncPatterns) Name() string {
|
|
|
|
return "validate:validate_sync_patterns"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *validateSyncPatterns) Apply(ctx context.Context, rb bundle.ReadOnlyBundle) diag.Diagnostics {
|
|
|
|
s := rb.Config().Sync
|
|
|
|
if len(s.Exclude) == 0 && len(s.Include) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
diags, err := checkPatterns(s.Exclude, "sync.exclude", rb)
|
|
|
|
if err != nil {
|
|
|
|
return diag.FromErr(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
includeDiags, err := checkPatterns(s.Include, "sync.include", rb)
|
|
|
|
if err != nil {
|
|
|
|
return diag.FromErr(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return diags.Extend(includeDiags)
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkPatterns(patterns []string, path string, rb bundle.ReadOnlyBundle) (diag.Diagnostics, error) {
|
|
|
|
var mu sync.Mutex
|
|
|
|
var errs errgroup.Group
|
|
|
|
var diags diag.Diagnostics
|
|
|
|
|
|
|
|
for i, pattern := range patterns {
|
|
|
|
index := i
|
2024-07-31 13:42:23 +00:00
|
|
|
fullPattern := pattern
|
|
|
|
// If the pattern is negated, strip the negation prefix
|
|
|
|
// and check if the pattern matches any files.
|
|
|
|
// Negation in gitignore syntax means "don't look at this path'
|
|
|
|
// So if p matches nothing it's useless negation, but if there are matches,
|
|
|
|
// it means: do not include these files into result set
|
|
|
|
p := strings.TrimPrefix(fullPattern, "!")
|
2024-04-18 15:13:16 +00:00
|
|
|
errs.Go(func() error {
|
2024-07-03 10:13:22 +00:00
|
|
|
fs, err := fileset.NewGlobSet(rb.BundleRoot(), []string{p})
|
2024-04-18 15:13:16 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
all, err := fs.All()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(all) == 0 {
|
|
|
|
loc := location{path: fmt.Sprintf("%s[%d]", path, index), rb: rb}
|
|
|
|
mu.Lock()
|
|
|
|
diags = diags.Append(diag.Diagnostic{
|
2024-07-23 17:20:11 +00:00
|
|
|
Severity: diag.Warning,
|
2024-07-31 13:42:23 +00:00
|
|
|
Summary: fmt.Sprintf("Pattern %s does not match any files", fullPattern),
|
2024-07-23 17:20:11 +00:00
|
|
|
Locations: []dyn.Location{loc.Location()},
|
2024-07-25 15:16:27 +00:00
|
|
|
Paths: []dyn.Path{loc.Path()},
|
2024-04-18 15:13:16 +00:00
|
|
|
})
|
|
|
|
mu.Unlock()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return diags, errs.Wait()
|
|
|
|
}
|