Skip to content
Permalink
Browse files
JENKINS-14483 Remaining Xvfb processes in matrix jobs
implemented as kindly suggested by Chris Jonhson on jenkins-dev mailing
list

https://groups.google.com/d/topic/jenkinsci-dev/KQVDCV9ATm8/discussion
  • Loading branch information
Zoran Regvart committed Sep 18, 2012
1 parent 6de9693 commit b25ee74766b91b268f740640590f985191323a21
Showing 2 changed files with 108 additions and 64 deletions.
@@ -36,8 +36,8 @@
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Computer;
import hudson.model.Executor;
import hudson.model.Node;
import hudson.model.Run.RunnerAbortedException;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.tools.ToolInstallation;
@@ -53,8 +53,6 @@

public class XvfbBuildWrapper extends BuildWrapper {

private static final int MILLIS_IN_SECOND = 1000;

@Extension
public static class XvfbBuildWrapperDescriptor extends BuildWrapperDescriptor {

@@ -95,8 +93,10 @@ public void setInstallations(final XvfbInstallation... installations) {
}
}

private static final int MILLIS_IN_SECOND = 1000;

/** default screen configuration for Xvfb, used by default, and if user left screen configuration blank */
private static final String DEFAULT_SCREEN = "1024x768x24";
private static final String DEFAULT_SCREEN = "1024x768x24";

/** Name of the installation used in a configured job. */
private final String installationName;
@@ -105,23 +105,14 @@ public void setInstallations(final XvfbInstallation... installations) {
private final Integer displayName;

/** Xvfb screen argument, in the form WxHxD (width x height x pixel depth), i.e. 800x600x8. */
private String screen = DEFAULT_SCREEN;
private String screen = DEFAULT_SCREEN;

/** Should the Xvfb output be displayed in job output. */
private boolean debug = false;
private boolean debug = false;

/** Time in milliseconds to wait for Xvfb initialization, by default 0 -- do not wait. */
private final long timeout;

/** Temporary directory to hold Xvfb session data, will not be persisted. */
private transient FilePath frameBufferDir;

/** Actual display name used, will not be persisted. */
private transient int displayNameUsed;

/** Handle to the Xvfb process. */
private transient Proc process;

/** Additional options to be passed to Xvfb */
private final String additionalOptions;

@@ -142,14 +133,57 @@ public XvfbBuildWrapper(final String installationName, final Integer displayName
this.additionalOptions = additionalOptions;
}

public String getAdditionalOptions() {
return additionalOptions;
}

@Override
public Launcher decorateLauncher(@SuppressWarnings("rawtypes") final AbstractBuild build, final Launcher launcher, final BuildListener listener) throws IOException, InterruptedException, RunnerAbortedException {
if (!launcher.isUnix()) {
listener.getLogger().println(Messages.XvfbBuildWrapper_NotUnix());
public XvfbBuildWrapperDescriptor getDescriptor() {
return (XvfbBuildWrapperDescriptor) super.getDescriptor();
}

public Integer getDisplayName() {
return displayName;
}

public XvfbInstallation getInstallation(final EnvVars env, final Node node, final BuildListener listener) {
for (final XvfbInstallation installation : getDescriptor().getInstallations()) {
if (installationName != null && installationName.equals(installation.getName())) {
try {
return installation.forEnvironment(env).forNode(node, TaskListener.NULL);
} catch (final IOException e) {
listener.fatalError("IOException while locating installation", e);
} catch (final InterruptedException e) {
listener.fatalError("InterruptedException while locating installation", e);
}
}
}

return null;
}

public String getInstallationName() {
return installationName;
}

public String getScreen() {
return screen;
}

public long getTimeout() {
return timeout;
}

public boolean isDebug() {
return debug;
}

private XvfbEnvironment launchXvfb(@SuppressWarnings("rawtypes") final AbstractBuild build, final Launcher launcher, final BuildListener listener) throws IOException, InterruptedException {
int displayNameUsed;

if (displayName == null) {
displayNameUsed = (int) (Math.random() * 100);
final Executor executor = build.getExecutor();
displayNameUsed = executor.getNumber();
}
else {
displayNameUsed = displayName;
@@ -159,15 +193,15 @@ public Launcher decorateLauncher(@SuppressWarnings("rawtypes") final AbstractBui
final Node currentNode = currentComputer.getNode();
final FilePath rootPath = currentNode.getRootPath();

frameBufferDir = rootPath.createTempDir(build.getId(), "xvfb");
final FilePath frameBufferDir = rootPath.createTempDir(build.getId(), "xvfb");

final EnvVars environment = currentComputer.getEnvironment();
final XvfbInstallation installation = getInstallation(environment, currentNode, listener);

if (installation == null) {
listener.error(Messages.XvfbBuildWrapper_NoInstallationsConfigured());

return launcher;
return null;
}

final String path = installation.getHome();
@@ -196,65 +230,41 @@ public Launcher decorateLauncher(@SuppressWarnings("rawtypes") final AbstractBui
procStarter.stdout(TaskListener.NULL);
}

process = procStarter.start();
final Proc process = procStarter.start();

Thread.sleep(timeout * MILLIS_IN_SECOND);

return launcher;
}

public String getAdditionalOptions() {
return additionalOptions;
return new XvfbEnvironment(frameBufferDir, displayNameUsed, process);
}

@Override
public XvfbBuildWrapperDescriptor getDescriptor() {
return (XvfbBuildWrapperDescriptor) super.getDescriptor();
}
public void makeBuildVariables(@SuppressWarnings("rawtypes") final AbstractBuild build, final Map<String, String> variables) {
final XvfbEnvironment xvfbEnvironment = build.getAction(XvfbEnvironment.class);

public Integer getDisplayName() {
return displayName;
final int displayNameUsed = xvfbEnvironment.getDisplayNameUsed();

variables.put("DISPLAY", ":" + displayNameUsed);
}

public XvfbInstallation getInstallation(final EnvVars env, final Node node, final BuildListener listener) {
for (final XvfbInstallation installation : getDescriptor().getInstallations()) {
if (installationName != null && installationName.equals(installation.getName())) {
try {
return installation.forEnvironment(env).forNode(node, TaskListener.NULL);
} catch (final IOException e) {
listener.fatalError("IOException while locating installation", e);
} catch (final InterruptedException e) {
listener.fatalError("InterruptedException while locating installation", e);
}
}
}
@Override
public Environment setUp(@SuppressWarnings("rawtypes") final AbstractBuild build, final Launcher launcher, final BuildListener listener) throws IOException, InterruptedException {
if (!launcher.isUnix()) {
listener.getLogger().println(Messages.XvfbBuildWrapper_NotUnix());

return null;
}
// we'll abort
return null;
}

public String getInstallationName() {
return installationName;
}
final XvfbEnvironment xvfbEnvironment = launchXvfb(build, launcher, listener);

public String getScreen() {
return screen;
}
build.addAction(xvfbEnvironment);

public long getTimeout() {
return timeout;
}
final int displayNameUsed = xvfbEnvironment.getDisplayNameUsed();

public boolean isDebug() {
return debug;
}
final FilePath frameBufferDir = xvfbEnvironment.getFrameBufferDir();

@Override
public void makeBuildVariables(@SuppressWarnings("rawtypes") final AbstractBuild build, final Map<String, String> variables) {
variables.put("DISPLAY", ":" + displayNameUsed);
}
final Proc process = xvfbEnvironment.getProcess();

@Override
public Environment setUp(@SuppressWarnings("rawtypes") final AbstractBuild build, final Launcher launcher, final BuildListener listener) throws IOException, InterruptedException {
return new Environment() {
@Override
public void buildEnvVars(final Map<String, String> env) {
@@ -0,0 +1,34 @@
package org.jenkinsci.plugins.xvfb;

import hudson.FilePath;
import hudson.Proc;
import hudson.model.InvisibleAction;

public class XvfbEnvironment extends InvisibleAction {
/** Temporary directory to hold Xvfb session data, will not be persisted. */
private final transient FilePath frameBufferDir;

/** Actual display name used, will not be persisted. */
private final transient int displayNameUsed;

/** Handle to the Xvfb process. */
private final transient Proc process;

public XvfbEnvironment(final FilePath frameBufferDir, final int displayNameUsed, final Proc process) {
this.frameBufferDir = frameBufferDir;
this.displayNameUsed = displayNameUsed;
this.process = process;
}

public int getDisplayNameUsed() {
return displayNameUsed;
}

public FilePath getFrameBufferDir() {
return frameBufferDir;
}

public Proc getProcess() {
return process;
}
}

0 comments on commit b25ee74

Please sign in to comment.