Skip to content

Commit 3950aa1

Browse files
committed
Add track_buildpack_timing for buildpack timing output
1 parent f96fa37 commit 3950aa1

File tree

6 files changed

+444
-398
lines changed

6 files changed

+444
-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

+88-79
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ 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,
24+
BuildpackOutputTextSection,
25+
};
2326
use buildpacks_jvm_shared::system_properties::{read_system_properties, ReadSystemPropertiesError};
2427
#[cfg(test)]
2528
use buildpacks_jvm_shared_test as _;
@@ -92,18 +95,19 @@ impl Buildpack for OpenJdkBuildpack {
9295
}
9396

9497
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! {"
98+
track_buildpack_timing(|| {
99+
output::print_buildpack_name("Heroku OpenJDK Buildpack");
100+
101+
let resolved_version = resolve_version(&context.app_dir)
102+
.map_err(OpenJdkBuildpackError::ResolveVersionError)?;
103+
104+
if matches!(
105+
resolved_version.source,
106+
OpenJdkArtifactRequirementSource::DefaultVersionLatestLts
107+
) {
108+
output::print_warning(
109+
"No OpenJDK version specified",
110+
formatdoc! {"
107111
Your application does not explicitly specify an OpenJDK version. The latest
108112
long-term support (LTS) version will be installed. This currently is OpenJDK {OPENJDK_LATEST_LTS_VERSION}.
109113
@@ -115,74 +119,79 @@ impl Buildpack for OpenJdkBuildpack {
115119
directory of your application to contain:
116120
117121
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-
]));
122+
);
129123
}
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)?;
184124

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

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

0 commit comments

Comments
 (0)