提交 29f6a5dd 编写于 作者: K Kohsuke Kawaguchi

[FIXED JENKINS-3070]

Added uninstaller that removes *.jpi.
上级 85eacfe3
......@@ -55,7 +55,9 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=>
<li class=rfe>
Plugin manager now supports uninstallation.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-3070">issue 3070</a>)
</ul>
</div><!--=TRUNK-END=-->
......
......@@ -26,6 +26,7 @@ package hudson;
import hudson.PluginManager.PluginInstanceStore;
import hudson.model.Api;
import hudson.model.ModelObject;
import jenkins.YesNoMaybe;
import jenkins.model.Jenkins;
import hudson.model.UpdateCenter;
......@@ -49,6 +50,7 @@ import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import org.kohsuke.stapler.interceptor.RequirePOST;
import java.util.Enumeration;
import java.util.jar.JarFile;
......@@ -76,7 +78,7 @@ import java.util.jar.JarFile;
* @author Kohsuke Kawaguchi
*/
@ExportedBean
public class PluginWrapper implements Comparable<PluginWrapper> {
public class PluginWrapper implements Comparable<PluginWrapper>, ModelObject {
/**
* {@link PluginManager} to which this belongs to.
*/
......@@ -116,6 +118,11 @@ public class PluginWrapper implements Comparable<PluginWrapper> {
*/
private final File pinFile;
/**
* A .jpi file, an exploded plugin directory, or a .jpl file.
*/
private final File archive;
/**
* Short name of the plugin. The artifact Id of the plugin.
* This is also used in the URL within Jenkins, so it needs
......@@ -200,6 +207,11 @@ public class PluginWrapper implements Comparable<PluginWrapper> {
this.active = !disableFile.exists();
this.dependencies = dependencies;
this.optionalDependencies = optionalDependencies;
this.archive = archive;
}
public String getDisplayName() {
return getLongName();
}
public Api getApi() {
......@@ -513,6 +525,16 @@ public class PluginWrapper implements Comparable<PluginWrapper> {
return pinFile.exists();
}
/**
* Returns true if this plugin is deleted.
*
* The plugin continues to function in this session, but in the next session it'll disappear.
*/
@Exported
public boolean isDeleted() {
return !archive.exists();
}
/**
* Sort by short name.
*/
......@@ -559,30 +581,41 @@ public class PluginWrapper implements Comparable<PluginWrapper> {
// Action methods
//
//
@RequirePOST
public HttpResponse doMakeEnabled() throws IOException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
enable();
return HttpResponses.ok();
}
@RequirePOST
public HttpResponse doMakeDisabled() throws IOException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
disable();
return HttpResponses.ok();
}
@RequirePOST
public HttpResponse doPin() throws IOException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
new FileOutputStream(pinFile).close();
return HttpResponses.ok();
}
@RequirePOST
public HttpResponse doUnpin() throws IOException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
pinFile.delete();
return HttpResponses.ok();
}
@RequirePOST
public HttpResponse doDoUninstall() throws IOException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
archive.delete();
return HttpResponses.redirectViaContextPath("/pluginManager/installed"); // send back to plugin manager
}
private static final Logger LOGGER = Logger.getLogger(PluginWrapper.class.getName());
......
......@@ -42,9 +42,10 @@ THE SOFTWARE.
<tr style="border-top: 0px;">
<th width="32" tooltip="${%Uncheck to disable the plugin}">${%Enabled}</th>
<th initialSortDir="down">${%Name}</th>
<th width="32">${%Version}</th>
<th width="32">${%Previously installed version}</th>
<th width="32">${%Pinned}</th>
<th width="1">${%Version}</th>
<th width="1">${%Previously installed version}</th>
<th width="1">${%Pinned}</th>
<th width="1">${%Uninstall}</th>
</tr>
<j:forEach var="p" items="${app.pluginManager.plugins}">
<tr>
......@@ -85,6 +86,18 @@ THE SOFTWARE.
<a href="${%wiki.url}"><img style="vertical-align:top" src="${imagesURL}/16x16/help.png"/></a>
</j:if>
</td>
<td class="center pane">
<j:choose>
<j:when test="${p.isDeleted()}">
<p>${%Uninstalltion pending}</p>
</j:when>
<j:when test="${!p.isBundled()}">
<form method="post" action="plugin/${p.shortName}/uninstall">
<input type="submit" value="${%Uninstall}"/>
</form>
</j:when>
</j:choose>
</td>
</tr>
</j:forEach>
<!-- failed ones -->
......@@ -121,6 +134,7 @@ THE SOFTWARE.
<!-- trigger -->
new Ajax.Request(btn.getAttribute('url')+"/make"+(btn.checked?"Enable":"Disable")+"d", {
method: "POST",
onFailure : function(req,o) {
$('needRestart').innerHTML = req.responseText;
}
......@@ -145,6 +159,7 @@ THE SOFTWARE.
function unpin(button,shortName) {
new Ajax.Request("./plugin/"+shortName+"/unpin", {
method: "POST",
onFailure : function(t) {
alert('Failed to unpin:'+t.responseText);
},
......
package hudson.PluginWrapper
def l = namespace(lib.LayoutTagLib)
def f = namespace(lib.FormTagLib)
l.layout {
def title = "Uninstalling ${my.shortName} plugin"
l.header(title:title)
l.main_panel {
h1 {
img(src:"${imagesURL}/48x48/error.png",alt:"[!]",height:48,width:48)
text(" ")
text(title)
}
p { raw _("msg",my.shortName) }
f.form(method:"post",action:"doUninstall") {
f.submit(value:_("Yes"))
}
}
}
\ No newline at end of file
msg=You are about to uninstall the <b>{0}</b> plugin. This will remove the plugin binary from your $JENKINS_HOME, \
but it'll the configuration files of the plugin.
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册