mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-08-07 14:25:17 +03:00
release: Backport workflow refactor
This commit is contained in:
165
cmd/internal/merge_aar/main.go
Normal file
165
cmd/internal/merge_aar/main.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"crypto/sha256"
|
||||
"flag"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/sagernet/sing-box/log"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
var outputPath string
|
||||
|
||||
func init() {
|
||||
flag.StringVar(&outputPath, "output", "", "output AAR path")
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
err := merge()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func merge() error {
|
||||
inputPaths := flag.Args()
|
||||
if outputPath == "" {
|
||||
return E.New("missing output path")
|
||||
}
|
||||
if len(inputPaths) == 0 {
|
||||
return E.New("missing input AAR paths")
|
||||
}
|
||||
archiveReaders := make([]*zip.ReadCloser, 0, len(inputPaths))
|
||||
for _, inputPath := range inputPaths {
|
||||
archiveReader, err := zip.OpenReader(inputPath)
|
||||
if err != nil {
|
||||
return E.Cause(err, "open input AAR: ", inputPath)
|
||||
}
|
||||
archiveReaders = append(archiveReaders, archiveReader)
|
||||
}
|
||||
defer func() {
|
||||
for _, archiveReader := range archiveReaders {
|
||||
archiveReader.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
referenceEntries := make(map[string][sha256.Size]byte)
|
||||
selectedEntries := make([]*zip.File, 0)
|
||||
selectedJNIEntries := make(map[string]bool)
|
||||
for inputIndex, archiveReader := range archiveReaders {
|
||||
seenEntries := make(map[string]bool)
|
||||
for _, archiveFile := range archiveReader.File {
|
||||
if strings.HasPrefix(archiveFile.Name, "jni/") {
|
||||
if archiveFile.FileInfo().IsDir() {
|
||||
continue
|
||||
}
|
||||
if selectedJNIEntries[archiveFile.Name] {
|
||||
return E.New("duplicate AAR JNI entry: ", archiveFile.Name)
|
||||
}
|
||||
selectedJNIEntries[archiveFile.Name] = true
|
||||
selectedEntries = append(selectedEntries, archiveFile)
|
||||
continue
|
||||
}
|
||||
entryDigest, err := digestEntry(archiveFile)
|
||||
if err != nil {
|
||||
return E.Cause(err, "read AAR entry: ", archiveFile.Name)
|
||||
}
|
||||
if inputIndex == 0 {
|
||||
referenceEntries[archiveFile.Name] = entryDigest
|
||||
selectedEntries = append(selectedEntries, archiveFile)
|
||||
} else {
|
||||
referenceDigest, loaded := referenceEntries[archiveFile.Name]
|
||||
if !loaded {
|
||||
return E.New("unexpected AAR entry: ", archiveFile.Name)
|
||||
}
|
||||
if referenceDigest != entryDigest {
|
||||
return E.New("AAR entry differs between architectures: ", archiveFile.Name)
|
||||
}
|
||||
}
|
||||
seenEntries[archiveFile.Name] = true
|
||||
}
|
||||
if inputIndex > 0 {
|
||||
for referenceName := range referenceEntries {
|
||||
if !seenEntries[referenceName] {
|
||||
return E.New("missing AAR entry: ", referenceName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absoluteOutputPath, err := filepath.Abs(outputPath)
|
||||
if err != nil {
|
||||
return E.Cause(err, "resolve output AAR path")
|
||||
}
|
||||
err = os.MkdirAll(filepath.Dir(absoluteOutputPath), 0o755)
|
||||
if err != nil {
|
||||
return E.Cause(err, "create output AAR directory")
|
||||
}
|
||||
temporaryFile, err := os.CreateTemp(filepath.Dir(absoluteOutputPath), ".merge-aar-*.aar")
|
||||
if err != nil {
|
||||
return E.Cause(err, "create temporary output AAR")
|
||||
}
|
||||
temporaryPath := temporaryFile.Name()
|
||||
defer os.Remove(temporaryPath)
|
||||
archiveWriter := zip.NewWriter(temporaryFile)
|
||||
for _, archiveFile := range selectedEntries {
|
||||
rawReader, openErr := archiveFile.OpenRaw()
|
||||
if openErr != nil {
|
||||
archiveWriter.Close()
|
||||
temporaryFile.Close()
|
||||
return E.Cause(openErr, "open raw AAR entry: ", archiveFile.Name)
|
||||
}
|
||||
header := archiveFile.FileHeader
|
||||
rawWriter, createErr := archiveWriter.CreateRaw(&header)
|
||||
if createErr != nil {
|
||||
archiveWriter.Close()
|
||||
temporaryFile.Close()
|
||||
return E.Cause(createErr, "create output AAR entry: ", archiveFile.Name)
|
||||
}
|
||||
_, copyErr := io.Copy(rawWriter, rawReader)
|
||||
if copyErr != nil {
|
||||
archiveWriter.Close()
|
||||
temporaryFile.Close()
|
||||
return E.Cause(copyErr, "copy output AAR entry: ", archiveFile.Name)
|
||||
}
|
||||
}
|
||||
err = archiveWriter.Close()
|
||||
if err != nil {
|
||||
temporaryFile.Close()
|
||||
return E.Cause(err, "finalize output AAR")
|
||||
}
|
||||
err = temporaryFile.Close()
|
||||
if err != nil {
|
||||
return E.Cause(err, "close output AAR")
|
||||
}
|
||||
err = os.Rename(temporaryPath, absoluteOutputPath)
|
||||
if err != nil {
|
||||
return E.Cause(err, "replace output AAR")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func digestEntry(archiveFile *zip.File) ([sha256.Size]byte, error) {
|
||||
entryReader, err := archiveFile.Open()
|
||||
if err != nil {
|
||||
return [sha256.Size]byte{}, err
|
||||
}
|
||||
digest := sha256.New()
|
||||
_, err = io.Copy(digest, entryReader)
|
||||
closeErr := entryReader.Close()
|
||||
if err != nil {
|
||||
return [sha256.Size]byte{}, err
|
||||
}
|
||||
if closeErr != nil {
|
||||
return [sha256.Size]byte{}, closeErr
|
||||
}
|
||||
var result [sha256.Size]byte
|
||||
copy(result[:], digest.Sum(nil))
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user