Skip to content
This repository was archived by the owner on Feb 13, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions .profile.d/buildpack-boot.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
DNX_BIN=`find .dnx/runtimes -type d -name bin`
export PATH="$PATH:/app/mono/bin:$DNX_BIN"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/app/mono/lib:/app/libuv/lib"
export MONO_OPTIONS=--server
export PATH="$PATH:$HOME/dotnet:$HOME/.apt/usr/bin"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$HOME/.apt/usr/lib/x86_64-linux-gnu:$HOME/.apt/usr/lib/i386-linux-gnu:$HOME/.apt/usr/lib"
export LIBRARY_PATH="$LIBRARY_PATH:$HOME/.apt/usr/lib/x86_64-linux-gnu:$HOME/.apt/usr/lib/i386-linux-gnu:$HOME/.apt/usr/lib"
export INCLUDE_PATH="$INCLUDE_PATH:$HOME/.apt/usr/include"
export CPATH="$INCLUDE_PATH"
export CPPPATH="$INCLUDE_PATH"
export apt_CONFIG_PATH="$apt_CONFIG_PATH:$HOME/.apt/usr/lib/x86_64-linux-gnu/aptconfig:$HOME/.apt/usr/lib/i386-linux-gnu/aptconfig:$HOME/.apt/usr/lib/aptconfig"
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
**Please note:** This buildpack is an experimental project and is not officially supported.

# ASP.NET 5 Buildpack
# ASP.NET Core Buildpack

