-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(semver): replace semver library with translation from node-semver #21
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
/* | ||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
* SPDX-License-Identifier: Apache-2.0 | ||
* | ||
* Translated from node-semver: | ||
* | ||
* The ISC License | ||
* Copyright (c) Isaac Z. Schlueter and Contributors | ||
* | ||
* See com.amazon.aws.iot.greengrass.semver.THIRD-PARTY-LICENSE | ||
*/ | ||
|
||
package com.amazon.aws.iot.greengrass.semver; | ||
|
||
import lombok.EqualsAndHashCode; | ||
|
||
import java.util.Objects; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
@EqualsAndHashCode | ||
public class Comparator { | ||
public final String value; | ||
private String operator; | ||
public SemVer semver; | ||
public static final AnySemVer ANY = Comparator.AnySemVer.ANY; | ||
|
||
public Comparator(String comp) { | ||
this.parse(comp); | ||
|
||
if (this.semver == ANY) { | ||
this.value = ""; | ||
} else { | ||
this.value = this.operator + this.semver.getVersion(); | ||
} | ||
} | ||
|
||
private void parse (String comp) { | ||
Pattern r = SemVerRegexes.re.get(SemVerRegexes.t.get("COMPARATOR")); | ||
Matcher m = r.matcher(comp); | ||
|
||
if (!m.find()) { | ||
throw new IllegalArgumentException("Invalid comparator " + comp); | ||
} | ||
|
||
this.operator = m.group(1) != null ? m.group(1) : ""; | ||
if (this.operator.equals("=")) { | ||
this.operator = ""; | ||
} | ||
|
||
// if it literally is just '>' or '' then allow anything. | ||
if (m.group(2) == null) { | ||
this.semver = ANY; | ||
} else { | ||
this.semver = new SemVer(m.group(2)); | ||
} | ||
} | ||
|
||
public boolean test (Object version) { | ||
if (this.semver == ANY || version == ANY) { | ||
return true; | ||
} | ||
|
||
if (version instanceof String) { | ||
try { | ||
version = new SemVer((String) version); | ||
} catch (RuntimeException e) { | ||
return false; | ||
} | ||
} | ||
|
||
return cmp((SemVer) version, this.operator, this.semver); | ||
} | ||
|
||
public static boolean cmp(SemVer a, String op, SemVer b) { | ||
switch (op) { | ||
case "===": | ||
return a.getVersion().equals(b.getVersion()); | ||
case "!==": | ||
return !a.getVersion().equals(b.getVersion()); | ||
case "": | ||
case "=": | ||
case "==": | ||
return eq(a, b); | ||
case "!=": | ||
return neq(a, b); | ||
case ">": | ||
return gt(a, b); | ||
case ">=": | ||
return gte(a, b); | ||
case "<": | ||
return lt(a, b); | ||
case "<=": | ||
return lte(a, b); | ||
default: | ||
throw new IllegalArgumentException("Invalid operator " + op); | ||
} | ||
} | ||
|
||
public static boolean eq(SemVer a, SemVer b){ | ||
return a.compareTo(b) == 0; | ||
} | ||
|
||
public static boolean neq(SemVer a, SemVer b){ | ||
return a.compareTo(b) != 0; | ||
} | ||
|
||
public static boolean gt(SemVer a, SemVer b){ | ||
return a.compareTo(b) > 0; | ||
} | ||
|
||
public static boolean gte(SemVer a, SemVer b){ | ||
return a.compareTo(b) >= 0; | ||
} | ||
|
||
public static boolean lt(SemVer a, SemVer b){ | ||
return a.compareTo(b) < 0; | ||
} | ||
|
||
public static boolean lte(SemVer a, SemVer b){ | ||
return a.compareTo(b) <= 0; | ||
} | ||
|
||
public boolean intersects (Comparator comp) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Recommendation generated by Amazon CodeGuru Reviewer. Leave feedback on this recommendation by replying to the comment or by reacting to the comment using emoji. The cyclomatic complexity of this method is 22. By comparison, 99% of the methods in the CodeGuru reference dataset have a lower cyclomatic complexity. This indicates the method has a high number of decisions and it can make the logic difficult to understand and test. We recommend that you simplify this method or break it into multiple methods. For example, consider extracting the code block on lines 125-135 into a separate method. |
||
if (this.operator.equals("")) { | ||
if (this.value.equals("")) { | ||
return true; | ||
} | ||
return new Range(comp.value).test(this.semver); | ||
} else if (comp.operator.equals("")) { | ||
if (comp.value.equals("")) { | ||
return true; | ||
} | ||
return new Range(this.value).test(comp.semver); | ||
} | ||
|
||
boolean sameDirectionIncreasing = | ||
(this.operator.equals(">=") || this.operator.equals(">")) && | ||
(comp.operator.equals(">=") || comp.operator.equals(">")); | ||
boolean sameDirectionDecreasing = | ||
(this.operator.equals("<=") || this.operator.equals("<")) && | ||
(comp.operator.equals("<=") || comp.operator.equals("<")); | ||
boolean sameSemVer = Objects.equals(this.semver.getVersion(), comp.semver.getVersion()); | ||
boolean differentDirectionsInclusive = | ||
(this.operator.equals(">=") || this.operator.equals("<=")) && | ||
(comp.operator.equals(">=") || comp.operator.equals("<=")); | ||
boolean oppositeDirectionsLessThan = | ||
cmp(this.semver, "<", comp.semver) && | ||
(Objects.equals(this.operator, ">=") || Objects.equals(this.operator, ">")) && | ||
(Objects.equals(comp.operator, "<=") || Objects.equals(comp.operator, "<")); | ||
boolean oppositeDirectionsGreaterThan = | ||
cmp(this.semver, ">", comp.semver) && | ||
(Objects.equals(this.operator, "<=") || Objects.equals(this.operator, "<")) && | ||
(Objects.equals(comp.operator, ">=") || Objects.equals(comp.operator, ">")); | ||
|
||
return ( | ||
sameDirectionIncreasing || | ||
sameDirectionDecreasing || | ||
(sameSemVer && differentDirectionsInclusive) || | ||
oppositeDirectionsLessThan || | ||
oppositeDirectionsGreaterThan | ||
); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return this.value; | ||
} | ||
|
||
public static class AnySemVer extends SemVer { | ||
final static AnySemVer ANY = new AnySemVer(); | ||
private AnySemVer() { | ||
super("0.0.0"); | ||
} | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are Requirements and Ranges equivalent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's the semver term for what the other library called a requirement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd recommend downloading this branch and then writing test code to play around with it and check whatever you think is needed. Just a code review with this volume of code is unlikely to find anything.