initial commit
This commit is contained in:
commit
97a3c7ab71
11
ansi_seq.go
Normal file
11
ansi_seq.go
Normal 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
56
compile_config.go
Normal 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
49
compile_report.go
Normal 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
15
go.mod
Normal 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
16
go.sum
Normal 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
135
main.go
Normal 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
43
watch.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user