Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ target/
# When testing JSON files
*.json
oci/
!src/test/resources/oci/
!src/test/resources/oci/**/*.json
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ repos:
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
exclude: ^src/test/resources/oci/artifact/
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>land.oras</groupId>
<artifactId>oras-java-sdk</artifactId>
<version>0.2.1-SNAPSHOT</version>
<version>0.3.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>${project.groupId}:${project.artifactId}</name>
<description>ORAS Java SDK</description>
Expand Down Expand Up @@ -253,7 +253,7 @@
<inceptionYear>2024</inceptionYear>
<addJavaLicenseAfterPackage>false</addJavaLicenseAfterPackage>
<emptyLineAfterHeader>true</emptyLineAfterHeader>
<excludes>**/logback*.xml,**/junit-platform.properties</excludes>
<excludes>**/logback*.xml,**/junit-platform.properties,**/*.json</excludes>
<processStartTag>= LICENSE =</processStartTag>
<sectionDelimiter>===</sectionDelimiter>
<processEndTag>= LICENSE END =</processEndTag>
Expand Down
17 changes: 2 additions & 15 deletions src/main/java/land/oras/ContainerRef.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* A referer of a container on a {@link Registry}.
*/
@NullMarked
public final class ContainerRef {
public final class ContainerRef extends Ref {

/**
* The regex pattern to parse the container name including the registry, namespace, repository, tag and digest.
Expand Down Expand Up @@ -62,11 +62,6 @@ public final class ContainerRef {
*/
private final @Nullable String namespace;

/**
* The tag of the container.
*/
private final String tag;

/**
* The digest of the container.
*/
Expand All @@ -82,10 +77,10 @@ public final class ContainerRef {
*/
private ContainerRef(
String registry, @Nullable String namespace, String repository, String tag, @Nullable String digest) {
super(tag);
this.registry = registry;
this.namespace = namespace;
this.repository = repository;
this.tag = tag;
this.digest = digest;
}

Expand Down Expand Up @@ -129,14 +124,6 @@ public String getRepository() {
return repository;
}

/**
* Get the tag
* @return The tag
*/
public String getTag() {
return tag;
}

/**
* Get the digest
* @return The digest
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/land/oras/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package land.oras;

import java.nio.file.Path;
import java.util.List;
import land.oras.utils.Const;
import land.oras.utils.JsonUtils;
Expand Down Expand Up @@ -135,14 +136,23 @@ public String getJson() {
}

/**
* Create a manifest from a JSON string
* Create an index from a JSON string
* @param json The JSON string
* @return The index
*/
public static Index fromJson(String json) {
return JsonUtils.fromJson(json, Index.class).withJson(json);
}

/**
* Create an index from a path
* @param path The path
* @return The index
*/
public static Index fromPath(Path path) {
return JsonUtils.fromJson(path, Index.class);
}

/**
* Create an index from a list of manifests
* @param descriptors The list of manifests
Expand Down
71 changes: 71 additions & 0 deletions src/main/java/land/oras/LayoutRef.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*-
* =LICENSE=
* ORAS Java SDK
* ===
* Copyright (C) 2024 - 2025 ORAS
* ===
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* =LICENSEEND=
*/

package land.oras;

import java.nio.file.Path;
import java.util.regex.Pattern;
import land.oras.exception.OrasException;
import org.jspecify.annotations.NullMarked;

/**
* A referer of a container on a {@link OCILayout}.
*/
@NullMarked
public final class LayoutRef extends Ref {

private final Path folder;

private static final Pattern NAME_REGEX = Pattern.compile(
"^(.+?)(?::([^:@]+))?(?:@(.+))?$" // folder[:tag][@digest]
);

/**
* Private constructor
* @param tag The tag.
*/
private LayoutRef(Path folder, String tag) {
super(tag);
this.folder = folder;
}

/**
* Get the folder
* @return The folder
*/
public Path getFolder() {
return folder;
}

/**
* Parse the layout ref with folder and tag.
* @param name The layout ref.
* @return The container object with the registry, repository and tag.
*/
public static LayoutRef parse(String name) {
var matcher = NAME_REGEX.matcher(name);
if (!matcher.matches()) {
throw new OrasException("Invalid layout ref: " + name);
}
Path path = Path.of(matcher.group(1)); // Folder path
String tag = matcher.group(2) != null ? matcher.group(2) : matcher.group(3); // Tag or digest
return new LayoutRef(path, tag);
}
}
10 changes: 10 additions & 0 deletions src/main/java/land/oras/Manifest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package land.oras;

import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -253,6 +254,15 @@ public static Manifest fromJson(String json) {
return JsonUtils.fromJson(json, Manifest.class).withJson(json);
}

/**
* Create a manifest from a path
* @param path The path
* @return The manifest
*/
public static Manifest fromPath(Path path) {
return JsonUtils.fromJson(path, Manifest.class);
}

/**
* Return the original JSON
* @return The original JSON
Expand Down
84 changes: 82 additions & 2 deletions src/main/java/land/oras/OCI.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,93 @@

package land.oras;

import java.io.InputStream;
import java.nio.file.Path;
import org.jspecify.annotations.Nullable;

/**
* Abstract class for OCI operation on remote registry or layout
* Commons methods for OCI operations
* @param <T> The reference type
*/
public abstract sealed class OCI permits Registry, OCILayout {
public abstract sealed class OCI<T extends Ref> permits Registry, OCILayout {

/**
* Default constructor
*/
public OCI() {}
protected OCI() {}

/**
* Push an artifact
* @param ref The ref
* @param paths The paths
* @return The manifest
*/
public Manifest pushArtifact(T ref, LocalPath... paths) {
return pushArtifact(ref, ArtifactType.unknown(), Annotations.empty(), Config.empty(), paths);
}

/**
* Push an artifact
* @param ref The ref
* @param artifactType The artifact type
* @param paths The paths
* @return The manifest
*/
public Manifest pushArtifact(T ref, ArtifactType artifactType, LocalPath... paths) {
return pushArtifact(ref, artifactType, Annotations.empty(), Config.empty(), paths);
}

/**
* Upload an ORAS artifact
* @param ref The ref
* @param artifactType The artifact type
* @param annotations The annotations
* @param paths The paths
* @return The manifest
*/
public Manifest pushArtifact(T ref, ArtifactType artifactType, Annotations annotations, LocalPath... paths) {
return pushArtifact(ref, artifactType, annotations, Config.empty(), paths);
}

/**
* Push an artifact
* @param ref The container
* @param artifactType The artifact type. Can be null
* @param annotations The annotations
* @param config The config
* @param paths The paths
* @return The manifest
*/
public abstract Manifest pushArtifact(
T ref, ArtifactType artifactType, Annotations annotations, @Nullable Config config, LocalPath... paths);

/**
* Pull an artifact
* @param ref The reference of the artifact
* @param path The path to save the artifact
* @param overwrite Overwrite the artifact if it exists
*/
public abstract void pullArtifact(T ref, Path path, boolean overwrite);

/**
* Get the blob for the given digest. Not be suitable for large blobs
* @param ref The ref
* @return The blob as bytes
*/
public abstract byte[] getBlob(T ref);

/**
* Fetch blob and save it to file
* @param ref The ref
* @param path The path to save the blob
*/
public abstract void fetchBlob(T ref, Path path);

/**
* Fetch blob and return it as input stream
* @param ref The ref
* @return The input stream
*/
public abstract InputStream fetchBlob(T ref);
}
Loading