DependencyResolver rewrite, likely broken

This seems to work, but it probably has lots of bugs as I can't really test it efficiently. Need to write unit tests for this, aw man...

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
So we back in the mine
Got our pickaxe swinging from side to side
Side-side to side
This task, a grueling one
Hope to find some diamonds tonight, night, night
Diamonds tonight

Heads up
You hear a sound, turn around and look up
Total shock fills your body
Oh, no, it's you again
I can never forget those eyes, eyes, eyes
Eyes-eye-eyes

'Cause, baby, tonight
The creeper's tryna steal all our stuff again
'Cause, baby, tonight
You grab your pick, shoval and bolt again (Bolt again-gain)
And run, run until it's done, done
Until the sun comes up in the morn'
'Cause, baby, tonight
The creeper's tryna steal all our stuff again (Stuff again-gain)

Just when you think you're safe
Overhear some hissing from right behind
Right-right behind
THat's a nice life you have
Shame it's gotta end at this time, time, time
Time-time-time-time

Then your health bar drops and you could use a one-up
Get inside, don't be tardy
So, now you're stuck in there
Half a heart is left, but don't die, die, die
Die-die-die

'Cause, baby, tonight
The creeper's tryna steal all our stuff again
'Cause, baby, tonight
You grab your pick, shovel and bolt again (Bolt again-gain)

