Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[JENKINS-27395] Start recording enclosing blocks for flow nodes
Specifically for AtomNodes, BlockStartNodes, and BlockEndNodes.
  • Loading branch information
abayer committed Aug 25, 2017
1 parent 63e8ad0 commit 3e8a1b7
Show file tree
Hide file tree
Showing 5 changed files with 340 additions and 0 deletions.
Expand Up @@ -36,5 +36,6 @@
public abstract class AtomNode extends FlowNode {
protected AtomNode(FlowExecution exec, String id, FlowNode... parents) {
super(exec, id, parents);
this.enclosingId = findEnclosingId();
}
}
Expand Up @@ -44,12 +44,14 @@ public BlockEndNode(FlowExecution exec, String id, START start, FlowNode... pare
super(exec, id, parents);
this.start = start;
startId = start.getId();
this.enclosingId = findEnclosingId();
}

public BlockEndNode(FlowExecution exec, String id, START start, List<FlowNode> parents) {
super(exec, id, parents);
this.start = start;
startId = start.getId();
this.enclosingId = findEnclosingId();
}

/**
Expand Down
Expand Up @@ -39,10 +39,12 @@
public abstract class BlockStartNode extends FlowNode {
protected BlockStartNode(FlowExecution exec, String id, FlowNode... parents) {
super(exec, id, parents);
this.enclosingId = findEnclosingId();
}

protected BlockStartNode(FlowExecution exec, String id, List<FlowNode> parents) {
super(exec, id, parents);
this.enclosingId = findEnclosingId();
}

}
85 changes: 85 additions & 0 deletions src/main/java/org/jenkinsci/plugins/workflow/graph/FlowNode.java
Expand Up @@ -38,6 +38,7 @@
import java.io.ObjectStreamException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
Expand All @@ -47,6 +48,7 @@
import java.util.logging.Logger;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;

import org.jenkinsci.plugins.workflow.actions.ErrorAction;
import org.jenkinsci.plugins.workflow.actions.LabelAction;
import org.jenkinsci.plugins.workflow.actions.PersistentAction;
Expand All @@ -69,6 +71,9 @@
public abstract class FlowNode extends Actionable implements Saveable {
private transient List<FlowNode> parents;
private final List<String> parentIds;
private transient List<FlowNode> enclosingBlocks;
private final List<String> allEnclosingIds = new ArrayList<>();
protected String enclosingId;

private String id;

Expand All @@ -82,13 +87,17 @@ protected FlowNode(FlowExecution exec, String id, List<FlowNode> parents) {
this.exec = exec;
this.parents = ImmutableList.copyOf(parents);
parentIds = ids();
// Note that enclosingId is set in the constructors of AtomNode, BlockEndNode, and BlockStartNode, since we need
// BlockEndNode in particular to have its start node beforehand.
}

protected FlowNode(FlowExecution exec, String id, FlowNode... parents) {
this.id = id;
this.exec = exec;
this.parents = ImmutableList.copyOf(parents);
parentIds = ids();
// Note that enclosingId is set in the constructors of AtomNode, BlockEndNode, and BlockStartNode, since we need
// BlockEndNode in particular to have its start node beforehand.
}

private List<String> ids() {
Expand All @@ -104,6 +113,9 @@ protected Object readResolve() throws ObjectStreamException {
if (this.id != null) {
this.id = this.id.intern();
}
if (this.enclosingId != null) {
this.enclosingId = this.enclosingId.intern();
}
if (parentIds != null) {
for (int i=0; i<parentIds.size(); i++) {
parentIds.set(i, parentIds.get(i).intern());
Expand All @@ -112,6 +124,38 @@ protected Object readResolve() throws ObjectStreamException {
return this;
}

/**
* Finds the first enclosing block this node is within, excluding itself.
*/
@CheckForNull
protected String findEnclosingId() {
if (this instanceof FlowStartNode || this instanceof FlowEndNode || parents.isEmpty()) {
return null;
}
if (this instanceof BlockEndNode) {
BlockStartNode startNode = ((BlockEndNode)this).getStartNode();
if (startNode instanceof FlowStartNode) {
return null;
} else {
allEnclosingIds.addAll(startNode.getAllEnclosingIds());
return startNode.getEnclosingId();
}
} else {
FlowNode parent = parents.get(0);
if (parent instanceof FlowStartNode) {
return null;
}
if (parent instanceof BlockStartNode) {
allEnclosingIds.add(parent.getId());
allEnclosingIds.addAll(parent.getAllEnclosingIds());
return parent.getId();
} else {
allEnclosingIds.addAll(parent.getAllEnclosingIds());
return parent.getEnclosingId();
}
}
}

/**
* Transient flag that indicates if this node is currently actively executing something.
* <p>It will be false for a node which still has active children, like a step with a running body.
Expand Down Expand Up @@ -278,6 +322,47 @@ private List<FlowNode> loadParents(List<String> parentIds) {
return _parents;
}

/**
* Get the first enclosing block ID for this node. Can be null.
* @return
*/
@CheckForNull
public String getEnclosingId() {
return enclosingId;
}

/**
* Get the list of enclosing blocks, starting from innermost, for this node. May be empty. Loads the flow nodes into
* the transient {@code enclosingBlocks} field if needed.
*/
@Nonnull
public List<FlowNode> getEnclosingBlocks() {
if (enclosingBlocks == null) {
enclosingBlocks = new ArrayList<>();
if (!allEnclosingIds.isEmpty()) {
try {
for (String enclId : allEnclosingIds) {
FlowNode enclosingNode = exec.getNode(enclId);
if (enclosingNode != null) {
enclosingBlocks.add(enclosingNode);
}
}
} catch (IOException e) {
LOGGER.log(Level.WARNING, "failed to load enclosing blocks of " + id, e);
}
}
}
return enclosingBlocks;
}

/**
* Returns a read-only view of the IDs for enclosing blocks of this flow node, innermost first. May be empty.
*/
@Nonnull
public List<String> getAllEnclosingIds() {
return Collections.unmodifiableList(allEnclosingIds);
}

@Restricted(DoNotUse.class)
@Exported(name="parents")
@Nonnull
Expand Down

0 comments on commit 3e8a1b7

Please sign in to comment.