We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Yearly archivs not rebuilt when their posts change


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `nikola/plugins/task/archive.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Copyright © 2012-2015 Roberto Alsina and others.
4 
5 # Permission is hereby granted, free of charge, to any
6 # person obtaining a copy of this software and associated
7 # documentation files (the "Software"), to deal in the
8 # Software without restriction, including without limitation
9 # the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the
11 # Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice
15 # shall be included in all copies or substantial portions of
16 # the Software.
17 #
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
19 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
20 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
21 # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
22 # OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24 # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 
27 """Render the post archives."""
28 
29 import copy
30 import os
31 
32 # for tearDown with _reload we cannot use 'import from' to access LocaleBorg
33 import nikola.utils
34 import datetime
35 from nikola.plugin_categories import Task
36 from nikola.utils import config_changed, adjust_name_for_index_path, adjust_name_for_index_link
37 
38 
39 class Archive(Task):
40 
41     """Render the post archives."""
42 
43     name = "render_archive"
44 
45     def set_site(self, site):
46         """Set Nikola site."""
47         site.register_path_handler('archive', self.archive_path)
48         site.register_path_handler('archive_atom', self.archive_atom_path)
49         return super(Archive, self).set_site(site)
50 
51     def _prepare_task(self, kw, name, lang, posts, items, template_name,
52                       title, deps_translatable=None):
53         """Prepare an archive task."""
54         # name: used to build permalink and destination
55         # posts, items: posts or items; only one of them should be used,
56         #               the other be None
57         # template_name: name of the template to use
58         # title: the (translated) title for the generated page
59         # deps_translatable: dependencies (None if not added)
60         assert posts is not None or items is not None
61 
62         context = {}
63         context["lang"] = lang
64         context["title"] = title
65         context["permalink"] = self.site.link("archive", name, lang)
66         context["pagekind"] = ["list", "archive_page"]
67         if posts is not None:
68             context["posts"] = posts
69             n = len(posts)
70         else:
71             context["items"] = items
72             n = len(items)
73         task = self.site.generic_post_list_renderer(
74             lang,
75             [],
76             os.path.join(kw['output_folder'], self.site.path("archive", name, lang)),
77             template_name,
78             kw['filters'],
79             context,
80         )
81 
82         task_cfg = {1: copy.copy(kw), 2: n}
83         if deps_translatable is not None:
84             task_cfg[3] = deps_translatable
85         task['uptodate'] = task['uptodate'] + [config_changed(task_cfg, 'nikola.plugins.task.archive')]
86         task['basename'] = self.name
87         return task
88 
89     def _generate_posts_task(self, kw, name, lang, posts, title, deps_translatable=None):
90         """Genereate a task for an archive with posts."""
91         posts = sorted(posts, key=lambda a: a.date)
92         posts.reverse()
93         if kw['archives_are_indexes']:
94             def page_link(i, displayed_i, num_pages, force_addition, extension=None):
95                 feed = "_atom" if extension == ".atom" else ""
96                 return adjust_name_for_index_link(self.site.link("archive" + feed, name, lang), i, displayed_i,
97                                                   lang, self.site, force_addition, extension)
98 
99             def page_path(i, displayed_i, num_pages, force_addition, extension=None):
100                 feed = "_atom" if extension == ".atom" else ""
101                 return adjust_name_for_index_path(self.site.path("archive" + feed, name, lang), i, displayed_i,
102                                                   lang, self.site, force_addition, extension)
103 
104             uptodate = []
105             if deps_translatable is not None:
106                 uptodate += [config_changed(deps_translatable, 'nikola.plugins.task.archive')]
107             context = {"archive_name": name,
108                        "is_feed_stale": kw["is_feed_stale"],
109                        "pagekind": ["index", "archive_page"]}
110             yield self.site.generic_index_renderer(
111                 lang,
112                 posts,
113                 title,
114                 "archiveindex.tmpl",
115                 context,
116                 kw,
117                 str(self.name),
118                 page_link,
119                 page_path,
120                 uptodate)
121         else:
122             yield self._prepare_task(kw, name, lang, posts, None, "list_post.tmpl", title, deps_translatable)
123 
124     def gen_tasks(self):
125         """Generate archive tasks."""
126         kw = {
127             "messages": self.site.MESSAGES,
128             "translations": self.site.config['TRANSLATIONS'],
129             "output_folder": self.site.config['OUTPUT_FOLDER'],
130             "filters": self.site.config['FILTERS'],
131             "archives_are_indexes": self.site.config['ARCHIVES_ARE_INDEXES'],
132             "create_monthly_archive": self.site.config['CREATE_MONTHLY_ARCHIVE'],
133             "create_single_archive": self.site.config['CREATE_SINGLE_ARCHIVE'],
134             "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
135             "create_full_archives": self.site.config['CREATE_FULL_ARCHIVES'],
136             "create_daily_archive": self.site.config['CREATE_DAILY_ARCHIVE'],
137             "pretty_urls": self.site.config['PRETTY_URLS'],
138             "strip_indexes": self.site.config['STRIP_INDEXES'],
139             "index_file": self.site.config['INDEX_FILE'],
140             "generate_atom": self.site.config["GENERATE_ATOM"],
141         }
142         self.site.scan_posts()
143         yield self.group_task()
144         # TODO add next/prev links for years
145         if (kw['create_monthly_archive'] and kw['create_single_archive']) and not kw['create_full_archives']:
146             raise Exception('Cannot create monthly and single archives at the same time.')
147         for lang in kw["translations"]:
148             if kw['create_single_archive'] and not kw['create_full_archives']:
149                 # if we are creating one single archive
150                 archdata = {}
151             else:
152                 # if we are not creating one single archive, start with all years
153                 archdata = self.site.posts_per_year.copy()
154             if kw['create_single_archive'] or kw['create_full_archives']:
155                 # if we are creating one single archive, or full archives
156                 archdata[None] = self.site.posts  # for create_single_archive
157 
158             for year, posts in archdata.items():
159                 # Filter untranslated posts (Issue #1360)
160                 if not kw["show_untranslated_posts"]:
161                     posts = [p for p in posts if lang in p.translated_to]
162 
163                 # Add archive per year or total archive
164                 if year:
165                     title = kw["messages"][lang]["Posts for year %s"] % year
166                     kw["is_feed_stale"] = (datetime.datetime.utcnow().strftime("%Y") != year)
167                 else:
168                     title = kw["messages"][lang]["Archive"]
169                     kw["is_feed_stale"] = False
170                 deps_translatable = {}
171                 for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:
172                     deps_translatable[k] = self.site.GLOBAL_CONTEXT[k](lang)
173                 if not kw["create_monthly_archive"] or kw["create_full_archives"]:
174                     yield self._generate_posts_task(kw, year, lang, posts, title, deps_translatable)
175                 else:
176                     months = set([(m.split('/')[1], self.site.link("archive", m, lang)) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])
177                     months = sorted(list(months))
178                     months.reverse()
179                     items = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link] for month, link in months]
180                     yield self._prepare_task(kw, year, lang, None, items, "list.tmpl", title, deps_translatable)
181 
182             if not kw["create_monthly_archive"] and not kw["create_full_archives"] and not kw["create_daily_archive"]:
183                 continue  # Just to avoid nesting the other loop in this if
184             for yearmonth, posts in self.site.posts_per_month.items():
185                 # Add archive per month
186                 year, month = yearmonth.split('/')
187 
188                 kw["is_feed_stale"] = (datetime.datetime.utcnow().strftime("%Y/%m") != yearmonth)
189 
190                 # Filter untranslated posts (via Issue #1360)
191                 if not kw["show_untranslated_posts"]:
192                     posts = [p for p in posts if lang in p.translated_to]
193 
194                 if kw["create_monthly_archive"] or kw["create_full_archives"]:
195                     title = kw["messages"][lang]["Posts for {month} {year}"].format(
196                         year=year, month=nikola.utils.LocaleBorg().get_month_name(int(month), lang))
197                     yield self._generate_posts_task(kw, yearmonth, lang, posts, title)
198 
199                 if not kw["create_full_archives"] and not kw["create_daily_archive"]:
200                     continue  # Just to avoid nesting the other loop in this if
201                 # Add archive per day
202                 days = dict()
203                 for p in posts:
204                     if p.date.day not in days:
205                         days[p.date.day] = list()
206                     days[p.date.day].append(p)
207                 for day, posts in days.items():
208                     title = kw["messages"][lang]["Posts for {month} {day}, {year}"].format(
209                         year=year, month=nikola.utils.LocaleBorg().get_month_name(int(month), lang), day=day)
210                     yield self._generate_posts_task(kw, yearmonth + '/{0:02d}'.format(day), lang, posts, title)
211 
212         if not kw['create_single_archive'] and not kw['create_full_archives']:
213             # And an "all your years" page for yearly and monthly archives
214             if "is_feed_stale" in kw:
215                 del kw["is_feed_stale"]
216             years = list(self.site.posts_per_year.keys())
217             years.sort(reverse=True)
218             kw['years'] = years
219             for lang in kw["translations"]:
220                 items = [(y, self.site.link("archive", y, lang)) for y in years]
221                 yield self._prepare_task(kw, None, lang, None, items, "list.tmpl", kw["messages"][lang]["Archive"])
222 
223     def archive_path(self, name, lang, is_feed=False):
224         """Return archive paths."""
225         if is_feed:
226             extension = ".atom"
227             archive_file = os.path.splitext(self.site.config['ARCHIVE_FILENAME'])[0] + extension
228             index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension
229         else:
230             archive_file = self.site.config['ARCHIVE_FILENAME']
231             index_file = self.site.config['INDEX_FILE']
232         if name:
233             return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
234                                   self.site.config['ARCHIVE_PATH'], name,
235                                   index_file] if _f]
236         else:
237             return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
238                                   self.site.config['ARCHIVE_PATH'],
239                                   archive_file] if _f]
240 
241     def archive_atom_path(self, name, lang):
242         """Return Atom archive paths."""
243         return self.archive_path(name, lang, is_feed=True)
244
```
--- 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/nikola/plugins/task/archive.py b/nikola/plugins/task/archive.py
--- a/nikola/plugins/task/archive.py
+++ b/nikola/plugins/task/archive.py
@@ -58,7 +58,7 @@
         # title: the (translated) title for the generated page
         # deps_translatable: dependencies (None if not added)
         assert posts is not None or items is not None
