Skip to content

Commit

Permalink
Import Reference type from rust-oci-client
Browse files Browse the repository at this point in the history
Almost all tools which operate with OCI will end up
wanting to parse and use proper references. Import
the code from the rust-oci-client crate.

I imported the code with history with this blog
which I found helpful:
https://savorywatt.com/2015/01/25/move-files-and-folders-between-git-repos-using-patches/

Changes:

- Move `regex.rs` code inline into this file
- Switch to std `LazyLock` instead of `lazy_static` crate

For more see:

- containers#205
- oras-project/rust-oci-client#159

Signed-off-by: Colin Walters <[email protected]>
  • Loading branch information
cgwalters committed Aug 30, 2024
1 parent 473839d commit 2fc53a9
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 7 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ regex = "~1.10.5"

[dev-dependencies]
tempfile = "3.2.0"
rstest = "0.22.0"
serde_json = { version = "1.0.66", features = ["preserve_order"] }
2 changes: 2 additions & 0 deletions src/distribution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
//! Guide](https://github.com/opencontainers/artifacts) (a.k.a. "OCI Artifacts").

mod error;
mod reference;
mod repository;
mod tag;
mod version;

pub use error::*;
pub use reference::*;
pub use repository::*;
pub use tag::*;
pub use version::*;
24 changes: 17 additions & 7 deletions src/distribution/reference.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::convert::TryFrom;
use std::error::Error;
use std::fmt;
use std::str::FromStr;
use std::{convert::TryFrom, sync::OnceLock};

use crate::regexp;
use regex::{Regex, RegexBuilder};

/// NAME_TOTAL_LENGTH_MAX is the maximum total number of characters in a repository name.
const NAME_TOTAL_LENGTH_MAX: usize = 255;
Expand All @@ -12,6 +12,19 @@ const DOCKER_HUB_DOMAIN_LEGACY: &str = "index.docker.io";
const DOCKER_HUB_DOMAIN: &str = "docker.io";
const DOCKER_HUB_OFFICIAL_REPO_NAME: &str = "library";
const DEFAULT_TAG: &str = "latest";
/// REFERENCE_REGEXP is the full supported format of a reference. The regexp
/// is anchored and has capturing groups for name, tag, and digest components.
const REFERENCE_REGEXP: &str = r"^((?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?/)?[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?)(?::([\w][\w.-]{0,127}))?(?:@([A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}))?$";

fn reference_regexp() -> &'static Regex {
static RE: OnceLock<Regex> = OnceLock::new();
RE.get_or_init(|| {
RegexBuilder::new(REFERENCE_REGEXP)
.size_limit(10 * (1 << 21))
.build()
.unwrap()
})
}

/// Reasons that parsing a string as a Reference can fail.
#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -62,7 +75,7 @@ impl Error for ParseError {}
/// Parsing a tagged image reference:
///
/// ```
/// use oci_client::Reference;
/// use oci_spec::distribution::Reference;
///
/// let reference: Reference = "docker.io/library/hello-world:latest".parse().unwrap();
///
Expand Down Expand Up @@ -228,10 +241,7 @@ impl TryFrom<String> for Reference {
if s.is_empty() {
return Err(ParseError::NameEmpty);
}
lazy_static! {
static ref RE: regex::Regex = regexp::must_compile(regexp::REFERENCE_REGEXP);
};
let captures = match RE.captures(&s) {
let captures = match reference_regexp().captures(&s) {
Some(caps) => caps,
None => {
return Err(ParseError::ReferenceInvalidFormat);
Expand Down

0 comments on commit 2fc53a9

Please sign in to comment.