Add uninstall plugin button

This commit is contained in:
Naoki Takezoe
2017-03-11 22:59:55 +09:00
parent 11fccf38a6
commit 8ee017c3fa
3 changed files with 92 additions and 50 deletions

View File

@@ -190,6 +190,15 @@ trait SystemSettingsControllerBase extends AccountManagementControllerBase {
redirect("/admin/plugins")
})
post("/admin/plugins/:pluginId/_uninstall")(adminOnly {
val pluginId = params("pluginId")
PluginRegistry().getPlugins().find(_.pluginId == pluginId).foreach { plugin =>
PluginRegistry.uninstall(pluginId, request.getServletContext, loadSystemSettings(), request2Session(request).conn)
flash += "info" -> s"${pluginId} was uninstalled."
}
redirect("/admin/plugins")
})
get("/admin/users")(adminOnly {
val includeRemoved = params.get("includeRemoved").map(_.toBoolean).getOrElse(false)
val users = getAllUsers(includeRemoved)

View File

@@ -160,7 +160,7 @@ object PluginRegistry {
private var instance = new PluginRegistry()
private var watcher: PluginWatchThread = null
// private var watcher: PluginWatchThread = null
/**
* Returns the PluginRegistry singleton instance.
@@ -176,6 +176,19 @@ object PluginRegistry {
initialize(context, settings, conn)
}
/**
* Uninstall a specified plugin.
*/
def uninstall(pluginId: String, context: ServletContext, settings: SystemSettings, conn: java.sql.Connection): Unit = synchronized {
instance.getPlugins().find(_.pluginId == pluginId).foreach { plugin =>
shutdown(context, settings)
// TODO kick uninstall action here?
plugin.pluginJar.delete()
instance = new PluginRegistry()
initialize(context, settings, conn)
}
}
/**
* Initializes all installed plugins.
*/
@@ -209,7 +222,9 @@ object PluginRegistry {
pluginName = plugin.pluginName,
pluginVersion = plugin.versions.last.getVersion,
description = plugin.description,
pluginClass = plugin
pluginClass = plugin,
pluginJar = pluginJar,
classLoader = classLoader
))
} catch {
@@ -220,10 +235,10 @@ object PluginRegistry {
}
}
if(watcher == null){
watcher = new PluginWatchThread(context)
watcher.start()
}
// if(watcher == null){
// watcher = new PluginWatchThread(context)
// watcher.start()
// }
}
def shutdown(context: ServletContext, settings: SystemSettings): Unit = synchronized {
@@ -234,6 +249,8 @@ object PluginRegistry {
case e: Exception => {
logger.error(s"Error during plugin shutdown", e)
}
} finally {
pluginInfo.classLoader.close()
}
}
}
@@ -247,47 +264,50 @@ case class PluginInfo(
pluginName: String,
pluginVersion: String,
description: String,
pluginClass: Plugin
pluginClass: Plugin,
pluginJar: File,
classLoader: URLClassLoader
)
class PluginWatchThread(context: ServletContext) extends Thread with SystemSettingsService {
import gitbucket.core.model.Profile.profile.blockingApi._
private val logger = LoggerFactory.getLogger(classOf[PluginWatchThread])
override def run(): Unit = {
val path = Paths.get(PluginHome)
val fs = path.getFileSystem
val watcher = fs.newWatchService
val watchKey = path.register(watcher,
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_MODIFY,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.OVERFLOW)
logger.info("Start PluginWatchThread: " + path)
try {
while (watchKey.isValid()) {
val detectedWatchKey = watcher.take()
if(detectedWatchKey != null){
val events = detectedWatchKey.pollEvents()
events.forEach { event =>
logger.info(event.kind + ": " + event.context)
}
gitbucket.core.servlet.Database() withTransaction { session =>
logger.info("Reloading plugins...")
PluginRegistry.reload(context, loadSystemSettings(), session.conn)
}
}
detectedWatchKey.reset()
}
} catch {
case _: InterruptedException => ()
}
logger.info("Shutdown PluginWatchThread")
}
}
//class PluginWatchThread(context: ServletContext) extends Thread with SystemSettingsService {
// import gitbucket.core.model.Profile.profile.blockingApi._
//
// private val logger = LoggerFactory.getLogger(classOf[PluginWatchThread])
//
// override def run(): Unit = {
// val path = Paths.get(PluginHome)
// val fs = path.getFileSystem
// val watcher = fs.newWatchService
//
// val watchKey = path.register(watcher,
// StandardWatchEventKinds.ENTRY_CREATE,
// StandardWatchEventKinds.ENTRY_MODIFY,
// StandardWatchEventKinds.ENTRY_DELETE,
// StandardWatchEventKinds.OVERFLOW)
//
// logger.info("Start PluginWatchThread: " + path)
//
// try {
// while (watchKey.isValid()) {
// val detectedWatchKey = watcher.take()
// val events = detectedWatchKey.pollEvents()
//
// events.forEach { event =>
// logger.info(event.kind + ": " + event.context)
// }
//
// gitbucket.core.servlet.Database() withTransaction { session =>
// logger.info("Reloading plugins...")
// PluginRegistry.reload(context, loadSystemSettings(), session.conn)
// }
//
// detectedWatchKey.reset()
// }
// } catch {
// case _: InterruptedException => watchKey.cancel()
// }
//
// logger.info("Shutdown PluginWatchThread")
// }
//
//}

View File

@@ -2,10 +2,10 @@
@gitbucket.core.html.main("Plugins"){
@gitbucket.core.admin.html.menu("plugins") {
@gitbucket.core.helper.html.information(info)
<h1>Installed plugins</h1>
<form action="@context.path/admin/plugins/_reload" method="POST" class="pull-right">
<input type="submit" value="Reload plugins" class="btn btn-success">
</form>
<h1>Installed plugins</h1>
@if(plugins.size > 0) {
<ul>
@plugins.map { plugin =>
@@ -15,7 +15,12 @@
@plugins.map { plugin =>
<div class="panel panel-default">
<div class="panel-heading strong" id="@plugin.pluginId">@plugin.pluginName</div>
<div class="panel-heading strong" id="@plugin.pluginId">
<form action="@{context.path}/admin/plugins/@{plugin.pluginId}/_uninstall" method="POST" class="pull-right uninstall-form">
<input type="submit" value="Uninstall" class="btn btn-danger btn-sm" style="position: relative; top: -5px; left: 10px;" data-name="@plugin.pluginName">
</form>
@plugin.pluginName
</div>
<div class="panel-body">
<div class="row">
<label class="col-md-2">Id</label>
@@ -41,3 +46,11 @@
}
}
}
<script>
$(function(){
$('.uninstall-form').click(function(e){
var name = $(e.target).data('name');
return confirm('Uninstall ' + name + '. Are you sure?');
});
});
</script>