Commit ce7f4793 authored by Hunter Loftis's avatar Hunter Loftis

bring caching logic to the forefront

parent 97f67177
#!/usr/bin/env bash #!/usr/bin/env bash
# bin/compile <build-dir> <cache-dir> <env-dir>
####### Configure environment ### Configure environment
set -o errexit # always exit on error set -o errexit # always exit on error
set -o errtrace # trap errors in functions as well
set -o pipefail # don't ignore exit codes when piping output set -o pipefail # don't ignore exit codes when piping output
set -o posix # more strict failures in subshells set -o nounset # fail on unset variables
# set -x # enable debugging unset GIT_DIR # Avoid GIT_DIR leak from previous build steps
# Configure directories ### Configure directories
build_dir=$1
cache_dir=$2 BUILD_DIR=${1:-}
env_dir=$3 CACHE_DIR=${2:-}
bp_dir=$(cd $(dirname $0); cd ..; pwd) ENV_DIR=${3:-}
heroku_dir=$build_dir/.heroku BP_DIR=$(cd $(dirname ${0:-}); cd ..; pwd)
mkdir -p $heroku_dir/node
warnings=$(mktemp) mkdir -p "$BUILD_DIR/.heroku/node/"
cd $BUILD_DIR
# Load dependencies export PATH="$BUILD_DIR/.heroku/node/bin":$PATH
source $bp_dir/lib/common.sh
source $bp_dir/lib/build.sh ### Load dependencies
source $bp_dir/lib/warnings.sh
source $BP_DIR/lib/output.sh
# Avoid GIT_DIR leak from previous build steps source $BP_DIR/lib/json.sh
unset GIT_DIR source $BP_DIR/lib/failure.sh
source $BP_DIR/lib/environment.sh
# Provide hook to deal with errors source $BP_DIR/lib/binaries.sh
trap build_failed ERR source $BP_DIR/lib/cache.sh
source $BP_DIR/lib/dependencies.sh
####### Determine current state
### Handle errors
head "Reading application state"
read_current_state handle_failure() {
show_current_state header "Build failed"
failure_message | indent
if [ "$iojs_engine" == "" ]; then }
warn_node_engine "$node_engine" trap 'handle_failure' ERR
else
warn_node_engine "$iojs_engine" ### Check initial state
fi
warn_node_modules "$modules_source" [ -e "$BUILD_DIR/node_modules" ] && PREBUILD=true || PREBUILD=false
####### Vendor in binaries ### Failures that should be caught immediately
head "Installing binaries" fail_invalid_package_json "$BUILD_DIR"
if [ "$iojs_engine" == "" ]; then warn_prebuilt_modules "$BUILD_DIR"
install_node "$node_engine" warn_missing_package_json "$BUILD_DIR"
else
install_iojs "$iojs_engine" ### Compile
fi
install_npm create_env() {
write_profile "$BP_DIR" "$BUILD_DIR"
####### Build the project's dependencies write_export "$BP_DIR" "$BUILD_DIR"
export_env_dir "$ENV_DIR"
head "Building dependencies" create_default_env
cd $build_dir }
build_dependencies
header "Creating runtime environment"
####### Create a Procfile if possible create_env # can't indent the whole thing because piping causes subshells; no exporting possible
list_node_config | indent
head "Checking startup method"
ensure_procfile "$start_method" "$build_dir" install_bins() {
warn_start "$start_method" local node_engine=$(read_json "$BUILD_DIR/package.json" ".engines.node")
local iojs_engine=$(read_json "$BUILD_DIR/package.json" ".engines.iojs")
####### Finalize the build local npm_engine=$(read_json "$BUILD_DIR/package.json" ".engines.npm")
head "Finalizing build" if [ -n "$iojs_engine" ]; then
write_profile echo "engines.iojs (package.json): $iojs_engine (iojs)"
write_export else
clean_npm echo "engines.node (package.json): ${node_engine:-unspecified}"
clean_cache fi
create_cache echo "engines.npm (package.json): ${npm_engine:-unspecified (use default)}"
build_succeeded echo ""
if [ -n "$iojs_engine" ]; then
warn_node_engine "$iojs_engine"
install_iojs "$iojs_engine" "$BUILD_DIR/.heroku/node"
else
warn_node_engine "$node_engine"
install_nodejs "$node_engine" "$BUILD_DIR/.heroku/node"
fi
install_npm "$npm_engine" "$BUILD_DIR/.heroku/node"
warn_old_npm
}
header "Installing binaries"
install_bins | indent
restore_cache() {
local cache_status=$(get_cache_status)
if [ "$cache_status" == "disabled" ]; then
echo "Skipping (cache disabled)"
elif [ "$cache_status" == "invalidated" ]; then
echo "Skipping (cache invalidated)"
else
local cache_directories=$(get_cache_directories)
if [ "$cache_directories" == "" ]; then
echo "Loading 1 from cacheDirectories (default):"
restore_cache_directories "$BUILD_DIR" "$CACHE_DIR" "node_modules"
else
echo "Loading $(echo $cache_directories | wc -w | xargs) from cacheDirectories (package.json):"
restore_cache_directories "$BUILD_DIR" "$CACHE_DIR" $cache_directories
fi
fi
}
header "Restoring cache"
restore_cache | indent
build_dependencies() {
if $PREBUILD; then
echo "Prebuild detected (node_modules already exists)"
rebuild_node_modules "$BUILD_DIR"
else
install_node_modules "$BUILD_DIR"
fi
}
header "Building dependencies"
build_dependencies | indent
cache_build() {
local cache_directories=$(get_cache_directories)
echo "Clearing previous node cache"
clear_cache
if [ "$cache_directories" == "" ]; then
echo "Saving 1 cacheDirectories (default):"
save_cache_directories "$BUILD_DIR" "$CACHE_DIR" "node_modules"
else
echo "Saving $(echo $cache_directories | wc -w | xargs) cacheDirectories (package.json):"
save_cache_directories "$BUILD_DIR" "$CACHE_DIR" $cache_directories
fi
}
header "Caching build"
cache_build | indent
summarize_build() {
cd $BUILD_DIR
(npm ls --depth=0 | tail -n +2 || true) 2>/dev/null
}
header "Build succeeded!"
summarize_build | indent
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
# bin/detect <build-dir> # bin/detect <build-dir>
if [ -f $1/package.json ]; then if [ -f $1/package.json ]; then
echo "Node.js" && exit 0 echo "Node.js"
elif [ -f $1/server.js ]; then exit 0
echo "Node.js" && exit 0
else
echo "no" && exit 1
fi fi
exit 1
#!/usr/bin/env bash #!/usr/bin/env bash
# bin/release <build-dir> # bin/release <build-dir>
cat << EOF cat << EOF
addons: [] addons: []
default_process_types: {} default_process_types:
web: npm start
EOF EOF
needs_resolution() {
local semver=$1
if ! [[ "$semver" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
return 0
else
return 1
fi
}
install_nodejs() {
local version="$1"
local dir="$2"
if needs_resolution "$version"; then
echo "Resolving node version ${version:-(latest stable)} via semver.io..."
local version=$(curl --silent --get --data-urlencode "range=${version}" https://semver.herokuapp.com/node/resolve)
fi
echo "Downloading and installing node $version..."
local download_url="http://s3pository.heroku.com/node/v$version/node-v$version-$os-$cpu.tar.gz"
curl "$download_url" -s -o - | tar xzf - -C /tmp
mv /tmp/node-v$version-$os-$cpu/* $dir
chmod +x $dir/bin/*
}
install_iojs() {
local version="$1"
local dir="$2"
if needs_resolution "$version"; then
echo "Resolving iojs version ${version:-(latest stable)} via semver.io..."
version=$(curl --silent --get --data-urlencode "range=${version}" https://semver.herokuapp.com/iojs/resolve)
fi
echo "Downloading and installing iojs $version..."
local download_url="https://iojs.org/dist/v$version/iojs-v$version-$os-$cpu.tar.gz"
curl $download_url -s -o - | tar xzf - -C /tmp
mv /tmp/iojs-v$version-$os-$cpu/* $dir
chmod +x $dir/bin/*
}
install_npm() {
local version="$1"
if [ "$version" == "" ]; then
echo "Using default npm version: `npm --version`"
else
if needs_resolution "$version"; then
echo "Resolving npm version ${version} via semver.io..."
version=$(curl --silent --get --data-urlencode "range=${version}" https://semver.herokuapp.com/npm/resolve)
fi
if [[ `npm --version` == "$version" ]]; then
echo "npm `npm --version` already installed with node"
else
echo "Downloading and installing npm $version (replacing version `npm --version`)..."
npm install --unsafe-perm --quiet -g npm@$version 2>&1 >/dev/null
fi
fi
}
build_failed() {
local warn=$(cat $warnings)
head "Build failed"
echo ""
info "We're sorry this build is failing!"
info ""
info "Are you running into a common issue?"
info "https://devcenter.heroku.com/articles/troubleshooting-node-deploys"
info ""
if [ "$warn" != "" ]; then
info "During the build we spotted some likely problems:"
info ""
echo "$warn" | indent
else
info "If you're stuck, please submit a ticket so we can help:"
info "https://help.heroku.com/"
fi
info ""
info "Love,"
info "Heroku"
}
build_succeeded() {
head "Build succeeded!"
echo ""
(npm ls --depth=0 || true) 2>/dev/null | indent
}
get_start_method() {
local build_dir=$1
if test -f $build_dir/Procfile; then
echo "Procfile"
elif [[ $(read_json "$build_dir/package.json" ".scripts.start") != "" ]]; then
echo "npm start"
elif test -f $build_dir/server.js; then
echo "server.js"
else
echo ""
fi
}
get_modules_source() {
local build_dir=$1
if test -d $build_dir/node_modules; then
echo "prebuilt"
elif test -f $build_dir/npm-shrinkwrap.json; then
echo "npm-shrinkwrap.json"
elif test -f $build_dir/package.json; then
echo "package.json"
else
echo ""
fi
}
get_modules_cached() {
local cache_dir=$1
if test -d $cache_dir/node/node_modules; then
echo "true"
else
echo "false"
fi
}
# Sets:
# iojs_engine
# node_engine
# npm_engine
# start_method
# modules_source
# npm_previous
# node_previous
# modules_cached
# environment variables (from ENV_DIR)
read_current_state() {
info "package.json..."
assert_json "$build_dir/package.json"
iojs_engine=$(read_json "$build_dir/package.json" ".engines.iojs")
node_engine=$(read_json "$build_dir/package.json" ".engines.node")
npm_engine=$(read_json "$build_dir/package.json" ".engines.npm")
info "build directory..."
start_method=$(get_start_method "$build_dir")
modules_source=$(get_modules_source "$build_dir")
info "cache directory..."
npm_previous=$(file_contents "$cache_dir/node/npm-version")
node_previous=$(file_contents "$cache_dir/node/node-version")
modules_cached=$(get_modules_cached "$cache_dir")
info "environment variables..."
export_env_dir $env_dir
export NPM_CONFIG_PRODUCTION=${NPM_CONFIG_PRODUCTION:-true}
export NODE_MODULES_CACHE=${NODE_MODULES_CACHE:-true}
}
show_current_state() {
echo ""
if [ "$iojs_engine" == "" ]; then
info "Node engine: ${node_engine:-unspecified}"
else
achievement "iojs"
info "Node engine: $iojs_engine (iojs)"
fi
info "Npm engine: ${npm_engine:-unspecified}"
info "Start mechanism: ${start_method:-none}"
info "node_modules source: ${modules_source:-none}"
info "node_modules cached: $modules_cached"
echo ""
printenv | grep ^NPM_CONFIG_ | indent
info "NODE_MODULES_CACHE=$NODE_MODULES_CACHE"
}
install_node() {
local node_engine=$1
# Resolve non-specific node versions using semver.herokuapp.com
if ! [[ "$node_engine" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
info "Resolving node version ${node_engine:-(latest stable)} via semver.io..."
node_engine=$(curl --silent --get --data-urlencode "range=${node_engine}" https://semver.herokuapp.com/node/resolve)
fi
# Download node from Heroku's S3 mirror of nodejs.org/dist
info "Downloading and installing node $node_engine..."
node_url="http://s3pository.heroku.com/node/v$node_engine/node-v$node_engine-linux-x64.tar.gz"
curl $node_url -s -o - | tar xzf - -C /tmp
# Move node (and npm) into .heroku/node and make them executable
mv /tmp/node-v$node_engine-linux-x64/* $heroku_dir/node
chmod +x $heroku_dir/node/bin/*
PATH=$heroku_dir/node/bin:$PATH
}
install_iojs() {
local iojs_engine=$1
# Resolve non-specific iojs versions using semver.herokuapp.com
if ! [[ "$iojs_engine" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
info "Resolving iojs version ${iojs_engine:-(latest stable)} via semver.io..."
iojs_engine=$(curl --silent --get --data-urlencode "range=${iojs_engine}" https://semver.herokuapp.com/iojs/resolve)
fi
# TODO: point at /dist once that's available
info "Downloading and installing iojs $iojs_engine..."
download_url="https://iojs.org/dist/v$iojs_engine/iojs-v$iojs_engine-linux-x64.tar.gz"
curl $download_url -s -o - | tar xzf - -C /tmp
# Move iojs/node (and npm) binaries into .heroku/node and make them executable
mv /tmp/iojs-v$iojs_engine-linux-x64/* $heroku_dir/node
chmod +x $heroku_dir/node/bin/*
PATH=$heroku_dir/node/bin:$PATH
}
install_npm() {
# Optionally bootstrap a different npm version
if [ "$npm_engine" != "" ]; then
if ! [[ "$npm_engine" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
info "Resolving npm version ${npm_engine} via semver.io..."
npm_engine=$(curl --silent --get --data-urlencode "range=${npm_engine}" https://semver.herokuapp.com/npm/resolve)
fi
if [[ `npm --version` == "$npm_engine" ]]; then
info "npm `npm --version` already installed with node"
else
info "Downloading and installing npm $npm_engine (replacing version `npm --version`)..."
npm install --unsafe-perm --quiet -g npm@$npm_engine 2>&1 >/dev/null | indent
fi
warn_old_npm `npm --version`
else
info "Using default npm version: `npm --version`"
fi
}
function build_dependencies() {
if [ "$modules_source" == "" ]; then
info "Skipping dependencies (no source for node_modules)"
elif [ "$modules_source" == "prebuilt" ]; then
info "Rebuilding any native modules for this architecture"
npm rebuild 2>&1 | indent
info "Installing any new modules"
npm install --unsafe-perm --quiet --userconfig $build_dir/.npmrc 2>&1 | indent
else
restore_cache
info "Installing node modules"
npm install --unsafe-perm --quiet --userconfig $build_dir/.npmrc 2>&1 | indent
fi
}
ensure_procfile() {
local start_method=$1
local build_dir=$2
if [ "$start_method" == "Procfile" ]; then
info "Found Procfile"
elif test -f $build_dir/Procfile; then
info "Procfile created during build"
elif [ "$start_method" == "npm start" ]; then
info "No Procfile; Adding 'web: npm start' to new Procfile"
echo "web: npm start" > $build_dir/Procfile
elif [ "$start_method" == "server.js" ]; then
info "No Procfile; Adding 'web: node server.js' to new Procfile"
echo "web: node server.js" > $build_dir/Procfile
else
info "None found"
fi
}
write_profile() {
info "Creating runtime environment"
mkdir -p $build_dir/.profile.d
echo "export PATH=\"\$HOME/.heroku/node/bin:\$HOME/bin:\$HOME/node_modules/.bin:\$PATH\"" > $build_dir/.profile.d/nodejs.sh
echo "export NODE_HOME=\"\$HOME/.heroku/node\"" >> $build_dir/.profile.d/nodejs.sh
cat $bp_dir/lib/concurrency.sh >> $build_dir/.profile.d/nodejs.sh
}
write_export() {
info "Exporting binary paths"
echo "export PATH=\"$build_dir/.heroku/node/bin:$build_dir/node_modules/.bin:\$PATH\"" > $bp_dir/export
echo "export NODE_HOME=\"$build_dir/.heroku/node\"" >> $bp_dir/export
}
clean_npm() {
info "Cleaning npm artifacts"
rm -rf "$build_dir/.node-gyp"
rm -rf "$build_dir/.npm"
}
# Caching
create_cache() {
info "Caching results for future builds"
mkdir -p $cache_dir/node
echo `node --version` > $cache_dir/node/node-version
echo `npm --version` > $cache_dir/node/npm-version
if test -d $build_dir/node_modules; then
cp -r $build_dir/node_modules $cache_dir/node
fi
write_user_cache
}
clean_cache() {
info "Cleaning previous cache"
rm -rf "$cache_dir/node_modules" # (for apps still on the older caching strategy)
rm -rf "$cache_dir/node"
}
get_cache_status() {
local node_version=`node --version`
local npm_version=`npm --version`
# Did we bust the cache?
if ! $modules_cached; then
echo "No cache available"
elif ! $NODE_MODULES_CACHE; then
echo "Cache disabled with NODE_MODULES_CACHE"
elif [ "$node_previous" != "" ] && [ "$node_version" != "$node_previous" ]; then
echo "Node version changed ($node_previous => $node_version); invalidating cache"
elif [ "$npm_previous" != "" ] && [ "$npm_version" != "$npm_previous" ]; then
echo "Npm version changed ($npm_previous => $npm_version); invalidating cache"
else
echo "valid"
fi
}
restore_cache() {
local directories=($(cache_directories))
local cache_status=$(get_cache_status)
if [ "$directories" != -1 ]; then
info "Restoring ${#directories[@]} directories from cache:"
for directory in "${directories[@]}"
do
local source_dir="$cache_dir/node/$directory"
if [ -e $source_dir ]; then
if [ "$directory" == "node_modules" ]; then
restore_npm_cache
else
info "- $directory"
cp -r $source_dir $build_dir/
fi
fi
done
elif [ "$cache_status" == "valid" ]; then
restore_npm_cache
info "$cache_status"
else
touch $build_dir/.npmrc
fi
}
restore_npm_cache() {
info "Restoring node modules from cache"
cp -r $cache_dir/node/node_modules $build_dir/
info "Pruning unused dependencies"
npm --unsafe-perm prune 2>&1 | indent
}
cache_directories() {
local package_json="$build_dir/package.json"
local key=".cache_directories"
local check=$(key_exist $package_json $key)
local result=-1
if [ "$check" != -1 ]; then
result=$(read_json "$package_json" "$key[]")
fi
local key=".cacheDirectories"
local check=$(key_exist $package_json $key)
if [ "$check" != -1 ]; then
result=$(read_json "$package_json" "$key[]")
fi
echo $result
}
key_exist() {
local file=$1
local key=$2
local output=$(read_json $file $key)
if [ -n "$output" ]; then
echo 1
else
echo -1
fi
}
write_user_cache() {
local directories=($(cache_directories))
if [ "$directories" != -1 ]; then
info "Storing directories:"
for directory in "${directories[@]}"
do
info "- $directory"
cp -r $build_dir/$directory $cache_dir/node/
done
fi
}
source $BP_DIR/lib/binaries.sh
create_signature() {
echo "$(node --version); $(npm --version)"
}
save_signature() {
echo "$(get_signature)" > $CACHE_DIR/node/signature
}
load_signature() {
if test -f $CACHE_DIR/node/signature; then
cat $CACHE_DIR/node/signature
else
echo ""
fi
}
signature_changed() {
if ! [ "$(create_signature)" == "$(load_signature)" ]; then
return 1
else
return 0
fi
}
get_cache_status() {
if ! ${NODE_MODULES_CACHE:-true}; then
echo "disabled"
elif signature_changed; then
echo "invalidated"
else
echo "valid"
fi
}
get_cache_directories() {
local dirs1=$(read_json "$BUILD_DIR/package.json" ".cacheDirectories | .[]?")
local dirs2=$(read_json "$BUILD_DIR/package.json" ".cache_directories | .[]?")
if [ -n "$dirs1" ]; then
echo "$dirs1"
else
echo "$dirs2"
fi
}
restore_cache_directories() {
local build_dir=${1:-}
local cache_dir=${2:-}
for cachepath in ${@:3}; do
if [ -e "$build_dir/$cachepath" ]; then
echo "- $cachepath (exists - skipping)"
else
if [ -e "$cache_dir/node/$cachepath" ]; then
echo "- $cachepath"
mkdir -p "$build_dir/$cachepath"
cp -a "$cache_dir/node/$cachepath" $(dirname "$build_dir/$cachepath")
else
echo "- $cachepath (not cached - skipping)"
fi
fi
done
}
clear_cache() {
rm -rf $CACHE_DIR/node
}
save_cache_directories() {
local build_dir=${1:-}
local cache_dir=${2:-}
mkdir -p $cache_dir/node
for cachepath in ${@:3}; do
if [ -e "$build_dir/$cachepath" ]; then
echo "- $cachepath"
mkdir -p "$cache_dir/node/$cachepath"
cp -a "$build_dir/$cachepath" $(dirname "$cache_dir/node/$cachepath")
else
echo "- $cachepath (nothing to cache)"
fi
done
}
error() {
echo " ! $*" >&2
echo ""
return 1
}
head() {
echo ""
echo "-----> $*"
}
info() {
#echo "`date +\"%M:%S\"` $*"
echo " $*"
}
warning() {
local tip=$1
local url=$2
echo "- $tip" >> $warnings
echo " ${url:-https://devcenter.heroku.com/articles/nodejs-support}" >> $warnings
echo "" >> $warnings
}
achievement() {
local msg=$1
echo " ACHIEVEMENT UNLOCKED: $msg :)"
echo ""
}
assert_json() {
local file=$1
if test -f $file; then
if ! cat $file | $bp_dir/vendor/jq '.' > /dev/null; then
error "Unable to parse $file as JSON"
fi
fi
}
file_contents() {
if test -f $1; then
echo "$(cat $1)"
else
echo ""
fi
}
read_json() {
local file=$1
local node=$2
if test -f $file; then
cat $file | $bp_dir/vendor/jq --raw-output "$node // \"\"" || return 1
else
echo ""
fi
}
# sed -l basically makes sed replace and buffer through stdin to stdout
# so you get updates while the command runs and dont wait for the end
# e.g. npm install | indent
indent() {
c='s/^/ /'
case $(uname) in
Darwin) sed -l "$c";; # mac/bsd sed: -l buffers on line boundaries
*) sed -u "$c";; # unix/gnu sed: -u unbuffered (arbitrary) chunks of data
esac
}
cat_npm_debug_log() {
test -f $build_dir/npm-debug.log && cat $build_dir/npm-debug.log
}
export_env_dir() {
env_dir=$1
if [ -d "$env_dir" ]; then
whitelist_regex=${2:-''}
blacklist_regex=${3:-'^(PATH|GIT_DIR|CPATH|CPPATH|LD_PRELOAD|LIBRARY_PATH)$'}
if [ -d "$env_dir" ]; then
for e in $(ls $env_dir); do
echo "$e" | grep -E "$whitelist_regex" | grep -qvE "$blacklist_regex" &&
export "$e=$(cat $env_dir/$e)"
:
done
fi
fi
}
install_node_modules() {
local build_dir=${1:-}
if [ -e $build_dir/package.json ]; then
cd $build_dir
echo "Pruning any extraneous modules"
npm prune --unsafe-perm --userconfig $build_dir/.npmrc 2>&1
if [ -e $build_dir/npm-shrinkwrap.json ]; then
echo "Installing node modules (package.json + shrinkwrap)"
else
echo "Installing node modules (package.json)"
fi
npm install --unsafe-perm --userconfig $build_dir/.npmrc 2>&1
else
echo "Skipping (no package.json)"
fi
}
rebuild_node_modules() {
local build_dir=${1:-}
if [ -e $build_dir/package.json ]; then
cd $build_dir
echo "Pruning any extraneous modules"
npm prune --unsafe-perm --userconfig $build_dir/.npmrc 2>&1
echo "Rebuilding any native modules"
npm rebuild 2>&1
if [ -e $build_dir/npm-shrinkwrap.json ]; then
echo "Installing any new modules (package.json + shrinkwrap)"
else
echo "Installing any new modules (package.json)"
fi
npm install --unsafe-perm --userconfig $build_dir/.npmrc 2>&1
else
echo "Skipping (no package.json)"
fi
}
create_default_env() {
export NPM_CONFIG_PRODUCTION=${NPM_CONFIG_PRODUCTION:-true}
export NPM_CONFIG_LOGLEVEL=${NPM_CONFIG_LOGLEVEL:-error}
export NODE_MODULES_CACHE=${NODE_MODULES_CACHE:-true}
}
list_node_config() {
echo ""
printenv | grep ^NPM_CONFIG_ || true
printenv | grep ^NODE_ || true
}
export_env_dir() {
local env_dir=$1
if [ -d "$env_dir" ]; then
local whitelist_regex=${2:-''}
local blacklist_regex=${3:-'^(PATH|GIT_DIR|CPATH|CPPATH|LD_PRELOAD|LIBRARY_PATH)$'}
if [ -d "$env_dir" ]; then
for e in $(ls $env_dir); do
echo "$e" | grep -E "$whitelist_regex" | grep -qvE "$blacklist_regex" &&
export "$e=$(cat $env_dir/$e)"
:
done
fi
fi
}
write_profile() {
local bp_dir="$1"
local build_dir="$2"
mkdir -p $build_dir/.profile.d
cp $bp_dir/profile/* $build_dir/.profile.d/
}
write_export() {
local bp_dir="$1"
local build_dir="$2"
echo "export PATH=\"$build_dir/.heroku/node/bin:$build_dir/node_modules/.bin:\$PATH\"" > $bp_dir/export
echo "export NODE_HOME=\"$build_dir/.heroku/node\"" >> $bp_dir/export
}
warnings=$(mktemp -t heroku-buildpack-nodejs-XXXX)
failure_message() {
local warn="$(cat $warnings)"
echo ""
echo "We're sorry this build is failing! You can troubleshoot common issues here:"
echo "https://devcenter.heroku.com/articles/troubleshooting-node-deploys"
echo ""
if [ "$warn" != "" ]; then
echo "Some possible problems:"
echo ""
echo "$warn"
else
echo "If you're stuck, please submit a ticket so we can help:"
echo "https://help.heroku.com/"
fi
echo ""
echo "Love,"
echo "Heroku"
echo ""
}
fail_invalid_package_json() {
if ! cat ${1:-}/package.json | $JQ "." 1>/dev/null; then
error "Unable to parse package.json"
return 1
fi
}
warning() {
local tip=${1:-}
local url=${2:-https://devcenter.heroku.com/articles/nodejs-support}
echo "- $tip" >> $warnings
echo " $url" >> $warnings
echo "" >> $warnings
}
warn_node_engine() { warn_node_engine() {
local node_engine=$1 local node_engine=${1:-}
if [ "$node_engine" == "" ]; then if [ "$node_engine" == "" ]; then
warning "Node version not specified in package.json" "https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version" warning "Node version not specified in package.json" "https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version"
elif [ "$node_engine" == "*" ]; then elif [ "$node_engine" == "*" ]; then
...@@ -9,26 +46,24 @@ warn_node_engine() { ...@@ -9,26 +46,24 @@ warn_node_engine() {
fi fi
} }
warn_node_modules() { warn_prebuilt_modules() {
local modules_source=$1 local build_dir=${1:-}
if [ "$modules_source" == "prebuilt" ]; then if [ -e "$build_dir/node_modules" ]; then
warning "node_modules checked into source control" "https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-" warning "node_modules checked into source control" "https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-"
elif [ "$modules_source" == "" ]; then
warning "No package.json found"
fi fi
} }
warn_start() { warn_missing_package_json() {
local start_method=$1 local build_dir=${1:-}
if [ "$start_method" == "" ]; then if ! [ -e "$build_dir/package.json" ]; then
warning "No Procfile, package.json start script, or server.js file found" "https://devcenter.heroku.com/articles/nodejs-support#runtime-behavior" warning "No package.json found"
fi fi
} }
warn_old_npm() { warn_old_npm() {
local npm_version=$1 local npm_version="$(npm --version)"
if [ "${npm_version:0:1}" -lt "2" ]; then if [ "${npm_version:0:1}" -lt "2" ]; then
local latest_npm=$(curl --silent --get https://semver.herokuapp.com/npm/stable) local latest_npm="$(curl --silent --get https://semver.herokuapp.com/npm/stable)"
warning "This version of npm ($npm_version) has several known issues - consider upgrading to the latest release ($latest_npm)" "https://devcenter.heroku.com/articles/nodejs-support#specifying-an-npm-version" warning "This version of npm ($npm_version) has several known issues - consider upgrading to the latest release ($latest_npm)" "https://devcenter.heroku.com/articles/nodejs-support#specifying-an-npm-version"
fi fi
} }
get_os() {
uname | tr A-Z a-z
}
get_cpu() {
if [[ "$(uname -p)" = "i686" ]]; then
echo "x86"
else
echo "x64"
fi
}
os=$(get_os)
cpu=$(get_cpu)
export JQ="$BP_DIR/vendor/jq-$os"
read_json() {
local file=$1
local key=$2
if test -f $file; then
cat $file | $JQ --raw-output "$key // \"\"" || return 1
else
echo ""
fi
}
info() {
echo " $*"
}
# sed -l basically makes sed replace and buffer through stdin to stdout
# so you get updates while the command runs and dont wait for the end
# e.g. npm install | indent
indent() {
c='s/^/ /'
case $(uname) in
Darwin) sed -l "$c";; # mac/bsd sed: -l buffers on line boundaries
*) sed -u "$c";; # unix/gnu sed: -u unbuffered (arbitrary) chunks of data
esac
}
header() {
echo ""
echo "-----> $*"
}
error() {
echo " ! $*" >&2
echo ""
}
...@@ -8,3 +8,8 @@ test-cedar-14: ...@@ -8,3 +8,8 @@ test-cedar-14:
test-cedar-10: test-cedar-10:
@echo "Running tests in docker (cedar)..." @echo "Running tests in docker (cedar)..."
@docker run -v $(shell pwd):/buildpack:ro --rm -it fabiokung/cedar bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;' @docker run -v $(shell pwd):/buildpack:ro --rm -it fabiokung/cedar bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
shell:
@echo "Opening cedar-14 shell..."
@docker run -v $(shell pwd):/buildpack:ro --rm -it heroku/cedar:14 bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; bash'
@echo ""
...@@ -27,6 +27,9 @@ detect_memory() { ...@@ -27,6 +27,9 @@ detect_memory() {
esac esac
} }
export PATH="$HOME/.heroku/node/bin:$HOME/bin:$HOME/node_modules/.bin:$PATH"
export NODE_HOME="$HOME/.heroku/node"
calculate_concurrency calculate_concurrency
log_concurrency log_concurrency
......
{
"name": "client",
"version": "1.0.0",
"description": "",
"main": "index.js",
"repository": {
"type": "git",
"url": "http://github.com/example/example.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"underscore": "^1.8.3"
}
}
...@@ -7,13 +7,11 @@ ...@@ -7,13 +7,11 @@
"url" : "http://github.com/example/example.git" "url" : "http://github.com/example/example.git"
}, },
"engines": { "engines": {
"node": "0.10.18" "node": "0.12.4"
},
"dependencies": {
"bower": "1.3.12"
}, },
"dependencies": {},
"scripts": { "scripts": {
"postinstall": "bower install --allow-root" "postinstall": "npm install --prefix=server && npm install --prefix=client"
}, },
"cacheDirectories": ["bower_components", "node_modules"] "cacheDirectories": ["server/node_modules", "client/node_modules", "non/existent"]
} }
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"repository": {
"type": "git",
"url": "http://github.com/example/example.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"lodash": "^3.9.3"
}
}
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
"type" : "git", "type" : "git",
"url" : "http://github.com/example/example.git" "url" : "http://github.com/example/example.git"
}, },
"dependencies": { "scripts": {
"forcefailure": "*" "postinstall": "exit 1"
}, },
"engines": { "engines": {
"node": "*" "node": "*"
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
"hashish": "*" "hashish": "*"
}, },
"engines": { "engines": {
"node": "0.10.x" "node": "0.10.38"
}, },
"scripts": { "scripts": {
"postinstall": "exit 1" "postinstall": "exit 1"
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
"url" : "http://github.com/example/example.git" "url" : "http://github.com/example/example.git"
}, },
"engines": { "engines": {
"node": "~0.10.20" "node": "0.12.4"
}, },
"dependencies": { "dependencies": {
"some-crazy-dep-that-doesnt-exist": "*" "some-crazy-dep-that-doesnt-exist": "*"
......
...@@ -10,6 +10,6 @@ ...@@ -10,6 +10,6 @@
"lodash": "1.0.0" "lodash": "1.0.0"
}, },
"engines": { "engines": {
"node": "~0.10.0" "node": "0.12.4"
} }
} }
...@@ -10,6 +10,6 @@ ...@@ -10,6 +10,6 @@
"lodash": "^1.0.0" "lodash": "^1.0.0"
}, },
"engines": { "engines": {
"node": "~0.10.0" "node": "0.12.4"
} }
} }
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository" : {
"type" : "git",
"url" : "http://github.com/example/example.git"
},
"dependencies": {
"hashish": "*"
},
"engines": {
"node": "~0.10.0"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository" : {
"type" : "git",
"url" : "http://github.com/example/example.git"
},
"dependencies": {
"hashish": "*"
},
"engines": {
"node": "~0.10.0"
},
"scripts": {
"start": "echo foo"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
{
"name": "node-buildpack-test-app",
"version": "0.0.1",
"description": "node buildpack integration test app",
"repository" : {
"type" : "git",
"url" : "http://github.com/example/example.git"
},
"dependencies": {
"hashish": "*"
},
"engines": {
"node": "~0.10.0"
}
}
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
A fake README, to keep npm from polluting stderr.
\ No newline at end of file
#!/usr/bin/env bash
mktmpdir() {
local dir=$(mktemp -t testXXXXX)
rm -rf $dir
mkdir $dir
echo $dir
}
compile() {
local fixture=$1
local bp_dir=$(mktmpdir)
local build_dir=$(mktmpdir)
local cache_dir=$(mktmpdir)
local env_dir=$(mktmpdir)
echo "Compiling $fixture"
echo "in $build_dir"
echo "(caching in $cache_dir)"
cp -a $(pwd)/* ${bp_dir}
cp -a ${bp_dir}/test/fixtures/$fixture/. ${build_dir}
"$bp_dir/bin/compile" "$build_dir" "$cache_dir"
}
fixture=${1:-'stable-node'}
compile "$fixture"
#!/usr/bin/env bash #!/usr/bin/env bash
# See README.md for info on running these tests. # See README.md for info on running these tests.
testDetectWithPackageJson() { testDisableCache() {
detect "stable-node" cache=$(mktmpdir)
assertCaptured "Node.js" env_dir=$(mktmpdir)
compile "node-modules-cache-1" $cache
assertCaptured "lodash@1.0.0"
assertEquals "1" "$(ls -1 $cache/node/node_modules | grep lodash | wc -l | tr -d ' ')"
assertCapturedSuccess
compile "node-modules-cache-2" $cache
assertCaptured "lodash@1.0.0"
assertCapturedSuccess
echo "false" > $env_dir/NODE_MODULES_CACHE
compile "node-modules-cache-2" $cache $env_dir
assertCaptured "lodash@1.3.1"
assertCapturedSuccess assertCapturedSuccess
} }
testDetectWithServer() { testDetectWithPackageJson() {
detect "server-present-only" detect "stable-node"
assertCaptured "Node.js" assertCaptured "Node.js"
assertCapturedSuccess assertCapturedSuccess
} }
...@@ -22,26 +35,22 @@ testBadJson() { ...@@ -22,26 +35,22 @@ testBadJson() {
compile "bad-json" compile "bad-json"
assertCaptured "Build failed" assertCaptured "Build failed"
assertCaptured "We're sorry this build is failing" assertCaptured "We're sorry this build is failing"
assertNotCaptured "build directory..."
assertNotCaptured "Installing binaries" assertNotCaptured "Installing binaries"
assertCapturedError 1 "Unable to parse" assertCapturedError 1 "Unable to parse"
} }
testIoJs() { testIoJs() {
compile "iojs" compile "iojs"
assertCaptured "Node engine: 1.0." assertCaptured "engines.iojs (package.json): 1.0."
assertCaptured "(iojs)" assertCaptured "Downloading and installing iojs 1.0."
assertCaptured "detected node version: v1.0."
assertCapturedSuccess assertCapturedSuccess
} }
testNoVersion() { testNoVersion() {
compile "no-version" compile "no-version"
assertCaptured "Node engine: unspecified" assertCaptured "engines.node (package.json): unspecified"
assertCaptured "Resolving node version (latest stable) via semver.io" assertCaptured "Resolving node version (latest stable) via semver.io"
assertCaptured "Downloading and installing node 0.12" assertCaptured "Downloading and installing node 0.12."
assertNotCaptured "Node version not specified in package.json"
assertNotCaptured "We're sorry this build is failing"
assertCapturedSuccess assertCapturedSuccess
} }
...@@ -50,13 +59,12 @@ testSpecificVersion() { ...@@ -50,13 +59,12 @@ testSpecificVersion() {
assertNotCaptured "Resolving node version" assertNotCaptured "Resolving node version"
assertCaptured "Downloading and installing node 0.10.29" assertCaptured "Downloading and installing node 0.10.29"
assertCaptured "Using default npm version: 1.4.14" assertCaptured "Using default npm version: 1.4.14"
assertNotCaptured "We're sorry this build is failing"
assertCapturedSuccess assertCapturedSuccess
} }
testStableVersion() { testStableVersion() {
compile "stable-node" compile "stable-node"
assertCaptured "Downloading and installing node 0.10" assertCaptured "Downloading and installing node 0.10."
assertNotCaptured "We're sorry this build is failing" assertNotCaptured "We're sorry this build is failing"
assertCapturedSuccess assertCapturedSuccess
} }
...@@ -64,7 +72,7 @@ testStableVersion() { ...@@ -64,7 +72,7 @@ testStableVersion() {
testUnstableVersion() { testUnstableVersion() {
compile "unstable-version" compile "unstable-version"
assertCaptured "Resolving node version 0.11.x via semver.io" assertCaptured "Resolving node version 0.11.x via semver.io"
assertCaptured "Downloading and installing node 0.11" assertCaptured "Downloading and installing node 0.11."
assertCapturedSuccess assertCapturedSuccess
} }
...@@ -75,6 +83,11 @@ testOldNpm() { ...@@ -75,6 +83,11 @@ testOldNpm() {
assertCapturedError assertCapturedError
} }
testOldNpm2() {
compile "failing-build"
assertCaptured "This version of npm (1.4.28) has several known issues"
}
testNonexistentNpm() { testNonexistentNpm() {
compile "nonexistent-npm" compile "nonexistent-npm"
assertCaptured "version not found: npm@1.1.65" assertCaptured "version not found: npm@1.1.65"
...@@ -124,27 +137,24 @@ testWarningsOnFailure() { ...@@ -124,27 +137,24 @@ testWarningsOnFailure() {
testTicketOnFailure() { testTicketOnFailure() {
compile "invalid-dependency" compile "invalid-dependency"
assertCaptured "troubleshooting-node-deploys" assertCaptured "troubleshooting-node-deploys"
assertNotCaptured "During the build we spotted some likely problems"
assertCaptured "please submit a ticket" assertCaptured "please submit a ticket"
assertNotCaptured "possible problems"
assertCapturedError assertCapturedError
} }
testInfoEmpty() { testInfoEmpty() {
compile "info-empty" compile "info-empty"
assertCaptured "Node engine: unspecified" assertCaptured "engines.node (package.json): unspecified"
assertCaptured "Npm engine: unspecified" assertCaptured "engines.npm (package.json): unspecified"
assertCaptured "Start mechanism: none" assertCaptured "Installing node modules (package.json)"
assertCaptured "node_modules source: package.json"
assertCaptured "node_modules cached: false"
assertCapturedSuccess assertCapturedSuccess
} }
testDangerousRangeStar() { testDangerousRangeStar() {
compile "dangerous-range-star" compile "dangerous-range-star"
assertCaptured "Dangerous semver range" assertCaptured "Dangerous semver range"
assertCaptured "Node engine: *"
assertCaptured "Resolving node version * via semver.io" assertCaptured "Resolving node version * via semver.io"
assertCaptured "Downloading and installing node 0.12" assertCaptured "Downloading and installing node 0.12."
assertCapturedError assertCapturedError
} }
...@@ -171,50 +181,57 @@ testInvalidDependency() { ...@@ -171,50 +181,57 @@ testInvalidDependency() {
testNodeModulesCached() { testNodeModulesCached() {
cache=$(mktmpdir) cache=$(mktmpdir)
compile "caching" $cache compile "caching" $cache
assertCaptured "Caching results for future builds" assertCaptured "Saving 1 cacheDirectories (default)"
assertEquals "1" "$(ls -1 $cache/ | grep node | wc -l)" assertCaptured "- node_modules"
assertEquals "1" "$(ls -1 $cache/node | grep node_modules | wc -l)" assertEquals "1" "$(ls -1 $cache/node | grep node_modules | wc -l | tr -d ' ')"
assertCapturedSuccess
} }
testBuildWithCache() { testBuildWithCache() {
cache=$(mktmpdir) cache=$(mktmpdir)
compile "stable-node" $cache compile "stable-node" $cache
assertCaptured "node_modules cached: false" assertCaptured "- node_modules (not cached - skipping)"
assertCaptured "Caching results for future builds" assertEquals "1" "$(ls -1 $cache/node | grep node_modules | wc -l | tr -d ' ')"
assertCapturedSuccess assertCapturedSuccess
compile "stable-node" $cache compile "stable-node" $cache
assertCaptured "node_modules cached: true" assertNotCaptured "- node_modules (not cached - skipping)"
assertCaptured "Restoring node modules from cache"
assertCapturedSuccess assertCapturedSuccess
} }
testBuildWithUserCacheDirectories() { testBuildWithUserCacheDirectories() {
cache=$(mktmpdir) cache=$(mktmpdir)
compile "cache-directories" $cache compile "cache-directories" $cache
assertCaptured "Saving 2 cacheDirectories"
assertEquals "1" "$(ls -1 $cache/node | grep bower_components | wc -l | tr -d ' ')"
assertEquals "1" "$(ls -1 $cache/node | grep node_modules | wc -l | tr -d ' ')"
assertCapturedSuccess assertCapturedSuccess
assertEquals "1" "$(ls -1 $cache/node | grep bower_components | wc -l)"
assertEquals "1" "$(ls -1 $cache/node | grep node_modules | wc -l)"
compile "cache-directories" $cache compile "cache-directories" $cache
assertCaptured "Restoring 2 directories from cache:" assertCaptured "Loading 2 from cacheDirectories"
assertCaptured "- node_modules"
assertCaptured "- bower_components" assertCaptured "- bower_components"
assertCaptured "Restoring node modules from cache"
assertCapturedSuccess assertCapturedSuccess
} }
testBuildWithUserCacheDirectoriesCamel() { testBuildWithUserCacheDirectoriesCamel() {
cache=$(mktmpdir) cache=$(mktmpdir)
compile "cache-directories-camel" $cache compile "cache-directories-camel" $cache
assertCaptured "- non/existent (nothing to cache)"
assertEquals "1" "$(ls -1 $cache/node/server | grep node_modules | wc -l | tr -d ' ')"
assertEquals "1" "$(ls -1 $cache/node/client | grep node_modules | wc -l | tr -d ' ')"
assertCapturedSuccess assertCapturedSuccess
assertEquals "1" "$(ls -1 $cache/node | grep bower_components | wc -l)"
assertEquals "1" "$(ls -1 $cache/node | grep node_modules | wc -l)"
compile "cache-directories" $cache compile "cache-directories-camel" $cache
assertCaptured "Restoring 2 directories from cache:" assertCaptured "Loading 3 from cacheDirectories"
assertCaptured "- bower_components" assertCaptured "- server/node_modules"
assertCaptured "Restoring node modules from cache" assertCaptured "- client/node_modules"
assertCaptured "- non/existent (not cached - skipping)"
assertCapturedSuccess assertCapturedSuccess
} }
...@@ -224,13 +241,11 @@ testModulesCheckedIn() { ...@@ -224,13 +241,11 @@ testModulesCheckedIn() {
assertCapturedSuccess assertCapturedSuccess
compile "modules-checked-in" $cache compile "modules-checked-in" $cache
assertCaptured "node_modules source: prebuilt" assertCaptured "Prebuild detected"
assertCaptured "Rebuilding any native modules for this architecture" assertCaptured "Rebuilding any native modules"
assertCaptured "(preinstall script)" assertCaptured "(preinstall script)"
assertCaptured "Installing any new modules" assertCaptured "Installing any new modules"
assertCaptured "(postinstall script)" assertCaptured "(postinstall script)"
assertNotCaptured "Restoring node modules"
assertNotCaptured "Pruning unused dependencies"
assertCapturedSuccess assertCapturedSuccess
} }
...@@ -241,52 +256,18 @@ testUserConfig() { ...@@ -241,52 +256,18 @@ testUserConfig() {
assertCapturedError 1 "" assertCapturedError 1 ""
} }
testProcfile() { testDefaultProcType() {
compile "procfile-present-only" release "stable-node"
assertCaptured "Start mechanism: Procfile" assertCaptured "web: npm start"
assertNotCaptured "new Procfile"
assertCapturedSuccess
}
testProcfileAbsentNpmStartPresent() {
compile "procfile-absent-npm-start-present"
assertCaptured "Start mechanism: npm start"
assertCaptured "Adding 'web: npm start' to new Procfile"
assertFile "web: npm start" "Procfile"
assertCapturedSuccess
}
testProcfileAbsentNpmStartAbsent() {
compile "procfile-absent-npm-start-absent"
assertCaptured "Start mechanism: none"
assertCaptured "None found"
assertNotCaptured "new Procfile"
assertCapturedSuccess assertCapturedSuccess
} }
testDynamicProcfile() { testDynamicProcfile() {
compile "dynamic-procfile" compile "dynamic-procfile"
assertCaptured "Procfile created during build"
assertFileContains "web: node index.js customArg" "${compile_dir}/Procfile" assertFileContains "web: node index.js customArg" "${compile_dir}/Procfile"
assertCapturedSuccess assertCapturedSuccess
} }
testProcfileAbsentServerPresent() {
compile "procfile-absent-server-present"
assertCaptured "Start mechanism: server.js"
assertCaptured "'web: node server.js' to new Procfile"
assertFile "web: node server.js" "Procfile"
assertCapturedSuccess
}
testServerPresentOnly() {
compile "server-present-only"
assertCaptured "Skipping dependencies"
assertCaptured "'web: node server.js' to new Procfile"
assertFile "web: node server.js" "Procfile"
assertCapturedSuccess
}
testEnvVars() { testEnvVars() {
env_dir=$(mktmpdir) env_dir=$(mktmpdir)
echo "false" > $env_dir/NPM_CONFIG_PRODUCTION echo "false" > $env_dir/NPM_CONFIG_PRODUCTION
...@@ -329,7 +310,6 @@ testDevDependencies() { ...@@ -329,7 +310,6 @@ testDevDependencies() {
testOptionalDependencies() { testOptionalDependencies() {
env_dir=$(mktmpdir) env_dir=$(mktmpdir)
#echo "true" > $env_dir/NPM_CONFIG_OPTIONAL
compile "optional-dependencies" "$(mktmpdir)" $env_dir compile "optional-dependencies" "$(mktmpdir)" $env_dir
assertNotCaptured "NPM_CONFIG_OPTIONAL" assertNotCaptured "NPM_CONFIG_OPTIONAL"
assertCaptured "less" assertCaptured "less"
...@@ -353,24 +333,6 @@ testNoOptionalDependencies() { ...@@ -353,24 +333,6 @@ testNoOptionalDependencies() {
assertCapturedSuccess assertCapturedSuccess
} }
testDisableCache() {
cache=$(mktmpdir)
env_dir=$(mktmpdir)
compile "node-modules-cache-1" $cache
assertCaptured "lodash@1.0.0"
assertCapturedSuccess
compile "node-modules-cache-2" $cache
assertCaptured "lodash@1.0.0"
assertCapturedSuccess
echo "false" > $env_dir/NODE_MODULES_CACHE
compile "node-modules-cache-2" $cache $env_dir
assertCaptured "lodash@1.3.1"
assertCapturedSuccess
}
testNpmrc() { testNpmrc() {
compile "dev-dependencies" compile "dev-dependencies"
assertNotCaptured "lodash" assertNotCaptured "lodash"
...@@ -408,35 +370,35 @@ testMultiExport() { ...@@ -408,35 +370,35 @@ testMultiExport() {
} }
testConcurrency1X() { testConcurrency1X() {
MEMORY_AVAILABLE=512 capture ${bp_dir}/lib/concurrency.sh MEMORY_AVAILABLE=512 capture $(pwd)/profile/nodejs.sh
assertCaptured "Detected 512 MB available memory, 512 MB limit per process (WEB_MEMORY)" assertCaptured "Detected 512 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=1" assertCaptured "Recommending WEB_CONCURRENCY=1"
assertCapturedSuccess assertCapturedSuccess
} }
testConcurrency2X() { testConcurrency2X() {
MEMORY_AVAILABLE=1024 capture ${bp_dir}/lib/concurrency.sh MEMORY_AVAILABLE=1024 capture $(pwd)/profile/nodejs.sh
assertCaptured "Detected 1024 MB available memory, 512 MB limit per process (WEB_MEMORY)" assertCaptured "Detected 1024 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=2" assertCaptured "Recommending WEB_CONCURRENCY=2"
assertCapturedSuccess assertCapturedSuccess
} }
testConcurrencyPX() { testConcurrencyPX() {
MEMORY_AVAILABLE=6144 capture ${bp_dir}/lib/concurrency.sh MEMORY_AVAILABLE=6144 capture $(pwd)/profile/nodejs.sh
assertCaptured "Detected 6144 MB available memory, 512 MB limit per process (WEB_MEMORY)" assertCaptured "Detected 6144 MB available memory, 512 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=12" assertCaptured "Recommending WEB_CONCURRENCY=12"
assertCapturedSuccess assertCapturedSuccess
} }
testConcurrencyCustomLimit() { testConcurrencyCustomLimit() {
MEMORY_AVAILABLE=1024 WEB_MEMORY=256 capture ${bp_dir}/lib/concurrency.sh MEMORY_AVAILABLE=1024 WEB_MEMORY=256 capture $(pwd)/profile/nodejs.sh
assertCaptured "Detected 1024 MB available memory, 256 MB limit per process (WEB_MEMORY)" assertCaptured "Detected 1024 MB available memory, 256 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=4" assertCaptured "Recommending WEB_CONCURRENCY=4"
assertCapturedSuccess assertCapturedSuccess
} }
testConcurrencySaneMaximum() { testConcurrencySaneMaximum() {
MEMORY_AVAILABLE=6144 WEB_MEMORY=32 capture ${bp_dir}/lib/concurrency.sh MEMORY_AVAILABLE=6144 WEB_MEMORY=32 capture $(pwd)/profile/nodejs.sh
assertCaptured "Detected 6144 MB available memory, 32 MB limit per process (WEB_MEMORY)" assertCaptured "Detected 6144 MB available memory, 32 MB limit per process (WEB_MEMORY)"
assertCaptured "Recommending WEB_CONCURRENCY=32" assertCaptured "Recommending WEB_CONCURRENCY=32"
assertCapturedSuccess assertCapturedSuccess
...@@ -446,10 +408,9 @@ testConcurrencySaneMaximum() { ...@@ -446,10 +408,9 @@ testConcurrencySaneMaximum() {
# Utils # Utils
pushd $(dirname 0) >/dev/null pushd $(dirname 0) >/dev/null
bp_dir=$(pwd)
popd >/dev/null popd >/dev/null
source ${bp_dir}/test/utils source $(pwd)/test/utils
mktmpdir() { mktmpdir() {
dir=$(mktemp -t testXXXXX) dir=$(mktemp -t testXXXXX)
...@@ -459,19 +420,35 @@ mktmpdir() { ...@@ -459,19 +420,35 @@ mktmpdir() {
} }
detect() { detect() {
capture ${bp_dir}/bin/detect ${bp_dir}/test/fixtures/$1 capture $(pwd)/bin/detect $(pwd)/test/fixtures/$1
} }
compile_dir="" compile_dir=""
default_process_types_cleanup() {
file="/tmp/default_process_types"
if [ -f "$file" ]; then
rm "$file"
fi
}
compile() { compile() {
default_process_types_cleanup
bp_dir=$(mktmpdir)
compile_dir=$(mktmpdir) compile_dir=$(mktmpdir)
cp -r ${bp_dir}/test/fixtures/$1/. ${compile_dir} cp -a $(pwd)/* ${bp_dir}
cp -a ${bp_dir}/test/fixtures/$1/. ${compile_dir}
capture ${bp_dir}/bin/compile ${compile_dir} ${2:-$(mktmpdir)} $3 capture ${bp_dir}/bin/compile ${compile_dir} ${2:-$(mktmpdir)} $3
} }
release() {
bp_dir=$(mktmpdir)
cp -a $(pwd)/* ${bp_dir}
capture ${bp_dir}/bin/release ${bp_dir}/test/fixtures/$1
}
assertFile() { assertFile() {
assertEquals "$1" "$(cat ${compile_dir}/$2)" assertEquals "$1" "$(cat ${compile_dir}/$2)"
} }
source ${bp_dir}/test/shunit2 source $(pwd)/test/shunit2
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment