Skip to content

Commit

Permalink
bring caching logic to the forefront
Browse files Browse the repository at this point in the history
  • Loading branch information
hunterloftis committed Jun 5, 2015
1 parent 97f6717 commit ce7f479
Show file tree
Hide file tree
Showing 38 changed files with 654 additions and 710 deletions.
210 changes: 141 additions & 69 deletions bin/compile
Original file line number Diff line number Diff line change
@@ -1,74 +1,146 @@
#!/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 errtrace # trap errors in functions as well
set -o pipefail # don't ignore exit codes when piping output
set -o posix # more strict failures in subshells
# set -x # enable debugging

# Configure directories
build_dir=$1
cache_dir=$2
env_dir=$3
bp_dir=$(cd $(dirname $0); cd ..; pwd)
heroku_dir=$build_dir/.heroku
mkdir -p $heroku_dir/node
warnings=$(mktemp)

# Load dependencies
source $bp_dir/lib/common.sh
source $bp_dir/lib/build.sh
source $bp_dir/lib/warnings.sh

# Avoid GIT_DIR leak from previous build steps
unset GIT_DIR

# Provide hook to deal with errors
trap build_failed ERR

####### Determine current state

head "Reading application state"
read_current_state
show_current_state

if [ "$iojs_engine" == "" ]; then
warn_node_engine "$node_engine"
else
warn_node_engine "$iojs_engine"
fi
warn_node_modules "$modules_source"

####### Vendor in binaries

head "Installing binaries"
if [ "$iojs_engine" == "" ]; then
install_node "$node_engine"
else
install_iojs "$iojs_engine"
fi
install_npm

####### Build the project's dependencies

head "Building dependencies"
cd $build_dir
build_dependencies

####### Create a Procfile if possible

head "Checking startup method"
ensure_procfile "$start_method" "$build_dir"
warn_start "$start_method"

####### Finalize the build

head "Finalizing build"
write_profile
write_export
clean_npm
clean_cache
create_cache
build_succeeded
set -o nounset # fail on unset variables
unset GIT_DIR # Avoid GIT_DIR leak from previous build steps

### Configure directories

BUILD_DIR=${1:-}
CACHE_DIR=${2:-}
ENV_DIR=${3:-}
BP_DIR=$(cd $(dirname ${0:-}); cd ..; pwd)

mkdir -p "$BUILD_DIR/.heroku/node/"
cd $BUILD_DIR
export PATH="$BUILD_DIR/.heroku/node/bin":$PATH

### Load dependencies

source $BP_DIR/lib/output.sh
source $BP_DIR/lib/json.sh
source $BP_DIR/lib/failure.sh
source $BP_DIR/lib/environment.sh
source $BP_DIR/lib/binaries.sh
source $BP_DIR/lib/cache.sh
source $BP_DIR/lib/dependencies.sh

### Handle errors

handle_failure() {
header "Build failed"
failure_message | indent
}
trap 'handle_failure' ERR

### Check initial state

[ -e "$BUILD_DIR/node_modules" ] && PREBUILD=true || PREBUILD=false

### Failures that should be caught immediately

fail_invalid_package_json "$BUILD_DIR"
warn_prebuilt_modules "$BUILD_DIR"
warn_missing_package_json "$BUILD_DIR"

### Compile

create_env() {
write_profile "$BP_DIR" "$BUILD_DIR"
write_export "$BP_DIR" "$BUILD_DIR"
export_env_dir "$ENV_DIR"
create_default_env
}

header "Creating runtime environment"
create_env # can't indent the whole thing because piping causes subshells; no exporting possible
list_node_config | indent

install_bins() {
local node_engine=$(read_json "$BUILD_DIR/package.json" ".engines.node")
local iojs_engine=$(read_json "$BUILD_DIR/package.json" ".engines.iojs")
local npm_engine=$(read_json "$BUILD_DIR/package.json" ".engines.npm")

if [ -n "$iojs_engine" ]; then
echo "engines.iojs (package.json): $iojs_engine (iojs)"
else
echo "engines.node (package.json): ${node_engine:-unspecified}"
fi
echo "engines.npm (package.json): ${npm_engine:-unspecified (use default)}"
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
9 changes: 4 additions & 5 deletions bin/detect
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
# bin/detect <build-dir>

if [ -f $1/package.json ]; then
echo "Node.js" && exit 0
elif [ -f $1/server.js ]; then
echo "Node.js" && exit 0
else
echo "no" && exit 1
echo "Node.js"
exit 0
fi

exit 1
4 changes: 3 additions & 1 deletion bin/release
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#!/usr/bin/env bash
# bin/release <build-dir>

cat << EOF
addons: []
default_process_types: {}
default_process_types:
web: npm start
EOF
59 changes: 59 additions & 0 deletions lib/binaries.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
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
}
Loading

0 comments on commit ce7f479

Please sign in to comment.