diff --git a/Makefile b/Makefile index 8e766738..5533ed90 100644 --- a/Makefile +++ b/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/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: go run ./cmd/internal/build goreleaser release --clean --skip-publish || exit 1 mkdir 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 release_install: go install -v github.com/goreleaser/goreleaser@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: @go test -v ./... && \ cd test && \ @@ -88,10 +152,10 @@ test_stdio: go mod tidy && \ go test -v -tags "$(TAGS_TEST),force_stdio" . -android: +lib_android: go run ./cmd/internal/build_libbox -target android -ios: +lib_ios: go run ./cmd/internal/build_libbox -target ios lib: diff --git a/cmd/internal/build_shared/tag.go b/cmd/internal/build_shared/tag.go index b1fecab4..089713bc 100644 --- a/cmd/internal/build_shared/tag.go +++ b/cmd/internal/build_shared/tag.go @@ -21,3 +21,12 @@ func ReadTag() (string, error) { } 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 +} diff --git a/cmd/internal/update_android_version/main.go b/cmd/internal/update_android_version/main.go new file mode 100644 index 00000000..b93e2ff8 --- /dev/null +++ b/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)) +} diff --git a/cmd/internal/update_apple_version/main.go b/cmd/internal/update_apple_version/main.go new file mode 100644 index 00000000..b77f02cf --- /dev/null +++ b/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 +} diff --git a/common/badversion/version.go b/common/badversion/version.go index 23168eca..ccff02a6 100644 --- a/common/badversion/version.go +++ b/common/badversion/version.go @@ -57,6 +57,10 @@ func (v Version) After(anotherVersion Version) bool { return false } +func (v Version) VersionString() string { + return F.ToString(v.Major, ".", v.Minor, ".", v.Patch) +} + func (v Version) String() string { version := F.ToString(v.Major, ".", v.Minor, ".", v.Patch) if v.PreReleaseIdentifier != "" { diff --git a/go.mod b/go.mod index 5d1af02e..f066690e 100644 --- a/go.mod +++ b/go.mod @@ -93,5 +93,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + howett.net/plist v1.0.0 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/go.sum b/go.sum index 9385b379..cdb963fb 100644 --- a/go.sum +++ b/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/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/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.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= 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 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/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 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/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=