From 13d15d6c9c14037141602a26284ef7c1edb7cb85 Mon Sep 17 00:00:00 2001 From: Tuan Anh Tran Date: Sat, 23 Dec 2023 18:23:03 +0700 Subject: [PATCH] feat: add a linter to check for dangling symlink Signed-off-by: Tuan Anh Tran --- pkg/linter/defaults/defaults.go | 1 + pkg/linter/linter.go | 54 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/pkg/linter/defaults/defaults.go b/pkg/linter/defaults/defaults.go index 55b7ec8b7..e4fee2ed2 100644 --- a/pkg/linter/defaults/defaults.go +++ b/pkg/linter/defaults/defaults.go @@ -34,6 +34,7 @@ var defaultLinters = []string{ "dev", "documentation", "empty", + "danglingsymlink", "opt", "object", "python/docs", diff --git a/pkg/linter/linter.go b/pkg/linter/linter.go index 412d286f4..9b51bd944 100644 --- a/pkg/linter/linter.go +++ b/pkg/linter/linter.go @@ -141,6 +141,12 @@ var postLinterMap = map[string]postLinter{ FailOnError: false, Explain: "Verify that this package is supposed to be empty; if it is, disable this linter; otherwise check the build", }, + "danglingsymlink": { + LinterFunc: danglingSymlinkLinter, + LinterClass: linter_defaults.LinterClassBuild | linter_defaults.LinterClassApk, + FailOnError: false, + Explain: "Verify that this package has no dangling symlink", + }, "python/docs": { LinterFunc: pythonDocsPostLinter, LinterClass: linter_defaults.LinterClassBuild | linter_defaults.LinterClassApk, @@ -644,3 +650,51 @@ func LintApk(ctx context.Context, path string, warn func(error), linters []strin return lctx.lintPackageFs(warn, linters, linter_defaults.LinterClassApk) } + +func danglingSymlinkLinter(lctx LinterContext, fsys fs.FS) error { + founddanglingsymlink := false + walkCb := func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if isIgnoredPath(path) { + return nil + } + + if d.IsDir() { + // Ignore directories + return nil + } + + if d.Type() == fs.ModeSymlink { + realpath, err := filepath.EvalSymlinks(path) + if err != nil { + return err + } + + f, err := lctx.fsys.Open(realpath) + if err != nil { + founddanglingsymlink = true + return fs.SkipAll + } + + defer f.Close() + + return nil + } + + return nil + } + + err := fs.WalkDir(fsys, ".", walkCb) + if err != nil { + return err + } + + if founddanglingsymlink { + return fmt.Errorf("found dangling symlink %w", err) + } + + return nil +}