Skip to content

Commit 0668ca3

Browse files
committed
Add track_buildpack_timing for buildpack timing output
1 parent f96fa37 commit 0668ca3

File tree

6 files changed

+443
-398
lines changed

6 files changed

+443
-398
lines changed

buildpacks/gradle/src/main.rs

+80-78
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use crate::layers::gradle_home::handle_gradle_home_layer;
77
use crate::GradleBuildpackError::{GradleBuildIoError, GradleBuildUnexpectedStatusError};
88
use buildpacks_jvm_shared as shared;
99
use buildpacks_jvm_shared::output::{
10-
print_buildpack_name, print_section, print_subsection, track_timing, BuildpackOutputText,
11-
BuildpackOutputTextSection,
10+
print_buildpack_name, print_section, print_subsection, track_buildpack_timing,
11+
track_subsection_timing, BuildpackOutputText, BuildpackOutputTextSection,
1212
};
1313
#[cfg(test)]
1414
use buildpacks_jvm_shared_test as _;
@@ -78,83 +78,85 @@ impl Buildpack for GradleBuildpack {
7878
}
7979

8080
fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
81-
print_buildpack_name("Heroku Gradle Buildpack");
82-
83-
let buildpack_config = GradleBuildpackConfig::from(&context);
84-
85-
let gradle_wrapper_executable_path = Some(context.app_dir.join("gradlew"))
86-
.filter(|path| path.exists())
87-
.ok_or(GradleBuildpackError::GradleWrapperNotFound)?;
88-
89-
shared::fs::set_executable(&gradle_wrapper_executable_path)
90-
.map_err(GradleBuildpackError::CannotSetGradleWrapperExecutableBit)?;
91-
92-
let mut gradle_env = Env::from_current();
93-
handle_gradle_home_layer(&context, &mut gradle_env)?;
94-
95-
print_section("Running Gradle build");
96-
97-
track_timing(|| {
98-
print_subsection("Starting Gradle daemon");
99-
gradle_command::start_daemon(&gradle_wrapper_executable_path, &gradle_env)
100-
.map_err(GradleBuildpackError::StartGradleDaemonError)
101-
})?;
102-
103-
let project_tasks = track_timing(|| {
104-
print_subsection("Querying tasks");
105-
gradle_command::tasks(&context.app_dir, &gradle_env)
106-
.map_err(|command_error| command_error.map_parse_error(|_| ()))
107-
.map_err(GradleBuildpackError::GetTasksError)
108-
})?;
109-
110-
let dependency_report = track_timing(|| {
111-
print_subsection("Querying dependency report");
112-
gradle_command::dependency_report(&context.app_dir, &gradle_env)
113-
.map_err(GradleBuildpackError::GetDependencyReportError)
114-
})?;
115-
116-
let task_name = buildpack_config
117-
.gradle_task
118-
.as_deref()
119-
.or_else(|| project_tasks.has_task("stage").then_some("stage"))
120-
.or_else(|| {
121-
detect_framework(&dependency_report).map(|framework| match framework {
122-
Framework::SpringBoot | Framework::Quarkus => "build",
123-
Framework::Ratpack => "installDist",
124-
Framework::Micronaut => "shadowJar",
81+
track_buildpack_timing(|| {
82+
print_buildpack_name("Heroku Gradle Buildpack");
83+
84+
let buildpack_config = GradleBuildpackConfig::from(&context);
85+
86+
let gradle_wrapper_executable_path = Some(context.app_dir.join("gradlew"))
87+
.filter(|path| path.exists())
88+
.ok_or(GradleBuildpackError::GradleWrapperNotFound)?;
89+
90+
shared::fs::set_executable(&gradle_wrapper_executable_path)
91+
.map_err(GradleBuildpackError::CannotSetGradleWrapperExecutableBit)?;
92+
93+
let mut gradle_env = Env::from_current();
94+
handle_gradle_home_layer(&context, &mut gradle_env)?;
95+
96+
print_section("Running Gradle build");
97+
98+
track_subsection_timing(|| {
99+
print_subsection("Starting Gradle daemon");
100+
gradle_command::start_daemon(&gradle_wrapper_executable_path, &gradle_env)
101+
.map_err(GradleBuildpackError::StartGradleDaemonError)
102+
})?;
103+
104+
let project_tasks = track_subsection_timing(|| {
105+
print_subsection("Querying tasks");
106+
gradle_command::tasks(&context.app_dir, &gradle_env)
107+
.map_err(|command_error| command_error.map_parse_error(|_| ()))
108+
.map_err(GradleBuildpackError::GetTasksError)
109+
})?;
110+
111+
let dependency_report = track_subsection_timing(|| {
112+
print_subsection("Querying dependency report");
113+
gradle_command::dependency_report(&context.app_dir, &gradle_env)
114+
.map_err(GradleBuildpackError::GetDependencyReportError)
115+
})?;
116+
117+
let task_name = buildpack_config
118+
.gradle_task
119+
.as_deref()
120+
.or_else(|| project_tasks.has_task("stage").then_some("stage"))
121+
.or_else(|| {
122+
detect_framework(&dependency_report).map(|framework| match framework {
123+
Framework::SpringBoot | Framework::Quarkus => "build",
124+
Framework::Ratpack => "installDist",
125+
Framework::Micronaut => "shadowJar",
126+
})
125127
})
126-
})
127-
.ok_or(GradleBuildpackError::BuildTaskUnknown)?;
128-
129-
print_section("Running Gradle build");
130-
print_subsection(BuildpackOutputText::new(vec![
131-
BuildpackOutputTextSection::regular("Running "),
132-
BuildpackOutputTextSection::command(format!("./gradlew {task_name} -x check")),
133-
]));
134-
135-
let output = Command::new(&gradle_wrapper_executable_path)
136-
.current_dir(&context.app_dir)
137-
.envs(&gradle_env)
138-
.args([task_name, "-x", "check"])
139-
.output_and_write_streams(stdout(), stderr())
140-
.map_err(GradleBuildIoError)?;
141-
142-
if !output.status.success() {
143-
Err(GradleBuildUnexpectedStatusError(output.status))?;
144-
}
145-
146-
// Explicitly ignoring the result. If the daemon cannot be stopped, that is not a build
147-
// failure, nor can we recover from it in any way.
148-
let _ = gradle_command::stop_daemon(&gradle_wrapper_executable_path, &gradle_env);
149-
150-
let process = default_app_process(&dependency_report, &context.app_dir)
151-
.map_err(GradleBuildpackError::CannotDetermineDefaultAppProcess)?;
152-
153-
process
154-
.map_or(BuildResultBuilder::new(), |process| {
155-
BuildResultBuilder::new().launch(LaunchBuilder::new().process(process).build())
156-
})
157-
.build()
128+
.ok_or(GradleBuildpackError::BuildTaskUnknown)?;
129+
130+
print_section("Running Gradle build");
131+
print_subsection(BuildpackOutputText::new(vec![
132+
BuildpackOutputTextSection::regular("Running "),
133+
BuildpackOutputTextSection::command(format!("./gradlew {task_name} -x check")),
134+
]));
135+
136+
let output = Command::new(&gradle_wrapper_executable_path)
137+
.current_dir(&context.app_dir)
138+
.envs(&gradle_env)
139+
.args([task_name, "-x", "check"])
140+
.output_and_write_streams(stdout(), stderr())
141+
.map_err(GradleBuildIoError)?;
142+
143+
if !output.status.success() {
144+
Err(GradleBuildUnexpectedStatusError(output.status))?;
145+
}
146+
147+
// Explicitly ignoring the result. If the daemon cannot be stopped, that is not a build
148+
// failure, nor can we recover from it in any way.
149+
let _ = gradle_command::stop_daemon(&gradle_wrapper_executable_path, &gradle_env);
150+
151+
let process = default_app_process(&dependency_report, &context.app_dir)
152+
.map_err(GradleBuildpackError::CannotDetermineDefaultAppProcess)?;
153+
154+
process
155+
.map_or(BuildResultBuilder::new(), |process| {
156+
BuildResultBuilder::new().launch(LaunchBuilder::new().process(process).build())
157+
})
158+
.build()
159+
})
158160
}
159161

160162
fn on_error(&self, error: libcnb::Error<Self::Error>) {

buildpacks/jvm/src/layers/openjdk.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ pub(crate) fn handle_openjdk_layer(
7979
_ => {}
8080
}
8181

82-
output::track_timing(|| {
82+
output::track_subsection_timing(|| {
8383
output::print_subsection("Downloading and unpacking OpenJDK distribution");
8484

8585
let temp_dir =
@@ -127,7 +127,7 @@ pub(crate) fn handle_openjdk_layer(
127127

128128
jdk_overlay_applied = true;
129129

130-
output::track_timing(|| {
130+
output::track_subsection_timing(|| {
131131
let jdk_overlay_contents =
132132
util::list_directory_contents(&app_jdk_overlay_dir_path)
133133
.map_err(OpenJdkBuildpackError::CannotListJdkOverlayContents)?;

buildpacks/jvm/src/main.rs

+87-79
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use crate::version_resolver::{
1919
resolve_version, OpenJdkArtifactRequirementSource, VersionResolveError,
2020
};
2121
use buildpacks_jvm_shared::output;
22-
use buildpacks_jvm_shared::output::{BuildpackOutputText, BuildpackOutputTextSection};
22+
use buildpacks_jvm_shared::output::{
23+
track_buildpack_timing, BuildpackOutputText, BuildpackOutputTextSection,
24+
};
2325
use buildpacks_jvm_shared::system_properties::{read_system_properties, ReadSystemPropertiesError};
2426
#[cfg(test)]
2527
use buildpacks_jvm_shared_test as _;
@@ -92,18 +94,19 @@ impl Buildpack for OpenJdkBuildpack {
9294
}
9395

9496
fn build(&self, context: BuildContext<Self>) -> libcnb::Result<BuildResult, Self::Error> {
95-
output::print_buildpack_name("Heroku OpenJDK Buildpack");
96-
97-
let resolved_version = resolve_version(&context.app_dir)
98-
.map_err(OpenJdkBuildpackError::ResolveVersionError)?;
99-
100-
if matches!(
101-
resolved_version.source,
102-
OpenJdkArtifactRequirementSource::DefaultVersionLatestLts
103-
) {
104-
output::print_warning(
105-
"No OpenJDK version specified",
106-
formatdoc! {"
97+
track_buildpack_timing(|| {
98+
output::print_buildpack_name("Heroku OpenJDK Buildpack");
99+
100+
let resolved_version = resolve_version(&context.app_dir)
101+
.map_err(OpenJdkBuildpackError::ResolveVersionError)?;
102+
103+
if matches!(
104+
resolved_version.source,
105+
OpenJdkArtifactRequirementSource::DefaultVersionLatestLts
106+
) {
107+
output::print_warning(
108+
"No OpenJDK version specified",
109+
formatdoc! {"
107110
Your application does not explicitly specify an OpenJDK version. The latest
108111
long-term support (LTS) version will be installed. This currently is OpenJDK {OPENJDK_LATEST_LTS_VERSION}.
109112
@@ -115,74 +118,79 @@ impl Buildpack for OpenJdkBuildpack {
115118
directory of your application to contain:
116119
117120
java.runtime.version = {OPENJDK_LATEST_LTS_VERSION}"},
118-
);
119-
}
120-
121-
output::print_section("OpenJDK version resolution");
122-
123-
match resolved_version.source {
124-
OpenJdkArtifactRequirementSource::SystemProperties => {
125-
output::print_subsection(BuildpackOutputText::new(vec![
126-
BuildpackOutputTextSection::regular("Using version string provided in "),
127-
BuildpackOutputTextSection::value("system.properties"),
128-
]));
121+
);
129122
}
130-
OpenJdkArtifactRequirementSource::DefaultVersionLatestLts => {
131-
output::print_subsection("No explicit configuration found, using latest LTS");
132-
}
133-
OpenJdkArtifactRequirementSource::DefaultVersionFunctions => {
134-
output::print_subsection(BuildpackOutputText::new(vec![
135-
BuildpackOutputTextSection::regular("No explicit configuration found, using "),
136-
BuildpackOutputTextSection::value("8"),
137-
]));
138-
}
139-
};
140-
141-
let openjdk_inventory = include_str!("../openjdk_inventory.toml")
142-
.parse::<Inventory<OpenJdkVersion, Sha256, OpenJdkArtifactMetadata>>()
143-
.map_err(OpenJdkBuildpackError::ParseInventoryError)?;
144-
145-
let openjdk_artifact = openjdk_inventory
146-
.partial_resolve(
147-
context
148-
.target
149-
.os
150-
.parse::<Os>()
151-
.expect("OS should be always parseable, buildpack will not run on unsupported operating systems."),
152-
// On platform API <= `0.9` together with lifecycle <= `0.17`, the `CNB_TARGET_ARCH` environment variable will not be set.
153-
// This will be the case for the `salesforce-functions` builder. To ensure this buildpack can run there, we will
154-
// fall back to Rust's architecture constant when the architecture cannot be determined. This workaround can be removed when
155-
// the `salesforce-functions` builder is EOL.
156-
Some(context.target.arch.as_str())
157-
.filter(|value| !value.is_empty())
158-
.unwrap_or(consts::ARCH)
159-
.parse::<Arch>()
160-
.expect("arch should be always parseable, buildpack will not run on unsupported architectures."),
161-
&resolved_version.requirement,
162-
)
163-
.ok_or(OpenJdkBuildpackError::UnsupportedOpenJdkVersion(
164-
resolved_version.requirement.clone(),
165-
))?;
166-
167-
output::print_subsection(match resolved_version.requirement.version {
168-
HerokuOpenJdkVersionRequirement::Major(major_version) => {
169-
BuildpackOutputText::new(vec![
170-
BuildpackOutputTextSection::regular("Selected major version "),
171-
BuildpackOutputTextSection::value(format!("{major_version}")),
172-
BuildpackOutputTextSection::regular(" resolves to "),
173-
BuildpackOutputTextSection::value(format!("{}", openjdk_artifact.version)),
174-
])
175-
}
176-
HerokuOpenJdkVersionRequirement::Specific(version) => BuildpackOutputText::new(vec![
177-
BuildpackOutputTextSection::regular("Selected version "),
178-
BuildpackOutputTextSection::value(format!("{version}")),
179-
]),
180-
});
181-
182-
handle_openjdk_layer(&context, openjdk_artifact)?;
183-
handle_runtime_layer(&context)?;
184123

185-
BuildResultBuilder::new().build()
124+
output::print_section("OpenJDK version resolution");
125+
126+
match resolved_version.source {
127+
OpenJdkArtifactRequirementSource::SystemProperties => {
128+
output::print_subsection(BuildpackOutputText::new(vec![
129+
BuildpackOutputTextSection::regular("Using version string provided in "),
130+
BuildpackOutputTextSection::value("system.properties"),
131+
]));
132+
}
133+
OpenJdkArtifactRequirementSource::DefaultVersionLatestLts => {
134+
output::print_subsection("No explicit configuration found, using latest LTS");
135+
}
136+
OpenJdkArtifactRequirementSource::DefaultVersionFunctions => {
137+
output::print_subsection(BuildpackOutputText::new(vec![
138+
BuildpackOutputTextSection::regular(
139+
"No explicit configuration found, using ",
140+
),
141+
BuildpackOutputTextSection::value("8"),
142+
]));
143+
}
144+
};
145+
146+
let openjdk_inventory = include_str!("../openjdk_inventory.toml")
147+
.parse::<Inventory<OpenJdkVersion, Sha256, OpenJdkArtifactMetadata>>()
148+
.map_err(OpenJdkBuildpackError::ParseInventoryError)?;
149+
150+
let openjdk_artifact = openjdk_inventory
151+
.partial_resolve(
152+
context
153+
.target
154+
.os
155+
.parse::<Os>()
156+
.expect("OS should be always parseable, buildpack will not run on unsupported operating systems."),
157+
// On platform API <= `0.9` together with lifecycle <= `0.17`, the `CNB_TARGET_ARCH` environment variable will not be set.
158+
// This will be the case for the `salesforce-functions` builder. To ensure this buildpack can run there, we will
159+
// fall back to Rust's architecture constant when the architecture cannot be determined. This workaround can be removed when
160+
// the `salesforce-functions` builder is EOL.
161+
Some(context.target.arch.as_str())
162+
.filter(|value| !value.is_empty())
163+
.unwrap_or(consts::ARCH)
164+
.parse::<Arch>()
165+
.expect("arch should be always parseable, buildpack will not run on unsupported architectures."),
166+
&resolved_version.requirement,
167+
)
168+
.ok_or(OpenJdkBuildpackError::UnsupportedOpenJdkVersion(
169+
resolved_version.requirement.clone(),
170+
))?;
171+
172+
output::print_subsection(match resolved_version.requirement.version {
173+
HerokuOpenJdkVersionRequirement::Major(major_version) => {
174+
BuildpackOutputText::new(vec![
175+
BuildpackOutputTextSection::regular("Selected major version "),
176+
BuildpackOutputTextSection::value(format!("{major_version}")),
177+
BuildpackOutputTextSection::regular(" resolves to "),
178+
BuildpackOutputTextSection::value(format!("{}", openjdk_artifact.version)),
179+
])
180+
}
181+
HerokuOpenJdkVersionRequirement::Specific(version) => {
182+
BuildpackOutputText::new(vec![
183+
BuildpackOutputTextSection::regular("Selected version "),
184+
BuildpackOutputTextSection::value(format!("{version}")),
185+
])
186+
}
187+
});
188+
189+
handle_openjdk_layer(&context, openjdk_artifact)?;
190+
handle_runtime_layer(&context)?;
191+
192+
BuildResultBuilder::new().build()
193+
})
186194
}
187195

188196
fn on_error(&self, error: libcnb::Error<Self::Error>) {

0 commit comments

Comments
 (0)