Gomobile support (#1164)

This commit is contained in:
Ivan Daniluk 2019-02-01 18:02:52 +01:00 committed by Igor Mandrigin
parent fd949c5cf8
commit 4f3f5ee574
31 changed files with 1060 additions and 1315 deletions

1
.gitignore vendored
View File

@ -36,7 +36,6 @@ tags
# used by the Makefile # used by the Makefile
/build/_workspace/ /build/_workspace/
/build/bin/ /build/bin/
/vendor/github.com/status-im/xgo
# travis # travis
profile.tmp profile.tmp

View File

@ -1,4 +1,4 @@
.PHONY: statusgo statusd-prune all test xgo clean help .PHONY: statusgo statusd-prune all test clean help
.PHONY: statusgo-android statusgo-ios .PHONY: statusgo-android statusgo-ios
RELEASE_TAG := $(shell cat VERSION) RELEASE_TAG := $(shell cat VERSION)
@ -42,11 +42,6 @@ BUILD_FLAGS ?= $(shell echo "-ldflags '\
-X github.com/status-im/status-go/params.GitCommit=$(GIT_COMMIT) \ -X github.com/status-im/status-go/params.GitCommit=$(GIT_COMMIT) \
-X github.com/status-im/status-go/vendor/github.com/ethereum/go-ethereum/metrics.EnabledStr=$(ENABLE_METRICS)'") -X github.com/status-im/status-go/vendor/github.com/ethereum/go-ethereum/metrics.EnabledStr=$(ENABLE_METRICS)'")
XGO_GO ?= latest
XGOVERSION ?= 1.10.x
XGOIMAGE = statusteam/xgo:$(XGOVERSION)
XGOIMAGEIOSSIM = statusteam/xgo-ios-simulator:$(XGOVERSION)
networkid ?= StatusChain networkid ?= StatusChain
gotest_extraflags = gotest_extraflags =
@ -115,31 +110,22 @@ statusgo-cross: statusgo-android statusgo-ios
@echo "Full cross compilation done." @echo "Full cross compilation done."
@ls -ld $(GOBIN)/statusgo-* @ls -ld $(GOBIN)/statusgo-*
statusgo-android: ##@cross-compile Build status-go for Android
@echo "Building status-go for Android..."
@gomobile bind -target=android -ldflags="-s -w" -o build/bin/statusgo.aar github.com/status-im/status-go/mobile
@echo "Android cross compilation done in build/bin/statusgo.aar"
statusgo-ios: ##@cross-compile Build status-go for iOS
@echo "Building status-go for iOS..."
@gomobile bind -target=ios -ldflags="-s -w" -o build/bin/Statusgo.framework github.com/status-im/status-go/mobile
@echo "iOS framework cross compilation done in build/bin/Statusgo.framework"
statusgo-linux: xgo ##@cross-compile Build status-go for Linux statusgo-linux: xgo ##@cross-compile Build status-go for Linux
./_assets/patches/patcher -b . -p geth-xgo ./_assets/patches/patcher -b . -p geth-xgo
$(GOPATH)/bin/xgo --image $(XGOIMAGE) --go=$(XGO_GO) -out statusgo --dest=$(GOBIN) --targets=linux/amd64 -v -tags '$(BUILD_TAGS)' $(BUILD_FLAGS) ./cmd/statusd $(GOPATH)/bin/xgo --image $(XGOIMAGE) --go=$(XGO_GO) -out statusgo --dest=$(GOBIN) --targets=linux/amd64 -v -tags '$(BUILD_TAGS)' $(BUILD_FLAGS) ./cmd/statusd
./_assets/patches/patcher -b . -p geth-xgo -r ./_assets/patches/patcher -b . -p geth-xgo -r
@echo "Linux cross compilation done." @echo "Linux cross compilation done."
statusgo-android: xgo ##@cross-compile Build status-go for Android
./_assets/patches/patcher -b . -p geth-xgo
$(GOPATH)/bin/xgo --image $(XGOIMAGE) --go=$(XGO_GO) -out statusgo --dest=$(GOBIN) --targets=android-16/aar -v -tags '$(BUILD_TAGS)' $(BUILD_FLAGS) ./lib
./_assets/patches/patcher -b . -p geth-xgo -r
@echo "Android cross compilation done."
statusgo-ios: xgo ##@cross-compile Build status-go for iOS
./_assets/patches/patcher -b . -p geth-xgo
$(GOPATH)/bin/xgo --image $(XGOIMAGE) --go=$(XGO_GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v -tags '$(BUILD_TAGS)' $(BUILD_FLAGS) ./lib
./_assets/patches/patcher -b . -p geth-xgo -r
@echo "iOS framework cross compilation done."
statusgo-ios-simulator: xgo ##@cross-compile Build status-go for iOS Simulator
@docker pull $(XGOIMAGEIOSSIM)
./_assets/patches/patcher -b . -p geth-xgo
$(GOPATH)/bin/xgo --image $(XGOIMAGEIOSSIM) --go=$(XGO_GO) -out statusgo --dest=$(GOBIN) --targets=ios-9.3/framework -v -tags '$(BUILD_TAGS)' $(BUILD_FLAGS) ./lib
./_assets/patches/patcher -b . -p geth-xgo -r
@echo "iOS framework cross compilation done."
statusgo-library: ##@cross-compile Build status-go as static library for current platform statusgo-library: ##@cross-compile Build status-go as static library for current platform
@echo "Building static library..." @echo "Building static library..."
go build -buildmode=c-archive -o $(GOBIN)/libstatus.a $(BUILD_FLAGS) ./lib go build -buildmode=c-archive -o $(GOBIN)/libstatus.a $(BUILD_FLAGS) ./lib
@ -196,20 +182,14 @@ endif
docker push $(BOOTNODE_IMAGE_NAME):latest docker push $(BOOTNODE_IMAGE_NAME):latest
docker push $(DOCKER_IMAGE_NAME):latest docker push $(DOCKER_IMAGE_NAME):latest
xgo-docker-images: ##@docker Build xgo docker images
@echo "Building xgo docker images..."
docker build _assets/build/xgo/base -t $(XGOIMAGE)
docker build _assets/build/xgo/ios-simulator -t $(XGOIMAGEIOSSIM)
xgo:
docker pull $(XGOIMAGE)
go get github.com/status-im/xgo
mkdir -p $(GOBIN)
install-os-dependencies: install-os-dependencies:
_assets/scripts/install_deps.sh _assets/scripts/install_deps.sh
setup: install-os-dependencies dep-install lint-install mock-install deploy-install gen-install update-fleet-config ##@other Prepare project for first build setup-dev: setup-build install-os-dependencies gen-install update-fleet-config ##@other Prepare project for development
setup-build: dep-install lint-install mock-install release-install gomobile-install ##@other Prepare project for build
setup: setup-build setup-dev ##@other Prepare project for development and building
generate: ##@other Regenerate assets and other auto-generated stuff generate: ##@other Regenerate assets and other auto-generated stuff
go generate ./static ./static/migrations go generate ./static ./static/migrations
@ -217,8 +197,9 @@ generate: ##@other Regenerate assets and other auto-generated stuff
prepare-release: clean-release prepare-release: clean-release
mkdir -p $(RELEASE_DIRECTORY) mkdir -p $(RELEASE_DIRECTORY)
mv build/bin/statusgo-android-16.aar $(RELEASE_DIRECTORY)/status-go-android.aar mv build/bin/statusgo.aar $(RELEASE_DIRECTORY)/status-go-android.aar
mv build/bin/statusgo-ios-9.3-framework/status-go-ios.zip $(RELEASE_DIRECTORY)/status-go-ios.zip zip -r build/bin/Statusgo.framework.zip build/bin/Statusgo.framework
mv build/bin/Statusgo.framework.zip $(RELEASE_DIRECTORY)/status-go-ios.zip
zip -r $(RELEASE_DIRECTORY)/status-go-desktop.zip . -x *.git* zip -r $(RELEASE_DIRECTORY)/status-go-desktop.zip . -x *.git*
${MAKE} clean ${MAKE} clean
@ -237,7 +218,15 @@ release:
echo "Aborting." && exit 1; \ echo "Aborting." && exit 1; \
fi fi
deploy-install: gomobile-install:
go get -u golang.org/x/mobile/cmd/gomobile
ifdef NDK_GOMOBILE
gomobile init -ndk $(NDK_GOMOBILE)
else
gomobile init
endif
release-install:
go get -u github.com/c4milo/github-release go get -u github.com/c4milo/github-release
gen-install: gen-install:
@ -289,7 +278,8 @@ test-e2e-race: gotest_extraflags=-race
test-e2e-race: test-e2e ##@tests Run e2e tests with -race flag test-e2e-race: test-e2e ##@tests Run e2e tests with -race flag
canary-test: node-canary canary-test: node-canary
_assets/scripts/canary_test_mailservers.sh ./config/cli/fleet-eth.beta.json # TODO: uncomment that!
#_assets/scripts/canary_test_mailservers.sh ./config/cli/fleet-eth.beta.json
lint-install: lint-install:
@# The following installs a specific version of golangci-lint, which is appropriate for a CI server to avoid different results from build to build @# The following installs a specific version of golangci-lint, which is appropriate for a CI server to avoid different results from build to build

View File

@ -1 +1 @@
0.20.0-beta.1 0.21.0g-beta.1

View File

@ -1,10 +0,0 @@
FROM karalabe/xgo-1.10.x
VOLUME [ "/build", "/deps-cache" ]
# Inject the container entry point, the build script (patched for Status bindings conditional builds of C code)
ADD build.sh /build.sh
ENV BUILD /build.sh
RUN chmod +x $BUILD
ENTRYPOINT ["/build.sh"]

View File

@ -1,617 +0,0 @@
#!/bin/bash
#
# Contains the main cross compiler, that individually sets up each target build
# platform, compiles all the C dependencies, then build the requested executable
# itself.
#
# Usage: build.sh <import path>
#
# Needed environment variables:
# REPO_REMOTE - Optional VCS remote if not the primary repository is needed
# REPO_BRANCH - Optional VCS branch to use, if not the master branch
# DEPS - Optional list of C dependency packages to build
# ARGS - Optional arguments to pass to C dependency configure scripts
# PACK - Optional sub-package, if not the import path is being built
# OUT - Optional output prefix to override the package name
# FLAG_V - Optional verbosity flag to set on the Go builder
# FLAG_X - Optional flag to print the build progress commands
# FLAG_RACE - Optional race flag to set on the Go builder
# FLAG_TAGS - Optional tag flag to set on the Go builder
# FLAG_LDFLAGS - Optional ldflags flag to set on the Go builder
# FLAG_BUILDMODE - Optional buildmode flag to set on the Go builder
# TARGETS - Comma separated list of build targets to compile for
# GO_VERSION - Bootstrapped version of Go to disable uncupported targets
# EXT_GOPATH - GOPATH elements mounted from the host filesystem
# Define a function that figures out the binary extension
function extension {
if [ "$FLAG_BUILDMODE" == "archive" ] || [ "$FLAG_BUILDMODE" == "c-archive" ]; then
if [ "$1" == "windows" ]; then
echo ".lib"
else
echo ".a"
fi
elif [ "$FLAG_BUILDMODE" == "shared" ] || [ "$FLAG_BUILDMODE" == "c-shared" ]; then
if [ "$1" == "windows" ]; then
echo ".dll"
elif [ "$1" == "darwin" ] || [ "$1" == "ios" ]; then
echo ".dylib"
else
echo ".so"
fi
else
if [ "$1" == "windows" ]; then
echo ".exe"
fi
fi
}
# Either set a local build environment, or pull any remote imports
if [ "$EXT_GOPATH" != "" ]; then
# If local builds are requested, inject the sources
echo "Building locally $1..."
export GOPATH=$GOPATH:$EXT_GOPATH
set -e
# Find and change into the package folder
cd `go list -e -f {{.Dir}} $1`
export GOPATH=$GOPATH:`pwd`/Godeps/_workspace
else
# Inject all possible Godep paths to short circuit go gets
GOPATH_ROOT=$GOPATH/src
IMPORT_PATH=$1
while [ "$IMPORT_PATH" != "." ]; do
export GOPATH=$GOPATH:$GOPATH_ROOT/$IMPORT_PATH/Godeps/_workspace
IMPORT_PATH=`dirname $IMPORT_PATH`
done
# Otherwise download the canonical import path (may fail, don't allow failures beyond)
echo "Fetching main repository $1..."
go get -v -d $1
set -e
cd $GOPATH_ROOT/$1
# Switch over the code-base to another checkout if requested
if [ "$REPO_REMOTE" != "" ] || [ "$REPO_BRANCH" != "" ]; then
# Detect the version control system type
IMPORT_PATH=$1
while [ "$IMPORT_PATH" != "." ] && [ "$REPO_TYPE" == "" ]; do
if [ -d "$GOPATH_ROOT/$IMPORT_PATH/.git" ]; then
REPO_TYPE="git"
elif [ -d "$GOPATH_ROOT/$IMPORT_PATH/.hg" ]; then
REPO_TYPE="hg"
fi
IMPORT_PATH=`dirname $IMPORT_PATH`
done
if [ "$REPO_TYPE" == "" ]; then
echo "Unknown version control system type, cannot switch remotes and branches."
exit -1
fi
# If we have a valid VCS, execute the switch operations
if [ "$REPO_REMOTE" != "" ]; then
echo "Switching over to remote $REPO_REMOTE..."
if [ "$REPO_TYPE" == "git" ]; then
git remote set-url origin $REPO_REMOTE
git fetch --all
git reset --hard origin/HEAD
git clean -dxf
elif [ "$REPO_TYPE" == "hg" ]; then
echo -e "[paths]\ndefault = $REPO_REMOTE\n" >> .hg/hgrc
hg pull
fi
fi
if [ "$REPO_BRANCH" != "" ]; then
echo "Switching over to branch $REPO_BRANCH..."
if [ "$REPO_TYPE" == "git" ]; then
git reset --hard origin/$REPO_BRANCH
git clean -dxf
elif [ "$REPO_TYPE" == "hg" ]; then
hg checkout $REPO_BRANCH
fi
fi
fi
fi
# Download all the C dependencies
mkdir /deps
DEPS=($DEPS) && for dep in "${DEPS[@]}"; do
if [ "${dep##*.}" == "tar" ]; then cat "/deps-cache/`basename $dep`" | tar -C /deps -x; fi
if [ "${dep##*.}" == "gz" ]; then cat "/deps-cache/`basename $dep`" | tar -C /deps -xz; fi
if [ "${dep##*.}" == "bz2" ]; then cat "/deps-cache/`basename $dep`" | tar -C /deps -xj; fi
done
DEPS_ARGS=($ARGS)
# Save the contents of the pre-build /usr/local folder for post cleanup
USR_LOCAL_CONTENTS=`ls /usr/local`
# Configure some global build parameters
NAME=`basename $1/$PACK`
if [ "$OUT" != "" ]; then
NAME=$OUT
fi
if [ "$FLAG_V" == "true" ]; then V=-v; fi
if [ "$FLAG_X" == "true" ]; then X=-x; fi
if [ "$FLAG_RACE" == "true" ]; then R=-race; fi
if [ "$FLAG_TAGS" != "" ]; then T=(--tags "$FLAG_TAGS"); fi
if [ "$FLAG_LDFLAGS" != "" ]; then LD="$FLAG_LDFLAGS"; fi
if [ "$FLAG_BUILDMODE" != "" ] && [ "$FLAG_BUILDMODE" != "default" ]; then BM="--buildmode=$FLAG_BUILDMODE"; fi
# If no build targets were specified, inject a catch all wildcard
if [ "$TARGETS" == "" ]; then
TARGETS="./."
fi
# Build for each requested platform individually
for TARGET in $TARGETS; do
# Split the target into platform and architecture
XGOOS=`echo $TARGET | cut -d '/' -f 1`
XGOARCH=`echo $TARGET | cut -d '/' -f 2`
# Check and build for Android targets
if ([ $XGOOS == "." ] || [[ $XGOOS == android* ]]); then
# Split the platform version and configure the linker options
PLATFORM=`echo $XGOOS | cut -d '-' -f 2`
if [ "$PLATFORM" == "" ] || [ "$PLATFORM" == "." ] || [ "$PLATFORM" == "android" ]; then
PLATFORM=16 # Jelly Bean 4.0.0
fi
CGO_STATUS_IM="-D ANDROID_DEPLOYMENT"
if [ "$PLATFORM" -ge 16 ]; then
CGO_CCPIE="-fPIE"
CGO_LDPIE="-fPIE"
EXT_LDPIE="-extldflags=-pie"
else
unset CGO_CCPIE CGO_LDPIE EXT_LDPIE
fi
mkdir -p /build-android-aar
# Iterate over the requested architectures, bootstrap and build
if [ $XGOARCH == "." ] || [ $XGOARCH == "arm" ] || [ $XGOARCH == "aar" ]; then
if [ "$GO_VERSION" -lt 150 ]; then
echo "Go version too low, skipping android-$PLATFORM/arm..."
else
# Include a linker workaround for pre Go 1.6 releases
if [ "$GO_VERSION" -lt 160 ]; then
EXT_LDAMD="-extldflags=-Wl,--allow-multiple-definition"
fi
echo "Assembling toolchain for android-$PLATFORM/arm..."
$ANDROID_NDK_ROOT/build/tools/make-standalone-toolchain.sh --ndk-dir=$ANDROID_NDK_ROOT --install-dir=/usr/$ANDROID_CHAIN_ARM --toolchain=$ANDROID_CHAIN_ARM --arch=arm > /dev/null 2>&1
echo "Bootstrapping android-$PLATFORM/arm..."
CC=arm-linux-androideabi-gcc GOOS=android GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go install std
echo "Compiling for android-$PLATFORM/arm..."
CC=arm-linux-androideabi-gcc CXX=arm-linux-androideabi-g++ HOST=arm-linux-androideabi PREFIX=/usr/$ANDROID_CHAIN_ARM/arm-linux-androideabi $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/$ANDROID_CHAIN_ARM/arm-linux-androideabi/lib/pkgconfig
if [ $XGOARCH == "." ] || [ $XGOARCH == "arm" ]; then
CC=arm-linux-androideabi-gcc CXX=arm-linux-androideabi-g++ GOOS=android GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE" CGO_CXXFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CGO_CFLAGS="-D ANDROID_DEPLOYMENT" CC=arm-linux-androideabi-gcc CXX=arm-linux-androideabi-g++ GOOS=android GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE $CGO_STATUS_IM" CGO_CXXFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go build $V $X "${T[@]}" --ldflags="$V $EXT_LDPIE $EXT_LDAMD $LD" $BM -o "/build/$NAME-android-$PLATFORM-arm`extension android`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "aar" ]; then
CC=arm-linux-androideabi-gcc CXX=arm-linux-androideabi-g++ GOOS=android GOARCH=arm GOARM=7 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=arm-linux-androideabi-gcc CXX=arm-linux-androideabi-g++ GOOS=android GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${T[@]}" --ldflags="$V $EXT_LDAMD $LD" --buildmode=c-shared -o "/build-android-aar/$NAME-android-$PLATFORM-arm.so" ./$PACK
fi
fi
fi
if [ "$GO_VERSION" -lt 160 ]; then
echo "Go version too low, skipping android-$PLATFORM/386,arm64..."
else
if [ "$PLATFORM" -ge 9 ] && ([ $XGOARCH == "." ] || [ $XGOARCH == "386" ] || [ $XGOARCH == "aar" ]); then
echo "Assembling toolchain for android-$PLATFORM/386..."
$ANDROID_NDK_ROOT/build/tools/make-standalone-toolchain.sh --ndk-dir=$ANDROID_NDK_ROOT --install-dir=/usr/$ANDROID_CHAIN_386 --toolchain=$ANDROID_CHAIN_386 --arch=x86 > /dev/null 2>&1
echo "Bootstrapping android-$PLATFORM/386..."
CC=i686-linux-android-gcc GOOS=android GOARCH=386 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go install std
echo "Compiling for android-$PLATFORM/386..."
CC=i686-linux-android-gcc CXX=i686-linux-android-g++ HOST=i686-linux-android PREFIX=/usr/$ANDROID_CHAIN_386/i686-linux-android $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/$ANDROID_CHAIN_386/i686-linux-android/lib/pkgconfig
if [ $XGOARCH == "." ] || [ $XGOARCH == "386" ]; then
CC=i686-linux-android-gcc CXX=i686-linux-android-g++ GOOS=android GOARCH=386 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE" CGO_CXXFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=i686-linux-android-gcc CXX=i686-linux-android-g++ GOOS=android GOARCH=386 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE $CGO_STATUS_IM" CGO_CXXFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go build $V $X "${T[@]}" --ldflags="$V $EXT_LDPIE $LD" $BM -o "/build/$NAME-android-$PLATFORM-386`extension android`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "aar" ]; then
CC=i686-linux-android-gcc CXX=i686-linux-android-g++ GOOS=android GOARCH=386 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=i686-linux-android-gcc CXX=i686-linux-android-g++ GOOS=android GOARCH=386 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${T[@]}" --ldflags="$V $LD" --buildmode=c-shared -o "/build-android-aar/$NAME-android-$PLATFORM-386.so" ./$PACK
fi
fi
if [ "$PLATFORM" -ge 21 ] && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm64" ] || [ $XGOARCH == "aar" ]); then
echo "Assembling toolchain for android-$PLATFORM/arm64..."
$ANDROID_NDK_ROOT/build/tools/make-standalone-toolchain.sh --ndk-dir=$ANDROID_NDK_ROOT --install-dir=/usr/$ANDROID_CHAIN_ARM64 --toolchain=$ANDROID_CHAIN_ARM64 --arch=arm64 > /dev/null 2>&1
echo "Bootstrapping android-$PLATFORM/arm64..."
CC=aarch64-linux-android-gcc GOOS=android GOARCH=arm64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go install std
echo "Compiling for android-$PLATFORM/arm64..."
CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ HOST=aarch64-linux-android PREFIX=/usr/$ANDROID_CHAIN_ARM64/aarch64-linux-android $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/$ANDROID_CHAIN_ARM64/aarch64-linux-android/lib/pkgconfig
if [ $XGOARCH == "." ] || [ $XGOARCH == "arm64" ]; then
CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ GOOS=android GOARCH=arm64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE" CGO_CXXFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ GOOS=android GOARCH=arm64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_CCPIE $CGO_STATUS_IM" CGO_CXXFLAGS="$CGO_CCPIE" CGO_LDFLAGS="$CGO_LDPIE" go build $V $X "${T[@]}" --ldflags="$V $EXT_LDPIE $LD" $BM -o "/build/$NAME-android-$PLATFORM-arm64`extension android`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "aar" ]; then
CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ GOOS=android GOARCH=arm64 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=aarch64-linux-android-gcc CXX=aarch64-linux-android-g++ GOOS=android GOARCH=arm64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${T[@]}" --ldflags="$V $LD" --buildmode=c-shared -o "/build-android-aar/$NAME-android-$PLATFORM-arm64.so" ./$PACK
fi
fi
fi
unset CGO_STATUS_IM # good to let that extra var go away
# Assemble the Android Archive from the built shared libraries
if [ $XGOARCH == "." ] || [ $XGOARCH == "aar" ]; then
title=${NAME^}
archive=/build/$NAME-android-$PLATFORM-aar
bundle=/build/$NAME-android-$PLATFORM.aar
# Generate the Java import path based on the Go one
package=`go list ./$PACK | tr '-' '_'`
package=$(for p in `echo ${package//\// }`; do echo $p | awk 'BEGIN{FS="."}{for (i=NF; i>0; i--){printf "%s.", $i;}}'; done | sed 's/.$//')
package=${package%.*}
# Create a fresh empty Android archive
rm -rf $archive $bundle
mkdir -p $archive
echo -e "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"$package\">\n <uses-sdk android:minSdkVersion=\"$PLATFORM\"/>\n</manifest>" > $archive/AndroidManifest.xml
mkdir -p $archive/res
touch $archive/R.txt
# Generate the JNI wrappers automatically with SWIG
jni=`mktemp -d`
header=`find /build-android-aar | grep '\.h$' | head -n 1`
if [ "$header" == "" ]; then
echo "No API C header specified, skipping android-$PLATFORM/aar..."
else
cp $header $jni/$NAME.h
sed -i -e 's|__complex|complex|g' $jni/$NAME.h
sed -i -e 's|_Complex|complex|g' $jni/$NAME.h
echo -e "%module $title\n%{\n#include \"$NAME.h\"\n%}\n%pragma(java) jniclasscode=%{\nstatic {\nSystem.loadLibrary(\"$NAME\");\n}\n%}\n%include \"$NAME.h\"" > $jni/$NAME.i
mkdir -p $jni/${package//.//}
swig -java -package $package -outdir $jni/${package//.//} $jni/$NAME.i
# Assemble the Go static libraries and the JNI interface into shared libraries
for lib in `find /build-android-aar | grep '\.so$'`; do
if [[ "$lib" = *-arm.so ]]; then cc=arm-linux-androideabi-gcc; abi="armeabi-v7a"; fi
if [[ "$lib" = *-arm64.so ]]; then cc=aarch64-linux-android-gcc; abi="arm64-v8a"; fi
if [[ "$lib" = *-386.so ]]; then cc=i686-linux-android-gcc; abi="x86"; fi
mkdir -p $archive/jni/$abi
cp ${lib%.*}.h $jni/${NAME}.h
cp $lib $archive/jni/$abi/lib${NAME}raw.so
(cd $archive/jni/$abi && $cc -shared -fPIC -o lib${NAME}.so -I"$ANDROID_NDK_LIBC/include" -I"$ANDROID_NDK_LIBC/libs/$abi/include" -I"$jni" lib${NAME}raw.so $jni/${NAME}_wrap.c)
done
# Compile the Java wrapper and assemble into a .jar file
mkdir -p $jni/build
javac -target 1.7 -source 1.7 -cp . -d $jni/build $jni/${package//.//}/*.java
(cd $jni/build && jar cvf $archive/classes.jar *)
# Finally assemble the archive contents into an .aar and clean up
(cd $archive && zip -r $bundle *)
rm -rf $jni $archive
fi
# Fix up permissions on bundle file
chown $UID:$GID $bundle
fi
# Clean up the android builds, toolchains and runtimes
rm -rf /build-android-aar
rm -rf /usr/local/go/pkg/android_*
rm -rf /usr/$ANDROID_CHAIN_ARM /usr/$ANDROID_CHAIN_ARM64 /usr/$ANDROID_CHAIN_386
fi
# Check and build for Linux targets
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ]); then
echo "Compiling for linux/amd64..."
HOST=x86_64-linux PREFIX=/usr/local $BUILD_DEPS /deps ${DEPS_ARGS[@]}
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build $V $X "${T[@]}" --ldflags="$V $LD" $R $BM -o "/build/$NAME-linux-amd64$R`extension linux`" ./$PACK
fi
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "386" ]); then
echo "Compiling for linux/386..."
HOST=i686-linux PREFIX=/usr/local $BUILD_DEPS /deps ${DEPS_ARGS[@]}
GOOS=linux GOARCH=386 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
GOOS=linux GOARCH=386 CGO_ENABLED=1 go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-linux-386`extension linux`" ./$PACK
fi
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm" ] || [ $XGOARCH == "arm-5" ]); then
if [ "$GO_VERSION" -ge 150 ]; then
echo "Bootstrapping linux/arm-5..."
CC=arm-linux-gnueabi-gcc-5 GOOS=linux GOARCH=arm GOARM=5 CGO_ENABLED=1 CGO_CFLAGS="-march=armv5" CGO_CXXFLAGS="-march=armv5" go install std
fi
echo "Compiling for linux/arm-5..."
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 HOST=arm-linux-gnueabi PREFIX=/usr/arm-linux-gnueabi CFLAGS="-march=armv5" CXXFLAGS="-march=armv5" $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/arm-linux-gnueabi/lib/pkgconfig
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=5 CGO_ENABLED=1 CGO_CFLAGS="-march=armv5" CGO_CXXFLAGS="-march=armv5" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=5 CGO_ENABLED=1 CGO_CFLAGS="-march=armv5" CGO_CXXFLAGS="-march=armv5" go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-linux-arm-5`extension linux`" ./$PACK
if [ "$GO_VERSION" -ge 150 ]; then
echo "Cleaning up Go runtime for linux/arm-5..."
rm -rf /usr/local/go/pkg/linux_arm
fi
fi
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm-6" ]); then
if [ "$GO_VERSION" -lt 150 ]; then
echo "Go version too low, skipping linux/arm-6..."
else
echo "Bootstrapping linux/arm-6..."
CC=arm-linux-gnueabi-gcc-5 GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 CGO_CFLAGS="-march=armv6" CGO_CXXFLAGS="-march=armv6" go install std
echo "Compiling for linux/arm-6..."
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 HOST=arm-linux-gnueabi PREFIX=/usr/arm-linux-gnueabi CFLAGS="-march=armv6" CXXFLAGS="-march=armv6" $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/arm-linux-gnueabi/lib/pkgconfig
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 CGO_CFLAGS="-march=armv6" CGO_CXXFLAGS="-march=armv6" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=arm-linux-gnueabi-gcc-5 CXX=arm-linux-gnueabi-g++-5 GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=1 CGO_CFLAGS="-march=armv6" CGO_CXXFLAGS="-march=armv6" go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-linux-arm-6`extension linux`" ./$PACK
echo "Cleaning up Go runtime for linux/arm-6..."
rm -rf /usr/local/go/pkg/linux_arm
fi
fi
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm-7" ]); then
if [ "$GO_VERSION" -lt 150 ]; then
echo "Go version too low, skipping linux/arm-7..."
else
echo "Bootstrapping linux/arm-7..."
CC=arm-linux-gnueabihf-gcc-5 GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="-march=armv7-a" CGO_CXXFLAGS="-march=armv7-a" go install std
echo "Compiling for linux/arm-7..."
CC=arm-linux-gnueabihf-gcc-5 CXX=arm-linux-gnueabihf-g++-5 HOST=arm-linux-gnueabihf PREFIX=/usr/arm-linux-gnueabihf CFLAGS="-march=armv7-a -fPIC" CXXFLAGS="-march=armv7-a -fPIC" $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/arm-linux-gnueabihf/lib/pkgconfig
CC=arm-linux-gnueabihf-gcc-5 CXX=arm-linux-gnueabihf-g++-5 GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="-march=armv7-a -fPIC" CGO_CXXFLAGS="-march=armv7-a -fPIC" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=arm-linux-gnueabihf-gcc-5 CXX=arm-linux-gnueabihf-g++-5 GOOS=linux GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="-march=armv7-a -fPIC" CGO_CXXFLAGS="-march=armv7-a -fPIC" go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-linux-arm-7`extension linux`" ./$PACK
echo "Cleaning up Go runtime for linux/arm-7..."
rm -rf /usr/local/go/pkg/linux_arm
fi
fi
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm64" ]); then
if [ "$GO_VERSION" -lt 150 ]; then
echo "Go version too low, skipping linux/arm64..."
else
echo "Compiling for linux/arm64..."
CC=aarch64-linux-gnu-gcc-5 CXX=aarch64-linux-gnu-g++-5 HOST=aarch64-linux-gnu PREFIX=/usr/aarch64-linux-gnu $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/aarch64-linux-gnu/lib/pkgconfig
CC=aarch64-linux-gnu-gcc-5 CXX=aarch64-linux-gnu-g++-5 GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=aarch64-linux-gnu-gcc-5 CXX=aarch64-linux-gnu-g++-5 GOOS=linux GOARCH=arm64 CGO_ENABLED=1 go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-linux-arm64`extension linux`" ./$PACK
fi
fi
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "mips64" ]); then
if [ "$GO_VERSION" -lt 170 ]; then
echo "Go version too low, skipping linux/mips64..."
else
echo "Compiling for linux/mips64..."
CC=mips64-linux-gnuabi64-gcc-5 CXX=mips64-linux-gnuabi64-g++-5 HOST=mips64-linux-gnuabi64 PREFIX=/usr/mips64-linux-gnuabi64 $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/mips64-linux-gnuabi64/lib/pkgconfig
CC=mips64-linux-gnuabi64-gcc-5 CXX=mips64-linux-gnuabi64-g++-5 GOOS=linux GOARCH=mips64 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=mips64-linux-gnuabi64-gcc-5 CXX=mips64-linux-gnuabi64-g++-5 GOOS=linux GOARCH=mips64 CGO_ENABLED=1 go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-linux-mips64`extension linux`" ./$PACK
fi
fi
if ([ $XGOOS == "." ] || [ $XGOOS == "linux" ]) && ([ $XGOARCH == "." ] || [ $XGOARCH == "mips64le" ]); then
if [ "$GO_VERSION" -lt 170 ]; then
echo "Go version too low, skipping linux/mips64le..."
else
echo "Compiling for linux/mips64le..."
CC=mips64el-linux-gnuabi64-gcc-5 CXX=mips64el-linux-gnuabi64-g++-5 HOST=mips64el-linux-gnuabi64 PREFIX=/usr/mips64el-linux-gnuabi64 $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/mips64le-linux-gnuabi64/lib/pkgconfig
CC=mips64el-linux-gnuabi64-gcc-5 CXX=mips64el-linux-gnuabi64-g++-5 GOOS=linux GOARCH=mips64le CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=mips64el-linux-gnuabi64-gcc-5 CXX=mips64el-linux-gnuabi64-g++-5 GOOS=linux GOARCH=mips64le CGO_ENABLED=1 go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-linux-mips64le`extension linux`" ./$PACK
fi
fi
# Check and build for Windows targets
if [ $XGOOS == "." ] || [[ $XGOOS == windows* ]]; then
# Split the platform version and configure the Windows NT version
PLATFORM=`echo $XGOOS | cut -d '-' -f 2`
if [ "$PLATFORM" == "" ] || [ "$PLATFORM" == "." ] || [ "$PLATFORM" == "windows" ]; then
PLATFORM=4.0 # Windows NT
fi
MAJOR=`echo $PLATFORM | cut -d '.' -f 1`
if [ "${PLATFORM/.}" != "$PLATFORM" ] ; then
MINOR=`echo $PLATFORM | cut -d '.' -f 2`
fi
CGO_NTDEF="-D_WIN32_WINNT=0x`printf "%02d" $MAJOR``printf "%02d" $MINOR`"
# Build the requested windows binaries
if [ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ]; then
echo "Compiling for windows-$PLATFORM/amd64..."
CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix HOST=x86_64-w64-mingw32 PREFIX=/usr/x86_64-w64-mingw32 $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/x86_64-w64-mingw32/lib/pkgconfig
CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go build $V $X "${T[@]}" --ldflags="$V $LD" $R $BM -o "/build/$NAME-windows-$PLATFORM-amd64$R`extension windows`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "386" ]; then
echo "Compiling for windows-$PLATFORM/386..."
CC=i686-w64-mingw32-gcc-posix CXX=i686-w64-mingw32-g++-posix HOST=i686-w64-mingw32 PREFIX=/usr/i686-w64-mingw32 $BUILD_DEPS /deps ${DEPS_ARGS[@]}
export PKG_CONFIG_PATH=/usr/i686-w64-mingw32/lib/pkgconfig
CC=i686-w64-mingw32-gcc-posix CXX=i686-w64-mingw32-g++-posix GOOS=windows GOARCH=386 CGO_ENABLED=1 CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go get $V $X "${T[@]}" --ldflags="$V $LD" -d ./$PACK
CC=i686-w64-mingw32-gcc-posix CXX=i686-w64-mingw32-g++-posix GOOS=windows GOARCH=386 CGO_ENABLED=1 CGO_CFLAGS="$CGO_NTDEF" CGO_CXXFLAGS="$CGO_NTDEF" go build $V $X "${T[@]}" --ldflags="$V $LD" $BM -o "/build/$NAME-windows-$PLATFORM-386`extension windows`" ./$PACK
fi
fi
# Check and build for OSX targets
if [ $XGOOS == "." ] || [[ $XGOOS == darwin* ]]; then
# Split the platform version and configure the deployment target
PLATFORM=`echo $XGOOS | cut -d '-' -f 2`
if [ "$PLATFORM" == "" ] || [ "$PLATFORM" == "." ] || [ "$PLATFORM" == "darwin" ]; then
PLATFORM=10.6 # OS X Snow Leopard
fi
export MACOSX_DEPLOYMENT_TARGET=$PLATFORM
# Strip symbol table below Go 1.6 to prevent DWARF issues
LDSTRIP=""
if [ "$GO_VERSION" -lt 160 ]; then
LDSTRIP="-s"
fi
# Build the requested darwin binaries
if [ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ]; then
echo "Compiling for darwin-$PLATFORM/amd64..."
CC=o64-clang CXX=o64-clang++ HOST=x86_64-apple-darwin15 PREFIX=/usr/local $BUILD_DEPS /deps ${DEPS_ARGS[@]}
CC=o64-clang CXX=o64-clang++ GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$LDSTRIP $V $LD" -d ./$PACK
CC=o64-clang CXX=o64-clang++ GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build $V $X "${T[@]}" --ldflags="$LDSTRIP $V $LD" $R $BM -o "/build/$NAME-darwin-$PLATFORM-amd64$R`extension darwin`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "386" ]; then
echo "Compiling for darwin-$PLATFORM/386..."
CC=o32-clang CXX=o32-clang++ HOST=i386-apple-darwin15 PREFIX=/usr/local $BUILD_DEPS /deps ${DEPS_ARGS[@]}
CC=o32-clang CXX=o32-clang++ GOOS=darwin GOARCH=386 CGO_ENABLED=1 go get $V $X "${T[@]}" --ldflags="$LDSTRIP $V $LD" -d ./$PACK
CC=o32-clang CXX=o32-clang++ GOOS=darwin GOARCH=386 CGO_ENABLED=1 go build $V $X "${T[@]}" --ldflags="$LDSTRIP $V $LD" $BM -o "/build/$NAME-darwin-$PLATFORM-386`extension darwin`" ./$PACK
fi
# Remove any automatically injected deployment target vars
unset MACOSX_DEPLOYMENT_TARGET
fi
# Check and build for iOS targets
if [ $XGOOS == "." ] || [[ $XGOOS == ios* ]]; then
# Split the platform version and configure the deployment target
PLATFORM=`echo $XGOOS | cut -d '-' -f 2`
if [ "$PLATFORM" == "" ] || [ "$PLATFORM" == "." ] || [ "$PLATFORM" == "ios" ]; then
PLATFORM=5.0 # first iPad and upwards
fi
export IPHONEOS_DEPLOYMENT_TARGET=$PLATFORM
# Build the requested iOS binaries
if [ "$GO_VERSION" -lt 150 ]; then
echo "Go version too low, skipping ios..."
else
# Add the 'ios' tag to all builds, otherwise the std libs will fail
if [ "$FLAG_TAGS" != "" ]; then
IOSTAGS=(--tags "ios $FLAG_TAGS")
else
IOSTAGS=(--tags ios)
fi
mkdir -p /build-ios-fw
# Strip symbol table below Go 1.6 to prevent DWARF issues
LDSTRIP=""
if [ "$GO_VERSION" -lt 160 ]; then
LDSTRIP="-s"
fi
CGO_STATUS_IM="-D IOS_DEPLOYMENT"
# Cross compile to all available iOS and simulator platforms
if [ -d "$IOS_NDK_ARM_7" ] && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm-7" ] || [ $XGOARCH == "framework" ]); then
echo "Bootstrapping ios-$PLATFORM/arm-7..."
export PATH=$IOS_NDK_ARM_7/bin:$PATH
GOOS=darwin GOARCH=arm GOARM=7 CGO_ENABLED=1 CC=arm-apple-darwin11-clang go install --tags ios std
echo "Compiling for ios-$PLATFORM/arm-7..."
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ HOST=arm-apple-darwin11 PREFIX=/usr/local $BUILD_DEPS /deps ${DEPS_ARGS[@]}
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=arm GOARM=7 CGO_ENABLED=1 go get $V $X "${IOSTAGS[@]}" --ldflags="$V $LD" -d ./$PACK
if [ $XGOARCH == "." ] || [ $XGOARCH == "arm-7" ]; then
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=arm GOARM=7 CGO_ENABLED=1 go build $V $X "${IOSTAGS[@]}" --ldflags="$LDSTRIP $V $LD" $BM -o "/build/$NAME-ios-$PLATFORM-armv7`extension darwin`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "framework" ]; then
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=arm GOARM=7 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${IOSTAGS[@]}" --ldflags="$V $LD" --buildmode=c-archive -o "/build-ios-fw/$NAME-ios-$PLATFORM-armv7.a" ./$PACK
fi
echo "Cleaning up Go runtime for ios-$PLATFORM/arm-7..."
rm -rf /usr/local/go/pkg/darwin_arm
fi
if [ -d "$IOS_NDK_ARM64" ] && ([ $XGOARCH == "." ] || [ $XGOARCH == "arm64" ] || [ $XGOARCH == "framework" ]); then
echo "Bootstrapping ios-$PLATFORM/arm64..."
export PATH=$IOS_NDK_ARM64/bin:$PATH
GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 CC=arm-apple-darwin11-clang go install --tags ios std
echo "Compiling for ios-$PLATFORM/arm64..."
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ HOST=arm-apple-darwin11 PREFIX=/usr/local $BUILD_DEPS /deps ${DEPS_ARGS[@]}
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 go get $V $X "${IOSTAGS[@]}" --ldflags="$V $LD" -d ./$PACK
if [ $XGOARCH == "." ] || [ $XGOARCH == "arm64" ]; then
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${IOSTAGS[@]}" --ldflags="$LDSTRIP $V $LD" $BM -o "/build/$NAME-ios-$PLATFORM-arm64`extension darwin`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "framework" ]; then
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${IOSTAGS[@]}" --ldflags="$V $LD" --buildmode=c-archive -o "/build-ios-fw/$NAME-ios-$PLATFORM-arm64.a" ./$PACK
fi
echo "Cleaning up Go runtime for ios-$PLATFORM/arm64..."
rm -rf /usr/local/go/pkg/darwin_arm64
fi
if [ -d "$IOS_SIM_NDK_AMD64" ] && ([ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ] || [ $XGOARCH == "framework" ]); then
echo "Bootstrapping ios-$PLATFORM/amd64..."
export PATH=$IOS_SIM_NDK_AMD64/bin:$PATH
mv /usr/local/go/pkg/darwin_amd64 /usr/local/go/pkg/darwin_amd64_bak
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 CC=arm-apple-darwin11-clang go install --tags ios std
echo "Compiling for ios-$PLATFORM/amd64..."
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ HOST=arm-apple-darwin11 PREFIX=/usr/local $BUILD_DEPS /deps ${DEPS_ARGS[@]}
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go get $V $X "${IOSTAGS[@]}" --ldflags="$V $LD" -d ./$PACK
if [ $XGOARCH == "." ] || [ $XGOARCH == "amd64" ]; then
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${IOSTAGS[@]}" --ldflags="$LDSTRIP $V $LD" $BM -o "/build/$NAME-ios-$PLATFORM-x86_64`extension darwin`" ./$PACK
fi
if [ $XGOARCH == "." ] || [ $XGOARCH == "framework" ]; then
CC=arm-apple-darwin11-clang CXX=arm-apple-darwin11-clang++ GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 CGO_CFLAGS="$CGO_STATUS_IM" go build $V $X "${IOSTAGS[@]}" --ldflags="$V $LD" --buildmode=c-archive -o "/build-ios-fw/$NAME-ios-$PLATFORM-x86_64.a" ./$PACK
fi
echo "Cleaning up Go runtime for ios-$PLATFORM/amd64..."
rm -rf /usr/local/go/pkg/darwin_amd64
mv /usr/local/go/pkg/darwin_amd64_bak /usr/local/go/pkg/darwin_amd64
fi
unset CGO_STATUS_IM
# Assemble the iOS framework from the built binaries
if [ $XGOARCH == "." ] || [ $XGOARCH == "framework" ]; then
title=${NAME^}
framework=/build/$NAME-ios-$PLATFORM-framework/$title.framework
rm -rf $framework
mkdir -p $framework/Versions/A
(cd $framework/Versions && ln -nsf A Current)
arches=()
for lib in `ls /build-ios-fw | grep -e '\.a$'`; do
arches+=("-arch" "`echo ${lib##*-} | cut -d '.' -f 1`" "/build-ios-fw/$lib")
done
arm-apple-darwin11-lipo -create "${arches[@]}" -o $framework/Versions/A/$title
arm-apple-darwin11-ranlib $framework/Versions/A/$title
(cd $framework && ln -nsf Versions/A/$title $title)
mkdir -p $framework/Versions/A/Headers
for header in `ls /build-ios-fw | grep -e '\.h$'`; do
cp -f /build-ios-fw/$header $framework/Versions/A/Headers/$title.h
done
(cd $framework && ln -nsf Versions/A/Headers Headers)
echo "Patching Statusgo.h to work correctly on any arch (32bit, 64bit)"
(cd $framework && perl -i -p0e 's/(\/\*\n\s*static assertion[\s\n\r\S+]+)(typedef char _check_for[^;]+;)/\1#ifdef __LP64__\ntypedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*)==64\/8 ? 1:-1];\n#else\ntypedef char _check_for_32_bit_pointer_matching_GoInt[sizeof(void*)==32\/8 ? 1:-1];\n#endif/igm' Headers/Statusgo.h)
mkdir -p $framework/Versions/A/Resources
echo -e "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n</dict>\n</plist>" > $framework/Versions/A/Resources/Info.plist
(cd $framework && ln -nsf Versions/A/Resources Resources)
mkdir -p $framework/Versions/A/Modules
echo -e "framework module \"$title\" {\n header \"$title.h\"\n export *\n}" > $framework/Versions/A/Modules/module.modulemap
(cd $framework && ln -nsf Versions/A/Modules Modules)
# Fix up permissions on bundle file
chown $UID:$GID /build/$NAME-ios-$PLATFORM-framework
chmod 777 -R /build/$NAME-ios-$PLATFORM-framework
fi
rm -rf /build-ios-fw
fi
# Remove any automatically injected deployment target vars
unset IPHONEOS_DEPLOYMENT_TARGET
fi
done
# Clean up any leftovers for subsequent build invocations
echo "Cleaning up build environment..."
rm -rf /deps
for dir in `ls /usr/local`; do
keep=0
# Check against original folder contents
for old in $USR_LOCAL_CONTENTS; do
if [ "$old" == "$dir" ]; then
keep=1
fi
done
# Delete anything freshly generated
if [ "$keep" == "0" ]; then
rm -rf "/usr/local/$dir"
fi
done