This is a [Heroku buildpack](http://devcenter.heroku.com/articles/buildpack) for building [ASP.NET 5](http://www.asp.net/vnext/overview/aspnet-vnext/aspnet-5-overview) apps using [`project.json` files](https://github.com/aspnet/Home/wiki/Project.json-file) and the [kpm package manager](https://github.com/aspnet/Home/wiki/Package-Manager).

[Mono](http://www.mono-project.com/) is bundled for runtime execution.
This is a [Heroku buildpack](http://devcenter.heroku.com/articles/buildpack) for building [ASP.NET Core](https://docs.asp.net/en/latest/conceptual-overview/aspnet.html) apps using [`project.json` files](https://github.com/aspnet/Home/wiki/Project.json-file) and the [.NET CLI](https://github.com/dotnet/cli).

## Usage

Example usage:

$ heroku create --buildpack http://github.com/heroku/dotnet-buildpack.git
$ heroku create --buildpack http://github.com/noliar/dotnet-buildpack.git
$ git push heroku master

The buildpack will detect your app as ASP.NET 5 if it has `project.json`. If the source code you want to build contains multiple `project.json` files, you can use a [`.deployment`](https://github.com/projectkudu/kudu/wiki/Customizing-deployments) or set a `$PROJECT` config var to control which one is built.
The buildpack will detect your app as ASP.NET Core if it has `project.json`. If the source code you want to build contains multiple `project.json` files, you can use a [`.deployment`](https://github.com/projectkudu/kudu/wiki/Customizing-deployments) or set a `$PROJECT` config var to control which one is built.

## Attension
1. You should configure a unique compatible framework in `project.json`.
2. Your Project should use `Microsoft.Extensions.Configuration.CommandLine` package.
3. You'd better configure SDK version using `global.json`.
154 changes: 86 additions & 68 deletions bin/compile
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,18 @@ source $BUILDPACK_DIR/bin/util

export_env_dir ${ENV_DIR}

: ${MONO_VERSION:="4.0.1.44"}
: ${MONO_DOWNLOAD_LOCATION:="https://github.com/friism/mono-builder/releases/download/v${MONO_VERSION}/mono-${MONO_VERSION}.tar.gz"}
: ${LIBUV_VERSION:="1.6.0"}
: ${NODE_VERSION:="0.12.2"}
: ${DNVM_BRANCH:="dev"}
: ${DNX_VERSION:="latest"}

# REMARK: https://github.com/aspnet/dnx/pull/2620 and https://github.com/aspnet/aspnet-docker/issues/80
[ -z "$MONO_THREADS_PER_CPU" ] && export MONO_THREADS_PER_CPU=50
: ${CORE_VERSION:="latest"}
: ${CORE_SCRIPT_LOCATION:="https://raw.githubusercontent.com/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.sh"}
: ${NODE_VERSION:="4.4.4"}
: ${CORE_VERSION:="latest"}
: ${CORE_CHANNEL:="preview"}

if [ -n "$BUILD_DEBUG" ]; then
DNU_FLAGS=""
echo "DNX_VERSION: ${DNX_VERSION}"
echo "DNVM_BRANCH: ${DNVM_BRANCH}"
else
DNU_FLAGS="--quiet"
fi

if [ -n "$UNSTABLE_TOOLCHAIN" ]; then
DNVM_FLAGS="-u"
CORE_CONFIGURATION="Debug"
CORE_ENVIRONMENT="--environment Development"
else
DNVM_FLAGS=""
CORE_CONFIGURATION="Release"
CORE_ENVIRONMENT=""
fi

SRC_DIR=`mktemp -d`
Expand All @@ -51,90 +41,118 @@ SRC_DIR=`mktemp -d`

mkdir -p ${CACHE_DIR}

echo "installing ${MONO_DOWNLOAD_LOCATION}"
# TODO: use s4cmd
curl ${MONO_DOWNLOAD_LOCATION} -Ls | tar xz -C ${BUILD_DIR}
# Mono expects to be running out of /app
ln -s ${BUILD_DIR}/mono /app

export PATH="/app/mono/bin:${PATH}"
export LD_LIBRARY_PATH="/app/mono/lib:${LD_LIBRARY_PATH}"

mozroots --import --sync --quiet
cp -r ~/.config ${BUILD_DIR}/.

# TODO: This test doesn't seen to actually work
# TODO: Maybe just run `npm install -g` and if anything is missing, install it after
if [[ -n $(find . -type f -iname package.json -o -iname bower.json -o -iname gruntfile.js) ]]
if [[ -n $(find ${SRC_DIR} -type f -iname package.json -o -iname bower.json) ]]
then
# Install Node and grunt-cli
echo "Installing Node"
NODE_PATH=`mktemp -d`
curl https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz -Ls \
| tar xz -C ${NODE_PATH}
export PATH="${NODE_PATH}/node-v${NODE_VERSION}-linux-x64/bin:${PATH}"
npm install -g grunt-cli bower gulp
echo "Installing bower"
if ! hash bower 2>/dev/null; then
npm install -g bower
fi
fi

# Install .NET Core
echo "Get .NET Core Version and Channel from the PROJECT"
DEPLOYMENT_FILE_LOCATION=${SRC_DIR}/.deployment
if [ -n "$(find ${SRC_DIR}/global.json)" ]; then
echo "Get version from global.json"
CORE_VERSION=$(ruby -rjson -e "j = JSON.parse(File.open('${SRC_DIR}/global.json','r:bom|utf-8').read); unless j['sdk'].nil? ; puts j['sdk']['version'];end")
if [ -z "${CORE_VERSION}" ]; then
CORE_VERSION="latest"
elif [[ "${CORE_VERSION}" != "latest" ]]; then
if [[ "${CORE_VERSION}" == "1.0.0-preview2.1-003155" ]]; then
CORE_DOWNLOAD_LOCATION="https://dotnetcli.blob.core.windows.net/dotnet/preview/Binaries/1.0.0-preview2.1-003155/dotnet-dev-ubuntu-x64.1.0.0-preview2.1-003155.tar.gz"
elif [[ "${CORE_VERSION}" > "1.0.0-preview2-003121" ]]; then
#TODO
CORE_DOWNLOAD_LOCATION="https://dotnetcli.blob.core.windows.net/dotnet/Sdk/rel-1.0.0/dotnet-dev-ubuntu-x64.latest.tar.gz"
elif [[ ! "${CORE_VERSION}" > "1.0.0-preview1-002702" ]]; then
CORE_CHANNEL="beta"
fi
fi
fi

if [[ "${CORE_VERSION}" == "latest" && -e "${DEPLOYMENT_FILE_LOCATION}" ]]; then
CORE_CHANNEL_TMP=$(awk -F "=" '/channel/ {print $2}' ${DEPLOYMENT_FILE_LOCATION} | tr -d ' ')
if [ ! -z "${CORE_CHANNEL_TMP}" ]; then
CORE_CHANNEL="${CORE_CHANNEL_TMP}"
fi
fi

# Install DNX
# TODO: consider making this not dependent on GitHub being up
touch ~/.profile
curl -sSL https://raw.githubusercontent.com/aspnet/Home/${DNVM_BRANCH}/dnvminstall.sh \
| sh && source ~/.dnx/dnvm/dnvm.sh
# Temporary fix noliar/dotnet-buildpack#8
if [[ "${CORE_VERSION}" == "latest" && "${CORE_CHANNEL}" == "preview" ]]; then
CORE_VERSION="1.0.0-preview2-003121"
fi

export DNVM_RUNTIME_LOCAL_CACHE="/app/.dnx"
export DNVM_RUNTIME_CACHE_LOCATION="${CACHE_DIR}/dnx/runtimes"
mkdir -p ${DNVM_RUNTIME_LOCAL_CACHE}
mkdir -p ${DNVM_RUNTIME_CACHE_LOCATION}
ln -s ${DNVM_RUNTIME_CACHE_LOCATION} ${DNVM_RUNTIME_LOCAL_CACHE}/runtimes
CORE_VERSION_FIRST="$CORE_VERSION"

# TODO: extract DNX version from global.json
dnvm install $DNX_VERSION $DNVM_FLAGS -a default
if [[ "${CORE_VERSION}" == "latest" ]]; then
CORE_VERSION_FIRST="Latest"
fi

# Add DNX to the build output
DNX_BUILD_LOCATION=${BUILD_DIR}/.dnx/runtimes/
mkdir -p ${DNX_BUILD_LOCATION}
cp -r ~/.dnx/runtimes/`dnvm alias default` ${DNX_BUILD_LOCATION}
: ${CORE_DOWNLOAD_LOCATION:="https://dotnetcli.blob.core.windows.net/dotnet/${CORE_CHANNEL}/Binaries/${CORE_VERSION_FIRST}/dotnet-dev-ubuntu-x64.${CORE_VERSION}.tar.gz"}

echo "Installing the dependencies"
apt_install libunwind8 gettext

mkdir -p ${BUILD_DIR}/dotnet

echo "Installing .NET CORE ${CORE_VERSION} from ${CORE_DOWNLOAD_LOCATION}"
# dotnet-install.sh using `ldconfig` which search pkg in `/lib` or `/usr/lib`. So I change it to binaries.
#curl -sSL ${CORE_SCRIPT_LOCATION} | bash /dev/stdin --version ${CORE_VERSION} --install-dir ${BUILD_DIR}/dotnet
curl ${CORE_DOWNLOAD_LOCATION} -Ls | tar xz -C ${BUILD_DIR}/dotnet
ln -s ${BUILD_DIR}/dotnet /app

export PATH="/app/dotnet:${PATH}"
export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}"

DEPLOYMENT_FILE_LOCATION=${SRC_DIR}/.deployment
if [ -n "$PROJECT" ]; then
PROJECT_JSON_FILE=${SRC_DIR}/${PROJECT}
echo "Project file configured in PROJECT environment variable"
elif [ -e ${DEPLOYMENT_FILE_LOCATION} ]; then
PROJECT_JSON_FILE=${SRC_DIR}/$(awk -F "=" '/project/ {print $2}' ${DEPLOYMENT_FILE_LOCATION} | tr -d ' ')
echo "Project file configured in .deployment file"
else
PROJECT_JSON_FILES=$(find ${SRC_DIR}/. -maxdepth 3 -iname "project.json")
PROJECT_JSON_FILES=$(find ${SRC_DIR}/. -maxdepth 5 -iname "project.json")
printf 'Found %s project.json files\n' $(echo "$PROJECT_JSON_FILES" | wc -l | tr -d ' ')
PROJECT_JSON_FILE=$(echo "$PROJECT_JSON_FILES" | head -1)
PROJECT_JSON_FILE=$(readlink -m $PROJECT_JSON_FILE)
fi
echo "Building ${PROJECT_JSON_FILE}"

export DNU_LOCAL_CACHE="/app/.local/share/dnu"
export DNU_CACHE_LOCATION="${CACHE_DIR}/dnu/cache"
mkdir -p ${DNU_LOCAL_CACHE}
mkdir -p ${DNU_CACHE_LOCATION}
ln -s ${DNU_CACHE_LOCATION} ${DNU_LOCAL_CACHE}/cache
PROJECT_DIR="$PROJECT_JSON_FILE"
if [[ -f $PROJECT_JSON_FILE ]]; then
PROJECT_DIR=$(dirname $PROJECT_JSON_FILE)
fi

echo "Reading App Name from project.json"
PROJECT_DIR_NAME=$(basename $PROJECT_DIR)
PROJECT_NAME=$(ruby -rjson -e "j = JSON.parse(File.open('${PROJECT_DIR}/project.json','r:bom|utf-8').read); unless j['buildOptions'].nil? ; puts j['buildOptions']['outputName'];end")
echo "${PROJECT_NAME:=$PROJECT_DIR_NAME}"

echo "Restoring the packages"
dotnet restore ${SRC_DIR}

dnu restore $DNU_FLAGS ${PROJECT_JSON_FILE}
# configure some npm command during building
export PATH="${PROJECT_DIR}/node_modules/.bin:${PATH}"

dnu publish --out ${BUILD_DIR} $DNU_FLAGS --no-source --configuration Release ${PROJECT_JSON_FILE}
echo "Publishing the app"
# Publish to heroku_output
dotnet publish ${PROJECT_JSON_FILE} --output ${BUILD_DIR}/heroku_output --configuration ${CORE_CONFIGURATION}

# Clean out core-stuff that we don't need in the slug
find ${BUILD_DIR} -iname dnxcore50 -print0 | xargs -r -0 rm --
echo "Publish Successed"

mkdir -p ${BUILD_DIR}/.profile.d
cp -n ${BUILDPACK_DIR}/.profile.d/* ${BUILD_DIR}/.profile.d/

curl https://github.com/friism/libuv-builder/releases/download/v${LIBUV_VERSION}/libuv-${LIBUV_VERSION}.tar.gz -sL \
| tar xz -C ${BUILD_DIR}
if [ -e ${SRC_DIR}/Procfile ]; then
cp ${SRC_DIR}/Procfile ${BUILD_DIR}
else
ROOTS=`cd ${BUILD_DIR}; find approot/packages/ -name root`
if [ $( echo "${ROOTS}" | wc -l ) -gt 0 ]; then
APP_ROOT=$(echo "$ROOTS" | head -1)
cat << EOT >> ${BUILD_DIR}/Procfile
web: ./kestrel --server.urls http://+:\$PORT
web: cd \$HOME/heroku_output && dotnet ./${PROJECT_NAME}.dll --server.urls http://+:\$PORT ${CORE_ENVIRONMENT}
EOT
fi
fi
4 changes: 2 additions & 2 deletions bin/detect
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env bash
# bin/detect <build-dir>

if [ -n "$( find $1 -maxdepth 3 -iname project.json )" ]; then
echo "ASP.NET 5" && exit 0
if [ -n "$( find $1 -maxdepth 5 -iname project.json )" ]; then
echo "ASP.NET Core" && exit 0
else
echo "no" && exit 1
fi
61 changes: 60 additions & 1 deletion bin/util
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function conditional_download() {

function export_env_dir() {
local env_dir=$1
local whitelist_regex=${2:-'(DEPENDENCY_S3_BUCKET_PATH|MONO_VERSION|LIBUV_VERSION|NODE_VERSION|PROJECT|BUILD_DEBUG|DNVM_BRANCH|DNX_VERSION)$'}
local whitelist_regex=${2:-'(DEPENDENCY_S3_BUCKET_PATH|MONO_VERSION|LIBUV_VERSION|NODE_VERSION|PROJECT|BUILD_DEBUG|CORE_VERSION|CORE_CHANNEL|CORE_DOWNLOAD_LOCATION|DEFAULT_CONNECTION|DefaultConnection|DATABASE_URL|JAWSDB_MARIA_URL|JAWSDB_URL|CLEARDB_DATABASE_URL)$'}
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
Expand All @@ -24,3 +24,62 @@ function export_env_dir() {
done
fi
}

# based on ddollar/heroku-buildpack-apt which is deprecated
function apt_install(){
echo "Install package"

local apt_cache_dir="$CACHE_DIR/apt/cache"
local apt_state_dir="$CACHE_DIR/apt/state"

mkdir -p "$apt_cache_dir/archives/partial"
mkdir -p "$apt_state_dir/lists/partial"

local apt_options="-o debug::nolocking=true -o dir::cache=$apt_cache_dir -o dir::state=$apt_state_dir"

topic "Cleaning apt caches"
apt-get $apt_options clean | indent

topic "Updating apt caches"
apt-get --allow-unauthenticated $apt_options update | indent

for package in "$@"; do
if [[ $package == *deb ]]; then
local package_name=$(basename $package .deb)
local package_file=$apt_cache_dir/archives/$package_name.deb
topic "Fetching $package"
curl -s -L -z $package_file -o $package_file $package 2>&1 | indent
else
topic "Fetching .debs for $package"
apt-get $apt_options -y --force-yes -d install --reinstall $package | indent
fi
done

mkdir -p "$BUILD_DIR/.apt"

for DEB in $(ls -1 $apt_cache_dir/archives/*.deb); do
topic "Installing $(basename $DEB)"
dpkg -x $DEB "$BUILD_DIR/.apt/"
done

export PATH="$PATH:$BUILD_DIR/.apt/usr/bin"
export LD_LIBRARY_PATH="$BUILD_DIR/.apt/usr/lib/x86_64-linux-gnu:$BUILD_DIR/.apt/usr/lib/i386-linux-gnu:$BUILD_DIR/.apt/usr/lib:$LD_LIBRARY_PATH"
export LIBRARY_PATH="$BUILD_DIR/.apt/usr/lib/x86_64-linux-gnu:$BUILD_DIR/.apt/usr/lib/i386-linux-gnu:$BUILD_DIR/.apt/usr/lib:$LIBRARY_PATH"
export INCLUDE_PATH="$BUILD_DIR/.apt/usr/include:$INCLUDE_PATH"
export CPATH="$INCLUDE_PATH"
export CPPPATH="$INCLUDE_PATH"
export PKG_CONFIG_PATH="$BUILD_DIR/.apt/usr/lib/x86_64-linux-gnu/pkgconfig:$BUILD_DIR/.apt/usr/lib/i386-linux-gnu/pkgconfig:$BUILD_DIR/.apt/usr/lib/pkgconfig:$PKG_CONFIG_PATH"
echo "APT packages Installled"
}

function topic() {
echo "-----> $*"
}

function indent() {
c='s/^/ /'
case $(uname) in
Darwin) sed -l "$c";;
*) sed -u "$c";;
esac
}