Created
June 24, 2017 17:36
-
-
Save double-z/cef86808d9b76036af2cb9fb93a679d5 to your computer and use it in GitHub Desktop.
Experiments to deal with node/npm/react on rails with habitat scaffolding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pkg_name=sharetribe | |
pkg_origin=zz. | |
pkg_version="0.1.6" | |
pkg_deps=(core/node/7.8.0) | |
pkg_build_deps=(core/node/7.8.0 core/mysql-client core/tzdata) | |
pkg_scaffolding=zz/scaffolding-ruby-react | |
# scaffolding_env[SECRET_KEY_BASE]=('4454a5818096fc29cebdb5ad03e619fdd80be79c3d6041ec9ea00b36b00a246143ff391012cf4d54b29377a17dba96d00c19e9d8ab9e3411c57a74607031896b') | |
# scaffolding_node_pkg_manager=npm | |
do_prepare() { | |
# attach | |
cp -rfpv . "$CACHE_PATH/" | |
# if [[ -d "client" ]]; then | |
# build_line "COPYING from $(pwd) to $CACHE_PATH" | |
# cp -rfv package.json "$CACHE_PATH/" | |
# cp -rfv client "$CACHE_PATH/" | |
# fi | |
do_default_prepare | |
return $? | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# shellcheck shell=bash disable=SC2086 | |
scaffolding_load() { | |
_setup_funcs | |
_setup_vars | |
pushd "$SRC_PATH" > /dev/null | |
: ${node_enabled=:} | |
_detect_package_json | |
rc=$? | |
if [[ $rc -eq 0 ]]; then | |
export node_enabled="true" | |
_detect_node | |
_detect_node_pkg_manager | |
fi | |
_detect_gemfile | |
_detect_app_type | |
_detect_missing_gems | |
_detect_process_bins | |
_update_vars | |
_update_pkg_build_deps | |
_update_pkg_deps | |
_update_bin_dirs | |
_update_svc_run | |
popd > /dev/null | |
} | |
do_ruby_prepare() { | |
local gem_dir gem_path | |
# Determine Ruby engine, ABI version, and Gem path by running `ruby` itself. | |
eval "$(ruby -rubygems -rrbconfig - <<-'EOF' | |
puts "local ruby_engine=#{defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'}" | |
puts "local ruby_version=#{RbConfig::CONFIG['ruby_version']}" | |
puts "local gem_path='#{Gem.path.join(':')}'" | |
EOF | |
)" | |
# Strip out any home directory entries at the front of the gem path. | |
# shellcheck disable=SC2001 | |
gem_path=$(echo "$gem_path" | sed 's|^/root/\.gem/[^:]\{1,\}:||') | |
# Compute gem directory where gems will be ultimately installed to | |
gem_dir="$scaffolding_app_prefix/vendor/bundle/$ruby_engine/$ruby_version" | |
# Compute gem directory where gems are initially installed to via Bundler | |
_cache_gem_dir="$CACHE_PATH/vendor/bundle/$ruby_engine/$ruby_version" | |
# Silence Bundler warning when run as root user | |
export BUNDLE_SILENCE_ROOT_WARNING=1 | |
GEM_HOME="$gem_dir" | |
build_line "Setting GEM_HOME=$GEM_HOME" | |
GEM_PATH="$gem_dir:$gem_path" | |
build_line "Setting GEM_PATH=$GEM_PATH" | |
export GEM_HOME GEM_PATH | |
} | |
do_node_prepare() { | |
export NODE_ENV=production | |
npm_dir="$scaffolding_app_prefix/vendor/bundle/$ruby_engine/$ruby_version" | |
npm_client_dir="$CACHE_PATH" | |
npm_install="$CACHE_PATH/client" | |
npm_client_install="$scaffolding_app_prefix/client" | |
build_line "Setting NODE_ENV=$NODE_ENV" | |
} | |
do_default_prepare() { | |
do_ruby_prepare | |
do_node_prepare | |
} | |
do_default_build() { | |
# TODO fin: add cache loading of `$CACHE_PATH/vendor` | |
# TODO fin: add cache loading of `$CACHE_PATH/node_modules` | |
# TODO fin: support prebuild step? | |
scaffolding_bundle_install | |
# build_line "Cleaning old cached gems" | |
# _bundle clean --dry-run --force | |
# TODO fin: add cache saving of `$CACHE_PATH/vendor` | |
scaffolding_remove_gem_cache | |
scaffolding_fix_rubygems_shebangs | |
if [[ $node_enabled = "true" ]]; then | |
scaffolding_npm_install | |
scaffolding_fix_node_shebangs | |
scaffolding_fix_node_client_shebangs | |
fi | |
scaffolding_setup_app_config | |
scaffolding_setup_node_app_config | |
scaffolding_setup_database_config | |
# TODO fin: support postbuild step? | |
# TODO fin: add cache saving of `$CACHE_PATH/node_modules` | |
} | |
do_default_install() { | |
if [[ $node_enabled = "true" ]]; then | |
scaffolding_install_node_modules | |
scaffolding_install_node_client | |
fi | |
scaffolding_install_app | |
scaffolding_install_gems | |
# Do Node npm install | |
scaffolding_generate_binstubs | |
scaffolding_vendor_bundler | |
scaffolding_install_libexec | |
scaffolding_fix_binstub_shebangs | |
scaffolding_log_process_bins | |
attach | |
scaffolding_run_assets_precompile | |
scaffolding_create_dir_symlinks | |
scaffolding_create_files_symlinks | |
scaffolding_create_process_bins | |
} | |
# do_node_install() { | |
# # scaffolding_install_app | |
# scaffolding_install_node_modules | |
# scaffolding_create_process_bins | |
# } | |
# do_default_install() { | |
# do_ruby_install | |
# do_node_install | |
# } | |
# This becomes the `do_default_build_config` implementation thanks to some | |
# function "renaming" above. I know, right? | |
_new_do_default_build_config() { | |
local key dir env_sh | |
_stock_do_default_build_config | |
if [[ ! -f "$PLAN_CONTEXT/hooks/init" ]]; then | |
build_line "No user-defined init hook found, generating init hook" | |
mkdir -p "$pkg_prefix/hooks" | |
cat <<EOT >> "$pkg_prefix/hooks/init" | |
#!/bin/sh | |
set -e | |
export HOME="$pkg_svc_data_path" | |
. '$pkg_svc_config_path/app_env.sh' | |
# Create a directory for each app symlinked dir under $pkg_svc_var_path | |
$( | |
for dir in "${scaffolding_symlinked_dirs[@]}"; do | |
echo "mkdir -pv '$pkg_svc_var_path/$dir'" | |
done | |
) | |
$( | |
case "$_app_type" in | |
(rails5|rails42|rails41) | |
cat <<_RAILS_ | |
# Check that the 'SECRET_KEY_BASE' environment variable is non-empty | |
if [ -z "\${SECRET_KEY_BASE:-}" ]; then | |
>&2 echo "Required environment variable SECRET_KEY_BASE is not set." | |
>&2 echo "Set this package's config setting 'secret_key_base' to a" | |
>&2 echo "non-empty value. You can run 'rails secret' in development" | |
>&2 echo "to generate a random key string." | |
>&2 echo "" | |
>&2 echo "Aborting..." | |
exit 5 | |
fi | |
_RAILS_ | |
;; | |
esac | |
if [[ "${_uses_pg:-}" == "true" \ | |
|| "${_uses_mysql:-}" == "true" ]]; then | |
cat <<_PG_ | |
# Confirm an initial database connection | |
if ! $pkg_prefix/libexec/is_db_connected; then | |
>&2 echo "" | |
>&2 echo "A database connection is required for this app to properly boot." | |
>&2 echo "Is the database not running or are the database connection" | |
>&2 echo "credentials incorrect?" | |
>&2 echo "" | |
{{~#if bind.database}} | |
>&2 echo "This app started with a database bind and will discovery the" | |
>&2 echo "hostname and port number in the Habitat ring." | |
>&2 echo "" | |
>&2 echo "There are 3 remaining config settings which must be set correctly:" | |
{{else}} | |
>&2 echo "This app started without a database bind meaning that the" | |
>&2 echo "database is assumed to be running outside of a Habitat ring." | |
>&2 echo "Therefore, you must provide all the database connection values." | |
>&2 echo "" | |
>&2 echo "There are 5 config settings which must be set correctly:" | |
{{~/if}} | |
>&2 echo "" | |
{{~#unless bind.database}} | |
>&2 echo " * db.host - The database hostname or IP address (Current: {{#if cfg.db.host}}{{cfg.db.host}}{{else}}<unset>{{/if}})" | |
>&2 echo " * db.port - The database listen port number (Current: {{#if cfg.db.port}}{{cfg.db.port}}{{else}}5432{{/if}})" | |
{{~/unless}} | |
>&2 echo " * db.user - The database username (Current: {{#if cfg.db.user}}{{cfg.db.user}}{{else}}<unset>{{/if}})" | |
>&2 echo " * db.password - The database password (Current: {{#if cfg.db.password}}<set>{{else}}<unset>{{/if}})" | |
>&2 echo " * db.name - The database name (Current: {{#if cfg.db.name}}{{cfg.db.name}}{{else}}<unset>{{/if}})" | |
>&2 echo "" | |
>&2 echo "Aborting..." | |
exit 15 | |
fi | |
_PG_ | |
fi | |
) | |
EOT | |
chmod 755 "$pkg_prefix/hooks/init" | |
fi | |
if [[ -f "$CACHE_PATH/default.scaffolding.toml" ]]; then | |
build_line "Appending Scaffolding defaults to $pkg_prefix/default.toml" | |
cat "$CACHE_PATH/default.scaffolding.toml" >> "$pkg_prefix/default.toml" | |
fi | |
env_sh="$pkg_prefix/config/app_env.sh" | |
mkdir -p "$(dirname "$env_sh")" | |
for key in "${!scaffolding_env[@]}"; do | |
echo "export $key='${scaffolding_env[$key]}'" >> "$env_sh" | |
done | |
} | |
# | |
# Ruby | |
# | |
scaffolding_bundle_install() { | |
local start_sec elapsed dot_bundle | |
# Attempt to preserve any original Bundler config by moving it to the side | |
if [[ -f .bundle/config ]]; then | |
mv .bundle/config .bundle/config.prehab | |
dot_bundle=true | |
elif [[ -d .bundle ]]; then | |
dot_bundle=true | |
fi | |
build_line "Installing dependencies using $(_bundle --version)" | |
start_sec="$SECONDS" | |
_bundle_install \ | |
"$CACHE_PATH/vendor/bundle" \ | |
--retry 5 | |
elapsed=$((SECONDS - start_sec)) | |
elapsed=$(echo $elapsed | awk '{printf "%dm%ds", $1/60, $1%60}') | |
build_line "Bundle completed ($elapsed)" | |
# If we preserved the original Bundler config, move it back into place | |
if [[ -f .bundle/config.prehab ]]; then | |
rm -f .bundle/config | |
mv .bundle/config.prehab .bundle/config | |
rm -f .bundle/config.prehab | |
fi | |
# If not `.bundle/` directory existed before, then clear it out now | |
if [[ -z "${dot_bundle:-}" ]]; then | |
rm -rf .bundle | |
fi | |
} | |
scaffolding_npm_install() { | |
if [[ -n "${_uses_git:-}" ]]; then | |
if ! git check-ignore node_modules && [[ -d node_modules ]]; then | |
warn "Detected directory 'node_modules' is not in .gitignore and is" | |
warn "not empty. The contents of 'node_modules' will not be used when" | |
warn "building this app." | |
warn "It is not recommended to commit your node modules into your" | |
warn "codebase." | |
fi | |
fi | |
build_line "Installing dependencies using $node_pkg_manager $("$node_pkg_manager" --version)" | |
start_sec="$SECONDS" | |
case "$node_pkg_manager" in | |
npm) | |
if [[ ! -f "$CACHE_PATH/package.json" ]]; then | |
cp -av package.json "$CACHE_PATH/" | |
fi | |
if [[ -f "npm-shrinkwrap.json" ]]; then | |
cp -av npm-shrinkwrap.json "$CACHE_PATH/" | |
fi | |
if [[ -n "$HAB_NONINTERACTIVE" ]]; then | |
export NPM_CONFIG_PROGRESS=false | |
fi | |
pushd "$CACHE_PATH" > /dev/null | |
npm install \ | |
--unsafe-perm \ | |
--production \ | |
--loglevel error \ | |
--fetch-retries 5 \ | |
--userconfig "$CACHE_PATH/.npmrc" | |
npm list --json > npm-list.json | |
popd > /dev/null | |
;; | |
yarn) | |
local extra_args | |
if [[ -n "$HAB_NONINTERACTIVE" ]]; then | |
extra_args="--no-progress" | |
fi | |
yarn install $extra_args \ | |
--pure-lockfile \ | |
--ignore-engines \ | |
--production \ | |
--modules-folder "$CACHE_PATH/node_modules" \ | |
--cache-folder "$CACHE_PATH/yarn_cache" | |
;; | |
*) | |
local e | |
e="Internal error: package manager variable" | |
e="$e not correctly set: '$node_pkg_manager'" | |
exit_with "$e" 9 | |
;; | |
esac | |
elapsed=$((SECONDS - start_sec)) | |
elapsed=$(echo $elapsed | awk '{printf "%dm%ds", $1/60, $1%60}') | |
build_line "Dependency installation completed ($elapsed)" | |
return 0 | |
} | |
scaffolding_install_node_modules() { | |
build_line "Installing vendored Node modules to $scaffolding_app_prefix/node_modules" | |
rm -rf "$scaffolding_app_prefix/node_modules" | |
cp -a "$CACHE_PATH/node_modules" "$scaffolding_app_prefix/" | |
if [[ -f "$CACHE_PATH/npm-list.json" \ | |
&& ! -f "$scaffolding_app_prefix/npm-list.json" ]]; then | |
cp -av "$CACHE_PATH/npm-list.json" "$scaffolding_app_prefix/" | |
fi | |
} | |
scaffolding_install_node_client() { | |
build_line "Installing vendored Node modules to $scaffolding_app_prefix/client/node_modules" | |
if [[ -d "$scaffolding_app_prefix/client" ]]; then | |
rm -rfv "$scaffolding_app_prefix/client" | |
fi | |
cp -a "$CACHE_PATH/client" "$scaffolding_app_prefix/" | |
} | |
scaffolding_remove_gem_cache() { | |
build_line "Removing installed gem cache" | |
rm -rf "$_cache_gem_dir/cache" | |
} | |
scaffolding_fix_rubygems_shebangs() { | |
local shebang | |
shebang="#!$(pkg_path_for "$_ruby_pkg")/bin/ruby" | |
build_line "Fixing Ruby shebang for RubyGems bins" | |
find "$_cache_gem_dir/bin" -type f | while read -r bin; do | |
sed -e "s|^#!.\{0,\}\$|${shebang}|" -i "$bin" | |
done | |
} | |
scaffolding_fix_node_shebangs() { | |
local shebang bin_path | |
shebang="#!$(pkg_path_for "$_node_pkg")/bin/node" | |
bin_path="$CACHE_PATH/node_modules/.bin" | |
build_line "Fixing Node shebang for node_module bins" | |
if [[ -d "$bin_path" ]]; then | |
find "$bin_path" -type f -o -type l | while read -r bin; do | |
sed -e "s|^#!.\{0,\}\$|${shebang}|" -i "$(readlink -f "$bin")" | |
done | |
fi | |
} | |
scaffolding_fix_node_client_shebangs() { | |
local shebang bin_path | |
shebang="#!$(pkg_path_for "$_node_pkg")/bin/node" | |
bin_path="$CACHE_PATH/client/node_modules/.bin" | |
build_line "Fixing Node shebang for client node_module bins" | |
if [[ -d "$bin_path" ]]; then | |
find "$bin_path" -type f -o -type l | while read -r bin; do | |
sed -e "s|^#!.\{0,\}\$|${shebang}|" -i "$(readlink -f "$bin")" | |
done | |
fi | |
} | |
scaffolding_setup_app_config() { | |
local t | |
t="$CACHE_PATH/default.scaffolding.toml" | |
echo "" >> "$t" | |
if _default_toml_has_no secret_key_base \ | |
&& [[ -v "scaffolding_env[SECRET_KEY_BASE]" ]]; then | |
{ echo "# Rails' secret key base is required and must be non-empty" | |
echo "# You can run 'rails secret' in development to generate" | |
echo "# a random key string." | |
echo 'secret_key_base = ""' | |
echo "" | |
} >> "$t" | |
fi | |
if _default_toml_has_no lang; then | |
echo 'lang = "en_US.UTF-8"' >> "$t" | |
fi | |
if _default_toml_has_no rack_env \ | |
&& [[ -v "scaffolding_env[RACK_ENV]" ]]; then | |
echo 'rack_env = "production"' >> "$t" | |
fi | |
if _default_toml_has_no rails_env \ | |
&& [[ -v "scaffolding_env[RAILS_ENV]" ]]; then | |
echo 'rails_env = "production"' >> "$t" | |
fi | |
if _default_toml_has_no app; then | |
echo "" >> "$t" | |
echo '[app]' >> "$t" | |
if _default_toml_has_no app.port; then | |
echo "port = $scaffolding_app_port" >> "$t" | |
fi | |
fi | |
} | |
scaffolding_setup_node_app_config() { | |
local t | |
t="$CACHE_PATH/default.scaffolding.toml" | |
if _default_toml_has_no node_env \ | |
&& [[ -v "scaffolding_env[NODE_ENV]" ]]; then | |
echo 'node_env = "production"' >> "$t" | |
fi | |
} | |
scaffolding_setup_database_config() { | |
local _adapter | |
if [[ "${_uses_pg:-}" == "true" ]]; then | |
_adapter="postgres" | |
elif [[ "${_uses_mysql:-}" == "true" ]]; then | |
_adapter="mysql2" | |
fi | |
if [[ -n "${_adapter:-}" ]]; then | |
local db t | |
db="${_adapter}://{{cfg.db.user}}:{{cfg.db.password}}" | |
db="${db}@{{#if bind.database}}{{bind.database.first.sys.ip}}{{else}}{{#if cfg.db.host}}{{cfg.db.host}}{{else}}db.host.not.set{{/if}}{{/if}}" | |
db="${db}:{{#if bind.database}}{{bind.database.first.cfg.port}}{{else}}{{#if cfg.db.port}}{{cfg.db.port}}{{else}}5432{{/if}}{{/if}}" | |
db="${db}/{{cfg.db.name}}" | |
_set_if_unset scaffolding_env DATABASE_URL "$db" | |
# Add an optional binding called `database` which will be the PostgreSQL | |
# database | |
_set_if_unset pkg_binds_optional database "port" | |
t="$CACHE_PATH/default.scaffolding.toml" | |
if _default_toml_has_no db; then | |
{ echo "" | |
echo "[db]" | |
} >> "$t" | |
if _default_toml_has_no db.name; then | |
echo "name = \"${pkg_name}_production\"" >> "$t" | |
fi | |
if _default_toml_has_no db.user; then | |
echo "user = \"${pkg_name}\"" >> "$t" | |
fi | |
if _default_toml_has_no db.password; then | |
echo "password = \"${pkg_name}\"" >> "$t" | |
fi | |
fi | |
fi | |
} | |
## | |
# Begin Install Functions | |
scaffolding_install_app() { | |
build_line "Installing app codebase to $scaffolding_app_prefix" | |
mkdir -pv "$scaffolding_app_prefix" | |
if [[ -n "${_uses_git:-}" ]]; then | |
# Use git commands to skip any git-ignored files and directories including | |
# the `.git/ directory. Current on-disk state of all files is used meaning | |
# that dirty and unstaged files are included which should help while | |
# working on package builds. | |
build_line "Using Git to install app from $(pwd)" | |
{ git ls-files; git ls-files --exclude-standard --others; } \ | |
| _tar_pipe_app_cp_to "$scaffolding_app_prefix" | |
else | |
# Use find to enumerate all files and directories for copying. This is the | |
# safe-fallback strategy if no version control software is detected. | |
build_line "NOT Using Git to install app from $(pwd)" | |
find . | _tar_pipe_app_cp_to "$scaffolding_app_prefix" | |
fi | |
} | |
scaffolding_install_gems() { | |
mkdir -pv "$scaffolding_app_prefix/vendor" | |
build_line "Installing vendored gems to $scaffolding_app_prefix/vendor/bundle" | |
cp -a "$CACHE_PATH/vendor/bundle" "$scaffolding_app_prefix/vendor/" | |
} | |
scaffolding_generate_binstubs() { | |
build_line "Generating app binstubs in $scaffolding_app_prefix/binstubs" | |
rm -rf "$scaffolding_app_prefix/.bundle" | |
pushd "$scaffolding_app_prefix" > /dev/null | |
_bundle_install \ | |
"$scaffolding_app_prefix/vendor/bundle" \ | |
--local \ | |
--quiet \ | |
--binstubs="$scaffolding_app_prefix/binstubs" | |
popd > /dev/null | |
} | |
scaffolding_vendor_bundler() { | |
build_line "Vendoring $(_bundle --version)" | |
gem install \ | |
--local "$(pkg_path_for bundler)/cache/bundler-${_bundler_version}.gem" \ | |
--install-dir "$GEM_HOME" \ | |
--bindir "$scaffolding_app_prefix/binstubs" \ | |
--no-ri \ | |
--no-rdoc | |
_wrap_ruby_bin "$scaffolding_app_prefix/binstubs/bundle" | |
_wrap_ruby_bin "$scaffolding_app_prefix/binstubs/bundler" | |
} | |
scaffolding_install_libexec() { | |
local shebang src dst | |
shebang="#!$(pkg_path_for "$_ruby_pkg")/bin/ruby" | |
build_line "Installing support programs into $pkg_prefix/libexec" | |
mkdir -pv "$pkg_prefix/libexec" | |
# TODO fin: Well, that's super awkward to find my own scaffolding path, | |
# perhaps the build program should set a `*_PATH` variable before invoking | |
# the scaffolding so there's an absolute path reference back? | |
find "$(pkg_path_for scaffolding-ruby-react)/libexec" -type f | while read -r src; do | |
dst="$pkg_prefix/libexec/$(basename "$src")" | |
cp -av "$src" "$dst" | |
sed -e "s|^#!/usr/bin/env .\{0,\}\$|${shebang}|" -i "$dst" | |
_create_process_bin "${dst%.*}" "bundle exec $dst" | |
done | |
} | |
scaffolding_fix_binstub_shebangs() { | |
local shebang | |
shebang="#!$(pkg_path_for "$_ruby_pkg")/bin/ruby" | |
build_line "Fixing Ruby shebang for binstubs" | |
find "$scaffolding_app_prefix/binstubs" -type f | while read -r binstub; do | |
if grep -q '^#!/usr/bin/env /.*/bin/ruby$' "$binstub"; then | |
sed -e "s|^#!/usr/bin/env /.\{0,\}/bin/ruby\$|${shebang}|" -i "$binstub" | |
fi | |
done | |
} | |
scaffolding_run_assets_precompile() { | |
# TODO fin: early exit if existing assets are found, meaning they've been | |
# committed or at least not ignored. | |
if _has_gem rake && _has_rakefile; then | |
pushd "$scaffolding_app_prefix" > /dev/null | |
if _rake -P --trace | grep -q '^rake assets:precompile$'; then | |
build_line "Detected and running Rake 'assets:precompile'" | |
_rake assets:precompile | |
fi | |
popd > /dev/null | |
fi | |
} | |
scaffolding_create_dir_symlinks() { | |
local entry dir target | |
for entry in "${scaffolding_symlinked_dirs[@]}"; do | |
dir="$scaffolding_app_prefix/$entry" | |
target="$pkg_svc_var_path/$entry" | |
build_line "Creating directory symlink to '$target' for '$dir'" | |
rm -rf "$dir" | |
mkdir -p "$(dirname "$dir")" | |
ln -sfv "$target" "$dir" | |
done | |
} | |
scaffolding_create_files_symlinks() { | |
return 0 | |
} | |
scaffolding_create_process_bins() { | |
local bin cmd | |
for bin in "${!scaffolding_process_bins[@]}"; do | |
cmd="${scaffolding_process_bins[$bin]}" | |
_create_process_bin "$pkg_prefix/bin/${pkg_name}-${bin}" "$cmd" | |
done | |
} | |
scaffolding_log_process_bins() { | |
local bin cmd | |
for bin in "${!scaffolding_process_bins[@]}"; do | |
cmd="${scaffolding_process_bins[$bin]}" | |
build_line "Proccess_bin: $cmd" | |
done | |
} | |
_setup_funcs() { | |
# Use the stock `do_default_build_config` by renaming it so we can call the | |
# stock behavior. How does this rate on the evil scale? | |
_rename_function "do_default_build_config" "_stock_do_default_build_config" | |
_rename_function "_new_do_default_build_config" "do_default_build_config" | |
} | |
_setup_vars() { | |
# The default Ruby package if one cannot be detected | |
_default_ruby_pkg="core/ruby" | |
# The absolute path to the `gemfile-parser` program | |
_gemfile_parser="$(pkg_path_for scaffolding-ruby-react)/bin/gemfile-parser" | |
# `$scaffolding_ruby_pkg` is empty by default | |
: "${scaffolding_ruby_pkg:=}" | |
# The list of PostgreSQL-related gems | |
_pg_gems=(pg activerecord-jdbcpostgresql-adapter jdbc-postgres | |
jdbc-postgresql jruby-pg rjack-jdbc-postgres | |
tgbyte-activerecord-jdbcpostgresql-adapter) | |
_mysql_gems=(mysql mysql2) | |
# The version of Bundler in use | |
_bundler_version="$("$(pkg_path_for bundler)/bin/bundle" --version \ | |
| awk '{print $NF}')" | |
# The install prefix path for the app | |
scaffolding_app_prefix="$pkg_prefix/app" | |
# | |
: "${scaffolding_app_port:=8000}" | |
# If `${scaffolding_env[@]` is not yet set, setup the hash | |
if [[ ! "$(declare -p scaffolding_env 2> /dev/null || true)" =~ "declare -A" ]]; then | |
declare -g -A scaffolding_env | |
fi | |
# If `${scaffolding_process_bins[@]` is not yet set, setup the hash | |
if [[ ! "$(declare -p scaffolding_process_bins 2> /dev/null || true)" =~ "declare -A" ]]; then | |
declare -g -A scaffolding_process_bins | |
fi | |
# | |
if [[ ! "$(declare -p scaffolding_symlinked_dirs 2> /dev/null || true)" =~ "declare -a" ]]; then | |
declare -g -a scaffolding_symlinked_dirs | |
fi | |
# | |
if [[ ! "$(declare -p scaffolding_symlinked_files 2> /dev/null || true)" =~ "declare -a" ]]; then | |
declare -g -a scaffolding_symlinked_files | |
fi | |
# | |
: "${_app_type:=}" | |
# # Node | |
# The default Node package if one cannot be detected | |
_default_node_pkg="core/node" | |
# `$scaffolding_node_pkg` is empty by default | |
: "${scaffolding_node_pkg:=}" | |
# `$scaffolding_node_pkg` is empty by default | |
: "${scaffolding_node_pkg_manager:=}" | |
_jq="$(pkg_path_for jq-static)/bin/jq" | |
} | |
_detect_package_json() { | |
if [[ ! -f package.json ]]; then | |
exit_with \ | |
"Node Scaffolding cannot find package.json in the root directory." 5 | |
fi | |
# shellcheck disable=SC2002 | |
if ! cat package.json | "$_jq" . > /dev/null; then | |
exit_with "Failed to parse package.json as JSON." 6 | |
fi | |
# TODO fin: do we check for any lockfiles here? | |
} | |
_detect_node_pkg_manager() { | |
if [[ -n "$scaffolding_node_pkg_manager" ]]; then | |
case "$scaffolding_node_pkg_manager" in | |
npm) | |
node_pkg_manager=npm | |
build_line "Detected package manager in Plan, using '$node_pkg_manager'" | |
;; | |
yarn) | |
node_pkg_manager=yarn | |
build_line "Detected package manager in Plan, using '$node_pkg_manager'" | |
;; | |
*) | |
local e | |
e="Variable 'scaffolding_pkg_manager' can only be" | |
e="$e set to: 'npm', 'yarn', or empty." | |
exit_with "$e" 9 | |
;; | |
esac | |
elif [[ -f yarn.lock ]]; then | |
node_pkg_manager=yarn | |
build_line "Detected yarn.lock in root directory, using '$node_pkg_manager'" | |
else | |
node_pkg_manager=npm | |
build_line "No package manager could be detected, using default '$node_pkg_manager'" | |
fi | |
} | |
_detect_gemfile() { | |
if [[ ! -f Gemfile ]]; then | |
exit_with "Ruby Scaffolding cannot find Gemfile in the root directory" 5 | |
fi | |
if [[ ! -f Gemfile.lock ]]; then | |
local uid gid | |
build_line "No Gemfile.lock found, running 'bundle lock'" | |
"$(pkg_path_for bundler)/bin/bundle" lock | |
# Set ownership of `Gemfile.lock` to be the same as `Gemfile`. | |
uid="$(stat -c "%u" Gemfile)" | |
gid="$(stat -c "%g" Gemfile)" | |
chown -v "${uid}:${gid}" Gemfile.lock | |
fi | |
} | |
_detect_app_type() { | |
_detect_rails5_app \ | |
|| _detect_rails42_app \ | |
|| _detect_rails41_app \ | |
|| _detect_rails4_app \ | |
|| _detect_rails3_app \ | |
|| _detect_rails2_app \ | |
|| _detect_rack_app \ | |
|| _detect_ruby_app | |
} | |
_detect_missing_gems() { | |
if [[ "$_app_type" == "rails5" ]] && ! _has_gem tzinfo-data; then | |
local e | |
e="A required gem 'tzinfo-data' is missing from the Gemfile." | |
e="$e If a 'gem \"tzinfo-data\", platforms: [...]' line exists," | |
e="$e simply remove the comma and 'platforms:' section," | |
e="$e run 'bundle update' to update the Gemfile.lock, and retry the build." | |
exit_with "$e" 10 | |
fi | |
if _has_gem railties \ | |
&& _compare_gem railties --greater-than-eq 3.0.0 --less-than 5.0.0 \ | |
&& ! _has_gem rails_12factor; then | |
local e | |
e="A required gem 'rails_12factor' is missing from the Gemfile." | |
e="$e Add the gem to your Gemfile," | |
e="$e run 'bundle install' to update the Gemfile.lock, and retry the build." | |
exit_with "$e" 10 | |
fi | |
} | |
# shellcheck disable=SC2016 | |
_detect_process_bins() { | |
if [[ -f Procfile ]]; then | |
local line bin cmd | |
build_line "Procfile detected, reading processes" | |
# Procfile parsing was heavily inspired by the implementation in | |
# gliderlabs/herokuish. Thanks to: | |
# https://github.com/gliderlabs/herokuish/blob/master/include/procfile.bash | |
while read -r line; do | |
if [[ "$line" =~ ^#.* ]]; then | |
continue | |
else | |
bin="${line%%:*}" | |
cmd="${line#*:}" | |
_set_if_unset scaffolding_process_bins "$(trim "$bin")" "$(trim "$cmd")" | |
fi | |
done < Procfile | |
fi | |
case "$_app_type" in | |
rails*) | |
_set_if_unset scaffolding_process_bins "web" \ | |
'bundle exec rails server -p $PORT' | |
_set_if_unset scaffolding_process_bins "console" \ | |
'bundle exec rails console' | |
;; | |
rack) | |
_set_if_unset scaffolding_process_bins "web" \ | |
'bundle exec rackup config.ru -p $PORT' | |
_set_if_unset scaffolding_process_bins "console" \ | |
'bundle exec irb' | |
;; | |
esac | |
if _has_gem rake && _has_rakefile; then | |
_set_if_unset scaffolding_process_bins "rake" 'bundle exec rake' | |
fi | |
_set_if_unset scaffolding_process_bins "sh" 'sh' | |
} | |
_update_vars() { | |
_set_if_unset scaffolding_env LANG "{{cfg.lang}}" | |
_set_if_unset scaffolding_env PORT "{{cfg.app.port}}" | |
# Export the app's listen port | |
_set_if_unset pkg_exports port "app.port" | |
_set_if_unset scaffolding_env NODE_ENV "{{cfg.node_env}}" | |
case "$_app_type" in | |
rails*) | |
scaffolding_symlinked_dirs+=(log tmp public/system) | |
if _compare_gem railties --less-than 4.1.0; then | |
scaffolding_symlinked_files+=(config/secrets.yml) | |
fi | |
_set_if_unset scaffolding_env RAILS_ENV "{{cfg.rails_env}}" | |
_set_if_unset scaffolding_env RACK_ENV "{{cfg.rack_env}}" | |
if _compare_gem railties --greater-than-eq 5.0.0; then | |
_set_if_unset scaffolding_env RAILS_LOG_TO_STDOUT "enabled" | |
fi | |
if _compare_gem railties --greater-than-eq 4.2.0; then | |
_set_if_unset scaffolding_env RAILS_SERVE_STATIC_FILES "enabled" | |
fi | |
if _compare_gem railties --greater-than-eq 4.1.0; then | |
_set_if_unset scaffolding_env SECRET_KEY_BASE "{{cfg.secret_key_base}}" | |
fi | |
;; | |
rack) | |
_set_if_unset scaffolding_env RACK_ENV "{{cfg.rack_env}}" | |
;; | |
esac | |
if _has_gem activerecord && _compare_gem activerecord \ | |
--less-than 4.1.0.beta1; then | |
build_line "Using config/database.yml for DB config" | |
scaffolding_symlinked_files+=(config/database.yml) | |
else | |
build_line "Using DATABASE_URL env_var for DB config" | |
fi | |
} | |
_update_pkg_build_deps() { | |
# Order here is important--entries which should be first in | |
# `${pkg_build_deps[@]}` should be called last. | |
_detect_git | |
_detect_yarn | |
} | |
_update_pkg_deps() { | |
# Order here is important--entries which should be first in `${pkg_deps[@]}` | |
# should be called last. | |
_add_busybox | |
_detect_sqlite3 | |
_detect_pg | |
_detect_nokogiri | |
_detect_execjs | |
_detect_webpacker | |
_detect_ruby | |
_detect_node | |
} | |
append_to_pkg_bin_dirs() { | |
local arr | |
arr=(${@}) | |
for dir in "${arr[@]}"; do | |
build_line "adding directory $dir to pkg_bin_dirs[@]" | |
pkg_bin_dirs=($(_return_or_append_to_set "$(trim $dir)" "${pkg_bin_dirs[@]}" )) | |
done | |
} | |
_update_bin_dirs_ruby() { | |
local ruby_bin_dirs | |
# Add the `bin/` directory and the app's `binstubs/` directory to the bin | |
# dirs so they will be on `PATH. We do this after the existing values so | |
# that the Plan author's `${pkg_bin_dirs[@]}` will always win. | |
ruby_bin_dirs=( | |
bin | |
$(basename "$scaffolding_app_prefix")/binstubs | |
) | |
append_to_pkg_bin_dirs ${ruby_bin_dirs[@]} | |
} | |
_update_bin_dirs_node() { | |
local node_bin_dirs | |
# Add the `bin/` directory and the app's `node_modules/.bin/` directory to | |
# the bin dirs so they will be on `PATH. We do this after the existing | |
# values so that the Plan author's `${pkg_bin_dirs[@]}` will always win. | |
# TODO: get this from package.json $cacheDirectories via jq | |
node_bin_dirs=( | |
$(basename "$scaffolding_app_prefix")/client/node_modules/.bin | |
$(basename "$scaffolding_app_prefix")/node_modules/.bin | |
) | |
append_to_pkg_bin_dirs ${node_bin_dirs[@]} | |
} | |
_update_bin_dirs() { | |
_update_bin_dirs_ruby | |
[[ -n $node_enabled ]] && _update_bin_dirs_node | |
} | |
_update_svc_run() { | |
if [[ -z "$pkg_svc_run" ]]; then | |
pkg_svc_run="$pkg_prefix/bin/${pkg_name}-web" | |
build_line "Setting pkg_svc_run='$pkg_svc_run'" | |
fi | |
} | |
_add_busybox() { | |
build_line "Adding Busybox package to run dependencies" | |
pkg_deps=(core/busybox-static ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
} | |
_detect_execjs() { | |
if _has_gem execjs; then | |
build_line "Detected 'execjs' gem in Gemfile.lock, adding node packages" | |
# TODO: use the version `core/node/$ver` here too | |
# pkg_deps=(core/node ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
fi | |
} | |
_detect_git() { | |
if [[ -d ".git" ]]; then | |
build_line "Detected '.git' directory, adding git packages as build deps" | |
pkg_build_deps=(core/git ${pkg_build_deps[@]}) | |
debug "Updating pkg_build_deps=(${pkg_build_deps[*]}) from Scaffolding detection" | |
_uses_git=true | |
fi | |
} | |
_detect_nokogiri() { | |
if _has_gem nokogiri; then | |
build_line "Detected 'nokogiri' gem in Gemfile.lock, adding libxml2 & libxslt packages" | |
export BUNDLE_BUILD__NOKOGIRI="--use-system-libraries" | |
pkg_deps=(core/libxml2 core/libxslt ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
fi | |
} | |
_detect_pg() { | |
for gem in "${_pg_gems[@]}"; do | |
if _has_gem "$gem"; then | |
build_line "Detected '$gem' gem in Gemfile.lock, adding postgresql package" | |
pkg_deps=(core/postgresql ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
_uses_pg=true | |
return 0 | |
fi | |
done | |
} | |
_detect_mysql() { | |
for gem in "${_mysql_gems[@]}"; do | |
if _has_gem "$gem"; then | |
build_line "Detected '$gem' gem in Gemfile.lock, adding mysql-client package" | |
pkg_deps=(core/mysql-client ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
_uses_mysql=true | |
return 0 | |
fi | |
done | |
} | |
_detect_rack_app() { | |
if _has_gem rack; then | |
build_line "Detected Rack app type" | |
_app_type="rack" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_detect_rails2_app() { | |
if _has_gem railties && _compare_gem railties \ | |
--greater-than-eq 2.0.0 --less-than 3.0.0; then | |
build_line "Detected Rails 2 app type" | |
warn "Rails 2 app types not yet supported with this Scaffolding" | |
exit_with "App type not supported" 2 | |
_app_type="rails2" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_detect_rails3_app() { | |
if _has_gem railties && _compare_gem railties \ | |
--greater-than-eq 3.0.0 --less-than 4.0.0; then | |
build_line "Detected Rails 3 app type" | |
warn "Rails 3 app types not yet supported with this Scaffolding" | |
exit_with "App type not supported" 2 | |
_app_type="rails3" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_detect_rails4_app() { | |
if _has_gem railties && _compare_gem railties \ | |
--greater-than-eq 4.0.0.beta --less-than 4.1.0.beta1; then | |
build_line "Detected Rails 4 app type" | |
warn "Rails 4 app types not yet supported with this Scaffolding" | |
exit_with "App type not supported" 2 | |
_app_type="rails4" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_detect_rails41_app() { | |
if _has_gem railties && _compare_gem railties \ | |
--greater-than-eq 4.1.0.beta1 --less-than 5.0.0; then | |
build_line "Detected Rails 4.1 app type" | |
warn "Rails 4.1 app types not yet supported with this Scaffolding" | |
exit_with "App type not supported" 2 | |
_app_type="rails41" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_detect_rails42_app() { | |
if _has_gem railties && _compare_gem railties \ | |
--greater-than-eq 4.2.0 --less-than 5.0.0; then | |
build_line "Detected Rails 4.2 app type" | |
_app_type="rails42" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_detect_rails5_app() { | |
if _has_gem railties && _compare_gem railties \ | |
--greater-than-eq 5.0.0 --less-than 6.0.0; then | |
build_line "Detected Rails 5 app type" | |
_app_type="rails5" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_detect_ruby_app() { | |
build_line "Detected Ruby app type" | |
warn "Ruby app types not yet supported with this Scaffolding" | |
exit_with "App type not supported" 2 | |
_app_type="ruby" | |
return 0 | |
} | |
_detect_ruby() { | |
local lockfile_version | |
if [[ -n "$scaffolding_ruby_pkg" ]]; then | |
_ruby_pkg="$scaffolding_ruby_pkg" | |
build_line "Detected Ruby version in Plan, using '$_ruby_pkg'" | |
else | |
lockfile_version="$($_gemfile_parser ruby-version ./Gemfile.lock || true)" | |
if [[ -n "$lockfile_version" ]]; then | |
# TODO fin: Add more robust Gemfile to Habitat package matching | |
case "$lockfile_version" in | |
*) | |
_ruby_pkg="core/ruby/$( | |
echo "$lockfile_version" | cut -d ' ' -f 2)" | |
;; | |
esac | |
build_line "Detected Ruby version '$lockfile_version' in Gemfile.lock, using '$_ruby_pkg'" | |
else | |
_ruby_pkg="$_default_ruby_pkg" | |
build_line "No Ruby version detected in Plan or Gemfile.lock, using default '$_ruby_pkg'" | |
fi | |
fi | |
pkg_deps=($_ruby_pkg ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
} | |
_detect_sqlite3() { | |
if _has_gem sqlite3; then | |
build_line "Detected 'sqlite3' gem in Gemfile.lock, adding sqlite packages" | |
pkg_deps=(core/sqlite ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
fi | |
} | |
_detect_webpacker() { | |
if _has_gem webpacker; then | |
build_line "Detected 'webpacker' gem in Gemfile.lock, adding yarn packages" | |
pkg_deps=(core/yarn ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
fi | |
} | |
_detect_node() { | |
if [[ -n "$scaffolding_node_pkg" ]]; then | |
_node_pkg="$scaffolding_node_pkg" | |
build_line "Detected Node.js version in Plan, using '$_node_pkg'" | |
else | |
local _node_version | |
_node_version="$(_json_val package.json .engines.node)" | |
if [[ -z "$_node_version" ]]; then | |
build_line "Unable to Determine Node Version from package.json" | |
else | |
node_version="$_node_version"; export node_version | |
fi | |
if [[ -n "$node_version" ]]; then | |
# TODO fin: Add more robust packages.json to Habitat package matching | |
case "$node_version" in | |
*) | |
_node_pkg="core/node/$node_version" | |
;; | |
esac | |
build_line "Detected Node.js version '$node_version' in package.json, using '$_node_pkg'" | |
elif [[ -f .nvmrc && -n "$(cat .nvmrc)" ]]; then | |
node_version="$(trim "$(cat .nvmrc)")" | |
# TODO fin: Add more robust .nvmrc to Habitat package matching | |
case "$node_version" in | |
*) | |
_node_pkg="core/node/$node_version" | |
;; | |
esac | |
build_line "Detected Node.js version '$node_version' in .nvmrc, using '$_node_pkg'" | |
else | |
_node_pkg="$_default_node_pkg" | |
build_line "No Node.js version detected in Plan, package.json, or .nvmrc, using default '$_node_pkg'" | |
fi | |
fi | |
pkg_deps=($_node_pkg ${pkg_deps[@]}) | |
debug "Updating pkg_deps=(${pkg_deps[*]}) from Scaffolding detection" | |
} | |
_detect_yarn() { | |
# TODO fin: support custom version of Yarn package? | |
if [[ "$node_pkg_manager" == "yarn" ]]; then | |
build_line "Adding Yarn package to build dependencies" | |
pkg_build_deps=(core/yarn ${pkg_build_deps[@]}) | |
debug "Updating pkg_build_deps=(${pkg_build_deps[*]}) from Scaffolding detection" | |
fi | |
} | |
# **Internal** Invokes the `bundle` program using the chosen version of Ruby. | |
# This way, we should avoid most Bundler warnings about mismatched Ruby | |
# versions specfied in the Gemfile. | |
_bundle() { | |
local bundler_prefix | |
bundler_prefix="$(pkg_path_for bundler)" | |
env \ | |
-u RUBYOPT \ | |
-u GEMRC \ | |
GEM_HOME="$bundler_prefix" \ | |
GEM_PATH="$bundler_prefix" \ | |
"$(pkg_path_for "$_ruby_pkg")/bin/ruby" \ | |
"$bundler_prefix/bin/bundle.real" ${*:-} | |
} | |
_rake() { | |
case "$_app_type" in | |
rails*) | |
RACK_ENV=production \ | |
RAILS_ENV=production \ | |
RAILS_GROUP=assets \ | |
_bundle exec rake ${*:-} | |
;; | |
rack) | |
RACK_ENV=production \ | |
_bundle exec rake ${*:-} | |
;; | |
*) | |
_bundle exec rake ${*:-} | |
;; | |
esac | |
} | |
_bundle_install() { | |
local path | |
path="$1" | |
shift | |
# TODO: make `--without development:test:staging` | |
# respect env. shit that goes for all over | |
_bundle install ${*:-} \ | |
--jobs "$(nproc)" \ | |
--without development:test:staging \ | |
--path "$path" \ | |
--shebang="$(pkg_path_for "$_ruby_pkg")/bin/ruby" \ | |
--no-clean \ | |
--deployment | |
} | |
_compare_gem() { | |
local gem result | |
gem="$1" | |
shift | |
result="$($_gemfile_parser compare-gem-version ${*:-} \ | |
./Gemfile.lock "$gem" 2> /dev/null || true)" | |
if [[ "$result" == "true" ]]; then | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_create_process_bin() { | |
local bin cmd env_sh | |
bin="$1" | |
cmd="$2" | |
env_sh="$pkg_svc_config_path/app_env.sh" | |
build_line "Creating ${bin} process bin" | |
cat <<EOF > "$bin" | |
#!$(pkg_path_for busybox-static)/bin/sh | |
set -e | |
if test -n "\$DEBUG"; then set -x; fi | |
export HOME="$pkg_svc_data_path" | |
if [ -f "$env_sh" ]; then | |
. "$env_sh" | |
else | |
>&2 echo "No app env file found: '$env_sh'" | |
>&2 echo "Have you not started this service ($pkg_origin/$pkg_name) before?" | |
>&2 echo "" | |
>&2 echo "Aborting..." | |
exit 1 | |
fi | |
cd $scaffolding_app_prefix | |
exec $cmd \$@ | |
EOF | |
chmod -v 755 "$bin" | |
} | |
_default_toml_has_no() { | |
local key toml | |
key="$1" | |
toml="$PLAN_CONTEXT/default.toml" | |
if [[ ! -f "$toml" ]]; then | |
return 0 | |
fi | |
if [[ "$(rq -t < "$toml" "at \"${key}\"")" == "null" ]]; then | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
# With thanks to: | |
# https://github.com/heroku/heroku-buildpack-nodejs/blob/master/lib/json.sh | |
# shellcheck disable=SC2002 | |
_json_val() { | |
local json | |
json="$1" | |
path="$2" | |
cat "$json" | "$_jq" --raw-output "$path // \"\"" | |
} | |
_has_gem() { | |
local result | |
result="$($_gemfile_parser has-gem ./Gemfile.lock "$1" 2> /dev/null || true)" | |
if [[ "$result" == "true" ]]; then | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
_has_rakefile() { | |
local candidate candidates | |
candidates=(Rakefile rakefile rakefile.rb Rakefile.rb) | |
for candidate in "${candidates[@]}"; do | |
if [[ -f "$candidate" ]]; then | |
return 0 | |
fi | |
done | |
return 1 | |
} | |
# Heavily inspired from: | |
# https://gist.github.com/Integralist/1e2616dc0b165f0edead9bf819d23c1e | |
_rename_function() { | |
local orig_name new_name | |
orig_name="$1" | |
new_name="$2" | |
declare -F "$orig_name" > /dev/null \ | |
|| exit_with "No function named $orig_name, aborting" 97 | |
eval "$(echo "${new_name}()"; declare -f "$orig_name" | tail -n +2)" | |
} | |
_set_if_unset() { | |
local hash key | |
hash="$1" | |
key="$2" | |
val="$3" | |
if [[ ! -v "$hash[$key]" ]]; then | |
eval "$hash[$key]='$val'" | |
fi | |
} | |
# **Internal** Use a "tar pipe" to copy the app source into a destination | |
# directory. This function reads from `stdin` for its file/directory manifest | |
# where each entry is on its own line ending in a newline. Several filters and | |
# changes are made via this copy strategy: | |
# | |
# * All user and group ids are mapped to root/0 | |
# * No extended attributes are copied | |
# * Some file editor backup files are skipped | |
# * Some version control-related directories are skipped | |
# * Any `./habitat/` directory is skipped | |
# * Any `./vendor/bundle` directory is skipped as it may have native gems | |
_tar_pipe_app_cp_to() { | |
local dst_path tar | |
dst_path="$1" | |
tar="$(pkg_path_for tar)/bin/tar" | |
"$tar" -cp \ | |
--owner=root:0 \ | |
--group=root:0 \ | |
--no-xattrs \ | |
--exclude-backups \ | |
--exclude-vcs \ | |
--exclude='habitat' \ | |
--exclude='vendor/bundle' \ | |
--files-from=- \ | |
-f - \ | |
| "$tar" -x \ | |
-C "$dst_path" \ | |
-f - | |
} | |
_wrap_ruby_bin() { | |
local bin="$1" | |
build_line "Adding wrapper $bin to ${bin}.real" | |
mv -v "$bin" "${bin}.real" | |
cat <<EOF > "$bin" | |
#!$(pkg_path_for busybox-static)/bin/sh | |
set -e | |
if test -n "\$DEBUG"; then set -x; fi | |
export GEM_HOME="$GEM_HOME" | |
export GEM_PATH="$GEM_PATH" | |
unset RUBYOPT GEMRC | |
exec $(pkg_path_for $_ruby_pkg)/bin/ruby ${bin}.real \$@ | |
EOF | |
chmod -v 755 "$bin" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment