Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8882c31eb4 | ||
|
|
8455ee8226 | ||
|
|
3f74aded8a | ||
|
|
2e19c2013c | ||
|
|
1edaa2d09b | ||
|
|
beee018287 | ||
|
|
34266ea59d | ||
|
|
f26127ce98 | ||
|
|
ccf321d178 | ||
|
|
355721c47a | ||
|
|
d400663e5d | ||
|
|
2203be945a | ||
|
|
b9a2bf4b42 | ||
|
|
cc08195cf2 | ||
|
|
50c40a7828 | ||
|
|
158be3f949 | ||
|
|
0f87c322ca | ||
|
|
d5dd19b64c | ||
|
|
3032d730b7 | ||
|
|
e93e7126b6 | ||
|
|
9bcf41d28f | ||
|
|
604ce47d5e | ||
|
|
e1ebe150d4 | ||
|
|
ae992737e8 | ||
|
|
c59d609eb8 | ||
|
|
9f26d12a3e | ||
|
|
9102577eba | ||
|
|
f0fcfde22b | ||
|
|
d9d813db56 | ||
|
|
a8808855ae | ||
|
|
5583f9418a | ||
|
|
7369ffd2aa | ||
|
|
ab15f30b13 | ||
|
|
8bff07d66b | ||
|
|
e2e2cb38be |
4
.github/codecov.yml
vendored
4
.github/codecov.yml
vendored
@@ -1,9 +1,11 @@
|
|||||||
coverage:
|
coverage:
|
||||||
ignore:
|
ignore:
|
||||||
- "chore"
|
- "chore"
|
||||||
- "cmd/internal"
|
- "cmd"
|
||||||
- "internal/build"
|
- "internal/build"
|
||||||
- "internal/llgen"
|
- "internal/llgen"
|
||||||
- "internal/mockable"
|
- "internal/mockable"
|
||||||
- "internal/packages"
|
- "internal/packages"
|
||||||
- "internal/typepatch"
|
- "internal/typepatch"
|
||||||
|
- "internal/github"
|
||||||
|
- "xtool/cppkg"
|
||||||
|
|||||||
2
.github/workflows/fmt.yml
vendored
2
.github/workflows/fmt.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
for dir in . runtime; do
|
for dir in . runtime; do
|
||||||
pushd $dir
|
pushd $dir
|
||||||
if [ -n "$(go fmt ./...)" ]; then
|
if [ -n "$(go fmt ./... | grep -v gop_autogen.go)" ]; then
|
||||||
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
|
echo "Some files are not properly formatted. Please run 'go fmt ./...'"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ Here are the Go packages that can be imported correctly:
|
|||||||
* [regexp/syntax](https://pkg.go.dev/regexp/syntax)
|
* [regexp/syntax](https://pkg.go.dev/regexp/syntax)
|
||||||
* [go/token](https://pkg.go.dev/go/token)
|
* [go/token](https://pkg.go.dev/go/token)
|
||||||
* [go/scanner](https://pkg.go.dev/go/scanner)
|
* [go/scanner](https://pkg.go.dev/go/scanner)
|
||||||
|
* [go/parser](https://pkg.go.dev/go/parser)
|
||||||
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|||||||
33
_cmptest/_goconstdemo/goconst.go
Normal file
33
_cmptest/_goconstdemo/goconst.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"go/constant"
|
||||||
|
"go/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Create the complex number 2.3 + 5i.
|
||||||
|
ar := constant.MakeFloat64(2.3)
|
||||||
|
ai := constant.MakeImag(constant.MakeInt64(5))
|
||||||
|
a := constant.BinaryOp(ar, token.ADD, ai)
|
||||||
|
|
||||||
|
// Compute (2.3 + 5i) * 11.
|
||||||
|
b := constant.MakeUint64(11)
|
||||||
|
c := constant.BinaryOp(a, token.MUL, b)
|
||||||
|
|
||||||
|
// Convert c into a complex128.
|
||||||
|
Ar, exact := constant.Float64Val(constant.Real(c))
|
||||||
|
if !exact {
|
||||||
|
fmt.Printf("Could not represent real part %s exactly as float64\n", constant.Real(c))
|
||||||
|
}
|
||||||
|
Ai, exact := constant.Float64Val(constant.Imag(c))
|
||||||
|
if !exact {
|
||||||
|
fmt.Printf("Could not represent imaginary part %s as exactly as float64\n", constant.Imag(c))
|
||||||
|
}
|
||||||
|
C := complex(Ar, Ai)
|
||||||
|
|
||||||
|
fmt.Println("literal", 25.3+55i)
|
||||||
|
fmt.Println("go/constant", c)
|
||||||
|
fmt.Println("complex128", C)
|
||||||
|
}
|
||||||
25
_cmptest/mathbigdemo/big.go
Normal file
25
_cmptest/mathbigdemo/big.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Initialize two big ints with the first two numbers in the sequence.
|
||||||
|
a := big.NewInt(0)
|
||||||
|
b := big.NewInt(1)
|
||||||
|
|
||||||
|
// Initialize limit as 10^99, the smallest integer with 100 digits.
|
||||||
|
var limit big.Int
|
||||||
|
limit.Exp(big.NewInt(10), big.NewInt(99), nil)
|
||||||
|
|
||||||
|
// Loop while a is smaller than 1e100.
|
||||||
|
for a.Cmp(&limit) < 0 {
|
||||||
|
// Compute the next Fibonacci number, storing it in a.
|
||||||
|
a.Add(a, b)
|
||||||
|
// Swap a and b so that b is the next number in the sequence.
|
||||||
|
a, b = b, a
|
||||||
|
}
|
||||||
|
fmt.Println(a) // 100-digit Fibonacci number
|
||||||
|
}
|
||||||
@@ -11,7 +11,3 @@ func main() {
|
|||||||
fmt.Println("hello world by fmt.Println")
|
fmt.Println("hello world by fmt.Println")
|
||||||
c.Printf(c.Str("Hello world by c.Printf\n"))
|
c.Printf(c.Str("Hello world by c.Printf\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expected output:
|
|
||||||
Hello world
|
|
||||||
*/
|
|
||||||
|
|||||||
737
cl/_testdefer/gobuild/in.go
Normal file
737
cl/_testdefer/gobuild/in.go
Normal file
@@ -0,0 +1,737 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"go/ast"
|
||||||
|
"go/doc"
|
||||||
|
"go/token"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
pathpkg "path"
|
||||||
|
"runtime"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsLocalImport(path string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAbsPath(path string) bool {
|
||||||
|
return strings.HasPrefix(path, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDir(path string) bool {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
|
func isFile(path string) bool {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return fi.Mode().IsRegular()
|
||||||
|
}
|
||||||
|
|
||||||
|
func joinPath(a string, b ...string) string {
|
||||||
|
if isAbsPath(b[0]) {
|
||||||
|
return b[0]
|
||||||
|
}
|
||||||
|
return pathpkg.Join(append([]string{a}, b...)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func nameExt(path string) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func gopath() []string {
|
||||||
|
all := make([]string, 0, 10)
|
||||||
|
for _, p := range strings.Split(os.Getenv("GOPATH"), ":") {
|
||||||
|
if p != "" {
|
||||||
|
all = append(all, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return all
|
||||||
|
}
|
||||||
|
|
||||||
|
type Context struct {
|
||||||
|
InstallSuffix string
|
||||||
|
Compiler string
|
||||||
|
GOOS string
|
||||||
|
GOARCH string
|
||||||
|
GOROOT string
|
||||||
|
CgoEnabled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Package struct {
|
||||||
|
ImportPath string
|
||||||
|
Dir string
|
||||||
|
Goroot bool
|
||||||
|
Root string
|
||||||
|
ConflictDir string
|
||||||
|
SrcRoot string
|
||||||
|
PkgRoot string
|
||||||
|
BinDir string
|
||||||
|
PkgTargetRoot string
|
||||||
|
PkgObj string
|
||||||
|
InvalidGoFiles []string
|
||||||
|
IgnoredGoFiles []string
|
||||||
|
IgnoredOtherFiles []string
|
||||||
|
CgoFiles []string
|
||||||
|
XTestGoFiles []string
|
||||||
|
TestGoFiles []string
|
||||||
|
GoFiles []string
|
||||||
|
Directives []Directive
|
||||||
|
TestDirectives []Directive
|
||||||
|
XTestDirectives []Directive
|
||||||
|
BinaryOnly bool
|
||||||
|
Name string
|
||||||
|
Doc string
|
||||||
|
ImportComment string
|
||||||
|
AllTags []string
|
||||||
|
EmbedPatterns []string
|
||||||
|
TestEmbedPatterns []string
|
||||||
|
XTestEmbedPatterns []string
|
||||||
|
Imports []string
|
||||||
|
TestImports []string
|
||||||
|
XTestImports []string
|
||||||
|
EmbedPatternPos map[string][]token.Position
|
||||||
|
TestEmbedPatternPos map[string][]token.Position
|
||||||
|
XTestEmbedPatternPos map[string][]token.Position
|
||||||
|
ImportPos map[string][]token.Position
|
||||||
|
TestImportPos map[string][]token.Position
|
||||||
|
XTestImportPos map[string][]token.Position
|
||||||
|
SFiles []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Directive struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type MultiplePackageError struct {
|
||||||
|
Dir string
|
||||||
|
Packages []string
|
||||||
|
Files []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MultiplePackageError) Error() string {
|
||||||
|
return fmt.Sprintf("multiple packages in single directory: %s\n\t%s\n\t%s", e.Dir, strings.Join(e.Packages, "\n\t"), strings.Join(e.Files, "\n\t"))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ImportMode = uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
IgnoreVendor ImportMode = 1 << iota
|
||||||
|
AllowBinary
|
||||||
|
FindOnly
|
||||||
|
ImportComment
|
||||||
|
)
|
||||||
|
|
||||||
|
func importGo(ctx *Context, p *Package, path, srcDir string, mode ImportMode) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasSubdir(root, sub string) (string, bool) {
|
||||||
|
return sub, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasGoFiles(ctxt *Context, file string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isStandardImportPath(path string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDir(name string) ([]os.DirEntry, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func findImportComment(data []byte) (s string, line int) {
|
||||||
|
return "", 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveCgo(ctxt *Context, filename string, p *Package, doc *ast.CommentGroup) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanDecls(m map[string][]token.Position) ([]string, map[string][]token.Position) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fileListForExt(p *Package, ext string) *[]string {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileInfo struct {
|
||||||
|
name string // full name including dir
|
||||||
|
header []byte
|
||||||
|
fset *token.FileSet
|
||||||
|
parsed *ast.File
|
||||||
|
parseErr error
|
||||||
|
imports []fileImport
|
||||||
|
embeds []fileEmbed
|
||||||
|
directives []Directive
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileImport struct {
|
||||||
|
path string
|
||||||
|
pos token.Pos
|
||||||
|
doc *ast.CommentGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
type fileEmbed struct {
|
||||||
|
pattern string
|
||||||
|
pos token.Position
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchFile(ctxt *Context, dir, name string, allTags map[string]bool, binaryOnly *bool, fset *token.FileSet) (*fileInfo, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var errNoModules = errors.New("no modules")
|
||||||
|
|
||||||
|
type godebug struct {
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGodebug(name string) *godebug {
|
||||||
|
return &godebug{
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *godebug) IncNonDefault() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *godebug) Value() string {
|
||||||
|
return g.name
|
||||||
|
}
|
||||||
|
|
||||||
|
var installgoroot = NewGodebug("installgoroot")
|
||||||
|
|
||||||
|
func IsStandardPackage(a, b, c string) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type NoGoError struct {
|
||||||
|
Dir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *NoGoError) Error() string {
|
||||||
|
return "no Go files in " + e.Dir
|
||||||
|
}
|
||||||
|
|
||||||
|
func Import(ctxt *Context, path string, srcDir string, mode ImportMode) (*Package, error) {
|
||||||
|
p := &Package{
|
||||||
|
ImportPath: path,
|
||||||
|
}
|
||||||
|
if path == "" {
|
||||||
|
return p, fmt.Errorf("import %q: invalid import path", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkgtargetroot string
|
||||||
|
var pkga string
|
||||||
|
var pkgerr error
|
||||||
|
suffix := ""
|
||||||
|
if ctxt.InstallSuffix != "" {
|
||||||
|
suffix = "_" + ctxt.InstallSuffix
|
||||||
|
}
|
||||||
|
switch ctxt.Compiler {
|
||||||
|
case "gccgo":
|
||||||
|
pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
|
||||||
|
case "gc":
|
||||||
|
pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
|
||||||
|
default:
|
||||||
|
// Save error for end of function.
|
||||||
|
pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
|
||||||
|
}
|
||||||
|
setPkga := func() {
|
||||||
|
switch ctxt.Compiler {
|
||||||
|
case "gccgo":
|
||||||
|
dir, elem := pathpkg.Split(p.ImportPath)
|
||||||
|
pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
|
||||||
|
case "gc":
|
||||||
|
pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setPkga()
|
||||||
|
|
||||||
|
binaryOnly := false
|
||||||
|
if IsLocalImport(path) {
|
||||||
|
pkga = "" // local imports have no installed path
|
||||||
|
if srcDir == "" {
|
||||||
|
return p, fmt.Errorf("import %q: import relative to unknown directory", path)
|
||||||
|
}
|
||||||
|
if !isAbsPath(path) {
|
||||||
|
p.Dir = joinPath(srcDir, path)
|
||||||
|
}
|
||||||
|
// p.Dir directory may or may not exist. Gather partial information first, check if it exists later.
|
||||||
|
// Determine canonical import path, if any.
|
||||||
|
// Exclude results where the import path would include /testdata/.
|
||||||
|
inTestdata := func(sub string) bool {
|
||||||
|
return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
|
||||||
|
}
|
||||||
|
if ctxt.GOROOT != "" {
|
||||||
|
root := joinPath(runtime.GOROOT(), "src")
|
||||||
|
if sub, ok := hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
|
||||||
|
p.Goroot = true
|
||||||
|
p.ImportPath = sub
|
||||||
|
p.Root = ctxt.GOROOT
|
||||||
|
setPkga() // p.ImportPath changed
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all := gopath()
|
||||||
|
for i, root := range all {
|
||||||
|
rootsrc := joinPath(root, "src")
|
||||||
|
if sub, ok := hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
|
||||||
|
// We found a potential import path for dir,
|
||||||
|
// but check that using it wouldn't find something
|
||||||
|
// else first.
|
||||||
|
if runtime.GOROOT() != "" && ctxt.Compiler != "gccgo" {
|
||||||
|
if dir := joinPath(runtime.GOROOT(), "src", sub); isDir(dir) {
|
||||||
|
p.ConflictDir = dir
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, earlyRoot := range all[:i] {
|
||||||
|
if dir := joinPath(earlyRoot, "src", sub); isDir(dir) {
|
||||||
|
p.ConflictDir = dir
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sub would not name some other directory instead of this one.
|
||||||
|
// Record it.
|
||||||
|
p.ImportPath = sub
|
||||||
|
p.Root = root
|
||||||
|
setPkga() // p.ImportPath changed
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// It's okay that we didn't find a root containing dir.
|
||||||
|
// Keep going with the information we have.
|
||||||
|
} else {
|
||||||
|
if strings.HasPrefix(path, "/") {
|
||||||
|
return p, fmt.Errorf("import %q: cannot import absolute path", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := importGo(ctxt, p, path, srcDir, mode); err == nil {
|
||||||
|
goto Found
|
||||||
|
} else if err != errNoModules {
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
gopath := gopath() // needed twice below; avoid computing many times
|
||||||
|
|
||||||
|
// tried records the location of unsuccessful package lookups
|
||||||
|
var tried struct {
|
||||||
|
vendor []string
|
||||||
|
goroot string
|
||||||
|
gopath []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vendor directories get first chance to satisfy import.
|
||||||
|
if mode&IgnoreVendor == 0 && srcDir != "" {
|
||||||
|
searchVendor := func(root string, isGoroot bool) bool {
|
||||||
|
sub, ok := hasSubdir(root, srcDir)
|
||||||
|
if !ok || !strings.HasPrefix(sub, "src/") || strings.Contains(sub, "/testdata/") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
vendor := joinPath(root, sub, "vendor")
|
||||||
|
if isDir(vendor) {
|
||||||
|
dir := joinPath(vendor, path)
|
||||||
|
if isDir(dir) && hasGoFiles(ctxt, dir) {
|
||||||
|
p.Dir = dir
|
||||||
|
p.ImportPath = strings.TrimPrefix(pathpkg.Join(sub, "vendor", path), "src/")
|
||||||
|
p.Goroot = isGoroot
|
||||||
|
p.Root = root
|
||||||
|
setPkga() // p.ImportPath changed
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
tried.vendor = append(tried.vendor, dir)
|
||||||
|
}
|
||||||
|
i := strings.LastIndex(sub, "/")
|
||||||
|
if i < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
sub = sub[:i]
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ctxt.Compiler != "gccgo" && ctxt.GOROOT != "" && searchVendor(ctxt.GOROOT, true) {
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
for _, root := range gopath {
|
||||||
|
if searchVendor(root, false) {
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine directory from import path.
|
||||||
|
if ctxt.GOROOT != "" {
|
||||||
|
// If the package path starts with "vendor/", only search GOROOT before
|
||||||
|
// GOPATH if the importer is also within GOROOT. That way, if the user has
|
||||||
|
// vendored in a package that is subsequently included in the standard
|
||||||
|
// distribution, they'll continue to pick up their own vendored copy.
|
||||||
|
gorootFirst := srcDir == "" || !strings.HasPrefix(path, "vendor/")
|
||||||
|
if !gorootFirst {
|
||||||
|
_, gorootFirst = hasSubdir(runtime.GOROOT(), srcDir)
|
||||||
|
}
|
||||||
|
if gorootFirst {
|
||||||
|
dir := joinPath(runtime.GOROOT(), "src", path)
|
||||||
|
if ctxt.Compiler != "gccgo" {
|
||||||
|
isDir := isDir(dir)
|
||||||
|
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(runtime.GOROOT(), pkga))
|
||||||
|
if isDir || binaryOnly {
|
||||||
|
p.Dir = dir
|
||||||
|
p.Goroot = true
|
||||||
|
p.Root = runtime.GOROOT()
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tried.goroot = dir
|
||||||
|
}
|
||||||
|
if ctxt.Compiler == "gccgo" && IsStandardPackage(runtime.GOROOT(), ctxt.Compiler, path) {
|
||||||
|
// TODO(bcmills): Setting p.Dir here is misleading, because gccgo
|
||||||
|
// doesn't actually load its standard-library packages from this
|
||||||
|
// directory. See if we can leave it unset.
|
||||||
|
p.Dir = joinPath(runtime.GOROOT(), "src", path)
|
||||||
|
p.Goroot = true
|
||||||
|
p.Root = runtime.GOROOT()
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, root := range gopath {
|
||||||
|
dir := joinPath(root, "src", path)
|
||||||
|
isDir := isDir(dir)
|
||||||
|
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(root, pkga))
|
||||||
|
if isDir || binaryOnly {
|
||||||
|
p.Dir = dir
|
||||||
|
p.Root = root
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
tried.gopath = append(tried.gopath, dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we tried GOPATH first due to a "vendor/" prefix, fall back to GOPATH.
|
||||||
|
// That way, the user can still get useful results from 'go list' for
|
||||||
|
// standard-vendored paths passed on the command line.
|
||||||
|
if runtime.GOROOT() != "" && tried.goroot == "" {
|
||||||
|
dir := joinPath(runtime.GOROOT(), "src", path)
|
||||||
|
if ctxt.Compiler != "gccgo" {
|
||||||
|
isDir := isDir(dir)
|
||||||
|
binaryOnly = !isDir && mode&AllowBinary != 0 && pkga != "" && isFile(joinPath(runtime.GOROOT(), pkga))
|
||||||
|
if isDir || binaryOnly {
|
||||||
|
p.Dir = dir
|
||||||
|
p.Goroot = true
|
||||||
|
p.Root = runtime.GOROOT()
|
||||||
|
goto Found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tried.goroot = dir
|
||||||
|
}
|
||||||
|
|
||||||
|
// package was not found
|
||||||
|
var paths []string
|
||||||
|
format := "\t%s (vendor tree)"
|
||||||
|
for _, dir := range tried.vendor {
|
||||||
|
paths = append(paths, fmt.Sprintf(format, dir))
|
||||||
|
format = "\t%s"
|
||||||
|
}
|
||||||
|
if tried.goroot != "" {
|
||||||
|
paths = append(paths, fmt.Sprintf("\t%s (from $GOROOT)", tried.goroot))
|
||||||
|
} else {
|
||||||
|
paths = append(paths, "\t($GOROOT not set)")
|
||||||
|
}
|
||||||
|
format = "\t%s (from $GOPATH)"
|
||||||
|
for _, dir := range tried.gopath {
|
||||||
|
paths = append(paths, fmt.Sprintf(format, dir))
|
||||||
|
format = "\t%s"
|
||||||
|
}
|
||||||
|
if len(tried.gopath) == 0 {
|
||||||
|
paths = append(paths, "\t($GOPATH not set. For more details see: 'go help gopath')")
|
||||||
|
}
|
||||||
|
return p, fmt.Errorf("cannot find package %q in any of:\n%s", path, strings.Join(paths, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
Found:
|
||||||
|
if p.Root != "" {
|
||||||
|
p.SrcRoot = joinPath(p.Root, "src")
|
||||||
|
p.PkgRoot = joinPath(p.Root, "pkg")
|
||||||
|
p.BinDir = joinPath(p.Root, "bin")
|
||||||
|
if pkga != "" {
|
||||||
|
// Always set PkgTargetRoot. It might be used when building in shared
|
||||||
|
// mode.
|
||||||
|
p.PkgTargetRoot = joinPath(p.Root, pkgtargetroot)
|
||||||
|
|
||||||
|
// Set the install target if applicable.
|
||||||
|
if !p.Goroot || (installgoroot.Value() == "all" && p.ImportPath != "unsafe" && p.ImportPath != "builtin") {
|
||||||
|
if p.Goroot {
|
||||||
|
installgoroot.IncNonDefault()
|
||||||
|
}
|
||||||
|
p.PkgObj = joinPath(p.Root, pkga)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's a local import path, by the time we get here, we still haven't checked
|
||||||
|
// that p.Dir directory exists. This is the right time to do that check.
|
||||||
|
// We can't do it earlier, because we want to gather partial information for the
|
||||||
|
// non-nil *Package returned when an error occurs.
|
||||||
|
// We need to do this before we return early on FindOnly flag.
|
||||||
|
if IsLocalImport(path) && !isDir(p.Dir) {
|
||||||
|
if ctxt.Compiler == "gccgo" && p.Goroot {
|
||||||
|
// gccgo has no sources for GOROOT packages.
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// package was not found
|
||||||
|
return p, fmt.Errorf("cannot find package %q in:\n\t%s", p.ImportPath, p.Dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode&FindOnly != 0 {
|
||||||
|
return p, pkgerr
|
||||||
|
}
|
||||||
|
if binaryOnly && (mode&AllowBinary) != 0 {
|
||||||
|
return p, pkgerr
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctxt.Compiler == "gccgo" && p.Goroot {
|
||||||
|
// gccgo has no sources for GOROOT packages.
|
||||||
|
return p, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dirs, err := readDir(p.Dir)
|
||||||
|
if err != nil {
|
||||||
|
return p, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var badGoError error
|
||||||
|
badGoFiles := make(map[string]bool)
|
||||||
|
badGoFile := func(name string, err error) {
|
||||||
|
if badGoError == nil {
|
||||||
|
badGoError = err
|
||||||
|
}
|
||||||
|
if !badGoFiles[name] {
|
||||||
|
p.InvalidGoFiles = append(p.InvalidGoFiles, name)
|
||||||
|
badGoFiles[name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var Sfiles []string // files with ".S"(capital S)/.sx(capital s equivalent for case insensitive filesystems)
|
||||||
|
var firstFile, firstCommentFile string
|
||||||
|
embedPos := make(map[string][]token.Position)
|
||||||
|
testEmbedPos := make(map[string][]token.Position)
|
||||||
|
xTestEmbedPos := make(map[string][]token.Position)
|
||||||
|
importPos := make(map[string][]token.Position)
|
||||||
|
testImportPos := make(map[string][]token.Position)
|
||||||
|
xTestImportPos := make(map[string][]token.Position)
|
||||||
|
allTags := make(map[string]bool)
|
||||||
|
fset := token.NewFileSet()
|
||||||
|
for _, d := range dirs {
|
||||||
|
if d.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.Type() == fs.ModeSymlink {
|
||||||
|
if isDir(joinPath(p.Dir, d.Name())) {
|
||||||
|
// Symlinks to directories are not source files.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := d.Name()
|
||||||
|
ext := nameExt(name)
|
||||||
|
|
||||||
|
info, err := matchFile(ctxt, p.Dir, name, allTags, &p.BinaryOnly, fset)
|
||||||
|
if err != nil && strings.HasSuffix(name, ".go") {
|
||||||
|
badGoFile(name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if info == nil {
|
||||||
|
if strings.HasPrefix(name, "_") || strings.HasPrefix(name, ".") {
|
||||||
|
// not due to build constraints - don't report
|
||||||
|
} else if ext == ".go" {
|
||||||
|
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
|
||||||
|
} else if fileListForExt(p, ext) != nil {
|
||||||
|
p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, name)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Going to save the file. For non-Go files, can stop here.
|
||||||
|
switch ext {
|
||||||
|
case ".go":
|
||||||
|
// keep going
|
||||||
|
case ".S", ".sx":
|
||||||
|
// special case for cgo, handled at end
|
||||||
|
Sfiles = append(Sfiles, name)
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
if list := fileListForExt(p, ext); list != nil {
|
||||||
|
*list = append(*list, name)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
data, filename := info.header, info.name
|
||||||
|
|
||||||
|
if info.parseErr != nil {
|
||||||
|
badGoFile(name, info.parseErr)
|
||||||
|
// Fall through: we might still have a partial AST in info.parsed,
|
||||||
|
// and we want to list files with parse errors anyway.
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkg string
|
||||||
|
if info.parsed != nil {
|
||||||
|
pkg = info.parsed.Name.Name
|
||||||
|
if pkg == "documentation" {
|
||||||
|
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isTest := strings.HasSuffix(name, "_test.go")
|
||||||
|
isXTest := false
|
||||||
|
if isTest && strings.HasSuffix(pkg, "_test") && p.Name != pkg {
|
||||||
|
isXTest = true
|
||||||
|
pkg = pkg[:len(pkg)-len("_test")]
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.Name == "" {
|
||||||
|
p.Name = pkg
|
||||||
|
firstFile = name
|
||||||
|
} else if pkg != p.Name {
|
||||||
|
// TODO(#45999): The choice of p.Name is arbitrary based on file iteration
|
||||||
|
// order. Instead of resolving p.Name arbitrarily, we should clear out the
|
||||||
|
// existing name and mark the existing files as also invalid.
|
||||||
|
badGoFile(name, &MultiplePackageError{
|
||||||
|
Dir: p.Dir,
|
||||||
|
Packages: []string{p.Name, pkg},
|
||||||
|
Files: []string{firstFile, name},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Grab the first package comment as docs, provided it is not from a test file.
|
||||||
|
if info.parsed != nil && info.parsed.Doc != nil && p.Doc == "" && !isTest && !isXTest {
|
||||||
|
p.Doc = doc.Synopsis(info.parsed.Doc.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode&ImportComment != 0 {
|
||||||
|
qcom, line := findImportComment(data)
|
||||||
|
if line != 0 {
|
||||||
|
com, err := strconv.Unquote(qcom)
|
||||||
|
if err != nil {
|
||||||
|
badGoFile(name, fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
|
||||||
|
} else if p.ImportComment == "" {
|
||||||
|
p.ImportComment = com
|
||||||
|
firstCommentFile = name
|
||||||
|
} else if p.ImportComment != com {
|
||||||
|
badGoFile(name, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record imports and information about cgo.
|
||||||
|
isCgo := false
|
||||||
|
for _, imp := range info.imports {
|
||||||
|
if imp.path == "C" {
|
||||||
|
if isTest {
|
||||||
|
badGoFile(name, fmt.Errorf("use of cgo in test %s not supported", filename))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isCgo = true
|
||||||
|
if imp.doc != nil {
|
||||||
|
if err := saveCgo(ctxt, filename, p, imp.doc); err != nil {
|
||||||
|
badGoFile(name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileList *[]string
|
||||||
|
var importMap, embedMap map[string][]token.Position
|
||||||
|
var directives *[]Directive
|
||||||
|
switch {
|
||||||
|
case isCgo:
|
||||||
|
allTags["cgo"] = true
|
||||||
|
if ctxt.CgoEnabled {
|
||||||
|
fileList = &p.CgoFiles
|
||||||
|
importMap = importPos
|
||||||
|
embedMap = embedPos
|
||||||
|
directives = &p.Directives
|
||||||
|
} else {
|
||||||
|
// Ignore imports and embeds from cgo files if cgo is disabled.
|
||||||
|
fileList = &p.IgnoredGoFiles
|
||||||
|
}
|
||||||
|
case isXTest:
|
||||||
|
fileList = &p.XTestGoFiles
|
||||||
|
importMap = xTestImportPos
|
||||||
|
embedMap = xTestEmbedPos
|
||||||
|
directives = &p.XTestDirectives
|
||||||
|
case isTest:
|
||||||
|
fileList = &p.TestGoFiles
|
||||||
|
importMap = testImportPos
|
||||||
|
embedMap = testEmbedPos
|
||||||
|
directives = &p.TestDirectives
|
||||||
|
default:
|
||||||
|
fileList = &p.GoFiles
|
||||||
|
importMap = importPos
|
||||||
|
embedMap = embedPos
|
||||||
|
directives = &p.Directives
|
||||||
|
}
|
||||||
|
*fileList = append(*fileList, name)
|
||||||
|
if importMap != nil {
|
||||||
|
for _, imp := range info.imports {
|
||||||
|
importMap[imp.path] = append(importMap[imp.path], fset.Position(imp.pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if embedMap != nil {
|
||||||
|
for _, emb := range info.embeds {
|
||||||
|
embedMap[emb.pattern] = append(embedMap[emb.pattern], emb.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if directives != nil {
|
||||||
|
*directives = append(*directives, info.directives...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for tag := range allTags {
|
||||||
|
p.AllTags = append(p.AllTags, tag)
|
||||||
|
}
|
||||||
|
slices.Sort(p.AllTags)
|
||||||
|
|
||||||
|
p.EmbedPatterns, p.EmbedPatternPos = cleanDecls(embedPos)
|
||||||
|
p.TestEmbedPatterns, p.TestEmbedPatternPos = cleanDecls(testEmbedPos)
|
||||||
|
p.XTestEmbedPatterns, p.XTestEmbedPatternPos = cleanDecls(xTestEmbedPos)
|
||||||
|
|
||||||
|
p.Imports, p.ImportPos = cleanDecls(importPos)
|
||||||
|
p.TestImports, p.TestImportPos = cleanDecls(testImportPos)
|
||||||
|
p.XTestImports, p.XTestImportPos = cleanDecls(xTestImportPos)
|
||||||
|
|
||||||
|
// add the .S/.sx files only if we are using cgo
|
||||||
|
// (which means gcc will compile them).
|
||||||
|
// The standard assemblers expect .s files.
|
||||||
|
if len(p.CgoFiles) > 0 {
|
||||||
|
p.SFiles = append(p.SFiles, Sfiles...)
|
||||||
|
slices.Sort(p.SFiles)
|
||||||
|
} else {
|
||||||
|
p.IgnoredOtherFiles = append(p.IgnoredOtherFiles, Sfiles...)
|
||||||
|
slices.Sort(p.IgnoredOtherFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
if badGoError != nil {
|
||||||
|
return p, badGoError
|
||||||
|
}
|
||||||
|
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
|
||||||
|
return p, &NoGoError{p.Dir}
|
||||||
|
}
|
||||||
|
return p, pkgerr
|
||||||
|
}
|
||||||
206
cl/_testdefer/gobuild/out.txt
Normal file
206
cl/_testdefer/gobuild/out.txt
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
0: always
|
||||||
|
1: cond
|
||||||
|
2: cond
|
||||||
|
3: cond
|
||||||
|
4: cond
|
||||||
|
6: cond
|
||||||
|
8: cond
|
||||||
|
7: cond
|
||||||
|
9: cond
|
||||||
|
5: cond
|
||||||
|
10: cond
|
||||||
|
11: cond
|
||||||
|
12: cond
|
||||||
|
13: cond
|
||||||
|
33: cond
|
||||||
|
34: cond
|
||||||
|
14: cond
|
||||||
|
35: cond
|
||||||
|
15: cond
|
||||||
|
36: cond
|
||||||
|
37: cond
|
||||||
|
16: cond
|
||||||
|
40: cond
|
||||||
|
19: cond
|
||||||
|
38: cond
|
||||||
|
17: cond
|
||||||
|
18: cond
|
||||||
|
43: cond
|
||||||
|
42: cond
|
||||||
|
41: cond
|
||||||
|
21: loop
|
||||||
|
22: loop
|
||||||
|
24: loop
|
||||||
|
23: cond
|
||||||
|
27: cond
|
||||||
|
25: cond
|
||||||
|
28: cond
|
||||||
|
26: cond
|
||||||
|
29: loop
|
||||||
|
30: loop
|
||||||
|
31: cond
|
||||||
|
32: cond
|
||||||
|
44: loop
|
||||||
|
45: loop
|
||||||
|
39: cond
|
||||||
|
46: cond
|
||||||
|
48: cond
|
||||||
|
49: cond
|
||||||
|
50: cond
|
||||||
|
51: cond
|
||||||
|
52: cond
|
||||||
|
54: cond
|
||||||
|
59: cond
|
||||||
|
58: cond
|
||||||
|
56: cond
|
||||||
|
57: cond
|
||||||
|
61: cond
|
||||||
|
60: cond
|
||||||
|
55: cond
|
||||||
|
53: cond
|
||||||
|
63: cond
|
||||||
|
62: cond
|
||||||
|
47: cond
|
||||||
|
64: loop
|
||||||
|
65: loop
|
||||||
|
68: loop
|
||||||
|
73: loop
|
||||||
|
72: loop
|
||||||
|
66: cond
|
||||||
|
70: cond
|
||||||
|
71: cond
|
||||||
|
76: cond
|
||||||
|
69: cond
|
||||||
|
74: cond
|
||||||
|
67: cond
|
||||||
|
77: cond
|
||||||
|
82: cond
|
||||||
|
81: cond
|
||||||
|
79: cond
|
||||||
|
80: cond
|
||||||
|
84: cond
|
||||||
|
83: cond
|
||||||
|
78: cond
|
||||||
|
20: cond
|
||||||
|
75: cond
|
||||||
|
96: cond
|
||||||
|
98: cond
|
||||||
|
100: cond
|
||||||
|
102: cond
|
||||||
|
101: cond
|
||||||
|
99: cond
|
||||||
|
103: cond
|
||||||
|
104: cond
|
||||||
|
97: cond
|
||||||
|
107: cond
|
||||||
|
106: cond
|
||||||
|
105: cond
|
||||||
|
111: cond
|
||||||
|
112: cond
|
||||||
|
110: cond
|
||||||
|
115: cond
|
||||||
|
108: cond
|
||||||
|
109: cond
|
||||||
|
113: cond
|
||||||
|
114: cond
|
||||||
|
118: cond
|
||||||
|
116: cond
|
||||||
|
117: cond
|
||||||
|
119: cond
|
||||||
|
120: cond
|
||||||
|
85: loop
|
||||||
|
86: loop
|
||||||
|
87: cond
|
||||||
|
88: cond
|
||||||
|
90: cond
|
||||||
|
89: cond
|
||||||
|
91: loop
|
||||||
|
92: loop
|
||||||
|
93: cond
|
||||||
|
94: cond
|
||||||
|
95: cond
|
||||||
|
121: loop
|
||||||
|
122: loop
|
||||||
|
123: cond
|
||||||
|
124: cond
|
||||||
|
125: cond
|
||||||
|
126: cond
|
||||||
|
129: cond
|
||||||
|
127: cond
|
||||||
|
128: cond
|
||||||
|
130: cond
|
||||||
|
131: cond
|
||||||
|
133: cond
|
||||||
|
137: cond
|
||||||
|
139: cond
|
||||||
|
132: cond
|
||||||
|
143: cond
|
||||||
|
140: cond
|
||||||
|
134: cond
|
||||||
|
135: cond
|
||||||
|
144: cond
|
||||||
|
138: cond
|
||||||
|
141: cond
|
||||||
|
136: cond
|
||||||
|
145: cond
|
||||||
|
142: cond
|
||||||
|
147: cond
|
||||||
|
146: cond
|
||||||
|
151: cond
|
||||||
|
150: cond
|
||||||
|
148: cond
|
||||||
|
149: cond
|
||||||
|
152: cond
|
||||||
|
154: cond
|
||||||
|
155: cond
|
||||||
|
153: cond
|
||||||
|
161: cond
|
||||||
|
160: cond
|
||||||
|
159: cond
|
||||||
|
158: cond
|
||||||
|
156: cond
|
||||||
|
157: cond
|
||||||
|
162: cond
|
||||||
|
164: cond
|
||||||
|
165: cond
|
||||||
|
166: cond
|
||||||
|
167: cond
|
||||||
|
168: cond
|
||||||
|
169: cond
|
||||||
|
163: cond
|
||||||
|
170: loop
|
||||||
|
171: loop
|
||||||
|
173: loop
|
||||||
|
174: loop
|
||||||
|
172: cond
|
||||||
|
175: cond
|
||||||
|
179: cond
|
||||||
|
181: cond
|
||||||
|
176: cond
|
||||||
|
182: cond
|
||||||
|
183: cond
|
||||||
|
180: cond
|
||||||
|
185: cond
|
||||||
|
177: cond
|
||||||
|
184: cond
|
||||||
|
186: cond
|
||||||
|
178: cond
|
||||||
|
187: cond
|
||||||
|
189: loop
|
||||||
|
190: loop
|
||||||
|
188: cond
|
||||||
|
191: cond
|
||||||
|
193: loop
|
||||||
|
194: loop
|
||||||
|
192: cond
|
||||||
|
195: cond
|
||||||
|
196: loop
|
||||||
|
197: loop
|
||||||
|
198: cond
|
||||||
|
199: cond
|
||||||
|
201: cond
|
||||||
|
200: cond
|
||||||
|
202: cond
|
||||||
|
203: cond
|
||||||
|
204: cond
|
||||||
|
205: cond
|
||||||
@@ -60,11 +60,14 @@ func findLoop(states []*blockState, path []int, from, iblk int) []int {
|
|||||||
path = append(path, iblk)
|
path = append(path, iblk)
|
||||||
self := states[iblk]
|
self := states[iblk]
|
||||||
for _, succ := range self.succs {
|
for _, succ := range self.succs {
|
||||||
if states[succ].fdel {
|
if s := states[succ]; s.fdel || s.loop {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pos := find(path, succ); pos >= 0 {
|
if pos := find(path, succ); pos >= 0 {
|
||||||
if pos > 0 {
|
if pos > 0 {
|
||||||
|
for _, i := range path[pos:] { // mark inner loop
|
||||||
|
states[i].loop = true
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, i := range path {
|
for _, i := range path {
|
||||||
@@ -72,6 +75,11 @@ func findLoop(states []*blockState, path []int, from, iblk int) []int {
|
|||||||
s.loop = true
|
s.loop = true
|
||||||
s.fdel = true
|
s.fdel = true
|
||||||
}
|
}
|
||||||
|
for _, s := range states { // clear inner loop mark
|
||||||
|
if !s.fdel {
|
||||||
|
s.loop = false
|
||||||
|
}
|
||||||
|
}
|
||||||
return path
|
return path
|
||||||
}
|
}
|
||||||
if ret := findLoop(states, path, from, succ); len(ret) > 0 {
|
if ret := findLoop(states, path, from, succ); len(ret) > 0 {
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ func TestTestdefer(t *testing.T) {
|
|||||||
if strings.HasPrefix(name, "firstloop") {
|
if strings.HasPrefix(name, "firstloop") {
|
||||||
return "Loop"
|
return "Loop"
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(name, "gobuild") {
|
||||||
|
return "Import"
|
||||||
|
}
|
||||||
return "main"
|
return "main"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
26
cmd/llgo/build_cmd.gox
Normal file
26
cmd/llgo/build_cmd.gox
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
self "github.com/goplus/llgo/cmd/internal/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Compile packages and dependencies"
|
||||||
|
|
||||||
|
flagOff
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
self.Cmd.Run self.Cmd, args
|
||||||
|
}
|
||||||
26
cmd/llgo/clean_cmd.gox
Normal file
26
cmd/llgo/clean_cmd.gox
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
self "github.com/goplus/llgo/cmd/internal/clean"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Remove object files and cached files"
|
||||||
|
|
||||||
|
flagOff
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
self.Cmd.Run self.Cmd, args
|
||||||
|
}
|
||||||
26
cmd/llgo/cmptest_cmd.gox
Normal file
26
cmd/llgo/cmptest_cmd.gox
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
self "github.com/goplus/llgo/cmd/internal/run"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Compile and run with llgo, compare result (stdout/stderr/exitcode) with go or llgo.expect; generate llgo.expect file if -gen is specified"
|
||||||
|
|
||||||
|
flagOff
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
self.CmpTestCmd.Run self.CmpTestCmd, args
|
||||||
|
}
|
||||||
20
cmd/llgo/cppkg_cmd.gox
Normal file
20
cmd/llgo/cppkg_cmd.gox
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
short "Manage C/C++ packages"
|
||||||
|
|
||||||
|
run => {
|
||||||
|
help
|
||||||
|
}
|
||||||
36
cmd/llgo/cppkg_install_cmd.gox
Normal file
36
cmd/llgo/cppkg_install_cmd.gox
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
self "github.com/goplus/llgo/xtool/cppkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Install a C/C++ package from github.com/goplus/cppkg"
|
||||||
|
|
||||||
|
long `Installs a C/C++ package with the given name and version. For example:
|
||||||
|
|
||||||
|
llgo cppkg install davegamble/cjson@1.7.18
|
||||||
|
llgo cppkg install davegamble/cjson@latest
|
||||||
|
llgo cppkg install davegamble/cjson
|
||||||
|
`
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
if args.len < 1 {
|
||||||
|
help
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.install args[0], self.DefaultFlags
|
||||||
|
}
|
||||||
20
cmd/llgo/get_cmd.gox
Normal file
20
cmd/llgo/get_cmd.gox
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
short "Add dependencies to current module and install them"
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
panic "todo"
|
||||||
|
}
|
||||||
247
cmd/llgo/gop_autogen.go
Normal file
247
cmd/llgo/gop_autogen.go
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
// Code generated by gop (Go+); DO NOT EDIT.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/goplus/cobra/xcmd"
|
||||||
|
build1 "github.com/goplus/llgo/cmd/internal/build"
|
||||||
|
clean1 "github.com/goplus/llgo/cmd/internal/clean"
|
||||||
|
install1 "github.com/goplus/llgo/cmd/internal/install"
|
||||||
|
run1 "github.com/goplus/llgo/cmd/internal/run"
|
||||||
|
test1 "github.com/goplus/llgo/cmd/internal/test"
|
||||||
|
"github.com/goplus/llgo/internal/env"
|
||||||
|
cppkg1 "github.com/goplus/llgo/xtool/cppkg"
|
||||||
|
"github.com/qiniu/x/stringutil"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
const _ = true
|
||||||
|
|
||||||
|
type build struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type clean struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type cmptest struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type cppkg struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type cppkg_install struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type get struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type install struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type run struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type test struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type version struct {
|
||||||
|
xcmd.Command
|
||||||
|
*App
|
||||||
|
}
|
||||||
|
type App struct {
|
||||||
|
xcmd.App
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *App) Main() {
|
||||||
|
_gop_obj0 := &build{App: this}
|
||||||
|
_gop_obj1 := &clean{App: this}
|
||||||
|
_gop_obj2 := &cmptest{App: this}
|
||||||
|
_gop_obj3 := &cppkg{App: this}
|
||||||
|
_gop_obj4 := &cppkg_install{App: this}
|
||||||
|
_gop_obj5 := &get{App: this}
|
||||||
|
_gop_obj6 := &install{App: this}
|
||||||
|
_gop_obj7 := &run{App: this}
|
||||||
|
_gop_obj8 := &test{App: this}
|
||||||
|
_gop_obj9 := &version{App: this}
|
||||||
|
xcmd.Gopt_App_Main(this, _gop_obj0, _gop_obj1, _gop_obj2, _gop_obj3, _gop_obj4, _gop_obj5, _gop_obj6, _gop_obj7, _gop_obj8, _gop_obj9)
|
||||||
|
}
|
||||||
|
//line cmd/llgo/build_cmd.gox:20
|
||||||
|
func (this *build) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/build_cmd.gox:20:1
|
||||||
|
this.Short("Compile packages and dependencies")
|
||||||
|
//line cmd/llgo/build_cmd.gox:22:1
|
||||||
|
this.FlagOff()
|
||||||
|
//line cmd/llgo/build_cmd.gox:24:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/build_cmd.gox:25:1
|
||||||
|
build1.Cmd.Run(build1.Cmd, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *build) Classfname() string {
|
||||||
|
return "build"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/clean_cmd.gox:20
|
||||||
|
func (this *clean) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/clean_cmd.gox:20:1
|
||||||
|
this.Short("Remove object files and cached files")
|
||||||
|
//line cmd/llgo/clean_cmd.gox:22:1
|
||||||
|
this.FlagOff()
|
||||||
|
//line cmd/llgo/clean_cmd.gox:24:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/clean_cmd.gox:25:1
|
||||||
|
clean1.Cmd.Run(clean1.Cmd, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *clean) Classfname() string {
|
||||||
|
return "clean"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/cmptest_cmd.gox:20
|
||||||
|
func (this *cmptest) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/cmptest_cmd.gox:20:1
|
||||||
|
this.Short("Compile and run with llgo, compare result (stdout/stderr/exitcode) with go or llgo.expect; generate llgo.expect file if -gen is specified")
|
||||||
|
//line cmd/llgo/cmptest_cmd.gox:22:1
|
||||||
|
this.FlagOff()
|
||||||
|
//line cmd/llgo/cmptest_cmd.gox:24:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/cmptest_cmd.gox:25:1
|
||||||
|
run1.CmpTestCmd.Run(run1.CmpTestCmd, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *cmptest) Classfname() string {
|
||||||
|
return "cmptest"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/cppkg_cmd.gox:16
|
||||||
|
func (this *cppkg) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/cppkg_cmd.gox:16:1
|
||||||
|
this.Short("Manage C/C++ packages")
|
||||||
|
//line cmd/llgo/cppkg_cmd.gox:18:1
|
||||||
|
this.Run__0(func() {
|
||||||
|
//line cmd/llgo/cppkg_cmd.gox:19:1
|
||||||
|
this.Help()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *cppkg) Classfname() string {
|
||||||
|
return "cppkg"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:20
|
||||||
|
func (this *cppkg_install) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:20:1
|
||||||
|
this.Short("Install a C/C++ package from github.com/goplus/cppkg")
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:22:1
|
||||||
|
this.Long(`Installs a C/C++ package with the given name and version. For example:
|
||||||
|
|
||||||
|
llgo cppkg install davegamble/cjson@1.7.18
|
||||||
|
llgo cppkg install davegamble/cjson@latest
|
||||||
|
llgo cppkg install davegamble/cjson
|
||||||
|
`)
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:29:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:30:1
|
||||||
|
if len(args) < 1 {
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:31:1
|
||||||
|
this.Help()
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:32:1
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//line cmd/llgo/cppkg_install_cmd.gox:35:1
|
||||||
|
cppkg1.Install(args[0], cppkg1.DefaultFlags)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *cppkg_install) Classfname() string {
|
||||||
|
return "cppkg_install"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/get_cmd.gox:16
|
||||||
|
func (this *get) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/get_cmd.gox:16:1
|
||||||
|
this.Short("Add dependencies to current module and install them")
|
||||||
|
//line cmd/llgo/get_cmd.gox:18:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/get_cmd.gox:19:1
|
||||||
|
panic("todo")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *get) Classfname() string {
|
||||||
|
return "get"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/install_cmd.gox:20
|
||||||
|
func (this *install) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/install_cmd.gox:20:1
|
||||||
|
this.Short("Compile and install packages and dependencies")
|
||||||
|
//line cmd/llgo/install_cmd.gox:22:1
|
||||||
|
this.FlagOff()
|
||||||
|
//line cmd/llgo/install_cmd.gox:24:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/install_cmd.gox:25:1
|
||||||
|
install1.Cmd.Run(install1.Cmd, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *install) Classfname() string {
|
||||||
|
return "install"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/run_cmd.gox:20
|
||||||
|
func (this *run) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/run_cmd.gox:20:1
|
||||||
|
this.Short("Compile and run Go program")
|
||||||
|
//line cmd/llgo/run_cmd.gox:22:1
|
||||||
|
this.FlagOff()
|
||||||
|
//line cmd/llgo/run_cmd.gox:24:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/run_cmd.gox:25:1
|
||||||
|
run1.Cmd.Run(run1.Cmd, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *run) Classfname() string {
|
||||||
|
return "run"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/test_cmd.gox:20
|
||||||
|
func (this *test) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/test_cmd.gox:20:1
|
||||||
|
this.Short("Compile and run Go test")
|
||||||
|
//line cmd/llgo/test_cmd.gox:22:1
|
||||||
|
this.FlagOff()
|
||||||
|
//line cmd/llgo/test_cmd.gox:24:1
|
||||||
|
this.Run__1(func(args []string) {
|
||||||
|
//line cmd/llgo/test_cmd.gox:25:1
|
||||||
|
test1.Cmd.Run(test1.Cmd, args)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *test) Classfname() string {
|
||||||
|
return "test"
|
||||||
|
}
|
||||||
|
//line cmd/llgo/version_cmd.gox:22
|
||||||
|
func (this *version) Main(_gop_arg0 string) {
|
||||||
|
this.Command.Main(_gop_arg0)
|
||||||
|
//line cmd/llgo/version_cmd.gox:22:1
|
||||||
|
this.Short("Print LLGo version")
|
||||||
|
//line cmd/llgo/version_cmd.gox:24:1
|
||||||
|
this.Run__0(func() {
|
||||||
|
//line cmd/llgo/version_cmd.gox:25:1
|
||||||
|
fmt.Println(stringutil.Concat("llgo ", env.Version(), " ", runtime.GOOS, "/", runtime.GOARCH))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
func (this *version) Classfname() string {
|
||||||
|
return "version"
|
||||||
|
}
|
||||||
|
func main() {
|
||||||
|
//line cmd/llgo/version_cmd.gox:24:1
|
||||||
|
new(App).Main()
|
||||||
|
}
|
||||||
26
cmd/llgo/install_cmd.gox
Normal file
26
cmd/llgo/install_cmd.gox
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
self "github.com/goplus/llgo/cmd/internal/install"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Compile and install packages and dependencies"
|
||||||
|
|
||||||
|
flagOff
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
self.Cmd.Run self.Cmd, args
|
||||||
|
}
|
||||||
26
cmd/llgo/run_cmd.gox
Normal file
26
cmd/llgo/run_cmd.gox
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
self "github.com/goplus/llgo/cmd/internal/run"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Compile and run Go program"
|
||||||
|
|
||||||
|
flagOff
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
self.Cmd.Run self.Cmd, args
|
||||||
|
}
|
||||||
26
cmd/llgo/test_cmd.gox
Normal file
26
cmd/llgo/test_cmd.gox
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
self "github.com/goplus/llgo/cmd/internal/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Compile and run Go test"
|
||||||
|
|
||||||
|
flagOff
|
||||||
|
|
||||||
|
run args => {
|
||||||
|
self.Cmd.Run self.Cmd, args
|
||||||
|
}
|
||||||
26
cmd/llgo/version_cmd.gox
Normal file
26
cmd/llgo/version_cmd.gox
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/goplus/llgo/internal/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
short "Print LLGo version"
|
||||||
|
|
||||||
|
run => {
|
||||||
|
echo "llgo ${env.version} ${runtime.GOOS}/${runtime.GOARCH}"
|
||||||
|
}
|
||||||
12
go.mod
12
go.mod
@@ -5,18 +5,18 @@ go 1.22.0
|
|||||||
toolchain go1.24.1
|
toolchain go1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/goplus/gogen v1.17.2
|
github.com/goccy/go-yaml v1.17.1
|
||||||
|
github.com/goplus/cobra v1.9.8 //gop:class
|
||||||
|
github.com/goplus/gogen v1.17.3
|
||||||
github.com/goplus/lib v0.2.0
|
github.com/goplus/lib v0.2.0
|
||||||
github.com/goplus/llgo/runtime v0.0.0-20250403035532-0a8a4eb6a653
|
github.com/goplus/llgo/runtime v0.0.0-00010101000000-000000000000
|
||||||
github.com/goplus/llvm v0.8.3
|
github.com/goplus/llvm v0.8.3
|
||||||
github.com/goplus/mod v0.16.0
|
github.com/goplus/mod v0.16.0
|
||||||
github.com/qiniu/x v1.13.19
|
github.com/qiniu/x v1.13.19
|
||||||
|
golang.org/x/mod v0.23.0
|
||||||
golang.org/x/tools v0.30.0
|
golang.org/x/tools v0.30.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require golang.org/x/sync v0.11.0 // indirect
|
||||||
golang.org/x/mod v0.23.0 // indirect
|
|
||||||
golang.org/x/sync v0.11.0 // indirect
|
|
||||||
)
|
|
||||||
|
|
||||||
replace github.com/goplus/llgo/runtime => ./runtime
|
replace github.com/goplus/llgo/runtime => ./runtime
|
||||||
|
|||||||
8
go.sum
8
go.sum
@@ -1,7 +1,11 @@
|
|||||||
|
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||||
|
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/goplus/gogen v1.17.2 h1:oQDWiVzZmDAdgNieJnrvrWTmxDTqYXGFMBa2rAbwjmA=
|
github.com/goplus/cobra v1.9.8 h1:4ZvhxUepT35vreZdxjl/bwnJdwhWyWCGnc60+v22x14=
|
||||||
github.com/goplus/gogen v1.17.2/go.mod h1:owX2e1EyU5WD+Nm6oH2m/GXjLdlBYcwkLO4wN8HHXZI=
|
github.com/goplus/cobra v1.9.8/go.mod h1:p4LhfNJDKEpiGjGiNn0crUXL5dUPA5DX2ztYpEJR34E=
|
||||||
|
github.com/goplus/gogen v1.17.3 h1:Xhoj2KQw4feRdPEtOYjTUe9lSvNIoxBG4urhdjf+fUg=
|
||||||
|
github.com/goplus/gogen v1.17.3/go.mod h1:owX2e1EyU5WD+Nm6oH2m/GXjLdlBYcwkLO4wN8HHXZI=
|
||||||
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
github.com/goplus/lib v0.2.0 h1:AjqkN1XK5H23wZMMlpaUYAMCDAdSBQ2NMFrLtSh7W4g=
|
||||||
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
github.com/goplus/lib v0.2.0/go.mod h1:SgJv3oPqLLHCu0gcL46ejOP3x7/2ry2Jtxu7ta32kp0=
|
||||||
github.com/goplus/llvm v0.8.3 h1:is1zOwhiQZWtLnOmSMVPO+1sPa2uK/XJ/FjTSfIjGBU=
|
github.com/goplus/llvm v0.8.3 h1:is1zOwhiQZWtLnOmSMVPO+1sPa2uK/XJ/FjTSfIjGBU=
|
||||||
|
|||||||
76
internal/github/commit.go
Normal file
76
internal/github/commit.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Author represents a github user or bot.
|
||||||
|
type Author struct {
|
||||||
|
Login string `json:"login"` // github-actions[bot]
|
||||||
|
ID int `json:"id"` // 41898282
|
||||||
|
NodeID string `json:"node_id"` // MDM6Qm90NDE4OTgyODI=
|
||||||
|
AvatarURL string `json:"avatar_url"` // https://avatars.githubusercontent.com/in/15368?v=4
|
||||||
|
URL string `json:"url"` // https://api.github.com/users/github-actions%5Bbot%5D
|
||||||
|
HtmlURL string `json:"html_url"` // https://github.com/apps/github-actions
|
||||||
|
Type string `json:"type"` // Bot
|
||||||
|
SiteAdmin bool `json:"site_admin"` // false
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitAuthor represents the author of a GitHub commit.
|
||||||
|
type CommitAuthor struct {
|
||||||
|
Name string `json:"name"` // xushiwei
|
||||||
|
Email string `json:"email"` // x@goplus.org
|
||||||
|
Date string `json:"date"` // 2025-04-21T14:13:29Z
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitSummary represents the summary of a GitHub commit.
|
||||||
|
type CommitSummary struct {
|
||||||
|
Author CommitAuthor `json:"author"`
|
||||||
|
Message string `json:"message"` // Merge pull request #2296 from goplus/main\n\nv1.4.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommitDetail represents the details of a GitHub commit.
|
||||||
|
type CommitDetail struct {
|
||||||
|
NodeID string `json:"node_id"` // C_kwDOAtpGOtoAKDE2OGEwODlmOWY5ZTNhNDdhMTliMTRjZDczODQ4N2M2ZTJkMTMxYmE
|
||||||
|
Commit CommitSummary `json:"commit"`
|
||||||
|
Author Author `json:"author"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func commitURL(pkgPath, sha string) string {
|
||||||
|
return "https://api.github.com/repos/" + pkgPath + "/commits/" + sha
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommit retrieves the details of a specific commit from a GitHub repository.
|
||||||
|
func GetCommit(pkgPath, shaOrURL string) (ret *CommitDetail, err error) {
|
||||||
|
url := shaOrURL
|
||||||
|
if !strings.HasPrefix(shaOrURL, "https://") {
|
||||||
|
url = commitURL(pkgPath, shaOrURL)
|
||||||
|
}
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
ret = new(CommitDetail)
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
75
internal/github/release.go
Normal file
75
internal/github/release.go
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReleaseAsset represents a GitHub release asset.
|
||||||
|
type ReleaseAsset struct {
|
||||||
|
URL string `json:"url"` // https://api.github.com/repos/flintlib/flint/releases/assets/242245930
|
||||||
|
ID int `json:"id"` // 242245930
|
||||||
|
NodeID string `json:"node_id"` // RA_kwDOAC8YHs4OcGEq
|
||||||
|
Name string `json:"name"` // flint-3.2.2.tar.gz
|
||||||
|
ContentType string `json:"content_type"` // application/x-gtar
|
||||||
|
State string `json:"state"` // uploaded
|
||||||
|
Size int64 `json:"size"` // 123456
|
||||||
|
DownloadCount int `json:"download_count"` // 176
|
||||||
|
UpdatedAt string `json:"updated_at"` // 2025-03-31T08:54:16Z
|
||||||
|
BrowserDownloadURL string `json:"browser_download_url"` // https://github.com/flintlib/flint/releases/download/v3.2.2/flint-3.2.2.tar.gz
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release represents a GitHub release.
|
||||||
|
type Release struct {
|
||||||
|
URL string `json:"url"` // https://api.github.com/repos/flintlib/flint/releases/209285187
|
||||||
|
ID int `json:"id"` // 209285187
|
||||||
|
NodeID string `json:"node_id"` // RE_kwDOAC8YHs4MeXBD
|
||||||
|
TagName string `json:"tag_name"` // v3.2.2
|
||||||
|
TargetCommitish string `json:"target_commitish"` // b8223680e38ad048355a421bf7f617bb6c5d5e12
|
||||||
|
Name string `json:"name"` // FLINT v3.2.2
|
||||||
|
PublishedAt string `json:"published_at"` // 2025-03-31T08:54:16Z
|
||||||
|
Body string `json:"body"` // Release Notes
|
||||||
|
TarballURL string `json:"tarball_url"` // https://api.github.com/repos/flintlib/flint/tarball/v3.2.2
|
||||||
|
ZipballURL string `json:"zipball_url"` // https://api.github.com/repos/flintlib/flint/zipball/v3.2.2
|
||||||
|
Author Author `json:"author"`
|
||||||
|
Assets []*ReleaseAsset `json:"assets"`
|
||||||
|
Prerelease bool `json:"prerelease"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// releaseURL constructs the URL for a GitHub release.
|
||||||
|
func releaseURL(pkgPath, ver string) string {
|
||||||
|
if ver == "" || ver == "latest" {
|
||||||
|
return "https://api.github.com/repos/" + pkgPath + "/releases/latest"
|
||||||
|
}
|
||||||
|
return "https://api.github.com/repos/" + pkgPath + "/releases/tags/" + ver
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRelease fetches the release information from GitHub.
|
||||||
|
func GetRelease(pkgPath, ver string) (ret *Release, err error) {
|
||||||
|
url := releaseURL(pkgPath, ver)
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
ret = new(Release)
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(ret)
|
||||||
|
return
|
||||||
|
}
|
||||||
125
internal/github/tag.go
Normal file
125
internal/github/tag.go
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrBreak = errors.New("break")
|
||||||
|
ErrNotFound = errors.New("not found")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Commit represents a commit in a GitHub repository.
|
||||||
|
type Commit struct {
|
||||||
|
SHA string `json:"sha"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tag represents a GitHub tag.
|
||||||
|
type Tag struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
ZipballURL string `json:"zipball_url"`
|
||||||
|
TarballURL string `json:"tarball_url"`
|
||||||
|
Commit Commit `json:"commit"`
|
||||||
|
NodeID string `json:"node_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// tagsURL constructs the URL for fetching tags from a GitHub repository.
|
||||||
|
func tagsURL(pkgPath string) string {
|
||||||
|
return "https://api.github.com/repos/" + pkgPath + "/tags"
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTag retrieves a specific tag from a GitHub repository.
|
||||||
|
func GetTag(pkgPath, ver string) (tag *Tag, err error) {
|
||||||
|
err = ErrNotFound
|
||||||
|
EnumTags(pkgPath, 0, func(tags []*Tag, page, total int) error {
|
||||||
|
for _, t := range tags {
|
||||||
|
if t.Name == ver {
|
||||||
|
tag = t
|
||||||
|
err = nil
|
||||||
|
return ErrBreak
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnumTags enumerates the tags of a GitHub repository.
|
||||||
|
func EnumTags(pkgPath string, page int, pager func(tags []*Tag, page, total int) error) (err error) {
|
||||||
|
total := 0
|
||||||
|
ubase := tagsURL(pkgPath)
|
||||||
|
|
||||||
|
loop:
|
||||||
|
u := ubase
|
||||||
|
if page > 0 {
|
||||||
|
vals := url.Values{"page": []string{strconv.Itoa(page + 1)}}
|
||||||
|
u += "?" + vals.Encode()
|
||||||
|
}
|
||||||
|
resp, err := http.Get(u)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var tags []*Tag
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&tags)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link: <https://api.github.com/repositories/47859258/tags?page=2>; rel="next",
|
||||||
|
// <https://api.github.com/repositories/47859258/tags?page=5>; rel="last"
|
||||||
|
if total == 0 {
|
||||||
|
const relLast = `rel="last"`
|
||||||
|
total = page + 1
|
||||||
|
link := resp.Header.Get("Link")
|
||||||
|
for _, part := range strings.Split(link, ",") {
|
||||||
|
if strings.HasSuffix(part, relLast) {
|
||||||
|
left := strings.TrimSpace(part[:len(part)-len(relLast)])
|
||||||
|
lastUrl := strings.TrimSuffix(strings.TrimPrefix(left, "<"), ">;")
|
||||||
|
if pos := strings.LastIndexByte(lastUrl, '?'); pos >= 0 {
|
||||||
|
if vals, e := url.ParseQuery(lastUrl[pos+1:]); e == nil {
|
||||||
|
if n, e := strconv.Atoi(vals.Get("page")); e == nil {
|
||||||
|
total = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = pager(tags, page, total)
|
||||||
|
if err != nil {
|
||||||
|
if err == ErrBreak {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
page++
|
||||||
|
if page < total {
|
||||||
|
goto loop
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ package sync
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
PthreadOnceSize = 16
|
PthreadOnceSize = 16
|
||||||
PthreadMutexSize = 56
|
PthreadMutexSize = 64
|
||||||
PthreadMutexAttrSize = 8
|
PthreadMutexAttrSize = 8
|
||||||
PthreadCondSize = 40
|
PthreadCondSize = 40
|
||||||
PthreadCondAttrSize = 8
|
PthreadCondAttrSize = 8
|
||||||
|
|||||||
26
runtime/internal/lib/math/big/prime.go
Normal file
26
runtime/internal/lib/math/big/prime.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2016 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 big
|
||||||
|
|
||||||
|
// ProbablyPrime reports whether x is probably prime,
|
||||||
|
// applying the Miller-Rabin test with n pseudorandomly chosen bases
|
||||||
|
// as well as a Baillie-PSW test.
|
||||||
|
//
|
||||||
|
// If x is prime, ProbablyPrime returns true.
|
||||||
|
// If x is chosen randomly and not prime, ProbablyPrime probably returns false.
|
||||||
|
// The probability of returning true for a randomly chosen non-prime is at most ¼ⁿ.
|
||||||
|
//
|
||||||
|
// ProbablyPrime is 100% accurate for inputs less than 2⁶⁴.
|
||||||
|
// See Menezes et al., Handbook of Applied Cryptography, 1997, pp. 145-149,
|
||||||
|
// and FIPS 186-4 Appendix F for further discussion of the error probabilities.
|
||||||
|
//
|
||||||
|
// ProbablyPrime is not suitable for judging primes that an adversary may
|
||||||
|
// have crafted to fool the test.
|
||||||
|
//
|
||||||
|
// As of Go 1.8, ProbablyPrime(0) is allowed and applies only a Baillie-PSW test.
|
||||||
|
// Before Go 1.8, ProbablyPrime applied only the Miller-Rabin tests, and ProbablyPrime(0) panicked.
|
||||||
|
func (x *Int) ProbablyPrime(n int) bool {
|
||||||
|
panic("ProbablyPrime: todo")
|
||||||
|
}
|
||||||
13
runtime/internal/lib/runtime/compiler.go
Normal file
13
runtime/internal/lib/runtime/compiler.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
// Copyright 2012 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 runtime
|
||||||
|
|
||||||
|
// Compiler is the name of the compiler toolchain that built the
|
||||||
|
// running binary. Known toolchains are:
|
||||||
|
//
|
||||||
|
// - gc Also known as cmd/compile.
|
||||||
|
// - gccgo The gccgo front end, part of the GCC compiler suite.
|
||||||
|
// - llgo Our project
|
||||||
|
const Compiler = "llgo"
|
||||||
88
xtool/cppkg/command.go
Normal file
88
xtool/cppkg/command.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cppkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrNotFound is the error resulting if a path search failed to find
|
||||||
|
// an executable file.
|
||||||
|
ErrNotFound = exec.ErrNotFound
|
||||||
|
)
|
||||||
|
|
||||||
|
// Tool represents a tool that can be executed.
|
||||||
|
type Tool struct {
|
||||||
|
cmd string
|
||||||
|
installs [][]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTool creates a new Tool instance with the specified tool and install commands.
|
||||||
|
func NewTool(cmd string, installs []string) *Tool {
|
||||||
|
inst := make([][]string, len(installs))
|
||||||
|
for i, install := range installs {
|
||||||
|
inst[i] = strings.Split(install, " ")
|
||||||
|
}
|
||||||
|
return &Tool{
|
||||||
|
cmd: cmd,
|
||||||
|
installs: inst,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new command with the specified arguments.
|
||||||
|
func (p *Tool) New(quietInstall bool, args ...string) (cmd *exec.Cmd, err error) {
|
||||||
|
app, err := p.Get(quietInstall)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return exec.Command(app, args...), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get retrieves the path of the command.
|
||||||
|
// If the command is not found, it attempts to install it using the specified
|
||||||
|
// install commands.
|
||||||
|
func (p *Tool) Get(quietInstall bool) (app string, err error) {
|
||||||
|
app, err = exec.LookPath(p.cmd)
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
amPath, install, err := p.getAppManager()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c := exec.Command(amPath, install[1:]...)
|
||||||
|
c.Stdout = os.Stdout
|
||||||
|
c.Stderr = os.Stderr
|
||||||
|
if err = c.Run(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return exec.LookPath(p.cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Tool) getAppManager() (amPath string, install []string, err error) {
|
||||||
|
for _, install = range p.installs {
|
||||||
|
am := install[0]
|
||||||
|
if amPath, err = exec.LookPath(am); err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = ErrNotFound
|
||||||
|
return
|
||||||
|
}
|
||||||
300
xtool/cppkg/conan.go
Normal file
300
xtool/cppkg/conan.go
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cppkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/goccy/go-yaml"
|
||||||
|
"github.com/goplus/llgo/internal/github"
|
||||||
|
"github.com/qiniu/x/httputil"
|
||||||
|
)
|
||||||
|
|
||||||
|
var conanCmd = NewTool("conan", []string{
|
||||||
|
"brew install conan",
|
||||||
|
"apt-get install conan",
|
||||||
|
})
|
||||||
|
|
||||||
|
type conandata struct {
|
||||||
|
Sources map[string]any `yaml:"sources"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceVer(src any, fromVer, toVer string) any {
|
||||||
|
switch src := src.(type) {
|
||||||
|
case map[string]any:
|
||||||
|
doReplace(src, fromVer, toVer)
|
||||||
|
case []any:
|
||||||
|
for _, u := range src {
|
||||||
|
doReplace(u.(map[string]any), fromVer, toVer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return src
|
||||||
|
}
|
||||||
|
|
||||||
|
func doReplace(src map[string]any, fromVer, toVer string) {
|
||||||
|
switch url := src["url"].(type) {
|
||||||
|
case string:
|
||||||
|
src["url"] = strings.ReplaceAll(url, fromVer, toVer)
|
||||||
|
delete(src, "sha256")
|
||||||
|
// TODO(xsw): src["sha256"] = hash
|
||||||
|
case []any:
|
||||||
|
for i, u := range url {
|
||||||
|
url[i] = strings.ReplaceAll(u.(string), fromVer, toVer)
|
||||||
|
}
|
||||||
|
delete(src, "sha256")
|
||||||
|
// TODO(xsw): src["sha256"] = hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type githubRelease struct {
|
||||||
|
PublishedAt string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRelease(pkg *Package, tagPattern string) (ret *githubRelease, err error) {
|
||||||
|
if tagPattern == "" {
|
||||||
|
return nil, ErrDynamicTag
|
||||||
|
}
|
||||||
|
if pkg.gr != nil {
|
||||||
|
return &githubRelease{PublishedAt: pkg.gr.PublishedAt}, nil
|
||||||
|
}
|
||||||
|
ver := strings.Replace(tagPattern, "*", pkg.Version, 1)
|
||||||
|
gr, err := github.GetRelease(pkg.Path, ver)
|
||||||
|
if err == nil {
|
||||||
|
ret = &githubRelease{PublishedAt: gr.PublishedAt}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t, err := github.GetTag(pkg.Path, ver)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c, err := github.GetCommit(pkg.Path, t.Commit.URL)
|
||||||
|
if err == nil {
|
||||||
|
ret = &githubRelease{PublishedAt: c.Commit.Author.Date}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install installs the specified package using Conan.
|
||||||
|
func (p *Manager) Install(pkg *Package, flags int) (err error) {
|
||||||
|
outDir := p.outDir(pkg)
|
||||||
|
os.MkdirAll(outDir, os.ModePerm)
|
||||||
|
|
||||||
|
var rev string
|
||||||
|
var gr *githubRelease
|
||||||
|
var conandataYml, conanfilePy []byte
|
||||||
|
|
||||||
|
conanfileDir := p.conanfileDir(pkg.Path, pkg.Folder)
|
||||||
|
pkgVer := pkg.Version
|
||||||
|
template := pkg.Template
|
||||||
|
if template != nil {
|
||||||
|
gr, err = getRelease(pkg, template.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = copyDirR(conanfileDir, outDir)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conanfilePy, err = os.ReadFile(outDir + "/conanfile.py")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conandataFile := outDir + "/conandata.yml"
|
||||||
|
conandataYml, err = os.ReadFile(conandataFile)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var cd conandata
|
||||||
|
err = yaml.Unmarshal(conandataYml, &cd)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fromVer := template.FromVer
|
||||||
|
source, ok := cd.Sources[fromVer]
|
||||||
|
if !ok {
|
||||||
|
return ErrVersionNotFound
|
||||||
|
}
|
||||||
|
cd.Sources = map[string]any{
|
||||||
|
pkgVer: replaceVer(source, fromVer, pkgVer),
|
||||||
|
}
|
||||||
|
conandataYml, err = yaml.Marshal(cd)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = os.WriteFile(conandataFile, conandataYml, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rev = recipeRevision(pkg, gr, conandataYml)
|
||||||
|
conanfileDir = outDir
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile := outDir + "/out.json"
|
||||||
|
out, err := os.Create(outFile)
|
||||||
|
if err == nil {
|
||||||
|
defer out.Close()
|
||||||
|
} else {
|
||||||
|
out = os.Stdout
|
||||||
|
}
|
||||||
|
|
||||||
|
nameAndVer := pkg.Name + "/" + pkgVer
|
||||||
|
if template == nil {
|
||||||
|
return conanInstall(nameAndVer, outDir, conanfileDir, out, flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
logFile := ""
|
||||||
|
if flags&LogRevertProxy != 0 {
|
||||||
|
logFile = outDir + "/rp.log"
|
||||||
|
}
|
||||||
|
return remoteProxy(flags, logFile, func() error {
|
||||||
|
return conanInstall(nameAndVer, outDir, conanfileDir, out, flags)
|
||||||
|
}, func(mux *http.ServeMux) {
|
||||||
|
base := "/v2/conans/" + nameAndVer
|
||||||
|
revbase := base + "/_/_/revisions/" + rev
|
||||||
|
mux.HandleFunc(base+"/_/_/latest", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h := w.Header()
|
||||||
|
h.Set("Cache-Control", "public,max-age=300")
|
||||||
|
httputil.Reply(w, http.StatusOK, map[string]any{
|
||||||
|
"revision": rev,
|
||||||
|
"time": gr.PublishedAt,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
mux.HandleFunc(revbase+"/files", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h := w.Header()
|
||||||
|
h.Set("Cache-Control", "public,max-age=3600")
|
||||||
|
empty := map[string]any{}
|
||||||
|
httputil.Reply(w, http.StatusOK, map[string]any{
|
||||||
|
"files": map[string]any{
|
||||||
|
"conan_export.tgz": empty,
|
||||||
|
"conanmanifest.txt": empty,
|
||||||
|
"conanfile.py": empty,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
mux.HandleFunc(revbase+"/files/conanfile.py", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
h := w.Header()
|
||||||
|
h.Set("Cache-Control", "public,max-age=3600")
|
||||||
|
h.Set("Content-Disposition", `attachment; filename="conanfile.py"`)
|
||||||
|
httputil.ReplyWith(w, http.StatusOK, "text/x-python", conanfilePy)
|
||||||
|
})
|
||||||
|
const conanmanifest = "%d\nconandata.yml: %s\nconanfile.py: %s\n"
|
||||||
|
mux.HandleFunc(revbase+"/files/conanmanifest.txt", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
mtime, err := unixTime(gr.PublishedAt)
|
||||||
|
if err != nil {
|
||||||
|
replyError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h := w.Header()
|
||||||
|
h.Set("Cache-Control", "public,max-age=3600")
|
||||||
|
h.Set("Content-Disposition", `attachment; filename="conanmanifest.txt"`)
|
||||||
|
data := fmt.Sprintf(conanmanifest, mtime, md5Of(conandataYml), md5Of(conanfilePy))
|
||||||
|
httputil.ReplyWithStream(w, http.StatusOK, "text/plain", strings.NewReader(data), int64(len(data)))
|
||||||
|
})
|
||||||
|
mux.HandleFunc(revbase+"/files/conan_export.tgz", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
conanExportTgz, err := tgzOfConandata(outDir)
|
||||||
|
if err != nil {
|
||||||
|
replyError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h := w.Header()
|
||||||
|
h.Set("Cache-Control", "public,max-age=3600")
|
||||||
|
h.Set("Content-Disposition", `attachment; filename="conan_export.tgz"`)
|
||||||
|
httputil.ReplyWith(w, http.StatusOK, "application/x-gzip", conanExportTgz)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Manager) outDir(pkg *Package) string {
|
||||||
|
return p.cacheDir + "/build/" + pkg.Name + "@" + pkg.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Manager) conanfileDir(pkgPath, pkgFolder string) string {
|
||||||
|
root := p.indexRoot()
|
||||||
|
return root + "/" + pkgPath + "/" + pkgFolder
|
||||||
|
}
|
||||||
|
|
||||||
|
func conanInstall(pkg, outDir, conanfileDir string, out io.Writer, flags int) (err error) {
|
||||||
|
args := make([]string, 0, 12)
|
||||||
|
args = append(args, "install",
|
||||||
|
"--requires", pkg,
|
||||||
|
"--generator", "PkgConfigDeps",
|
||||||
|
"--build", "missing",
|
||||||
|
"--format", "json",
|
||||||
|
"--output-folder", outDir,
|
||||||
|
)
|
||||||
|
quietInstall := flags&ToolQuietInstall != 0
|
||||||
|
cmd, err := conanCmd.New(quietInstall, args...)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cmd.Dir = conanfileDir
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdout = out
|
||||||
|
err = cmd.Run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func recipeRevision(_ *Package, _ *githubRelease, conandataYml []byte) string {
|
||||||
|
return md5Of(conandataYml)
|
||||||
|
}
|
||||||
|
|
||||||
|
func md5Of(data []byte) string {
|
||||||
|
h := md5.New()
|
||||||
|
h.Write(data)
|
||||||
|
return hex.EncodeToString(h.Sum(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func tgzOfConandata(outDir string) (_ []byte, err error) {
|
||||||
|
cmd := exec.Command("tar", "-czf", "conan_export.tgz", "conandata.yml")
|
||||||
|
cmd.Dir = outDir
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return os.ReadFile(outDir + "/conan_export.tgz")
|
||||||
|
}
|
||||||
|
|
||||||
|
func unixTime(tstr string) (ret int64, err error) {
|
||||||
|
t, err := time.Parse(time.RFC3339, tstr)
|
||||||
|
if err == nil {
|
||||||
|
ret = t.Unix()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyDirR(srcDir, destDir string) error {
|
||||||
|
if cp, err := exec.LookPath("cp"); err == nil {
|
||||||
|
return exec.Command(cp, "-r", "-p", srcDir+"/", destDir).Run()
|
||||||
|
}
|
||||||
|
if cp, err := exec.LookPath("xcopy"); err == nil {
|
||||||
|
// TODO(xsw): check xcopy
|
||||||
|
return exec.Command(cp, "/E", "/I", "/Y", srcDir+"/", destDir).Run()
|
||||||
|
}
|
||||||
|
return errors.New("copy command not found")
|
||||||
|
}
|
||||||
55
xtool/cppkg/cppkg.go
Normal file
55
xtool/cppkg/cppkg.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cppkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultFlags is the default flags for package installation.
|
||||||
|
DefaultFlags = IndexAutoUpdate | ToolQuietInstall
|
||||||
|
)
|
||||||
|
|
||||||
|
// Install installs a package with the given name and version.
|
||||||
|
// pkgAndVer: 7bitcoder/7bitconf@1.2.0
|
||||||
|
func Install(pkgAndVer string, flags int) {
|
||||||
|
pkgPath, ver := parsePkgVer(pkgAndVer)
|
||||||
|
|
||||||
|
m, err := New("")
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
pkg, err := m.Lookup(pkgPath, ver, flags)
|
||||||
|
check(err)
|
||||||
|
|
||||||
|
err = m.Install(pkg, flags)
|
||||||
|
check(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePkgVer(pkg string) (string, string) {
|
||||||
|
parts := strings.SplitN(pkg, "@", 2)
|
||||||
|
if len(parts) == 1 {
|
||||||
|
return parts[0], ""
|
||||||
|
}
|
||||||
|
return parts[0], parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
196
xtool/cppkg/manager.go
Normal file
196
xtool/cppkg/manager.go
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cppkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/goccy/go-yaml"
|
||||||
|
"github.com/goplus/llgo/internal/github"
|
||||||
|
"golang.org/x/mod/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
var gitCmd = NewTool("git", []string{
|
||||||
|
"brew install git",
|
||||||
|
"apt-get install git",
|
||||||
|
})
|
||||||
|
|
||||||
|
// Manager represents a package manager for C/C++ packages.
|
||||||
|
type Manager struct {
|
||||||
|
cacheDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cacheDir string) (ret *Manager, err error) {
|
||||||
|
if cacheDir == "" {
|
||||||
|
cacheDir, err = os.UserCacheDir()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cacheDir += "/cppkg"
|
||||||
|
}
|
||||||
|
os.MkdirAll(cacheDir, os.ModePerm)
|
||||||
|
ret = &Manager{
|
||||||
|
cacheDir: cacheDir,
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type version struct {
|
||||||
|
Folder string `yaml:"folder"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Template represents a template for package versions.
|
||||||
|
type Template struct {
|
||||||
|
FromVer string `yaml:"from"`
|
||||||
|
Folder string `yaml:"folder"`
|
||||||
|
Tag string `yaml:"tag,omitempty"` // pattern with *, empty if dynamic tag
|
||||||
|
}
|
||||||
|
|
||||||
|
type config struct {
|
||||||
|
PkgName string `yaml:"name"`
|
||||||
|
Versions map[string]version `yaml:"versions"`
|
||||||
|
Template Template `yaml:"template"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Package represents a C/C++ package.
|
||||||
|
type Package struct {
|
||||||
|
Name string
|
||||||
|
Path string
|
||||||
|
Version string
|
||||||
|
Folder string
|
||||||
|
Template *Template
|
||||||
|
|
||||||
|
gr *github.Release // optional
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrVersionNotFound is returned when the specified version is not found.
|
||||||
|
ErrVersionNotFound = errors.New("version not found")
|
||||||
|
|
||||||
|
// ErrDynamicTag is returned when the tag is dynamic.
|
||||||
|
ErrDynamicTag = errors.New("dynamic tag")
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// IndexAutoUpdate is a flag to automatically update the index.
|
||||||
|
IndexAutoUpdate = 1 << iota
|
||||||
|
|
||||||
|
// ToolQuietInstall is a flag to suppress output during installation.
|
||||||
|
ToolQuietInstall
|
||||||
|
|
||||||
|
// LogRevertProxy is a flag to log revert proxy.
|
||||||
|
LogRevertProxy
|
||||||
|
)
|
||||||
|
|
||||||
|
// Lookup looks up a package by its path and version.
|
||||||
|
func (p *Manager) Lookup(pkgPath, ver string, flags int) (_ *Package, err error) {
|
||||||
|
root := p.indexRoot()
|
||||||
|
err = indexUpate(root, flags)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
pkgDir := root + "/" + pkgPath
|
||||||
|
confFile := pkgDir + "/config.yml"
|
||||||
|
b, err := os.ReadFile(confFile)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var conf config
|
||||||
|
err = yaml.Unmarshal(b, &conf)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ver == "" || ver == "latest" {
|
||||||
|
if conf.Template.Tag == "" {
|
||||||
|
return nil, ErrDynamicTag
|
||||||
|
}
|
||||||
|
gr, e := github.GetRelease(pkgPath, "")
|
||||||
|
if e != nil {
|
||||||
|
return nil, e
|
||||||
|
}
|
||||||
|
ver, err = verByTag(gr.TagName, conf.Template.Tag)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
templ := conf.Template
|
||||||
|
return &Package{conf.PkgName, pkgPath, ver, templ.Folder, &templ, gr}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := conf.Versions[ver]; ok {
|
||||||
|
return &Package{conf.PkgName, pkgPath, ver, v.Folder, nil, nil}, nil
|
||||||
|
}
|
||||||
|
if compareVer(ver, conf.Template.FromVer) < 0 {
|
||||||
|
err = ErrVersionNotFound
|
||||||
|
return
|
||||||
|
}
|
||||||
|
templ := conf.Template
|
||||||
|
return &Package{conf.PkgName, pkgPath, ver, templ.Folder, &templ, nil}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Manager) indexRoot() string {
|
||||||
|
return p.cacheDir + "/index"
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexUpate(root string, flags int) (err error) {
|
||||||
|
if _, err = os.Stat(root + "/.git"); os.IsNotExist(err) {
|
||||||
|
os.RemoveAll(root)
|
||||||
|
return indexInit(root, flags)
|
||||||
|
}
|
||||||
|
if flags&IndexAutoUpdate != 0 {
|
||||||
|
quietInstall := flags&ToolQuietInstall != 0
|
||||||
|
git, e := gitCmd.New(quietInstall, "pull", "--ff-only", "origin", "main")
|
||||||
|
if e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
git.Dir = root
|
||||||
|
git.Stdout = os.Stdout
|
||||||
|
git.Stderr = os.Stderr
|
||||||
|
err = git.Run()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func indexInit(root string, flags int) (err error) {
|
||||||
|
quietInstall := flags&ToolQuietInstall != 0
|
||||||
|
git, err := gitCmd.New(quietInstall, "clone", "https://github.com/goplus/cppkg.git", root)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
git.Stdout = os.Stdout
|
||||||
|
git.Stderr = os.Stderr
|
||||||
|
err = git.Run()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func compareVer(v1, v2 string) int {
|
||||||
|
return semver.Compare("v"+v1, "v"+v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func verByTag(tag, tagPattern string) (ver string, err error) {
|
||||||
|
if pos := strings.IndexByte(tagPattern, '*'); pos >= 0 {
|
||||||
|
prefix := tagPattern[:pos]
|
||||||
|
suffix := tagPattern[pos+1:]
|
||||||
|
if strings.HasPrefix(tag, prefix) && strings.HasSuffix(tag, suffix) {
|
||||||
|
ver = tag[pos : len(tag)-len(suffix)]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errors.New("tag not match: " + tag + " with " + tagPattern)
|
||||||
|
}
|
||||||
176
xtool/cppkg/revertproxy.go
Normal file
176
xtool/cppkg/revertproxy.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 The GoPlus Authors (goplus.org). All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package cppkg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
stdlog "log"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type rtHandler func(req *http.Request) (resp *http.Response, err error)
|
||||||
|
|
||||||
|
func (p rtHandler) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
return p(req)
|
||||||
|
}
|
||||||
|
|
||||||
|
type teeReader struct {
|
||||||
|
rc io.ReadCloser
|
||||||
|
b bytes.Buffer
|
||||||
|
req *http.Request
|
||||||
|
resp *http.Response
|
||||||
|
log *stdlog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *teeReader) Read(b []byte) (n int, err error) {
|
||||||
|
n, err = p.rc.Read(b)
|
||||||
|
p.b.Write(b[:n])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *teeReader) Close() error {
|
||||||
|
err := p.rc.Close()
|
||||||
|
if log := p.log; log != nil {
|
||||||
|
resp := *p.resp
|
||||||
|
resp.Body = io.NopCloser(&p.b)
|
||||||
|
var b bytes.Buffer
|
||||||
|
p.req.Write(&b)
|
||||||
|
resp.Write(&b)
|
||||||
|
log.Print(b.String())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type response = httptest.ResponseRecorder
|
||||||
|
|
||||||
|
func newResponse() *response {
|
||||||
|
return httptest.NewRecorder()
|
||||||
|
}
|
||||||
|
|
||||||
|
type revertProxy = httptest.Server
|
||||||
|
type rpFunc = func(mux *http.ServeMux)
|
||||||
|
|
||||||
|
const (
|
||||||
|
passThrough = http.StatusNotFound
|
||||||
|
)
|
||||||
|
|
||||||
|
func replyError(w http.ResponseWriter, _ error) {
|
||||||
|
w.WriteHeader(passThrough)
|
||||||
|
}
|
||||||
|
|
||||||
|
func startRevertProxy(endpoint string, f rpFunc, log *stdlog.Logger) (_ *revertProxy, err error) {
|
||||||
|
rpURL, err := url.Parse(endpoint)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var mux *http.ServeMux
|
||||||
|
if f != nil {
|
||||||
|
mux = http.NewServeMux()
|
||||||
|
f(mux)
|
||||||
|
}
|
||||||
|
proxy := httptest.NewServer(&httputil.ReverseProxy{
|
||||||
|
Rewrite: func(r *httputil.ProxyRequest) {
|
||||||
|
r.SetURL(rpURL)
|
||||||
|
},
|
||||||
|
Transport: rtHandler(func(req *http.Request) (resp *http.Response, err error) {
|
||||||
|
if mux != nil {
|
||||||
|
w := newResponse()
|
||||||
|
mux.ServeHTTP(w, req)
|
||||||
|
if w.Code != passThrough {
|
||||||
|
resp = w.Result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp == nil {
|
||||||
|
resp, err = http.DefaultTransport.RoundTrip(req)
|
||||||
|
}
|
||||||
|
if err == nil && resp.Body != nil {
|
||||||
|
resp.Body = &teeReader{
|
||||||
|
rc: resp.Body,
|
||||||
|
req: req,
|
||||||
|
resp: resp,
|
||||||
|
log: log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
return proxy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
conanCenter = "conancenter"
|
||||||
|
conanEndpoint = "https://center2.conan.io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type remoteList []struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func remoteProxy(flags int, logFile string, f func() error, rpf rpFunc) (err error) {
|
||||||
|
quietInstall := flags&ToolQuietInstall != 0
|
||||||
|
app, err := conanCmd.Get(quietInstall)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint := conanEndpoint
|
||||||
|
cmd := exec.Command(app, "remote", "list", "-f", "json")
|
||||||
|
if b, err := cmd.Output(); err == nil {
|
||||||
|
var rl remoteList
|
||||||
|
if json.Unmarshal(b, &rl) == nil {
|
||||||
|
for _, r := range rl {
|
||||||
|
if r.Name == conanCenter && strings.HasPrefix(r.URL, "https://") {
|
||||||
|
endpoint = r.URL
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
exec.Command(app, "remote", "add", "--force", conanCenter, endpoint).Run()
|
||||||
|
}()
|
||||||
|
|
||||||
|
var log *stdlog.Logger
|
||||||
|
if logFile != "" {
|
||||||
|
f, err := os.Create(logFile)
|
||||||
|
if err == nil {
|
||||||
|
defer f.Close()
|
||||||
|
log = stdlog.New(f, "", stdlog.LstdFlags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rp, err := startRevertProxy(conanEndpoint, rpf, log)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer rp.Close()
|
||||||
|
|
||||||
|
err = exec.Command(app, "remote", "add", "--force", conanCenter, rp.URL).Run()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return f()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user