@@ -131,6 +131,15 @@ if has_old_preset_sbt_opts; then
131131 EOF
132132fi
133133
134+ # Copy the target dir from cache to speed up compilation. This is legacy buildpack
135+ # behavior that other JVM buildpacks don't implement. It can cause cache bloat, stale artifacts,
136+ # and reduced build reproducibility. We've observed customers using SBT_CLEAN (which will remove these files)
137+ # much more than expected (~10% of builds), presumably to work around issues.
138+ # This will be removed in a future version.
139+ target_dir_cache_restore_start_time=$(util::nowms)
140+ util::cache_copy "target" "${CACHE_DIR}" "${BUILD_DIR}"
141+ metrics::set_duration "target_dir_cache_restore_duration" "${target_dir_cache_restore_start_time}"
142+
134143if [[ -n "${SBT_PROJECT}" ]]; then
135144 SBT_TASKS="${SBT_PROJECT}/compile ${SBT_PROJECT}/stage"
136145else
147156# See: https://devcenter.heroku.com/articles/scala-support#clean-builds
148157[[ "${SBT_CLEAN}" = "true" ]] && SBT_TASKS="clean ${SBT_TASKS}"
149158
150-
159+ # Disable log formatting (which would modify already printed lines...)
160+ util::prepend_to_env "SBT_OPTS" "-Dsbt.log.noformat=true"
161+ # Run sbt in batch mode, disabling interactive prompts
162+ util::prepend_to_env "SBT_OPTS" "-batch"
163+ # Disable colored output
164+ util::prepend_to_env "SBT_OPTS" "-Dsbt.color=false"
151165
152166ivy_home_dir="${CACHE_DIR}/ivy_home"
153167util::prepend_to_env "SBT_OPTS" "-Dsbt.ivy.home=${ivy_home_dir}"
@@ -161,24 +175,35 @@ sbt_boot_dir="${CACHE_DIR}/sbt_boot"
161175util::prepend_to_env "SBT_OPTS" "-Dsbt.boot.directory=${sbt_boot_dir}"
162176mkdir -p "${sbt_boot_dir}"
163177
164- # Recreate the sbt global directory on each build with the current Heroku plugins and settings.
165178# See: https://www.scala-sbt.org/1.x/docs/Command-Line-Reference.html
166179sbt_global_dir="${CACHE_DIR}/sbt_global"
167180util::prepend_to_env "SBT_OPTS" "-Dsbt.global.base=${sbt_global_dir}"
168- rm -rf "${sbt_global_dir}"
169181mkdir -p "${sbt_global_dir}"
170182
171- # Install the Heroku sbt plugin
172- mkdir -p "${sbt_global_dir}/plugins"
183+ # Install the Heroku sbt plugin if the exising version differs (or is missing). We do this conditionally to
184+ # ensure we can cache the compiled class files of the plugin between builds, speeding up the build overall.
173185case "${sbt_version}" in
1741861.*)
175- cp "${BUILDPACK_DIR}/opt/HerokuBuildpackPlugin_sbt1.scala" "${sbt_global_dir}/plugins/HerokuBuildpackPlugin .scala"
187+ plugin_source_path= "${BUILDPACK_DIR}/opt/HerokuBuildpackPlugin_sbt1.scala"
176188 ;;
177189*)
178- cp "${BUILDPACK_DIR}/opt/HerokuBuildpackPlugin.scala" "${sbt_global_dir}/plugins /HerokuBuildpackPlugin.scala"
190+ plugin_source_path= "${BUILDPACK_DIR}/opt/HerokuBuildpackPlugin.scala"
179191 ;;
180192esac
181193
194+ plugins_dir="${sbt_global_dir}/plugins"
195+ plugin_destination_path="${plugins_dir}/HerokuBuildpackPlugin.scala"
196+ source_checksum="$(sha256sum "${plugin_source_path}" | awk '{print $1}')"
197+
198+ if [[ ! -f "${plugin_destination_path}" ]] || [[ "${source_checksum}" != "$(sha256sum "${plugin_destination_path}" | awk '{print $1}')" ]]; then
199+ # We remove the whole directory since we also want to remove the (cached) compiled files
200+ # for the older version of the plugin in the ./target directory.
201+ rm -rf "${plugins_dir}"
202+
203+ mkdir -p "${plugins_dir}"
204+ cp "${plugin_source_path}" "${plugin_destination_path}"
205+ fi
206+
182207sbt::install_sbt_launcher "${sbt_version}" "${CACHE_DIR}/sbt-launcher"
183208
184209# Collect metrics
196221
197222# build app
198223cd "${BUILD_DIR}"
224+
199225run_sbt "${SBT_TASKS}"
200226
201227if [[ -z "${DISABLE_DEPENDENCY_CLASSPATH_LOG:-}" ]]; then
202228 write_sbt_dependency_classpath_log
203229fi
204230
205- # drop useless directories from slug for play and sbt-native-launcher only
206- if is_sbt_native_packager "${BUILD_DIR}" || is_play "${BUILD_DIR}"; then
207- if [[ "${KEEP_SBT_CACHE:-}" != "true" ]]; then
208- if [[ -d "${BUILD_DIR}/target" ]]; then
209- output::step "Dropping compilation artifacts from the slug"
210- rm -rf "${BUILD_DIR}/target/scala-"*
211- rm -rf "${BUILD_DIR}/target/streams"
212- if [[ -d "${BUILD_DIR}/target/resolution-cache" ]]; then
213- find "${BUILD_DIR}/target/resolution-cache"/* ! -name "reports" ! -name "*-compile.xml" -print0 | xargs -0 rm -rf --
214- fi
215- fi
216- fi
231+ # Copy the target dir back to cache for the next build (see cache restore comment above for context)
232+ target_dir_cache_write_start_time=$(util::nowms)
233+ util::cache_copy "target" "${BUILD_DIR}" "${CACHE_DIR}"
234+ metrics::set_duration "target_dir_cache_write_duration" "${target_dir_cache_write_start_time}"
235+
236+ # When sbt-native-packager is used (either directly or implicitly by the Play framework), a standalone JAR file with
237+ # all code and dependencies is created. This makes the other JAR and class files redundant since they are not used by
238+ # the running application. We remove these files here to reduce the slug size. However, this is a broad assumption that
239+ # is often but not always correct. Users might want to use these files to run the application differently or for other
240+ # purposes. This is legacy behavior that we will not change at this point to avoid users running into slug size limits
241+ # needlessly. Ideally customers would curate their builds to not include extraneous files.
242+ if (is_sbt_native_packager "${BUILD_DIR}" || is_play "${BUILD_DIR}") && [[ "${KEEP_SBT_CACHE:-}" != "true" ]]; then
243+ output::step "Dropping compilation artifacts from the slug"
244+ rm -rf "${BUILD_DIR}/target/scala-"*
245+ rm -rf "${BUILD_DIR}/target/streams"
246+ find "${BUILD_DIR}/target/resolution-cache" -mindepth 1 ! -name "reports" ! -name "*-compile.xml" -exec rm -rf {} + 2>/dev/null || true
217247fi
218248
219249# write profile.d script
220250profile_script="${BUILD_DIR}/.profile.d/scala.sh"
221251mkdir -p "$(dirname "${profile_script}")"
222252cat <<-EOF >"${profile_script}"
223- export SBT_HOME="\$HOME/${SBT_USER_HOME}"
224253 export PATH="\$SBT_HOME/bin:\$PATH"
225254EOF
226255
227256# write export script
228257cat <<-EOF >"${BASE_DIR}/export"
229- export SBT_HOME="${BUILD_DIR}/${SBT_USER_HOME}"
230258 export PATH="\$SBT_HOME/bin:\$PATH"
231259EOF
0 commit comments