in pkg/linguist/linguist.go [51:173]
func initLinguistAttributes(dir string) error {
ignore := []string{}
except := []string{}
detected := make(map[string]string)
gitignoreExists, err := osutil.Exists(filepath.Join(dir, ".gitignore"))
if err != nil {
return err
}
if gitignoreExists {
log.Debugln("found .gitignore")
f, err := os.Open(filepath.Join(dir, ".gitignore"))
if err != nil {
return err
}
defer f.Close()
ignoreScanner := bufio.NewScanner(f)
for ignoreScanner.Scan() {
var isExcept bool
path := strings.TrimSpace(ignoreScanner.Text())
// if it's whitespace or a comment
if len(path) == 0 || string(path[0]) == "#" {
continue
}
if string(path[0]) == "!" {
isExcept = true
path = path[1:]
}
p := strings.Trim(path, string(filepath.Separator))
if isExcept {
except = append(except, p)
} else {
ignore = append(ignore, p)
}
}
if err := ignoreScanner.Err(); err != nil {
return fmt.Errorf("error reading .gitignore: %v", err)
}
}
gitAttributesExists, err := osutil.Exists(filepath.Join(dir, ".gitattributes"))
if err != nil {
return err
}
if gitAttributesExists {
log.Debugln("found .gitattributes")
f, err := os.Open(filepath.Join(dir, ".gitattributes"))
if err != nil {
return err
}
defer f.Close()
attributeScanner := bufio.NewScanner(f)
var lineNumber int
for attributeScanner.Scan() {
lineNumber++
line := strings.TrimSpace(attributeScanner.Text())
words := strings.Fields(line)
if len(words) != 2 {
log.Printf("invalid line in .gitattributes at L%d: '%s'\n", lineNumber, line)
continue
}
path := strings.Trim(words[0], string(filepath.Separator))
if runtime.GOOS == "windows" {
// on Windows, we also accept / as a path separator, so let's strip those as well
path = strings.Trim(words[0], "/")
}
attribute := words[1]
if strings.HasPrefix(attribute, "linguist-documentation") || strings.HasPrefix(attribute, "linguist-vendored") || strings.HasPrefix(attribute, "linguist-generated") {
if !strings.HasSuffix(strings.ToLower(attribute), "false") {
ignore = append(ignore, path)
}
} else if strings.HasPrefix(attribute, "linguist-language") {
attr := strings.Split(attribute, "=")
if len(attr) != 2 {
log.Printf("invalid line in .gitattributes at L%d: '%s'\n", lineNumber, line)
continue
}
language := attr[1]
detected[path] = language
}
}
if err := attributeScanner.Err(); err != nil {
return fmt.Errorf("error reading .gitattributes: %v", err)
}
}
isIgnored = func(filename string) bool {
for _, p := range ignore {
cleanPath, err := filepath.Rel(dir, filename)
if err != nil {
log.Debugf("could not get relative path: %v", err)
return false
}
if m, _ := filepath.Match(p, cleanPath); m {
for _, e := range except {
if m, _ := filepath.Match(e, cleanPath); m {
return false
}
}
return true
}
}
return false
}
isDetectedInGitAttributes = func(filename string) string {
for p, lang := range detected {
cleanPath, err := filepath.Rel(dir, filename)
if err != nil {
log.Debugf("could not get relative path: %v", err)
return ""
}
if m, _ := filepath.Match(p, cleanPath); m {
return lang
}
}
return ""
}
return nil
}