Skip to content
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

Improve tracking of unattached dependencies #13350

Merged
merged 1 commit into from Jun 9, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -640,6 +640,84 @@ class JavaPlatformResolveIntegrationTest extends AbstractHttpDependencyResolutio
platform << ["project(':platform')", "'org:other-platform:1.0'", "'org:bom-platform:1.0'"]
}

def 'platform deselection / reselection does not cause orphan edges'() {
given:
def depExcluded = mavenHttpRepo.module('org.test', 'excluded', '1.0').publish()
def depA = mavenHttpRepo.module('org.test', 'depA', '1.0').publish()
def platform = mavenHttpRepo.module('org.test', 'platform', '1.0').withModuleMetadata().withoutDefaultVariants()
.withVariant('apiElements') {
useDefaultArtifacts = false
attribute(Usage.USAGE_ATTRIBUTE.name, Usage.JAVA_API)
attribute(Category.CATEGORY_ATTRIBUTE.name, Category.REGULAR_PLATFORM)
constraint('org.test', 'depA', '1.0')
constraint('org.test', 'excluded', '1.0')
}
.withVariant('runtimeElements') {
useDefaultArtifacts = false
attribute(Usage.USAGE_ATTRIBUTE.name, Usage.JAVA_RUNTIME)
attribute(Category.CATEGORY_ATTRIBUTE.name, Category.REGULAR_PLATFORM)
constraint('org.test', 'depA', '1.0')
constraint('org.test', 'excluded', '1.0')
}.publish()
def depC = mavenHttpRepo.module('org.test', 'depC', '1.0').withModuleMetadata()
.withVariant('runtime') {
dependsOn('org.test', 'platform', '1.0', null, [(Category.CATEGORY_ATTRIBUTE.name): Category.REGULAR_PLATFORM])
}.publish()
def depB = mavenHttpRepo.module('org.test', 'depB', '1.0').dependsOn([exclusions: [[module: 'excluded']]], depC).publish()
def depF = mavenHttpRepo.module('org.test', 'depF', '1.0').dependsOn(depC).publish()
def depE = mavenHttpRepo.module('org.test', 'depE', '1.0').dependsOn(depF).publish()
def depD = mavenHttpRepo.module('org.test', 'depD', '1.0').dependsOn(depE).publish()

depExcluded.allowAll()
depA.allowAll()
depB.allowAll()
depC.allowAll()
depD.allowAll()
depE.allowAll()
depF.allowAll()
platform.allowAll()

buildFile << """
configurations {
conf.dependencies.clear()
}

dependencies {
conf 'org.test:depA'
conf 'org.test:depB:1.0'
conf 'org.test:depD:1.0'
}
"""
checkConfiguration("conf")
resolve.expectDefaultConfiguration("runtime")

when:
succeeds 'checkDeps'

then:
resolve.expectGraph {
root(":", "org.test:test:1.9") {
edge("org.test:depA", "org.test:depA:1.0")
module("org.test:depB:1.0") {
module("org.test:depC:1.0") {
module('org.test:platform:1.0') {
noArtifacts()
constraint('org.test:depA:1.0')
}
}
}
module('org.test:depD:1.0') {
module('org.test:depE:1.0') {
module('org.test:depF:1.0') {
module('org.test:depC:1.0')
}
}
}
}
}
}


private void checkConfiguration(String configuration) {
resolve = new ResolveTestFixture(buildFile, configuration)
resolve.expectDefaultConfiguration("compile")
Expand Down
Expand Up @@ -66,6 +66,7 @@ class EdgeState implements DependencyGraphEdge {
private ExcludeSpec cachedExclusions;

private ResolvedVariantResult resolvedVariant;
private boolean unattached;

EdgeState(NodeState from, DependencyState dependencyState, ExcludeSpec transitiveExclusions, ResolveState resolveState) {
this.from = from;
Expand Down Expand Up @@ -181,9 +182,13 @@ void failWith(Throwable err) {
targetNodeSelectionFailure = new ModuleVersionResolveException(dependencyState.getRequested(), err);
}

public void restart() {
public void restart(boolean checkUnattached) {
if (from.isSelected()) {
removeFromTargetConfigurations();
// We now have corner cases that can lead to this restart not succeeding
if (checkUnattached && !isUnattached()) {
selector.getTargetModule().addUnattachedDependency(this);
}
attachToTargetConfigurations();
}
}
Expand Down Expand Up @@ -430,4 +435,16 @@ public void updateTransitiveExcludes(ExcludeSpec newResolutionFilter) {
targetNode.updateTransitiveExcludes();
}
}

public void markUnattached() {
this.unattached = true;
}

public void markAttached() {
this.unattached = false;
}

public boolean isUnattached() {
return unattached;
}
}
Expand Up @@ -262,20 +262,23 @@ private void doRestart(ComponentState selected) {
private void restartUnattachedDependencies() {
if (unattachedDependencies.size() == 1) {
EdgeState singleDependency = unattachedDependencies.get(0);
singleDependency.restart();
singleDependency.restart(false);
} else {
for (EdgeState dependency : new ArrayList<>(unattachedDependencies)) {
dependency.restart();
dependency.restart(false);
}
}
}

public void addUnattachedDependency(EdgeState edge) {
unattachedDependencies.add(edge);
edge.markUnattached();
}

public void removeUnattachedDependency(EdgeState edge) {
unattachedDependencies.remove(edge);
if (unattachedDependencies.remove(edge)) {
edge.markAttached();
}
}

public ComponentState getVersion(ModuleVersionIdentifier id, ComponentIdentifier componentIdentifier) {
Expand Down
Expand Up @@ -615,7 +615,7 @@ public boolean isSelected() {

public void evict() {
evicted = true;
restartIncomingEdges();
restartIncomingEdges(false);
}

boolean shouldIncludedInGraphResult() {
Expand Down Expand Up @@ -976,18 +976,18 @@ public void restart(ComponentState selected) {
}
} else {
if (!incomingEdges.isEmpty()) {
restartIncomingEdges();
restartIncomingEdges(true);
}
}
}

private void restartIncomingEdges() {
private void restartIncomingEdges(boolean checkUnattached) {
if (incomingEdges.size() == 1) {
EdgeState singleEdge = incomingEdges.get(0);
singleEdge.restart();
singleEdge.restart(checkUnattached);
} else {
for (EdgeState dependency : new ArrayList<>(incomingEdges)) {
dependency.restart();
dependency.restart(checkUnattached);
}
}
clearIncomingEdges();
Expand Down