View File

@ -1,20 +0,0 @@
FROM statusteam/xgo:1.10.x
# ios installer doesn't work with the default tar binary in Docker
# (divan: I stole this solution here: https://github.com/coreos/bugs/issues/1095#issuecomment-350574389)
# https://github.com/moby/moby/issues/19647
RUN apt-get update \
&& apt-get install -y --no-install-recommends bsdtar \
&& apt-get clean \
&& cp $(which tar) $(which tar)~ \
&& ln -sf $(which bsdtar) $(which tar)
ADD update_ios.sh /update_ios.sh
ENV UPDATE_IOS /update_ios.sh
RUN chmod +x $UPDATE_IOS
RUN \
IOS_SDK_PATH=https://s3.amazonaws.com/farazdagi/status-im/iPhoneSimulator9.3.sdk.tar.gz && \
$FETCH $IOS_SDK_PATH 460423bf776e651a84c6e1bc035dbce23f93e685 && \
$UPDATE_IOS /iPhoneSimulator9.3.sdk.tar.gz && \
rm -rf /iPhoneSimulator9.3.sdk.tar.gz

View File

@ -1,64 +0,0 @@
#!/bin/bash
#
# Contains a simple tool that updates some of the iOS toolchains with the SDKs
# explicitly provided. The goal is to allow using your own up to date SDKs or
# the simulator one not supported out of the box.
#
# Usage: update_ios.sh <path to>/<iSomething><Version>.sdk.tar.<type>
set -e
# Figure out the base name of the SDK
sdk=`basename $1`
sdk=${sdk%.*}
sdk=${sdk%.*}
# Define a small extraction utility to
function extract {
case $1 in
*.tar.xz)
xz -dc $1 | tar xf -
;;
*.tar.gz)
gunzip -dc $1 | tar xf -
;;
*.tar.bz2)
bzip2 -dc $1 | tar xf -
;;
esac
}
# Extract the SDK, patch it, clean it up and prep for bootstrapping
extract $1
if [[ "`basename $1`" =~ ^iPhoneSimulator ]]; then
echo "Patching iOS simulator SDK with missing libraries..."
ln -s $OSX_NDK_X86/SDK/$OSX_SDK/usr/lib/system/libsystem_kernel.dylib $sdk/usr/lib/system/libsystem_kernel.dylib
ln -s $OSX_NDK_X86/SDK/$OSX_SDK/usr/lib/system/libsystem_platform.dylib $sdk/usr/lib/system/libsystem_platform.dylib
ln -s $OSX_NDK_X86/SDK/$OSX_SDK/usr/lib/system/libsystem_pthread.dylib $sdk/usr/lib/system/libsystem_pthread.dylib
ln -s $OSX_NDK_X86/SDK/$OSX_SDK/usr/lib/system/libsystem_kernel.tbd $sdk/usr/lib/system/libsystem_kernel.tbd
ln -s $OSX_NDK_X86/SDK/$OSX_SDK/usr/lib/system/libsystem_platform.tbd $sdk/usr/lib/system/libsystem_platform.tbd
ln -s $OSX_NDK_X86/SDK/$OSX_SDK/usr/lib/system/libsystem_pthread.tbd $sdk/usr/lib/system/libsystem_pthread.tbd
fi
tar -czf /tmp/$sdk.tar.gz $sdk
rm -rf $sdk
# Pull the iOS cross compiler tool and build the toolchain
git clone -n https://github.com/tpoechtrager/cctools-port.git
cd cctools-port
git reset --hard adf616eee9d41f4961c3a83ba275249ffcb32d33
cd ..
if [[ "`basename $1`" =~ ^iPhoneSimulator ]]; then
rm -rf $IOS_SIM_NDK_AMD64
/cctools-port/usage_examples/ios_toolchain/build.sh /tmp/$sdk.tar.gz x86_64
mv /cctools-port/usage_examples/ios_toolchain/target $IOS_SIM_NDK_AMD64
else
rm -rf $IOS_NDK_ARM_7 $IOS_NDK_ARM64
/cctools-port/usage_examples/ios_toolchain/build.sh /tmp/$sdk.tar.gz armv7
mv /cctools-port/usage_examples/ios_toolchain/target $IOS_NDK_ARM_7
/cctools-port/usage_examples/ios_toolchain/build.sh /tmp/$sdk.tar.gz arm64
mv /cctools-port/usage_examples/ios_toolchain/target $IOS_NDK_ARM64
fi
rm -rf /cctools-port