-
+        task_cfg = [copy.copy(kw)]
         context = {}
         context["lang"] = lang
         context["title"] = title
@@ -66,10 +66,12 @@
         context["pagekind"] = ["list", "archive_page"]
         if posts is not None:
             context["posts"] = posts
-            n = len(posts)
+            # Depend on all post metadata because it can be used in templates (Issue #1931)
+            task_cfg.append(repr(p) for p in posts)
         else:
+            # Depend on the content of items, to rebuild if links change (Issue #1931)
             context["items"] = items
-            n = len(items)
+            task_cfg.append(items)
         task = self.site.generic_post_list_renderer(
             lang,
             [],
@@ -79,7 +81,7 @@
             context,
         )
 
-        task_cfg = {1: copy.copy(kw), 2: n}
+        task_cfg = {i: x for i, x in enumerate(task_cfg)}
         if deps_translatable is not None:
             task_cfg[3] = deps_translatable
         task['uptodate'] = task['uptodate'] + [config_changed(task_cfg, 'nikola.plugins.task.archive')]

{"golden_diff": "diff --git a/nikola/plugins/task/archive.py b/nikola/plugins/task/archive.py\n--- a/nikola/plugins/task/archive.py\n+++ b/nikola/plugins/task/archive.py\n@@ -58,7 +58,7 @@\n         # title: the (translated) title for the generated page\n         # deps_translatable: dependencies (None if not added)\n         assert posts is not None or items is not None\n-\n+        task_cfg = [copy.copy(kw)]\n         context = {}\n         context[\"lang\"] = lang\n         context[\"title\"] = title\n@@ -66,10 +66,12 @@\n         context[\"pagekind\"] = [\"list\", \"archive_page\"]\n         if posts is not None:\n             context[\"posts\"] = posts\n-            n = len(posts)\n+            # Depend on all post metadata because it can be used in templates (Issue #1931)\n+            task_cfg.append(repr(p) for p in posts)\n         else:\n+            # Depend on the content of items, to rebuild if links change (Issue #1931)\n             context[\"items\"] = items\n-            n = len(items)\n+            task_cfg.append(items)\n         task = self.site.generic_post_list_renderer(\n             lang,\n             [],\n@@ -79,7 +81,7 @@\n             context,\n         )\n \n-        task_cfg = {1: copy.copy(kw), 2: n}\n+        task_cfg = {i: x for i, x in enumerate(task_cfg)}\n         if deps_translatable is not None:\n             task_cfg[3] = deps_translatable\n         task['uptodate'] = task['uptodate'] + [config_changed(task_cfg, 'nikola.plugins.task.archive')]\n", "issue": "Yearly archivs not rebuilt when their posts change\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2012-2015 Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Render the post archives.\"\"\"\n\nimport copy\nimport os\n\n# for tearDown with _reload we cannot use 'import from' to access LocaleBorg\nimport nikola.utils\nimport datetime\nfrom nikola.plugin_categories import Task\nfrom nikola.utils import config_changed, adjust_name_for_index_path, adjust_name_for_index_link\n\n\nclass Archive(Task):\n\n    \"\"\"Render the post archives.\"\"\"\n\n    name = \"render_archive\"\n\n    def set_site(self, site):\n        \"\"\"Set Nikola site.\"\"\"\n        site.register_path_handler('archive', self.archive_path)\n        site.register_path_handler('archive_atom', self.archive_atom_path)\n        return super(Archive, self).set_site(site)\n\n    def _prepare_task(self, kw, name, lang, posts, items, template_name,\n                      title, deps_translatable=None):\n        \"\"\"Prepare an archive task.\"\"\"\n        # name: used to build permalink and destination\n        # posts, items: posts or items; only one of them should be used,\n        #               the other be None\n        # template_name: name of the template to use\n        # title: the (translated) title for the generated page\n        # deps_translatable: dependencies (None if not added)\n        assert posts is not None or items is not None\n\n        context = {}\n        context[\"lang\"] = lang\n        context[\"title\"] = title\n        context[\"permalink\"] = self.site.link(\"archive\", name, lang)\n        context[\"pagekind\"] = [\"list\", \"archive_page\"]\n        if posts is not None:\n            context[\"posts\"] = posts\n            n = len(posts)\n        else:\n            context[\"items\"] = items\n            n = len(items)\n        task = self.site.generic_post_list_renderer(\n            lang,\n            [],\n            os.path.join(kw['output_folder'], self.site.path(\"archive\", name, lang)),\n            template_name,\n            kw['filters'],\n            context,\n        )\n\n        task_cfg = {1: copy.copy(kw), 2: n}\n        if deps_translatable is not None:\n            task_cfg[3] = deps_translatable\n        task['uptodate'] = task['uptodate'] + [config_changed(task_cfg, 'nikola.plugins.task.archive')]\n        task['basename'] = self.name\n        return task\n\n    def _generate_posts_task(self, kw, name, lang, posts, title, deps_translatable=None):\n        \"\"\"Genereate a task for an archive with posts.\"\"\"\n        posts = sorted(posts, key=lambda a: a.date)\n        posts.reverse()\n        if kw['archives_are_indexes']:\n            def page_link(i, displayed_i, num_pages, force_addition, extension=None):\n                feed = \"_atom\" if extension == \".atom\" else \"\"\n                return adjust_name_for_index_link(self.site.link(\"archive\" + feed, name, lang), i, displayed_i,\n                                                  lang, self.site, force_addition, extension)\n\n            def page_path(i, displayed_i, num_pages, force_addition, extension=None):\n                feed = \"_atom\" if extension == \".atom\" else \"\"\n                return adjust_name_for_index_path(self.site.path(\"archive\" + feed, name, lang), i, displayed_i,\n                                                  lang, self.site, force_addition, extension)\n\n            uptodate = []\n            if deps_translatable is not None:\n                uptodate += [config_changed(deps_translatable, 'nikola.plugins.task.archive')]\n            context = {\"archive_name\": name,\n                       \"is_feed_stale\": kw[\"is_feed_stale\"],\n                       \"pagekind\": [\"index\", \"archive_page\"]}\n            yield self.site.generic_index_renderer(\n                lang,\n                posts,\n                title,\n                \"archiveindex.tmpl\",\n                context,\n                kw,\n                str(self.name),\n                page_link,\n                page_path,\n                uptodate)\n        else:\n            yield self._prepare_task(kw, name, lang, posts, None, \"list_post.tmpl\", title, deps_translatable)\n\n    def gen_tasks(self):\n        \"\"\"Generate archive tasks.\"\"\"\n        kw = {\n            \"messages\": self.site.MESSAGES,\n            \"translations\": self.site.config['TRANSLATIONS'],\n            \"output_folder\": self.site.config['OUTPUT_FOLDER'],\n            \"filters\": self.site.config['FILTERS'],\n            \"archives_are_indexes\": self.site.config['ARCHIVES_ARE_INDEXES'],\n            \"create_monthly_archive\": self.site.config['CREATE_MONTHLY_ARCHIVE'],\n            \"create_single_archive\": self.site.config['CREATE_SINGLE_ARCHIVE'],\n            \"show_untranslated_posts\": self.site.config['SHOW_UNTRANSLATED_POSTS'],\n            \"create_full_archives\": self.site.config['CREATE_FULL_ARCHIVES'],\n            \"create_daily_archive\": self.site.config['CREATE_DAILY_ARCHIVE'],\n            \"pretty_urls\": self.site.config['PRETTY_URLS'],\n            \"strip_indexes\": self.site.config['STRIP_INDEXES'],\n            \"index_file\": self.site.config['INDEX_FILE'],\n            \"generate_atom\": self.site.config[\"GENERATE_ATOM\"],\n        }\n        self.site.scan_posts()\n        yield self.group_task()\n        # TODO add next/prev links for years\n        if (kw['create_monthly_archive'] and kw['create_single_archive']) and not kw['create_full_archives']:\n            raise Exception('Cannot create monthly and single archives at the same time.')\n        for lang in kw[\"translations\"]:\n            if kw['create_single_archive'] and not kw['create_full_archives']:\n                # if we are creating one single archive\n                archdata = {}\n            else:\n                # if we are not creating one single archive, start with all years\n                archdata = self.site.posts_per_year.copy()\n            if kw['create_single_archive'] or kw['create_full_archives']:\n                # if we are creating one single archive, or full archives\n                archdata[None] = self.site.posts  # for create_single_archive\n\n            for year, posts in archdata.items():\n                # Filter untranslated posts (Issue #1360)\n                if not kw[\"show_untranslated_posts\"]:\n                    posts = [p for p in posts if lang in p.translated_to]\n\n                # Add archive per year or total archive\n                if year:\n                    title = kw[\"messages\"][lang][\"Posts for year %s\"] % year\n                    kw[\"is_feed_stale\"] = (datetime.datetime.utcnow().strftime(\"%Y\") != year)\n                else:\n                    title = kw[\"messages\"][lang][\"Archive\"]\n                    kw[\"is_feed_stale\"] = False\n                deps_translatable = {}\n                for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:\n                    deps_translatable[k] = self.site.GLOBAL_CONTEXT[k](lang)\n                if not kw[\"create_monthly_archive\"] or kw[\"create_full_archives\"]:\n                    yield self._generate_posts_task(kw, year, lang, posts, title, deps_translatable)\n                else:\n                    months = set([(m.split('/')[1], self.site.link(\"archive\", m, lang)) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])\n                    months = sorted(list(months))\n                    months.reverse()\n                    items = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link] for month, link in months]\n                    yield self._prepare_task(kw, year, lang, None, items, \"list.tmpl\", title, deps_translatable)\n\n            if not kw[\"create_monthly_archive\"] and not kw[\"create_full_archives\"] and not kw[\"create_daily_archive\"]:\n                continue  # Just to avoid nesting the other loop in this if\n            for yearmonth, posts in self.site.posts_per_month.items():\n                # Add archive per month\n                year, month = yearmonth.split('/')\n\n                kw[\"is_feed_stale\"] = (datetime.datetime.utcnow().strftime(\"%Y/%m\") != yearmonth)\n\n                # Filter untranslated posts (via Issue #1360)\n                if not kw[\"show_untranslated_posts\"]:\n                    posts = [p for p in posts if lang in p.translated_to]\n\n                if kw[\"create_monthly_archive\"] or kw[\"create_full_archives\"]:\n                    title = kw[\"messages\"][lang][\"Posts for {month} {year}\"].format(\n                        year=year, month=nikola.utils.LocaleBorg().get_month_name(int(month), lang))\n                    yield self._generate_posts_task(kw, yearmonth, lang, posts, title)\n\n                if not kw[\"create_full_archives\"] and not kw[\"create_daily_archive\"]:\n                    continue  # Just to avoid nesting the other loop in this if\n                # Add archive per day\n                days = dict()\n                for p in posts:\n                    if p.date.day not in days:\n                        days[p.date.day] = list()\n                    days[p.date.day].append(p)\n                for day, posts in days.items():\n                    title = kw[\"messages\"][lang][\"Posts for {month} {day}, {year}\"].format(\n                        year=year, month=nikola.utils.LocaleBorg().get_month_name(int(month), lang), day=day)\n                    yield self._generate_posts_task(kw, yearmonth + '/{0:02d}'.format(day), lang, posts, title)\n\n        if not kw['create_single_archive'] and not kw['create_full_archives']:\n            # And an \"all your years\" page for yearly and monthly archives\n            if \"is_feed_stale\" in kw:\n                del kw[\"is_feed_stale\"]\n            years = list(self.site.posts_per_year.keys())\n            years.sort(reverse=True)\n            kw['years'] = years\n            for lang in kw[\"translations\"]:\n                items = [(y, self.site.link(\"archive\", y, lang)) for y in years]\n                yield self._prepare_task(kw, None, lang, None, items, \"list.tmpl\", kw[\"messages\"][lang][\"Archive\"])\n\n    def archive_path(self, name, lang, is_feed=False):\n        \"\"\"Return archive paths.\"\"\"\n        if is_feed:\n            extension = \".atom\"\n            archive_file = os.path.splitext(self.site.config['ARCHIVE_FILENAME'])[0] + extension\n            index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension\n        else:\n            archive_file = self.site.config['ARCHIVE_FILENAME']\n            index_file = self.site.config['INDEX_FILE']\n        if name:\n            return [_f for _f in [self.site.config['TRANSLATIONS'][lang],\n                                  self.site.config['ARCHIVE_PATH'], name,\n                                  index_file] if _f]\n        else:\n            return [_f for _f in [self.site.config['TRANSLATIONS'][lang],\n                                  self.site.config['ARCHIVE_PATH'],\n                                  archive_file] if _f]\n\n    def archive_atom_path(self, name, lang):\n        \"\"\"Return Atom archive paths.\"\"\"\n        return self.archive_path(name, lang, is_feed=True)\n", "path": "nikola/plugins/task/archive.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Copyright \u00a9 2012-2015 Roberto Alsina and others.\n\n# Permission is hereby granted, free of charge, to any\n# person obtaining a copy of this software and associated\n# documentation files (the \"Software\"), to deal in the\n# Software without restriction, including without limitation\n# the rights to use, copy, modify, merge, publish,\n# distribute, sublicense, and/or sell copies of the\n# Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice\n# shall be included in all copies or substantial portions of\n# the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY\n# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR\n# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS\n# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\n# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\"\"\"Render the post archives.\"\"\"\n\nimport copy\nimport os\n\n# for tearDown with _reload we cannot use 'import from' to access LocaleBorg\nimport nikola.utils\nimport datetime\nfrom nikola.plugin_categories import Task\nfrom nikola.utils import config_changed, adjust_name_for_index_path, adjust_name_for_index_link\n\n\nclass Archive(Task):\n\n    \"\"\"Render the post archives.\"\"\"\n\n    name = \"render_archive\"\n\n    def set_site(self, site):\n        \"\"\"Set Nikola site.\"\"\"\n        site.register_path_handler('archive', self.archive_path)\n        site.register_path_handler('archive_atom', self.archive_atom_path)\n        return super(Archive, self).set_site(site)\n\n    def _prepare_task(self, kw, name, lang, posts, items, template_name,\n                      title, deps_translatable=None):\n        \"\"\"Prepare an archive task.\"\"\"\n        # name: used to build permalink and destination\n        # posts, items: posts or items; only one of them should be used,\n        #               the other be None\n        # template_name: name of the template to use\n        # title: the (translated) title for the generated page\n        # deps_translatable: dependencies (None if not added)\n        assert posts is not None or items is not None\n        task_cfg = [copy.copy(kw)]\n        context = {}\n        context[\"lang\"] = lang\n        context[\"title\"] = title\n        context[\"permalink\"] = self.site.link(\"archive\", name, lang)\n        context[\"pagekind\"] = [\"list\", \"archive_page\"]\n        if posts is not None:\n            context[\"posts\"] = posts\n            # Depend on all post metadata because it can be used in templates (Issue #1931)\n            task_cfg.append(repr(p) for p in posts)\n        else:\n            # Depend on the content of items, to rebuild if links change (Issue #1931)\n            context[\"items\"] = items\n            task_cfg.append(items)\n        task = self.site.generic_post_list_renderer(\n            lang,\n            [],\n            os.path.join(kw['output_folder'], self.site.path(\"archive\", name, lang)),\n            template_name,\n            kw['filters'],\n            context,\n        )\n\n        task_cfg = {i: x for i, x in enumerate(task_cfg)}\n        if deps_translatable is not None:\n            task_cfg[3] = deps_translatable\n        task['uptodate'] = task['uptodate'] + [config_changed(task_cfg, 'nikola.plugins.task.archive')]\n        task['basename'] = self.name\n        return task\n\n    def _generate_posts_task(self, kw, name, lang, posts, title, deps_translatable=None):\n        \"\"\"Genereate a task for an archive with posts.\"\"\"\n        posts = sorted(posts, key=lambda a: a.date)\n        posts.reverse()\n        if kw['archives_are_indexes']:\n            def page_link(i, displayed_i, num_pages, force_addition, extension=None):\n                feed = \"_atom\" if extension == \".atom\" else \"\"\n                return adjust_name_for_index_link(self.site.link(\"archive\" + feed, name, lang), i, displayed_i,\n                                                  lang, self.site, force_addition, extension)\n\n            def page_path(i, displayed_i, num_pages, force_addition, extension=None):\n                feed = \"_atom\" if extension == \".atom\" else \"\"\n                return adjust_name_for_index_path(self.site.path(\"archive\" + feed, name, lang), i, displayed_i,\n                                                  lang, self.site, force_addition, extension)\n\n            uptodate = []\n            if deps_translatable is not None:\n                uptodate += [config_changed(deps_translatable, 'nikola.plugins.task.archive')]\n            context = {\"archive_name\": name,\n                       \"is_feed_stale\": kw[\"is_feed_stale\"],\n                       \"pagekind\": [\"index\", \"archive_page\"]}\n            yield self.site.generic_index_renderer(\n                lang,\n                posts,\n                title,\n                \"archiveindex.tmpl\",\n                context,\n                kw,\n                str(self.name),\n                page_link,\n                page_path,\n                uptodate)\n        else:\n            yield self._prepare_task(kw, name, lang, posts, None, \"list_post.tmpl\", title, deps_translatable)\n\n    def gen_tasks(self):\n        \"\"\"Generate archive tasks.\"\"\"\n        kw = {\n            \"messages\": self.site.MESSAGES,\n            \"translations\": self.site.config['TRANSLATIONS'],\n            \"output_folder\": self.site.config['OUTPUT_FOLDER'],\n            \"filters\": self.site.config['FILTERS'],\n            \"archives_are_indexes\": self.site.config['ARCHIVES_ARE_INDEXES'],\n            \"create_monthly_archive\": self.site.config['CREATE_MONTHLY_ARCHIVE'],\n            \"create_single_archive\": self.site.config['CREATE_SINGLE_ARCHIVE'],\n            \"show_untranslated_posts\": self.site.config['SHOW_UNTRANSLATED_POSTS'],\n            \"create_full_archives\": self.site.config['CREATE_FULL_ARCHIVES'],\n            \"create_daily_archive\": self.site.config['CREATE_DAILY_ARCHIVE'],\n            \"pretty_urls\": self.site.config['PRETTY_URLS'],\n            \"strip_indexes\": self.site.config['STRIP_INDEXES'],\n            \"index_file\": self.site.config['INDEX_FILE'],\n            \"generate_atom\": self.site.config[\"GENERATE_ATOM\"],\n        }\n        self.site.scan_posts()\n        yield self.group_task()\n        # TODO add next/prev links for years\n        if (kw['create_monthly_archive'] and kw['create_single_archive']) and not kw['create_full_archives']:\n            raise Exception('Cannot create monthly and single archives at the same time.')\n        for lang in kw[\"translations\"]:\n            if kw['create_single_archive'] and not kw['create_full_archives']:\n                # if we are creating one single archive\n                archdata = {}\n            else:\n                # if we are not creating one single archive, start with all years\n                archdata = self.site.posts_per_year.copy()\n            if kw['create_single_archive'] or kw['create_full_archives']:\n                # if we are creating one single archive, or full archives\n                archdata[None] = self.site.posts  # for create_single_archive\n\n            for year, posts in archdata.items():\n                # Filter untranslated posts (Issue #1360)\n                if not kw[\"show_untranslated_posts\"]:\n                    posts = [p for p in posts if lang in p.translated_to]\n\n                # Add archive per year or total archive\n                if year:\n                    title = kw[\"messages\"][lang][\"Posts for year %s\"] % year\n                    kw[\"is_feed_stale\"] = (datetime.datetime.utcnow().strftime(\"%Y\") != year)\n                else:\n                    title = kw[\"messages\"][lang][\"Archive\"]\n                    kw[\"is_feed_stale\"] = False\n                deps_translatable = {}\n                for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:\n                    deps_translatable[k] = self.site.GLOBAL_CONTEXT[k](lang)\n                if not kw[\"create_monthly_archive\"] or kw[\"create_full_archives\"]:\n                    yield self._generate_posts_task(kw, year, lang, posts, title, deps_translatable)\n                else:\n                    months = set([(m.split('/')[1], self.site.link(\"archive\", m, lang)) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])\n                    months = sorted(list(months))\n                    months.reverse()\n                    items = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link] for month, link in months]\n                    yield self._prepare_task(kw, year, lang, None, items, \"list.tmpl\", title, deps_translatable)\n\n            if not kw[\"create_monthly_archive\"] and not kw[\"create_full_archives\"] and not kw[\"create_daily_archive\"]:\n                continue  # Just to avoid nesting the other loop in this if\n            for yearmonth, posts in self.site.posts_per_month.items():\n                # Add archive per month\n                year, month = yearmonth.split('/')\n\n                kw[\"is_feed_stale\"] = (datetime.datetime.utcnow().strftime(\"%Y/%m\") != yearmonth)\n\n                # Filter untranslated posts (via Issue #1360)\n                if not kw[\"show_untranslated_posts\"]:\n                    posts = [p for p in posts if lang in p.translated_to]\n\n                if kw[\"create_monthly_archive\"] or kw[\"create_full_archives\"]:\n                    title = kw[\"messages\"][lang][\"Posts for {month} {year}\"].format(\n                        year=year, month=nikola.utils.LocaleBorg().get_month_name(int(month), lang))\n                    yield self._generate_posts_task(kw, yearmonth, lang, posts, title)\n\n                if not kw[\"create_full_archives\"] and not kw[\"create_daily_archive\"]:\n                    continue  # Just to avoid nesting the other loop in this if\n                # Add archive per day\n                days = dict()\n                for p in posts:\n                    if p.date.day not in days:\n                        days[p.date.day] = list()\n                    days[p.date.day].append(p)\n                for day, posts in days.items():\n                    title = kw[\"messages\"][lang][\"Posts for {month} {day}, {year}\"].format(\n                        year=year, month=nikola.utils.LocaleBorg().get_month_name(int(month), lang), day=day)\n                    yield self._generate_posts_task(kw, yearmonth + '/{0:02d}'.format(day), lang, posts, title)\n\n        if not kw['create_single_archive'] and not kw['create_full_archives']:\n            # And an \"all your years\" page for yearly and monthly archives\n            if \"is_feed_stale\" in kw:\n                del kw[\"is_feed_stale\"]\n            years = list(self.site.posts_per_year.keys())\n            years.sort(reverse=True)\n            kw['years'] = years\n            for lang in kw[\"translations\"]:\n                items = [(y, self.site.link(\"archive\", y, lang)) for y in years]\n                yield self._prepare_task(kw, None, lang, None, items, \"list.tmpl\", kw[\"messages\"][lang][\"Archive\"])\n\n    def archive_path(self, name, lang, is_feed=False):\n        \"\"\"Return archive paths.\"\"\"\n        if is_feed:\n            extension = \".atom\"\n            archive_file = os.path.splitext(self.site.config['ARCHIVE_FILENAME'])[0] + extension\n            index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension\n        else:\n            archive_file = self.site.config['ARCHIVE_FILENAME']\n            index_file = self.site.config['INDEX_FILE']\n        if name:\n            return [_f for _f in [self.site.config['TRANSLATIONS'][lang],\n                                  self.site.config['ARCHIVE_PATH'], name,\n                                  index_file] if _f]\n        else:\n            return [_f for _f in [self.site.config['TRANSLATIONS'][lang],\n                                  self.site.config['ARCHIVE_PATH'],\n                                  archive_file] if _f]\n\n    def archive_atom_path(self, name, lang):\n        \"\"\"Return Atom archive paths.\"\"\"\n        return self.archive_path(name, lang, is_feed=True)\n", "path": "nikola/plugins/task/archive.py"}]}