diff --git a/src/main/scala/plugin/JavaScriptPlugin.scala b/src/main/scala/plugin/JavaScriptPlugin.scala index 8c6b690..7984c32 100644 --- a/src/main/scala/plugin/JavaScriptPlugin.scala +++ b/src/main/scala/plugin/JavaScriptPlugin.scala @@ -71,7 +71,7 @@ val context = JsContext.enter() try { val scope = context.initStandardObjects() - scope.put("PluginSystem", scope, this) + scope.put("PluginSystem", scope, PluginSystem) scope.put("JavaScriptPlugin", scope, this) val result = context.evaluateString(scope, script, "", 1, null) result diff --git a/src/main/scala/plugin/PluginSystem.scala b/src/main/scala/plugin/PluginSystem.scala index daae34c..1956ec6 100644 --- a/src/main/scala/plugin/PluginSystem.scala +++ b/src/main/scala/plugin/PluginSystem.scala @@ -3,6 +3,9 @@ import app.Context import javax.servlet.http.{HttpServletResponse, HttpServletRequest} import org.slf4j.LoggerFactory +import java.util.concurrent.atomic.AtomicBoolean +import util.Directory._ +import org.apache.commons.io.FileUtils /** * Provides extension points to plug-ins. @@ -11,6 +14,7 @@ private val logger = LoggerFactory.getLogger(PluginSystem.getClass) + private val initialized = new AtomicBoolean(false) private val pluginsMap = scala.collection.mutable.Map[String, Plugin]() def install(plugin: Plugin): Unit = { @@ -23,6 +27,28 @@ pluginsMap.remove(id) } + /** + * Initializes the plugin system. Load scripts from GITBUCKET_HOME/plugins. + */ + def init(): Unit = { + if(initialized.compareAndSet(false, true)){ + val pluginDir = new java.io.File(PluginHome) + if(pluginDir.exists && pluginDir.isDirectory){ + pluginDir.listFiles.filter(f => f.isDirectory && !f.getName.startsWith(".")).foreach { dir => + val file = new java.io.File(dir, "plugin.js") + if(file.exists && file.isFile){ + val script = FileUtils.readFileToString(file, "UTF-8") + try { + JavaScriptPlugin.evaluateJavaScript(script) + } catch { + case e: Exception => logger.warn(s"Error in plugin loading for ${file.getAbsolutePath}", e) + } + } + } + } + } + } + def repositoryMenus : List[RepositoryMenu] = pluginsMap.values.flatMap(_.repositoryMenus).toList def globalMenus : List[GlobalMenu] = pluginsMap.values.flatMap(_.globalMenus).toList def repositoryActions : List[Action] = pluginsMap.values.flatMap(_.repositoryActions).toList diff --git a/src/main/scala/plugin/ScalaPlugin.scala b/src/main/scala/plugin/ScalaPlugin.scala new file mode 100644 index 0000000..b1388e1 --- /dev/null +++ b/src/main/scala/plugin/ScalaPlugin.scala @@ -0,0 +1,37 @@ +package plugin + +import app.Context +import scala.collection.mutable.ListBuffer +import plugin.PluginSystem.{Action, GlobalMenu, RepositoryMenu} +import javax.servlet.http.{HttpServletResponse, HttpServletRequest} + +// TODO This is a sample implementation for Scala based plug-ins. +class ScalaPlugin(val id: String, val author: String, val url: String, val description: String) extends Plugin { + + private val repositoryMenuList = ListBuffer[RepositoryMenu]() + private val globalMenuList = ListBuffer[GlobalMenu]() + private val repositoryActionList = ListBuffer[Action]() + private val globalActionList = ListBuffer[Action]() + + def repositoryMenus : List[RepositoryMenu] = repositoryMenuList.toList + def globalMenus : List[GlobalMenu] = globalMenuList.toList + def repositoryActions : List[Action] = repositoryActionList.toList + def globalActions : List[Action] = globalActionList.toList + + def addRepositoryMenu(label: String, name: String, url: String, icon: String)(condition: (Context) => Boolean): Unit = { + repositoryMenuList += RepositoryMenu(label, name, url, icon, condition) + } + + def addGlobalMenu(label: String, url: String, icon: String)(condition: (Context) => Boolean): Unit = { + globalMenuList += GlobalMenu(label, url, icon, condition) + } + + def addGlobalAction(path: String)(function: (HttpServletRequest, HttpServletResponse) => Any): Unit = { + globalActionList += Action(path, function) + } + + def addRepositoryAction(path: String)(function: (HttpServletRequest, HttpServletResponse) => Any): Unit = { + repositoryActionList += Action(path, function) + } + +} diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala index 801ff68..0b39b13 100644 --- a/src/main/scala/servlet/AutoUpdateListener.scala +++ b/src/main/scala/servlet/AutoUpdateListener.scala @@ -178,6 +178,10 @@ } } logger.debug("End schema update") + + logger.debug("Starting plugin system...") + plugin.PluginSystem.init() + logger.debug("Plugin system is initialized.") } def contextDestroyed(sce: ServletContextEvent): Unit = { diff --git a/src/main/scala/util/Directory.scala b/src/main/scala/util/Directory.scala index 1d15f1a..dac409f 100644 --- a/src/main/scala/util/Directory.scala +++ b/src/main/scala/util/Directory.scala @@ -34,6 +34,8 @@ val DatabaseHome = s"${GitBucketHome}/data" + val PluginHome = s"${GitBucketHome}/plugins" + /** * Substance directory of the repository. */