go-assembler-gen/main.go

262 lines
5.7 KiB
Go

package main
import (
"embed"
"errors"
"flag"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"go/format"
"os"
"path"
"regexp"
"strings"
)
//go:embed internal
var patchFiles embed.FS
func main() {
repositoryUrl := flag.String("url", "https://github.com/golang/go.git", "golang repository url")
repositoryRef := flag.String("ref", Version, "git reference")
outputDirectory := flag.String("output", ".", "output directory")
packagePath := flag.String("pkg", "", "package path")
flag.Parse()
tmpDir, err := os.MkdirTemp(os.TempDir(), "golang_repo")
if err != nil {
panic(err)
}
defer os.RemoveAll(tmpDir)
_, err = git.PlainClone(tmpDir, false, &git.CloneOptions{
URL: *repositoryUrl,
ReferenceName: plumbing.NewTagReferenceName(*repositoryRef),
SingleBranch: true,
Depth: 1,
RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
ShallowSubmodules: true,
Progress: os.Stderr,
})
if errors.Is(err, git.NoMatchingRefSpecError{}) {
//retry with branch name instead
_, err = git.PlainClone(tmpDir, false, &git.CloneOptions{
URL: *repositoryUrl,
ReferenceName: plumbing.NewBranchReferenceName(*repositoryRef),
SingleBranch: true,
Depth: 1,
RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
ShallowSubmodules: true,
Progress: os.Stderr,
})
}
if err != nil {
panic(err)
}
err = os.MkdirAll(*outputDirectory, 0755)
if err != nil {
panic(err)
}
dirList, err := os.ReadDir(*outputDirectory)
if err != nil {
panic(err)
}
// Cleanup directories from source
for _, d := range dirList {
if d.IsDir() {
err = os.RemoveAll(path.Join(*outputDirectory, d.Name()))
if err != nil {
panic(err)
}
}
}
type targets [2]string
for _, t := range []targets{
{"src/cmd/asm/internal/arch", "asm/arch"},
{"src/cmd/internal/obj", "obj"},
{"src/cmd/internal/objabi", "objabi"},
{"src/cmd/internal/goobj", "goobj"},
{"src/cmd/internal/dwarf", "dwarf"},
{"src/cmd/internal/src", "src"},
{"src/cmd/internal/sys", "sys"},
{"src/internal/abi", "abi"},
{"src/internal/goarch", "goarch"},
{"src/internal/buildcfg", "buildcfg"},
} {
srcPath := path.Join(tmpDir, t[0])
outPath := path.Join(*outputDirectory, t[1])
err = os.MkdirAll(path.Dir(outPath), 0755)
if err != nil {
panic(err)
}
//todo: os.CopyFS https://github.com/golang/go/issues/62484
err = os.Rename(srcPath, outPath)
if err != nil {
panic(err)
}
}
for _, fileToDelete := range []string{
// removes dependency on goexperiment
"buildcfg/exp.go",
// removes dependency on internal/bisect
"objabi/flag.go",
// removes dependency on cmd/internal/bio
"obj/objfile.go",
"goobj/objfile.go",
"goobj/funcinfo.go",
} {
err = os.Remove(path.Join(*outputDirectory, fileToDelete))
if err != nil {
panic(err)
}
}
var nestPatch func(dir string) error
nestPatch = func(dir string) error {
dirList, err := patchFiles.ReadDir(dir)
if err != nil {
return err
}
for _, p := range dirList {
if p.IsDir() {
err = nestPatch(path.Join(dir, p.Name()))
if err != nil {
return err
}
continue
}
fData, err := patchFiles.ReadFile(path.Join(dir, p.Name()))
if err != nil {
return err
}
err = os.WriteFile(path.Join(*outputDirectory, strings.TrimPrefix(dir, "internal/"), p.Name()), fData, 0655)
if err != nil {
return err
}
}
return nil
}
err = nestPatch("internal")
if err != nil {
panic(err)
}
// Copy license file
err = os.Rename(path.Join(tmpDir, "LICENSE"), path.Join(*outputDirectory, "LICENSE"))
if err != nil {
panic(err)
}
type replaceEntry struct {
Regexp *regexp.Regexp
Replacement []byte
}
replacer := []replaceEntry{
// fixup notsha256
{regexp.MustCompile("(\\s)\"cmd/internal/notsha256\""), []byte("$1\"crypto/sha256\"")},
{regexp.MustCompile("notsha256\\."), []byte("sha256.")},
// fixup lazyregexp
{regexp.MustCompile("(\\s)\"cmd/internal/lazyregexp\""), []byte("$1\"regexp\"")},
{regexp.MustCompile("lazyregexp\\.New"), []byte("regexp.MustCompile")},
// fixup imports
{regexp.MustCompile("(\\s)\"cmd/internal"), []byte("$1\"" + *packagePath)},
{regexp.MustCompile("(\\s)\"internal"), []byte("$1\"" + *packagePath)},
}
var nestDir func(dir string, depth int) error
nestDir = func(dir string, depth int) error {
dirList, err := os.ReadDir(dir)
if err != nil {
return err
}
for _, d := range dirList {
fPath := path.Join(dir, d.Name())
if d.IsDir() {
// remove tests
if d.Name() == "testdata" {
err = os.RemoveAll(fPath)
if err != nil {
return err
}
continue
}
err := nestDir(fPath, depth+1)
if err != nil {
return err
}
continue
}
// do not replace on root
if depth < 2 {
continue
}
// remove tests
if strings.HasSuffix(d.Name(), "_test.go") || strings.HasSuffix(d.Name(), "_test.s") {
err := os.Remove(fPath)
if err != nil {
return err
}
continue
}
if strings.HasSuffix(d.Name(), ".go") {
err := func() error {
fData, err := os.ReadFile(fPath)
if err != nil {
return err
}
for _, r := range replacer {
fData = r.Regexp.ReplaceAll(fData, r.Replacement)
}
// gofmt
fData, err = format.Source(fData)
if err != nil {
return err
}
writer, err := os.Create(fPath)
if err != nil {
return err
}
defer writer.Close()
_, err = writer.Write(fData)
if err != nil {
return err
}
return nil
}()
if err != nil {
return err
}
}
}
return nil
}
err = nestDir(*outputDirectory, 1)
if err != nil {
panic(err)
}
}