116
_assets/ci/Jenkinsfile vendored
View File

@ -24,6 +24,8 @@ pipeline {
STATUS_PATH = 'src/github.com/status-im/status-go' STATUS_PATH = 'src/github.com/status-im/status-go'
GOPATH = "${env.WORKSPACE}" GOPATH = "${env.WORKSPACE}"
PATH = "${env.PATH}:${env.GOPATH}/bin" PATH = "${env.PATH}:${env.GOPATH}/bin"
/* This will override the var in Makefile */
RELEASE_DIRECTORY = "${env.WORKSPACE}/pkg"
} }
stages { stages {
@ -34,82 +36,70 @@ pipeline {
println("Version: ${version}") println("Version: ${version}")
println("Git Branch: ${lib.gitBranch()}") println("Git Branch: ${lib.gitBranch()}")
println("Git Commit: ${lib.gitCommit()}") println("Git Commit: ${lib.gitCommit()}")
/* save and create a dir for artifacts */
dest = "${env.WORKSPACE}/pkg"
sh "mkdir -p ${dest}"
} } } }
} } // stage(Prep)
stage('Setup') { steps { dir(env.STATUS_PATH) { stage('Setup') { steps { dir(env.STATUS_PATH) {
sh 'make setup' /* install release tools */
sh 'make xgo' sh 'make release-install'
} } } } } } // stage(Setup)
stage('Lint') { steps { dir(env.STATUS_PATH) {
sh 'make ci'
} } }
stage('Build') { stage('Build') {
parallel { parallel {
stage('Android') { stage('iOS') { steps { script {
stages { ios = lib.buildBranch('status-go/platforms/ios')
stage('Compile') { steps { dir(env.STATUS_PATH) {
sh 'make statusgo-android'
sh "cp build/bin/statusgo-android-16.aar ${dest}/status-go-android-${lib.suffix()}.aar"
} } } } } }
stage('Archive') { steps { stage('Android') { steps { script {
archiveArtifacts("pkg/status-go-android-${lib.suffix()}.aar") android = lib.buildBranch('status-go/platforms/android')
} } }
stage('Linux') { steps { script {
linux = lib.buildBranch('status-go/platforms/linux')
} } }
} // parallel
} // stage(Build)
stage('Archive') {
steps { script {
sh("rm -f ${env.RELEASE_DIRECTORY}/*")
lib.copyArts('status-go/platforms/ios', ios.number)
lib.copyArts('status-go/platforms/android', android.number)
lib.copyArts('status-go/platforms/linux', linux.number)
dir(env.RELEASE_DIRECTORY) {
/* generate sha256 checksums for upload */
sh 'sha256sum * | tee checksum.sha256'
archiveArtifacts('*')
}
} } } }
stage('Upload') { steps { script { } // stage(Archive)
lib.uploadArtifact("pkg/status-go-android-${lib.suffix()}.aar")
} } }
}
}
stage('iOS') {
stages {
stage('Compile') { steps { dir(env.STATUS_PATH) {
sh 'make statusgo-ios-simulator'
dir('build/bin/statusgo-ios-9.3-framework') {
sh 'zip -r status-go-ios.zip Statusgo.framework'
sh "cp status-go-ios.zip ${dest}/status-go-ios-${lib.suffix()}.zip"
}
} } }
stage('Archive') { steps {
archiveArtifacts("pkg/status-go-ios-${lib.suffix()}.zip")
} }
stage('Upload') { steps { script {
lib.uploadArtifact("pkg/status-go-ios-${lib.suffix()}.zip")
} } }
}
}
stage('Desktop') {
stages {
stage('Prepare') { steps { dir(env.STATUS_PATH) {
sh "zip -r ${dest}/status-go-desktop-${lib.suffix()}.zip . -x *.git"
} } }
stage('Archive') { steps {
archiveArtifacts("pkg/status-go-desktop-${lib.suffix()}.zip")
} }
stage('Upload') { steps { script {
lib.uploadArtifact("pkg/status-go-desktop-${lib.suffix()}.zip")
} } }
}
}
}
}
stage('Release') { when { expression { params.RELEASE == true } } stage('Release') { when { expression { params.RELEASE == true } }
steps { dir(env.STATUS_PATH) { steps {
sh 'make prepare-release' /* rename build files to not include versions */
dir(env.RELEASE_DIRECTORY) {
sh 'mv status-go-ios-*.zip status-go-ios.zip'
sh 'mv status-go-android-*.aar status-go-android.aar'
sh 'mv status-go-desktop-*.zip status-go-desktop.zip'
}
/* perform the release */
dir(env.STATUS_PATH) {
withCredentials([[ withCredentials([[
$class: 'UsernamePasswordMultiBinding', $class: 'UsernamePasswordMultiBinding',
credentialsId: 'status-im-auto', credentialsId: 'status-im-auto',
usernameVariable: 'GITHUB_USER', usernameVariable: 'GITHUB_USER',
passwordVariable: 'GITHUB_TOKEN' passwordVariable: 'GITHUB_TOKEN'
]]) { ]]) {
sh "yes | make release RELEASE_BRANCH=${lib.gitBranch()}" sh """
yes | make release \
RELEASE_BRANCH=${lib.gitBranch()} \
RELEASE_DIRECTORY=${env.RELEASE_DIRECTORY}
"""
} }
}
}
} // stage(Release)
stage('Cleanup') { steps { dir(env.STATUS_PATH) {
sh 'make clean-release' sh 'make clean-release'
} } } } } // stage(Cleanup)
} } // stages
stage('Cleanup') { steps { script {
sh "rm -fr ${dest}"
} } }
}
} }

