Enhance --plugin_dir option behavior

It became an option to specify an extra plugin jars directory, not to overwrite PLUGIN_HOME.
This commit is contained in:
Naoki Takezoe
2017-07-18 13:04:32 +09:00
parent 84891abc04
commit 944cbf04ed
2 changed files with 55 additions and 43 deletions

View File

@@ -24,7 +24,6 @@ import play.twirl.api.Html
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import com.github.zafarkhaja.semver.{Version => Semver}
class PluginRegistry {
@@ -190,6 +189,7 @@ object PluginRegistry {
private var instance = new PluginRegistry()
private var watcher: PluginWatchThread = null
private var extraWatcher: PluginWatchThread = null
/**
* Returns the PluginRegistry singleton instance.
@@ -242,6 +242,8 @@ object PluginRegistry {
}).toSeq.sortBy(_.getName).reverse
}
lazy val extraPluginDir: Option[String] = Option(System.getProperty("gitbucket.pluginDir"))
/**
* Initializes all installed plugins.
*/
@@ -256,57 +258,65 @@ object PluginRegistry {
}
installedDir.mkdir()
if(pluginDir.exists && pluginDir.isDirectory) {
pluginDir.listFiles(new FilenameFilter {
override def accept(dir: File, name: String): Boolean = name.endsWith(".jar")
}).toSeq.sortBy(_.getName).reverse.foreach { pluginJar =>
val pluginJars = listPluginJars(pluginDir)
val extraJars = extraPluginDir.map { extraDir => listPluginJars(new File(extraDir)) }.getOrElse(Nil)
val installedJar = new File(installedDir, pluginJar.getName)
FileUtils.copyFile(pluginJar, installedJar)
(extraJars ++ pluginJars).foreach { pluginJar =>
val installedJar = new File(installedDir, pluginJar.getName)
FileUtils.copyFile(pluginJar, installedJar)
logger.info(s"Initialize ${pluginJar.getName}")
val classLoader = new URLClassLoader(Array(installedJar.toURI.toURL), Thread.currentThread.getContextClassLoader)
try {
val plugin = classLoader.loadClass("Plugin").getDeclaredConstructor().newInstance().asInstanceOf[Plugin]
val pluginId = plugin.pluginId
// Check duplication
instance.getPlugins().find(_.pluginId == pluginId).foreach { x =>
throw new IllegalStateException(s"Plugin ${pluginId} is duplicated. ${x.pluginJar.getName} is available.")
logger.info(s"Initialize ${pluginJar.getName}")
val classLoader = new URLClassLoader(Array(installedJar.toURI.toURL), Thread.currentThread.getContextClassLoader)
try {
val plugin = classLoader.loadClass("Plugin").getDeclaredConstructor().newInstance().asInstanceOf[Plugin]
val pluginId = plugin.pluginId
// Check duplication
instance.getPlugins().find(_.pluginId == pluginId) match {
case Some(x) => {
logger.warn(s"Plugin ${pluginId} is duplicated. ${x.pluginJar.getName} is available.")
}
case None => {
// Migration
val solidbase = new Solidbase()
solidbase.migrate(conn, classLoader, DatabaseConfig.liquiDriver, new Module(plugin.pluginId, plugin.versions: _*))
// Migration
val solidbase = new Solidbase()
solidbase.migrate(conn, classLoader, DatabaseConfig.liquiDriver, new Module(plugin.pluginId, plugin.versions: _*))
// Check database version
val databaseVersion = manager.getCurrentVersion(plugin.pluginId)
val pluginVersion = plugin.versions.last.getVersion
if (databaseVersion != pluginVersion) {
throw new IllegalStateException(s"Plugin version is ${pluginVersion}, but database version is ${databaseVersion}")
}
// Check database version
val databaseVersion = manager.getCurrentVersion(plugin.pluginId)
val pluginVersion = plugin.versions.last.getVersion
if (databaseVersion != pluginVersion) {
throw new IllegalStateException(s"Plugin version is ${pluginVersion}, but database version is ${databaseVersion}")
// Initialize
plugin.initialize(instance, context, settings)
instance.addPlugin(PluginInfo(
pluginId = plugin.pluginId,
pluginName = plugin.pluginName,
pluginVersion = plugin.versions.last.getVersion,
description = plugin.description,
pluginClass = plugin,
pluginJar = pluginJar,
classLoader = classLoader
))
}
// Initialize
plugin.initialize(instance, context, settings)
instance.addPlugin(PluginInfo(
pluginId = plugin.pluginId,
pluginName = plugin.pluginName,
pluginVersion = plugin.versions.last.getVersion,
description = plugin.description,
pluginClass = plugin,
pluginJar = pluginJar,
classLoader = classLoader
))
} catch {
case e: Throwable => logger.error(s"Error during plugin initialization: ${pluginJar.getName}", e)
}
} catch {
case e: Throwable => logger.error(s"Error during plugin initialization: ${pluginJar.getName}", e)
}
}
if(watcher == null){
watcher = new PluginWatchThread(context)
watcher = new PluginWatchThread(context, PluginHome)
watcher.start()
}
extraPluginDir.foreach { extraDir =>
if(extraWatcher == null){
extraWatcher = new PluginWatchThread(context, extraDir)
extraWatcher.start()
}
}
}
def shutdown(context: ServletContext, settings: SystemSettings): Unit = synchronized {
@@ -349,14 +359,14 @@ case class PluginInfo(
classLoader: URLClassLoader
) extends PluginInfoBase(pluginId, pluginName, pluginVersion, description)
class PluginWatchThread(context: ServletContext) extends Thread with SystemSettingsService {
class PluginWatchThread(context: ServletContext, dir: String) extends Thread with SystemSettingsService {
import gitbucket.core.model.Profile.profile.blockingApi._
import scala.collection.JavaConverters._
private val logger = LoggerFactory.getLogger(classOf[PluginWatchThread])
override def run(): Unit = {
val path = Paths.get(PluginHome)
val path = Paths.get(dir)
if(!Files.exists(path)){
Files.createDirectories(path)
}
@@ -374,7 +384,9 @@ class PluginWatchThread(context: ServletContext) extends Thread with SystemSetti
try {
while (watchKey.isValid()) {
val detectedWatchKey = watcher.take()
val events = detectedWatchKey.pollEvents.asScala.filter(_.context.toString != ".installed")
val events = detectedWatchKey.pollEvents.asScala.filter { e =>
e.context.toString != ".installed" && !e.context.toString.endsWith(".bak")
}
if(events.nonEmpty){
events.foreach { event =>
logger.info(event.kind + ": " + event.context)

View File

@@ -32,7 +32,7 @@ object Directory {
val DatabaseHome = s"${GitBucketHome}/data"
val PluginHome = Option(System.getProperty("gitbucket.pluginDir")).getOrElse(s"${GitBucketHome}/plugins")
val PluginHome = s"${GitBucketHome}/plugins"
val TemporaryHome = s"${GitBucketHome}/tmp"