diff --git a/Makefile b/Makefile index 0d3810489d..d1fda96aad 100644 --- a/Makefile +++ b/Makefile @@ -111,14 +111,9 @@ release-android: export BUILD_ENV ?= prod release-android: export BUILD_TYPE ?= nightly release-android: export BUILD_NUMBER ?= 9999 release-android: export NDK_ABI_FILTERS ?= armeabi-v7a;arm64-v8a;x86 -release-android: export STORE_FILE ?= ~/.gradle/status-im.keystore +release-android: export STORE_FILE ?= $(HOME)/.gradle/status-im.keystore release-android: ##@build build release for Android - nix/build.sh targets.mobile.$(TARGET_OS).release \ - --arg env '{NDK_ABI_FILTERS="$(NDK_ABI_FILTERS)";}' \ - --argstr build-type $(BUILD_TYPE) \ - --argstr build-number $(BUILD_NUMBER) \ - --argstr keystore-file $(STORE_FILE) \ - --option extra-sandbox-paths $(STORE_FILE) + scripts/release-android.sh release-ios: export TARGET_OS ?= ios release-ios: export BUILD_ENV ?= prod diff --git a/nix/mobile/android/default.nix b/nix/mobile/android/default.nix index dec6de3329..06b2bf209e 100644 --- a/nix/mobile/android/default.nix +++ b/nix/mobile/android/default.nix @@ -8,11 +8,14 @@ let androidEnv = callPackage ./android-env.nix { inherit target-os openjdk; }; gradle = callPackage ./gradle.nix { }; + # Import a patched version of watchman (important for sandboxed builds on macOS) + watchmanFactory = callPackage ./watchman.nix { }; + # Import a local patched version of node_modules, together with a local version of the Maven repo mavenAndNpmDeps = callPackage ./maven-and-npm-deps { inherit stdenv stdenvNoCC gradle bash nodejs zlib localMavenRepoBuilder mkFilter projectNodePackage; }; # TARGETS - release = callPackage ./targets/release-android.nix { inherit target-os gradle mavenAndNpmDeps mkFilter nodejs jsbundle status-go zlib; androidEnvShellHook = androidEnv.shellHook; }; + release = callPackage ./targets/release-android.nix { inherit target-os gradle mavenAndNpmDeps mkFilter nodejs jsbundle status-go zlib watchmanFactory; androidEnvShellHook = androidEnv.shellHook; }; generate-maven-and-npm-deps-shell = callPackage ./maven-and-npm-deps/maven/shell.nix { inherit mkShell gradle maven nodejs projectNodePackage status-go; androidEnvShellHook = androidEnv.shellHook; }; adb-shell = mkShell { buildInputs = [ androidEnv.licensedAndroidEnv ]; diff --git a/nix/mobile/android/targets/release-android.nix b/nix/mobile/android/targets/release-android.nix index 005d267505..46b055ce95 100644 --- a/nix/mobile/android/targets/release-android.nix +++ b/nix/mobile/android/targets/release-android.nix @@ -1,5 +1,5 @@ { stdenv, stdenvNoCC, lib, target-os, callPackage, - mkFilter, bash, file, gnumake, watchman, gradle, + mkFilter, bash, file, gnumake, watchmanFactory, gradle, androidEnvShellHook, mavenAndNpmDeps, nodejs, openjdk, jsbundle, status-go, unzip, zlib }: @@ -8,9 +8,12 @@ gradle-opts ? "", keystore-file ? "", # Path to the .keystore file used to sign the package secrets-file ? "", # Path to the file containing secret environment variables + watchmanSockPath ? "", # Path to the socket file exposed by an external watchman instance (workaround needed for building Android on macOS) env ? {} # Attribute set contaning environment variables to expose to the build script }: +assert (builtins.stringLength watchmanSockPath) > 0 -> stdenv.isDarwin; + let baseName = "release-${target-os}"; name = "status-react-build-${baseName}"; @@ -23,6 +26,7 @@ let buildType' = if (build-type == "pr" || build-type == "e2e") then "pr" else "release"; /* PR builds shouldn't replace normal releases */ generatedApkPath = "$sourceRoot/android/app/build/outputs/apk/${buildType'}/app-${buildType'}.apk"; outApkName = "app.apk"; + patchedWatchman = watchmanFactory watchmanSockPath; in stdenv.mkDerivation { inherit name; @@ -36,15 +40,15 @@ in stdenv.mkDerivation { mkFilter { dirRootsToInclude = [ "mobile_files" - "modules/react-native-status" + "modules/react-native-status/android" "resources" ]; dirsToExclude = [ ".git" ".svn" "CVS" ".hg" ".gradle" "build" "intermediates" "libs" "obj" ]; - filesToInclude = [ envFileName "status-go-version.json" "VERSION" "react-native.config.js" ]; + filesToInclude = [ envFileName "status-go-version.json" "VERSION" "react-native.config.js" ".watchmanconfig" ]; root = path; }; }; - nativeBuildInputs = [ bash gradle unzip ] ++ lib.optionals stdenv.isDarwin [ file gnumake watchman ]; + nativeBuildInputs = [ bash gradle unzip ] ++ lib.optionals stdenv.isDarwin [ file gnumake patchedWatchman ]; buildInputs = [ nodejs openjdk ]; phases = [ "unpackPhase" "patchPhase" "buildPhase" "checkPhase" "installPhase" ]; unpackPhase = '' diff --git a/nix/mobile/android/watchman.nix b/nix/mobile/android/watchman.nix new file mode 100644 index 0000000000..78c1001fcf --- /dev/null +++ b/nix/mobile/android/watchman.nix @@ -0,0 +1,18 @@ +{ stdenv, runCommand, makeWrapper, + watchman }: + +let + patchedWatchmanFactory = watchmanSockPath: + assert (builtins.stringLength watchmanSockPath) > 0 -> stdenv.isDarwin; + if stdenv.isDarwin then + assert (builtins.stringLength watchmanSockPath) > 0; + # Create a wrapper to watchman that includes the --sockname flag + runCommand "patched-watchman" { nativeBuildInputs = [ makeWrapper ]; } '' + mkdir -p $out/bin + + makeWrapper ${watchman}/bin/watchman \ + $out/bin/watchman \ + --add-flags "--sockname=${watchmanSockPath}" + '' else watchman; + +in patchedWatchmanFactory diff --git a/nix/shell.sh b/nix/shell.sh index 2016ef802f..02a5d8d660 100755 --- a/nix/shell.sh +++ b/nix/shell.sh @@ -22,7 +22,7 @@ if ! command -v "nix" >/dev/null 2>&1; then if [ -f ~/.nix-profile/etc/profile.d/nix.sh ]; then . ~/.nix-profile/etc/profile.d/nix.sh elif [ "$IN_NIX_SHELL" != 'pure' ]; then - echo -e "${GREEN}Setting up environment...${NC}" + echo -e "${GREEN}Setting up environment...${NC}" > /dev/stderr ./scripts/setup . ~/.nix-profile/etc/profile.d/nix.sh @@ -30,7 +30,7 @@ if ! command -v "nix" >/dev/null 2>&1; then fi if !command -v "nix" >/dev/null 2>&1; then - echo "Nix not available, sourcing profile failed!" + echo "Nix not available, sourcing profile failed!" > /dev/stderr exit 1 fi @@ -41,7 +41,7 @@ shellArgs=( if [[ -n "${TARGET_OS}" ]]; then shellArgs+=("--argstr target-os ${TARGET_OS}") else - echo -e "${YELLOW}Env is missing TARGET_OS, assuming no target platform.${NC} See nix/README.md for more details." + echo -e "${YELLOW}Env is missing TARGET_OS, assuming no target platform.${NC} See nix/README.md for more details." > /dev/stderr fi if [[ "$TARGET_OS" =~ (linux|windows|darwin|macos) ]]; then @@ -61,7 +61,7 @@ fi # ENTER_NIX_SHELL is the fake command used when `make shell` is run. # It is just a special string, not a variable, and a marker to not use `--run`. if [[ $@ == "ENTER_NIX_SHELL" ]]; then - echo -e "${GREEN}Configuring ${_NIX_ATTR:-default} Nix shell for target '${TARGET_OS:-none}'...${NC}" + echo -e "${GREEN}Configuring ${_NIX_ATTR:-default} Nix shell for target '${TARGET_OS:-none}'...${NC}" > /dev/stderr exec nix-shell ${shellArgs[@]} ${entryPoint} else # Not all builds are ready to be run in a pure environment @@ -74,6 +74,6 @@ else if [[ -n "${_NIX_KEEP}" ]]; then shellArgs+=("--keep ${_NIX_KEEP//;/ --keep }") fi - echo -e "${GREEN}Configuring ${pureDesc}${_NIX_ATTR:-default} Nix shell for target '${TARGET_OS}'...${NC}" + echo -e "${GREEN}Configuring ${pureDesc}${_NIX_ATTR:-default} Nix shell for target '${TARGET_OS}'...${NC}" > /dev/stderr exec nix-shell ${shellArgs[@]} --run "$@" ${entryPoint} fi diff --git a/scripts/release-android.sh b/scripts/release-android.sh new file mode 100755 index 0000000000..9e7791cd32 --- /dev/null +++ b/scripts/release-android.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel) +_current_dir=$(cd "${BASH_SOURCE%/*}" && pwd) +source "$_current_dir/lib/setup/path-support.sh" + +source_lib "platform.sh" + +nixOpts=( + "--arg env {NDK_ABI_FILTERS=\"${NDK_ABI_FILTERS}\";}" + "--argstr build-type ${BUILD_TYPE}" + "--argstr build-number ${BUILD_NUMBER}" + "--argstr keystore-file ${STORE_FILE}" +) + +if is_macos; then + # Start a watchman instance if not started already and store its socket path. + # In order to get access to the right versions of watchman and jq, we start an ad-hoc nix-shell that imports the packages from nix/nixpkgs-bootstrap. + WATCHMAN_SOCKFILE=$(watchman get-sockname --no-pretty | jq -r .sockname) + nixOpts+=( + "--argstr watchmanSockPath ${WATCHMAN_SOCKFILE}" + "--option extra-sandbox-paths ${STORE_FILE};${WATCHMAN_SOCKFILE}" + ) +else + nixOpts+=( + "--option extra-sandbox-paths ${STORE_FILE}" + ) +fi + +${GIT_ROOT}/nix/build.sh targets.mobile.${TARGET_OS}.release "${nixOpts[@]}"