世界 пре 2 година
родитељ
комит
e7b35be5f6

+ 74 - 10
Makefile

@@ -58,24 +58,88 @@ proto_install:
 	go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest
 	go install -v google.golang.org/protobuf/cmd/protoc-gen-go@latest
 	go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
 	go install -v google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
 
 
-snapshot:
-	go run ./cmd/internal/build goreleaser release --clean --snapshot || exit 1
-	mkdir dist/release
-	mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release
-	ghr --delete --draft --prerelease -p 1 nightly dist/release
-	rm -r dist
-
 release:
 release:
 	go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1
 	go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1
 	mkdir dist/release
 	mkdir dist/release
 	mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release
 	mv dist/*.tar.gz dist/*.zip dist/*.deb dist/*.rpm dist/release
-	ghr --delete --draft --prerelease -p 3 $(shell git describe --tags) dist/release
+	ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release
 	rm -r dist
 	rm -r dist
 
 
 release_install:
 release_install:
 	go install -v github.com/goreleaser/goreleaser@latest
 	go install -v github.com/goreleaser/goreleaser@latest
 	go install -v github.com/tcnksm/ghr@latest
 	go install -v github.com/tcnksm/ghr@latest
 
 
+upload_android:
+	go run ./cmd/internal/update_android_version
+	cd ../sing-box-for-android && ./gradlew :app:assembleRelease
+	mkdir dist/release_android
+	cp ../sing-box-for-android/app/build/outputs/apk/release/*.apk dist/release_android
+	ghr --replace --draft --prerelease -p 3 "v${VERSION}" dist/release_android
+
+publish_android:
+	cd ../sing-box-for-android && ./gradlew :app:appCenterAssembleAndUploadRelease
+
+build_ios:
+	cd ../sing-box-for-apple && \
+	rm -rf build/SFI.xcarchive && \
+	xcodebuild archive -scheme SFI -configuration Release -archivePath build/SFI.xcarchive
+
+upload_ios_app_store:
+	cd ../sing-box-for-apple && \
+	xcodebuild -exportArchive -archivePath build/SFI.xcarchive -exportOptionsPlist SFI/Upload.plist
+
+release_ios: build_ios upload_ios_app_store
+
+build_macos:
+	cd ../sing-box-for-apple && \
+	rm -rf build/SFM.xcarchive && \
+	xcodebuild archive -scheme SFM -configuration Release -archivePath build/SFM.xcarchive
+
+upload_macos_app_store:
+	cd ../sing-box-for-apple && \
+	xcodebuild -exportArchive -archivePath build/SFM.xcarchive -exportOptionsPlist SFI/Upload.plist
+
+release_macos: build_macos upload_macos_app_store
+
+build_macos_independent:
+	cd ../sing-box-for-apple && \
+	rm -rf build/SFT.System.xcarchive && \
+	xcodebuild archive -scheme SFM.System -configuration Release -archivePath build/SFM.System.xcarchive
+
+notarize_macos_independent:
+	cd ../sing-box-for-apple && \
+	xcodebuild -exportArchive -archivePath "build/SFM.System.xcarchive" -exportOptionsPlist SFM.System/Upload.plist
+
+export_macos_independent:
+	rm -rf dist/SFM
+	cd ../sing-box-for-apple && \
+	xcodebuild -exportNotarizedApp -archivePath build/SFM.System.xcarchive -exportPath "../sing-box/dist/SFM"
+
+upload_macos_independent:
+	cd dist/SFM && \
+	rm -f *.zip && \
+	zip -ry "SFM-${VERSION}-universal.zip" SFM.app && \
+	ghr --replace --draft --prerelease "v${VERSION}" *.zip
+
+release_macos_independent: build_macos_independent notarize_macos_independent export_macos_independent upload_macos_independent
+
+build_tvos:
+	cd ../sing-box-for-apple && \
+	rm -rf build/SFT.xcarchive && \
+	export DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer && \
+	xcodebuild archive -scheme SFT -configuration Release -archivePath build/SFT.xcarchive
+
+upload_tvos_app_store:
+	cd ../sing-box-for-apple && \
+	xcodebuild -exportArchive -archivePath "build/SFT.xcarchive" -exportOptionsPlist SFI/Upload.plist
+
+release_tvos: build_tvos upload_tvos_app_store
+
+update_apple_version:
+	go run ./cmd/internal/update_apple_version
+
+release_apple: update_apple_version release_ios release_macos release_macos_independent release_tvos
+
 test:
 test:
 	@go test -v ./... && \
 	@go test -v ./... && \
 	cd test && \
 	cd test && \
@@ -88,10 +152,10 @@ test_stdio:
 	go mod tidy && \
 	go mod tidy && \
 	go test -v -tags "$(TAGS_TEST),force_stdio" .
 	go test -v -tags "$(TAGS_TEST),force_stdio" .
 
 
-android:
+lib_android:
 	go run ./cmd/internal/build_libbox -target android
 	go run ./cmd/internal/build_libbox -target android
 
 
-ios:
+lib_ios:
 	go run ./cmd/internal/build_libbox -target ios
 	go run ./cmd/internal/build_libbox -target ios
 
 
 lib:
 lib:

+ 9 - 0
cmd/internal/build_shared/tag.go

@@ -21,3 +21,12 @@ func ReadTag() (string, error) {
 	}
 	}
 	return version.String() + "-" + shortCommit, nil
 	return version.String() + "-" + shortCommit, nil
 }
 }
+
+func ReadTagVersion() (string, error) {
+	currentTagRev, err := shell.Exec("git", "describe", "--tags", "--abbrev=0").ReadOutput()
+	if err != nil {
+		return "", err
+	}
+	version := badversion.Parse(currentTagRev[1:])
+	return version.VersionString(), nil
+}

+ 51 - 0
cmd/internal/update_android_version/main.go

@@ -0,0 +1,51 @@
+package main
+
+import (
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+
+	"github.com/sagernet/sing-box/cmd/internal/build_shared"
+	"github.com/sagernet/sing-box/log"
+	"github.com/sagernet/sing/common"
+)
+
+func main() {
+	newTag := common.Must1(build_shared.ReadTag())
+	androidPath, err := filepath.Abs("../sing-box-for-android")
+	if err != nil {
+		log.Fatal(err)
+	}
+	common.Must(os.Chdir(androidPath))
+	localProps := common.Must1(os.ReadFile("local.properties"))
+	var propsList [][]string
+	for _, propLine := range strings.Split(string(localProps), "\n") {
+		propsList = append(propsList, strings.Split(propLine, "="))
+	}
+	for _, propPair := range propsList {
+		if propPair[0] == "VERSION_NAME" {
+			if propPair[1] == newTag {
+				log.Info("version not changed")
+				return
+			}
+			propPair[1] = newTag
+			log.Info("updated version to ", newTag)
+		}
+	}
+	for _, propPair := range propsList {
+		switch propPair[0] {
+		case "VERSION_CODE":
+			versionCode := common.Must1(strconv.ParseInt(propPair[1], 10, 64))
+			propPair[1] = strconv.Itoa(int(versionCode + 1))
+			log.Info("updated version code to ", propPair[1])
+		case "RELEASE_NOTES":
+			propPair[1] = "sing-box " + newTag
+		}
+	}
+	var newProps []string
+	for _, propPair := range propsList {
+		newProps = append(newProps, strings.Join(propPair, "="))
+	}
+	common.Must(os.WriteFile("local.properties", []byte(strings.Join(newProps, "\n")), 0o644))
+}

+ 77 - 0
cmd/internal/update_apple_version/main.go

@@ -0,0 +1,77 @@
+package main
+
+import (
+	"os"
+	"path/filepath"
+	"regexp"
+	"strings"
+
+	"github.com/sagernet/sing-box/cmd/internal/build_shared"
+	"github.com/sagernet/sing-box/log"
+	"github.com/sagernet/sing/common"
+
+	"howett.net/plist"
+)
+
+func main() {
+	newVersion := common.Must1(build_shared.ReadTagVersion())
+	newTag := common.Must1(build_shared.ReadTag())
+	applePath, err := filepath.Abs("../sing-box-for-apple")
+	if err != nil {
+		log.Fatal(err)
+	}
+	common.Must(os.Chdir(applePath))
+	projectFile := common.Must1(os.Open("sing-box.xcodeproj/project.pbxproj"))
+	var project map[string]any
+	decoder := plist.NewDecoder(projectFile)
+	common.Must(decoder.Decode(&project))
+	objectsMap := project["objects"].(map[string]any)
+	projectContent := string(common.Must1(os.ReadFile("sing-box.xcodeproj/project.pbxproj")))
+	newContent, updated0 := findAndReplace(objectsMap, projectContent, []string{"io.nekohasekai.sfa"}, newVersion)
+	newContent, updated1 := findAndReplace(objectsMap, newContent, []string{"io.nekohasekai.sfa.independent", "io.nekohasekai.sfa.system"}, newTag)
+	if updated0 || updated1 {
+		log.Info("updated version to ", newTag)
+		common.Must(os.WriteFile("sing-box.xcodeproj/project.pbxproj.bak", []byte(projectContent), 0o644))
+		common.Must(os.WriteFile("sing-box.xcodeproj/project.pbxproj", []byte(newContent), 0o644))
+	} else {
+		log.Info("version not changed")
+	}
+}
+
+func findAndReplace(objectsMap map[string]any, projectContent string, bundleIDList []string, newVersion string) (string, bool) {
+	objectKeyList := findObjectKey(objectsMap, bundleIDList)
+	var updated bool
+	for _, objectKey := range objectKeyList {
+		matchRegexp := common.Must1(regexp.Compile(objectKey + ".*= \\{"))
+		indexes := matchRegexp.FindStringIndex(projectContent)
+		indexStart := indexes[1]
+		indexEnd := indexStart + strings.Index(projectContent[indexStart:], "}")
+		versionStart := indexStart + strings.Index(projectContent[indexStart:indexEnd], "MARKETING_VERSION = ") + 20
+		versionEnd := versionStart + strings.Index(projectContent[versionStart:indexEnd], ";")
+		version := projectContent[versionStart:versionEnd]
+		if version == newVersion {
+			continue
+		}
+		updated = true
+		projectContent = projectContent[indexStart:versionStart] + newVersion + projectContent[versionEnd:indexEnd]
+	}
+	return projectContent, updated
+}
+
+func findObjectKey(objectsMap map[string]any, bundleIDList []string) []string {
+	var objectKeyList []string
+	for objectKey, object := range objectsMap {
+		buildSettings := object.(map[string]any)["buildSettings"]
+		if buildSettings == nil {
+			continue
+		}
+		bundleIDObject := buildSettings.(map[string]any)["PRODUCT_BUNDLE_IDENTIFIER"]
+		if bundleIDObject == nil {
+			continue
+		}
+		if common.Contains(bundleIDList, bundleIDObject.(string)) {
+			objectKeyList = append(objectKeyList, objectKey)
+		}
+	}
+	return objectKeyList
+}

+ 4 - 0
common/badversion/version.go

@@ -57,6 +57,10 @@ func (v Version) After(anotherVersion Version) bool {
 	return false
 	return false
 }
 }
 
 
+func (v Version) VersionString() string {
+	return F.ToString(v.Major, ".", v.Minor, ".", v.Patch)
+}
+
 func (v Version) String() string {
 func (v Version) String() string {
 	version := F.ToString(v.Major, ".", v.Minor, ".", v.Patch)
 	version := F.ToString(v.Major, ".", v.Minor, ".", v.Patch)
 	if v.PreReleaseIdentifier != "" {
 	if v.PreReleaseIdentifier != "" {

+ 1 - 0
go.mod

@@ -93,5 +93,6 @@ require (
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
 	gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
 	gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
+	howett.net/plist v1.0.0 // indirect
 	lukechampine.com/blake3 v1.2.1 // indirect
 	lukechampine.com/blake3 v1.2.1 // indirect
 )
 )

+ 4 - 0
go.sum

@@ -58,6 +58,7 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
 github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d h1:Ka64cclWedOkGzm9M2/XYuwJUdmWRUozmsxW0PyKA3A=
 github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d h1:Ka64cclWedOkGzm9M2/XYuwJUdmWRUozmsxW0PyKA3A=
 github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
 github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4=
+github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
 github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
 github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
 github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
 github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
 github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
@@ -239,8 +240,11 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=
+howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g=
 lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
 lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
 lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
 lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=