Files
coder/agent/agentcontainers/ignore/dir.go
T
Spike Curtis 49b34a716a fix: fix slog to always use array of Fields (#21426)
Upgrades to slog v3 which includes a small, but backward incompatible API change to the acceptible call arguments when logging. This change allows us to verify via compile time type checking that arguments are correct and won't cause a panic, as was possible in slog v1, which this replaces (v2 was tagged but never used in coder/coder).

It also updates dependencies that also use slog and were updated.

I've left the `aibridge` dependency as a commit SHA, under the assumption that the team there (cc @pawbana @dannykopping ) will tag and update the dependency soon and on their own schedule.

Other dependencies, I pushed new tags.
2026-01-08 10:29:41 +04:00

125 lines
2.7 KiB
Go

package ignore
import (
"bytes"
"context"
"errors"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/go-git/go-git/v5/plumbing/format/config"
"github.com/go-git/go-git/v5/plumbing/format/gitignore"
"github.com/spf13/afero"
"golang.org/x/xerrors"
"cdr.dev/slog/v3"
)
const (
gitconfigFile = ".gitconfig"
gitignoreFile = ".gitignore"
gitInfoExcludeFile = ".git/info/exclude"
)
func FilePathToParts(path string) []string {
components := []string{}
if path == "" {
return components
}
for segment := range strings.SplitSeq(filepath.Clean(path), string(filepath.Separator)) {
if segment != "" {
components = append(components, segment)
}
}
return components
}
func readIgnoreFile(fileSystem afero.Fs, path, ignore string) ([]gitignore.Pattern, error) {
var ps []gitignore.Pattern
data, err := afero.ReadFile(fileSystem, filepath.Join(path, ignore))
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
}
for s := range strings.SplitSeq(string(data), "\n") {
if !strings.HasPrefix(s, "#") && len(strings.TrimSpace(s)) > 0 {
ps = append(ps, gitignore.ParsePattern(s, FilePathToParts(path)))
}
}
return ps, nil
}
func ReadPatterns(ctx context.Context, logger slog.Logger, fileSystem afero.Fs, path string) ([]gitignore.Pattern, error) {
var ps []gitignore.Pattern
subPs, err := readIgnoreFile(fileSystem, path, gitInfoExcludeFile)
if err != nil {
return nil, err
}
ps = append(ps, subPs...)
if err := afero.Walk(fileSystem, path, func(path string, info fs.FileInfo, err error) error {
if err != nil {
logger.Error(ctx, "encountered error while walking for git ignore files",
slog.F("path", path),
slog.Error(err))
return nil
}
if !info.IsDir() {
return nil
}
subPs, err := readIgnoreFile(fileSystem, path, gitignoreFile)
if err != nil {
return err
}
ps = append(ps, subPs...)
return nil
}); err != nil {
return nil, err
}
return ps, nil
}
func loadPatterns(fileSystem afero.Fs, path string) ([]gitignore.Pattern, error) {
data, err := afero.ReadFile(fileSystem, path)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return nil, err
}
decoder := config.NewDecoder(bytes.NewBuffer(data))
conf := config.New()
if err := decoder.Decode(conf); err != nil {
return nil, xerrors.Errorf("decode config: %w", err)
}
excludes := conf.Section("core").Options.Get("excludesfile")
if excludes == "" {
return nil, nil
}
return readIgnoreFile(fileSystem, "", excludes)
}
func LoadGlobalPatterns(fileSystem afero.Fs) ([]gitignore.Pattern, error) {
home, err := os.UserHomeDir()
if err != nil {
return nil, err
}
return loadPatterns(fileSystem, filepath.Join(home, gitconfigFile))
}