diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..b87bcd7ff --- /dev/null +++ b/.dockerignore @@ -0,0 +1,52 @@ +# docker specific +.git/ + +# built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +.gradle/ +app/build/ +app/src/main/jniLibs + +# gradle-play-publisher +.android/ +*.keystore +*.jks +keys.json + +# Local configuration file (sdk path, etc) +local.properties +project.properties + +# Intellij project files +*.iml +*.ipr +*.iws +.idea/ + +# Gradle wrapper +gradle/wrapper/gradle/ +gradle/wrapper/gradlew* + +# Go modules +syncthing/pkg/mod/ +syncthing/pkg/sumdb/ + +# External build artifacts +ext/ + +# files generated by the debug scripts +debug_scripts/*.xml + +# Unsupported translations +app/src/main/play/listings/nb +app/src/main/play/listings/nl-BE +app/src/main/play/listings/nn diff --git a/.gitattributes b/.gitattributes index 8517edc4f..1a82218b0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,9 @@ -*.cmd text eol=crlf +docker/* eol=lf + +*.bash text eol=lf *.bat text eol=crlf +*.cmd text eol=crlf +*.dockerignore eol=lf +*.sh text eol=lf + +gradlew eol=lf diff --git a/.github/workflows/actions-setup.txt b/.github/workflows/actions-setup.txt new file mode 100644 index 000000000..f4ff0d8fa --- /dev/null +++ b/.github/workflows/actions-setup.txt @@ -0,0 +1,42 @@ +# +# https://github.com/settings/tokens/new +## Token name +### docker-push +## Expiration +### 30 days +## Permissions +### write:packages +### read:packages +### delete:packages +# +# Login +echo %GHP% | docker login ghcr.io -u catfriend1 --password-stdin +# +# Tag +docker tag syncthing-android-builder ghcr.io/catfriend1/syncthing-android-builder:latest +# +# Push container +docker push ghcr.io/catfriend1/syncthing-android-builder:latest +# +# Verify +## https://github.com/Catfriend1?tab=packages +# +# https://github.com/Catfriend1/syncthing-android/pkgs/container/syncthing-android-builder +## Link image to repository "Catfriend1/syncthing-android" +# +# https://github.com/users/Catfriend1/packages/container/syncthing-android-builder/settings +## Manage Actions access +### + Catfriend1/syncthing-android +# +# Setup actions +## https://github.com/Catfriend1/syncthing-android/settings/actions +### Allow GitHub Actions to use actions created by GitHub +### Allow actions created by Marketplace +# +# Add repository strings: https://github.com/Catfriend1/syncthing-android/settings/secrets/actions +## DEBUG_KEYSTORE_B64 +### powershell "[Convert]::ToBase64String([IO.File]::ReadAllBytes(${env:USERPROFILE} + '\.android\debug.keystore'))" > "X:\debug.keystore.b64" +## SIGNING_KEYSTORE_JKS_BASE64 +### powershell "[Convert]::ToBase64String([IO.File]::ReadAllBytes(${env:USERPROFILE} + '\.android\catfriend1.jks'))" > "X:\catfriend1.jks.b64" +## SIGNING_PASSWORD +### [PWD] diff --git a/.github/workflows/build-app.yaml b/.github/workflows/build-app.yaml index bb28e6332..ccb59c6ce 100644 --- a/.github/workflows/build-app.yaml +++ b/.github/workflows/build-app.yaml @@ -16,25 +16,28 @@ jobs: build: name: Debug Build runs-on: ubuntu-latest - container: ghcr.io/syncthing/syncthing-android-builder + container: ghcr.io/catfriend1/syncthing-android-builder steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 - name: build run: | + set -eu + mkdir -p ~/.android + echo '${{ secrets.DEBUG_KEYSTORE_B64 }}' | base64 -d > ~/.android/debug.keystore git config --system --add safe.directory '*' java -version - ./gradlew --no-daemon buildNative lint assembleDebug + ./gradlew --no-daemon buildNative lintDebug assembleDebug - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: syncthing-android-debug.apk path: app/build/outputs/apk/debug/app-debug.apk - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: reports-and-libs path: | diff --git a/.github/workflows/image-builder-template.yaml b/.github/workflows/image-builder-template.yaml index c6e2eda60..7c77a7b1c 100644 --- a/.github/workflows/image-builder-template.yaml +++ b/.github/workflows/image-builder-template.yaml @@ -12,21 +12,21 @@ env: BUILD_USER: android-builder BUILD_HOST: github.syncthing.net # template var - image: ghcr.io/syncthing/syncthing-android-builder + image: ghcr.io/catfriend1/syncthing-android-builder jobs: build-image: name: Build Builder Docker runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 - uses: docker/setup-buildx-action@v2 - - uses: docker/login-action@v2 + - uses: docker/login-action@v3 if: ${{ inputs.push }} with: registry: ghcr.io diff --git a/.github/workflows/release-app.yaml b/.github/workflows/release-app.yaml index 0c782228c..4502efee5 100644 --- a/.github/workflows/release-app.yaml +++ b/.github/workflows/release-app.yaml @@ -4,10 +4,10 @@ on: push: # Cannot filter on both branches (release) and tags - it's ORed tags: - - '[0-9]+.[0-9]+.[0-9]+' - - '[0-9]+.[0-9]+.[0-9]+.[0-9]+' - - '[0-9]+.[0-9]+.[0-9]+-rc\.[0-9]+' - - '[0-9]+.[0-9]+.[0-9]+-rc\.[0-9]+\.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-rc\.[0-9]+' + - 'v[0-9]+.[0-9]+.[0-9]+-rc\.[0-9]+\.[0-9]+' env: # Our build metadata @@ -18,9 +18,9 @@ jobs: release: name: Release Build and Publish runs-on: ubuntu-latest - container: ghcr.io/syncthing/syncthing-android-builder + container: ghcr.io/catfriend1/syncthing-android-builder steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: true fetch-depth: 0 @@ -35,29 +35,30 @@ jobs: - name: build_release env: - SYNCTHING_RELEASE_KEY_ALIAS: android + SYNCTHING_RELEASE_KEY_ALIAS: Syncthing-Fork SIGNING_PASSWORD: '${{ secrets.SIGNING_PASSWORD }}' SYNCTHING_RELEASE_STORE_FILE: '${{ runner.temp }}/signing-keystore.jks' - SYNCTHING_RELEASE_PLAY_ACCOUNT_CONFIG_FILE: '${{ runner.temp }}/google-play-secrets.json' + # SYNCTHING_RELEASE_PLAY_ACCOUNT_CONFIG_FILE: '${{ runner.temp }}/google-play-secrets.json' shell: bash run: | - set -eu -o pipefail + set -eu echo '${{ secrets.SIGNING_KEYSTORE_JKS_BASE64 }}' | base64 -d > "$SYNCTHING_RELEASE_STORE_FILE" - echo '${{ secrets.GOOGLE_PLAY_SECRETS_BASE64 }}' | base64 -d > "$SYNCTHING_RELEASE_PLAY_ACCOUNT_CONFIG_FILE" + # echo '${{ secrets.GOOGLE_PLAY_SECRETS_BASE64 }}' | base64 -d > "$SYNCTHING_RELEASE_PLAY_ACCOUNT_CONFIG_FILE" java -version # TODO: Readd publishReleaseBundle if google play works again, or # remove everything related to publishing to google play. - ./gradlew --no-daemon buildNative lint assembleRelease bundleRelease - rm "$SYNCTHING_RELEASE_STORE_FILE" "$SYNCTHING_RELEASE_PLAY_ACCOUNT_CONFIG_FILE" + ./gradlew --no-daemon buildNative lintRelease assembleRelease bundleRelease + # rm "$SYNCTHING_RELEASE_STORE_FILE" "$SYNCTHING_RELEASE_PLAY_ACCOUNT_CONFIG_FILE" - echo '${{ secrets.GNUPG_SIGNING_KEY_BASE64 }}' | base64 -d | gpg --import - cd app/build/outputs/apk/release - sha256sum app-release.apk | gpg --clearsign > sha256sum.txt.asc + # echo '${{ secrets.GNUPG_SIGNING_KEY_BASE64 }}' | base64 -d | gpg --import + # cd app/build/outputs/apk/release + # sha256sum app-release.apk | gpg --clearsign > sha256sum.txt.asc - uses: ncipollo/release-action@v1 with: - artifacts: "app/build/outputs/apk/release/*.apk,app/build/outputs/apk/release/*.asc" + # TODO: Readd ,app/build/outputs/apk/release/*.asc + artifacts: "app/build/outputs/apk/release/*.apk" artifactErrorsFailBuild: true - bodyFile: "app/src/main/play/release-notes/en-GB/default.txt" + bodyFile: "app/src/main/play/release-notes/en-US/default.txt" prerelease: ${{ contains('-rc.', github.ref_name) }} draft: true diff --git a/.gitignore b/.gitignore index 350d9329d..96820de3f 100644 --- a/.gitignore +++ b/.gitignore @@ -9,8 +9,15 @@ *.class # generated files -build/ .gradle/ +app/build/ +app/src/main/jniLibs + +# gradle-play-publisher +.android/ +*.keystore +*.jks +keys.json # Local configuration file (sdk path, etc) local.properties diff --git a/app/.gitignore b/app/.gitignore deleted file mode 100644 index 53223ea26..000000000 --- a/app/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# generated files -/build -/src/main/jniLibs - -# gradle-play-publisher -keys.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 4a330ec38..071d347f0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -108,6 +108,8 @@ android { packaging { jniLibs { + // Otherwise libsyncthing.so doesn't appear where it should in installs + // based on app bundles, and thus nothing works. useLegacyPackaging = true } } diff --git a/docker/Dockerfile b/docker/Dockerfile index 56f61eece..8200ebf74 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,10 +1,10 @@ FROM eclipse-temurin:17-jdk-jammy -ENV GO_VERSION 1.22.7 +ENV GO_VERSION=1.24.1 # Can be found scrolling down on this page: # https://developer.android.com/studio/index.html#command-tools -ARG ANDROID_SDK_FILENAME=commandlinetools-linux-9123335_latest.zip +ARG ANDROID_SDK_FILENAME=commandlinetools-linux-11076708_latest.zip WORKDIR /opt # The '--reinstall' combined with 'build-essentials' is necessary for cgo @@ -16,15 +16,15 @@ RUN apt-get update && apt-get install --reinstall --no-install-recommends -y bui RUN wget -nv https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz && \ tar -zxf go${GO_VERSION}.linux-amd64.tar.gz && \ rm go${GO_VERSION}.linux-amd64.tar.gz -ENV GOROOT /opt/go -ENV PATH /opt/go/bin:${PATH} +ENV GOROOT=/opt/go +ENV PATH=/opt/go/bin:${PATH} # Install Android SDK manager RUN mkdir -p /opt/android-sdk && cd /opt/android-sdk && \ wget -q https://dl.google.com/android/repository/${ANDROID_SDK_FILENAME} && \ unzip -q ${ANDROID_SDK_FILENAME} && \ rm ${ANDROID_SDK_FILENAME} -ENV ANDROID_HOME /opt/android-sdk +ENV ANDROID_HOME=/opt/android-sdk ARG SDKMANAGER="${ANDROID_HOME}/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROID_HOME}" @@ -32,8 +32,8 @@ ARG SDKMANAGER="${ANDROID_HOME}/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROI RUN yes | $SDKMANAGER --licenses > /dev/null # NDK version -ENV NDK_VERSION 27.0.12077973 -ENV TARGET_SDK_VERSION 35 +ENV NDK_VERSION=28.0.13004108 +ENV TARGET_SDK_VERSION=35 # Install other android packages, including NDK RUN $SDKMANAGER tools platform-tools "build-tools;${TARGET_SDK_VERSION}.0.0" "platforms;android-${TARGET_SDK_VERSION}" "extras;android;m2repository" "ndk;${NDK_VERSION}" @@ -42,16 +42,20 @@ RUN $SDKMANAGER tools platform-tools "build-tools;${TARGET_SDK_VERSION}.0.0" "pl RUN yes | $SDKMANAGER --licenses # Enable prebuild mode -ENV SYNCTHING_ANDROID_PREBUILT 1 +ENV SYNCTHING_ANDROID_PREBUILT=1 # Set location of go cache -ENV GOCACHE /opt/gocache +ENV GOCACHE=/opt/gocache # Set location of GOPATH to persist packages for module builds in GOPATH/pkg/mod -ENV GOPATH /opt/gopath +ENV GOPATH=/opt/gopath # Run prebuild script (will prebuild stuff into the image if env var is set) ADD . /opt/syncthing-android + +RUN find /opt/syncthing-android -name "*.sh" -exec sed -i 's/\r$//' {} \; +RUN find /opt/syncthing-android -name "gradlew" -exec sed -i 's/\r$//' {} \; + RUN /opt/syncthing-android/docker/prebuild.sh WORKDIR /mnt diff --git a/docker/README.md b/docker/README.md index 39038d0ff..ad19bfef7 100644 --- a/docker/README.md +++ b/docker/README.md @@ -1,3 +1,72 @@ +# Fresh howto to build with Docker Desktop under WSL 2 + +## Add WSL feature +``` +dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart +dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart +``` + +## Reboot +``` +shutdown -r -t 0 +``` + +## Set WSL version 2 +``` +wsl --set-default-version 2 +``` + +## Install Debian Linux +``` +wsl.exe --install debian +wsl.exe -l -v +``` + +## Install Docker Desktop +- Download https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe +- Install +- logoff +- Relogon + +## Docker Desktop +- Settings +- Resources +- Resources / Advanced +- Resources / Advanced / Disk image location +``` +%LocalAppData%\docker\wsl +``` +- Resources / Advanced / WSL integration +Enable integration with my default WSL distro +``` +Debian +``` + +## Docker build step +- Open "cmd" +``` +cd /d "syncthing-android" + +docker build -t syncthing-android-builder:latest -f docker/Dockerfile . +docker run --rm -v "%userprofile%/.android/debug.keystore:/root/.android/debug.keystore:ro" -v .:/mnt syncthing-android-builder:latest ./gradlew buildNative assembleDebug +``` + + +## Container insight +``` +docker run -it --rm syncthing-android-builder bash +du -h -d 1 / +du -h -d 1 /opt +du -h -d 1 /root +``` + +## Destroy docker container +``` +docker images +docker rmi syncthing-android-builder:latest +``` + + # How to use this ## Create the builder image diff --git a/docker/prebuild.sh b/docker/prebuild.sh index 117e64dca..c951240fd 100755 --- a/docker/prebuild.sh +++ b/docker/prebuild.sh @@ -1,4 +1,4 @@ -#!/bin/bash -e +#!/bin/bash if [ -z "$SYNCTHING_ANDROID_PREBUILT" ]; then echo "Prebuild disabled" diff --git a/gradle.properties b/gradle.properties index f8b6780ad..b5f1a5733 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,3 +2,4 @@ android.enableJetifier=false android.nonFinalResIds=false android.nonTransitiveRClass=false android.useAndroidX=true +org.gradle.jvmargs=-Xmx4096M diff --git a/syncthing/build-syncthing.py b/syncthing/build-syncthing.py index 81cacfb4c..91b5783a5 100644 --- a/syncthing/build-syncthing.py +++ b/syncthing/build-syncthing.py @@ -29,6 +29,7 @@ NDK_VERSION = 'r28' NDK_EXPECTED_SHASUM_LINUX = '894f469c5192a116d21f412de27966140a530ebc' NDK_EXPECTED_SHASUM_WINDOWS = 'f79a00c721dc5c15b2bf093d7bb2af96496a42b2' +# The values here must correspond with those in ../docker/prebuild.sh BUILD_TARGETS = [ { 'arch': 'arm', @@ -226,11 +227,18 @@ def write_file(fullfn, text): def get_ndk_ready(): if os.environ.get('ANDROID_NDK_HOME', ''): return - if not (os.environ.get('NDK_VERSION', '') and os.environ.get('ANDROID_SDK_ROOT', '')): - print('ANDROID_NDK_HOME env var is not defined. Then, NDK_VERSION and ANDROID_SDK_ROOT env vars must be defined.') + ndk_env_vars_defined = True + if not os.environ.get('NDK_VERSION', ''): + print('NDK_VERSION is NOT defined.') + ndk_env_vars_defined = False + if not os.environ.get('ANDROID_HOME', ''): + print('ANDROID_HOME is NOT defined.') + ndk_env_vars_defined = False + if not ndk_env_vars_defined: + print('ANDROID_NDK_HOME or NDK_VERSION and ANDROID_HOME environment variable must be defined.') install_ndk() return - os.environ["ANDROID_NDK_HOME"] = os.path.join(os.environ['ANDROID_SDK_ROOT'], 'ndk', os.environ['NDK_VERSION']) + os.environ["ANDROID_NDK_HOME"] = os.path.join(os.environ['ANDROID_HOME'], 'ndk', os.environ['NDK_VERSION']) return