| #!/bin/bash |
| # Copyright 2015 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| APP_YAML="app.yaml" |
| DEFAULT_SDK_MIRROR="https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.19.zip" |
| # Apps can further modify the appengine sdk by providing this shell script in |
| # their top level directory. This is needed because the turnaround time to |
| # submitting patches upstream to the SDK is rather large. |
| # WARNING: Remember that this only changes the local installation of the SDK. |
| # So, this is only useful to fix bugs that make local development hard. AE |
| # will use a non-patched version of the SDK. |
| # The script will be run as: |
| # sdk_mod <absolute/path/to/sdk> |
| APPENGINE_SDK_MOD_FILE="appengine_sdk_mod" |
| |
| PYTHONPATH_PREFIX="" |
| PATH_PREFIX="" |
| PS1_PREFIX="" |
| |
| usage() { |
| cat << EOF |
| Usage: ${BASH_SOURCE} <app_dir> |
| |
| Use this script to enter an environment to develop an appengine app in. |
| This script will: |
| - Download the requested version of SDK if it's not already available. |
| - Set up the environment in the new shell so that relevant SDK and project |
| tools are available, and PYTHONPATH is setup to use these tools. |
| |
| You can create some files under your toplevel directory to modify the |
| behaviour of this script for your project: |
| - appengine_sdk_mod: A bash script that will be executed by this script as: |
| ./fancy_project/appengine_sdk_mod <absolute/path/to/AE/SDK> |
| This script can be used to modify the *local installation only* of the |
| SDK. This can, for example, fixup the SDK to ease local development. |
| For an example, see cq_stats/appengine_sdk_mod. |
| EOF |
| } |
| |
| enter_ae_shell() { |
| local rcfile="$(mktemp)" |
| |
| cat >"${rcfile}" << EOF |
| [[ -e ~/.bashrc ]] && source ~/.bashrc |
| |
| export PYTHONPATH="${PYTHONPATH_PREFIX}:\${PYTHONPATH}" |
| export PATH="${PATH_PREFIX}:\${PATH}" |
| export PS1="${PS1_PREFIX} \${PS1}" |
| |
| # Clear BASH_ENV so that if a subshell is launched, we don't |
| # get sourced twice. (This file is going to dissapear after the first time it's |
| # sourced.) |
| unset BASH_ENV |
| rm -f "${rcfile}" |
| EOF |
| |
| info "Entering ae_shell for ${appname}..." |
| if [[ $# -eq 0 ]]; then |
| # Enter a shell that will survive successful completion of this script, and |
| # will have the new environment setup for the user. |
| exec bash --rcfile "${rcfile}" -i |
| else |
| # A command was given, run that command in the new shell. |
| # bash will ignore BASH_ENV if it detects that it's launched by sshd. |
| # Trick it! |
| unset SSH_CLIENT |
| unset SSH_CONNECTION |
| unset SSH_TTY |
| BASH_ENV=${rcfile} exec bash -c '"$@"' "$@" |
| fi |
| } |
| |
| prepare_sdk() { |
| local -r appengine_dir="$1" |
| local -r ae_sdk_dir="$2" |
| local -r appname="$3" |
| |
| if [[ ! -d "${ae_sdk_dir}" ]]; then |
| local temp_ae_sdk_dir="temp_ae_sdk_dir" |
| |
| info "Using appegine SDK mirror ${DEFAULT_SDK_MIRROR}" |
| |
| rm -rf "${temp_ae_sdk_dir}" |
| mkdir -p "${temp_ae_sdk_dir}" |
| info "Downloading appengine SDK" |
| local sdk_zip="${temp_ae_sdk_dir}/sdk.zip" |
| wget -c "${DEFAULT_SDK_MIRROR}" -O "${sdk_zip}" |
| if [[ $? -ne 0 ]]; then |
| error "Failed to download SDK from ${DEFAULT_SDK_MIRROR}" |
| rm -rf "${temp_ae_sdk_dir}" |
| return ${E_GENERAL} |
| fi |
| |
| info "Unpacking..." |
| unzip -q "${sdk_zip}" -d "${temp_ae_sdk_dir}" |
| if [[ $? -ne 0 ]]; then |
| error "Failed to unzip ${sdk_zip}." |
| rm -rf "${temp_ae_sdk_dir}" |
| return ${E_GENERAL} |
| fi |
| |
| mv "${temp_ae_sdk_dir}/google_appengine" "${ae_sdk_dir}" |
| rm -rf "${temp_ae_sdk_dir}" |
| |
| if [[ -f "${appname}/${APPENGINE_SDK_MOD_FILE}" ]]; then |
| info "Running appengine sdk mod script from " \ |
| "${appname}/${APPENGINE_SDK_MOD_FILE}" |
| if ! "./${appname}/${APPENGINE_SDK_MOD_FILE}" \ |
| "${appengine_dir}/${ae_sdk_dir}"; then |
| return ${E_GENERAL} |
| fi |
| fi |
| fi |
| |
| info "Using appengine SDK at ${ae_sdk_dir}" |
| return 0 |
| } |
| |
| setup_django_path() { |
| local -r appengine_dir="$1" |
| local -r ae_sdk_dir="$2" |
| local -r appname="$3" |
| |
| if [[ ! -f "${appname}/${APP_YAML}" ]]; then |
| return ${E_GENERAL} |
| fi |
| |
| local django_version |
| django_version="$(awk '$0 == "- name: django" { getline; print $NF }' \ |
| "${appname}/${APP_YAML}")" |
| if [[ -z "${django_version}" ]]; then |
| return ${E_GENERAL} |
| fi |
| |
| info "Setting django version to ${django_version}" |
| django_dir="${ae_sdk_dir}/lib/django-${django_version}" |
| PYTHONPATH_PREFIX="${appengine_dir}/${django_dir}:${PYTHONPATH_PREFIX}" |
| PATH_PREFIX="${appengine_dir}/${django_dir}/django/bin:${PATH_PREFIX}" |
| } |
| |
| # This sets up the chromite path so that chromite is available inside ae_shell. |
| # Note that this is different from using chromite/scripts/wrapper.py because the |
| # appengine apps that launched / deployed inside the ae_shell run in an |
| # environment controlled by the AE SDK's dev_appserver.py |
| # This ensures that chromite is available inside that environment as well. |
| setup_chromite_path() { |
| local -r appengine_dir="$1" |
| # Must go deeper. |
| local basedir |
| base_dir="$(dirname "$(dirname "${appengine_dir}")")" |
| PYTHONPATH_PREFIX="${base_dir}:${PYTHONPATH_PREFIX}" |
| } |
| |
| main() { |
| local -r appengine_dir="$(readlink -e "$(dirname "${BASH_SOURCE}")")" |
| source "${appengine_dir}/common.sh" |
| |
| # Argument parsing. |
| local -r appdir="$1" |
| shift |
| |
| if [[ $# -gt 0 && "$1" != "--" ]]; then |
| error "Unexpected argument: $1" |
| usage |
| exit ${E_GENERAL} |
| fi |
| # End argument parsing. |
| |
| local -r appname="$(basename "${appdir}")" |
| local -r ae_sdk_dir="google_appengine_${appname}" |
| |
| local appname_shell="$(echo "${appname}" | tr '[:lower:]' '[:upper:]')" |
| |
| if [[ ! -d "${appdir}" ]]; then |
| error "'${appdir}' is not an appengine app source directory!" |
| usage |
| exit ${E_GENERAL} |
| fi |
| |
| info "Found appengine directory ${appengine_dir}" |
| info "Found appengine app ${appname} at ${appdir}" |
| |
| pushd "${appengine_dir}" >/dev/null |
| |
| if ! prepare_sdk "${appengine_dir}" "${ae_sdk_dir}" "${appname}"; then |
| exit ${E_GENERAL} |
| fi |
| |
| setup_django_path "${appengine_dir}" "${ae_sdk_dir}" "${appname}" |
| setup_chromite_path "${appengine_dir}" |
| PYTHONPATH_PREFIX="${appengine_dir}/${ae_sdk_dir}:${PYTHONPATH_PREFIX}" |
| PYTHONPATH="${appengine_dir}/${appname}:${PYTHONPATH}" |
| PATH_PREFIX="${appengine_dir}/${ae_sdk_dir}:${appengine_dir}:${PATH_PREFIX}" |
| PS1_PREFIX="AE:${appname_shell}${PS1_PREFIX}" |
| |
| popd >/dev/null |
| enter_ae_shell "$@" |
| } |
| |
| main "$@" |