diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 334964e0..32a524f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -62,6 +62,141 @@ jobs: GPG_FINGERPRINT: ${{ steps.import_gpg.outputs.fingerprint }} HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} + vfs-build-linux: + name: Build VFS (Linux ${{ matrix.arch }}) + runs-on: ubuntu-20.04 # Use older Ubuntu for broader glibc compatibility (2.31) + needs: goreleaser + strategy: + matrix: + arch: [amd64, arm64] + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Install cross-compiler (arm64) + if: matrix.arch == 'arm64' + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu + + - name: Get version + id: version + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "version=${{ inputs.tag }}" >> $GITHUB_OUTPUT + else + echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + fi + + - name: Build VFS extension + run: make vfs-linux-${{ matrix.arch }} + + - name: Verify artifact + run: | + file dist/litestream-vfs-linux-${{ matrix.arch }}.so + # For native arch, verify it can be loaded by SQLite + if [ "${{ matrix.arch }}" == "amd64" ]; then + sqlite3 ':memory:' ".load dist/litestream-vfs-linux-amd64.so" ".exit" && echo "Extension loads successfully" + fi + # For cross-compiled arch, verify ELF header and architecture + if [ "${{ matrix.arch }}" == "arm64" ]; then + readelf -h dist/litestream-vfs-linux-arm64.so | grep -E "(Class|Machine)" + echo "ARM64 ELF header verified" + fi + + - name: Create archive + run: | + cd dist + cp litestream-vfs-linux-${{ matrix.arch }}.so litestream-vfs.so + tar -czvf litestream-vfs-${{ steps.version.outputs.version }}-linux-${{ matrix.arch }}.tar.gz \ + litestream-vfs.so + + - name: Generate checksum + run: | + cd dist + sha256sum litestream-vfs-${{ steps.version.outputs.version }}-linux-${{ matrix.arch }}.tar.gz \ + > litestream-vfs-${{ steps.version.outputs.version }}-linux-${{ matrix.arch }}.tar.gz.sha256 + + - name: Upload to release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload ${{ steps.version.outputs.version }} \ + dist/litestream-vfs-${{ steps.version.outputs.version }}-linux-${{ matrix.arch }}.tar.gz \ + dist/litestream-vfs-${{ steps.version.outputs.version }}-linux-${{ matrix.arch }}.tar.gz.sha256 \ + --clobber + + vfs-build-darwin: + name: Build VFS (macOS ${{ matrix.arch }}) + runs-on: ${{ matrix.runner }} + needs: goreleaser + strategy: + matrix: + include: + - arch: amd64 + runner: macos-13 + - arch: arm64 + runner: macos-14 + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Get version + id: version + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + echo "version=${{ inputs.tag }}" >> $GITHUB_OUTPUT + else + echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + fi + + - name: Build VFS extension + run: make vfs-darwin-${{ matrix.arch }} + + - name: Verify artifact + run: | + file dist/litestream-vfs-darwin-${{ matrix.arch }}.dylib + # Verify the extension can be loaded by SQLite + sqlite3 ':memory:' ".load dist/litestream-vfs-darwin-${{ matrix.arch }}.dylib" ".exit" && echo "Extension loads successfully" + + - name: Create archive + run: | + cd dist + cp litestream-vfs-darwin-${{ matrix.arch }}.dylib litestream-vfs.dylib + tar -czvf litestream-vfs-${{ steps.version.outputs.version }}-darwin-${{ matrix.arch }}.tar.gz \ + litestream-vfs.dylib + + - name: Generate checksum + run: | + cd dist + shasum -a 256 litestream-vfs-${{ steps.version.outputs.version }}-darwin-${{ matrix.arch }}.tar.gz \ + > litestream-vfs-${{ steps.version.outputs.version }}-darwin-${{ matrix.arch }}.tar.gz.sha256 + + - name: Upload to release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload ${{ steps.version.outputs.version }} \ + dist/litestream-vfs-${{ steps.version.outputs.version }}-darwin-${{ matrix.arch }}.tar.gz \ + dist/litestream-vfs-${{ steps.version.outputs.version }}-darwin-${{ matrix.arch }}.tar.gz.sha256 \ + --clobber + # macos-sign: # runs-on: macos-latest # needs: goreleaser diff --git a/.goreleaser.yml b/.goreleaser.yml index a8f7209b..029674f7 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -151,6 +151,17 @@ release: ### Binary installation Download the appropriate archive for your platform, extract, and move to your PATH. + ## VFS Extension (Experimental) + + SQLite loadable extensions for read-only access to Litestream replicas are available for supported platforms: + + | Platform | File | + |----------|------| + | Linux x86_64 | `litestream-vfs-v{{.Version}}-linux-amd64.tar.gz` | + | Linux ARM64 | `litestream-vfs-v{{.Version}}-linux-arm64.tar.gz` | + | macOS Intel | `litestream-vfs-v{{.Version}}-darwin-amd64.tar.gz` | + | macOS Apple Silicon | `litestream-vfs-v{{.Version}}-darwin-arm64.tar.gz` | + # Signing configuration # signs: # - id: macos diff --git a/Makefile b/Makefile index 5c55a014..ebd06fb3 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,14 @@ default: docker: docker build -t litestream . +# VFS build configuration +VFS_BUILD_TAGS := vfs,SQLITE3VFS_LOADABLE_EXT +VFS_SRC := ./cmd/litestream-vfs +VFS_C_SRC := src/litestream-vfs.c +MACOSX_MIN_VERSION := 11.0 +DARWIN_LDFLAGS := -framework CoreFoundation -framework Security -lresolv -mmacosx-version-min=$(MACOSX_MIN_VERSION) +LINUX_LDFLAGS := -lpthread -ldl -lm + .PHONY: vfs vfs: mkdir -p dist @@ -10,6 +18,42 @@ vfs: mv dist/litestream-vfs.h src/litestream-vfs.h gcc -framework CoreFoundation -framework Security -lresolv -g -fPIC -shared -o dist/litestream-vfs.so src/litestream-vfs.c dist/litestream-vfs.a +.PHONY: vfs-linux-amd64 +vfs-linux-amd64: + mkdir -p dist + CGO_ENABLED=1 GOOS=linux GOARCH=amd64 \ + go build -tags $(VFS_BUILD_TAGS) -o dist/litestream-vfs-linux-amd64.a -buildmode=c-archive $(VFS_SRC) + cp dist/litestream-vfs-linux-amd64.h src/litestream-vfs.h + gcc -g -fPIC -shared -o dist/litestream-vfs-linux-amd64.so \ + $(VFS_C_SRC) dist/litestream-vfs-linux-amd64.a $(LINUX_LDFLAGS) + +.PHONY: vfs-linux-arm64 +vfs-linux-arm64: + mkdir -p dist + CGO_ENABLED=1 GOOS=linux GOARCH=arm64 CC=aarch64-linux-gnu-gcc \ + go build -tags $(VFS_BUILD_TAGS) -o dist/litestream-vfs-linux-arm64.a -buildmode=c-archive $(VFS_SRC) + cp dist/litestream-vfs-linux-arm64.h src/litestream-vfs.h + aarch64-linux-gnu-gcc -g -fPIC -shared -o dist/litestream-vfs-linux-arm64.so \ + $(VFS_C_SRC) dist/litestream-vfs-linux-arm64.a $(LINUX_LDFLAGS) + +.PHONY: vfs-darwin-amd64 +vfs-darwin-amd64: + mkdir -p dist + CGO_ENABLED=1 GOOS=darwin GOARCH=amd64 \ + go build -tags $(VFS_BUILD_TAGS) -o dist/litestream-vfs-darwin-amd64.a -buildmode=c-archive $(VFS_SRC) + cp dist/litestream-vfs-darwin-amd64.h src/litestream-vfs.h + clang -arch x86_64 -g -fPIC -shared -o dist/litestream-vfs-darwin-amd64.dylib \ + $(VFS_C_SRC) dist/litestream-vfs-darwin-amd64.a $(DARWIN_LDFLAGS) + +.PHONY: vfs-darwin-arm64 +vfs-darwin-arm64: + mkdir -p dist + CGO_ENABLED=1 GOOS=darwin GOARCH=arm64 \ + go build -tags $(VFS_BUILD_TAGS) -o dist/litestream-vfs-darwin-arm64.a -buildmode=c-archive $(VFS_SRC) + cp dist/litestream-vfs-darwin-arm64.h src/litestream-vfs.h + clang -arch arm64 -g -fPIC -shared -o dist/litestream-vfs-darwin-arm64.dylib \ + $(VFS_C_SRC) dist/litestream-vfs-darwin-arm64.a $(DARWIN_LDFLAGS) + vfs-test: go test -v -tags=vfs ./cmd/litestream-vfs