mod config;
pub mod digest;
mod image_ref;
pub mod local_registry;
mod manifest;
pub mod media_types;
#[cfg(feature = "remote-artifact")]
mod push;
#[cfg(feature = "remote-artifact")]
mod remote_transport;
mod save;
pub use config::*;
pub use digest::sha256_digest;
pub use image_ref::ImageRef;
pub(crate) use manifest::stable_json_bytes;
pub(crate) use manifest::{
anonymous_artifact_image_name, anonymous_local_image_name, anonymous_local_repository_key,
is_anonymous_experiment_ref_name,
};
pub use manifest::{
is_anonymous_artifact_ref_name, is_anonymous_artifact_tag, ArtifactDraft, AsArtifact,
LocalArtifact, LocalArtifactDyn, LocalManifest, LocalRegistryHandle,
};
pub use media_types::OCI_IMAGE_MANIFEST_MEDIA_TYPE;
use anyhow::{Context, Result};
use oci_spec::image::ImageManifest;
#[cfg(feature = "remote-artifact")]
use crate::artifact::remote_transport::RemoteTransport;
#[cfg(feature = "remote-artifact")]
use oci_client::RegistryOperation;
use std::path::Path;
use std::{env, path::PathBuf, sync::OnceLock};
static LOCAL_REGISTRY_ROOT: OnceLock<PathBuf> = OnceLock::new();
pub fn set_local_registry_root(path: impl Into<PathBuf>) -> Result<()> {
let path = path.into();
LOCAL_REGISTRY_ROOT.set(path.clone()).map_err(|path| {
anyhow::anyhow!(
"Local registry root has already been set: {}",
path.display()
)
})?;
tracing::debug!("Local registry root configured via API: {}", path.display());
Ok(())
}
pub fn get_local_registry_root() -> &'static Path {
LOCAL_REGISTRY_ROOT.get_or_init(|| {
let path = if let Ok(custom_dir) = env::var("OMMX_LOCAL_REGISTRY_ROOT") {
let path = PathBuf::from(custom_dir);
tracing::debug!(
"Local registry root resolved from OMMX_LOCAL_REGISTRY_ROOT: {}",
path.display()
);
path
} else {
let path = directories::ProjectDirs::from("org", "ommx", "ommx")
.expect("Failed to get project directories")
.data_dir()
.to_path_buf();
tracing::debug!(
"Local registry root resolved to default: {}",
path.display()
);
path
};
path
})
}
#[deprecated(note = "Use get_local_registry_root instead")]
pub fn data_dir() -> Result<PathBuf> {
let path = get_local_registry_root().to_path_buf();
if !path.exists() {
std::fs::create_dir_all(&path)
.with_context(|| format!("Failed to create data directory: {}", path.display()))?;
}
Ok(path)
}
pub fn ghcr(org: &str, repo: &str, name: &str, tag: &str) -> Result<ImageRef> {
ImageRef::parse(&format!(
"ghcr.io/{}/{}/{}:{}",
org.to_lowercase(),
repo.to_lowercase(),
name.to_lowercase(),
tag
))
}
#[cfg(feature = "remote-artifact")]
pub fn fetch_remote_manifest(image_name: &ImageRef) -> Result<ImageManifest> {
let transport = RemoteTransport::new(image_name)?;
transport.auth_for(image_name, RegistryOperation::Pull)?;
let (manifest_bytes, _digest) =
transport.pull_manifest_raw(image_name, &[OCI_IMAGE_MANIFEST_MEDIA_TYPE])?;
serde_json::from_slice(&manifest_bytes)
.context("Failed to parse OCI image manifest from the remote registry")
}
pub fn get_images() -> Result<Vec<ImageRef>> {
let root = get_local_registry_root();
let registry = local_registry::LocalRegistry::open(root)?;
registry.list_image_refs()
}