2019-06-04 16:50:29 +00:00
#
# This script prepares a finalized version of node_modules
# (required because for Android we need to run `gradle react-native-android:installArchives`, which builds some additional native libraries
# under node_modules/react-native), as well as a local version of the Maven repository required by Gradle scripts
#
{ stdenv , stdenvNoCC , lib , callPackage ,
gradle , bash , file , nodejs , status-go , zlib ,
projectNodePackage , androidEnvShellHook , localMavenRepoBuilder , mkFilter } :
let
mavenLocalRepo = callPackage ./maven { inherit localMavenRepoBuilder ; stdenv = if stdenv . isLinux then stdenv else stdenvNoCC ; } ;
# Import the native dependencies for React Native Android builds
jsc-filename = " j s c - a n d r o i d - 2 3 6 3 5 5 . 1 . 1 " ;
react-native-deps = callPackage ./maven/reactnative-android-native-deps.nix { inherit stdenvNoCC jsc-filename ; } ;
createMobileFilesSymlinks = root : ''
ln - sf $ { root } /mobile_files/package.json.orig $ { root } /package.json
ln - sf $ { root } /mobile_files/metro.config.js $ { root } /metro.config.js
ln - sf $ { root } /mobile_files/yarn.lock $ { root } /yarn.lock
'' ;
# fake build to pre-download deps into fixed-output derivation
deps =
let
# Place build target directories in NIX_BUILD_TOP (normally represents /build)
projectDir = " $ N I X _ B U I L D _ T O P / p r o j e c t " ;
mavenRepoDir = " $ N I X _ B U I L D _ T O P / . m 2 / r e p o s i t o r y " ;
reactNativeMavenPackageDir = " ${ mavenRepoDir } / c o m / f a c e b o o k / r e a c t / r e a c t - n a t i v e " ; # This is directory where the react-native Maven package will be generated in
reactNativeDepsDir = " $ N I X _ B U I L D _ T O P / d e p s " ; # Use local writable deps, otherwise (probably due to some interaction between Nix sandboxing and Java) gradle will fail copying directly from the nix store
in
stdenv . mkDerivation {
2019-07-26 14:51:06 +00:00
name = " a n d r o i d - g r a d l e - a n d - n p m - m o d u l e s " ;
2019-06-04 16:50:29 +00:00
src =
let path = ./../../../.. ; # Import the root /android and /mobile_files folders clean of any build artifacts
in builtins . path { # We use builtins.path so that we can name the resulting derivation, otherwise the name would be taken from the checkout directory, which is outside of our control
inherit path ;
2019-07-15 16:34:33 +00:00
name = " s t a t u s - r e a c t - s o u r c e - g r a d l e - i n s t a l l " ;
2019-06-04 16:50:29 +00:00
filter =
# Keep this filter as restrictive as possible in order to avoid unnecessary rebuilds and limit closure size
mkFilter {
dirRootsToInclude = [
" a n d r o i d " " m o b i l e _ f i l e s " " p a c k a g e r " " r e s o u r c e s "
" t r a n s l a t i o n s " " s t a t u s - m o d u l e s "
] ;
dirsToExclude = [ " . g i t " " . s v n " " C V S " " . h g " " . g r a d l e " " b u i l d " " i n t e r m e d i a t e s " " l i b s " " o b j " ] ;
filesToInclude = [ " . b a b e l r c " ] ;
filesToExclude = [ " a n d r o i d / g r a d l e w " ] ;
root = path ;
} ;
} ;
nativeBuildInputs = [ projectNodePackage ] ;
2019-08-01 10:49:46 +00:00
buildInputs = [ gradle nodejs bash file zlib mavenLocalRepo ] ;
2019-06-04 16:50:29 +00:00
propagatedBuildInputs = [ react-native-deps ] ++ status-go . buildInputs ;
unpackPhase = ''
runHook preUnpack
# Copy project directory
mkdir - p $ { projectDir }
cp - a $ src/. $ { projectDir }
chmod u + w $ { projectDir }
cd $ { projectDir }
# Copy RN maven dependencies and make them writable, otherwise Gradle copy fails (since the top-level directory is read-only, Java isn't smart enough to copy the child files/folders into that target directory)
mkdir - p $ { mavenRepoDir }
cp - a $ { mavenLocalRepo } /. $ { mavenRepoDir }
mkdir - p $ { reactNativeMavenPackageDir }
chmod u + w $ { reactNativeMavenPackageDir } /
cp - a $ { react-native-deps } /deps $ { reactNativeDepsDir }
for d in ` find $ { reactNativeDepsDir } - mindepth 1 - maxdepth 1 - type d ` ; do
chmod - R u + w $ d
done
# Copy node_modules from Nix store
rm - rf $ { projectDir } /node_modules
mkdir - p $ { projectDir } /node_modules
cp - a $ { projectNodePackage } /node_modules/. $ { projectDir } /node_modules /
# Adjust permissions
chmod - R u + w $ { projectDir }
cp - R $ { projectDir } /status-modules / $ { projectDir } /node_modules/status-modules /
cp - R $ { projectDir } /translations / $ { projectDir } /node_modules/status-modules/translations /
# Set up symlinks to mobile enviroment in project root
$ { createMobileFilesSymlinks projectDir }
# Create a dummy VERSION, since we don't want this expression to be invalidated just because the version changed
echo ' 0 .0 . 1 ' > $ { projectDir } /VERSION
runHook postUnpack
'' ;
patchPhase = ''
runHook prePatch
prevSet = $ -
set - e
patchShebangs $ { projectDir }
function patchMavenSource ( ) {
set + e
local targetGradleFile = " $ 1 "
local source = " $ 2 "
local deriv = " $ 3 "
grep " $ s o u r c e " $ targetGradleFile > /dev/null && \
substituteInPlace $ targetGradleFile - - replace " $ s o u r c e " " $ d e r i v "
}
function patchMavenSources ( ) {
set + e
local targetGradleFile = " $ 1 "
local deriv = " $ 2 "
patchMavenSource $ targetGradleFile ' mavenCentral ( ) ' ' mavenLocal ( ) '
patchMavenSource $ targetGradleFile ' google ( ) ' ' mavenLocal ( ) '
patchMavenSource $ targetGradleFile ' jcenter ( ) ' ' mavenLocal ( ) '
grep ' https://maven.google.com' $ targetGradleFile > /dev/null && \
substituteInPlace $ targetGradleFile - - replace ' https://maven.google.com' " $ d e r i v "
grep ' https://jitpack.io' $ targetGradleFile > /dev/null && \
substituteInPlace $ targetGradleFile - - replace ' https://jitpack.io' " $ d e r i v "
}
# Patch maven and google central repositories with our own local directories. This prevents the builder from downloading Maven artifacts
patchMavenSources ' android/build.gradle ' ' $ { mavenLocalRepo } '
for f in ` find $ { projectDir } /node_modules / - name build . gradle ` ; do
patchMavenSources $ f ' $ { mavenLocalRepo } '
done
# Patch prepareJSC so that it doesn't try to download from registry
substituteInPlace $ { projectDir } /node_modules/react-native/ReactAndroid/build.gradle \
- - replace ' prepareJSC ( dependsOn : downloadJSC ) ' ' prepareJSC ( dependsOn : createNativeDepsDirectories ) ' \
- - replace ' def jscTar = tarTree ( downloadJSC . dest ) ' " d e f j s c T a r = t a r T r e e ( n e w F i l e ( \" ${ react-native-deps } / d e p s / ${ jsc-filename } . t a r . g z \" ) ) "
# Do not add a BuildId to the generated libraries, for reproducibility
substituteInPlace $ { projectDir } /node_modules/react-native/ReactAndroid/src/main/jni/Application.mk \
- - replace ' - Wl , - - build-id' ' - Wl , - - build-id = none'
# Disable Gradle daemon and caching, since that causes rebuilds (and subsequently errors) anyway due to cache being considered stale
substituteInPlace $ { projectDir } /android/gradle.properties \
- - replace ' org . gradle . jvmargs = - Xmx8704M' ' org . gradle . jvmargs = - Xmx8704M
org . gradle . daemon = false
org . gradle . caching = false'
# Patch the path to nodejs in project.ext.react
substituteInPlace $ { projectDir } /android/app/build.gradle \
- - replace ' nodeExecutableAndArgs : [ " n o d e " ' ' nodeExecutableAndArgs : [ " ${ nodejs } / b i n / n o d e " '
set $ prevSet
runHook postPatch
'' ;
buildPhase =
androidEnvShellHook +
status-go . shellHook + ''
export HOME = $ NIX_BUILD_TOP
export REACT_NATIVE_DEPENDENCIES = " ${ reactNativeDepsDir } "
export STATUS_REACT_HOME = " ${ projectDir } "
pushd $ { projectDir } /android
# NOTE: This generates the react-native-android binaries under node_modules/react-native/android
LD_LIBRARY_PATH = $ LD_LIBRARY_PATH : $ { lib . makeLibraryPath [ zlib ] } \
gradle - Dmaven . repo . local = $ { mavenRepoDir } - - offline - S react-native-android:installArchives || exit
popd > /dev/null
'' ;
doCheck = true ;
checkPhase = ''
runHook preCheck
test - d $ { projectDir } /node_modules/react-native/ReactAndroid/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/facebook || \
exit 1
test - d $ { projectDir } /node_modules/react-native/ReactAndroid/build/react-ndk/exported || \
exit 2
runHook postCheck
'' ;
installPhase = ''
rm - rf $ out
mkdir - p $ out/project $ out/.m2/repository
# TODO: maybe node_modules/react-native/ReactAndroid/build/{tmp,generated} can be discarded?
cp - R $ { mavenRepoDir } $ out/.m2 /
cp - R $ { projectDir } /android / $ { projectDir } /node_modules / $ out/project
'' ;
fixupPhase = ''
# Patch prepareJSC so that it doesn't subsequently try to build NDK libs
substituteInPlace $ out/project/node_modules/react-native/ReactAndroid/build.gradle \
- - replace ' packageReactNdkLibs ( dependsOn : buildReactNdkLib , ' ' packageReactNdkLibs ( '
'' ;
# The ELF types are incompatible with the host platform, so let's not even try
# TODO: Use Android NDK to strip binaries manually
dontPatchELF = true ;
dontStripHost = true ;
# Take whole sources into consideration when calculating sha
outputHashMode = " r e c u r s i v e " ;
outputHashAlgo = " s h a 2 5 6 " ;
} ;
in {
deriv = deps ;
shellHook = ''
$ { createMobileFilesSymlinks " $ S T A T U S _ R E A C T _ H O M E " }
export STATUSREACT_NIX_MAVEN_REPO = " ${ deps } / . m 2 / r e p o s i t o r y "
'' ;
}