(Creepers, you're mine, haha)
Dig up diamonds and craft those diamonds
And make some armor, get it, baby
Go and forge that like you so MLG pro
The sword's made of diamonds, so come at me, bro, huh
Training in your room under the torchlight
Hone that form to get you ready for the big fight
Every single day and the whole night
Creeper's out prowlin', hoo, alright
Look at me, look at you
Take my revenge, that's what I'm gonna do
I'm a warrior, baby, what else is new?
And my blade's gonna tear through you, bring it

'Cause, baby, tonight
The creeper's tryna steal all our stuff again
(Gather your stuff, yeah, let's take back the world)
Yeah, baby, tonight (Haha)
Grab your sword, armor and go (It's on)
Take your revenge (Woo), oh-oh, oh-oh
So fight, fight, like it's the last, last night
Of your life, life, show them your bite (Woo)

'Cause, baby, tonight
The creeper's tryna steal all our stuff again
'Cause, baby, tonight
You grab your pick, shovel and bolt again (Bolt again-gain, woo)
And run, run until it's done, done
Until the sun comes up in the morn'
'Cause, baby, tonight (Come on, swing your sword up high)
The creeper's tryna steal all our stuff again (Come on, jab your sword down low)
(Woo)
This commit is contained in:
JeremyStar™ 2024-08-17 21:57:10 +02:00
parent 72b40613b8
commit 081ac106f4
Signed by: JeremyStarTM
GPG key ID: E366BAEF67E4704D

View file

@ -19,15 +19,17 @@
package de.staropensource.sosengine.base.utility;
import de.staropensource.sosengine.base.classes.VersioningSystem;
import de.staropensource.sosengine.base.exceptions.UnexpectedThrowableException;
import de.staropensource.sosengine.base.exceptions.dependency.UnmetDependenciesException;
import de.staropensource.sosengine.base.logging.LoggerInstance;
import de.staropensource.sosengine.base.types.DependencyVector;
import de.staropensource.sosengine.base.types.immutable.ImmutableArrayList;
import de.staropensource.sosengine.base.types.immutable.ImmutableLinkedList;
import lombok.Getter;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
/**
@ -38,18 +40,33 @@ import java.util.*;
@SuppressWarnings({ "unused", "UnusedReturnValue", "JavadocDeclaration" })
public final class DependencyResolver {
/**
* A list of {@link DependencyVector}s.
* Contains the {@link LoggerInstance} for this instance.
*
* @see LoggerInstance
* @since v1-alpha4
*/
private final @NotNull LoggerInstance logger = new LoggerInstance.Builder().setClazz(getClass()).setOrigin("ENGINE").setMetadata(String.valueOf(hashCode())).build();
/**
* List of {@link DependencyVector}s to resolve.
*
* @since v1-alpha1
*/
List<DependencyVector> vectors = new ArrayList<>();
Set<DependencyVector> vectors = new HashSet<>();
/**
* {@code true} if the current {@link DependencyVector} list has been resolved successfully.
* List of identifiers of already resolved vectors.
*
* @since v1-alpha4
*/
Set<@NotNull String> vectorsResolved = new HashSet<>();
/**
* Contains whether the current {@link DependencyVector} list has been resolved successfully.
*
* @since v1-alpha1
* -- GETTER --
* Returns {@code true} if the current {@link DependencyVector} list has been resolved successfully.
* Returns whether the current {@link DependencyVector} list has been resolved successfully.
*
* @return resolved status
* @since v1-alpha1
@ -72,7 +89,9 @@ public final class DependencyResolver {
* @since v1-alpha1
*/
public synchronized DependencyResolver addVector(@NotNull DependencyVector vector) {
vectors.add(vector);
try {
vectors.add(vector);
} catch (IllegalArgumentException ignored) {}
resolved = false;
return this;
}
@ -84,10 +103,8 @@ public final class DependencyResolver {
* @return itself
* @since v1-alpha1
*/
public synchronized DependencyResolver addVectors(@NotNull DependencyVector[] vectors) {
addVectors(Arrays.stream(vectors).toList());
resolved = false;
return this;
public DependencyResolver addVectors(@NotNull DependencyVector[] vectors) {
return addVectors(Arrays.stream(vectors).toList());
}
/**
@ -97,61 +114,9 @@ public final class DependencyResolver {
* @return itself
* @since v1-alpha1
*/
public synchronized DependencyResolver addVectors(@NotNull Collection<? extends @NotNull DependencyVector> vectors) {
this.vectors.addAll(vectors);
resolved = false;
return this;
}
/**
* Adds multiple dependency vectors.
*
* @param vectors dependency vectors to add
* @return itself
* @since v1-alpha1
*/
public synchronized DependencyResolver addVectors(@NotNull List<? extends @NotNull DependencyVector> vectors) {
this.vectors.addAll(vectors);
resolved = false;
return this;
}
/**
* Adds multiple dependency vectors.
*
* @param vectors dependency vectors to add
* @return itself
* @since v1-alpha1
*/
public synchronized DependencyResolver addVectors(@NotNull ImmutableArrayList<? extends @NotNull DependencyVector> vectors) {
this.vectors.addAll(vectors);
resolved = false;
return this;
}
/**
* Adds multiple dependency vectors.
*
* @param vectors dependency vectors to add
* @return itself
* @since v1-alpha1
*/
public synchronized DependencyResolver addVectors(@NotNull ImmutableLinkedList<? extends @NotNull DependencyVector> vectors) {
this.vectors.addAll(vectors);
resolved = false;
return this;
}
/**
* Adds multiple dependency vectors.
*
* @param vectors dependency vectors to add
* @return itself
* @since v1-alpha1
*/
public synchronized DependencyResolver addVectors(@NotNull Set<? extends @NotNull DependencyVector> vectors) {
this.vectors.addAll(vectors);
resolved = false;
public DependencyResolver addVectors(@NotNull Collection<? extends @NotNull DependencyVector> vectors) {
for (DependencyVector vector : vectors) // thread-safety
addVector(vector);
return this;
}
@ -161,100 +126,252 @@ public final class DependencyResolver {
*
* @return itself
* @throws UnmetDependenciesException when dependencies are unmet
* @throws IllegalStateException when encountering an invalid dependency or provider
* @throws UnexpectedThrowableException when some unknown error occurs
* @since v1-alpha1
*/
@SuppressWarnings("JavaReflectionInvocation")
public synchronized DependencyResolver resolve() throws UnmetDependenciesException, UnexpectedThrowableException {
Map<DependencyVector, String> unmetDependencies = new HashMap<>();
resolved = false;
try {
for (DependencyVector vector : vectors)
for (String dependency : vector.getDependencies()) {
int match = 0;
if (dependency.contains("=")) {
String dependencyIdentifier = dependency.substring(0, dependency.indexOf("="));
String dependencyVersion = dependency.substring(dependency.indexOf("="));
for (DependencyVector vectorCheck : vectors)
if (vectorCheck.getIdentifier().equals(dependency)) {
if (vectorCheck.getVersioningSystem().getDeclaredConstructor().newInstance(dependencyVersion).compare(vectorCheck.getVersioningSystem().getDeclaredConstructor().newInstance(vectorCheck.getVersion())) == 1)
match = -1;
else
match = 2;
break;
}
if (match == 0)
unmetDependencies.put(vector, "Depends on '" + dependencyIdentifier + "', which is missing");
else {
unmetDependencies.put(vector, "Depends exactly on '" + dependency + "', which is not installed");
}
} else if (dependency.contains("<")) {
String dependencyIdentifier = dependency.substring(0, dependency.indexOf("<"));
String dependencyVersion = dependency.substring(dependency.indexOf("<"));
for (DependencyVector vectorCheck : vectors)
if (vectorCheck.getIdentifier().equals(dependency)) {
if (vectorCheck.getVersioningSystem().getDeclaredConstructor().newInstance(dependencyVersion).compare(vectorCheck.getVersioningSystem().getDeclaredConstructor().newInstance(vectorCheck.getVersion())) == 0)
match = -1;
else
match = 2;
break;
}
if (match == 0)
unmetDependencies.put(vector, "Depends on '" + dependencyIdentifier + "', which is missing");
else {
unmetDependencies.put(vector, "Depends at maximum on '" + dependency + "', which is not installed");
}
} else if (dependency.contains(">")) {
String dependencyIdentifier = dependency.substring(0, dependency.indexOf(">"));
String dependencyVersion = dependency.substring(dependency.indexOf(">"));
for (DependencyVector vectorCheck : vectors)
if (vectorCheck.getIdentifier().equals(dependency)) {
if (vectorCheck.getVersioningSystem().getDeclaredConstructor().newInstance(dependencyVersion).compare(vectorCheck.getVersioningSystem().getDeclaredConstructor().newInstance(vectorCheck.getVersion())) == 2)
match = -1;
else
match = 2;
break;
}
if (match == 0)
unmetDependencies.put(vector, "Depends on '" + dependencyIdentifier + "', which is missing");
else {
unmetDependencies.put(vector, "Depends at minimum on '" + dependency + "', which is not installed");
}
} else {
for (DependencyVector vectorCheck : vectors)
if (vectorCheck.getIdentifier().equals(dependency)) {
match = -1;
break;
}
if (match == 0)
unmetDependencies.put(vector, "Depends on any version of '" + dependency + "', which is missing");
}
}
} catch (Exception exception) {
// Throw UnexpectedThrowableException when something horribly fails
throw new UnexpectedThrowableException(exception);
for (DependencyVector vector : vectors) {
if (!vectorsResolved.contains(vector.getIdentifier())) {
resolveVector(vector);
vectorsResolved.add(vector.getIdentifier());
}
}
// Check for any unmet dependencies
if (!unmetDependencies.isEmpty())
throw new UnmetDependenciesException(unmetDependencies);
resolved = true;
return this;
}
/**
* Resolves a vector.
* Throws an exception when detecting an unmet dependency or a dependency cycle.
*
* @return list of unmet dependencies
* @throws IllegalStateException when encountering an invalid dependency or provider
* @throws Exception when some unknown error occurs
* @since v1-alpha4
*/
private @NotNull List<@NotNull String> resolveVector(@NotNull DependencyVector vector) throws IllegalStateException {
List<@NotNull String> unmetDependencies = new ArrayList<>();
// provides
for (String dependency : vector.getDependencies()) {
// 0 = identifier
// 1 = version equal
// 2 = version smaller
// 3 = version bigger
int mode = 0;
boolean[] duplicateCheck = new boolean[3];
StringBuilder identifier = new StringBuilder();
StringBuilder versionEqual = new StringBuilder();
StringBuilder versionSmaller = new StringBuilder();
StringBuilder versionBigger = new StringBuilder();
// Get variables
for (char character : dependency.toCharArray()) {
switch (character) {
case '=' -> {
mode = 1;
continue;
}
case '<' -> {
mode = 2;
continue;
}
case '>' -> {
mode = 3;
continue;
}
}
switch (mode) {
// Identifier
case 0 -> identifier.append(character);
// Version equal
case 1 -> {
// Check for duplicate
if (character == '=' && duplicateCheck[0])
throw new IllegalStateException("The dependency listing \"" + dependency + "\" cannot include multiple '=' characters");
duplicateCheck[0] = true;
// Check for smaller and bigger than
if (duplicateCheck[1] || duplicateCheck[2])
throw new IllegalStateException("The dependency listing \"" + dependency + "\" cannot require a specific version and have minimum and maximum version specifiers");
versionEqual.append(character);
}
// Version smaller
case 2 -> {
// Check for duplicate
if (character == '<' && duplicateCheck[1])
throw new IllegalStateException("The dependency listing \"" + dependency + "\" cannot include multiple '<' characters");
duplicateCheck[1] = true;
// Check for equal
if (duplicateCheck[0])
throw new IllegalStateException("The dependency listing \"" + dependency + "\" cannot require a specific version and have minimum and maximum version specifiers");
versionSmaller.append(character);
}
// Version bigger
case 3 -> {
// Check for duplicate
if (character == '>' && duplicateCheck[2])
throw new IllegalStateException("The dependency listing \"" + dependency + "\" cannot include multiple '>' characters");
duplicateCheck[2] = true;
// Check for equal
if (duplicateCheck[0])
throw new IllegalStateException("The dependency listing \"" + dependency + "\" cannot require a specific version and have minimum and maximum version specifiers");
versionBigger.append(character);
}
}
}
// Resolve vector
DependencyVector dependencyResolved = getMatchingVector(identifier.toString());
if (dependencyResolved == null) {
unmetDependencies.add("Dependency \"" + dependency + "\" is not met: Not found");
continue;
}
VersioningSystem versioningSystemResolved;
// Get resolved versioning system
try {
versioningSystemResolved = dependencyResolved.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(dependencyResolved.getVersion());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + dependencyResolved.getVersioningSystem().getName(), exception);
break;
}
// Compare
if (!versionEqual.isEmpty()) { // Version equals
VersioningSystem versioningSystemEquals;
// Get expected VersioningSystem
try {
versioningSystemEquals = dependencyResolved.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionEqual.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + dependencyResolved.getVersioningSystem().getName(), exception);
break;
}
// Compare versions
if (versioningSystemResolved.compare(versioningSystemEquals) != 1)
unmetDependencies.add("Dependency \"" + dependency + "\" is not met: Expected version " + versionEqual + " does not match found version " + vector.getVersion());
} else {
VersioningSystem versioningSystemSmaller = null;
VersioningSystem versioningSystemBigger = null;
if (!versionSmaller.isEmpty())
// Get expected VersioningSystem
try {
versioningSystemSmaller = dependencyResolved.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionSmaller.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + dependencyResolved.getVersioningSystem().getName(), exception);
break;
}
if (!versionBigger.isEmpty())
// Get expected VersioningSystem
try {
versioningSystemBigger = dependencyResolved.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(versionBigger.toString());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + dependencyResolved.getVersioningSystem().getName(), exception);
break;
}
// Compare versions
if (versioningSystemSmaller != null && versioningSystemBigger != null) {
if (versioningSystemResolved.compare(versioningSystemSmaller) != 0 && versioningSystemResolved.compare(versioningSystemBigger) != 2)
unmetDependencies.add("Dependency \"" + dependency + "\" is not met: Version " + vector.getVersion() + " is not in range " + versionSmaller + " to " + versionBigger);
} else {
if (versioningSystemSmaller != null)
if (versioningSystemResolved.compare(versioningSystemSmaller) != 0)
unmetDependencies.add("Dependency \"" + dependency + "\" is not met: Version " + vector.getVersion() + " is bigger than " + versionSmaller);
if (versioningSystemBigger != null)
if (versioningSystemResolved.compare(versioningSystemBigger) != 2)
unmetDependencies.add("Dependency \"" + dependency + "\" is not met: Version " + vector.getVersion() + " is smaller than " + versionBigger);
}
}
/*
if (dependency.contains("=")) {
// Check for '<' and '>'
if (dependency.contains("<") || dependency.contains(">"))
throw new IllegalStateException("The dependency listing \"" + dependency + "\" can't require a specific version and have minimum and maximum version specifiers");
// Check for multiple '='
if (dependency.split("\\\\=").length != 1)
throw new IllegalStateException("The dependency listing \"" + dependency + "\" can't include multiple equals characters");
// Get identifier and required version
int index = dependency.indexOf("=");
String identifier = dependency.substring(0, index);
String version = dependency.substring(index + 1);
DependencyVector dependencyResolved = getMatchingVector(identifier);
if (dependencyResolved == null)
unmetDependencies.add("Dependency \"" + dependency + "\" is not met: Not found");
else {
VersioningSystem versioningSystemResolved;
VersioningSystem versioningSystemEquals;
// Create VersioningSystem instances for comparing versions
try {
versioningSystemResolved = dependencyResolved.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(dependencyResolved.getVersion());
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException exception) {
logger.crash("Unable to check version of dependency \"" + dependency + "\": Unable to initialize versioning system " + dependencyResolved.getVersioningSystem().getName(), exception);
break;
}
try {
versioningSystemEquals = dependencyResolved.getVersioningSystem().getDeclaredConstructor(String.class).newInstance(version);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException exception) {
logger.crash("Unable to initialize versioning system " + vector.getVersioningSystem().getName() + " of vector " + vector.getIdentifier(), exception);
break;
}
// Compare versions
if (versioningSystemResolved.compare(versioningSystemEquals) != 1)
unmetDependencies.add("Dependency \"" + dependency + "\" is not met: Expected version " + version + " does not match found version " + vector.getVersion());
}
} else {
throw new IllegalStateException("The dependency listing \"" + dependency + "\" does not contain a version identifier");
}
*/
}
return unmetDependencies;
}
/**
* Searches all registered {@link DependencyVector}s for the specified identifier
* and returns the first matching one.
*
* @return matching vector or {@code null} if not found
* @since v1-alpha4
*/
private @Nullable DependencyVector getMatchingVector(@NotNull String identifier) {
for (DependencyVector vector : vectors) {
if (vector.getIdentifier().equals(identifier)) {
return vector;
} else {
// Search 'provides' for matches
for (String provider : vector.getProvides())
if (provider.substring(0, provider.indexOf("=")).equals(identifier))
return vector;
}
}
return null;
}
/**
* Returns the correct order which stuff needs to be loaded/done in.
*