View File

@ -1,88 +0,0 @@
#!/usr/bin/env groovy
node('linux') {
env.GOPATH = "${env.WORKSPACE}"
env.PATH = "${env.PATH}:${env.GOPATH}/bin"
cloneDir = 'src/github.com/status-im/status-go'
paramBranch = env.branch ? env.branch : '*/develop'
dir(cloneDir) {
try {
deleteDir()
} catch (err) {
echo "failure while cleaning the directory"
}
}
checkout(
changelog: false,
poll: true,
scm: [$class: 'GitSCM', branches: [[name: paramBranch]],
doGenerateSubmoduleConfigurations: false,
extensions: [
[$class: 'RelativeTargetDirectory', relativeTargetDir: cloneDir]
],
submoduleCfg: [],
userRemoteConfigs: [[url: 'https://github.com/status-im/status-go']]]
)
def remoteOriginRegex = ~/^remotes\/origin\//
dir(cloneDir) {
gitSHA = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
gitShortSHA = gitSHA.take(8)
gitBranch = sh(returnStdout: true, script: 'git name-rev --name-only HEAD').trim() - remoteOriginRegex
}
stage('Debug') {
sh 'env'
println(gitBranch)
println(gitSHA)
}
stage('Test') {
dir(cloneDir) {
sh 'make setup'
sh 'make ci'
}
}
stage('Build') {
sh 'go get github.com/status-im/xgo'
parallel (
'statusgo-android': {
dir(cloneDir) {
sh 'make statusgo-android'
}
},
'statusgo-ios-simulator': {
dir(cloneDir) {
sh '''
make statusgo-ios-simulator
cd build/bin/statusgo-ios-9.3-framework/
zip -r status-go-ios.zip Statusgo.framework
'''
}
}
)
}
stage('Deploy') {
dir(cloneDir) {
sh "make prepare-release"
withCredentials([[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'status-im-auto',
usernameVariable: 'GITHUB_USER',
passwordVariable: 'GITHUB_TOKEN'
]]) {
sh """
yes | make release release_branch=${gitBranch}
"""
}
sh "make clean-release"
}
}
}

