File: port.go

package info (click to toggle)
golang-github-cue-lang-cue 0.12.0.-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 19,072 kB
  • sloc: sh: 57; makefile: 17
file content (204 lines) | stat: -rw-r--r-- 5,663 bytes parent folder | download
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package cache

import (
	"bytes"
	"go/build"
	"go/parser"
	"go/token"
	"io"
	"path/filepath"
	"strings"

	"cuelang.org/go/internal/golangorgx/gopls/util/bug"
)

type port struct{ GOOS, GOARCH string }

var (
	// preferredPorts holds GOOS/GOARCH combinations for which we dynamically
	// create new Views, by setting GOOS=... and GOARCH=... on top of
	// user-provided configuration when we detect that the default build
	// configuration does not match an open file. Ports are matched in the order
	// defined below, so that when multiple ports match a file we use the port
	// occurring at a lower index in the slice. For that reason, we sort first
	// class ports ahead of secondary ports, and (among first class ports) 64-bit
	// ports ahead of the less common 32-bit ports.
	preferredPorts = []port{
		// First class ports, from https://go.dev/wiki/PortingPolicy.
		{"darwin", "amd64"},
		{"darwin", "arm64"},
		{"linux", "amd64"},
		{"linux", "arm64"},
		{"windows", "amd64"},
		{"linux", "arm"},
		{"linux", "386"},
		{"windows", "386"},

		// Secondary ports, from GOROOT/src/internal/platform/zosarch.go.
		// (First class ports are commented out.)
		{"aix", "ppc64"},
		{"dragonfly", "amd64"},
		{"freebsd", "386"},
		{"freebsd", "amd64"},
		{"freebsd", "arm"},
		{"freebsd", "arm64"},
		{"illumos", "amd64"},
		{"linux", "ppc64"},
		{"linux", "ppc64le"},
		{"linux", "mips"},
		{"linux", "mipsle"},
		{"linux", "mips64"},
		{"linux", "mips64le"},
		{"linux", "riscv64"},
		{"linux", "s390x"},
		{"android", "386"},
		{"android", "amd64"},
		{"android", "arm"},
		{"android", "arm64"},
		{"ios", "arm64"},
		{"ios", "amd64"},
		{"js", "wasm"},
		{"netbsd", "386"},
		{"netbsd", "amd64"},
		{"netbsd", "arm"},
		{"netbsd", "arm64"},
		{"openbsd", "386"},
		{"openbsd", "amd64"},
		{"openbsd", "arm"},
		{"openbsd", "arm64"},
		{"openbsd", "mips64"},
		{"plan9", "386"},
		{"plan9", "amd64"},
		{"plan9", "arm"},
		{"solaris", "amd64"},
		{"windows", "arm"},
		{"windows", "arm64"},

		{"aix", "ppc64"},
		{"android", "386"},
		{"android", "amd64"},
		{"android", "arm"},
		{"android", "arm64"},
		// {"darwin", "amd64"},
		// {"darwin", "arm64"},
		{"dragonfly", "amd64"},
		{"freebsd", "386"},
		{"freebsd", "amd64"},
		{"freebsd", "arm"},
		{"freebsd", "arm64"},
		{"freebsd", "riscv64"},
		{"illumos", "amd64"},
		{"ios", "amd64"},
		{"ios", "arm64"},
		{"js", "wasm"},
		// {"linux", "386"},
		// {"linux", "amd64"},
		// {"linux", "arm"},
		// {"linux", "arm64"},
		{"linux", "loong64"},
		{"linux", "mips"},
		{"linux", "mips64"},
		{"linux", "mips64le"},
		{"linux", "mipsle"},
		{"linux", "ppc64"},
		{"linux", "ppc64le"},
		{"linux", "riscv64"},
		{"linux", "s390x"},
		{"linux", "sparc64"},
		{"netbsd", "386"},
		{"netbsd", "amd64"},
		{"netbsd", "arm"},
		{"netbsd", "arm64"},
		{"openbsd", "386"},
		{"openbsd", "amd64"},
		{"openbsd", "arm"},
		{"openbsd", "arm64"},
		{"openbsd", "mips64"},
		{"openbsd", "ppc64"},
		{"openbsd", "riscv64"},
		{"plan9", "386"},
		{"plan9", "amd64"},
		{"plan9", "arm"},
		{"solaris", "amd64"},
		{"wasip1", "wasm"},
		// {"windows", "386"},
		// {"windows", "amd64"},
		{"windows", "arm"},
		{"windows", "arm64"},
	}
)

// matches reports whether the port matches a file with the given absolute path
// and content.
//
// Note that this function accepts content rather than e.g. a file.Handle,
// because we trim content before matching for performance reasons, and
// therefore need to do this outside of matches when considering multiple ports.
func (p port) matches(path string, content []byte) bool {
	ctxt := build.Default // make a copy
	ctxt.UseAllFiles = false
	dir, name := filepath.Split(path)

	// The only virtualized operation called by MatchFile is OpenFile.
	ctxt.OpenFile = func(p string) (io.ReadCloser, error) {
		if p != path {
			return nil, bug.Errorf("unexpected file %q", p)
		}
		return io.NopCloser(bytes.NewReader(content)), nil
	}

	ctxt.GOOS = p.GOOS
	ctxt.GOARCH = p.GOARCH
	ok, err := ctxt.MatchFile(dir, name)
	return err == nil && ok
}

// trimContentForPortMatch trims the given Go file content to a minimal file
// containing the same build constraints, if any.
//
// This is an unfortunate but necessary optimization, as matching build
// constraints using go/build has significant overhead, and involves parsing
// more than just the build constraint.
//
// TestMatchingPortsConsistency enforces consistency by comparing results
// without trimming content.
func trimContentForPortMatch(content []byte) []byte {
	buildComment := buildComment(content)
	return []byte(buildComment + "\npackage p") // package name does not matter
}

// buildComment returns the first matching //go:build comment in the given
// content, or "" if none exists.
func buildComment(content []byte) string {
	f, err := parser.ParseFile(token.NewFileSet(), "", content, parser.PackageClauseOnly|parser.ParseComments)
	if err != nil {
		return ""
	}

	for _, cg := range f.Comments {
		for _, c := range cg.List {
			if isGoBuildComment(c.Text) {
				return c.Text
			}
		}
	}
	return ""
}

// Adapted from go/build/build.go.
//
// TODO(rfindley): use constraint.IsGoBuild once we are on 1.19+.
func isGoBuildComment(line string) bool {
	const goBuildComment = "//go:build"
	if !strings.HasPrefix(line, goBuildComment) {
		return false
	}
	// Report whether //go:build is followed by a word boundary.
	line = strings.TrimSpace(line)
	rest := line[len(goBuildComment):]
	return len(rest) == 0 || len(strings.TrimSpace(rest)) < len(rest)
}