Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
/*
* Copyright 2019 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.gestalt.module.dependencyresolution;

import org.terasology.gestalt.naming.Name;
import org.terasology.gestalt.naming.SemverExpression;
import org.terasology.gestalt.naming.Version;
import org.terasology.gestalt.naming.VersionRange;

import java.util.Objects;
import java.util.function.Predicate;

/**
* Describes a dependency on a module. Dependencies apply to a range of versions - anything from the min version (inclusive) to the max version (exclusive) are supported.
Expand Down Expand Up @@ -126,6 +115,21 @@ public VersionRange versionRange() {
return new VersionRange(getMinVersion(), getMaxVersion());
}

public Predicate<Version> versionPredicate() {
if (maxVersion != null) {
return versionRange();
} else {
String source;
if (minVersion.isSnapshot()) {
// semver doesn't like snapshots in caret ranges?
source = minVersion + " | ^" + minVersion.getNextPatchVersion();
} else {
source = "^" + minVersion;
}
return new SemverExpression(source);
}
}

@Override
public String toString() {
return String.format("DependencyInfo [id=%s, minVersion=%s, maxVersion=%s, optional=%s]",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
/*
* Copyright 2019 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.gestalt.module.dependencyresolution;

Expand All @@ -25,6 +12,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;

/**
* Dependency Resolver determines a working set of modules for a given set of desired modules. Where multiple versions are compatible, they are resolved in favour of the
Expand Down Expand Up @@ -86,7 +74,7 @@ public ResolutionBuilder builder() {
* Prepares and performs the process of resolving dependencies.
*/
public class ResolutionBuilder {
private final Map<Name, Optional<VersionRange>> validVersions = new HashMap<>();
private final Map<Name, Optional<Predicate<Version>>> validVersions = new HashMap<>();

/**
* Adds a module to the set of requirements.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
/*
* Copyright 2019 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.gestalt.module.dependencyresolution;

Expand All @@ -30,7 +17,6 @@
import org.terasology.gestalt.module.ModuleRegistry;
import org.terasology.gestalt.naming.Name;
import org.terasology.gestalt.naming.Version;
import org.terasology.gestalt.naming.VersionRange;
import org.terasology.gestalt.util.collection.UniqueQueue;

import java.util.Arrays;
Expand All @@ -42,6 +28,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

class ResolutionAttempt {
Expand All @@ -58,7 +45,7 @@ class ResolutionAttempt {
this.optionalStrategy = optionalStrategy;
}

ResolutionResult resolve(Map<Name, Optional<VersionRange>> validVersions) {
ResolutionResult resolve(Map<Name, Optional<Predicate<Version>>> validVersions) {
rootModules = ImmutableSet.copyOf(validVersions.keySet());
populateDomains(validVersions);
populateConstraints();
Expand All @@ -80,7 +67,7 @@ ResolutionResult resolve(Map<Name, Optional<VersionRange>> validVersions) {
/**
* Populates the domains (modules of interest) for resolution. Includes all versions of all modules depended on by any version of a module of interest, recursively.
*/
private void populateDomains(Map<Name, Optional<VersionRange>> validVersions) {
private void populateDomains(Map<Name, Optional<Predicate<Version>>> validVersions) {
moduleVersionPool = HashMultimap.create();
Set<Name> involvedModules = Sets.newHashSet();
Deque<Name> moduleQueue = Queues.newArrayDeque();
Expand All @@ -92,8 +79,8 @@ private void populateDomains(Map<Name, Optional<VersionRange>> validVersions) {
while (!moduleQueue.isEmpty()) {
Name id = moduleQueue.pop();
for (Module version : registry.getModuleVersions(id)) {
Optional<VersionRange> range = validVersions.getOrDefault(version.getId(), Optional.empty());
if (!range.isPresent() || range.get().contains(version.getVersion())) {
Optional<Predicate<Version>> range = validVersions.getOrDefault(version.getId(), Optional.empty());
if (!range.isPresent() || range.get().test(version.getVersion())) {
moduleVersionPool.put(id, new PossibleVersion(version.getVersion()));
for (DependencyInfo dependency : version.getMetadata().getDependencies()) {
if (involvedModules.add(dependency.getId())) {
Expand Down Expand Up @@ -125,7 +112,7 @@ private void populateConstraints() {
Module versionedModule = registry.getModule(name, version.getVersion().get());
DependencyInfo info = versionedModule.getMetadata().getDependencyInfo(dependency);
if (info != null) {
constraintTable.put(version.getVersion().get(), new CompatibleVersions(info.versionRange(), info.isOptional() && !optionalStrategy.isRequired()));
constraintTable.put(version.getVersion().get(), new CompatibleVersions(info.versionPredicate(), info.isOptional() && !optionalStrategy.isRequired()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd love to have a uniform code formatter...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what prompted that thought on this line in particular?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, probably the length of that line 🤔

}
}
}
Expand Down Expand Up @@ -376,17 +363,17 @@ public String toString() {
}

private static class CompatibleVersions {
private final VersionRange versionRange;
private final Predicate<Version> versionRange;
private final boolean missingAllowed;

public CompatibleVersions(VersionRange versionRange, boolean missingAllowed) {
public CompatibleVersions(Predicate<Version> versionRange, boolean missingAllowed) {
this.versionRange = versionRange;
this.missingAllowed = missingAllowed;
}

public boolean isCompatible(PossibleVersion version) {
if (version.getVersion().isPresent()) {
return versionRange.contains(version.getVersion().get());
return versionRange.test(version.getVersion().get());
} else {
return missingAllowed;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.gestalt.naming;

import com.github.zafarkhaja.semver.expr.ExpressionParser;
import com.google.common.base.MoreObjects;

import java.util.function.Predicate;

public class SemverExpression implements Predicate<Version> {

private final Predicate<com.github.zafarkhaja.semver.Version> expression;
private final String source;

public SemverExpression(String source) {
this.source = source;
this.expression = ExpressionParser.newInstance().parse(source);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: error handling
or maybe using a documented exception here, and error handling in DependencyInfo?

}

@Override
public boolean test(Version version) {
return expression.test(version.semver);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.addValue(source)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
/*
* Copyright 2019 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0
package org.terasology.gestalt.naming;

import com.github.zafarkhaja.semver.ParseException;
Expand All @@ -32,7 +19,7 @@ public final class Version implements Comparable<Version> {

private static final String SNAPSHOT = "SNAPSHOT";

private com.github.zafarkhaja.semver.Version semver;
com.github.zafarkhaja.semver.Version semver;

/**
* Constructs a version with the given values
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,19 @@
/*
* Copyright 2019 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2021 The Terasology Foundation
// SPDX-License-Identifier: Apache-2.0

package org.terasology.gestalt.naming;

import com.google.common.base.Preconditions;

import java.util.Objects;
import java.util.function.Predicate;

/**
* A range of versions from a lower-bound (inclusive) to an upper-bound (exclusive).
*
* @author Immortius
*/
public class VersionRange {
public class VersionRange implements Predicate<Version> {
private final Version lowerBound;
private final Version upperBound;

Expand Down Expand Up @@ -59,6 +47,11 @@ public boolean contains(Version version) {
return version.compareTo(lowerBound.getSnapshot()) >= 0 && version.compareTo(upperBound.getSnapshot()) < 0;
}

@Override
public boolean test(Version version) {
return contains(version);
}

@Override
public boolean equals(Object obj) {
if (obj == this) {
Expand Down