From 4e3926d43b956ff69c8e6ef69ab43b398ee47730 Mon Sep 17 00:00:00 2001 From: Amy Boyd Date: Wed, 22 Jun 2016 23:09:59 +0100 Subject: [PATCH] Add source file finder. --- editorconfig/source_file_finder.go | 102 ++++++++++++++++++++++++ editorconfig/source_file_finder_test.go | 41 ++++++++++ 2 files changed, 143 insertions(+) create mode 100644 editorconfig/source_file_finder.go create mode 100644 editorconfig/source_file_finder_test.go diff --git a/editorconfig/source_file_finder.go b/editorconfig/source_file_finder.go new file mode 100644 index 0000000..090d192 --- /dev/null +++ b/editorconfig/source_file_finder.go @@ -0,0 +1,102 @@ +package editorconfig + +import ( + "bytes" + "github.com/codegangsta/cli" + "os" + "path/filepath" + "regexp" + "strings" +) + +var containsDotDirectoryRegex = regexp.MustCompile(`(^|/)\.[^/]+/`) + +var fileExtensions = GetSourceFileExtensions() + +var fileExtensionsRegex = CreateSourceFileExtensionRegex(fileExtensions) + +func GetSourceFileExtensions() []string { + var file, err = Asset("data/file-extensions.txt") + if err != nil { + ExitBecauseOfInternalError("Could not open list of file extensions") + } + + reader := bytes.NewBuffer(file) + exts := []string{} + + for { + ext, _ := reader.ReadBytes(' ') + if len(ext) == 0 { + break + } + ext = ext[0 : len(ext)-1] + exts = append(exts, string(ext)) + + // Skip the rest of the line (a description of what the file extension means). + reader.ReadBytes('\n') + } + + if len(exts) == 0 { + ExitBecauseOfInternalError("No file extensions found") + } + + return exts +} + +func CreateSourceFileExtensionRegex(fileExtensions []string) *regexp.Regexp { + for i, e := range fileExtensions { + fileExtensions[i] = regexp.QuoteMeta(e) + } + + r, err := regexp.Compile("\\.(" + strings.Join(fileExtensions, "|") + ")$") + if err != nil { + ExitBecauseOfInternalError("Could not compile regex: " + err.Error()) + } + + return r +} + +func FindSourceFiles(searchPaths []string) ([]string, error) { + files := []string{} + + for _, searchPath := range searchPaths { + if searchPath == "/" { + errMessage := "The path / was given.\n" + + "Exiting because this could be a mistake," + + " e.g. an environment variable infront of / might be unintentionally empty.\n" + + "Here is an example of why we won't run on /:\n" + + "http://www.theregister.co.uk/2015/01/17/scary_code_of_the_week_steam_cleans_linux_pcs/" + return nil, cli.NewExitError(errMessage, 2) + } + + _ = filepath.Walk(searchPath, func(path string, fileInfo os.FileInfo, err error) error { + // Don't add paths that don't exist. + if err != nil { + return nil + } + + // Only add files, not directories. + if fileInfo.IsDir() { + return nil + } + + // Don't run on files inside dot directories. These directories are likely to + // be source control directories like ".git" or ".svn", or temporary directories + // like ".vagrant" or ".idea". + if containsDotDirectoryRegex.MatchString(path) { + return nil + } + + // Only keep files with extensions that we know are textual. + if !fileExtensionsRegex.MatchString(path) { + return nil + } + + files = append(files, path) + + return nil + }) + } + + return files, nil +} diff --git a/editorconfig/source_file_finder_test.go b/editorconfig/source_file_finder_test.go new file mode 100644 index 0000000..ba725ed --- /dev/null +++ b/editorconfig/source_file_finder_test.go @@ -0,0 +1,41 @@ +package editorconfig + +import ( + "strconv" + "testing" +) + +func TestGetSourceFileExtensions(t *testing.T) { + result := GetSourceFileExtensions() + + ExpectExtension := func(ext string) { + if !ContainsString(result, ext) { + t.Error("Result does not contain extension '" + ext + "'") + } + } + + ExpectExtension("go") + ExpectExtension("java") + ExpectExtension("php") +} + +func TestFindSourceFiles(t *testing.T) { + result, _ := FindSourceFiles([]string{"tests/a/b/c"}) + + if len(result) != 6 { + t.Error("Result should have 6 files, but has " + strconv.Itoa(len(result))) + } + + ExpectPath := func(path string) { + if !ContainsString(result, path) { + t.Error("Result does not contain path '" + path + "'") + } + } + + ExpectPath("tests/a/b/c/.editorconfig") + ExpectPath("tests/a/b/c/d/file.go") + ExpectPath("tests/a/b/c/d/file.java") + ExpectPath("tests/a/b/c/d/file.php") + ExpectPath("tests/a/b/c/d/keep-trailing-spaces.txt") + ExpectPath("tests/a/b/c/file.java") +}