-
Notifications
You must be signed in to change notification settings - Fork 4
/
embed.go
128 lines (116 loc) · 3.12 KB
/
embed.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
// Copyright ©2022 Dan Kortschak. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"encoding/json"
"go/token"
"io"
"os"
"path/filepath"
"sort"
"unicode"
"unicode/utf8"
"golang.org/x/sys/execabs"
)
// TODO(kortschak): Remove this and use packages.Load
// when https://go.dev/issue/50720 is resolved.
func embedFiles(pkgs []string) ([]string, error) {
args := []string{"list", "-json"}
cmd := execabs.Command("go", append(args, pkgs...)...)
var buf bytes.Buffer
cmd.Stdout = &buf
err := cmd.Run()
if err != nil {
return nil, err
}
var files []string
dec := json.NewDecoder(&buf)
for {
var pkg struct {
Dir string
EmbedFiles []string
}
err := dec.Decode(&pkg)
if err != nil {
if err != io.EOF {
return nil, err
}
break
}
for i, f := range pkg.EmbedFiles {
pkg.EmbedFiles[i] = filepath.Join(pkg.Dir, f)
}
files = append(files, pkg.EmbedFiles...)
}
return files, nil
}
// embedded is a representation of embedded data.
type embedded struct {
path string
data string
lines []int
}
// loadEmbedded reads the file at the provided path as an embedded.
// If the data in the file is not valid UTF-8, contains bytes not found
// in ASCII or UTF-8 text, or contains lines longer than maxLineLen, no
// line-based position information will be retained and the file will be
// treated as binary data.
func (c *checker) loadEmbedded(path string, maxLineLen int) (*embedded, error) {
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
e := &embedded{path: path, data: string(b)}
if c.unexpectedEntropy(e.data, false) { // Consider all characters for entropy.
e.data = ""
return e, nil
}
if !utf8.ValidString(e.data) {
return e, nil
}
e.lines = []int{0}
for i, b := range e.data {
if (b <= unicode.MaxASCII && neverInText[b]) || i > e.lines[len(e.lines)-1]+maxLineLen {
e.lines = nil
break
}
if b == '\n' {
e.lines = append(e.lines, i)
}
}
return e, nil
}
// neverInText is the set of bytes never found in ASCII/UTF-8 text files.
var neverInText = [256]bool{
// First row minus BEL BS TAB LF VT FF CR.
0x00: true, 0x01: true, 0x02: true, 0x03: true, 0x04: true,
0x05: true, 0x06: true, 0x0e: true, 0x0f: true,
// Second row minus ESC.
0x10: true, 0x11: true, 0x12: true, 0x13: true, 0x14: true,
0x15: true, 0x16: true, 0x17: true, 0x18: true, 0x19: true,
0x1a: true, 0x1c: true, 0x1d: true, 0x1e: true, 0x1f: true,
// DEL.
0x7f: true,
}
// Text returns the text representation of the embedded data.
func (e *embedded) Text() string { return e.data }
// Pos and End implement ast.Node.
func (e *embedded) Pos() token.Pos { return 1 }
func (e *embedded) End() token.Pos { return e.Pos() + token.Pos(len(e.data)) }
// Position implements positioner.
func (e *embedded) Position(pos token.Pos) token.Position {
p := int(pos)
var line, col int
if e.lines != nil && pos.IsValid() && p <= len(e.data) {
line = sort.SearchInts(e.lines, p)
col = p - e.lines[line-1]
}
return token.Position{
Filename: e.path,
Offset: p,
Line: line,
Column: col,
}
}