Skip to content

Commit

Permalink
refactor tinygoize
Browse files Browse the repository at this point in the history
  • Loading branch information
archie2x committed Sep 20, 2024
1 parent 1e1c116 commit c964799
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 205 deletions.
45 changes: 27 additions & 18 deletions tools/tinygoize/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@ const (
BuildCodeFatal
)

// Additional tags required for specific commands. Assume command names unique
// despite being in different directories.
type BuildRes struct {
err *exec.ExitError
excluded bool
output []byte
}

// Additional tags required for specific commands. Assumes command names are
// unique despite being in different directories.
var addBuildTags = map[string]string{
"gzip": "noasm",
"insmod": "noasm",
Expand All @@ -33,7 +39,7 @@ var addBuildTags = map[string]string{
"init": "noasm",
}

// returns the needed build-tags for a given package
// Returns the needed build-tags for a given package
func buildTags(dir string) (tags string) {
parts := strings.Split(dir, "/")
cmd := parts[len(parts)-1]
Expand Down Expand Up @@ -65,35 +71,38 @@ func isExcluded(dir string) bool {
}

// "tinygo build" in directory 'dir'
func build(id int, tinygo *string, dir string) (BuildCode, error) {

func build(id int, tinygo *string, dir string) (res BuildRes, err error) {
wlog := func(format string, args ...interface{}) {
log.Printf("[%d] "+format, append([]interface{}{id}, args...)...)
}

wlog("%s Building...\n", dir)

tags := []string{"tinygo.enable"}
if addTags := buildTags(dir); addTags != "" {
tags = append(tags, addTags)
}
c := exec.Command(*tinygo, "build", "-tags", strings.Join(tags, ","))
c.Dir = dir
c.Stdout, c.Stderr = os.Stdout, os.Stderr
c.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64")
err := c.Run()
cmd := exec.Command(*tinygo, "build", "-tags", strings.Join(tags, ","))
cmd.Env = append(os.Environ(), "GOOS=linux", "GOARCH=amd64")
cmd.Dir = dir
res.output, err = cmd.CombinedOutput()
if err != nil {
berr, ok := err.(*exec.ExitError)
var ok bool
res.err, ok = err.(*exec.ExitError)
if !ok {
return BuildCodeFatal, err
return
}
err = nil
if isExcluded(dir) {
wlog("%v EXCLUDED\n", dir)
return BuildCodeExclude, nil
res.excluded = true
return
}
lines := strings.Split(string(res.output), "\n")
for _,line := range lines {
wlog(line)
}
wlog("%v FAILED %v\n", dir, berr)
return BuildCodeFailed, nil
wlog("%v FAILED %v\n", dir, res.err)
return
}
wlog("%v PASS\n", dir)
return BuildCodeSuccess, nil
return
}
14 changes: 14 additions & 0 deletions tools/tinygoize/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2017-2024 the u-root 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 main

type Config struct {
pathMD string
tinygo string
nWorkers int
checkOnly bool
verbose bool
dirs []string
}
168 changes: 95 additions & 73 deletions tools/tinygoize/constraints.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,96 +23,118 @@ const (
)

// Modifies, adds, or removes //go:build line as appropriate with '!tinygo ||
// tinygo.enable' for all .go files in dir depending on whether it 'builds' or
// not as previously tested.
func fixupConstraints(dir string, builds bool) (err error) {
p := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}

files, err := filepath.Glob(filepath.Join(dir, "*"))
// tinygo.enable'
func fixupFileConstraints(file string, builds bool, checkonly bool) (mustDoWork bool, err error) {
log.Printf("Process %s", file)
b, err := os.ReadFile(file)
if err != nil {
log.Fatal(err)
}
nextFile:
for _, file := range files {
if !strings.HasSuffix(file, ".go") {
continue
}
log.Printf("Process %s", file)
b, err := os.ReadFile(file)
if err != nil {
log.Fatal(err)
}
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(fset, file, string(b), parser.ParseComments|parser.SkipObjectResolution)
if err != nil {
log.Fatalf("parsing\n%v\n:%v", string(b), err)
}
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(fset, file, string(b), parser.ParseComments|parser.SkipObjectResolution)
if err != nil {
log.Fatalf("parsing\n%v\n:%v", string(b), err)
}

goBuildPresent := false
goBuildPresent := false

done:
// modify existing //go:build line
for _, cg := range f.Comments {
for _, c := range cg.List {
if !strings.HasPrefix(c.Text, goBuild) {
continue
}
goBuildPresent = true
// modify existing //go:build line
for _, cg := range f.Comments {
for _, c := range cg.List {
if !strings.HasPrefix(c.Text, goBuild) {
continue
}
goBuildPresent = true

contains := strings.Contains(c.Text, constraint)
contains := strings.Contains(c.Text, constraint)

if (builds && !contains) || (!builds && contains) {
log.Printf("Skipped, constraint up-to-date: %s\n", file)
continue nextFile
}
if (builds && !contains) || (!builds && contains) {
log.Printf("Skipped, constraint up-to-date: %s\n", file)
return
}

if builds {
re := regexp.MustCompile(`\(?\s*!tinygo\s+\|\|\s+tinygo.enable\s*\)?(\s+\&\&)?`)
c.Text = re.ReplaceAllString(c.Text, "")
log.Printf("Stripping build constraint %v\n", file)

if builds {
re := regexp.MustCompile(`\(?\s*!tinygo\s+\|\|\s+tinygo.enable\s*\)?(\s+\&\&)?`)
c.Text = re.ReplaceAllString(c.Text, "")
log.Printf("Stripping build constraint %v\n", file)

// handle potentially now-empty build constraint
re = regexp.MustCompile(`^\s*//go:build\s*$`)
if re.MatchString(c.Text) {
filtered := []*ast.Comment{}
for _, comment := range cg.List {
if !re.MatchString(comment.Text) {
filtered = append(filtered, comment)
}
// handle potentially now-empty build constraint
re = regexp.MustCompile(`^\s*//go:build\s*$`)
if re.MatchString(c.Text) {
filtered := []*ast.Comment{}
for _, comment := range cg.List {
if !re.MatchString(comment.Text) {
filtered = append(filtered, comment)
}
cg.List = filtered
}
} else {
c.Text = goBuild + "(" + constraint + ") && (" + c.Text[len(goBuild):] + ")"
cg.List = filtered
}
break done
} else {
c.Text = goBuild + "(" + constraint + ") && (" + c.Text[len(goBuild):] + ")"
}
break
}
}

if !builds && !goBuildPresent {
// no //go:build line found: insert one
var cg ast.CommentGroup
cg.List = append(cg.List, &ast.Comment{Text: goBuild + constraint})

if len(f.Comments) > 0 {
// insert //go:build after first comment
// group, assumed copyright. Doesn't seem
// quite right but seems to work.
cg.List[0].Slash = f.Comments[0].List[0].Slash + 1
f.Comments = append([]*ast.CommentGroup{f.Comments[0], &cg}, f.Comments[1:]...)
} else {
// prepend //go:build
f.Comments = append([]*ast.CommentGroup{&cg}, f.Comments...)
}
// if it doesn't build but no //go:build found, insert one XXX skip space after copyright
if !builds && !goBuildPresent {
// no //go:build line found: insert one
var cg ast.CommentGroup
cg.List = append(cg.List, &ast.Comment{Text: goBuild + constraint})

if len(f.Comments) > 0 {
// insert //go:build after first comment
// group, assumed copyright. Doesn't seem
// quite right but seems to work.
cg.List[0].Slash = f.Comments[0].List[0].Slash + 1
f.Comments = append([]*ast.CommentGroup{f.Comments[0], &cg}, f.Comments[1:]...)
} else {
// prepend //go:build
f.Comments = append([]*ast.CommentGroup{&cg}, f.Comments...)
}
}

// Complete source file.
var buf bytes.Buffer
p := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
if err = p.Fprint(&buf, fset, f); err != nil {
log.Fatalf("Printing:%v", err)
}


// Complete source file.
var buf bytes.Buffer
if err = p.Fprint(&buf, fset, f); err != nil {
log.Fatalf("Printing:%v", err)
if bytes.Equal(b, buf.Bytes()) {
log.Printf("Skipped, constraint up-to-date: %s\n", file)
return
} else {
mustDoWork = true
}
if checkonly {
return
}

if err := os.WriteFile(file, buf.Bytes(), 0o644); err != nil {
log.Fatal(err)
}
return
}

// fixup build constraint lines for all .go files in pkg
func fixupPkgConstraints(dir string, builds bool, checkonly bool) (mustDoWork bool, err error) {
files, err := filepath.Glob(filepath.Join(dir, "*"))
if err != nil {
log.Fatal(err)
}
for _, file := range files {
if !strings.HasSuffix(file, ".go") {
continue
}
mdw, err2 := fixupFileConstraints(file, builds, checkonly)
if err2 != nil {
err = err2
return
}
if err := os.WriteFile(file, buf.Bytes(), 0o644); err != nil {
log.Fatal(err)
if mdw {
mustDoWork = true
}
}
return
Expand Down
Loading

0 comments on commit c964799

Please sign in to comment.