Skip to content

Commit

Permalink
Merge commit '817f1149781eeb3ceea7839ab3213d2d2fdc9b3d' of git://gith…
Browse files Browse the repository at this point in the history
…ub.com/jenkinsci/jenkins
  • Loading branch information
daniel-beck committed Aug 13, 2018
2 parents 6d85033 + 817f114 commit c508620
Show file tree
Hide file tree
Showing 21 changed files with 515 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .mvn/extensions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<extension>
<groupId>io.jenkins.tools.incrementals</groupId>
<artifactId>git-changelist-maven-extension</artifactId>
<version>1.0-beta-3</version>
<version>1.0-beta-4</version>
</extension>
</extensions>
2 changes: 1 addition & 1 deletion core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ THE SOFTWARE.
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.2.1</version>
<version>4.5.2</version>
</dependency>
<dependency>
<groupId>org.kohsuke</groupId>
Expand Down
25 changes: 19 additions & 6 deletions core/src/main/java/hudson/Launcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ public final class ProcStarter {
@CheckForNull
protected OutputStream stdout = NULL_OUTPUT_STREAM, stderr;
@CheckForNull
private TaskListener stdoutListener;
@CheckForNull
protected InputStream stdin = NULL_INPUT_STREAM;
@CheckForNull
protected String[] envs = null;
Expand Down Expand Up @@ -285,17 +287,20 @@ public FilePath pwd() {
*/
public ProcStarter stdout(@CheckForNull OutputStream out) {
this.stdout = out;
stdoutListener = null;
return this;
}

/**
* Sends the stdout to the given {@link TaskListener}.
*
* @param out Task listener
* @param out Task listener (must be safely remotable)
* @return {@code this}
*/
public ProcStarter stdout(@Nonnull TaskListener out) {
return stdout(out.getLogger());
stdout = out.getLogger();
stdoutListener = out;
return this;
}

/**
Expand Down Expand Up @@ -490,6 +495,7 @@ public int join() throws IOException, InterruptedException {
@Nonnull
public ProcStarter copy() {
ProcStarter rhs = new ProcStarter().cmds(commands).pwd(pwd).masks(masks).stdin(stdin).stdout(stdout).stderr(stderr).envs(envs).quiet(quiet);
rhs.stdoutListener = stdoutListener;
rhs.reverseStdin = this.reverseStdin;
rhs.reverseStderr = this.reverseStderr;
rhs.reverseStdout = this.reverseStdout;
Expand Down Expand Up @@ -1041,15 +1047,15 @@ public VirtualChannel getChannel() {
}

public Proc launch(ProcStarter ps) throws IOException {
final OutputStream out = ps.stdout == null ? null : new RemoteOutputStream(new CloseProofOutputStream(ps.stdout));
final OutputStream out = ps.stdout == null || ps.stdoutListener != null ? null : new RemoteOutputStream(new CloseProofOutputStream(ps.stdout));
final OutputStream err = ps.stderr==null ? null : new RemoteOutputStream(new CloseProofOutputStream(ps.stderr));
final InputStream in = (ps.stdin==null || ps.stdin==NULL_INPUT_STREAM) ? null : new RemoteInputStream(ps.stdin,false);

final FilePath psPwd = ps.pwd;
final String workDir = psPwd==null ? null : psPwd.getRemote();

try {
return new ProcImpl(getChannel().call(new RemoteLaunchCallable(ps.commands, ps.masks, ps.envs, in, ps.reverseStdin, out, ps.reverseStdout, err, ps.reverseStderr, ps.quiet, workDir, listener)));
return new ProcImpl(getChannel().call(new RemoteLaunchCallable(ps.commands, ps.masks, ps.envs, in, ps.reverseStdin, out, ps.reverseStdout, err, ps.reverseStderr, ps.quiet, workDir, listener, ps.stdoutListener)));
} catch (InterruptedException e) {
throw (IOException)new InterruptedIOException().initCause(e);
}
Expand Down Expand Up @@ -1265,14 +1271,15 @@ private static class RemoteLaunchCallable extends MasterToSlaveCallable<RemotePr
private final @CheckForNull OutputStream err;
private final @CheckForNull String workDir;
private final @Nonnull TaskListener listener;
private final @CheckForNull TaskListener stdoutListener;
private final boolean reverseStdin, reverseStdout, reverseStderr;
private final boolean quiet;

RemoteLaunchCallable(@Nonnull List<String> cmd, @CheckForNull boolean[] masks, @CheckForNull String[] env,
@CheckForNull InputStream in, boolean reverseStdin,
@CheckForNull OutputStream out, boolean reverseStdout,
@CheckForNull OutputStream err, boolean reverseStderr,
boolean quiet, @CheckForNull String workDir, @Nonnull TaskListener listener) {
boolean quiet, @CheckForNull String workDir, @Nonnull TaskListener listener, @CheckForNull TaskListener stdoutListener) {
this.cmd = new ArrayList<>(cmd);
this.masks = masks;
this.env = env;
Expand All @@ -1281,6 +1288,7 @@ private static class RemoteLaunchCallable extends MasterToSlaveCallable<RemotePr
this.err = err;
this.workDir = workDir;
this.listener = listener;
this.stdoutListener = stdoutListener;
this.reverseStdin = reverseStdin;
this.reverseStdout = reverseStdout;
this.reverseStderr = reverseStderr;
Expand All @@ -1290,7 +1298,12 @@ private static class RemoteLaunchCallable extends MasterToSlaveCallable<RemotePr
public RemoteProcess call() throws IOException {
final Channel channel = getOpenChannelOrFail();
Launcher.ProcStarter ps = new LocalLauncher(listener).launch();
ps.cmds(cmd).masks(masks).envs(env).stdin(in).stdout(out).stderr(err).quiet(quiet);
ps.cmds(cmd).masks(masks).envs(env).stdin(in).stderr(err).quiet(quiet);
if (stdoutListener != null) {
ps.stdout(stdoutListener.getLogger());
} else {
ps.stdout(out);
}
if(workDir!=null) ps.pwd(workDir);
if (reverseStdin) ps.writeStdin();
if (reverseStdout) ps.readStdout();
Expand Down
31 changes: 24 additions & 7 deletions core/src/main/java/hudson/PluginWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
import hudson.model.UpdateCenter;
import hudson.model.UpdateSite;
import hudson.util.VersionNumber;
import org.jvnet.localizer.ResourceBundleHolder;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.accmod.restrictions.NoExternalUse;
Expand All @@ -54,7 +53,6 @@
import javax.annotation.Nonnull;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
Expand All @@ -64,7 +62,6 @@
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -600,7 +597,7 @@ public boolean hasLicensesXml() {
} else {
VersionNumber actualVersion = Jenkins.getVersion();
if (actualVersion.isOlderThan(new VersionNumber(requiredCoreVersion))) {
dependencyErrors.put(Messages.PluginWrapper_obsoleteCore(Jenkins.getVersion().toString(), requiredCoreVersion), false);
versionDependencyError(Messages.PluginWrapper_obsoleteCore(Jenkins.getVersion().toString(), requiredCoreVersion), Jenkins.getVersion().toString(), requiredCoreVersion);
}
}
}
Expand All @@ -618,11 +615,11 @@ public boolean hasLicensesXml() {
} else {
if (dependency.isActive()) {
if (isDependencyObsolete(d, dependency)) {
dependencyErrors.put(Messages.PluginWrapper_obsolete(dependency.getLongName(), dependency.getVersion(), d.version), false);
versionDependencyError(Messages.PluginWrapper_obsolete(dependency.getLongName(), dependency.getVersion(), d.version), dependency.getVersion(), d.version);
}
} else {
if (isDependencyObsolete(d, dependency)) {
dependencyErrors.put(Messages.PluginWrapper_disabledAndObsolete(dependency.getLongName(), dependency.getVersion(), d.version), false);
versionDependencyError(Messages.PluginWrapper_disabledAndObsolete(dependency.getLongName(), dependency.getVersion(), d.version), dependency.getVersion(), d.version);
} else {
dependencyErrors.put(Messages.PluginWrapper_disabled(dependency.getLongName()), false);
}
Expand All @@ -635,7 +632,7 @@ public boolean hasLicensesXml() {
PluginWrapper dependency = parent.getPlugin(d.shortName);
if (dependency != null && dependency.isActive()) {
if (isDependencyObsolete(d, dependency)) {
dependencyErrors.put(Messages.PluginWrapper_obsolete(dependency.getLongName(), dependency.getVersion(), d.version), false);
versionDependencyError(Messages.PluginWrapper_obsolete(dependency.getLongName(), dependency.getVersion(), d.version), dependency.getVersion(), d.version);
} else {
dependencies.add(d);
}
Expand All @@ -660,6 +657,26 @@ private boolean isDependencyObsolete(Dependency d, PluginWrapper dependency) {
return ENABLE_PLUGIN_DEPENDENCIES_VERSION_CHECK && dependency.getVersionNumber().isOlderThan(new VersionNumber(d.version));
}

/**
* Called when there appears to be a core or plugin version which is too old for a stated dependency.
* Normally records an error in {@link #dependencyErrors}.
* But if one or both versions {@link #isSnapshot}, just issue a warning (JENKINS-52665).
*/
private void versionDependencyError(String message, String actual, String minimum) {
if (isSnapshot(actual) || isSnapshot(minimum)) {
LOGGER.log(WARNING, "Suppressing dependency error in {0} v{1}: {2}", new Object[] {getLongName(), getVersion(), message});
} else {
dependencyErrors.put(message, false);
}
}

/**
* Similar to {@code org.apache.maven.artifact.ArtifactUtils.isSnapshot}.
*/
static boolean isSnapshot(@Nonnull String version) {
return version.contains("-SNAPSHOT") || version.matches(".+-[0-9]{8}.[0-9]{6}-[0-9]+");
}

/**
* If the plugin has {@link #getUpdateInfo() an update},
* returns the {@link hudson.model.UpdateSite.Plugin} object.
Expand Down
100 changes: 100 additions & 0 deletions core/src/main/java/hudson/cli/EnablePluginCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* The MIT License
*
* Copyright (c) 2018 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package hudson.cli;

import hudson.Extension;
import hudson.PluginManager;
import hudson.PluginWrapper;
import jenkins.model.Jenkins;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;

import java.io.IOException;
import java.util.List;

/**
* Enables one or more installed plugins. The listed plugins must already be installed along with its dependencies.
* Any listed plugin with disabled dependencies will have its dependencies enabled transitively. Note that enabling an
* already enabled plugin does nothing.
*
* @since TODO
*/
@Extension
public class EnablePluginCommand extends CLICommand {

@Argument(required = true, usage = "Enables the plugins with the given short names and their dependencies.")
private List<String> pluginNames;

@Option(name = "-restart", usage = "Restart Jenkins after enabling plugins.")
private boolean restart;

@Override
public String getShortDescription() {
return Messages.EnablePluginCommand_ShortDescription();
}

@Override
protected int run() throws Exception {
Jenkins jenkins = Jenkins.get();
jenkins.checkPermission(Jenkins.ADMINISTER);
PluginManager manager = jenkins.getPluginManager();
for (String pluginName : pluginNames) {
enablePlugin(manager, pluginName);
}
if (restart) {
jenkins.safeRestart();
}
return 0;
}

private void enablePlugin(PluginManager manager, String shortName) throws IOException {
PluginWrapper plugin = manager.getPlugin(shortName);
if (plugin == null) {
throw new IllegalArgumentException(Messages.EnablePluginCommand_NoSuchPlugin(shortName));
}
if (plugin.isEnabled()) {
return;
}
stdout.println(String.format("Enabling plugin `%s' (%s)", plugin.getShortName(), plugin.getVersion()));
enableDependencies(manager, plugin);
plugin.enable();
stdout.println(String.format("Plugin `%s' was enabled.", plugin.getShortName()));
}

private void enableDependencies(PluginManager manager, PluginWrapper plugin) throws IOException {
for (PluginWrapper.Dependency dep : plugin.getDependencies()) {
PluginWrapper dependency = manager.getPlugin(dep.shortName);
if (dependency == null) {
throw new IllegalArgumentException(Messages.EnablePluginCommand_MissingDependencies(plugin.getShortName(), dep));
}
if (!dependency.isEnabled()) {
enableDependencies(manager, dependency);
stdout.println(String.format("Enabling plugin dependency `%s' (%s) for `%s'", dependency.getShortName(), dependency.getVersion(), plugin.getShortName()));
dependency.enable();
}
}
}

}
2 changes: 1 addition & 1 deletion core/src/main/java/hudson/model/Queue.java
Original file line number Diff line number Diff line change
Expand Up @@ -1470,7 +1470,7 @@ public void maintain() {
{// update parked (and identify any pending items whose executor has disappeared)
List<BuildableItem> lostPendings = new ArrayList<BuildableItem>(pendings);
for (Computer c : jenkins.getComputers()) {
for (Executor e : c.getExecutors()) {
for (Executor e : c.getAllExecutors()) {
if (e.isInterrupted()) {
// JENKINS-28840 we will deadlock if we try to touch this executor while interrupt flag set
// we need to clear lost pendings as we cannot know what work unit was on this executor
Expand Down
5 changes: 4 additions & 1 deletion core/src/main/java/hudson/model/TaskListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import hudson.console.ConsoleNote;
import hudson.console.HyperlinkNote;
import hudson.remoting.Channel;
import hudson.util.NullStream;
import hudson.util.StreamTaskListener;

Expand Down Expand Up @@ -59,7 +60,9 @@
*
* <p>
* {@link StreamTaskListener} is the most typical implementation of this interface.
* All the {@link TaskListener} implementations passed to plugins from Hudson core are remotable.
*
* <p>
* Implementations are generally expected to be remotable via {@link Channel}.
*
* @author Kohsuke Kawaguchi
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
* {@link NodeProperty} that sets additional environment variables.
Expand All @@ -65,6 +68,14 @@ public EnvVars getEnvVars() {
return envVars;
}

/**
* @return environment variables using same data type as constructor parameter.
* @since TODO
*/
public List<Entry> getEnv() {
return envVars.entrySet().stream().map(Entry::new).collect(Collectors.toList());
}

@Override
public Environment setUp(AbstractBuild build, Launcher launcher,
BuildListener listener) throws IOException, InterruptedException {
Expand Down Expand Up @@ -100,6 +111,10 @@ public String getHelpPage() {
public static class Entry {
public String key, value;

private Entry(Map.Entry<String,String> e) {
this(e.getKey(), e.getValue());
}

@DataBoundConstructor
public Entry(String key, String value) {
this.key = key;
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/hudson/tools/ToolInstaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@

/**
* An object which can ensure that a generic {@link ToolInstallation} in fact exists on a node.
* The properties can be added to {@link ToolInstallation} using the {@link InstallSourceProperty}.
*
* The subclass should have a {@link ToolInstallerDescriptor}.
* A {@code config.jelly} should be provided to customize specific fields;
* {@code <t:label xmlns:t="/hudson/tools"/>} to customize {@code label}.
* @see <a href="http://wiki.jenkins-ci.org/display/JENKINS/Tool+Auto-Installation">Tool Auto-Installation</a>
* @since 1.305
* @see InstallSourceProperty
*/
public abstract class ToolInstaller implements Describable<ToolInstaller>, ExtensionPoint {

Expand Down
Loading

0 comments on commit c508620

Please sign in to comment.