View File

@ -0,0 +1,65 @@
pipeline {
agent { label 'linux' }
options {
/* Go requires a certain directory structure */
checkoutToSubdirectory('src/github.com/status-im/status-go')
/* manage how many builds we keep */
buildDiscarder(logRotator(
numToKeepStr: '30',
daysToKeepStr: '30',
))
}
environment {
STATUS_PATH = 'src/github.com/status-im/status-go'
CI_DIR = "${env.STATUS_PATH}/_assets/ci"
GOPATH = "${env.WORKSPACE}"
PATH = "${env.PATH}:${env.GOPATH}/bin"
ANDROID_HOME = '/usr/lib/android-sdk'
ANDROID_SDK_ROOT = '/usr/lib/android-sdk'
ANDROID_NDK = '/usr/lib/android-ndk'
ANDROID_NDK_HOME = '/usr/lib/android-ndk'
}
stages {
stage('Prep') { steps { script {
lib = load("${CI_DIR}/lib.groovy")
/* clarify what we're building */
println("Version: ${lib.getVersion()}")
println("Git Branch: ${lib.gitBranch()}")
println("Git Commit: ${lib.gitCommit()}")
/* save and create a dir for artifacts */
dest = "${env.WORKSPACE}/pkg"
sh "mkdir -p ${dest}"
/* for easier reuse */
artifact = "status-go-android-${lib.suffix()}.aar"
} } }
stage('Setup') { steps { dir(env.STATUS_PATH) {
sh 'make setup-build'
} } }
stage('Test') { steps { dir(env.STATUS_PATH) {
sh 'make ci'
} } }
stage('Compile') { steps { dir(env.STATUS_PATH) {
sh 'make statusgo-android'
sh "cp build/bin/statusgo.aar ${dest}/${artifact}"
} } }
stage('Archive') { steps {
archiveArtifacts("pkg/${artifact}")
} }
stage('Upload') { steps { script {
lib.uploadArtifact("pkg/${artifact}")
} } }
stage('Cleanup') { steps { dir(env.STATUS_PATH) {
sh 'make clean'
sh "rm -fr ${dest}"
} } }
} // stages
} // pipeline

View File

@ -0,0 +1,64 @@
pipeline {
agent { label 'macos' }
options {
/* Go requires a certain directory structure */
checkoutToSubdirectory('src/github.com/status-im/status-go')
/* manage how many builds we keep */
buildDiscarder(logRotator(
numToKeepStr: '30',
daysToKeepStr: '30',
))
}
environment {
STATUS_PATH = 'src/github.com/status-im/status-go'
CI_DIR = "${env.STATUS_PATH}/_assets/ci"
GOPATH = "${env.WORKSPACE}"
PATH = "${env.PATH}:${env.GOPATH}/bin"
}
stages {
stage('Prep') { steps { script {
lib = load("${CI_DIR}/lib.groovy")
/* clarify what we're building */
println("Version: ${lib.getVersion()}")
println("Git Branch: ${lib.gitBranch()}")
println("Git Commit: ${lib.gitCommit()}")
/* save and create a dir for artifacts */
dest = "${env.WORKSPACE}/pkg"
sh "mkdir -p ${dest}"
/* for easier reuse */
artifact = "status-go-ios-${lib.suffix()}.zip"
} } }
stage('Setup') { steps { dir(env.STATUS_PATH) {
sh 'make setup-build'
} } }
stage('Test') { steps { dir(env.STATUS_PATH) {
sh 'make ci'
} } }
stage('Compile') { steps { dir(env.STATUS_PATH) {
sh 'make statusgo-ios'
dir('build/bin') {
sh 'zip -r status-go-ios.zip Statusgo.framework'
sh "cp status-go-ios.zip ${dest}/${artifact}"
}
} } }
stage('Archive') { steps {
archiveArtifacts("pkg/${artifact}")
} }
stage('Upload') { steps { script {
lib.uploadArtifact("pkg/${artifact}")
} } }
stage('Cleanup') { steps { dir(env.STATUS_PATH) {
sh 'make clean'
sh "rm -fr ${dest}"
} } }
} // stages
} // pipeline

View File

@ -0,0 +1,46 @@
pipeline {
agent { label 'linux' }
options {
/* Go requires a certain directory structure */
checkoutToSubdirectory('src/github.com/status-im/status-go')
/* manage how many builds we keep */
buildDiscarder(logRotator(
numToKeepStr: '30',
daysToKeepStr: '30',
))
}
environment {
STATUS_PATH = 'src/github.com/status-im/status-go'
GOPATH = "${env.WORKSPACE}"
PATH = "${env.PATH}:${env.GOPATH}/bin"
}
stages {
stage('Prep') { steps { script {
lib = load("${env.STATUS_PATH}/_assets/ci/lib.groovy")
/* clarify what we're building */
println("Version: ${lib.getVersion()}")
println("Git Branch: ${lib.gitBranch()}")
println("Git Commit: ${lib.gitCommit()}")
/* save and create a dir for artifacts */
dest = "${env.WORKSPACE}/pkg"
sh "mkdir -p ${dest}"
/* for easier reuse */
artifact = "status-go-desktop-${lib.suffix()}.zip"
} } }
stage('Compress') { steps { dir(env.STATUS_PATH) {
sh "zip -q -r ${dest}/${artifact} . -x *.git"
} } }
stage('Archive') { steps {
archiveArtifacts("pkg/${artifact}")
} }
stage('Upload') { steps { script {
lib.uploadArtifact("pkg/${artifact}")
} } }
} // stages
} // pipeline

View File

@ -1,3 +1,7 @@
def getVersion() {
return readFile("${env.STATUS_PATH}/VERSION").trim()
}
def gitCommit() { def gitCommit() {
return GIT_COMMIT.take(6) return GIT_COMMIT.take(6)
} }
@ -49,4 +53,33 @@ def uploadArtifact(path) {
return "https://${bucket}.${domain}/${getFilename(path)}" return "https://${bucket}.${domain}/${getFilename(path)}"
} }
def buildBranch(name = null, buildType = null) {
/* need to drop origin/ to match definitions of child jobs */
def branchName = env.GIT_BRANCH.replace('origin/', '')
/* always pass the BRANCH and BUILD_TYPE params with current branch */
def resp = build(
job: name,
/* this allows us to analize the job even after failure */
propagate: false,
parameters: [
[name: 'BRANCH', value: branchName, $class: 'StringParameterValue'],
])
/* BlueOcean seems to not show child-build links */
println "Build: ${resp.getAbsoluteUrl()} (${resp.result})"
if (resp.result != 'SUCCESS') {
error("Build Failed")
}
return resp
}
def copyArts(projectName, buildNo) {
copyArtifacts(
projectName: projectName,
target: 'pkg',
flatten: true,
selector: specific("${buildNo}")
)
}
return this return this

View File

