Initial commit
This commit is contained in:
commit
55a1efa08f
60 changed files with 5485 additions and 0 deletions
5
lang/go/utils/parser/go.mod
Normal file
5
lang/go/utils/parser/go.mod
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
module puck.moe/zilch/go/parser
|
||||
|
||||
go 1.22.5
|
||||
|
||||
require github.com/davecgh/go-spew v1.1.1
|
||||
289
lang/go/utils/parser/main.go
Normal file
289
lang/go/utils/parser/main.go
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type WrappedStat struct {
|
||||
fs.FileInfo
|
||||
newName string // meow
|
||||
}
|
||||
|
||||
func (s *WrappedStat) Name() string {
|
||||
return s.newName
|
||||
}
|
||||
|
||||
type DirStat struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (s *DirStat) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
func (s *DirStat) Size() int64 {
|
||||
return 1
|
||||
}
|
||||
|
||||
func (s *DirStat) Mode() fs.FileMode {
|
||||
return fs.FileMode(fs.ModeDir | 0777)
|
||||
}
|
||||
|
||||
func (s *DirStat) ModTime() time.Time {
|
||||
return time.Time{}
|
||||
}
|
||||
|
||||
func (s *DirStat) IsDir() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *DirStat) Sys() any {
|
||||
return "zilch"
|
||||
}
|
||||
|
||||
type Input struct {
|
||||
// directory -> filename -> path
|
||||
Files map[string]map[string]string `json:"files"`
|
||||
GOARCH string `json:"GOARCH"`
|
||||
GOOS string `json:"GOOS"`
|
||||
}
|
||||
|
||||
type Output struct {
|
||||
Name string `json:"name"`
|
||||
GoFiles []string `json:"goFiles"`
|
||||
SFiles []string `json:"sFiles"`
|
||||
Imports []string `json:"imports"`
|
||||
Embeds map[string][][]string `json:"embeds"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
inputFile, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var input Input
|
||||
err = json.NewDecoder(inputFile).Decode(&input)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx := build.Context{
|
||||
GOARCH: input.GOARCH,
|
||||
GOOS: input.GOOS,
|
||||
Compiler: "gc",
|
||||
ToolTags: build.Default.ToolTags,
|
||||
ReleaseTags: build.Default.ReleaseTags,
|
||||
ReadDir: func(dir string) ([]fs.FileInfo, error) {
|
||||
fmt.Printf("ReadDir(%q)\n", dir)
|
||||
if !strings.HasPrefix(dir, "/code") {
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
||||
dir = path.Clean(dir[5:])
|
||||
if dir == "." {
|
||||
dir = "/"
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(dir, "/") {
|
||||
dir += "/"
|
||||
}
|
||||
|
||||
dircontents, ok := input.Files[dir]
|
||||
if !ok {
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
||||
infos := make([]fs.FileInfo, len(dircontents))
|
||||
i := 0
|
||||
for name, file := range dircontents {
|
||||
stat, err := os.Stat(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
infos[i] = &WrappedStat{FileInfo: stat, newName: name}
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
for key := range input.Files {
|
||||
if path.Dir(key) == dir {
|
||||
base := path.Base(key)
|
||||
if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
|
||||
continue
|
||||
}
|
||||
|
||||
infos = append(infos, &DirStat{base})
|
||||
}
|
||||
}
|
||||
|
||||
return infos, nil
|
||||
},
|
||||
|
||||
OpenFile: func(pth string) (io.ReadCloser, error) {
|
||||
opth := pth
|
||||
fmt.Printf("OpenFile(%q)\n", pth)
|
||||
if !strings.HasPrefix(pth, "/code") {
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
||||
pth = path.Clean(pth[5:])
|
||||
dirname, fname := path.Split(pth)
|
||||
if dirname == "." {
|
||||
dirname = "/"
|
||||
}
|
||||
dir := input.Files[dirname]
|
||||
|
||||
data, err := os.Open(dir[fname])
|
||||
if err != nil {
|
||||
return data, fmt.Errorf("OpenFile(%q; %q[%q]; %q): %w", opth, dirname, fname, dir[fname], err)
|
||||
}
|
||||
return data, err
|
||||
},
|
||||
|
||||
IsDir: func(dir string) bool {
|
||||
fmt.Printf("IsDir(%q)\n", dir)
|
||||
if !strings.HasPrefix(dir, "/code") {
|
||||
return false
|
||||
}
|
||||
|
||||
dir = path.Clean(dir[5:])
|
||||
if dir == "." {
|
||||
dir = "/"
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(dir, "/") {
|
||||
dir += "/"
|
||||
}
|
||||
|
||||
_, ok := input.Files[dir]
|
||||
fmt.Printf("IsDir -> %q, %v\n", dir, ok)
|
||||
return ok
|
||||
},
|
||||
|
||||
HasSubdir: func(root, dir string) (rel string, ok bool) {
|
||||
root = path.Clean(root)
|
||||
dir = path.Clean(dir)
|
||||
|
||||
return strings.CutPrefix(dir, root)
|
||||
},
|
||||
}
|
||||
|
||||
var filenames []string
|
||||
for dirname, files := range input.Files {
|
||||
for filename := range files {
|
||||
filenames = append(filenames, filepath.Join(dirname, filename))
|
||||
}
|
||||
}
|
||||
|
||||
files := make(map[string]Output)
|
||||
|
||||
for dir, filelist := range input.Files {
|
||||
isGo := false
|
||||
for file := range filelist {
|
||||
if strings.HasSuffix(file, ".go") {
|
||||
isGo = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Checking %q..\n", dir)
|
||||
if strings.Contains(dir, "/.") || strings.Contains(dir, "/_") || strings.Contains(dir, "/testdata/") {
|
||||
fmt.Printf(" skipping; \n")
|
||||
continue
|
||||
}
|
||||
|
||||
base := path.Base(dir)
|
||||
|
||||
if !isGo || strings.HasPrefix(base, "_") || strings.HasPrefix(base, ".") || base == "testdata" {
|
||||
fmt.Printf(" skipping (not go)\n")
|
||||
continue
|
||||
}
|
||||
|
||||
pkg, err := ctx.Import(".", path.Clean("/code"+dir), 0)
|
||||
if err != nil {
|
||||
if _, ok := err.(*build.NoGoError); ok {
|
||||
continue
|
||||
}
|
||||
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out := Output{
|
||||
Name: pkg.Name,
|
||||
Imports: pkg.Imports,
|
||||
GoFiles: pkg.GoFiles,
|
||||
SFiles: pkg.SFiles,
|
||||
Embeds: make(map[string][][]string),
|
||||
}
|
||||
|
||||
// _test only, or so
|
||||
if len(pkg.GoFiles) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
sort.Strings(out.Imports)
|
||||
sort.Strings(out.GoFiles)
|
||||
sort.Strings(out.SFiles)
|
||||
sort.Strings(pkg.EmbedPatterns)
|
||||
|
||||
for _, pattern := range pkg.EmbedPatterns {
|
||||
matchedFiles := []string{}
|
||||
|
||||
// TODO: proper matching
|
||||
if strings.HasPrefix(pattern, "all:") {
|
||||
pattern = pattern[4:]
|
||||
}
|
||||
|
||||
fullPattern := filepath.Join(dir, pattern)
|
||||
for _, file := range filenames {
|
||||
if ok, _ := filepath.Match(fullPattern, file); ok {
|
||||
matchedFiles = append(matchedFiles, file)
|
||||
}
|
||||
}
|
||||
|
||||
if len(matchedFiles) == 0 {
|
||||
dirpattern := fullPattern + "/"
|
||||
for _, file := range filenames {
|
||||
if strings.HasPrefix(file, dirpattern) {
|
||||
matchedFiles = append(matchedFiles, file)
|
||||
}
|
||||
|
||||
if file == fullPattern {
|
||||
matchedFiles = append(matchedFiles, file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(matchedFiles)
|
||||
var split [][]string
|
||||
for _, match := range matchedFiles {
|
||||
split = append(split, []string{match[len(dir):], filepath.Dir(match) + "/", filepath.Base(match)})
|
||||
}
|
||||
|
||||
out.Embeds[pattern] = split
|
||||
}
|
||||
|
||||
files[dir] = out
|
||||
}
|
||||
|
||||
out, err := os.OpenFile(os.Getenv("out"), os.O_CREATE|os.O_RDWR, 0666)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(out).Encode(files); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
out.Close()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue