Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/devonfw#158-version-rang…
Browse files Browse the repository at this point in the history
…e-with-open-intervals' into feature/devonfw#103-implement-version-security-checks

# Conflicts:
#	cli/src/test/java/com/devonfw/tools/ide/version/VersionRangeTest.java
  • Loading branch information
MattesMrzik committed Dec 19, 2023
2 parents 7e2023e + 9574f8d commit 64c8454
Show file tree
Hide file tree
Showing 5 changed files with 286 additions and 12 deletions.
19 changes: 19 additions & 0 deletions cli/src/main/java/com/devonfw/tools/ide/version/BoundaryType.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.devonfw.tools.ide.version;

/**
* Enum representing the type of interval regarding its boundaries.
*/
public enum BoundaryType {

/** Closed interval - includes the specified values at the boundaries. */
CLOSED,

/** Open interval - excludes the specified values at the boundaries. */
OPEN,

/** Left open interval - excludes the lower bound but includes the upper bound. */
LEFT_OPEN,

/** Right open interval - includes the lower bound but excludes the upper bound. */
RIGHT_OPEN
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
/**
* Abstract base interface for a version object such as {@link VersionIdentifier} and {@link VersionSegment}.
*
*
* {@link Comparable} for versions with an extended contract. If two versions are not strictly comparable (e.g.
* "1.apple" and "1.banana") we fall back to some heuristics (e.g. lexicographical comparison for
* {@link VersionSegment#getLettersString() letters} that we do not understand (e.g. "apple" < "banana"). Therefore you can
* use {@link #compareVersion(Object)} to get a {@link VersionComparisonResult} that contains the additional information
* as {@link VersionComparisonResult#isUnsafe() unsafe} flag.
* {@link VersionSegment#getLettersString() letters} that we do not understand (e.g. "apple" < "banana"). Therefore, you
* can use {@link #compareVersion(Object)} to get a {@link VersionComparisonResult} that contains the additional
* information as {@link VersionComparisonResult#isUnsafe() unsafe} flag.
*
* @param <T> type of the object to compare (this class itself).
*/
Expand Down
137 changes: 134 additions & 3 deletions cli/src/main/java/com/devonfw/tools/ide/version/VersionRange.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,20 @@
import com.fasterxml.jackson.annotation.JsonValue;

/**
* Container for a range of versions.
* Container for a range of versions. The lower and upper bounds can be exclusive or inclusive. If a bound is null, it
* means that this direction is unbounded. The boolean defining whether this bound is inclusive or exclusive is ignored
* in this case.
*/
public final class VersionRange implements Comparable<VersionRange> {

private final VersionIdentifier min;

private final VersionIdentifier max;

private final boolean leftIsExclusive;

private final boolean rightIsExclusive;

/**
* The constructor.
*
Expand All @@ -24,6 +30,42 @@ public VersionRange(VersionIdentifier min, VersionIdentifier max) {
super();
this.min = min;
this.max = max;
this.leftIsExclusive = false;
this.rightIsExclusive = false;
}

/**
* The constructor.
*
* @param min the {@link #getMin() minimum}.
* @param max the {@link #getMax() maximum}.
* @param boundaryType the {@link BoundaryType} defining whether the boundaries of the range are inclusive or
* exclusive.
*/
public VersionRange(VersionIdentifier min, VersionIdentifier max, BoundaryType boundaryType) {

super();
this.min = min;
this.max = max;
this.leftIsExclusive = BoundaryType.LEFT_OPEN.equals(boundaryType) || BoundaryType.OPEN.equals(boundaryType);
this.rightIsExclusive = BoundaryType.RIGHT_OPEN.equals(boundaryType) || BoundaryType.OPEN.equals(boundaryType);
}

/**
* The constructor.
*
* @param min the {@link #getMin() minimum}.
* @param max the {@link #getMax() maximum}.
* @param leftIsExclusive - {@code true} if the {@link #getMin() minimum} is exclusive, {@code false} otherwise.
* @param rightIsExclusive - {@code true} if the {@link #getMax() maximum} is exclusive, {@code false} otherwise.
*/
public VersionRange(VersionIdentifier min, VersionIdentifier max, boolean leftIsExclusive, boolean rightIsExclusive) {

super();
this.min = min;
this.max = max;
this.leftIsExclusive = leftIsExclusive;
this.rightIsExclusive = rightIsExclusive;
}

/**
Expand All @@ -44,6 +86,38 @@ public VersionIdentifier getMax() {
return this.max;
}

/**
* @return {@code true} if the {@link #getMin() minimum} is exclusive, {@code false} otherwise.
*/
public boolean isLeftExclusive() {

return this.leftIsExclusive;
}

/**
* @return {@code true} if the {@link #getMax() maximum} is exclusive, {@code false} otherwise.
*/
public boolean isRightExclusive() {

return this.rightIsExclusive;
}

/**
* @return the {@link BoundaryType} defining whether the boundaries of the range are inclusive or exclusive.
*/
public BoundaryType getBoundaryType() {

if (this.leftIsExclusive && this.rightIsExclusive) {
return BoundaryType.OPEN;
} else if (this.leftIsExclusive) {
return BoundaryType.LEFT_OPEN;
} else if (this.rightIsExclusive) {
return BoundaryType.RIGHT_OPEN;
} else {
return BoundaryType.CLOSED;
}
}

/**
* @param version the {@link VersionIdentifier} to check.
* @return {@code true} if the given {@link VersionIdentifier} is contained in this {@link VersionRange},
Expand All @@ -52,11 +126,17 @@ public VersionIdentifier getMax() {
public boolean contains(VersionIdentifier version) {

if (this.min != null) {
if (this.min.equals(version)) {
return !this.leftIsExclusive;
}
if (version.isLess(this.min)) {
return false;
}
}
if (this.max != null) {
if (this.max.equals(version)) {
return !this.rightIsExclusive;
}
if (version.isGreater(this.max)) {
return false;
}
Expand All @@ -75,7 +155,37 @@ public int compareTo(VersionRange o) {
}
return -1;
}
return this.min.compareTo(o.min);
int compareMins = this.min.compareTo(o.min);
if (compareMins == 0) {
return this.leftIsExclusive == o.leftIsExclusive ? 0 : this.leftIsExclusive ? 1 : -1;
} else {
return compareMins;
}
}

@Override
public boolean equals(Object obj) {

if (this == obj)
return true;

if (obj == null || getClass() != obj.getClass())
return false;

VersionRange o = (VersionRange) obj;

if (this.min == null && this.max == null) {
return o.min == null && o.max == null;
}
if (this.min == null) {
return o.min == null && this.max.equals(o.max) && this.rightIsExclusive == o.rightIsExclusive;
}
if (this.max == null) {
return this.min.equals(o.min) && o.max == null && this.leftIsExclusive == o.leftIsExclusive;
}
return this.min.equals(o.min) && this.leftIsExclusive == o.leftIsExclusive && this.max.equals(o.max)
&& this.rightIsExclusive == o.rightIsExclusive;

}

@Override
Expand Down Expand Up @@ -107,13 +217,15 @@ public boolean equals(Object obj) {
public String toString() {

StringBuilder sb = new StringBuilder();
sb.append(this.leftIsExclusive ? '(' : '[');
if (this.min != null) {
sb.append(this.min);
}
sb.append('>');
if (this.max != null) {
sb.append(this.max);
}
sb.append(this.rightIsExclusive ? ')' : ']');
return sb.toString();
}

Expand All @@ -124,10 +236,29 @@ public String toString() {
@JsonCreator
public static VersionRange of(String value) {

boolean leftIsExclusive = false;
boolean rightIsExclusive = false;

if (value.startsWith("(")) {
leftIsExclusive = true;
value = value.substring(1);
}
if (value.startsWith("[")) {
value = value.substring(1);
}
if (value.endsWith(")")) {
rightIsExclusive = true;
value = value.substring(0, value.length() - 1);
}
if (value.endsWith("]")) {
value = value.substring(0, value.length() - 1);
}

int index = value.indexOf('>');
if (index == -1) {
return null; // log warning?
}

VersionIdentifier min = null;
if (index > 0) {
min = VersionIdentifier.of(value.substring(0, index));
Expand All @@ -137,7 +268,7 @@ public static VersionRange of(String value) {
if (!maxString.isEmpty()) {
max = VersionIdentifier.of(maxString);
}
return new VersionRange(min, max);
return new VersionRange(min, max, leftIsExclusive, rightIsExclusive);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ protected static IdeTestContext newContext(String projectName, String projectPat
* in that project.
* @return the {@link IdeTestContext} pointing to that project.
*/
protected static IdeTestContext newContext(String projectName, String projectPath, boolean copyForMutation, String ... answers) {
protected static IdeTestContext newContext(String projectName, String projectPath, boolean copyForMutation,
String... answers) {

Path sourceDir = PATH_PROJECTS.resolve(projectName);
Path userDir = sourceDir;
Expand Down
Loading

0 comments on commit 64c8454

Please sign in to comment.