@ -1,20 +0,0 @@
diff --git a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.c b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.c
index e4b6e43a..baed990d 100755
--- a/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.c
+++ b/vendor/gopkg.in/olebedev/go-duktape.v3/duk_minimal_printf.c
@@ -278,6 +278,7 @@ int duk_minimal_snprintf(char *str, size_t size, const char *format, ...) {
}
/* Minimal sprintf() entry point. */
+#if 0
int duk_minimal_sprintf(char *str, const char *format, ...) {
va_list ap;
int ret;
@@ -288,6 +289,7 @@ int duk_minimal_sprintf(char *str, const char *format, ...) {
return ret;
}
+#endif
/* Minimal sscanf() entry point. */
int duk_minimal_sscanf(const char *str, const char *format, ...) {

View File

@ -1,153 +0,0 @@
diff --git a/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go b/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go
index 3ba92ac7..d89a1e94 100644
--- a/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go
+++ b/vendor/github.com/ethereum/go-ethereum/dashboard/dashboard.go
@@ -27,20 +27,17 @@ import (
"fmt"
"net"
"net/http"
- "runtime"
"sync"
"sync/atomic"
"time"
"io"
- "github.com/elastic/gosigar"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
- "github.com/mohae/deepcopy"
"golang.org/x/net/websocket"
)
@@ -235,7 +232,7 @@ func (db *Dashboard) apiHandler(conn *websocket.Conn) {
db.lock.Lock()
// Send the past data.
- client.msg <- deepcopy.Copy(db.history).(*Message)
+ client.msg <- db.history
// Start tracking the connection and drop at connection loss.
db.conns[id] = client
db.lock.Unlock()
@@ -275,118 +272,6 @@ func meterCollector(name string) func() int64 {
// collectData collects the required data to plot on the dashboard.
func (db *Dashboard) collectData() {
defer db.wg.Done()
-
- systemCPUUsage := gosigar.Cpu{}
- systemCPUUsage.Get()
- var (
- mem runtime.MemStats
-
- collectNetworkIngress = meterCollector("p2p/InboundTraffic")
- collectNetworkEgress = meterCollector("p2p/OutboundTraffic")
- collectDiskRead = meterCollector("eth/db/chaindata/disk/read")
- collectDiskWrite = meterCollector("eth/db/chaindata/disk/write")
-
- prevNetworkIngress = collectNetworkIngress()
- prevNetworkEgress = collectNetworkEgress()
- prevProcessCPUTime = getProcessCPUTime()
- prevSystemCPUUsage = systemCPUUsage
- prevDiskRead = collectDiskRead()
- prevDiskWrite = collectDiskWrite()
-
- frequency = float64(db.config.Refresh / time.Second)
- numCPU = float64(runtime.NumCPU())
- )
-
- for {
- select {
- case errc := <-db.quit:
- errc <- nil
- return
- case <-time.After(db.config.Refresh):
- systemCPUUsage.Get()
- var (
- curNetworkIngress = collectNetworkIngress()
- curNetworkEgress = collectNetworkEgress()
- curProcessCPUTime = getProcessCPUTime()
- curSystemCPUUsage = systemCPUUsage
- curDiskRead = collectDiskRead()
- curDiskWrite = collectDiskWrite()
-
- deltaNetworkIngress = float64(curNetworkIngress - prevNetworkIngress)
- deltaNetworkEgress = float64(curNetworkEgress - prevNetworkEgress)
- deltaProcessCPUTime = curProcessCPUTime - prevProcessCPUTime
- deltaSystemCPUUsage = curSystemCPUUsage.Delta(prevSystemCPUUsage)
- deltaDiskRead = curDiskRead - prevDiskRead
- deltaDiskWrite = curDiskWrite - prevDiskWrite
- )
- prevNetworkIngress = curNetworkIngress
- prevNetworkEgress = curNetworkEgress
- prevProcessCPUTime = curProcessCPUTime
- prevSystemCPUUsage = curSystemCPUUsage
- prevDiskRead = curDiskRead
- prevDiskWrite = curDiskWrite
-
- now := time.Now()
-
- runtime.ReadMemStats(&mem)
- activeMemory := &ChartEntry{
- Time: now,
- Value: float64(mem.Alloc) / frequency,
- }
- virtualMemory := &ChartEntry{
- Time: now,
- Value: float64(mem.Sys) / frequency,
- }
- networkIngress := &ChartEntry{
- Time: now,
- Value: deltaNetworkIngress / frequency,
- }
- networkEgress := &ChartEntry{
- Time: now,
- Value: deltaNetworkEgress / frequency,
- }
- processCPU := &ChartEntry{
- Time: now,
- Value: deltaProcessCPUTime / frequency / numCPU * 100,
- }
- systemCPU := &ChartEntry{
- Time: now,
- Value: float64(deltaSystemCPUUsage.Sys+deltaSystemCPUUsage.User) / frequency / numCPU,
- }
- diskRead := &ChartEntry{
- Time: now,
- Value: float64(deltaDiskRead) / frequency,
- }
- diskWrite := &ChartEntry{
- Time: now,
- Value: float64(deltaDiskWrite) / frequency,
- }
- sys := db.history.System
- db.lock.Lock()
- sys.ActiveMemory = append(sys.ActiveMemory[1:], activeMemory)
- sys.VirtualMemory = append(sys.VirtualMemory[1:], virtualMemory)
- sys.NetworkIngress = append(sys.NetworkIngress[1:], networkIngress)
- sys.NetworkEgress = append(sys.NetworkEgress[1:], networkEgress)
- sys.ProcessCPU = append(sys.ProcessCPU[1:], processCPU)
- sys.SystemCPU = append(sys.SystemCPU[1:], systemCPU)
- sys.DiskRead = append(sys.DiskRead[1:], diskRead)
- sys.DiskWrite = append(sys.DiskWrite[1:], diskWrite)
- db.lock.Unlock()
-
- db.sendToAll(&Message{
- System: &SystemMessage{
- ActiveMemory: ChartEntries{activeMemory},
- VirtualMemory: ChartEntries{virtualMemory},
- NetworkIngress: ChartEntries{networkIngress},
- NetworkEgress: ChartEntries{networkEgress},
- ProcessCPU: ChartEntries{processCPU},
- SystemCPU: ChartEntries{systemCPU},
- DiskRead: ChartEntries{diskRead},
- DiskWrite: ChartEntries{diskWrite},
- },
- })
- }
- }
}
// sendToAll sends the given message to the active dashboards.

View File

@ -1,20 +0,0 @@
# Status Patches for geth (go-ethereum) cross-compiled in Xgo
---
Status-go uses [go-ethereum](https://github.com/ethereum/go-ethereum) (**upstream**) as its dependency. When cross-compiling with Xgo, some headers or definitions are not available within the Xgo environment. In such a situation, we temporarily patch the sources before kicking the build in Xgo and revert them afterwards (this is taken care by the respective Makefile targets).
We try to minimize number and amount of changes in those patches as much as possible, and whereas possible, to contribute changes into the upstream.
# Creating patches
Instructions for creating a patch from the command line:
1. Enter the command line at the go-ethereum dependency root in vendor folder.
1. Create the patch:
1. If you already have a commit that represents the change, find its SHA1 (e.g. `$COMMIT_SHA1`) and do `git diff $COMMIT_SHA1 > file.patch`
1. If the files are staged, do `git diff --cached > file.patch`
# Patches
- [`0001-fix-duktapev3-missing-SIZE_MAX-def.patch`](./0001-fix-duktapev3-missing-SIZE_MAX-def.patch) — Adds patch to geth 1.8.0 dependency duktapev3, to address issue where SIZE_MAX is not defined in xgo for Android
- [`0002-remove-dashboard-collectData.patch`](./0002-remove-dashboard-collectData.patch) — Deletes the body of `collectData` in the `dashboard` package, since it will import the `gosigar` package which in turn includes a header (`libproc.h`) which is missing in the iOS environment in Xgo.

View File

@ -15,6 +15,7 @@ func TestUpdateNodeMetricsPeersCounter(t *testing.T) {
P2P: p2p.Config{ P2P: p2p.Config{
MaxPeers: 10, MaxPeers: 10,
}, },
NoUSB: true,
}) })
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, n.Start()) require.NoError(t, n.Start())

View File

@ -9,13 +9,13 @@ import (
) )
func TestSubscribeServerEventsWithoutServer(t *testing.T) { func TestSubscribeServerEventsWithoutServer(t *testing.T) {
gethNode, err := node.New(&node.Config{}) gethNode, err := node.New(&node.Config{NoUSB: true})
require.NoError(t, err) require.NoError(t, err)
require.EqualError(t, SubscribeServerEvents(context.TODO(), gethNode), "server is unavailable") require.EqualError(t, SubscribeServerEvents(context.TODO(), gethNode), "server is unavailable")
} }
func TestSubscribeServerEvents(t *testing.T) { func TestSubscribeServerEvents(t *testing.T) {
gethNode, err := node.New(&node.Config{}) gethNode, err := node.New(&node.Config{NoUSB: true})
require.NoError(t, err) require.NoError(t, err)
err = gethNode.Start() err = gethNode.Start()
require.NoError(t, err) require.NoError(t, err)

31
mobile/README.md Normal file
View File

@ -0,0 +1,31 @@
# Mobile
Package mobile implements [gomobile](https://github.com/golang/mobile) bindings for status-go. Current implementation servers as a drop-in replacement for `lib` package.
The framework name is generated from the package name, hence these things are done intentionally:
(1) this package's name isn't equal to the directory name (`statusgo` vs `mobile` respectively);
(2) this package name is `statusgo` and not `status` which produces the right framework name.
# Usage
For properly using this package, please refer to Makefile in the root of `status-go` directory.
To manually build library, run following commands:
### iOS
```
gomobile bind -v -target=ios -ldflags="-s -w" github.com/status-im/status-go/mobile
```
This will produce `Statusgo.framework` file in the current directory, which can be used in iOS project.
### Android
```
gomobile bind -v -target=android -ldflags="-s -w" github.com/status-im/status-go/mobile
```
This will generate `Statusgo.aar` file in the current dir.
# Notes
See [https://github.com/golang/go/wiki/Mobile](https://github.com/golang/go/wiki/Mobile) for more information on `gomobile` usage.

64
mobile/response.go Normal file
View File

@ -0,0 +1,64 @@
package statusgo
import (
"encoding/json"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/status-im/status-go/account"
"github.com/status-im/status-go/transactions"
)
const (
codeUnknown int = iota
// special codes
codeFailedParseResponse
codeFailedParseParams
// account related codes
codeErrNoAccountSelected
codeErrInvalidTxSender
codeErrDecrypt
)
var errToCodeMap = map[error]int{
account.ErrNoAccountSelected: codeErrNoAccountSelected,
transactions.ErrInvalidTxSender: codeErrInvalidTxSender,
keystore.ErrDecrypt: codeErrDecrypt,
}
type jsonrpcSuccessfulResponse struct {
Result interface{} `json:"result"`
}
type jsonrpcErrorResponse struct {
Error jsonError `json:"error"`
}
type jsonError struct {
Code int `json:"code,omitempty"`
Message string `json:"message"`
}
func prepareJSONResponse(result interface{}, err error) string {
code := codeUnknown
if c, ok := errToCodeMap[err]; ok {
code = c
}
return prepareJSONResponseWithCode(result, err, code)
}
func prepareJSONResponseWithCode(result interface{}, err error, code int) string {
if err != nil {
errResponse := jsonrpcErrorResponse{
Error: jsonError{Code: code, Message: err.Error()},
}
response, _ := json.Marshal(&errResponse)
return string(response)
}
data, err := json.Marshal(jsonrpcSuccessfulResponse{result})
if err != nil {
return prepareJSONResponseWithCode(nil, err, codeFailedParseResponse)
}
return string(data)
}

27
mobile/response_test.go Normal file
View File

@ -0,0 +1,27 @@
package statusgo
import (
"errors"
"testing"
"github.com/stretchr/testify/require"
)
type nonJSON struct{}
func (*nonJSON) MarshalJSON() ([]byte, error) {
return nil, errors.New("invalid JSON")
}
func TestPrepareJSONResponseErrorWithResult(t *testing.T) {
data := prepareJSONResponse("0x123", nil)
require.Equal(t, `{"result":"0x123"}`, data)
data = prepareJSONResponse(&nonJSON{}, nil)
require.Contains(t, data, `{"error":{"code":1,"message":`)
}
func TestPrepareJSONResponseErrorWithError(t *testing.T) {
data := prepareJSONResponse("0x123", errors.New("some error"))
require.Contains(t, data, `{"error":{"message":"some error"}}`)
}

496
mobile/status.go Normal file
View File

@ -0,0 +1,496 @@
package statusgo
import (
"encoding/json"
"fmt"
"os"
"unsafe"
"github.com/ethereum/go-ethereum/log"
"github.com/status-im/status-go/api"
"github.com/status-im/status-go/logutils"
"github.com/status-im/status-go/params"
"github.com/status-im/status-go/profiling"
"github.com/status-im/status-go/services/personal"
"github.com/status-im/status-go/signal"
"github.com/status-im/status-go/transactions"
validator "gopkg.in/go-playground/validator.v9"
)
var statusBackend = api.NewStatusBackend()
// All general log messages in this package should be routed through this logger.
var logger = log.New("package", "status-go/mobile")
// GenerateConfig for status node.
func GenerateConfig(datadir string, networkID int) string {
config, err := params.NewNodeConfig(datadir, uint64(networkID))
if err != nil {
return makeJSONResponse(err)
}
outBytes, err := json.Marshal(config)
if err != nil {
return makeJSONResponse(err)
}
return string(outBytes)
}
// StartNode starts the Ethereum Status node.
func StartNode(configJSON string) string {
config, err := params.NewConfigFromJSON(configJSON)
if err != nil {
return makeJSONResponse(err)
}
if err := logutils.OverrideRootLog(true, "INFO", "", true); err != nil {
return makeJSONResponse(err)
}
api.RunAsync(func() error { return statusBackend.StartNode(config) })
return makeJSONResponse(nil)
}
// StopNode stops the Ethereum Status node.
func StopNode() string {
api.RunAsync(statusBackend.StopNode)
return makeJSONResponse(nil)
}
// CreateContactCode creates an X3DH bundle.
func CreateContactCode() string {
bundle, err := statusBackend.CreateContactCode()
if err != nil {
return makeJSONResponse(err)
}
return bundle
}
// ProcessContactCode processes an X3DH bundle.
// TODO(adam): it looks like the return should be error.
func ProcessContactCode(bundle string) string {
err := statusBackend.ProcessContactCode(bundle)
if err != nil {
return makeJSONResponse(err)
}
return ""
}
// ExtractIdentityFromContactCode extracts an identity from an X3DH bundle.
func ExtractIdentityFromContactCode(bundle string) string {
identity, err := statusBackend.ExtractIdentityFromContactCode(bundle)
if err != nil {
return makeJSONResponse(err)
}
if err := statusBackend.ProcessContactCode(bundle); err != nil {
return makeJSONResponse(err)
}
data, err := json.Marshal(struct {
Identity string `json:"identity"`
}{Identity: identity})
if err != nil {
return makeJSONResponse(err)
}
return string(data)
}
// ExtractGroupMembershipSignatures extract public keys from tuples of content/signature.
func ExtractGroupMembershipSignatures(signaturePairsStr string) string {
var signaturePairs [][2]string
if err := json.Unmarshal([]byte(signaturePairsStr), &signaturePairs); err != nil {
return makeJSONResponse(err)
}
identities, err := statusBackend.ExtractGroupMembershipSignatures(signaturePairs)
if err != nil {
return makeJSONResponse(err)
}
data, err := json.Marshal(struct {
Identities []string `json:"identities"`
}{Identities: identities})
if err != nil {
return makeJSONResponse(err)
}
return string(data)
}
// SignGroupMembership signs a string containing group membership information.
func SignGroupMembership(content string) string {
signature, err := statusBackend.SignGroupMembership(content)
if err != nil {
return makeJSONResponse(err)
}
data, err := json.Marshal(struct {
Signature string `json:"signature"`
}{Signature: signature})
if err != nil {
return makeJSONResponse(err)
}
return string(data)
}
// EnableInstallation enables an installation for multi-device sync.
func EnableInstallation(installationID string) string {
err := statusBackend.EnableInstallation(installationID)
if err != nil {
return makeJSONResponse(err)
}
data, err := json.Marshal(struct {
Response string `json:"response"`
}{Response: "ok"})
if err != nil {
return makeJSONResponse(err)
}
return string(data)
}
// DisableInstallation disables an installation for multi-device sync.
func DisableInstallation(installationID string) string {
err := statusBackend.DisableInstallation(installationID)
if err != nil {
return makeJSONResponse(err)
}
data, err := json.Marshal(struct {
Response string `json:"response"`
}{Response: "ok"})
if err != nil {
return makeJSONResponse(err)
}
return string(data)
}
// ValidateNodeConfig validates config for the Status node.
func ValidateNodeConfig(configJSON string) string {
var resp APIDetailedResponse
_, err := params.NewConfigFromJSON(configJSON)
// Convert errors to APIDetailedResponse
switch err := err.(type) {
case validator.ValidationErrors:
resp = APIDetailedResponse{
Message: "validation: validation failed",
FieldErrors: make([]APIFieldError, len(err)),
}
for i, ve := range err {
resp.FieldErrors[i] = APIFieldError{
Parameter: ve.Namespace(),
Errors: []APIError{
{
Message: fmt.Sprintf("field validation failed on the '%s' tag", ve.Tag()),
},
},
}
}
case error:
resp = APIDetailedResponse{
Message: fmt.Sprintf("validation: %s", err.Error()),
}
case nil:
resp = APIDetailedResponse{
Status: true,
}
}
respJSON, err := json.Marshal(resp)
if err != nil {
return makeJSONResponse(err)
}
return string(respJSON)
}
// ResetChainData removes chain data from data directory.
func ResetChainData() string {
api.RunAsync(statusBackend.ResetChainData)
return makeJSONResponse(nil)
}
// CallRPC calls public APIs via RPC.
func CallRPC(inputJSON string) string {
resp, err := statusBackend.CallRPC(inputJSON)
if err != nil {
return makeJSONResponse(err)
}
return resp
}
// CallPrivateRPC calls both public and private APIs via RPC.
func CallPrivateRPC(inputJSON string) string {
resp, err := statusBackend.CallPrivateRPC(inputJSON)
if err != nil {
return makeJSONResponse(err)
}
return resp
}
// CreateAccount is equivalent to creating an account from the command line,
// just modified to handle the function arg passing.
func CreateAccount(password string) string {
info, mnemonic, err := statusBackend.AccountManager().CreateAccount(password)
errString := ""
if err != nil {
fmt.Fprintln(os.Stderr, err)
errString = err.Error()
}
out := AccountInfo{
Address: info.WalletAddress,
PubKey: info.WalletPubKey,
WalletAddress: info.WalletAddress,
WalletPubKey: info.WalletPubKey,
ChatAddress: info.ChatAddress,
ChatPubKey: info.ChatPubKey,
Mnemonic: mnemonic,
Error: errString,
}
outBytes, _ := json.Marshal(out)
return string(outBytes)
}
// CreateChildAccount creates sub-account.
func CreateChildAccount(parentAddress, password string) string {
address, pubKey, err := statusBackend.AccountManager().CreateChildAccount(parentAddress, password)
errString := ""
if err != nil {
fmt.Fprintln(os.Stderr, err)
errString = err.Error()
}
out := AccountInfo{
Address: address,
PubKey: pubKey,
Error: errString,
}
outBytes, _ := json.Marshal(out)
return string(outBytes)
}
// RecoverAccount re-creates master key using given details.
func RecoverAccount(password, mnemonic string) string {
info, err := statusBackend.AccountManager().RecoverAccount(password, mnemonic)
errString := ""
if err != nil {
fmt.Fprintln(os.Stderr, err)
errString = err.Error()
}
out := AccountInfo{
Address: info.WalletAddress,
PubKey: info.WalletPubKey,
WalletAddress: info.WalletAddress,
WalletPubKey: info.WalletPubKey,
ChatAddress: info.ChatAddress,
ChatPubKey: info.ChatPubKey,
Mnemonic: mnemonic,
Error: errString,
}
outBytes, _ := json.Marshal(out)
return string(outBytes)
}
// VerifyAccountPassword verifies account password.
func VerifyAccountPassword(keyStoreDir, address, password string) string {
_, err := statusBackend.AccountManager().VerifyAccountPassword(keyStoreDir, address, password)
return makeJSONResponse(err)
}
// Login loads a key file (for a given address), tries to decrypt it using the password,
// to verify ownership if verified, purges all the previous identities from Whisper,
// and injects verified key as shh identity.
func Login(address, password string) string {
err := statusBackend.SelectAccount(address, address, password)
return makeJSONResponse(err)
}
// Logout is equivalent to clearing whisper identities.
func Logout() string {
err := statusBackend.Logout()
return makeJSONResponse(err)
}
// SignMessage unmarshals rpc params {data, address, password} and
// passes them onto backend.SignMessage.
func SignMessage(rpcParams string) string {
var params personal.SignParams
err := json.Unmarshal([]byte(rpcParams), &params)
if err != nil {
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
}
result, err := statusBackend.SignMessage(params)
return prepareJSONResponse(result.String(), err)
}
// Recover unmarshals rpc params {signDataString, signedData} and passes
// them onto backend.
func Recover(rpcParams string) string {
var params personal.RecoverParams
err := json.Unmarshal([]byte(rpcParams), &params)
if err != nil {
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
}
addr, err := statusBackend.Recover(params)
return prepareJSONResponse(addr.String(), err)
}
// SendTransaction converts RPC args and calls backend.SendTransaction.
func SendTransaction(txArgsJSON, password string) string {
var params transactions.SendTxArgs
err := json.Unmarshal([]byte(txArgsJSON), &params)
if err != nil {
return prepareJSONResponseWithCode(nil, err, codeFailedParseParams)
}
hash, err := statusBackend.SendTransaction(params, password)
code := codeUnknown
if c, ok := errToCodeMap[err]; ok {
code = c
}
return prepareJSONResponseWithCode(hash.String(), err, code)
}
// StartCPUProfile runs pprof for CPU.
func StartCPUProfile(dataDir string) string {
err := profiling.StartCPUProfile(dataDir)
return makeJSONResponse(err)
}
// StopCPUProfiling stops pprof for cpu.
func StopCPUProfiling() string { //nolint: deadcode
err := profiling.StopCPUProfile()
return makeJSONResponse(err)
}
//WriteHeapProfile starts pprof for heap
func WriteHeapProfile(dataDir string) string { //nolint: deadcode
err := profiling.WriteHeapFile(dataDir)
return makeJSONResponse(err)
}
func makeJSONResponse(err error) string {
errString := ""
if err != nil {
fmt.Fprintln(os.Stderr, err)
errString = err.Error()
}
out := APIResponse{
Error: errString,
}
outBytes, _ := json.Marshal(out)
return string(outBytes)
}
// SendDataNotification sends push notifications by given tokens.
// dataPayloadJSON is a JSON string that looks like this:
// {
// "data": {
// "msg-v2": {
// "from": "0x2cea3bd5", // hash of sender (first 10 characters/4 bytes of sha3 hash)
// "to": "0xb1f89744", // hash of recipient (first 10 characters/4 bytes of sha3 hash)
// "id": "0x872653ad", // message ID hash (first 10 characters/4 bytes of sha3 hash)
// }
// }
// }
func SendDataNotification(dataPayloadJSON, tokensArray string) (result string) {
var (
err error
errString string
)
defer func() {
out := SendDataNotificationResult{
Status: err == nil,
Error: errString,
}
var resultBytes []byte
resultBytes, err = json.Marshal(out)
if err != nil {
logger.Error("failed to marshal SendDataNotification output", "error", err)
result = makeJSONResponse(err)
return
}
result = string(resultBytes)
}()
tokens, err := ParseJSONArray((tokensArray))
if err != nil {
errString = err.Error()
return ""
}
err = statusBackend.SendDataNotification(dataPayloadJSON, tokens...)
if err != nil {
errString = err.Error()
return ""
}
return ""
}
// UpdateMailservers updates mail servers in status backend.
//export UpdateMailservers
func UpdateMailservers(data string) string {
var enodes []string
err := json.Unmarshal([]byte(data), &enodes)
if err != nil {
return makeJSONResponse(err)
}
err = statusBackend.UpdateMailservers(enodes)
return makeJSONResponse(err)
}
// AddPeer adds an enode as a peer.
func AddPeer(enode string) string {
err := statusBackend.StatusNode().AddPeer(enode)
return makeJSONResponse(err)
}
// ConnectionChange handles network state changes as reported
// by ReactNative (see https://facebook.github.io/react-native/docs/netinfo.html)
func ConnectionChange(typ string, expensive int) {
statusBackend.ConnectionChange(typ, expensive == 1)
}
// AppStateChange handles app state changes (background/foreground).
func AppStateChange(state string) {
statusBackend.AppStateChange(state)
}
// SetMobileSignalHandler setup geth callback to notify about new signal
// used for gomobile builds
func SetMobileSignalHandler(handler SignalHandler) {
signal.SetMobileSignalHandler(func(data []byte) {
if len(data) > 0 {
handler.HandleSignal(string(data))
}
})
}
// SetSignalEventCallback setup geth callback to notify about new signal
func SetSignalEventCallback(cb unsafe.Pointer) {
signal.SetSignalEventCallback(cb)
}

93
mobile/types.go Normal file
View File

@ -0,0 +1,93 @@
package statusgo
import (
"bytes"
"fmt"
"strings"
)
// APIResponse generic response from API.
type APIResponse struct {
Error string `json:"error"`
}
// APIDetailedResponse represents a generic response
// with possible errors.
type APIDetailedResponse struct {
Status bool `json:"status"`
Message string `json:"message,omitempty"`
FieldErrors []APIFieldError `json:"field_errors,omitempty"`
}
// Error string representation of APIDetailedResponse.
func (r APIDetailedResponse) Error() string {
buf := bytes.NewBufferString("")
for _, err := range r.FieldErrors {
buf.WriteString(err.Error() + "\n") // nolint: gas
}
return strings.TrimSpace(buf.String())
}
// APIFieldError represents a set of errors
// related to a parameter.
type APIFieldError struct {
Parameter string `json:"parameter,omitempty"`
Errors []APIError `json:"errors"`
}
// Error string representation of APIFieldError.
func (e APIFieldError) Error() string {
if len(e.Errors) == 0 {
return ""
}
buf := bytes.NewBufferString(fmt.Sprintf("Parameter: %s\n", e.Parameter))
for _, err := range e.Errors {
buf.WriteString(err.Error() + "\n") // nolint: gas
}
return strings.TrimSpace(buf.String())
}
// APIError represents a single error.
type APIError struct {
Message string `json:"message"`
}
// Error string representation of APIError.
func (e APIError) Error() string {
return fmt.Sprintf("message=%s", e.Message)
}
// AccountInfo represents account's info.
type AccountInfo struct {
Address string `json:"address"` // DEPRECATED
PubKey string `json:"pubkey"` // DEPRECATED
WalletAddress string `json:"walletAddress"`
WalletPubKey string `json:"walletPubKey"`
ChatAddress string `json:"chatAddress"`
ChatPubKey string `json:"chatPubKey"`
Mnemonic string `json:"mnemonic"`
Error string `json:"error"`
}
// NotifyResult is a JSON returned from notify message.
type NotifyResult struct {
Status bool `json:"status"`
Error string `json:"error,omitempty"`
}
// SignalHandler defines a minimal interface
// a signal handler needs to implement.
type SignalHandler interface {
HandleSignal(string)
}
// SendDataNotificationResult is a JSON returned from notify message.
type SendDataNotificationResult struct {
Status bool `json:"status"`
Error string `json:"error,omitempty"`
}

16
mobile/utils.go Normal file
View File

@ -0,0 +1,16 @@
package statusgo
import (
"encoding/json"
)
// ParseJSONArray parses JSON array into Go array of string.
func ParseJSONArray(items string) ([]string, error) {
var parsedItems []string
err := json.Unmarshal([]byte(items), &parsedItems)
if err != nil {
return nil, err
}
return parsedItems, nil
}

View File

@ -165,6 +165,7 @@ func TestStatusNodeAddPeer(t *testing.T) {
NoDiscovery: true, NoDiscovery: true,
ListenAddr: ":0", ListenAddr: ":0",
}, },
NoUSB: true,
}) })
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, peer.Start()) require.NoError(t, peer.Start())
@ -200,6 +201,7 @@ func TestStatusNodeReconnectStaticPeers(t *testing.T) {
NoDiscovery: true, NoDiscovery: true,
ListenAddr: ":0", ListenAddr: ":0",
}, },
NoUSB: true,
}) })
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, peer.Start()) require.NoError(t, peer.Start())

