2017-04-18 06:57:59 +00:00
|
|
|
package slinguist
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"regexp"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2017-04-19 09:48:01 +00:00
|
|
|
const shebang = `#!`
|
|
|
|
|
2017-04-18 06:57:59 +00:00
|
|
|
var (
|
|
|
|
shebangExecHack = regexp.MustCompile(`exec (\w+).+\$0.+\$@`)
|
|
|
|
pythonVersion = regexp.MustCompile(`python\d\.\d+`)
|
|
|
|
)
|
|
|
|
|
2017-05-31 10:07:46 +00:00
|
|
|
// GetLanguagesByShebang returns a slice of possible languages for the given content, filename will be ignored.
|
|
|
|
// It accomplish the signature to be a Strategy type.
|
|
|
|
func GetLanguagesByShebang(filename string, content []byte) (languages []string) {
|
2017-04-18 06:57:59 +00:00
|
|
|
interpreter := getInterpreter(content)
|
2017-05-31 10:07:46 +00:00
|
|
|
return languagesByInterpreter[interpreter]
|
2017-04-18 06:57:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func getInterpreter(data []byte) (interpreter string) {
|
|
|
|
line := getFirstLine(data)
|
|
|
|
if !hasShebang(line) {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// skip shebang
|
|
|
|
line = bytes.TrimSpace(line[2:])
|
|
|
|
|
|
|
|
splitted := bytes.Fields(line)
|
|
|
|
if bytes.Contains(splitted[0], []byte("env")) {
|
|
|
|
if len(splitted) > 1 {
|
|
|
|
interpreter = string(splitted[1])
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
splittedPath := bytes.Split(splitted[0], []byte{'/'})
|
|
|
|
interpreter = string(splittedPath[len(splittedPath)-1])
|
|
|
|
}
|
|
|
|
|
|
|
|
if interpreter == "sh" {
|
|
|
|
interpreter = lookForMultilineExec(data)
|
|
|
|
}
|
|
|
|
|
|
|
|
if pythonVersion.MatchString(interpreter) {
|
|
|
|
interpreter = interpreter[:strings.Index(interpreter, `.`)]
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func getFirstLine(data []byte) []byte {
|
|
|
|
buf := bufio.NewScanner(bytes.NewReader(data))
|
|
|
|
buf.Scan()
|
|
|
|
line := buf.Bytes()
|
|
|
|
if err := buf.Err(); err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return line
|
|
|
|
}
|
|
|
|
|
|
|
|
func hasShebang(line []byte) bool {
|
2017-04-19 09:48:01 +00:00
|
|
|
shebang := []byte(shebang)
|
2017-04-18 06:57:59 +00:00
|
|
|
return bytes.HasPrefix(line, shebang)
|
|
|
|
}
|
|
|
|
|
|
|
|
func lookForMultilineExec(data []byte) string {
|
|
|
|
const magicNumOfLines = 5
|
|
|
|
interpreter := "sh"
|
|
|
|
|
|
|
|
buf := bufio.NewScanner(bytes.NewReader(data))
|
|
|
|
for i := 0; i < magicNumOfLines && buf.Scan(); i++ {
|
|
|
|
line := buf.Bytes()
|
|
|
|
if shebangExecHack.Match(line) {
|
|
|
|
interpreter = shebangExecHack.FindStringSubmatch(string(line))[1]
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := buf.Err(); err != nil {
|
|
|
|
return interpreter
|
|
|
|
}
|
|
|
|
|
|
|
|
return interpreter
|
|
|
|
}
|