We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Warn about ignored buildHorizon and logHorizion.
These aren't currently used, but they could be supported in the database. Either we should get rid of them, or open a ticket to add back support (and probably document that they aren't currently working).


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `master/buildbot/status/web/logs.py`
Content:
```
1 # This file is part of Buildbot.  Buildbot is free software: you can
2 # redistribute it and/or modify it under the terms of the GNU General Public
3 # License as published by the Free Software Foundation, version 2.
4 #
5 # This program is distributed in the hope that it will be useful, but WITHOUT
6 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7 # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
8 # details.
9 #
10 # You should have received a copy of the GNU General Public License along with
11 # this program; if not, write to the Free Software Foundation, Inc., 51
12 # Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13 #
14 # Copyright Buildbot Team Members
15 
16 
17 from zope.interface import implements
18 from twisted.python import components
19 from twisted.spread import pb
20 from twisted.web import server
21 from twisted.web.resource import Resource
22 from twisted.web.error import NoResource
23 
24 from buildbot import interfaces
25 from buildbot.status import logfile
26 from buildbot.status.web.base import IHTMLLog, HtmlResource, path_to_root
27 
28 class ChunkConsumer:
29     implements(interfaces.IStatusLogConsumer)
30 
31     def __init__(self, original, textlog):
32         self.original = original
33         self.textlog = textlog
34     def registerProducer(self, producer, streaming):
35         self.producer = producer
36         self.original.registerProducer(producer, streaming)
37     def unregisterProducer(self):
38         self.original.unregisterProducer()
39     def writeChunk(self, chunk):
40         formatted = self.textlog.content([chunk])
41         try:
42             if isinstance(formatted, unicode):
43                 formatted = formatted.encode('utf-8')
44             self.original.write(formatted)
45         except pb.DeadReferenceError:
46             self.producing.stopProducing()
47     def finish(self):
48         self.textlog.finished()
49 
50 
51 # /builders/$builder/builds/$buildnum/steps/$stepname/logs/$logname
52 class TextLog(Resource):
53     # a new instance of this Resource is created for each client who views
54     # it, so we can afford to track the request in the Resource.
55     implements(IHTMLLog)
56 
57     asText = False
58     subscribed = False
59 
60     def __init__(self, original):
61         Resource.__init__(self)
62         self.original = original
63 
64     def getChild(self, path, req):
65         if path == "text":
66             self.asText = True
67             return self
68         return Resource.getChild(self, path, req)
69 
70     def content(self, entries):
71         html_entries = []
72         text_data = ''
73         for type, entry in entries:
74             if type >= len(logfile.ChunkTypes) or type < 0:
75                 # non-std channel, don't display
76                 continue
77             
78             is_header = type == logfile.HEADER
79 
80             if not self.asText:
81                 # jinja only works with unicode, or pure ascii, so assume utf-8 in logs
82                 if not isinstance(entry, unicode):
83                     entry = unicode(entry, 'utf-8', 'replace')
84                 html_entries.append(dict(type = logfile.ChunkTypes[type], 
85                                          text = entry,
86                                          is_header = is_header))
87             elif not is_header:
88                 text_data += entry
89 
90         if self.asText:
91             return text_data
92         else:
93             return self.template.module.chunks(html_entries)
94 
95     def render_HEAD(self, req):
96         self._setContentType(req)
97 
98         # vague approximation, ignores markup
99         req.setHeader("content-length", self.original.length)
100         return ''
101 
102     def render_GET(self, req):
103         self._setContentType(req)
104         self.req = req
105 
106         if not self.asText:
107             self.template = req.site.buildbot_service.templates.get_template("logs.html")                
108             
109             data = self.template.module.page_header(
110                     pageTitle = "Log File contents",
111                     texturl = req.childLink("text"),
112                     path_to_root = path_to_root(req))
113             data = data.encode('utf-8')                   
114             req.write(data)
115 
116         self.original.subscribeConsumer(ChunkConsumer(req, self))
117         return server.NOT_DONE_YET
118 
119     def _setContentType(self, req):
120         if self.asText:
121             req.setHeader("content-type", "text/plain; charset=utf-8")
122         else:
123             req.setHeader("content-type", "text/html; charset=utf-8")
124         
125     def finished(self):
126         if not self.req:
127             return
128         try:
129             if not self.asText:
130                 data = self.template.module.page_footer()
131                 data = data.encode('utf-8')
132                 self.req.write(data)
133             self.req.finish()
134         except pb.DeadReferenceError:
135             pass
136         # break the cycle, the Request's .notifications list includes the
137         # Deferred (from req.notifyFinish) that's pointing at us.
138         self.req = None
139         
140         # release template
141         self.template = None
142 
143 components.registerAdapter(TextLog, interfaces.IStatusLog, IHTMLLog)
144 
145 
146 class HTMLLog(Resource):
147     implements(IHTMLLog)
148 
149     def __init__(self, original):
150         Resource.__init__(self)
151         self.original = original
152 
153     def render(self, request):
154         request.setHeader("content-type", "text/html")
155         return self.original.html
156 
157 components.registerAdapter(HTMLLog, logfile.HTMLLogFile, IHTMLLog)
158 
159 
160 class LogsResource(HtmlResource):
161     addSlash = True
162 
163     def __init__(self, step_status):
164         HtmlResource.__init__(self)
165         self.step_status = step_status
166 
167     def getChild(self, path, req):
168         for log in self.step_status.getLogs():
169             if path == log.getName():
170                 if log.hasContents():
171                     return IHTMLLog(interfaces.IStatusLog(log))
172                 return NoResource("Empty Log '%s'" % path)
173         return HtmlResource.getChild(self, path, req)
174
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/master/buildbot/status/web/logs.py b/master/buildbot/status/web/logs.py
--- a/master/buildbot/status/web/logs.py
+++ b/master/buildbot/status/web/logs.py
@@ -103,6 +103,11 @@
         self._setContentType(req)
         self.req = req
 
+        if (self.original.isFinished()):
+            req.setHeader("Cache-Control", "max-age=604800")
+        else:
+            req.setHeader("Cache-Control", "no-cache")
+
         if not self.asText:
             self.template = req.site.buildbot_service.templates.get_template("logs.html")

{"golden_diff": "diff --git a/master/buildbot/status/web/logs.py b/master/buildbot/status/web/logs.py\n--- a/master/buildbot/status/web/logs.py\n+++ b/master/buildbot/status/web/logs.py\n@@ -103,6 +103,11 @@\n         self._setContentType(req)\n         self.req = req\n \n+        if (self.original.isFinished()):\n+            req.setHeader(\"Cache-Control\", \"max-age=604800\")\n+        else:\n+            req.setHeader(\"Cache-Control\", \"no-cache\")\n+\n         if not self.asText:\n             self.template = req.site.buildbot_service.templates.get_template(\"logs.html\")\n", "issue": "Warn about ignored buildHorizon and logHorizion.\nThese aren't currently used, but they could be supported in the database. Either we should get rid of them, or open a ticket to add back support (and probably document that they aren't currently working).\n\n", "before_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\n\nfrom zope.interface import implements\nfrom twisted.python import components\nfrom twisted.spread import pb\nfrom twisted.web import server\nfrom twisted.web.resource import Resource\nfrom twisted.web.error import NoResource\n\nfrom buildbot import interfaces\nfrom buildbot.status import logfile\nfrom buildbot.status.web.base import IHTMLLog, HtmlResource, path_to_root\n\nclass ChunkConsumer:\n    implements(interfaces.IStatusLogConsumer)\n\n    def __init__(self, original, textlog):\n        self.original = original\n        self.textlog = textlog\n    def registerProducer(self, producer, streaming):\n        self.producer = producer\n        self.original.registerProducer(producer, streaming)\n    def unregisterProducer(self):\n        self.original.unregisterProducer()\n    def writeChunk(self, chunk):\n        formatted = self.textlog.content([chunk])\n        try:\n            if isinstance(formatted, unicode):\n                formatted = formatted.encode('utf-8')\n            self.original.write(formatted)\n        except pb.DeadReferenceError:\n            self.producing.stopProducing()\n    def finish(self):\n        self.textlog.finished()\n\n\n# /builders/$builder/builds/$buildnum/steps/$stepname/logs/$logname\nclass TextLog(Resource):\n    # a new instance of this Resource is created for each client who views\n    # it, so we can afford to track the request in the Resource.\n    implements(IHTMLLog)\n\n    asText = False\n    subscribed = False\n\n    def __init__(self, original):\n        Resource.__init__(self)\n        self.original = original\n\n    def getChild(self, path, req):\n        if path == \"text\":\n            self.asText = True\n            return self\n        return Resource.getChild(self, path, req)\n\n    def content(self, entries):\n        html_entries = []\n        text_data = ''\n        for type, entry in entries:\n            if type >= len(logfile.ChunkTypes) or type < 0:\n                # non-std channel, don't display\n                continue\n            \n            is_header = type == logfile.HEADER\n\n            if not self.asText:\n                # jinja only works with unicode, or pure ascii, so assume utf-8 in logs\n                if not isinstance(entry, unicode):\n                    entry = unicode(entry, 'utf-8', 'replace')\n                html_entries.append(dict(type = logfile.ChunkTypes[type], \n                                         text = entry,\n                                         is_header = is_header))\n            elif not is_header:\n                text_data += entry\n\n        if self.asText:\n            return text_data\n        else:\n            return self.template.module.chunks(html_entries)\n\n    def render_HEAD(self, req):\n        self._setContentType(req)\n\n        # vague approximation, ignores markup\n        req.setHeader(\"content-length\", self.original.length)\n        return ''\n\n    def render_GET(self, req):\n        self._setContentType(req)\n        self.req = req\n\n        if not self.asText:\n            self.template = req.site.buildbot_service.templates.get_template(\"logs.html\")                \n            \n            data = self.template.module.page_header(\n                    pageTitle = \"Log File contents\",\n                    texturl = req.childLink(\"text\"),\n                    path_to_root = path_to_root(req))\n            data = data.encode('utf-8')                   \n            req.write(data)\n\n        self.original.subscribeConsumer(ChunkConsumer(req, self))\n        return server.NOT_DONE_YET\n\n    def _setContentType(self, req):\n        if self.asText:\n            req.setHeader(\"content-type\", \"text/plain; charset=utf-8\")\n        else:\n            req.setHeader(\"content-type\", \"text/html; charset=utf-8\")\n        \n    def finished(self):\n        if not self.req:\n            return\n        try:\n            if not self.asText:\n                data = self.template.module.page_footer()\n                data = data.encode('utf-8')\n                self.req.write(data)\n            self.req.finish()\n        except pb.DeadReferenceError:\n            pass\n        # break the cycle, the Request's .notifications list includes the\n        # Deferred (from req.notifyFinish) that's pointing at us.\n        self.req = None\n        \n        # release template\n        self.template = None\n\ncomponents.registerAdapter(TextLog, interfaces.IStatusLog, IHTMLLog)\n\n\nclass HTMLLog(Resource):\n    implements(IHTMLLog)\n\n    def __init__(self, original):\n        Resource.__init__(self)\n        self.original = original\n\n    def render(self, request):\n        request.setHeader(\"content-type\", \"text/html\")\n        return self.original.html\n\ncomponents.registerAdapter(HTMLLog, logfile.HTMLLogFile, IHTMLLog)\n\n\nclass LogsResource(HtmlResource):\n    addSlash = True\n\n    def __init__(self, step_status):\n        HtmlResource.__init__(self)\n        self.step_status = step_status\n\n    def getChild(self, path, req):\n        for log in self.step_status.getLogs():\n            if path == log.getName():\n                if log.hasContents():\n                    return IHTMLLog(interfaces.IStatusLog(log))\n                return NoResource(\"Empty Log '%s'\" % path)\n        return HtmlResource.getChild(self, path, req)\n", "path": "master/buildbot/status/web/logs.py"}], "after_files": [{"content": "# This file is part of Buildbot.  Buildbot is free software: you can\n# redistribute it and/or modify it under the terms of the GNU General Public\n# License as published by the Free Software Foundation, version 2.\n#\n# This program is distributed in the hope that it will be useful, but WITHOUT\n# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\n# details.\n#\n# You should have received a copy of the GNU General Public License along with\n# this program; if not, write to the Free Software Foundation, Inc., 51\n# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n#\n# Copyright Buildbot Team Members\n\n\nfrom zope.interface import implements\nfrom twisted.python import components\nfrom twisted.spread import pb\nfrom twisted.web import server\nfrom twisted.web.resource import Resource\nfrom twisted.web.error import NoResource\n\nfrom buildbot import interfaces\nfrom buildbot.status import logfile\nfrom buildbot.status.web.base import IHTMLLog, HtmlResource, path_to_root\n\nclass ChunkConsumer:\n    implements(interfaces.IStatusLogConsumer)\n\n    def __init__(self, original, textlog):\n        self.original = original\n        self.textlog = textlog\n    def registerProducer(self, producer, streaming):\n        self.producer = producer\n        self.original.registerProducer(producer, streaming)\n    def unregisterProducer(self):\n        self.original.unregisterProducer()\n    def writeChunk(self, chunk):\n        formatted = self.textlog.content([chunk])\n        try:\n            if isinstance(formatted, unicode):\n                formatted = formatted.encode('utf-8')\n            self.original.write(formatted)\n        except pb.DeadReferenceError:\n            self.producing.stopProducing()\n    def finish(self):\n        self.textlog.finished()\n\n\n# /builders/$builder/builds/$buildnum/steps/$stepname/logs/$logname\nclass TextLog(Resource):\n    # a new instance of this Resource is created for each client who views\n    # it, so we can afford to track the request in the Resource.\n    implements(IHTMLLog)\n\n    asText = False\n    subscribed = False\n\n    def __init__(self, original):\n        Resource.__init__(self)\n        self.original = original\n\n    def getChild(self, path, req):\n        if path == \"text\":\n            self.asText = True\n            return self\n        return Resource.getChild(self, path, req)\n\n    def content(self, entries):\n        html_entries = []\n        text_data = ''\n        for type, entry in entries:\n            if type >= len(logfile.ChunkTypes) or type < 0:\n                # non-std channel, don't display\n                continue\n            \n            is_header = type == logfile.HEADER\n\n            if not self.asText:\n                # jinja only works with unicode, or pure ascii, so assume utf-8 in logs\n                if not isinstance(entry, unicode):\n                    entry = unicode(entry, 'utf-8', 'replace')\n                html_entries.append(dict(type = logfile.ChunkTypes[type], \n                                         text = entry,\n                                         is_header = is_header))\n            elif not is_header:\n                text_data += entry\n\n        if self.asText:\n            return text_data\n        else:\n            return self.template.module.chunks(html_entries)\n\n    def render_HEAD(self, req):\n        self._setContentType(req)\n\n        # vague approximation, ignores markup\n        req.setHeader(\"content-length\", self.original.length)\n        return ''\n\n    def render_GET(self, req):\n        self._setContentType(req)\n        self.req = req\n\n        if (self.original.isFinished()):\n            req.setHeader(\"Cache-Control\", \"max-age=604800\")\n        else:\n            req.setHeader(\"Cache-Control\", \"no-cache\")\n\n        if not self.asText:\n            self.template = req.site.buildbot_service.templates.get_template(\"logs.html\")                \n            \n            data = self.template.module.page_header(\n                    pageTitle = \"Log File contents\",\n                    texturl = req.childLink(\"text\"),\n                    path_to_root = path_to_root(req))\n            data = data.encode('utf-8')                   \n            req.write(data)\n\n        self.original.subscribeConsumer(ChunkConsumer(req, self))\n        return server.NOT_DONE_YET\n\n    def _setContentType(self, req):\n        if self.asText:\n            req.setHeader(\"content-type\", \"text/plain; charset=utf-8\")\n        else:\n            req.setHeader(\"content-type\", \"text/html; charset=utf-8\")\n        \n    def finished(self):\n        if not self.req:\n            return\n        try:\n            if not self.asText:\n                data = self.template.module.page_footer()\n                data = data.encode('utf-8')\n                self.req.write(data)\n            self.req.finish()\n        except pb.DeadReferenceError:\n            pass\n        # break the cycle, the Request's .notifications list includes the\n        # Deferred (from req.notifyFinish) that's pointing at us.\n        self.req = None\n        \n        # release template\n        self.template = None\n\ncomponents.registerAdapter(TextLog, interfaces.IStatusLog, IHTMLLog)\n\n\nclass HTMLLog(Resource):\n    implements(IHTMLLog)\n\n    def __init__(self, original):\n        Resource.__init__(self)\n        self.original = original\n\n    def render(self, request):\n        request.setHeader(\"content-type\", \"text/html\")\n        return self.original.html\n\ncomponents.registerAdapter(HTMLLog, logfile.HTMLLogFile, IHTMLLog)\n\n\nclass LogsResource(HtmlResource):\n    addSlash = True\n\n    def __init__(self, step_status):\n        HtmlResource.__init__(self)\n        self.step_status = step_status\n\n    def getChild(self, path, req):\n        for log in self.step_status.getLogs():\n            if path == log.getName():\n                if log.hasContents():\n                    return IHTMLLog(interfaces.IStatusLog(log))\n                return NoResource(\"Empty Log '%s'\" % path)\n        return HtmlResource.getChild(self, path, req)\n", "path": "master/buildbot/status/web/logs.py"}]}