Skip to content

Commit bd1e7c3

Browse files
authored
Add optional OS version and feature (#608)
Signed-off-by: Valentin Delaye <jonesbusy@users.noreply.github.com>
1 parent 31b84b1 commit bd1e7c3

11 files changed

Lines changed: 335 additions & 68 deletions

src/main/java/land/oras/Index.java

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.util.List;
3232
import java.util.Map;
3333
import java.util.Objects;
34+
import java.util.function.BiPredicate;
3435
import land.oras.utils.Const;
3536
import land.oras.utils.JsonUtils;
3637
import org.jspecify.annotations.NonNull;
@@ -149,8 +150,18 @@ public List<ManifestDescriptor> getManifests() {
149150
* @return The list of manifests that match the platform
150151
*/
151152
public List<ManifestDescriptor> filter(Platform platform) {
153+
return filter(platform, Platform::matches);
154+
}
155+
156+
/**
157+
* Filter the manifests by platform with a custom comparator
158+
* @param platform The platform
159+
* @param comparator The comparator to compare the platform of the manifest descriptor and the given platform. The first parameter is the platform of the manifest descriptor, and the second parameter is the given platform. The comparator should return true if the manifest descriptor matches the given platform, and false otherwise.
160+
* @return The list of manifests that match the platform
161+
*/
162+
public List<ManifestDescriptor> filter(Platform platform, BiPredicate<Platform, Platform> comparator) {
152163
return getManifests().stream()
153-
.filter(descriptor -> descriptor.getPlatform().equals(platform))
164+
.filter(descriptor -> comparator.test(descriptor.getPlatform(), platform))
154165
.toList();
155166
}
156167

@@ -170,10 +181,7 @@ public List<ManifestDescriptor> unspecifiedPlatforms() {
170181
* @return The manifest that matches the platform, or null if there are multiple matches or no matches
171182
*/
172183
public @Nullable ManifestDescriptor findUnique(Platform platform) {
173-
return getManifests().stream()
174-
.filter(descriptor -> descriptor.getPlatform().equals(platform))
175-
.findFirst()
176-
.orElse(null);
184+
return filter(platform).stream().findFirst().orElse(null);
177185
}
178186

179187
@Override

src/main/java/land/oras/ManifestDescriptor.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public final class ManifestDescriptor {
5353
private final long size;
5454

5555
@Nullable
56-
private final Map<String, String> platform;
56+
private final Platform platform;
5757

5858
@Nullable
5959
private final Map<String, String> annotations;
@@ -64,7 +64,7 @@ private ManifestDescriptor(
6464
@JsonProperty(Const.JSON_PROPERTY_MEDIA_TYPE) String mediaType,
6565
@JsonProperty(Const.JSON_PROPERTY_DIGEST) String digest,
6666
@JsonProperty(Const.JSON_PROPERTY_SIZE) long size,
67-
@JsonProperty(Const.JSON_PROPERTY_PLATFORM) @Nullable Map<String, String> platform,
67+
@JsonProperty(Const.JSON_PROPERTY_PLATFORM) @Nullable Platform platform,
6868
@JsonProperty(Const.JSON_PROPERTY_ANNOTATIONS) @Nullable Map<String, String> annotations) {
6969
this.artifactType = artifactType;
7070
this.mediaType = mediaType;
@@ -107,20 +107,22 @@ public long getSize() {
107107
}
108108

109109
/**
110-
* Get the platform as annotations
110+
* Return the platform as a Platform object
111111
* @return The platform
112112
*/
113-
public @Nullable @JsonProperty(Const.JSON_PROPERTY_PLATFORM) Map<String, String> getPlatformAnnotations() {
114-
return platform;
113+
@JsonIgnore
114+
public Platform getPlatform() {
115+
return platform != null ? platform : Platform.empty();
115116
}
116117

117118
/**
118-
* Return the platform as a Platform object
119-
* @return The platform
119+
* Return the platform or null if the platform is not set
120+
* Only use for serialization purposes, as the platform field is nullable in the JSON representation of the manifest descriptor
121+
* @return The platform or null
120122
*/
121-
@JsonIgnore
122-
public Platform getPlatform() {
123-
return Platform.of(platform);
123+
@JsonProperty(Const.JSON_PROPERTY_PLATFORM)
124+
public @Nullable Platform getPlatformOrNull() {
125+
return platform;
124126
}
125127

126128
/**
@@ -188,7 +190,7 @@ public ManifestDescriptor withArtifactType(@Nullable String artifactType) {
188190
* @return The subject
189191
*/
190192
public ManifestDescriptor withPlatform(Platform platform) {
191-
return new ManifestDescriptor(artifactType, mediaType, digest, size, platform.annotations(), annotations);
193+
return new ManifestDescriptor(artifactType, mediaType, digest, size, platform, annotations);
192194
}
193195

194196
/**

src/main/java/land/oras/Platform.java

Lines changed: 154 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -20,54 +20,118 @@
2020

2121
package land.oras;
2222

23-
import com.fasterxml.jackson.annotation.JsonCreator;
24-
import com.fasterxml.jackson.annotation.JsonGetter;
25-
import com.fasterxml.jackson.annotation.JsonIgnore;
23+
import com.fasterxml.jackson.annotation.JsonProperty;
2624
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
27-
import java.util.Map;
25+
import java.util.List;
26+
import java.util.Objects;
2827
import land.oras.utils.Const;
2928
import org.jspecify.annotations.NullMarked;
3029
import org.jspecify.annotations.Nullable;
3130

3231
/**
3332
* Record for platform information
34-
* @param annotations Platform annotations, which can include os and architecture information
33+
* @param os The operating system of the platform
34+
* @param architecture The architecture of the platform
35+
* @param variant The variant of the platform, which is optional and may be null
36+
* @param osVersion The operating system version of the platform, which is optional and may be
37+
* @param features The features of the platform, which is optional and may be null
38+
* @param osFeatures The operating system features of the platform, which is optional and may be
3539
*/
3640
@NullMarked
3741
@OrasModel
38-
@JsonPropertyOrder({Const.PLATFORM_OS, Const.PLATFORM_ARCHITECTURE})
39-
public record Platform(@Nullable @JsonIgnore Map<String, String> annotations) {
42+
@JsonPropertyOrder({
43+
Const.PLATFORM_OS,
44+
Const.PLATFORM_ARCHITECTURE,
45+
Const.PLATFORM_VARIANT,
46+
Const.PLATFORM_OS_VERSION,
47+
Const.PLATFORM_OS_FEATURES
48+
})
49+
public record Platform(
50+
@Nullable @JsonProperty(Const.PLATFORM_OS) String os,
51+
@Nullable @JsonProperty(Const.PLATFORM_ARCHITECTURE) String architecture,
52+
@Nullable @JsonProperty(Const.PLATFORM_OS_VERSION) String osVersion,
53+
@Nullable @JsonProperty(Const.PLATFORM_VARIANT) String variant,
54+
@Nullable @JsonProperty(Const.PLATFORM_FEATURES) List<String> features,
55+
@Nullable @JsonProperty(Const.PLATFORM_OS_FEATURES) List<String> osFeatures) {
4056

4157
/**
42-
* Constructor for JSON deserialization
43-
* @param annotations Platform annotations, which can include os and architecture information
58+
* Create a new platform linux/amd64
59+
* @return The platform
4460
*/
45-
@JsonCreator
46-
public Platform {}
61+
public static Platform linuxAmd64() {
62+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_AMD64);
63+
}
4764

4865
/**
49-
* Create a new platform with the given annotations
50-
* @param annotations Platform annotations, which can include os and architecture information
66+
* Create a new platform windows/amd64
5167
* @return The platform
5268
*/
53-
public static Platform of(@Nullable Map<String, String> annotations) {
54-
return new Platform(annotations);
69+
public static Platform windowsAmd64() {
70+
return of(Const.PLATFORM_WINDOWS, Const.PLATFORM_ARCHITECTURE_AMD64);
5571
}
5672

5773
/**
5874
* Create a new platform linux/amd64
5975
* @return The platform
6076
*/
61-
public static Platform linuxAmd64() {
62-
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_AMD64);
77+
public static Platform linux386() {
78+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_386);
79+
}
80+
81+
/**
82+
* Create a new platform linux arm/v6
83+
* @return The platform
84+
*/
85+
public static Platform linuxArmV6() {
86+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_ARM, Const.VARIANT_V6);
87+
}
88+
89+
/**
90+
* Create a new platform linux arm/v7
91+
* @return The platform
92+
*/
93+
public static Platform linuxArmV7() {
94+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_ARM, Const.VARIANT_V7);
95+
}
96+
97+
/**
98+
* Create a new platform linux arm64/v8
99+
* @return The platform
100+
*/
101+
public static Platform linuxArm64V8() {
102+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_ARM64, Const.VARIANT_V8);
103+
}
104+
105+
/**
106+
* Create a new platform ppc64le
107+
* @return The platform
108+
*/
109+
public static Platform linuxPpc64le() {
110+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_PPC64LE, null);
111+
}
112+
113+
/**
114+
* Create a new platform riscv64
115+
* @return The platform
116+
*/
117+
public static Platform linuxRiscv64() {
118+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_RISCV64, null);
119+
}
120+
121+
/**
122+
* Create a new platform s390x
123+
* @return The platform
124+
*/
125+
public static Platform linuxS390x() {
126+
return of(Const.PLATFORM_LINUX, Const.PLATFORM_ARCHITECTURE_S390X, null);
63127
}
64128

65129
/**
66130
* Create a new platform with empty os and architecture
67131
* @return The platform
68132
*/
69133
public static Platform empty() {
70-
return new Platform(null);
134+
return new Platform(null, null, null, null, null, null);
71135
}
72136

73137
/**
@@ -85,7 +149,7 @@ public static Platform unknown() {
85149
* @return The platform
86150
*/
87151
public static Platform of(String os, String architecture) {
88-
return new Platform(Map.of(Const.PLATFORM_OS, os, Const.PLATFORM_ARCHITECTURE, architecture));
152+
return new Platform(os, architecture, null, null, null, null);
89153
}
90154

91155
/**
@@ -96,44 +160,61 @@ public static Platform of(String os, String architecture) {
96160
* @return The platform
97161
*/
98162
public static Platform of(String os, String architecture, @Nullable String variant) {
99-
if (variant == null) {
100-
return of(os, architecture);
101-
}
102-
return new Platform(Map.of(
103-
Const.PLATFORM_OS, os,
104-
Const.PLATFORM_ARCHITECTURE, architecture,
105-
Const.PLATFORM_VARIANT, variant));
163+
return new Platform(os, architecture, null, variant, null, null);
106164
}
107165

108166
/**
109-
* Return the architecture of the platform, or "unknown" if not specified
110-
* @return The architecture of the platform
167+
* Return the os of the platform, or "unknown" if the os is null
168+
* @return The os of the platform
111169
*/
112-
@JsonGetter
170+
@Override
113171
public String os() {
114-
return annotations != null
115-
? annotations.getOrDefault(Const.PLATFORM_OS, Const.PLATFORM_UNKNOWN)
116-
: Const.PLATFORM_UNKNOWN;
172+
return os != null ? os : Const.PLATFORM_UNKNOWN;
117173
}
118174

119175
/**
120-
* Return the architecture of the platform, or "unknown" if not specified
121-
* @return The architecture of the platform
176+
* Return the os of the platform, or "unknown" if the os is null
177+
* @return The os of the platform
122178
*/
123-
@JsonGetter
179+
@Override
124180
public String architecture() {
125-
return annotations != null
126-
? annotations.getOrDefault(Const.PLATFORM_ARCHITECTURE, Const.PLATFORM_UNKNOWN)
127-
: Const.PLATFORM_UNKNOWN;
181+
return architecture != null ? architecture : Const.PLATFORM_UNKNOWN;
182+
}
183+
184+
/**
185+
* Create a new platform with the given features
186+
* @param features The features of the platform
187+
* @return The platform
188+
*/
189+
public Platform withFeatures(List<String> features) {
190+
return new Platform(os, architecture, osVersion, variant, features, osFeatures);
191+
}
192+
193+
/**
194+
* Create a new platform with the given variant
195+
* @param variant The variant of the platform
196+
* @return The platform
197+
*/
198+
public Platform withVariant(String variant) {
199+
return new Platform(os, architecture, osVersion, variant, features, osFeatures);
200+
}
201+
202+
/**
203+
* Create a new platform with the given os version
204+
* @param osVersion The os version of the platform
205+
* @return The platform
206+
*/
207+
public Platform withOsVersion(String osVersion) {
208+
return new Platform(os, architecture, osVersion, variant, features, osFeatures);
128209
}
129210

130211
/**
131-
* Return the variant of the platform, or null if not specified
132-
* @return The variant of the platform
212+
* Create a new platform with the given os features
213+
* @param osFeatures The os features of the platform
214+
* @return The platform
133215
*/
134-
@JsonGetter
135-
public @Nullable String variant() {
136-
return annotations != null ? annotations.get(Const.PLATFORM_VARIANT) : null;
216+
public Platform withOsFeatures(List<String> osFeatures) {
217+
return new Platform(os, architecture, osVersion, variant, features, osFeatures);
137218
}
138219

139220
/**
@@ -144,4 +225,34 @@ public String architecture() {
144225
public static boolean unspecified(Platform platform) {
145226
return platform.equals(Platform.empty()) || platform.equals(Platform.unknown());
146227
}
228+
229+
/**
230+
* Check if 2 platform are matching, which means the os and architecture are the same (including variant)
231+
* @param platform The platform to check
232+
* @param target The target platform to match
233+
* @return True if the platform is matching, false otherwise
234+
*/
235+
public static boolean matches(Platform platform, Platform target) {
236+
return matches(platform, target, false);
237+
}
238+
239+
/**
240+
* Check if 2 platform are matching, which means the os and architecture are the same (including variant)
241+
* @param platform The platform to check
242+
* @param target The target platform to match
243+
* @param includeVersion Whether to include os version
244+
* @return True if the platform is matching, false otherwise
245+
*/
246+
public static boolean matches(Platform platform, Platform target, boolean includeVersion) {
247+
if (!platform.os().equals(target.os()) || !platform.architecture().equals(target.architecture())) {
248+
return false;
249+
}
250+
if (!Objects.equals(platform.variant(), target.variant())) {
251+
return false;
252+
}
253+
if (includeVersion) {
254+
return Objects.equals(platform.osVersion(), target.osVersion());
255+
}
256+
return true;
257+
}
147258
}

0 commit comments

Comments
 (0)