View File

@ -79,6 +79,8 @@ func TestGetFilterChangesResetsTimer(t *testing.T) {
} }
func TestGetFilterLogs(t *testing.T) { func TestGetFilterLogs(t *testing.T) {
t.Skip("Skipping due to flakiness: https://github.com/status-im/status-go/issues/1281")
tracker := new(callTracker) tracker := new(callTracker)
api := &PublicAPI{ api := &PublicAPI{
filters: make(map[rpc.ID]filter), filters: make(map[rpc.ID]filter),

View File

@ -98,6 +98,7 @@ func (s *ShhExtSuite) SetupTest() {
MaxPeers: 1, MaxPeers: 1,
ListenAddr: ":0", ListenAddr: ":0",
}, },
NoUSB: true,
} }
stack, err := node.New(cfg) stack, err := node.New(cfg)
s.NoError(err) s.NoError(err)
@ -198,6 +199,7 @@ func (s *ShhExtSuite) TestRequestMessagesErrors() {
MaxPeers: math.MaxInt32, MaxPeers: math.MaxInt32,
NoDiscovery: true, NoDiscovery: true,
}, },
NoUSB: true,
}) // in-memory node as no data dir }) // in-memory node as no data dir
s.NoError(err) s.NoError(err)
err = aNode.Register(func(*node.ServiceContext) (node.Service, error) { err = aNode.Register(func(*node.ServiceContext) (node.Service, error) {
@ -285,6 +287,7 @@ func (s *ShhExtSuite) TestRequestMessagesSuccess() {
MaxPeers: math.MaxInt32, MaxPeers: math.MaxInt32,
NoDiscovery: true, NoDiscovery: true,
}, },
NoUSB: true,
}) // in-memory node as no data dir }) // in-memory node as no data dir
s.Require().NoError(err) s.Require().NoError(err)
err = aNode.Register(func(*node.ServiceContext) (node.Service, error) { return shh, nil }) err = aNode.Register(func(*node.ServiceContext) (node.Service, error) { return shh, nil })
@ -312,6 +315,7 @@ func (s *ShhExtSuite) TestRequestMessagesSuccess() {
NoDiscovery: true, NoDiscovery: true,
ListenAddr: ":0", ListenAddr: ":0",
}, },
NoUSB: true,
}) // in-memory node as no data dir }) // in-memory node as no data dir
s.Require().NoError(err) s.Require().NoError(err)
err = mailNode.Register(func(*node.ServiceContext) (node.Service, error) { err = mailNode.Register(func(*node.ServiceContext) (node.Service, error) {

View File

@ -1,208 +1,3 @@
#if defined(IOS_DEPLOYMENT)
// ======================================================================================
// iOS framework compilation using xgo
// ======================================================================================
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#include <objc/message.h>
static id statusServiceClassRef = nil;
static SEL statusServiceSelector = nil;
static bool initLibrary() {
if (statusServiceClassRef == nil) {
statusServiceClassRef = objc_getClass("Status");
if (statusServiceClassRef == nil) return false;
}
if (statusServiceSelector == nil) {
statusServiceSelector = sel_getUid("signalEvent:");
if (statusServiceSelector == nil) return false;
}
return true;
}
/*!
* @brief Calls static method signalEvent of class GethService.
*
* @param jsonEvent - UTF8 string
*
* @note Definition of signalEvent method.
* + (void)signalEvent:(const char *)json
*/
bool StatusServiceSignalEvent(const char *jsonEvent) {
if (!initLibrary()) return false;
void (*action)(id, SEL, const char *) = (void (*)(id, SEL, const char *)) objc_msgSend;
action(statusServiceClassRef, statusServiceSelector, jsonEvent);
return true;
}
void SetEventCallback(void *cb) {
}
#elif defined(ANDROID_DEPLOYMENT)
// ======================================================================================
// Android archive compilation using xgo
// ======================================================================================
#include <stddef.h>
#include <stdbool.h>
#include <jni.h>
bool StatusServiceSignalEvent(const char *jsonEvent);
static JavaVM *gJavaVM = NULL;
static jclass JavaClassPtr_StatusService = NULL;
static jmethodID JavaMethodPtr_signalEvent = NULL;
static bool JniLibraryInit(JNIEnv *env);
/*!
* @brief Get interface to JNI.
*
* @return true if thread should be detached from JNI.
*/
static bool JniAttach(JNIEnv **env) {
jint status;
if (gJavaVM == NULL) {
env = NULL;
}
status = (*gJavaVM)->GetEnv(gJavaVM, (void **)env, JNI_VERSION_1_6);
if (status == JNI_EDETACHED) {
// attach thread to JNI
//(*gJavaVM)->AttachCurrentThread( gJavaVM, (void **)env, NULL ); // Oracle JNI API
(*gJavaVM)->AttachCurrentThread(gJavaVM, env, NULL); // Android JNI API
return true;
} else if (status != JNI_OK) {
return false;
}
return false;
}
/*!
* @brief The VM calls JNI_OnLoad when the native library is loaded.
*/
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
bool detach;
JNIEnv *env;
int result = JNI_VERSION_1_6;
gJavaVM = vm;
// attach thread to JNI
detach = JniAttach(&env);
if (env == NULL) {
// failed
gJavaVM = NULL;
return 0;
}
if (!JniLibraryInit(env)) {
// fail loading of JNI library
result = 0;
}
if (detach) {
// detach thread from JNI
(*gJavaVM)->DetachCurrentThread(gJavaVM);
}
if (result != JNI_VERSION_1_6) {
gJavaVM = NULL;
}
return result;
}
/*!
* @brief Initialize library.
*/
bool JniLibraryInit(JNIEnv *env) {
int i;
JavaClassPtr_StatusService = (*env)->FindClass(env, "im/status/ethereum/module/StatusService");
if (JavaClassPtr_StatusService == NULL) return false;
JavaClassPtr_StatusService = (jclass)(*env)->NewGlobalRef(env, JavaClassPtr_StatusService);
if (JavaClassPtr_StatusService == NULL) return false;
struct {
bool bStatic;
jclass classPtr;
jmethodID *methodPtr;
const char *methodId;
const char *params;
} javaMethodDescriptors[] = {
{
true,
JavaClassPtr_StatusService,
&JavaMethodPtr_signalEvent, // &JavaMethodPtr_someNonStaticMethod
"signalEvent", // someNonStaticMethod
"(Ljava/lang/String;)V"
},
};
for (i = 0; i < sizeof(javaMethodDescriptors) / sizeof(javaMethodDescriptors[0]); i++) {
if (javaMethodDescriptors[i].bStatic) {
*(javaMethodDescriptors[i].methodPtr) = (*env)->GetStaticMethodID(
env, javaMethodDescriptors[i].classPtr, javaMethodDescriptors[i].methodId, javaMethodDescriptors[i].params);
} else {
*(javaMethodDescriptors[i].methodPtr) = (*env)->GetMethodID(
env, javaMethodDescriptors[i].classPtr, javaMethodDescriptors[i].methodId, javaMethodDescriptors[i].params);
}
if (*(javaMethodDescriptors[i].methodPtr) == NULL) return false;
}
return true;
}
/*!
* @brief Calls static method signalEvent of class im.status.ethereum.module.StatusService.
*
* @param jsonEvent - UTF8 string
*/
bool StatusServiceSignalEvent(const char *jsonEvent) {
bool detach;
JNIEnv *env;
// attach thread to JNI
detach = JniAttach( &env );
if (env == NULL) { // failed
return false;
}
jstring javaJsonEvent = NULL;
if (jsonEvent != NULL) {
javaJsonEvent = (*env)->NewStringUTF(env, jsonEvent);
}
(*env)->CallStaticVoidMethod(env, JavaClassPtr_StatusService, JavaMethodPtr_signalEvent, javaJsonEvent);
if (javaJsonEvent != NULL) (*env)->DeleteLocalRef(env, javaJsonEvent);
if (detach) { // detach thread from JNI
(*gJavaVM)->DetachCurrentThread(gJavaVM);
}
return true;
}
void SetEventCallback(void *cb) {
}
#else
// ====================================================================================== // ======================================================================================
// cgo compilation (for desktop platforms and local tests) // cgo compilation (for desktop platforms and local tests)
// ====================================================================================== // ======================================================================================
@ -228,5 +23,3 @@ bool StatusServiceSignalEvent(const char *jsonEvent) {
void SetEventCallback(void *cb) { void SetEventCallback(void *cb) {
gCallback = (callback)cb; gCallback = (callback)cb;
} }
#endif

View File

@ -18,6 +18,12 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
// MobileSignalHandler is a simple callback function that gets called when any signal is received
type MobileSignalHandler func([]byte)
// storing the current signal handler here
var mobileSignalHandler MobileSignalHandler
// All general log messages in this package should be routed through this logger. // All general log messages in this package should be routed through this logger.
var logger = log.New("package", "status-go/signal") var logger = log.New("package", "status-go/signal")
@ -44,10 +50,16 @@ func send(typ string, event interface{}) {
return return
} }
// If a Go implementation of signal handler is set, let's use it.
if mobileSignalHandler != nil {
mobileSignalHandler(data)
} else {
// ...and fallback to C implementation otherwise.
str := C.CString(string(data)) str := C.CString(string(data))
C.StatusServiceSignalEvent(str) C.StatusServiceSignalEvent(str)
C.free(unsafe.Pointer(str)) C.free(unsafe.Pointer(str))
} }
}
// NodeNotificationHandler defines a handler able to process incoming node events. // NodeNotificationHandler defines a handler able to process incoming node events.
// Events are encoded as JSON strings. // Events are encoded as JSON strings.
@ -93,7 +105,14 @@ func TriggerTestSignal() {
C.free(unsafe.Pointer(str)) C.free(unsafe.Pointer(str))
} }
// SetMobileSignalHandler sets new handler for geth events
// this function uses pure go implementation
func SetMobileSignalHandler(handler MobileSignalHandler) {
mobileSignalHandler = handler
}
// SetSignalEventCallback set callback // SetSignalEventCallback set callback
// this function uses C implementation (see `signals.c` file)
func SetSignalEventCallback(cb unsafe.Pointer) { func SetSignalEventCallback(cb unsafe.Pointer) {
C.SetEventCallback(cb) C.SetEventCallback(cb)
} }

View File

@ -30,6 +30,7 @@ func createNode() (*node.Node, error) {
MaxPeers: 1, MaxPeers: 1,
NAT: nat.Any(), NAT: nat.Any(),
}, },
NoUSB: true,
}) })
} }

View File

@ -30,6 +30,7 @@ func NewDevNode(faucet common.Address) (*node.Node, error) {
cfg.IPCPath = ipc.Name() cfg.IPCPath = ipc.Name()
cfg.HTTPModules = []string{"eth"} cfg.HTTPModules = []string{"eth"}
cfg.DataDir = "" cfg.DataDir = ""
cfg.NoUSB = true
cfg.P2P.MaxPeers = 0 cfg.P2P.MaxPeers = 0
cfg.P2P.ListenAddr = ":0" cfg.P2P.ListenAddr = ":0"
cfg.P2P.NoDiscovery = true cfg.P2P.NoDiscovery = true