-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Prefix layers with sequential numbers starting at `0001_<name>`. To support this it assumes any layers on disk with a number prefix is equivalent i.e. changing the order of layers will not invalidate the cache. This has the benefit that: - Layers can be named something semantic without side effects. - Build and launch layer behavior is guaranteed to be the same (provided `read_env` is called and applied for every layer in main).
- Loading branch information
Showing
5 changed files
with
144 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
use libcnb::data::layer::LayerName; | ||
use std::path::{Path, PathBuf}; | ||
use std::sync::atomic::{AtomicUsize, Ordering}; | ||
|
||
/// As layers are created this is incremented | ||
static LAYER_COUNT: AtomicUsize = AtomicUsize::new(1); | ||
/// Formatting for number of leanding zeros. Max number of layers is 1024 (as of 2025). Four digits allows | ||
/// one buildpack to meet or exceed that value | ||
static DIGITS: usize = 4; | ||
|
||
fn prefix(value: usize) -> String { | ||
format!("{value:0DIGITS$}_") | ||
} | ||
|
||
fn next_count() -> usize { | ||
LAYER_COUNT.fetch_add(1, Ordering::Acquire) | ||
} | ||
|
||
/// Removes the `NNNN_` prefix if there is one | ||
pub(crate) fn strip_order_prefix(name: &str) -> String { | ||
let re = regex::Regex::new(&format!("^\\d{{{DIGITS}}}_")) | ||
.expect("internal code bugs caught by unit tests"); | ||
re.replace(name, "").to_string() | ||
} | ||
|
||
/// Searches the given dir for an entry with the exact name or any NNNN_ prefix and returns Ok(Some(PathBuf)) | ||
pub(crate) fn contains_entry_with_name_or_pattern( | ||
dir: &Path, | ||
name: &str, | ||
) -> Result<Option<PathBuf>, std::io::Error> { | ||
let name = strip_order_prefix(name); | ||
|
||
let pattern = format!("^\\d{{{DIGITS}}}_{}$", regex::escape(&name)); | ||
let re = regex::Regex::new(&pattern).expect("internal error if this fails to compile"); | ||
|
||
for entry in fs_err::read_dir(dir)?.flatten() { | ||
if let Some(file_name) = entry.file_name().to_str() { | ||
if file_name == name || re.is_match(file_name) { | ||
return Ok(Some(entry.path().clone())); | ||
} | ||
} | ||
} | ||
|
||
Ok(None) | ||
} | ||
|
||
/// Gets and increments the next name | ||
/// | ||
/// # Panics | ||
/// | ||
/// Assumes that prepending a value to a valid layer name is a valid operation | ||
#[must_use] | ||
pub(crate) fn ordered_layer_name(name: LayerName) -> LayerName { | ||
let prefix = prefix(next_count()); | ||
prefix_layer_name(&prefix, name) | ||
} | ||
|
||
/// # Panics | ||
/// | ||
/// Assumes that prepending a value to a valid layer name is a valid operation | ||
#[must_use] | ||
#[allow(clippy::needless_pass_by_value)] | ||
fn prefix_layer_name(prefix: impl AsRef<str>, name: LayerName) -> LayerName { | ||
let prefix = prefix.as_ref(); | ||
format!("{prefix}{}", name.as_str()) | ||
.parse() | ||
.expect("Prepending to a valid layer name is valid") | ||
} |