Skip to content

Commit

Permalink
Merge branch 'main' into libcnb_test_meta_buildpack_support
Browse files Browse the repository at this point in the history
* main:
  Ignore file support when finding buildpacks (#673)
  Apply rustfmt to README example (#676)
  Update example `cargo libcnb package` log output in READMEs (#675)
  Add CLI usage help output to libcnb-cargo README (#674)
  Fix lint errors with Rust 1.73 (#672)
  Include README.md in lib.rs (#667)

# Conflicts:
#	CHANGELOG.md
  • Loading branch information
colincasey committed Sep 19, 2023
2 parents a66b030 + 31ec5af commit ff6fdc3
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 70 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `libcnb-cargo`:
- No longer outputs paths for non-libcnb.rs and non-meta buildpacks. ([#657](https://github.com/heroku/libcnb.rs/pull/657))
- Build output for humans changed slightly, output intended for machines/scripting didn't change. ([#657](https://github.com/heroku/libcnb.rs/pull/657))
- When performing buildpack detection, standard ignore files (`.ignore` and `.gitignore`) will be respected. ([#673](https://github.com/heroku/libcnb.rs/pull/673))
- `libcnb-test`:
- Renamed the variant `Crate` to `CurrentCrate` for the `build_config::BuildpackReference` enum which references the buildpack within the Rust Crate currently being tested. ([#666](https://github.com/heroku/libcnb.rs/pull/666))

Expand Down
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,14 @@ impl Buildpack for HelloWorldBuildpack {
BuildResultBuilder::new()
.launch(
LaunchBuilder::new().process(
ProcessBuilder::new(process_type!("web"), ["echo"])
.arg("Hello World!")
.default(true)
.build(),
)
.build(),
LaunchBuilder::new()
.process(
ProcessBuilder::new(process_type!("web"), ["echo"])
.arg("Hello World!")
.default(true)
.build(),
)
.build(),
)
.build()
}
Expand All @@ -178,22 +179,23 @@ In your project directory, run `cargo libcnb package` to start packaging:

```shell
$ cargo libcnb package
🔍 Locating buildpacks...
📦 [1/1] Building libcnb-examples/my-buildpack
Determining automatic cross-compile settings...
Building binaries (x86_64-unknown-linux-musl)...
🚚 Preparing package directory...
🖥️ Gathering Cargo configuration (for x86_64-unknown-linux-musl)
🏗️ Building buildpack dependency graph...
🔀 Determining build order...
🚚 Building 1 buildpacks...
📦 [1/1] Building libcnb-examples/my-buildpack (./)
# Omitting compilation output...
Finished dev [unoptimized] target(s) in 8.92s
Writing buildpack directory...
Successfully wrote buildpack directory: packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack (4.06 MiB)
Finished dev [unoptimized] target(s) in 8.24s
Successfully wrote buildpack directory: packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack (4.09 MiB)
✨ Packaging successfully finished!

💡 To test your buildpack locally with pack, run:
pack build my-image-name \
--buildpack /home/ponda.baba/my-buildpack/packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack \
--buildpack packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack \
--path /path/to/application

/home/ponda.baba/my-buildpack/packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack
/Users/example/src/my-buildpack/packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack
```

If you get errors with hints about how to install required tools to cross-compile from your host platform to the
Expand Down
45 changes: 34 additions & 11 deletions libcnb-cargo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,45 @@ $ cargo install libcnb-cargo

## Usage

Currently, there is only one sub-command: `package`. It allows users to package their Rust buildpack in a spec-compliant
manner and helps with cross-compilation. Using it is fairly simple, run `cargo libcnb package` inside the buildpack's
Currently, there is only one sub-command: `package`. It allows users to package their
Rust buildpack in a spec-compliant manner and helps with cross-compilation.

```shell
$ cargo libcnb package --help
Packages a libcnb.rs Cargo project as a Cloud Native Buildpack

Usage: cargo libcnb package [OPTIONS]

Options:
--no-cross-compile-assistance Disable cross-compile assistance
--release Build in release mode, with optimizations
--target <TARGET> Build for the target triple [default: x86_64-unknown-linux-musl]
--package-dir <PACKAGE_DIR> Directory for packaged buildpacks, defaults to 'packaged' in Cargo workspace root
-h, --help Print help
```
Using it is fairly simple, run `cargo libcnb package` inside the buildpack's
project directory:
```shell
$ cargo libcnb package
INFO - Reading buildpack metadata...
INFO - Found buildpack libcnb-examples/my-buildpack with version 0.1.0.
INFO - Determining automatic cross-compile settings...
INFO - Building binaries (x86_64-unknown-linux-musl)...
🚚 Preparing package directory...
🖥️ Gathering Cargo configuration (for x86_64-unknown-linux-musl)
🏗️ Building buildpack dependency graph...
🔀 Determining build order...
🚚 Building 1 buildpacks...
📦 [1/1] Building libcnb-examples/my-buildpack (./)
# Omitting compilation output...
Finished dev [unoptimized + debuginfo] target(s) in 4.29s
INFO - Writing buildpack directory...
INFO - Successfully wrote buildpack directory: target/buildpack/debug/libcnb-examples_my-buildpack (3.26 MiB)
INFO - Packaging successfully finished!
INFO - Hint: To test your buildpack locally with pack, run: pack build my-image --buildpack target/buildpack/debug/libcnb-examples_my-buildpack --path /path/to/application
Finished dev [unoptimized] target(s) in 8.24s
Successfully wrote buildpack directory: packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack (4.09 MiB)
✨ Packaging successfully finished!
💡 To test your buildpack locally with pack, run:
pack build my-image-name \
--buildpack packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack \
--path /path/to/application
/Users/example/src/my-buildpack/packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack
```
[Latest Version]: https://img.shields.io/crates/v/libcnb-cargo.svg
Expand Down
5 changes: 2 additions & 3 deletions libcnb-cargo/src/package/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ pub(crate) fn execute(args: &PackageArgs) -> Result<(), Error> {
};

eprintln!("🏗️ Building buildpack dependency graph...");
let buildpack_dependency_graph =
build_libcnb_buildpacks_dependency_graph(&workspace_root_path, &[&package_dir])
.map_err(Error::CannotBuildBuildpackDependencyGraph)?;
let buildpack_dependency_graph = build_libcnb_buildpacks_dependency_graph(&workspace_root_path)
.map_err(Error::CannotBuildBuildpackDependencyGraph)?;

eprintln!("🔀 Determining build order...");
let root_nodes = buildpack_dependency_graph
Expand Down
49 changes: 48 additions & 1 deletion libcnb-cargo/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,53 @@ fn package_command_error_when_run_in_project_with_no_buildpacks() {
);
}

#[test]
#[ignore = "integration test"]
fn package_command_respects_ignore_files() {
let fixture_dir = copy_fixture_to_temp_dir("multiple_buildpacks").unwrap();

// The `ignore` crate supports `.ignore` files. So this first `cargo libcnb package` execution
// just sanity checks that our ignore rules will be respected.
let ignore_file = fixture_dir.path().join(".ignore");
fs::write(&ignore_file, "meta-buildpacks\nbuildpacks\n").unwrap();

let output = Command::new(CARGO_LIBCNB_BINARY_UNDER_TEST)
.args(["libcnb", "package", "--release"])
.current_dir(fixture_dir.path())
.output()
.unwrap();

assert_ne!(output.status.code(), Some(0));
assert_eq!(
String::from_utf8_lossy(&output.stderr),
"🚚 Preparing package directory...\n🖥\u{fe0f} Gathering Cargo configuration (for x86_64-unknown-linux-musl)\n🏗\u{fe0f} Building buildpack dependency graph...\n🔀 Determining build order...\n❌ No buildpacks found!\n"
);

fs::remove_file(ignore_file).unwrap();

// The `ignore` crate supports `.gitignore` files but only if the folder is within a git repository
// which is the default configuration used in our directory traversal.
// https://docs.rs/ignore/latest/ignore/struct.WalkBuilder.html#method.require_git
//
// So this second `cargo libcnb package` execution just sanity checks that our gitignore rules
// in a git repository will be respected.
fs::create_dir(fixture_dir.path().join(".git")).unwrap();
let ignore_file = fixture_dir.path().join(".gitignore");
fs::write(ignore_file, "meta-buildpacks\nbuildpacks\n").unwrap();

let output = Command::new(CARGO_LIBCNB_BINARY_UNDER_TEST)
.args(["libcnb", "package", "--release"])
.current_dir(fixture_dir.path())
.output()
.unwrap();

assert_ne!(output.status.code(), Some(0));
assert_eq!(
String::from_utf8_lossy(&output.stderr),
"🚚 Preparing package directory...\n🖥\u{fe0f} Gathering Cargo configuration (for x86_64-unknown-linux-musl)\n🏗\u{fe0f} Building buildpack dependency graph...\n🔀 Determining build order...\n❌ No buildpacks found!\n"
);
}

fn validate_packaged_buildpack(packaged_buildpack_dir: &Path, buildpack_id: &BuildpackId) {
assert!(packaged_buildpack_dir.join("buildpack.toml").exists());
assert!(packaged_buildpack_dir.join("package.toml").exists());
Expand Down Expand Up @@ -274,7 +321,7 @@ fn copy_fixture_to_temp_dir(name: &str) -> Result<TempDir, std::io::Error> {
env::temp_dir()
.canonicalize()
.and_then(tempdir_in)
.and_then(|temp_dir| copy_dir_recursively(&fixture_dir, temp_dir.path()).map(|_| temp_dir))
.and_then(|temp_dir| copy_dir_recursively(&fixture_dir, temp_dir.path()).map(|()| temp_dir))
}

fn copy_dir_recursively(source: &Path, destination: &Path) -> std::io::Result<()> {
Expand Down
1 change: 1 addition & 0 deletions libcnb-common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![doc = include_str!("../README.md")]
#![warn(clippy::pedantic)]
#![warn(unused_crate_dependencies)]
// This lint is too noisy and enforces a style that reduces readability in many cases.
Expand Down
1 change: 1 addition & 0 deletions libcnb-package/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ include = ["src/**/*", "LICENSE", "README.md"]

[dependencies]
cargo_metadata = "0.17.0"
ignore = "0.4"
libcnb-common.workspace = true
libcnb-data.workspace = true
petgraph = { version = "0.6.3", default-features = false }
Expand Down
7 changes: 3 additions & 4 deletions libcnb-package/src/buildpack_dependency_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@ use std::path::{Path, PathBuf};
/// package.toml or an IO error occurred while traversing the given directory.
pub fn build_libcnb_buildpacks_dependency_graph(
cargo_workspace_root: &Path,
ignore: &[&Path],
) -> Result<Graph<BuildpackDependencyGraphNode, ()>, BuildBuildpackDependencyGraphError> {
find_buildpack_dirs(cargo_workspace_root, ignore)
find_buildpack_dirs(cargo_workspace_root)
.map_err(BuildBuildpackDependencyGraphError::FindBuildpackDirectories)
.and_then(|buildpack_directories| {
buildpack_directories
Expand Down Expand Up @@ -85,8 +84,8 @@ fn build_libcnb_buildpack_dependency_graph_node(

#[derive(thiserror::Error, Debug)]
pub enum BuildBuildpackDependencyGraphError {
#[error("IO error while finding buildpack directories: {0}")]
FindBuildpackDirectories(std::io::Error),
#[error("Error while finding buildpack directories: {0}")]
FindBuildpackDirectories(ignore::Error),
#[error("Cannot read buildpack descriptor: {0}")]
ReadBuildpackDescriptorError(TomlFileError),
#[error("Cannot read package descriptor: {0}")]
Expand Down
48 changes: 16 additions & 32 deletions libcnb-package/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,39 +106,23 @@ fn create_file_symlink<P: AsRef<Path>, Q: AsRef<Path>>(
///
/// # Errors
///
/// Will return an `Err` if any I/O errors happen while walking the file system.
pub fn find_buildpack_dirs(start_dir: &Path, ignore: &[&Path]) -> std::io::Result<Vec<PathBuf>> {
fn find_buildpack_dirs_recursive(
path: &Path,
ignore: &[&Path],
accumulator: &mut Vec<PathBuf>,
) -> std::io::Result<()> {
if ignore.contains(&path) {
return Ok(());
}

let metadata = path.metadata()?;
if metadata.is_dir() {
let entries = fs::read_dir(path)?;
for entry in entries {
let entry = entry?;
let metadata = entry.metadata()?;
if metadata.is_dir() {
find_buildpack_dirs_recursive(&entry.path(), ignore, accumulator)?;
} else if let Some(file_name) = entry.path().file_name() {
if file_name.to_string_lossy() == "buildpack.toml" {
accumulator.push(path.to_path_buf());
/// Will return an `Err` if any I/O errors happen while walking the file system or any parsing errors
/// from reading a gitignore file.
pub fn find_buildpack_dirs(start_dir: &Path) -> Result<Vec<PathBuf>, ignore::Error> {
ignore::Walk::new(start_dir)
.collect::<Result<Vec<_>, _>>()
.map(|entries| {
entries
.iter()
.filter_map(|entry| {
if entry.path().is_dir() && entry.path().join("buildpack.toml").exists() {
Some(entry.path().to_path_buf())
} else {
None
}
}
}
}

Ok(())
}

let mut buildpack_dirs: Vec<PathBuf> = vec![];
find_buildpack_dirs_recursive(start_dir, ignore, &mut buildpack_dirs)?;
Ok(buildpack_dirs)
})
.collect()
})
}

/// Returns the path of the root workspace directory for a Rust Cargo project. This is often a useful
Expand Down
1 change: 1 addition & 0 deletions libcnb-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ tempfile = "3.7.1"
[dev-dependencies]
indoc = "2.0.3"
ureq = { version = "2.7.1", default-features = false }
libcnb.workspace = true
5 changes: 2 additions & 3 deletions libcnb-test/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,8 @@ pub(crate) fn package_buildpack(
target_triple.as_ref(),
);

let buildpack_dependency_graph =
build_libcnb_buildpacks_dependency_graph(&workspace_root_path, &[])
.map_err(PackageTestBuildpackError::BuildBuildpackDependencyGraph)?;
let buildpack_dependency_graph = build_libcnb_buildpacks_dependency_graph(&workspace_root_path)
.map_err(PackageTestBuildpackError::BuildBuildpackDependencyGraph)?;

let root_node = buildpack_dependency_graph
.node_weights()
Expand Down
2 changes: 2 additions & 0 deletions libcnb-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ pub use crate::test_runner::*;
#[cfg(test)]
use indoc as _;
#[cfg(test)]
use libcnb as _;
#[cfg(test)]
use ureq as _;

0 comments on commit ff6fdc3

Please sign in to comment.