status-mobile/nix/scripts/node_modules.sh

143 lines
4.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
#
# Check if we need to copy node_modules.
# (e.g. in case it has been modified after last copy)
#
# The reasoning for a (mostly) read-only node_modules folder:
# ideally wed symlink the folder directly to the Nix store
# so that were guaranteed to have a reproducible source.
# Unfortunately react-native wants to build some stuff after the fact
# and this is incompatible with the concept of a pure Nix package.
# Therefore we copy the whole source to the repo directory,
# allow writing only on the folders where it is absolutely required,
# and therefore we still keep some peace of mind that the rest
# of node_modules is unchanged the rest of the time.
#
set -Eeuo pipefail
GIT_ROOT=$(cd "${BASH_SOURCE%/*}" && git rev-parse --show-toplevel)
source "${GIT_ROOT}/scripts/colors.sh"
# More concise output from 'time'
export TIMEFORMAT="Done in: %Es"
removeDir() {
[[ ! -d "${tmp}" ]] && return
chmod -R u+w "${tmp}"
rm -rf "${tmp}"
}
copyNodeModules() {
local src="${1}"
local dst="${2}"
# WARNING: The ../ is there to avoid a Nix builtins.path bug:
# https://github.com/NixOS/nix/issues/3593
local tmp=$(mktemp -d -p "$(dirname "${dst}")/../")
# We use a temporary directory to use mv as "atomic" change
trap "removeDir ${tmp}" ERR INT HUP
# WARNING: The -L here is crucial to let Metro find modules.
cp -LRf ${src}/node_modules/. "${tmp}"
chmod -R +w "${tmp}"
# WARNING: We can't de-reference .bin symlinks
cp -Rf ${src}/node_modules/.bin/. "${tmp}/.bin/"
# Cmake called by react-native-reanimated 3.3.0 during build creates read-only temporary files.
chmod -R u+w node_modules/react-native-reanimated/android/ -f || true
rm -r "${dst}"
mv -f "${tmp}" "${dst}"
}
# Find files that were modified and should cause a re-copying of node modules.
# Some files are generated/modified by build processes and should be ignored.
findFilesNewerThan() {
local sentinel="${1}"
local dir="${2}"
find "${dir}" -type f -writable \
-newer "${sentinel}" \
-not -ipath "*/*android/build/*" -prune \
-not -ipath "*/xcuserdata/*" -prune \
-not -ipath "*/scripts/.packager.env" \
\ # generated at runtime by react-native \
\ # related code https://github.com/facebook/react-native/blob/v0.72.5/packages/react-native/ReactCommon/React-rncore.podspec#L19 \
-not -path "*/node_modules/react-native/ReactCommon/react/renderer/components/rncore/*" \
\ # generated at runtime by react-native-config \
\ # related code https://github.com/lugg/react-native-config/blob/v1.5.0/react-native-config.podspec#L52 \
-not -path "*/node_modules/react-native-config/ios/ReactNativeConfig/GeneratedDotEnv.m" \
\ # generated at runtime by react-native from v0.73.x onwards \
-not -path "*/node_modules/react-native/React/Fabric/RCTThirdPartyFabricComponentsProvider.mm" \
-print
}
nodeModulesUnchanged() {
local src="$1"
local dst="$2"
local sentinelFile="${dst}/.copied~"
# Check if node_modules exists and is valid
if [[ ! -f "${sentinelFile}" ]]; then
# node_modules have not been created by this script
echo -e "${YLW}Node modules not created by Nix${RST}" >&2
return 1
fi
# Sentinel file holds location of the node_modules source in Nix store
currentNixSrc="$(cat "${sentinelFile}")"
if [ "${currentNixSrc}" != "${src}" ]; then
echo -e "${YLW}Yarn modules changed, copying new version over${RST}" >&2
return 1
fi
# Some build processes modify files in node_modules
modifiedFiles=($(findFilesNewerThan "${sentinelFile}" "${dst}"))
if [ ${#modifiedFiles[@]} -ne 0 ]; then
echo -e "${YLW}Changes detected in node_modules:${RST} ${#modifiedFiles[@]}" >&2
# Print files that have changes
for file in ${modifiedFiles[@]}; do
echo "- $(realpath --relative-to="${dst}" "${file}")" >&2
done
return 1
fi
echo -e "${GRN}No changes detected.${RST}" >&2
return 0
}
replaceNodeModules() {
local src="$1"
local dst="$2"
local sentinelFile="${dst}/.copied~"
if nodeModulesUnchanged "${src}" "${dst}"; then
return
fi
# Replace node_modules if necessary
echo "Copying node_modules from Nix store:" >&2
echo " - ${src}" >&2
copyNodeModules "${src}" "${dst}"
echo -n "${src}" > "${sentinelFile}"
}
# Destination folder, Nix sets STATUS_MOBILE_HOME
dst="$STATUS_MOBILE_HOME/node_modules"
# Source of Node modules from /nix/store
src="$1"
if [[ ! -d ${src} ]]; then
echo -e "${RED}No such folder:${RST} ${src}" >&2
exit 1
fi
# Make those available in shell spawned by flock
export -f replaceNodeModules nodeModulesUnchanged copyNodeModules findFilesNewerThan removeDir
mkdir -p "${dst}"
# Leverage file lock to create an exclusive lock.
# Otherwise multiple calls to this script would clash.
flock "${dst}/" sh -c "time replaceNodeModules '${src}' '${dst}'"