initial commit

This commit is contained in:
Timon Ringwald 2022-08-17 18:16:21 +02:00
commit 97a3c7ab71
7 changed files with 325 additions and 0 deletions

11
ansi_seq.go Normal file
View File

@ -0,0 +1,11 @@
package main
import "os"
func clearEOL() {
os.Stdout.Write([]byte{0x1b, 0x5b, 0x4b})
}
func goUp() {
os.Stdout.Write([]byte{0x1b, 0x5b, 0x41})
}

56
compile_config.go Normal file
View File

@ -0,0 +1,56 @@
package main
import (
"os/exec"
"strings"
"golang.org/x/exp/slices"
)
var CompileConfigs = []*CompileConfig{}
type CompileConfig struct {
OS string
Arch string
FileExt string
Compress bool
}
func FillCompileConfigs() error {
cmd := exec.Command("go", "tool", "dist", "list")
systems := strings.Split(*OS, ",")
arches := strings.Split(*Arch, ",")
out, err := cmd.Output()
if err != nil {
return err
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
for _, line := range lines {
splits := strings.Split(line, "/")
os, arch := splits[0], splits[1]
if (*OS != "" && !slices.Contains(systems, os)) || (*Arch != "" && !slices.Contains(arches, arch)) {
continue
}
ext := ""
if os == "windows" {
ext = ".exe"
}
cfg := &CompileConfig{
OS: os,
Arch: arch,
Compress: true,
FileExt: ext,
}
CompileConfigs = append(CompileConfigs, cfg)
}
return nil
}

49
compile_report.go Normal file
View File

@ -0,0 +1,49 @@
package main
import (
"github.com/fatih/color"
)
type CompileReport struct {
Config *CompileConfig
State CompileState
}
type CompileState string
const (
StateWaiting CompileState = "waiting"
StateCompiling CompileState = "compiling"
StateCompressing CompileState = "compressing"
StateDone CompileState = "done"
StateCompileError CompileState = "compile error"
StateCompressError CompileState = "compress error"
)
var (
ColorWaiting = color.New(color.FgHiBlack, color.Italic)
ColorError = color.New(color.FgRed, color.Bold)
ColorInProgress = color.New(color.FgBlue)
ColorDone = color.New(color.FgGreen, color.Bold)
)
func (s CompileState) String() string {
switch s {
case StateWaiting:
return ColorWaiting.Sprint(string(s))
case StateCompiling:
return ColorInProgress.Sprint(string(s))
case StateCompressing:
return ColorInProgress.Sprint(string(s))
case StateDone:
return ColorDone.Sprint(string(s))
case StateCompileError:
return ColorError.Sprint(string(s))
case StateCompressError:
return ColorError.Sprint(string(s))
default:
panic("invalid compile state")
}
}

15
go.mod Normal file
View File

@ -0,0 +1,15 @@
module git.milar.in/milarin/gocc
go 1.19
require (
git.milar.in/milarin/channel v0.0.7
github.com/fatih/color v1.13.0
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e
)
require (
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect
)

16
go.sum Normal file
View File

@ -0,0 +1,16 @@
git.milar.in/milarin/channel v0.0.7 h1:cVKtwgH/EE7U+XTHcoFCClJ4LR349KanzjX9xKwRcNg=
git.milar.in/milarin/channel v0.0.7/go.mod h1:We83LTI8S7u7II3pD+A2ChCDWJfCkcBUCUqii9HjTtM=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

135
main.go Normal file
View File

@ -0,0 +1,135 @@
package main
import (
"flag"
"fmt"
"os/exec"
"path/filepath"
"runtime"
"strconv"
"sync"
"time"
"git.milar.in/milarin/channel"
)
var ModulePath string
var ProjectName string
var (
OS = flag.String("os", "", "comma-separated list of operating systems to compile for (empty for all)")
Arch = flag.String("arch", "", "comma-separated list of architectures to compile for (empty for all)")
Silent = flag.Bool("s", false, "silent mode (no output)")
NoCompress = flag.Bool("c", false, "dont compress any executables")
NumThreads = flag.Int("t", runtime.NumCPU(), "amount of threads (0 = infinite)")
)
var Runner channel.Runner
func main() {
var err error
flag.Parse()
if err := FillCompileConfigs(); err != nil {
panic(err)
}
ModulePath, err = filepath.Abs(flag.Arg(0))
if err != nil {
panic(err)
}
ProjectName = filepath.Base(ModulePath)
ch := make(chan *CompileReport, len(CompileConfigs))
wg := new(sync.WaitGroup)
doneCh := make(chan struct{})
go Watch(ch, doneCh)
Runner = GetRunner()
start := time.Now()
for _, cfg := range CompileConfigs {
cfg := cfg
wg.Add(1)
go Runner.Run(func() { Compile(cfg, ch, wg) })
}
wg.Wait()
close(ch)
end := time.Now()
<-doneCh // wait for Watch
if !*Silent {
fmt.Printf("compilation took %s (using %s threads)\n", end.Sub(start), GetThreadCount())
}
}
func Compile(cfg *CompileConfig, ch chan<- *CompileReport, wg *sync.WaitGroup) {
filename := fmt.Sprintf("%s_%s_%s%s", ProjectName, cfg.OS, cfg.Arch, cfg.FileExt)
ch <- &CompileReport{Config: cfg, State: StateCompiling}
compileCmd := exec.Command("go", "build", "-o", filename)
compileCmd.Dir = ModulePath
if err := compileCmd.Start(); err != nil {
ch <- &CompileReport{Config: cfg, State: StateCompileError}
wg.Done()
return
}
if err := compileCmd.Wait(); err != nil {
ch <- &CompileReport{Config: cfg, State: StateCompileError}
wg.Done()
return
}
Compress(filename, cfg, ch, wg)
// uncomment for independent compile and compress tasks
/*
ch <- &CompileReport{Config: cfg, State: StateWaiting}
go Runner.Run(func() { Compress(filename, cfg, ch, wg) })
*/
}
func Compress(filename string, cfg *CompileConfig, ch chan<- *CompileReport, wg *sync.WaitGroup) {
defer wg.Done()
ch <- &CompileReport{Config: cfg, State: StateCompressing}
if !*NoCompress && cfg.Compress {
compressCmd := exec.Command("upx", "--best", filename)
compressCmd.Dir = ModulePath
if err := compressCmd.Start(); err != nil {
ch <- &CompileReport{Config: cfg, State: StateCompressError}
return
}
if err := compressCmd.Wait(); err != nil {
ch <- &CompileReport{Config: cfg, State: StateCompressError}
return
}
}
ch <- &CompileReport{Config: cfg, State: StateDone}
}
func GetRunner() channel.Runner {
if *NumThreads <= 0 {
return channel.NewUnlimitedRunner()
} else {
return channel.NewLimitedRunner(*NumThreads)
}
}
func GetThreadCount() string {
if *NumThreads == 0 {
return "infinitely many"
}
return strconv.Itoa(*NumThreads)
}

43
watch.go Normal file
View File

@ -0,0 +1,43 @@
package main
import "fmt"
func Watch(ch <-chan *CompileReport, doneCh chan<- struct{}) {
defer close(doneCh)
states := map[*CompileConfig]CompileState{}
for _, cfg := range CompileConfigs {
states[cfg] = StateWaiting
}
cleared := false
for report := range ch {
states[report.Config] = report.State
if !*Silent {
PrintStates(states, cleared)
}
cleared = true
}
doneCh <- struct{}{}
}
func PrintStates(states map[*CompileConfig]CompileState, clear bool) {
if clear {
for i := 0; i < len(CompileConfigs); i++ {
goUp()
clearEOL()
}
}
for _, cfg := range CompileConfigs {
state, ok := states[cfg]
if !ok {
fmt.Println()
continue
}
fmt.Printf("%-16s %s\n", fmt.Sprintf("%s/%s:", cfg.OS, cfg.Arch), state)
}
}