1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/patches/patch-cache-pageparams-1.8.diff Sat Mar 29 19:32:26 2014 +0100
1.3 @@ -0,0 +1,168 @@
1.4 +diff -r d57b620213dd MoinMoin/Page.py
1.5 +--- a/MoinMoin/Page.py Tue Jul 30 17:41:42 2013 +0200
1.6 ++++ b/MoinMoin/Page.py Sat Mar 29 16:01:13 2014 +0100
1.7 +@@ -41,6 +41,7 @@
1.8 +
1.9 + from MoinMoin import config, caching, user, util, wikiutil
1.10 + from MoinMoin.logfile import eventlog
1.11 ++from MoinMoin.support.python_compatibility import hash_new
1.12 +
1.13 + def is_cache_exception(e):
1.14 + args = e.args
1.15 +@@ -1239,15 +1240,17 @@
1.16 + request.formatter = old_formatter
1.17 +
1.18 +
1.19 +- def getFormatterName(self):
1.20 ++ def getFormatterName(self, request=None):
1.21 + """ Return a formatter name as used in the caching system
1.22 +
1.23 ++ @param request: the active request (optional)
1.24 + @rtype: string
1.25 + @return: formatter name as used in caching
1.26 + """
1.27 +- if not hasattr(self, 'formatter') or self.formatter is None:
1.28 ++ formatter = getattr(self, 'formatter', None) or request and getattr(request, 'formatter', None)
1.29 ++ if not formatter:
1.30 + return ''
1.31 +- module = self.formatter.__module__
1.32 ++ module = formatter.__module__
1.33 + return module[module.rfind('.') + 1:]
1.34 +
1.35 + def canUseCache(self, parser=None):
1.36 +@@ -1336,9 +1339,12 @@
1.37 +
1.38 + def loadCache(self, request):
1.39 + """ Return page content cache or raises 'CacheNeedsUpdate' """
1.40 +- cache = caching.CacheEntry(request, self, self.getFormatterName(), scope='item')
1.41 +- attachmentsPath = self.getPagePath('attachments', check_create=0)
1.42 +- if cache.needsUpdate(self._text_filename(), attachmentsPath):
1.43 ++ for with_params in (True, False):
1.44 ++ cache = caching.CacheEntry(request, self, self.getCacheKey(request, with_params), scope='item')
1.45 ++ attachmentsPath = self.getPagePath('attachments', check_create=0)
1.46 ++ if not cache.needsUpdate(self._text_filename(), attachmentsPath):
1.47 ++ break
1.48 ++ else:
1.49 + raise Exception('CacheNeedsUpdate')
1.50 +
1.51 + import marshal
1.52 +@@ -1357,7 +1363,7 @@
1.53 + """ Format content into code, update cache and return code """
1.54 + import marshal
1.55 + from MoinMoin.formatter.text_python import Formatter
1.56 +- formatter = Formatter(request, ["page"], self.formatter)
1.57 ++ formatter = Formatter(request, ["page", "pageparams"], self.formatter)
1.58 +
1.59 + # Save request state while formatting page
1.60 + saved_current_lang = request.current_lang
1.61 +@@ -1369,10 +1375,45 @@
1.62 + src = formatter.assemble_code(text)
1.63 + code = compile(src.encode(config.charset),
1.64 + self.page_name.encode(config.charset), 'exec')
1.65 +- cache = caching.CacheEntry(request, self, self.getFormatterName(), scope='item')
1.66 ++ self.enforceCacheLimit(request)
1.67 ++ # Determine whether the parameters/args need to be incorporated into the
1.68 ++ # cache entry key.
1.69 ++ with_params = "pageparams" in formatter.getReportedDependencies()
1.70 ++ cache = caching.CacheEntry(request, self, self.getCacheKey(request, with_params), scope='item')
1.71 + cache.update(marshal.dumps(code))
1.72 + return code
1.73 +
1.74 ++ def enforceCacheLimit(self, request):
1.75 ++ """ Prevent too many cache entries being stored for a page """
1.76 ++ keys = caching.get_cache_list(request, self, 'item')
1.77 ++ try:
1.78 ++ cache_limit = int(getattr(request.cfg, 'page_cache_limit', "10"))
1.79 ++ except ValueError:
1.80 ++ cache_limit = 10
1.81 ++
1.82 ++ if len(keys) >= cache_limit:
1.83 ++ items = [caching.CacheEntry(request, self, key, scope='item') for key in keys]
1.84 ++ item_ages = [(item.mtime(), item) for item in items]
1.85 ++ item_ages.sort()
1.86 ++ for item_age, item in item_ages[:-cache_limit]:
1.87 ++ item.remove()
1.88 ++
1.89 ++ def getCacheKey(self, request, with_params=False, key=None):
1.90 ++ """ Generate a cache key for a page using optional request information """
1.91 ++ key = key or self.getFormatterName(request)
1.92 ++ if with_params and request.args:
1.93 ++ args = request.args.items()
1.94 ++ args.sort()
1.95 ++ key_args = []
1.96 ++ for k, values in args:
1.97 ++ for v in values:
1.98 ++ if not (k == "action" and v == "refresh"):
1.99 ++ key_args.append("%s=%s" % (k, wikiutil.url_quote(v)))
1.100 ++ arg_str = "&".join(key_args)
1.101 ++ if arg_str:
1.102 ++ key = "%s:%s" % (key, hash_new('sha1', arg_str).hexdigest())
1.103 ++ return key
1.104 ++
1.105 + def _specialPageText(self, request, special_type):
1.106 + """ Output the default page content for new pages.
1.107 +
1.108 +diff -r d57b620213dd MoinMoin/action/refresh.py
1.109 +--- a/MoinMoin/action/refresh.py Tue Jul 30 17:41:42 2013 +0200
1.110 ++++ b/MoinMoin/action/refresh.py Sat Mar 29 16:01:13 2014 +0100
1.111 +@@ -14,11 +14,14 @@
1.112 + arena = request.form.get('arena', ['Page.py'])[0]
1.113 + if arena == 'Page.py':
1.114 + arena = Page(request, pagename)
1.115 +- key = request.form.get('key', ['text_html'])[0]
1.116 ++ prefix = request.form.get('key', ['text_html'])[0]
1.117 +
1.118 + # Remove cache entry (if exists), and send the page
1.119 + from MoinMoin import caching
1.120 +- caching.CacheEntry(request, arena, key, scope='item').remove()
1.121 ++ keys = caching.get_cache_list(request, arena, 'item')
1.122 ++ for key in keys:
1.123 ++ if key.startswith(prefix):
1.124 ++ caching.CacheEntry(request, arena, key, scope='item').remove()
1.125 + caching.CacheEntry(request, arena, "pagelinks", scope='item').remove()
1.126 + request.page.send_page()
1.127 +
1.128 +diff -r d57b620213dd MoinMoin/formatter/text_python.py
1.129 +--- a/MoinMoin/formatter/text_python.py Tue Jul 30 17:41:42 2013 +0200
1.130 ++++ b/MoinMoin/formatter/text_python.py Sat Mar 29 16:01:13 2014 +0100
1.131 +@@ -10,6 +10,7 @@
1.132 +
1.133 + import time
1.134 + from MoinMoin import wikiutil
1.135 ++from MoinMoin.support.python_compatibility import set
1.136 +
1.137 +
1.138 + class Formatter:
1.139 +@@ -40,6 +41,12 @@
1.140 + self.text_cmd_begin = '\nrequest.write('
1.141 + self.text_cmd_end = ')\n'
1.142 +
1.143 ++ # Record dependency requirements of certain content
1.144 ++ self.__dependencies = set()
1.145 ++
1.146 ++ def getReportedDependencies(self):
1.147 ++ return self.__dependencies
1.148 ++
1.149 + def assemble_code(self, text):
1.150 + """inserts the code into the generated text
1.151 + """
1.152 +@@ -186,7 +193,10 @@
1.153 + return self.formatter.div(on, **kw)
1.154 +
1.155 + def macro(self, macro_obj, name, args, markup=None):
1.156 +- if self.__is_static(macro_obj.get_dependencies(name)):
1.157 ++ Dependencies = macro_obj.get_dependencies(name)
1.158 ++ self.__dependencies.update(Dependencies)
1.159 ++
1.160 ++ if self.__is_static(Dependencies):
1.161 + # XXX: why is this necessary??
1.162 + macro_obj.formatter = self
1.163 + return macro_obj.execute(name, args)
1.164 +@@ -204,6 +214,7 @@
1.165 + Dependencies = wikiutil.searchAndImportPlugin(self.request.cfg, "parser", parser_name, "Dependencies")
1.166 + except (wikiutil.PluginMissingError, wikiutil.PluginAttributeError):
1.167 + Dependencies = self.defaultDependencies
1.168 ++ self.__dependencies.update(Dependencies)
1.169 +
1.170 + if self.__is_static(Dependencies):
1.171 + return self.formatter.parser(parser_name, lines)