-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmaketools.go
More file actions
140 lines (127 loc) · 3.67 KB
/
maketools.go
File metadata and controls
140 lines (127 loc) · 3.67 KB
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package maketools
import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path/filepath"
"regexp"
"sort"
"strings"
)
// Filenames is ordered list of makefile names
var Filenames = []string{"GNUmakefile", "makefile", "Makefile"}
// HelpLineRegexp is the regexp to catch target lines
var HelpLineRegexp = regexp.MustCompile(`(?m)^([\w-]+):[\t ]*([^#\n]+)?[\t ]*(#[\t ]*(.*))?$`)
// IncludedRegexp is the regexp to catch included makefiles
var IncludedRegexp = regexp.MustCompile(`(?m)^-?include\s+(.*)$`)
// HelpLine holds information about a line of help
type HelpLine struct {
Name string
Description string
Dependencies []string
}
// HelpLineSorter sorts HelpLine by name
type HelpLineSorter []HelpLine
func (a HelpLineSorter) Len() int { return len(a) }
func (a HelpLineSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a HelpLineSorter) Less(i, j int) bool { return a[i].Name < a[j].Name }
// FileExists tells if given file exists:
// - file: the name of the file to test
// Return: a boolean that tells if file exists
func FileExists(file string) bool {
if stat, err := os.Stat(file); err == nil && !stat.IsDir() {
return true
}
return false
}
// FindMakefile looks for makefile in current directory
// Return: found makefile name
func FindMakefile() string {
for _, name := range Filenames {
if FileExists(name) {
return name
}
}
return ""
}
// ExpandUserHome expand path starting with "~/":
// - path: the path to expand
// Return: expanded path
func ExpandUserHome(path string) string {
if strings.HasPrefix(path, "~/") {
currentUser, err := user.Current()
if err != nil {
panic("could not get current user")
}
home := currentUser.HomeDir
path = filepath.Join(home, path[2:])
}
return path
}
// IncludedFiles extracts included makefiles
// - source: makefile source
// Return: included makefiles
func IncludedFiles(source string) ([]string, error) {
var included []string
lines := IncludedRegexp.FindAllStringSubmatch(source, -1)
for _, line := range lines {
globs := strings.Split(line[1], " ")
for _, glob := range globs {
glob = ExpandUserHome(glob)
files, err := filepath.Glob(glob)
if err != nil {
return nil, err
}
included = append(included, files...)
}
}
return included, nil
}
// ReadFile and exit on error
// - filename: name of the file to read
// Return: file content as a string
func ReadFile(filename string) string {
bytes, err := ioutil.ReadFile(filepath.Clean(filename))
if err != nil {
fmt.Printf("Error reading makefile %s: %v", filename, err)
os.Exit(1)
}
return string(bytes)
}
// ParseMakefile parses passed makefile
// - source: the makefile source
// - recursive: tells if we should parse recursively (defaults to true)
// Return: HelpLine list and error if any
func ParseMakefile(source string, recursive bool) ([]HelpLine, error) {
result := HelpLineRegexp.FindAllStringSubmatch(source, -1)
var help []HelpLine
for _, line := range result {
dependencies := strings.Split(strings.TrimSpace(line[2]), " ")
if len(dependencies) == 1 && dependencies[0] == "" {
dependencies = nil
}
helpLine := HelpLine{
Name: line[1],
Description: line[4],
Dependencies: dependencies,
}
help = append(help, helpLine)
}
if recursive {
filenames, err := IncludedFiles(source)
if err != nil {
return nil, fmt.Errorf("parsing included makefile: %v", err)
}
for _, filename := range filenames {
included := ExpandUserHome(filename)
helpsIncluded, err := ParseMakefile(ReadFile(included), recursive)
if err != nil {
return nil, fmt.Errorf("parsing included makefile: %v", err)
}
help = append(help, helpsIncluded...)
}
}
sort.Sort(HelpLineSorter(help))
return help, nil
}