Permalink
Browse files

Merge remote-tracking branch 'origin/versions'

  • Loading branch information...
2 parents 4a8eff9 + 1d061d0 commit a5ee40ad2753639854f6676ea7248d4981f6d635 @hone hone committed Feb 22, 2012
View
@@ -29,27 +29,44 @@ Example usage:
The buildpack will detect your app as Node.js if it has the file `package.json` in the root. It will use NPM to install your dependencies, and vendors a version of the Node.js runtime into your slug. The `node_modules` directory will be cached between builds to allow for faster NPM install time.
+Node.js and npm versions
+------------------------
+
+You can specify the versions of Node.js and npm your application requires using `package.json`
+
+ {
+ "name": "myapp",
+ "engines": {
+ "node": ">=0.4.7 <0.7.0",
+ "npm": ">=1.0.0"
+ }
+ }
+
+To list the available versions of Node.js and npm, see these manifests:
+
+http://heroku-buildpack-nodejs.s3.amazonaws.com/manifest.nodejs
+http://heroku-buildpack-nodejs.s3.amazonaws.com/manifest.npm
+
Hacking
-------
To use this buildpack, fork it on Github. Push up changes to your fork, then create a test app with `--buildpack <your-github-url>` and push to it.
To change the vendored binaries for Node.js, NPM, and SCons, use the helper scripts in the `support/` subdirectory. You'll need an S3-enabled AWS account and a bucket to store your binaries in.
-For example, you can change the vendored version of Node.js to v0.5.8.
+For example, you can change the default version of Node.js to v0.6.7.
First you'll need to build a Heroku-compatible version of Node.js:
$ export AWS_ID=xxx AWS_SECRET=yyy S3_BUCKET=zzz
$ s3 create $S3_BUCKET
- $ support/package_node 0.5.8
+ $ support/package_nodejs 0.6.7
Open `bin/compile` in your editor, and change the following lines:
- NODE_VERSION="0.5.8"
-
+ DEFAULT_NODE_VERSION="0.6.7"
S3_BUCKET=zzz
Commit and push the changes to your buildpack to your Github fork, then push your sample app to Heroku to test. You should see:
- -----> Vendoring node 0.5.8
+ -----> Vendoring node 0.6.7
View
@@ -1,7 +1,32 @@
#!/usr/bin/env bash
# bin/compile <build-dir> <cache-dir>
-mktmpdir() {
+# fail fast
+set -e
+
+# debug
+# set -x
+
+# clean up leaking environment
+unset GIT_DIR
+
+# config
+SCONS_VERSION="1.2.0"
+S3_BUCKET="heroku-buildpack-nodejs"
+
+# parse and derive params
+BUILD_DIR=$1
+CACHE_DIR=$2
+LP_DIR=`cd $(dirname $0); cd ..; pwd`
+CACHE_STORE_DIR="$CACHE_DIR/node_modules/$NPM_VERSION"
+CACHE_TARGET_DIR="$BUILD_DIR/node_modules"
+
+function error() {
+ echo " ! $*"
+ exit 1
+}
+
+function mktmpdir() {
dir=$(mktemp -t node-$1-XXXX)
rm -rf $dir
mkdir -p $dir
@@ -16,8 +41,10 @@ function indent() {
esac
}
-run_npm() {
+function run_npm() {
command="$1"
+
+ cd $BUILD_DIR
HOME="$BUILD_DIR" $VENDORED_NODE/bin/node $VENDORED_NPM/cli.js $command 2>&1 | indent
if [ "${PIPESTATUS[*]}" != "0 0" ]; then
@@ -26,21 +53,76 @@ run_npm() {
fi
}
-# clean up leaking environment
-unset GIT_DIR
+function manifest_versions() {
+ curl "http://${S3_BUCKET}.s3.amazonaws.com/manifest.${1}" -s -o - | tr -s '\n' ' '
+}
-# config
-NODE_VERSION="0.4.7"
-NPM_VERSION="1.0.94"
-SCONS_VERSION="1.2.0"
-S3_BUCKET="heroku-buildpack-nodejs"
+function resolve_version() {
+ available_versions="$1"
+ requested_version="$2"
+ default_version="$3"
+
+ if [ "$2" == "" ]; then
+ echo $3
+ else
+ args=""
+ for version in $available_versions; do args="${args} -v \"${version}\""; done
+ for version in $requested_version; do args="${args} -r \"${version}\""; done
+ eval $bootstrap_node/bin/node $LP_DIR/vendor/node-semver/bin/semver ${args} | tail -n1
+ fi
+}
-# parse and derive params
-BUILD_DIR=$1
-CACHE_DIR=$2
-LP_DIR=`cd $(dirname $0); cd ..; pwd`
-CACHE_STORE_DIR="$CACHE_DIR/node_modules/$NPM_VERSION"
-CACHE_TARGET_DIR="$BUILD_DIR/node_modules"
+function package_engine_version() {
+ version=$(cat $BUILD_DIR/package.json | $bootstrap_node/bin/node $LP_DIR/vendor/json/json engines.$1 2>/dev/null)
+ if [ $? == 0 ]; then
+ echo $version
+ fi
+}
+
+function package_resolve_version() {
+ engine="$1"
+ resolved_version=$(resolve_version "${engine_versions[$engine]}" "${engine_requests[$engine]}" "${engine_defaults[$engine]}")
+
+ if [ "${resolved_version}" == "" ]; then
+ error "Requested engine $engine version ${engine_requests[$engine]} does not match available versions: ${engine_versions[$engine]}"
+ else
+ echo $resolved_version
+ fi
+}
+
+function package_download() {
+ engine="$1"
+ version="$2"
+ location="$3"
+
+ mkdir -p $location
+ package="http://${S3_BUCKET}.s3.amazonaws.com/$engine-$version.tgz"
+ curl $package -s -o - | tar xzf - -C $location
+}
+
+bootstrap_node=$(mktmpdir bootstrap_node)
+package_download "nodejs" "0.4.7" $bootstrap_node
+
+# make some associative arrays
+declare -A engine_versions
+declare -A engine_defaults
+declare -A engine_requests
+
+engine_defaults["node"]="0.4.7"
+engine_defaults["npm"]="1.0.94"
+
+engine_versions["node"]=$(manifest_versions "nodejs")
+engine_requests["node"]=$(package_engine_version "node")
+
+engine_versions["npm"]=$(manifest_versions "npm")
+engine_requests["npm"]=$(package_engine_version "npm")
+
+echo "-----> Resolving engine versions"
+NODE_VERSION=$(package_resolve_version "node")
+echo "Using Node.js version: ${NODE_VERSION}" | indent
+
+NPM_VERSION=$(package_resolve_version "npm")
+echo "Using npm version: ${NPM_VERSION}" | indent
# s3 packages
NODE_PACKAGE="http://${S3_BUCKET}.s3.amazonaws.com/nodejs-${NODE_VERSION}.tgz"
@@ -54,13 +136,13 @@ VENDORED_SCONS="$(mktmpdir scons)"
# download and unpack packages
echo "-----> Fetching Node.js binaries"
-mkdir -p $VENDORED_NODE && curl $NODE_PACKAGE -s -o - | tar xzf - -C $VENDORED_NODE
-mkdir -p $VENDORED_NPM && curl $NPM_PACKAGE -s -o - | tar xzf - -C $VENDORED_NPM
-mkdir -p $VENDORED_SCONS && curl $SCONS_PACKAGE -s -o - | tar xzf - -C $VENDORED_SCONS
+package_download "nodejs" "${NODE_VERSION}" "${VENDORED_NODE}"
+package_download "npm" "${NPM_VERSION}" "${VENDORED_NPM}"
+package_download "scons" "${SCONS_VERSION}" "${VENDORED_SCONS}"
# vendor node into the slug
PATH="$BUILD_DIR/bin:$PATH"
-echo "-----> Vendoring node $NODE_VERSION"
+echo "-----> Vendoring node into slug"
mkdir -p "$BUILD_DIR/bin"
cp "$VENDORED_NODE/bin/node" "$BUILD_DIR/bin/node"
@@ -93,12 +175,9 @@ if [ -d $CACHE_STORE_DIR ]; then
fi
# install dependencies with npm
-echo "-----> Installing dependencies with npm $NPM_VERSION"
-
-cd $BUILD_DIR
-run_npm install
-run_npm rebuild
-
+echo "-----> Installing dependencies with npm"
+run_npm "install"
+run_npm "rebuild"
echo "Dependencies installed" | indent
# repack cache with new assets
View
@@ -117,14 +117,17 @@ s3_curl() {
# $2 = remote bucket.
# $3 = remote name
# $4 = local name.
+ # $5 = mime type
local bucket remote date sig md5 arg inout headers
# header handling is kinda fugly, but it works.
bucket="${2:+/${2}}/" # slashify the bucket
remote="$(urlenc "${3}")" # if you don't, strange things may happen.
stdopts="--connect-timeout 10 --fail --silent"
+ mime="${5}"
[[ $CURL_S3_DEBUG == true ]] && stdopts="${stdopts} --show-error --fail"
case "${1}" in
GET) arg="-o" inout="${4:--}" # stdout if no $4
+ headers[${#headers[@]}]="x-amz-acl: public-read"
;;
PUT) [[ ${2} ]] || die "PUT can has bucket?"
if [[ ! ${3} ]]; then
@@ -135,6 +138,9 @@ s3_curl() {
arg="-T" inout="${4}"
headers[${#headers[@]}]="x-amz-acl: public-read"
headers[${#headers[@]}]="Expect: 100-continue"
+ if [ "$mime" != "" ]; then
+ headers[${#headers[@]}]="Content-Type: $mime"
+ fi
else
die "Cannot write non-existing file ${4}"
fi
@@ -145,7 +151,7 @@ s3_curl() {
*) die "Unknown verb ${1}. It probably would not have worked anyways." ;;
esac
date="$(TZ=UTC date '+%a, %e %b %Y %H:%M:%S %z')"
- sig=$(s3_signature_string ${1} "${date}" "${bucket}" "${remote}" "${md5}" "" "x-amz-acl:public-read")
+ sig=$(s3_signature_string ${1} "${date}" "${bucket}" "${remote}" "${md5}" "${mime}" "x-amz-acl:public-read")
headers[${#headers[@]}]="Authorization: AWS ${AWS_ID}:${sig}"
headers[${#headers[@]}]="Date: ${date}"
@@ -159,7 +165,8 @@ s3_put() {
# $1 = remote bucket to put it into
# $2 = remote name to put
# $3 = file to put. This must be present if $2 is.
- s3_curl PUT "${1}" "${2}" "${3:-${2}}"
+ # $4 = mime type
+ s3_curl PUT "${1}" "${2}" "${3:-${2}}" "${4}"
return $?
}
View
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+set -e
+
+manifest_type="$1"
+
+if [ "$manifest_type" == "" ]; then
+ echo "usage: $0 <nodejs|npm>"
+ exit 1
+fi
+
+if [ "$AWS_ID" == "" ]; then
+ echo "must set AWS_ID"
+ exit 1
+fi
+
+if [ "$AWS_SECRET" == "" ]; then
+ echo "must set AWS_SECRET"
+ exit 1
+fi
+
+if [ "$S3_BUCKET" == "" ]; then
+ echo "must set S3_BUCKET"
+ exit 1
+fi
+
+basedir="$( cd -P "$( dirname "$0" )" && pwd )"
+
+# make a temp directory
+tempdir="$( mktemp -t node_XXXX )"
+rm -rf $tempdir
+mkdir -p $tempdir
+pushd $tempdir
+
+# generate manifest
+$basedir/aws/s3 ls $S3_BUCKET \
+ | grep "^${manifest_type}" \
+ | sed -e "s/${manifest_type}-\([0-9.]*\)\\.tgz/\\1/" \
+ | awk 'BEGIN {FS="."} {printf("%03d.%03d.%03d %s\n",$1,$2,$3,$0)}' | sort -r | cut -d" " -f2 \
+ > manifest.${manifest_type}
+
+# upload manifest to s3
+$basedir/aws/s3 put $S3_BUCKET \
+ manifest.${manifest_type} "" "text/plain"
@@ -30,14 +30,14 @@ basedir="$( cd -P "$( dirname "$0" )" && pwd )"
tempdir="$( mktemp -t node_XXXX )"
rm -rf $tempdir
mkdir -p $tempdir
-pushd $tempdir
+cd $tempdir
# download and extract node
-curl http://nodejs.org/dist/node-v${node_version}.tar.gz -o node.tgz
+curl http://nodejs.org/dist/v${node_version}/node-v${node_version}.tar.gz -o node.tgz
tar xzvf node.tgz
# go into node dir
-pushd node-v${node_version}
+cd node-v${node_version}
# build and package nodejs for heroku
vulcan build -v -o $tempdir/node-${node_version}.tgz
@@ -47,7 +47,7 @@ $basedir/aws/s3 put $S3_BUCKET \
nodejs-${node_version}.tgz $tempdir/node-${node_version}.tgz
# go into scons
-pushd tools/scons
+cd tools/scons
# package scons
scons_version=$(ls | grep "scons-local" | cut -d- -f3)
@@ -56,3 +56,6 @@ tar czvf $tempdir/scons-${scons_version}.tgz *
# upload scons to s3
$basedir/aws/s3 put $S3_BUCKET \
scons-${scons_version}.tgz $tempdir/scons-${scons_version}.tgz
+
+# generate manifest
+$basedir/manifest nodejs
View
@@ -48,3 +48,6 @@ tar czvf $tempdir/npm-${npm_version}.tgz *
# upload npm to s3
$basedir/aws/s3 put $S3_BUCKET \
npm-${npm_version}.tgz $tempdir/npm-${npm_version}.tgz
+
+# generate manifest
+$basedir/manifest npm
View
@@ -0,0 +1,2 @@
+json: https://github.com/trentm/json
+node-semver: http://github.com/isaacs/node-semver
Oops, something went wrong.

0 comments on commit a5ee40a

Please sign in to comment.