-
Notifications
You must be signed in to change notification settings - Fork 16
/
filesearch.go
83 lines (77 loc) · 2.41 KB
/
filesearch.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package main
import (
"errors"
"os"
"path/filepath"
"strings"
"time"
)
// Don't search for a corresponding header/source file for longer than ~0.5 seconds
var fileSearchMaxTime = 500 * time.Millisecond
// ExtFileSearch will search for a corresponding file, given a slice of extensions.
// This is useful for ie. finding a corresponding .h file for a .c file.
// The search starts in the current directory, then searches every parent directory in depth.
// TODO: Search sibling and parent directories named "include" first, then search the rest.
func ExtFileSearch(absCppFilename string, headerExtensions []string, maxTime time.Duration) (string, error) {
cppBasename := filepath.Base(absCppFilename)
searchPath := filepath.Dir(absCppFilename)
ext := filepath.Ext(cppBasename)
if ext == "" {
return "", errors.New("filename has no extension: " + cppBasename)
}
firstName := cppBasename[:len(cppBasename)-len(ext)]
// First search the same path as the given filename, without using Walk
withoutExt := strings.TrimSuffix(absCppFilename, ext)
for _, hext := range headerExtensions {
if exists(withoutExt + hext) {
return withoutExt + hext, nil
}
}
var headerNames []string
for _, ext := range headerExtensions {
headerNames = append(headerNames, firstName+ext)
}
foundHeaderAbsPath := ""
startTime := time.Now()
for {
err := filepath.Walk(searchPath, func(path string, info os.FileInfo, err error) error {
basename := filepath.Base(info.Name())
if err == nil {
//logf("Walking %s\n", path)
for _, headerName := range headerNames {
if time.Since(startTime) > maxTime {
return errors.New("file search timeout")
}
if basename == headerName {
// Found the corresponding header!
absFilename, err := filepath.Abs(path)
if err != nil {
continue
}
foundHeaderAbsPath = absFilename
//logf("Found %s!\n", absFilename)
return nil
}
}
}
// No result
return nil
})
if err != nil {
return "", errors.New("error when searching for a corresponding header for " + cppBasename + ":" + err.Error())
}
if len(foundHeaderAbsPath) == 0 {
// Try the parent directory
searchPath = filepath.Dir(searchPath)
if len(searchPath) > 2 {
continue
}
}
break
}
if len(foundHeaderAbsPath) == 0 {
return "", errors.New("found no corresponding header for " + cppBasename)
}
// Return the result
return foundHeaderAbsPath, nil
}