/
files.go
146 lines (134 loc) · 2.94 KB
/
files.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
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
141
142
143
144
145
146
package main
import (
"bufio"
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
const (
defaultPattern = "*.go"
dropFile = ".drop"
)
var ignoreFiles = []string{"doc.go"}
var errNeedDir = errors.New("expected directory")
// files gets a list of files to include from the specified path.
// If no .drop file is specified, default files are selected.
func files(path string) ([]string, error) {
info, err := os.Stat(path)
if err != nil {
return nil, err
}
if !info.IsDir() {
return nil, errNeedDir
}
files, err := dropfile(path)
if err == nil {
return files, nil
}
files, err = filepath.Glob(filepath.Join(path, defaultPattern))
if err != nil {
return nil, err
}
return cleanFiles(files...), nil
}
type errLine struct {
file string
n int
err error
}
func (e errLine) Error() string {
return fmt.Sprintf("%s:%d: %s", e.file, e.n, e.err)
}
// license gets the path to a license file (if there is one).
func license(p string) (string, error) {
files, err := ioutil.ReadDir(p)
if err != nil {
return "", err
}
for _, file := range files {
if file.IsDir() {
continue
}
base := filepath.Base(file.Name())
base = strings.TrimSuffix(base, filepath.Ext(base))
if strings.ToLower(base) == "license" {
return extractFirstLine(filepath.Join(p, file.Name()))
}
}
return "", nil
}
func extractFirstLine(path string) (string, error) {
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
s := bufio.NewScanner(f)
for s.Scan() {
clean := strings.TrimSpace(s.Text())
if len(clean) > 0 {
return clean, nil
}
}
return "", nil
}
// dropfile gets a cleaned list of files from the .drop
// file at the specified path.
func dropfile(path string) ([]string, error) {
dropfile := filepath.Join(path, dropFile)
src, err := ioutil.ReadFile(dropfile)
if err != nil {
return nil, err
}
var files []string
s := bufio.NewScanner(bytes.NewReader(src))
lineNumber := 0
for s.Scan() {
lineNumber++
text := s.Text()
if strings.HasPrefix(text, "#") || len(text) == 0 {
// ignore comments and empty lines
continue
}
relPattern := filepath.Join(path, text)
theseFiles, err := filepath.Glob(relPattern)
if err != nil {
return nil, errLine{file: dropfile, n: lineNumber, err: err}
}
files = append(files, theseFiles...)
}
return cleanFiles(files...), nil
}
// cleanFiles ignores ignoreFiles and selects only unique
// files from the list.
func cleanFiles(files ...string) []string {
var cleanFiles []string
for _, file := range files {
include := true
for _, existing := range cleanFiles {
if existing == file {
include = false
break
}
}
for _, ignore := range ignoreFiles {
match, err := filepath.Match(ignore, filepath.Base(file))
if err != nil {
log.Println("drop: filepath.Match:", err)
}
if match {
include = false
break
}
}
if include {
cleanFiles = append(cleanFiles, file)
}
}
return cleanFiles
}