Skip to content

Commit

Permalink
RunListener.allowLoad + AbstractLazyLoadRunMap.recognizeNumber (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jglick committed Mar 24, 2024
1 parent 4ce021a commit 5cec09d
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 12 deletions.
46 changes: 43 additions & 3 deletions core/src/main/java/hudson/model/RunMap.java
Expand Up @@ -28,7 +28,10 @@
import static jenkins.model.lazy.AbstractLazyLoadRunMap.Direction.ASC;
import static jenkins.model.lazy.AbstractLazyLoadRunMap.Direction.DESC;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Util;
import hudson.model.listeners.RunListener;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
Expand All @@ -38,6 +41,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.SortedMap;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -64,6 +68,8 @@ public final class RunMap<R extends Run<?, R>> extends AbstractLazyLoadRunMap<R>
*/
private final SortedMap<Integer, R> view = Collections.unmodifiableSortedMap(this);

private final @CheckForNull Job<?, ?> job;

private Constructor<R> cons;

/** Normally overwritten by {@link LazyBuildMixIn#onLoad} or {@link LazyBuildMixIn#onCreatedFromScratch}, in turn created during {@link Job#onLoad}. */
Expand All @@ -76,20 +82,38 @@ public final class RunMap<R extends Run<?, R>> extends AbstractLazyLoadRunMap<R>

/**
* @deprecated as of 1.485
* Use {@link #RunMap(File, Constructor)}.
* Use {@link #RunMap(Job, Constructor)}.
*/
@Deprecated
public RunMap() {
super(null); // will be set later
job = null;
initBaseDir(null); // will be set later
}

@Restricted(NoExternalUse.class)
public RunMap(@NonNull Job<?, ?> job) {
this.job = Objects.requireNonNull(job);
}

/**
* @param cons
* Used to create new instance of {@link Run}.
* @since TODO
*/
public RunMap(@NonNull Job<?, ?> job, Constructor cons) {
this.job = Objects.requireNonNull(job);
this.cons = cons;
initBaseDir(job.getBuildDir());
}

/**
* @deprecated Use {@link #RunMap(Job, Constructor)}.
*/
@Deprecated
public RunMap(File baseDir, Constructor cons) {
super(baseDir);
job = null;
this.cons = cons;
initBaseDir(baseDir);
}

public boolean remove(R run) {
Expand Down Expand Up @@ -224,6 +248,22 @@ protected BuildReference<R> createReference(R r) {
return r.createReference();
}

@Override
protected boolean allowLoad(int buildNumber) {
if (job == null) {
LOGGER.fine(() -> "deprecated constructor without Job used on " + dir);
return true;
}
for (RunListener<?> l : RunListener.all()) {
if (!l.allowLoad(job, buildNumber)) {
LOGGER.finer(() -> l + " declined to load " + buildNumber + " in " + job);
return false;
}
}
LOGGER.finest(() -> "no RunListener declined to load " + buildNumber + " in " + job + " so proceeding");
return true;
}

@Override
protected R retrieve(File d) throws IOException {
if (new File(d, "build.xml").exists()) {
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/hudson/model/ViewJob.java
Expand Up @@ -26,6 +26,7 @@

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.model.Descriptor.FormException;
import java.io.File;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
Expand Down Expand Up @@ -62,7 +63,7 @@ public abstract class ViewJob<JobT extends ViewJob<JobT, RunT>, RunT extends Run
/**
* All {@link Run}s. Copy-on-write semantics.
*/
protected transient volatile /*almost final*/ RunMap<RunT> runs = new RunMap<>(null, null);
protected transient volatile /*almost final*/ RunMap<RunT> runs = new RunMap<>((File) null, null);

private transient volatile boolean notLoaded = true;

Expand Down
16 changes: 16 additions & 0 deletions core/src/main/java/hudson/model/listeners/RunListener.java
Expand Up @@ -35,6 +35,7 @@
import hudson.model.AbstractBuild;
import hudson.model.BuildListener;
import hudson.model.Environment;
import hudson.model.Job;
import hudson.model.JobProperty;
import hudson.model.Run;
import hudson.model.Run.RunnerAbortedException;
Expand All @@ -46,8 +47,11 @@
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import jenkins.model.lazy.AbstractLazyLoadRunMap;
import jenkins.util.Listeners;
import org.jvnet.tiger_types.Types;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.Beta;

/**
* Receives notifications about builds.
Expand Down Expand Up @@ -171,6 +175,18 @@ public Environment setUpEnvironment(AbstractBuild build, Launcher launcher, Buil
*/
public void onDeleted(R r) {}

/**
* Allows listeners to veto build loading.
* @param job the job from which a build might be loaded
* @param buildNumber the proposed build number
* @return false to veto build loading
* @see AbstractLazyLoadRunMap#recognizeNumber
*/
@Restricted(Beta.class)
public boolean allowLoad(@NonNull Job<?, ?> job, int buildNumber) {
return true;
}

/**
* Registers this object as an active listener so that it can start getting
* callbacks invoked.
Expand Down
48 changes: 44 additions & 4 deletions core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java
Expand Up @@ -31,6 +31,7 @@
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.RunMap;
import hudson.model.listeners.RunListener;
import java.io.File;
import java.io.IOException;
import java.util.AbstractCollection;
Expand All @@ -54,6 +55,7 @@
import java.util.regex.Pattern;
import jenkins.util.MemoryReductionUtil;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.Beta;
import org.kohsuke.accmod.restrictions.NoExternalUse;

/**
Expand Down Expand Up @@ -290,8 +292,7 @@ private Index(Index rhs) {
protected File dir;

@Restricted(NoExternalUse.class) // subclassing other than by RunMap does not guarantee compatibility
protected AbstractLazyLoadRunMap(File dir) {
initBaseDir(dir);
protected AbstractLazyLoadRunMap() {
}

@Restricted(NoExternalUse.class)
Expand Down Expand Up @@ -348,7 +349,12 @@ private void loadNumberOnDisk() {
continue;
}
try {
list.add(Integer.parseInt(s));
int buildNumber = Integer.parseInt(s);
if (allowLoad(buildNumber)) {
list.add(buildNumber);
} else {
LOGGER.fine(() -> "declining to consider " + buildNumber + " in " + dir);
}
} catch (NumberFormatException e) {
// matched BUILD_NUMBER but not an int?
}
Expand All @@ -357,6 +363,35 @@ private void loadNumberOnDisk() {
numberOnDisk = list;
}

@Restricted(NoExternalUse.class)
protected boolean allowLoad(int buildNumber) {
return true;
}

/**
* Permits a previous blocked build number to be eligible for loading.
* @param buildNumber a build number
* @see RunListener#allowLoad
*/
@Restricted(Beta.class)
public final void recognizeNumber(int buildNumber) {
if (new File(dir, Integer.toString(buildNumber)).isDirectory()) {
synchronized (this) {
SortedIntList list = new SortedIntList(numberOnDisk);
if (list.contains(buildNumber)) {
LOGGER.fine(() -> "already knew about " + buildNumber + " in " + dir);
} else {
list.add(buildNumber);
list.sort();
numberOnDisk = list;
LOGGER.fine(() -> "recognizing " + buildNumber + " in " + dir);
}
}
} else {
LOGGER.fine(() -> "no such subdirectory " + buildNumber + " in " + dir);
}
}

@Override
public Comparator<? super Integer> comparator() {
return Collections.reverseOrder();
Expand Down Expand Up @@ -540,7 +575,12 @@ public R getByNumber(int n) {
return v;
}
}
return load(n, null);
if (allowLoad(n)) {
return load(n, null);
} else {
LOGGER.fine(() -> "declining to load " + n + " in " + dir);
return null;
}
}
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java
Expand Up @@ -66,8 +66,8 @@ public abstract class LazyBuildMixIn<JobT extends Job<JobT, RunT> & Queue.Task &

private static final Logger LOGGER = Logger.getLogger(LazyBuildMixIn.class.getName());

@SuppressWarnings("deprecation") // [JENKINS-15156] builds accessed before onLoad or onCreatedFromScratch called
private @NonNull RunMap<RunT> builds = new RunMap<>();
// [JENKINS-15156] builds accessed before onLoad or onCreatedFromScratch called
private @NonNull RunMap<RunT> builds = new RunMap<>(asJob());

/**
* Initializes this mixin.
Expand Down Expand Up @@ -142,7 +142,7 @@ public void onLoad(ItemGroup<? extends Item> parent, String name) throws IOExcep
}

private RunMap<RunT> createBuildRunMap() {
RunMap<RunT> r = new RunMap<>(asJob().getBuildDir(), new RunMap.Constructor<RunT>() {
RunMap<RunT> r = new RunMap<>(asJob(), new RunMap.Constructor<RunT>() {
@Override
public RunT create(File dir) throws IOException {
return loadBuild(dir);
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/java/jenkins/model/lazy/FakeMap.java
Expand Up @@ -34,7 +34,7 @@
*/
public class FakeMap extends AbstractLazyLoadRunMap<Build> {
public FakeMap(File dir) {
super(dir);
initBaseDir(dir);
}

@Override
Expand Down

0 comments on commit 5cec09d

Please sign in to comment.