diff --git a/project/build.scala b/project/build.scala index 78bcb23..e206b02 100644 --- a/project/build.scala +++ b/project/build.scala @@ -41,6 +41,7 @@ "com.typesafe.slick" %% "slick" % "1.0.1", "org.mozilla" % "rhino" % "1.7R4", "com.novell.ldap" % "jldap" % "2009-10-07", + "org.quartz-scheduler" % "quartz" % "2.2.1", "com.h2database" % "h2" % "1.3.173", "ch.qos.logback" % "logback-classic" % "1.0.13" % "runtime", "org.eclipse.jetty" % "jetty-webapp" % "8.1.8.v20121106" % "container;provided", diff --git a/src/main/scala/app/SystemSettingsController.scala b/src/main/scala/app/SystemSettingsController.scala index f0b9050..3efb6c3 100644 --- a/src/main/scala/app/SystemSettingsController.scala +++ b/src/main/scala/app/SystemSettingsController.scala @@ -7,7 +7,6 @@ import util.ControlUtil._ import jp.sf.amateras.scalatra.forms._ import ssh.SshServer -import org.scalatra.Ok import org.apache.commons.io.FileUtils import java.io.FileInputStream import plugin.{Plugin, PluginSystem} @@ -100,8 +99,6 @@ }) get("/admin/plugins/available")(adminOnly { - // TODO Do periodical and asynchronous...? - PluginSystem.updateAllRepositories() val installedPlugins = plugin.PluginSystem.plugins val availablePlugins = getAvailablePlugins(installedPlugins).filter(_.status == "available") admin.plugins.html.available(availablePlugins) diff --git a/src/main/scala/plugin/PluginSystem.scala b/src/main/scala/plugin/PluginSystem.scala index 1f095e5..e40f860 100644 --- a/src/main/scala/plugin/PluginSystem.scala +++ b/src/main/scala/plugin/PluginSystem.scala @@ -88,25 +88,6 @@ case class Action(path: String, function: (HttpServletRequest, HttpServletResponse) => Any) /** - * Clone or pull all plugin repositories - * - * TODO Support plugin repository access through the proxy server - */ - def updateAllRepositories(): Unit = { - repositories.foreach { repository => - val dir = getPluginCacheDir() - val repo = new java.io.File(dir, repository.id) - if(repo.exists){ - // pull if the repository is already cloned - Git.open(repo).pull().call() - } else { - // clone if the repository is not exist - Git.cloneRepository().setURI(repository.url).setDirectory(repo).call() - } - } - } - - /** * Checks whether the plugin is updatable. */ def isUpdatable(oldVersion: String, newVersion: String): Boolean = { @@ -126,8 +107,6 @@ } } - - // TODO This is a test // addGlobalMenu("Google", "http://www.google.co.jp/", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAEvwAABL8BkeKJvAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAIgSURBVEiJtdZNiI1hFAfw36ORhSFFPgYLszOKJAsWRLGzks1gYyFZKFs7C7K2Y2XDRiwmq9kIJWQjJR9Tk48xRtTIRwjH4p473nm99yLNqdNTz/mf//+555x7ektEmEmbNaPs6OkUKKX0YBmWp6/IE8bwIs8xjEfEt0aiiJBl6sEuXMRLfEf8pX/PnIvJ0TPFWxE4+w+Ef/Kzbd5qDx5l8H8tkku7LG17gH7sxWatevdhEUoXsjda5RnDTZzH6jagtMe0lHIa23AJw3iOiSRZlmJ9mfcyfTzFl2AldmI3rkbEkbrAYKrX7S1eVRyWVnxhQ87eiLjQ+o2/mtyve+PuYy3W4+EfsP2/TVGKTHRI+Iz9Fdx8XOmAnZjGWRMYqoF/4ESW4hpOYk1iZ2WsLjDUTeBYBfgeuyux2XiNT5hXud+DD5W8Y90EtifoSfultfjx7MVtrKzcr8No5m7vJtCLx1hQJ8/4IZzClpyoy5ibsYUYQW81Z9o2jYgPeKr15+poEXE9+1XF9WIkOaasaV2P4k4pZUdDbEm+VEQcjIgtEfGxlLIVd/Gs6TX1MhzQquU3HK1t23f4IsuS94fxNXMO/MbXIDBg+tidw5yMbcCmylSdqWEH/kagYLKWeAt9Fcxi3KhhJuXq6SqQBMO15NDalvswmLWux4cbuToIbMS9BpJOfg8bm7imtmmTlVJWaa3hpnU9nufziBjtyDHTny0/AaA7Qnb4AM4aAAAAAElFTkSuQmCC") // { context => context.loginAccount.isDefined } diff --git a/src/main/scala/plugin/PluginUpdateJob.scala b/src/main/scala/plugin/PluginUpdateJob.scala new file mode 100644 index 0000000..f041e64 --- /dev/null +++ b/src/main/scala/plugin/PluginUpdateJob.scala @@ -0,0 +1,66 @@ +package plugin + +import util.Directory._ +import org.eclipse.jgit.api.Git +import org.slf4j.LoggerFactory +import org.quartz.{Scheduler, JobExecutionContext, Job} +import org.quartz.JobBuilder._ +import org.quartz.TriggerBuilder._ +import org.quartz.SimpleScheduleBuilder._ + +class PluginUpdateJob extends Job { + + private val logger = LoggerFactory.getLogger(classOf[PluginUpdateJob]) + private var failedCount = 0 + + /** + * Clone or pull all plugin repositories + * + * TODO Support plugin repository access through the proxy server + */ + override def execute(context: JobExecutionContext): Unit = { + try { + if(failedCount > 3){ + logger.error("Skip plugin information updating because failed count is over limit") + } else { + logger.info("Start plugin information updating") + PluginSystem.repositories.foreach { repository => + logger.info(s"Updating ${repository.id}: ${repository.url}...") + val dir = getPluginCacheDir() + val repo = new java.io.File(dir, repository.id) + if(repo.exists){ + // pull if the repository is already cloned + Git.open(repo).pull().call() + } else { + // clone if the repository is not exist + Git.cloneRepository().setURI(repository.url).setDirectory(repo).call() + } + } + logger.info("End plugin information updating") + } + } catch { + case e: Exception => { + failedCount = failedCount + 1 + logger.error("Failed to update plugin information", e) + } + } + } +} + +object PluginUpdateJob { + + def schedule(scheduler: Scheduler): Unit = { + val job = newJob(classOf[PluginUpdateJob]) + .withIdentity("pluginUpdateJob") + .build() + + val trigger = newTrigger() + .withIdentity("pluginUpdateTrigger") + .startNow() + .withSchedule(simpleSchedule().withIntervalInHours(24).repeatForever()) + .build() + + scheduler.scheduleJob(job, trigger) + } + +} \ No newline at end of file diff --git a/src/main/scala/servlet/AutoUpdateListener.scala b/src/main/scala/servlet/AutoUpdateListener.scala index 1a924e0..e79faa5 100644 --- a/src/main/scala/servlet/AutoUpdateListener.scala +++ b/src/main/scala/servlet/AutoUpdateListener.scala @@ -10,6 +10,7 @@ import util.ControlUtil._ import org.eclipse.jgit.api.Git import util.Directory +import plugin.PluginUpdateJob object AutoUpdate { @@ -143,8 +144,14 @@ * Update database schema automatically in the context initializing. */ class AutoUpdateListener extends ServletContextListener { + import org.quartz.impl.StdSchedulerFactory + import org.quartz.JobBuilder._ + import org.quartz.TriggerBuilder._ + import org.quartz.SimpleScheduleBuilder._ import AutoUpdate._ + private val logger = LoggerFactory.getLogger(classOf[AutoUpdateListener]) + private val scheduler = StdSchedulerFactory.getDefaultScheduler override def contextInitialized(event: ServletContextEvent): Unit = { val datadir = event.getServletContext.getInitParameter("gitbucket.home") @@ -181,11 +188,16 @@ logger.debug("Starting plugin system...") plugin.PluginSystem.init() + + scheduler.start() + PluginUpdateJob.schedule(scheduler) + logger.debug("PluginUpdateJob is started.") + logger.debug("Plugin system is initialized.") } def contextDestroyed(sce: ServletContextEvent): Unit = { - // Nothing to do. + scheduler.shutdown() } private def getConnection(servletContext: ServletContext): Connection =