libcnb_package/
package.rs1use crate::build::build_buildpack_binaries;
2use crate::buildpack_kind::{BuildpackKind, determine_buildpack_kind};
3use crate::package_descriptor::{NormalizePackageDescriptorError, normalize_package_descriptor};
4use crate::{CargoProfile, assemble_buildpack_directory};
5use cargo_metadata::MetadataCommand;
6use libcnb_common::toml_file::{TomlFileError, read_toml_file, write_toml_file};
7use libcnb_data::buildpack::BuildpackId;
8use libcnb_data::package_descriptor::PackageDescriptor;
9use std::collections::BTreeMap;
10use std::ffi::OsString;
11use std::fs;
12use std::path::{Path, PathBuf};
13
14pub fn package_buildpack(
20 buildpack_directory: &Path,
21 cargo_profile: CargoProfile,
22 target_triple: &str,
23 cargo_build_env: &[(OsString, OsString)],
24 destination: &Path,
25 dependencies: &BTreeMap<BuildpackId, PathBuf>,
26) -> Result<(), PackageBuildpackError> {
27 match determine_buildpack_kind(buildpack_directory) {
28 Some(BuildpackKind::LibCnbRs) => package_libcnb_buildpack(
29 buildpack_directory,
30 cargo_profile,
31 target_triple,
32 cargo_build_env,
33 destination,
34 )
35 .map_err(PackageBuildpackError::PackageLibcnbBuildpackError),
36 Some(BuildpackKind::Composite) => {
37 package_composite_buildpack(buildpack_directory, destination, dependencies)
38 .map_err(PackageBuildpackError::PackageCompositeBuildpackError)
39 }
40 _ => Err(PackageBuildpackError::UnsupportedBuildpack),
41 }
42}
43
44#[derive(thiserror::Error, Debug)]
45pub enum PackageBuildpackError {
46 #[error(transparent)]
47 PackageCompositeBuildpackError(PackageCompositeBuildpackError),
48 #[error(transparent)]
49 PackageLibcnbBuildpackError(PackageLibcnbBuildpackError),
50 #[error("Buildpack is not supported to be packaged")]
51 UnsupportedBuildpack,
52}
53
54fn package_libcnb_buildpack(
60 buildpack_directory: &Path,
61 cargo_profile: CargoProfile,
62 target_triple: &str,
63 cargo_build_env: &[(OsString, OsString)],
64 destination: &Path,
65) -> Result<(), PackageLibcnbBuildpackError> {
66 let cargo_metadata = MetadataCommand::new()
67 .manifest_path(buildpack_directory.join("Cargo.toml"))
68 .exec()
69 .map_err(PackageLibcnbBuildpackError::CargoMetadataError)?;
70
71 let buildpack_binaries = build_buildpack_binaries(
72 buildpack_directory,
73 &cargo_metadata,
74 cargo_profile,
75 cargo_build_env,
76 target_triple,
77 )
78 .map_err(PackageLibcnbBuildpackError::BuildBinariesError)?;
79
80 assemble_buildpack_directory(
81 destination,
82 buildpack_directory.join("buildpack.toml"),
83 &buildpack_binaries,
84 )
85 .map_err(PackageLibcnbBuildpackError::AssembleBuildpackDirectory)?;
86
87 fs::write(
88 destination.join("package.toml"),
89 "[buildpack]\nuri = \".\"\n",
90 )
91 .map_err(PackageLibcnbBuildpackError::WritePackageDescriptor)
92}
93
94#[derive(thiserror::Error, Debug)]
95pub enum PackageLibcnbBuildpackError {
96 #[error("Assembling buildpack directory failed: {0}")]
97 AssembleBuildpackDirectory(std::io::Error),
98 #[error("Couldn't write package.toml: {0}")]
99 WritePackageDescriptor(std::io::Error),
100 #[error("Building buildpack binaries failed: {0}")]
101 BuildBinariesError(crate::build::BuildBinariesError),
102 #[error("Obtaining Cargo metadata failed: {0}")]
103 CargoMetadataError(cargo_metadata::Error),
104}
105
106pub fn package_composite_buildpack(
120 buildpack_directory: &Path,
121 destination: &Path,
122 buildpack_paths: &BTreeMap<BuildpackId, PathBuf>,
123) -> Result<(), PackageCompositeBuildpackError> {
124 fs::copy(
125 buildpack_directory.join("buildpack.toml"),
126 destination.join("buildpack.toml"),
127 )
128 .map_err(PackageCompositeBuildpackError::CouldNotCopyBuildpackToml)?;
129
130 let package_descriptor_path = buildpack_directory.join("package.toml");
131
132 let normalized_package_descriptor =
133 read_toml_file::<PackageDescriptor>(&package_descriptor_path)
134 .map_err(PackageCompositeBuildpackError::CouldNotReadPackageDescriptor)
135 .and_then(|package_descriptor| {
136 normalize_package_descriptor(
137 &package_descriptor,
138 &package_descriptor_path,
139 buildpack_paths,
140 )
141 .map_err(PackageCompositeBuildpackError::NormalizePackageDescriptorError)
142 })?;
143
144 write_toml_file(
145 &normalized_package_descriptor,
146 destination.join("package.toml"),
147 )
148 .map_err(PackageCompositeBuildpackError::CouldNotWritePackageDescriptor)
149}
150
151#[derive(thiserror::Error, Debug)]
152pub enum PackageCompositeBuildpackError {
153 #[error("Couldn't copy buildpack.toml: {0}")]
154 CouldNotCopyBuildpackToml(std::io::Error),
155 #[error("Couldn't read package.toml: {0}")]
156 CouldNotReadPackageDescriptor(TomlFileError),
157 #[error("Error while normalizing package.toml: {0}")]
158 NormalizePackageDescriptorError(NormalizePackageDescriptorError),
159 #[error("Couldn't write package.toml: {0}")]
160 CouldNotWritePackageDescriptor(TomlFileError),
161}