Index: lib/cronlib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/cronlib.php,v
retrieving revision 1.13
diff -u -r1.13 cronlib.php
--- lib/cronlib.php	18 Nov 2010 21:34:02 -0000	1.13
+++ lib/cronlib.php	22 Nov 2010 18:11:59 -0000
@@ -156,30 +156,26 @@
     }
     mtrace("Finished quiz reports");
 
-    mtrace('Starting admin reports');
+    mtrace('Starting admin and course reports');
     // Admin reports do not have a database table that lists them. Instead a
     // report includes cron.php with function report_reportname_cron() if it wishes
     // to be cronned. It is up to cron.php to handle e.g. if it only needs to
     // actually do anything occasionally.
-    $reports = get_plugin_list('report');
-    foreach($reports as $report => $reportdir) {
-        $cronfile = $reportdir.'/cron.php';
-        if (file_exists($cronfile)) {
-            require_once($cronfile);
-            $cronfunction = 'report_'.$report.'_cron';
-            mtrace('Processing cron function for '.$report.'...', '');
-            $pre_dbqueries = null;
-            $pre_dbqueries = $DB->perf_get_queries();
-            $pre_time      = microtime(true);
-            $cronfunction();
-            if (isset($pre_dbqueries)) {
-                mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries");
-                mtrace("... used " . round(microtime(true) - $pre_time, 2) . " seconds");
-            }
-            mtrace('done.');
+    $reports = get_plugin_list_with_function(array('report', 'coursereport'),
+            'cron', 'cron.php');
+    foreach($reports as $report => $cronfunction) {
+        mtrace('Processing cron function for '.$report.'...', '');
+        $pre_dbqueries = null;
+        $pre_dbqueries = $DB->perf_get_queries();
+        $pre_time      = microtime(true);
+        $cronfunction();
+        if (isset($pre_dbqueries)) {
+            mtrace("... used " . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries");
+            mtrace("... used " . round(microtime(true) - $pre_time, 2) . " seconds");
         }
+        mtrace('done.');
     }
-    mtrace('Finished admin reports');
+    mtrace('Finished admin and course reports');
 
     mtrace('Starting main gradebook job ...');
     grade_cron();
Index: lib/moodlelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/moodlelib.php,v
retrieving revision 1.1506
diff -u -r1.1506 moodlelib.php
--- lib/moodlelib.php	14 Nov 2010 02:01:59 -0000	1.1506
+++ lib/moodlelib.php	22 Nov 2010 18:12:01 -0000
@@ -7228,6 +7228,65 @@
 }
 
 /**
+ * Gets a list of all plugin API functions for given plugin types, function
+ * name, and filename.
+ * @param mixed $plugintype Either a string naming plugin type, e.g. 'mod',
+ *   or else an array of such strings
+ * @param string $function Name of function after the frankenstyle prefix;
+ *   e.g. if the function is called report_courselist_hook then this value
+ *   would be 'hook'
+ * @param string $file Name of file that includes function within plugin,
+ *   default 'lib.php'
+ * @return Array of plugin frankenstyle (e.g. 'report_courselist', 'mod_forum')
+ *   to valid, existing plugin function name (e.g. 'report_courselist_hook',
+ *   'forum_hook')
+ */
+function get_plugin_list_with_function($plugintype, $function, $file='lib.php') {
+    $result = array();
+    if (is_array($plugintype)) {
+        foreach ($plugintype as $type) {
+            $result = array_merge($result,
+                get_plugin_list_with_function($type, $function, $file));
+        }
+        return $result;
+    }
+
+    $list = get_plugin_list($plugintype);
+    foreach($list as $plugin => $dir) {
+        $path = $dir . '/' . $file;
+        if (file_exists($path)) {
+            require_once($path);
+            $fullfunction = get_plugin_function_name(
+                    $plugintype, $plugin, $function);
+            if (function_exists($fullfunction)) {
+                $result[$plugintype . '_' . $plugin] = $fullfunction;
+            }
+        }
+    }
+    return $result;
+}
+
+/**
+ * Returns the name for an API function within a plugin. For example, if the
+ * plugintype is 'coursereport' and the plugin is 'progress' and the function
+ * name is 'frog' then the name will be 'courseport_progress_frog'. There is a
+ * special case for modules which don't have 'mod_' in the start of the
+ * function name.
+ * @param string $plugintype Plugin type e.g. 'mod'
+ * @param string $plugin Plugin name e.g. 'forum'
+ * @param string $name Function name e.g. 'cron'
+ * @return string Function name e.g. 'forum_cron'
+ */
+function get_plugin_function_name($plugintype, $plugin, $name) {
+    if ($plugintype == 'mod') {
+        // Module plugins do not have 'mod_' at the start
+        return $plugin . '_' . $name;
+    } else {
+        return $plugintype . '_' . $plugin . '_' . $name;
+    }
+}
+
+/**
  * Simplified version of get_list_of_plugins()
  * @param string $plugintype type of plugin
  * @return array name=>fulllocation pairs of plugins of given type
