flux diff artifact: Add support for the `--ignore-paths` flag.

Signed-off-by: Florian Forster <fforster@gitlab.com>
pull/4916/head
Florian Forster 4 months ago
parent 72d32a248b
commit 672b759f2e
No known key found for this signature in database

@ -33,6 +33,7 @@ import (
oci "github.com/fluxcd/pkg/oci/client"
"github.com/fluxcd/pkg/tar"
sourcev1 "github.com/fluxcd/source-controller/api/v1beta2"
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
"github.com/gonvenience/ytbx"
"github.com/google/shlex"
"github.com/hexops/gotextdiff"
@ -177,6 +178,16 @@ func diffArtifactCmdRun(cmd *cobra.Command, args []string) error {
return fmt.Errorf("%q and %q: %w", from, to, ErrDiffArtifactChanged)
}
func newMatcher(ignorePaths []string) gitignore.Matcher {
var patterns []gitignore.Pattern
for _, path := range ignorePaths {
patterns = append(patterns, gitignore.ParsePattern(path, nil))
}
return gitignore.NewMatcher(patterns)
}
func diffArtifact(ctx context.Context, client *oci.Client, from, to string, flags diffArtifactFlags) (string, error) {
fromDir, fromCleanup, err := loadArtifact(ctx, client, from)
if err != nil {
@ -190,7 +201,7 @@ func diffArtifact(ctx context.Context, client *oci.Client, from, to string, flag
}
defer toCleanup()
return flags.differ.Diff(ctx, fromDir, toDir)
return flags.differ.Diff(ctx, fromDir, toDir, flags.ignorePaths)
}
// loadArtifact ensures that the artifact is in a local directory that can be
@ -279,6 +290,7 @@ func extractTo(archivePath, destDir string) error {
if err != nil {
return err
}
defer archiveFH.Close()
if err := tar.Untar(archiveFH, destDir); err != nil {
return fmt.Errorf("Untar(%q, %q): %w", archivePath, destDir, err)
@ -303,21 +315,25 @@ func copyFile(from io.Reader, to string) error {
type differ interface {
// Diff compares the two local directories "to" and "from" and returns their differences, or an empty string if they are equal.
Diff(ctx context.Context, from, to string) (string, error)
Diff(ctx context.Context, from, to string, ignorePaths []string) (string, error)
}
type unifiedDiff struct{}
func (d unifiedDiff) Diff(_ context.Context, fromDir, toDir string) (string, error) {
fromFiles, err := filesInDir(fromDir)
func (d unifiedDiff) Diff(_ context.Context, fromDir, toDir string, ignorePaths []string) (string, error) {
matcher := newMatcher(ignorePaths)
fromFiles, err := filesInDir(fromDir, matcher)
if err != nil {
return "", err
}
fmt.Fprintf(os.Stderr, "fromFiles = %v\n", fromFiles)
toFiles, err := filesInDir(toDir)
toFiles, err := filesInDir(toDir, matcher)
if err != nil {
return "", err
}
fmt.Fprintf(os.Stderr, "toFiles = %v\n", toFiles)
allFiles := fromFiles.Union(toFiles)
@ -338,13 +354,19 @@ func (d unifiedDiff) Diff(_ context.Context, fromDir, toDir string) (string, err
func (d unifiedDiff) diffFiles(fromDir, toDir, relPath string) (string, error) {
fromPath := filepath.Join(fromDir, relPath)
fromData, err := d.readFile(fromPath)
if err != nil {
switch {
case errors.Is(err, fs.ErrNotExist):
return fmt.Sprintf("Only in %s: %s\n", toDir, relPath), nil
case err != nil:
return "", fmt.Errorf("readFile(%q): %w", fromPath, err)
}
toPath := filepath.Join(toDir, relPath)
toData, err := d.readFile(toPath)
if err != nil {
switch {
case errors.Is(err, fs.ErrNotExist):
return fmt.Sprintf("Only in %s: %s\n", fromDir, relPath), nil
case err != nil:
return "", fmt.Errorf("readFile(%q): %w", toPath, err)
}
@ -355,14 +377,18 @@ func (d unifiedDiff) diffFiles(fromDir, toDir, relPath string) (string, error) {
func (d unifiedDiff) readFile(path string) ([]byte, error) {
file, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("os.Open(%q): %w", path, err)
return nil, err
}
defer file.Close()
return io.ReadAll(file)
}
func filesInDir(root string) (stringset.Set, error) {
func splitPath(path string) []string {
return strings.Split(path, string([]rune{filepath.Separator}))
}
func filesInDir(root string, matcher gitignore.Matcher) (stringset.Set, error) {
var files stringset.Set
err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
@ -370,15 +396,22 @@ func filesInDir(root string) (stringset.Set, error) {
return err
}
if !d.Type().IsRegular() {
return nil
}
relPath, err := filepath.Rel(root, path)
if err != nil {
return fmt.Errorf("filepath.Rel(%q, %q): %w", root, path, err)
}
if matcher.Match(splitPath(relPath), d.IsDir()) {
if d.IsDir() {
return fs.SkipDir
}
return nil
}
if !d.Type().IsRegular() {
return nil
}
files.Add(relPath)
return nil
})
@ -395,7 +428,7 @@ type externalDiff struct{}
// externalDiffVar is the environment variable users can use to overwrite the external diff command.
const externalDiffVar = "FLUX_EXTERNAL_DIFF"
func (externalDiff) Diff(ctx context.Context, fromDir, toDir string) (string, error) {
func (externalDiff) Diff(ctx context.Context, fromDir, toDir string, ignorePaths []string) (string, error) {
cmdline := os.Getenv(externalDiffVar)
if cmdline == "" {
return "", fmt.Errorf("the required %q environment variable is unset", externalDiffVar)
@ -409,6 +442,10 @@ func (externalDiff) Diff(ctx context.Context, fromDir, toDir string) (string, er
var executable string
executable, args = args[0], args[1:]
for _, path := range ignorePaths {
args = append(args, "--exclude", path)
}
args = append(args, fromDir, toDir)
cmd := exec.CommandContext(ctx, executable, args...)
@ -435,7 +472,7 @@ type dyffBuiltin struct {
opts []dyff.CompareOption
}
func (d dyffBuiltin) Diff(ctx context.Context, fromDir, toDir string) (string, error) {
func (d dyffBuiltin) Diff(ctx context.Context, fromDir, toDir string, _ []string) (string, error) {
fromFile, err := ytbx.LoadDirectory(fromDir)
if err != nil {
return "", fmt.Errorf("ytbx.LoadDirectory(%q): %w", fromDir, err)

Loading…
Cancel
Save