Skip to content

Commit 6e11a3c

Browse files
committed
Merge remote-tracking branch 'upstream/master' into update-test-suite
2 parents 498f3b0 + f16a2eb commit 6e11a3c

File tree

1 file changed

+76
-75
lines changed

1 file changed

+76
-75
lines changed

src/main/java/com/github/packageurl/PackageURL.java

Lines changed: 76 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,52 @@ public final class PackageURL implements Serializable {
6262

6363
private static final char PERCENT_CHAR = '%';
6464

65+
/**
66+
* The PackageURL scheme constant
67+
*/
68+
public static final String SCHEME = "pkg";
69+
70+
/**
71+
* The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
72+
*/
73+
private static final String SCHEME_PART = SCHEME + ':';
74+
75+
/**
76+
* The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
77+
* Required.
78+
*/
79+
private String type;
80+
81+
/**
82+
* The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization.
83+
* Optional and type-specific.
84+
*/
85+
private @Nullable String namespace;
86+
87+
/**
88+
* The name of the package.
89+
* Required.
90+
*/
91+
private String name;
92+
93+
/**
94+
* The version of the package.
95+
* Optional.
96+
*/
97+
private @Nullable String version;
98+
99+
/**
100+
* Extra qualifying data for a package such as an OS, architecture, a distro, etc.
101+
* Optional and type-specific.
102+
*/
103+
private @Nullable Map<String, String> qualifiers;
104+
105+
/**
106+
* Extra subpath within a package, relative to the package root.
107+
* Optional.
108+
*/
109+
private @Nullable String subpath;
110+
65111
/**
66112
* Constructs a new PackageURL object by parsing the specified string.
67113
*
@@ -111,12 +157,12 @@ public PackageURL(
111157
final @Nullable String subpath)
112158
throws MalformedPackageURLException {
113159
this.type = toLowerCase(validateType(requireNonNull(type, "type")));
114-
this.namespace = validateNamespace(namespace);
115-
this.name = validateName(requireNonNull(name, "name"));
160+
this.namespace = validateNamespace(this.type, namespace);
161+
this.name = validateName(this.type, requireNonNull(name, "name"));
116162
this.version = validateVersion(type, version);
117163
this.qualifiers = parseQualifiers(qualifiers);
118164
this.subpath = validateSubpath(subpath);
119-
verifyTypeConstraints(this.type, this.namespace, this.name);
165+
verifyTypeConstraints(this.type, this.namespace, this.name, this.version, this.qualifiers);
120166
}
121167

122168
/**
@@ -143,52 +189,6 @@ public PackageURL(
143189
this(type, namespace, name, version, (qualifiers != null) ? new TreeMap<>(qualifiers) : null, subpath);
144190
}
145191

146-
/**
147-
* The PackageURL scheme constant
148-
*/
149-
public static final String SCHEME = "pkg";
150-
151-
/**
152-
* The PackageURL scheme ({@code "pkg"}) constant followed by a colon ({@code ':'}).
153-
*/
154-
private static final String SCHEME_PART = SCHEME + ':';
155-
156-
/**
157-
* The package "type" or package "protocol" such as maven, npm, nuget, gem, pypi, etc.
158-
* Required.
159-
*/
160-
private String type;
161-
162-
/**
163-
* The name prefix such as a Maven groupid, a Docker image owner, a GitHub user or organization.
164-
* Optional and type-specific.
165-
*/
166-
private @Nullable String namespace;
167-
168-
/**
169-
* The name of the package.
170-
* Required.
171-
*/
172-
private String name;
173-
174-
/**
175-
* The version of the package.
176-
* Optional.
177-
*/
178-
private @Nullable String version;
179-
180-
/**
181-
* Extra qualifying data for a package such as an OS, architecture, a distro, etc.
182-
* Optional and type-specific.
183-
*/
184-
private @Nullable Map<String, String> qualifiers;
185-
186-
/**
187-
* Extra subpath within a package, relative to the package root.
188-
* Optional.
189-
*/
190-
private @Nullable String subpath;
191-
192192
/**
193193
* Converts this {@link PackageURL} to a {@link PackageURLBuilder}.
194194
*
@@ -276,7 +276,7 @@ public Map<String, String> getQualifiers() {
276276
return subpath;
277277
}
278278

279-
private void validateScheme(final String value) throws MalformedPackageURLException {
279+
private static void validateScheme(final String value) throws MalformedPackageURLException {
280280
if (!SCHEME.equals(value)) {
281281
throw new MalformedPackageURLException(
282282
"The PackageURL scheme '" + value + "' is invalid. It should be '" + SCHEME + "'");
@@ -321,14 +321,16 @@ private static void validateChars(String value, IntPredicate predicate, String c
321321
}
322322
}
323323

324-
private @Nullable String validateNamespace(final @Nullable String value) throws MalformedPackageURLException {
324+
private static @Nullable String validateNamespace(final String type, final @Nullable String value)
325+
throws MalformedPackageURLException {
325326
if (isEmpty(value)) {
326327
return null;
327328
}
328-
return validateNamespace(value.split("/"));
329+
return validateNamespace(type, value.split("/"));
329330
}
330331

331-
private @Nullable String validateNamespace(final String[] values) throws MalformedPackageURLException {
332+
private static @Nullable String validateNamespace(final String type, final String[] values)
333+
throws MalformedPackageURLException {
332334
if (values.length == 0) {
333335
return null;
334336
}
@@ -362,7 +364,7 @@ private static void validateChars(String value, IntPredicate predicate, String c
362364
return retVal;
363365
}
364366

365-
private String validateName(final String value) throws MalformedPackageURLException {
367+
private static String validateName(final String type, final String value) throws MalformedPackageURLException {
366368
if (value.isEmpty()) {
367369
throw new MalformedPackageURLException("The PackageURL name specified is invalid");
368370
}
@@ -393,7 +395,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
393395
return temp;
394396
}
395397

396-
private @Nullable String validateVersion(final String type, final @Nullable String value) {
398+
private static @Nullable String validateVersion(final String type, final @Nullable String value) {
397399
if (value == null) {
398400
return null;
399401
}
@@ -408,7 +410,7 @@ private String validateName(final String value) throws MalformedPackageURLExcept
408410
}
409411
}
410412

411-
private @Nullable Map<String, String> validateQualifiers(final @Nullable Map<String, String> values)
413+
private static @Nullable Map<String, String> validateQualifiers(final @Nullable Map<String, String> values)
412414
throws MalformedPackageURLException {
413415
if (values == null || values.isEmpty()) {
414416
return null;
@@ -438,7 +440,7 @@ private static void validateValue(final String key, final @Nullable String value
438440
}
439441
}
440442

441-
private @Nullable String validateSubpath(final @Nullable String value) throws MalformedPackageURLException {
443+
private static @Nullable String validateSubpath(final @Nullable String value) throws MalformedPackageURLException {
442444
if (isEmpty(value)) {
443445
return null;
444446
}
@@ -597,20 +599,13 @@ private static String toLowerCase(String s) {
597599
return new String(chars);
598600
}
599601

600-
private static int indexOfPercentChar(final byte[] bytes, final int start) {
601-
return IntStream.range(start, bytes.length)
602+
private static int indexOfFirstPercentChar(final byte[] bytes) {
603+
return IntStream.range(0, bytes.length)
602604
.filter(i -> isPercent(bytes[i]))
603605
.findFirst()
604606
.orElse(-1);
605607
}
606608

607-
private static int indexOfUnsafeChar(final byte[] bytes, final int start) {
608-
return IntStream.range(start, bytes.length)
609-
.filter(i -> shouldEncode(bytes[i]))
610-
.findFirst()
611-
.orElse(-1);
612-
}
613-
614609
private static byte percentDecode(final byte[] bytes, final int start) {
615610
if (start + 2 >= bytes.length) {
616611
throw new ValidationException("Incomplete percent encoding at offset " + start + " with value '"
@@ -644,7 +639,7 @@ private static String percentDecode(final String source) {
644639
}
645640

646641
byte[] bytes = source.getBytes(StandardCharsets.UTF_8);
647-
int i = indexOfPercentChar(bytes, 0);
642+
int i = indexOfFirstPercentChar(bytes);
648643

649644
if (i == -1) {
650645
return source;
@@ -779,13 +774,13 @@ private void parse(final String purl) throws MalformedPackageURLException {
779774
// The 'remainder' should now consist of an optional namespace and the name
780775
index = remainder.lastIndexOf('/');
781776
if (index <= start) {
782-
this.name = validateName(percentDecode(remainder.substring(start)));
777+
this.name = validateName(this.type, percentDecode(remainder.substring(start)));
783778
} else {
784-
this.name = validateName(percentDecode(remainder.substring(index + 1)));
779+
this.name = validateName(this.type, percentDecode(remainder.substring(index + 1)));
785780
remainder = remainder.substring(0, index);
786-
this.namespace = validateNamespace(parsePath(remainder.substring(start), false));
781+
this.namespace = validateNamespace(this.type, parsePath(remainder.substring(start), false));
787782
}
788-
verifyTypeConstraints(this.type, this.namespace, this.name);
783+
verifyTypeConstraints(this.type, this.namespace, this.name, this.version, this.qualifiers);
789784
} catch (URISyntaxException e) {
790785
throw new MalformedPackageURLException("Invalid purl: " + e.getMessage(), e);
791786
}
@@ -797,7 +792,12 @@ private void parse(final String purl) throws MalformedPackageURLException {
797792
* @param namespace the purl namespace
798793
* @throws MalformedPackageURLException if constraints are not met
799794
*/
800-
private void verifyTypeConstraints(final String type, final String namespace, final String name)
795+
private void verifyTypeConstraints(
796+
final String type,
797+
final @Nullable String namespace,
798+
final @Nullable String name,
799+
final @Nullable String version,
800+
final @Nullable Map<String, String> qualifiers)
801801
throws MalformedPackageURLException {
802802
switch (type) {
803803
case StandardTypes.CONAN:
@@ -843,6 +843,7 @@ private void verifyTypeConstraints(final String type, final String namespace, fi
843843
URL url = new URL(repositoryUrl);
844844
host = url.getHost();
845845
if (host.matches(".*[.]?azuredatabricks.net$")) {
846+
// TODO: Move this eventually
846847
this.name = name.toLowerCase();
847848
}
848849
} catch (MalformedURLException e) {
@@ -862,7 +863,7 @@ private void verifyTypeConstraints(final String type, final String namespace, fi
862863
}
863864
}
864865

865-
private @Nullable Map<String, String> parseQualifiers(final @Nullable Map<String, String> qualifiers)
866+
private static @Nullable Map<String, String> parseQualifiers(final @Nullable Map<String, String> qualifiers)
866867
throws MalformedPackageURLException {
867868
if (qualifiers == null || qualifiers.isEmpty()) {
868869
return null;
@@ -882,7 +883,7 @@ private void verifyTypeConstraints(final String type, final String namespace, fi
882883
}
883884

884885
@SuppressWarnings("StringSplitter") // reason: surprising behavior is okay in this case
885-
private @Nullable Map<String, String> parseQualifiers(final String encodedString)
886+
private static @Nullable Map<String, String> parseQualifiers(final String encodedString)
886887
throws MalformedPackageURLException {
887888
try {
888889
final TreeMap<String, String> results = Arrays.stream(encodedString.split("&"))
@@ -913,7 +914,7 @@ private static String[] parsePath(final String value, final boolean isSubpath) {
913914
.toArray(String[]::new);
914915
}
915916

916-
private String encodePath(final String path) {
917+
private static String encodePath(final String path) {
917918
return Arrays.stream(path.split("/")).map(PackageURL::percentEncode).collect(Collectors.joining("/"));
918919
}
919920

0 commit comments

Comments
 (0)