mirror of
https://github.com/goreleaser/goreleaser.git
synced 2025-01-08 03:31:59 +02:00
145 lines
3.5 KiB
Go
145 lines
3.5 KiB
Go
package upx
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/caarlos0/log"
|
|
"github.com/docker/go-units"
|
|
"github.com/goreleaser/goreleaser/internal/artifact"
|
|
"github.com/goreleaser/goreleaser/internal/pipe"
|
|
"github.com/goreleaser/goreleaser/internal/semerrgroup"
|
|
"github.com/goreleaser/goreleaser/internal/tmpl"
|
|
"github.com/goreleaser/goreleaser/pkg/config"
|
|
"github.com/goreleaser/goreleaser/pkg/context"
|
|
)
|
|
|
|
type Pipe struct{}
|
|
|
|
func (Pipe) String() string { return "upx" }
|
|
func (Pipe) Default(ctx *context.Context) error {
|
|
for i := range ctx.Config.UPXs {
|
|
upx := &ctx.Config.UPXs[i]
|
|
if upx.Binary == "" {
|
|
upx.Binary = "upx"
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
func (Pipe) Skip(ctx *context.Context) bool { return len(ctx.Config.UPXs) == 0 }
|
|
func (Pipe) Run(ctx *context.Context) error {
|
|
g := semerrgroup.NewSkipAware(semerrgroup.New(ctx.Parallelism))
|
|
for _, upx := range ctx.Config.UPXs {
|
|
upx := upx
|
|
enabled, err := tmpl.New(ctx).Bool(upx.Enabled)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !enabled {
|
|
return pipe.Skip("upx is not enabled")
|
|
}
|
|
if _, err := exec.LookPath(upx.Binary); err != nil {
|
|
return pipe.Skipf("%s not found in PATH", upx.Binary)
|
|
}
|
|
for _, bin := range findBinaries(ctx, upx) {
|
|
bin := bin
|
|
g.Go(func() error {
|
|
sizeBefore := sizeOf(bin.Path)
|
|
args := []string{
|
|
"--quiet",
|
|
}
|
|
switch upx.Compress {
|
|
case "best":
|
|
args = append(args, "--best")
|
|
case "":
|
|
default:
|
|
args = append(args, "-"+upx.Compress)
|
|
}
|
|
if upx.LZMA {
|
|
args = append(args, "--lzma")
|
|
}
|
|
if upx.Brute {
|
|
args = append(args, "--brute")
|
|
}
|
|
args = append(args, bin.Path)
|
|
out, err := exec.CommandContext(ctx, "upx", args...).CombinedOutput()
|
|
if err != nil {
|
|
for _, ke := range knownExceptions {
|
|
if strings.Contains(string(out), ke) {
|
|
log.WithField("binary", bin.Path).
|
|
WithField("exception", ke).
|
|
Warn("could not pack")
|
|
return nil
|
|
}
|
|
}
|
|
return fmt.Errorf("could not pack %s: %w: %s", bin.Path, err, string(out))
|
|
}
|
|
|
|
sizeAfter := sizeOf(bin.Path)
|
|
|
|
log.
|
|
WithField("before", units.HumanSize(float64(sizeBefore))).
|
|
WithField("after", units.HumanSize(float64(sizeAfter))).
|
|
WithField("ratio", fmt.Sprintf("%d%%", (sizeAfter*100)/sizeBefore)).
|
|
WithField("binary", bin.Path).
|
|
Info("packed")
|
|
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
return g.Wait()
|
|
}
|
|
|
|
var knownExceptions = []string{
|
|
"CantPackException",
|
|
"AlreadyPackedException",
|
|
"NotCompressibleException",
|
|
}
|
|
|
|
func findBinaries(ctx *context.Context, upx config.UPX) []*artifact.Artifact {
|
|
filters := []artifact.Filter{
|
|
artifact.Or(
|
|
artifact.ByType(artifact.Binary),
|
|
artifact.ByType(artifact.UniversalBinary),
|
|
),
|
|
}
|
|
if f := orBy(artifact.ByGoos, upx.Goos); f != nil {
|
|
filters = append(filters, f)
|
|
}
|
|
if f := orBy(artifact.ByGoarch, upx.Goarch); f != nil {
|
|
filters = append(filters, f)
|
|
}
|
|
if f := orBy(artifact.ByGoarm, upx.Goarm); f != nil {
|
|
filters = append(filters, f)
|
|
}
|
|
if f := orBy(artifact.ByGoamd64, upx.Goamd64); f != nil {
|
|
filters = append(filters, f)
|
|
}
|
|
if len(upx.IDs) > 0 {
|
|
filters = append(filters, artifact.ByIDs(upx.IDs...))
|
|
}
|
|
return ctx.Artifacts.Filter(artifact.And(filters...)).List()
|
|
}
|
|
|
|
func orBy(fn func(string) artifact.Filter, items []string) artifact.Filter {
|
|
var result []artifact.Filter
|
|
for _, f := range items {
|
|
result = append(result, fn(f))
|
|
}
|
|
if len(result) == 0 {
|
|
return nil
|
|
}
|
|
return artifact.Or(result...)
|
|
}
|
|
|
|
func sizeOf(name string) int64 {
|
|
st, err := os.Stat(name)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return st.Size()
|
|
}
|