Skip to content

Commit 8ea62b4

Browse files
committed
feat: Move shared data into common target which targets inherit from
1 parent 1dc61e9 commit 8ea62b4

File tree

2 files changed

+110
-51
lines changed

2 files changed

+110
-51
lines changed

rust/boil/src/build/bakefile.rs

Lines changed: 106 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use crate::{
2828
utils::{format_image_manifest_uri, format_image_repository_uri},
2929
};
3030

31+
pub const COMMON_TARGET_NAME: &str = "common--target";
3132
pub const ENTRY_TARGET_NAME_PREFIX: &str = "entry--";
3233

3334
#[derive(Debug, Snafu)]
@@ -232,6 +233,22 @@ impl Bakefile {
232233
.collect()
233234
}
234235

236+
/// Creates the common target, containing shared data, which will be inherited by other targets.
237+
fn common_target(args: &cli::BuildArguments, config: Config) -> Result<BakefileTarget, Error> {
238+
let revision = Self::git_head_revision().context(GetRevisionSnafu)?;
239+
let date_time = Self::now()?;
240+
241+
let target = BakefileTarget::common(
242+
date_time,
243+
revision,
244+
config,
245+
args.docker_build_arguments.clone(),
246+
args.image_version.base_prerelease(),
247+
);
248+
249+
Ok(target)
250+
}
251+
235252
fn from_targets(
236253
targets: Targets,
237254
args: &cli::BuildArguments,
@@ -240,23 +257,15 @@ impl Bakefile {
240257
let mut bakefile_targets = BTreeMap::new();
241258
let mut groups: BTreeMap<String, BakefileGroup> = BTreeMap::new();
242259

243-
let revision = Self::git_head_revision().context(GetRevisionSnafu)?;
244-
let date_time = Self::now()?;
245-
246-
// TODO (@Techassi): Can we somehow optimize this to come by with minimal amount of
247-
// cloning, because we also need to clone on every loop iteration below.
248-
let mut docker_build_arguments = config.build_arguments;
249-
docker_build_arguments.extend(args.docker_build_arguments.clone());
250-
docker_build_arguments.insert(BuildArgument::new(
251-
"RELEASE_VERSION".to_owned(),
252-
args.image_version.base_prerelease(),
253-
));
260+
// Create a common target, which contains shared data, like annotations, arguments, labels, etc...
261+
let common_target = Self::common_target(args, config)?;
262+
bakefile_targets.insert(COMMON_TARGET_NAME.to_owned(), common_target);
254263

255-
for (image_name, image_versions) in targets.0.into_iter() {
264+
for (image_name, image_versions) in targets.into_iter() {
256265
for (image_version, (image_options, is_entry)) in image_versions {
257266
// TODO (@Techassi): Clean this up
258267
// TODO (@Techassi): Move the arg formatting into functions
259-
let mut docker_build_arguments = docker_build_arguments.clone();
268+
let mut build_arguments = BuildArguments::new();
260269

261270
let local_version_docker_args: Vec<_> = image_options
262271
.local_images
@@ -272,9 +281,10 @@ impl Bakefile {
272281
})
273282
.collect();
274283

275-
docker_build_arguments.extend(image_options.build_arguments.clone());
276-
docker_build_arguments.extend(local_version_docker_args);
277-
docker_build_arguments.insert(BuildArgument::new(
284+
build_arguments.extend(image_options.build_arguments);
285+
build_arguments.extend(local_version_docker_args);
286+
// TODO (@Techassi): Rename this to IMAGE_VERSION
287+
build_arguments.insert(BuildArgument::new(
278288
"PRODUCT_VERSION".to_owned(),
279289
image_version.to_string(),
280290
));
@@ -318,24 +328,20 @@ impl Bakefile {
318328
})
319329
.collect();
320330

321-
let annotations = BakefileTarget::annotations(
322-
&date_time,
323-
&revision,
324-
&image_version,
325-
&args.image_version,
326-
&config.metadata,
327-
);
328-
let labels = BakefileTarget::labels(date_time.clone(), revision.clone());
331+
let annotations =
332+
BakefileTarget::image_version_annotation(&image_version, &args.image_version);
329333

330334
let target = BakefileTarget {
331335
tags: vec![image_manifest_uri],
332-
arguments: docker_build_arguments,
336+
arguments: build_arguments,
333337
platforms: vec![args.target_platform.clone()],
334-
context: PathBuf::from("."),
338+
// NOTE (@Techassi): Should this instead be scoped to the folder of the image we build
339+
context: Some(PathBuf::from(".")),
340+
dockerfile: Some(dockerfile),
341+
inherits: vec![COMMON_TARGET_NAME.to_owned()],
335342
annotations,
336-
dockerfile,
337343
contexts,
338-
labels,
344+
..Default::default()
339345
};
340346

341347
bakefile_targets.insert(target_name, target);
@@ -404,63 +410,112 @@ impl Bakefile {
404410

405411
// TODO (@Techassi): Figure out of we can use borrowed data in here. This would avoid a whole bunch
406412
// of cloning.
407-
#[derive(Debug, Serialize)]
413+
#[derive(Debug, Default, Serialize)]
408414
pub struct BakefileTarget {
415+
/// Defines build arguments for the target.
416+
#[serde(rename = "args", skip_serializing_if = "BuildArguments::is_empty")]
417+
pub arguments: BuildArguments,
418+
419+
/// Adds annotations to images built with bake.
420+
#[serde(skip_serializing_if = "Vec::is_empty")]
409421
pub annotations: Vec<String>,
410-
pub context: PathBuf,
411422

423+
/// Specifies the location of the build context to use for this target.
424+
///
425+
/// Accepts a URL or a directory path.
426+
#[serde(skip_serializing_if = "Option::is_none")]
427+
pub context: Option<PathBuf>,
428+
429+
/// Additional build contexts.
430+
///
431+
/// This attribute takes a map, where keys result in named contexts that you can reference in
432+
/// your builds.
412433
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
413434
pub contexts: BTreeMap<String, String>,
414-
pub dockerfile: PathBuf,
415435

416-
#[serde(rename = "args", skip_serializing_if = "BuildArguments::is_empty")]
417-
pub arguments: BuildArguments,
436+
/// Name of the Dockerfile to use for the build.
437+
#[serde(skip_serializing_if = "Option::is_none")]
438+
pub dockerfile: Option<PathBuf>,
439+
440+
/// A target can inherit attributes from other targets.
441+
#[serde(skip_serializing_if = "Vec::is_empty")]
442+
pub inherits: Vec<String>,
418443

444+
/// Assigns image labels to the build.
445+
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
419446
pub labels: BTreeMap<String, String>,
420-
pub tags: Vec<String>,
447+
448+
// TODO (@Techassi): Explore how we can build multiple platforms at once
449+
/// Set target platforms for the build target.
450+
///
451+
/// Technically, multiple architectures can be listed in here, but boil chooses to build only
452+
/// one architecture at a time.
453+
#[serde(skip_serializing_if = "Vec::is_empty")]
421454
pub platforms: Vec<TargetPlatform>,
455+
456+
/// Image names and tags to use for the build target.
457+
#[serde(skip_serializing_if = "Vec::is_empty")]
458+
pub tags: Vec<String>,
422459
}
423460

424461
impl BakefileTarget {
425-
fn annotations(
426-
date_time: &str,
427-
revision: &str,
428-
image_version: &str,
429-
sdp_image_version: &Version,
430-
global_metadata: &config::Metadata,
431-
) -> Vec<String> {
462+
fn common(
463+
date_time: String,
464+
revision: String,
465+
config: Config,
466+
docker_build_arguments: Vec<BuildArgument>,
467+
release_version: String,
468+
) -> Self {
432469
let config::Metadata {
433470
documentation,
434471
licenses,
435472
authors,
436473
source,
437474
vendor,
438-
} = global_metadata;
475+
} = config.metadata;
439476

440477
// Annotations describe OCI image components.
441-
vec![
478+
let annotations = vec![
442479
format!("{ANNOTATION_CREATED}={date_time}"),
443480
format!("{ANNOTATION_AUTHORS}={authors}"),
444481
format!("{ANNOTATION_DOCUMENTATION}={documentation}"),
445482
format!("{ANNOTATION_SOURCE}={source}"),
446-
// TODO (@Techassi): Move this version formatting into a function
447-
// TODO (@Techassi): Make this vendor agnostic, don't hard-code stackable here
448-
format!("{ANNOTATION_VERSION}={image_version}-stackable{sdp_image_version}"),
449483
format!("{ANNOTATION_REVISION}={revision}"),
450484
format!("{ANNOTATION_VENDOR}={vendor}"),
451485
format!("{ANNOTATION_LICENSES}={licenses}"),
452-
]
453-
}
486+
];
487+
488+
let mut arguments = config.build_arguments;
489+
arguments.extend(docker_build_arguments);
490+
arguments.insert(BuildArgument::new(
491+
"RELEASE_VERSION".to_owned(),
492+
release_version,
493+
));
454494

455-
fn labels(date_time: String, revision: String) -> BTreeMap<String, String> {
456495
// Labels describe Docker resources, and con be considered legacy. We
457496
// should use annotations instead. These labels are only added to be
458497
// consistent with `bake`.
459-
BTreeMap::from([
498+
let labels = BTreeMap::from([
460499
(ANNOTATION_CREATED.to_owned(), date_time.clone()),
461500
(ANNOTATION_REVISION.to_owned(), revision),
462501
("build-date".to_owned(), date_time),
463-
])
502+
]);
503+
504+
Self {
505+
annotations,
506+
arguments,
507+
labels,
508+
..Default::default()
509+
}
510+
}
511+
512+
fn image_version_annotation(image_version: &str, sdp_image_version: &Version) -> Vec<String> {
513+
// Annotations describe OCI image components.
514+
vec![
515+
// TODO (@Techassi): Move this version formatting into a function
516+
// TODO (@Techassi): Make this vendor agnostic, don't hard-code stackable here
517+
format!("{ANNOTATION_VERSION}={image_version}-stackable{sdp_image_version}"),
518+
]
464519
}
465520
}
466521

rust/boil/src/build/docker.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,10 @@ impl Serialize for BuildArguments {
154154
}
155155

156156
impl BuildArguments {
157+
pub fn new() -> Self {
158+
Self(BTreeSet::new())
159+
}
160+
157161
pub fn is_empty(&self) -> bool {
158162
self.0.is_empty()
159163
}

0 commit comments

Comments
 (0)