Example #1
0
    def remove_excluded_image(self, img):
        # Remove excluded images
        # img is something like galleries/demo/tesla2_lg.jpg so it's the *source* path
        # and we should remove both the large and thumbnail *destination* paths

        img = os.path.relpath(img, self.kw['gallery_path'])
        output_folder = os.path.dirname(
            os.path.join(
                self.kw["output_folder"],
                self.site.path("gallery", os.path.dirname(img))))
        img_path = os.path.join(output_folder, os.path.basename(img))
        fname, ext = os.path.splitext(img_path)
        thumb_path = fname + '.thumbnail' + ext

        yield utils.apply_filters({
            'basename': '_render_galleries_clean',
            'name': thumb_path,
            'actions': [
                (utils.remove_file, (thumb_path,))
            ],
            'clean': True,
            'uptodate': [utils.config_changed(self.kw)],
        }, self.kw['filters'])

        yield utils.apply_filters({
            'basename': '_render_galleries_clean',
            'name': img_path,
            'actions': [
                (utils.remove_file, (img_path,))
            ],
            'clean': True,
            'uptodate': [utils.config_changed(self.kw)],
        }, self.kw['filters'])
Example #2
0
    def gen_tasks(self):
        """Generate Windows Live Tiles and notifications."""
        kw = {
            "default_lang": self.site.config["DEFAULT_LANG"],
            "site_url": self.site.config["BASE_URL"],
            "output_folder": self.site.config["OUTPUT_FOLDER"],
            "show_untranslated_posts": self.site.config["SHOW_UNTRANSLATED_POSTS"],
            "windows_live_tiles": self.site.config["WINDOWS_LIVE_TILES"],
        }

        msapplication_assets = os.path.join(kw["output_folder"], "assets", "msapplication")
        if not os.path.exists(msapplication_assets):
            os.makedirs(msapplication_assets)

        self.site.scan_posts()
        yield self.group_task()

        deps = []
        if kw["show_untranslated_posts"]:
            posts = self.site.posts[:5]
        else:
            posts = [x for x in self.site.posts if x.is_translation_available(kw["default_lang"])][:5]
        for post in posts:
            deps += post.deps(kw["default_lang"])

        for i, post in zip(range(len(posts)), posts):
            notification_deps = post.deps(kw["default_lang"])
            output_name = os.path.join(msapplication_assets, "tile_notification" + str(i + 1) + ".xml")
            titles = {
                "maintitle": post.title(kw["default_lang"]),
                "title1": posts[0].title(kw["default_lang"]),
                "title2": posts[1].title(kw["default_lang"]),
                "title3": posts[2].title(kw["default_lang"])
            }

            yield {
                "basename": "windows_live_tiles",
                "name": os.path.normpath(output_name),
                "file_dep": notification_deps,
                "targets": [output_name],
                "actions": [(self.generate_notification_tile, (output_name, kw["default_lang"], kw["windows_live_tiles"]["tileimages"], titles, post.meta[kw["default_lang"]]["previewimage"]))],
                "task_dep": ["render_posts"],
                "clean": True,
                "uptodate": [utils.config_changed(kw)],
            }

        browserconfig_output_name = os.path.join(kw["output_folder"], "browserconfig.xml")
        yield {
            "basename": "windows_live_tiles",
            "name": os.path.normpath(browserconfig_output_name),
            "file_dep": deps,
            "targets": [browserconfig_output_name],
            "actions": [(self.generate_browserconfig,
                        (browserconfig_output_name, kw["windows_live_tiles"],
                         len(posts)))],

            "task_dep": ["render_posts"],
            "clean": True,
            "uptodate": [utils.config_changed(kw)],
        }
Example #3
0
    def remove_excluded_image(self, img, input_folder):
        # Remove excluded images
        # img is something like input_folder/demo/tesla2_lg.jpg so it's the *source* path
        # and we should remove both the large and thumbnail *destination* paths

        output_folder = os.path.dirname(
            os.path.join(self.kw["output_folder"], self.site.path("gallery", os.path.dirname(img)))
        )
        img = os.path.relpath(img, input_folder)
        img_path = os.path.join(output_folder, os.path.basename(img))
        fname, ext = os.path.splitext(img_path)
        thumb_path = fname + ".thumbnail" + ext

        yield utils.apply_filters(
            {
                "basename": "_render_galleries_clean",
                "name": thumb_path,
                "actions": [(utils.remove_file, (thumb_path,))],
                "clean": True,
                "uptodate": [utils.config_changed(self.kw, "nikola.plugins.task.galleries:clean_thumb")],
            },
            self.kw["filters"],
        )

        yield utils.apply_filters(
            {
                "basename": "_render_galleries_clean",
                "name": img_path,
                "actions": [(utils.remove_file, (img_path,))],
                "clean": True,
                "uptodate": [utils.config_changed(self.kw, "nikola.plugins.task.galleries:clean_file")],
            },
            self.kw["filters"],
        )
Example #4
0
    def gen_tasks(self):
        """Create tasks to copy the assets of the whole theme chain.

        If a file is present on two themes, use the version
        from the "youngest" theme.
        """

        kw = {
            "themes": self.site.THEMES,
            "output_folder": self.site.config['OUTPUT_FOLDER'],
            "filters": self.site.config['FILTERS'],
            "code_color_scheme": self.site.config['CODE_COLOR_SCHEME'],
        }
        flag = True
        has_code_css = False
        tasks = {}
        code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')
        for theme_name in kw['themes']:
            src = os.path.join(utils.get_theme_path(theme_name), 'assets')
            dst = os.path.join(kw['output_folder'], 'assets')
            for task in utils.copy_tree(src, dst):
                if task['name'] in tasks:
                    continue
                if task['targets'][0] == code_css_path:
                    has_code_css = True
                tasks[task['name']] = task
                task['uptodate'] = [utils.config_changed(kw)]
                task['basename'] = self.name
                flag = False
                yield utils.apply_filters(task, kw['filters'])

        if flag:
            yield {
                'basename': self.name,
                'name': 'None',
                'uptodate': [True],
                'actions': [],
            }

        if not has_code_css:  # Generate it

            def create_code_css():
                from pygments.formatters import get_formatter_by_name
                formatter = get_formatter_by_name('html', style=kw["code_color_scheme"])
                utils.makedirs(os.path.dirname(code_css_path))
                with codecs.open(code_css_path, 'wb+', 'utf8') as outf:
                    outf.write(formatter.get_style_defs('.code'))
                    outf.write("table.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}")

            task = {
                'basename': self.name,
                'name': code_css_path,
                'targets': [code_css_path],
                'uptodate': [utils.config_changed(kw)],
                'actions': [(create_code_css, [])],
                'clean': True,
            }
            yield utils.apply_filters(task, kw['filters'])
Example #5
0
    def gen_tasks(self):
        """Create tasks to copy the assets of the whole theme chain.

        If a file is present on two themes, use the version
        from the "youngest" theme.
        """

        kw = {
            "themes": self.site.THEMES,
            "output_folder": self.site.config["OUTPUT_FOLDER"],
            "filters": self.site.config["FILTERS"],
            "code_color_scheme": self.site.config["CODE_COLOR_SCHEME"],
        }
        has_code_css = False
        tasks = {}
        code_css_path = os.path.join(kw["output_folder"], "assets", "css", "code.css")

        yield self.group_task()

        for theme_name in kw["themes"]:
            src = os.path.join(utils.get_theme_path(theme_name), "assets")
            dst = os.path.join(kw["output_folder"], "assets")
            for task in utils.copy_tree(src, dst):
                if task["name"] in tasks:
                    continue
                if task["targets"][0] == code_css_path:
                    has_code_css = True
                tasks[task["name"]] = task
                task["uptodate"] = [utils.config_changed(kw)]
                task["basename"] = self.name
                yield utils.apply_filters(task, kw["filters"])

        if not has_code_css:  # Generate it

            def create_code_css():
                from pygments.formatters import get_formatter_by_name

                formatter = get_formatter_by_name("html", style=kw["code_color_scheme"])
                utils.makedirs(os.path.dirname(code_css_path))
                with codecs.open(code_css_path, "wb+", "utf8") as outf:
                    outf.write(formatter.get_style_defs(["pre.code", "div.code pre"]))
                    outf.write("\ntable.codetable { width: 100%;} td.linenos {text-align: right; width: 4em;}\n")

            task = {
                "basename": self.name,
                "name": code_css_path,
                "targets": [code_css_path],
                "uptodate": [utils.config_changed(kw)],
                "actions": [(create_code_css, [])],
                "clean": True,
            }
            yield utils.apply_filters(task, kw["filters"])
Example #6
0
    def create_target_images(self, img, input_path):
        """Copy images to output."""
        gallery_name = os.path.dirname(img)
        output_gallery = os.path.dirname(
            os.path.join(
                self.kw["output_folder"],
                self.site.path("gallery_global", gallery_name)))
        # Do thumbnails and copy originals
        # img is "galleries/name/image_name.jpg"
        # img_name is "image_name.jpg"
        # fname, ext are "image_name", ".jpg"
        # thumb_path is
        # "output/GALLERY_PATH/name/image_name.thumbnail.jpg"
        img_name = os.path.basename(img)
        fname, ext = os.path.splitext(img_name)
        thumb_path = os.path.join(
            output_gallery,
            ".thumbnail".join([fname, ext]))
        # thumb_path is "output/GALLERY_PATH/name/image_name.jpg"
        orig_dest_path = os.path.join(output_gallery, img_name)
        yield utils.apply_filters({
            'basename': self.name,
            'name': thumb_path,
            'file_dep': [img],
            'targets': [thumb_path],
            'actions': [
                (self.resize_image,
                    (img, thumb_path, self.kw['thumbnail_size'], True, self.kw['preserve_exif_data'],
                     self.kw['exif_whitelist'], self.kw['preserve_icc_profiles']))
            ],
            'clean': True,
            'uptodate': [utils.config_changed({
                1: self.kw['thumbnail_size']
            }, 'nikola.plugins.task.galleries:resize_thumb')],
        }, self.kw['filters'])

        yield utils.apply_filters({
            'basename': self.name,
            'name': orig_dest_path,
            'file_dep': [img],
            'targets': [orig_dest_path],
            'actions': [
                (self.resize_image,
                    (img, orig_dest_path, self.kw['max_image_size'], True, self.kw['preserve_exif_data'],
                     self.kw['exif_whitelist'], self.kw['preserve_icc_profiles']))
            ],
            'clean': True,
            'uptodate': [utils.config_changed({
                1: self.kw['max_image_size']
            }, 'nikola.plugins.task.galleries:resize_max')],
        }, self.kw['filters'])
Example #7
0
    def create_target_images(self, img):
        gallery_name = os.path.relpath(os.path.dirname(img), self.kw['gallery_path'])
        output_gallery = os.path.dirname(
            os.path.join(
                self.kw["output_folder"],
                self.site.path("gallery", gallery_name)))
        # Do thumbnails and copy originals
        # img is "galleries/name/image_name.jpg"
        # img_name is "image_name.jpg"
        # fname, ext are "image_name", ".jpg"
        # thumb_path is
        # "output/GALLERY_PATH/name/image_name.thumbnail.jpg"
        img_name = os.path.basename(img)
        fname, ext = os.path.splitext(img_name)
        thumb_path = os.path.join(
            output_gallery,
            ".thumbnail".join([fname, ext]))
        # thumb_path is "output/GALLERY_PATH/name/image_name.jpg"
        orig_dest_path = os.path.join(output_gallery, img_name)
        yield utils.apply_filters({
            'basename': self.name,
            'name': thumb_path,
            'file_dep': [img],
            'targets': [thumb_path],
            'actions': [
                (self.resize_image,
                    (img, thumb_path, self.kw['thumbnail_size']))
            ],
            'clean': True,
            'uptodate': [utils.config_changed({
                1: self.kw['thumbnail_size']
            })],
        }, self.kw['filters'])

        yield utils.apply_filters({
            'basename': self.name,
            'name': orig_dest_path,
            'file_dep': [img],
            'targets': [orig_dest_path],
            'actions': [
                (self.resize_image,
                    (img, orig_dest_path, self.kw['max_image_size']))
            ],
            'clean': True,
            'uptodate': [utils.config_changed({
                1: self.kw['max_image_size']
            })],
        }, self.kw['filters'])
Example #8
0
    def gen_tasks(self):
        """Copy static files into the output folder."""

        kw = {
            'files_folders': self.site.config['FILES_FOLDERS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
            'filters': self.site.config['FILTERS'],
        }

        flag = False
        for src in kw['files_folders']:
            dst = kw['output_folder']
            filters = kw['filters']
            real_dst = os.path.join(dst, kw['files_folders'][src])
            for task in utils.copy_tree(src, real_dst, link_cutoff=dst):
                flag = True
                task['basename'] = self.name
                task['uptodate'] = task.get('uptodate', []) +\
                    [utils.config_changed(kw)]
                yield utils.apply_filters(task, filters)
        if not flag:
            yield {
                'basename': self.name,
                'actions': (),
            }
Example #9
0
    def gen_tasks(self):
        """Build HTML fragments from metadata and text."""
        self.site.scan_posts()
        kw = {
            "translations": self.site.config["TRANSLATIONS"],
            "timeline": self.site.timeline,
            "default_lang": self.site.config["DEFAULT_LANG"],
            "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
            "demote_headers": self.site.config['DEMOTE_HEADERS'],
        }

        yield self.group_task()

        for lang in kw["translations"]:
            deps_dict = copy(kw)
            deps_dict.pop('timeline')
            for post in kw['timeline']:
                dest = post.translated_base_path(lang)
                file_dep = [p for p in post.fragment_deps(lang) if not p.startswith("####MAGIC####")]
                task = {
                    'basename': self.name,
                    'name': dest,
                    'file_dep': file_dep,
                    'targets': [dest],
                    'actions': [(post.compile, (lang, )),
                                (update_deps, (post, lang, )),
                                ],
                    'clean': True,
                    'uptodate': [
                        utils.config_changed(deps_dict, 'nikola.plugins.task.posts'),
                        lambda p=post, l=lang: dependence_on_timeline(p, l)
                    ] + post.fragment_deps_uptodate(lang),
                }
                yield task
Example #10
0
 def list_tags_page(self, kw):
     """a global "all your tags/categories" page for each language"""
     tags = list(self.site.posts_per_tag.keys())
     categories = list(self.site.posts_per_category.keys())
     # We want our tags to be sorted case insensitive
     tags.sort(key=lambda a: a.lower())
     categories.sort(key=lambda a: a.lower())
     if categories != [""]:
         has_categories = True
     else:
         has_categories = False
     template_name = "tags.tmpl"
     kw["tags"] = tags
     kw["categories"] = categories
     for lang in kw["translations"]:
         output_name = os.path.join(kw["output_folder"], self.site.path("tag_index", None, lang))
         output_name = output_name
         context = {}
         if has_categories:
             context["title"] = kw["messages"][lang]["Tags and Categories"]
         else:
             context["title"] = kw["messages"][lang]["Tags"]
         context["items"] = [(tag, self.site.link("tag", tag, lang)) for tag in tags]
         if has_categories:
             context["cat_items"] = [(tag, self.site.link("category", tag, lang)) for tag in categories]
         else:
             context["cat_items"] = None
         context["permalink"] = self.site.link("tag_index", None, lang)
         context["description"] = None
         task = self.site.generic_post_list_renderer(lang, [], output_name, template_name, kw["filters"], context)
         task_cfg = {1: task["uptodate"][0].config, 2: kw}
         task["uptodate"] = [utils.config_changed(task_cfg)]
         task["basename"] = str(self.name)
         yield task
Example #11
0
 def author_rss(self, author, lang, posts, kw):
     """Create a RSS feed for a single author in a given language."""
     kind = "author"
     # Render RSS
     output_name = os.path.normpath(
         os.path.join(kw['output_folder'],
                      self.site.path(kind + "_rss", author, lang)))
     feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", author, lang).lstrip('/'))
     deps = []
     deps_uptodate = []
     post_list = sorted(posts, key=lambda a: a.date)
     post_list.reverse()
     for post in post_list:
         deps += post.deps(lang)
         deps_uptodate += post.deps_uptodate(lang)
     task = {
         'basename': str(self.name),
         'name': output_name,
         'file_dep': deps,
         'targets': [output_name],
         'actions': [(utils.generic_rss_renderer,
                     (lang, "{0} ({1})".format(kw["blog_title"](lang), self._get_title(author)),
                      kw["site_url"], None, post_list,
                      output_name, kw["feed_teasers"], kw["feed_plain"], kw['feed_length'],
                      feed_url, None, kw["feed_link_append_query"]))],
         'clean': True,
         'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.authors:rss')] + deps_uptodate,
         'task_dep': ['render_posts'],
     }
     return utils.apply_filters(task, kw['filters'])
Example #12
0
 def tag_page_as_list(self, tag, lang, post_list, kw, is_category):
     """We render a single flat link list with this tag's posts"""
     kind = "category" if is_category else "tag"
     template_name = "tag.tmpl"
     output_name = os.path.join(kw['output_folder'], self.site.path(
         kind, tag, lang))
     context = {}
     context["lang"] = lang
     context["title"] = kw["messages"][lang]["Posts about %s"] % tag
     context["posts"] = post_list
     context["permalink"] = self.site.link(kind, tag, lang)
     context["tag"] = tag
     context["kind"] = kind
     context["description"] = None
     task = self.site.generic_post_list_renderer(
         lang,
         post_list,
         output_name,
         template_name,
         kw['filters'],
         context,
     )
     task_cfg = {1: task['uptodate'][0].config, 2: kw}
     task['uptodate'] = [utils.config_changed(task_cfg)]
     task['basename'] = str(self.name)
     yield task
Example #13
0
 def gen_tasks(self):
     """Generate RSS feeds."""
     kw = {
         "translations": self.site.config["TRANSLATIONS"],
         "filters": self.site.config["FILTERS"],
         "blog_title": self.site.config["BLOG_TITLE"],
         "site_url": self.site.config["SITE_URL"],
         "blog_description": self.site.config["BLOG_DESCRIPTION"],
         "output_folder": self.site.config["OUTPUT_FOLDER"],
         "rss_teasers": self.site.config["RSS_TEASERS"],
     }
     self.site.scan_posts()
     # TODO: timeline is global, kill it
     for lang in kw["translations"]:
         output_name = os.path.join(kw['output_folder'],
                                    self.site.path("rss", None, lang))
         deps = []
         posts = [x for x in self.site.timeline if x.use_in_feeds][:10]
         for post in posts:
             deps += post.deps(lang)
         yield {
             'basename': 'render_rss',
             'name': output_name,
             'file_dep': deps,
             'targets': [output_name],
             'actions': [(utils.generic_rss_renderer,
                         (lang, kw["blog_title"], kw["site_url"],
                          kw["blog_description"], posts, output_name,
                          kw["rss_teasers"]))],
             'clean': True,
             'uptodate': [utils.config_changed(kw)],
         }
Example #14
0
    def _generate_subclassification_page(self, taxonomy, node, context, kw, lang):
        """Render a list of subclassifications."""
        def get_subnode_data(subnode):
            return [
                taxonomy.get_classification_friendly_name(subnode.classification_name, lang, only_last_component=True),
                self.site.link(taxonomy.classification_name, subnode.classification_name, lang),
                len(self._filter_list(self.site.posts_per_classification[taxonomy.classification_name][lang][subnode.classification_name], lang))
            ]

        items = [get_subnode_data(subnode) for subnode in node.children]
        context = copy(context)
        context["lang"] = lang
        context["permalink"] = self.site.link(taxonomy.classification_name, node.classification_name, lang)
        if "pagekind" not in context:
            context["pagekind"] = ["list", "archive_page"]
        context["items"] = items
        task = self.site.generic_post_list_renderer(
            lang,
            [],
            os.path.join(kw['output_folder'], self.site.path(taxonomy.classification_name, node.classification_name, lang)),
            taxonomy.subcategories_list_template,
            kw['filters'],
            context,
        )
        task_cfg = {1: kw, 2: items}
        task['uptodate'] = task['uptodate'] + [utils.config_changed(task_cfg, 'nikola.plugins.task.taxonomy')]
        task['basename'] = self.name
        return task
Example #15
0
 def tag_rss(self, tag, lang, posts, kw, is_category):
     """RSS for a single tag / language"""
     kind = "category" if is_category else "tag"
     #Render RSS
     output_name = os.path.normpath(
         os.path.join(kw['output_folder'],
                      self.site.path(kind + "_rss", tag, lang)))
     feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", tag, lang).lstrip('/'))
     deps = []
     post_list = [self.site.global_data[post] for post in posts if
                  self.site.global_data[post].use_in_feeds]
     post_list.sort(key=lambda a: a.date)
     post_list.reverse()
     for post in post_list:
         deps += post.deps(lang)
     return {
         'basename': str(self.name),
         'name': output_name,
         'file_dep': deps,
         'targets': [output_name],
         'actions': [(utils.generic_rss_renderer,
                     (lang, "{0} ({1})".format(kw["blog_title"], tag),
                      kw["site_url"], None, post_list,
                      output_name, kw["rss_teasers"], kw['feed_length'], feed_url))],
         'clean': True,
         'uptodate': [utils.config_changed(kw)],
         'task_dep': ['render_posts'],
     }
Example #16
0
 def _generate_classification_page_as_rss(self, taxonomy, classification, filtered_posts, title, description, kw, lang):
     """Create a RSS feed for a single classification in a given language."""
     kind = taxonomy.classification_name
     # Render RSS
     output_name = os.path.normpath(os.path.join(self.site.config['OUTPUT_FOLDER'], self.site.path(kind + "_rss", classification, lang)))
     feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", classification, lang).lstrip('/'))
     deps = []
     deps_uptodate = []
     for post in filtered_posts:
         deps += post.deps(lang)
         deps_uptodate += post.deps_uptodate(lang)
     blog_title = kw["blog_title"](lang)
     task = {
         'basename': str(self.name),
         'name': output_name,
         'file_dep': deps,
         'targets': [output_name],
         'actions': [(utils.generic_rss_renderer,
                     (lang, "{0} ({1})".format(blog_title, title) if blog_title != title else blog_title,
                      kw["site_url"], description, filtered_posts,
                      output_name, kw["feed_teasers"], kw["feed_plain"], kw['feed_length'],
                      feed_url, _enclosure, kw["feed_links_append_query"]))],
         'clean': True,
         'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.taxonomies:rss')] + deps_uptodate,
         'task_dep': ['render_posts'],
     }
     return utils.apply_filters(task, kw['filters'])
Example #17
0
    def _prepare_task(self, kw, name, lang, posts, items, template_name,
                      title, deps_translatable=None):
        # name: used to build permalink and destination
        # posts, items: posts or items; only one of them should be used,
        #               the other be None
        # template_name: name of the template to use
        # 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

        context = {}
        context["lang"] = lang
        context["title"] = title
        context["permalink"] = self.site.link("archive", name, lang)
        if posts is not None:
            context["posts"] = posts
            n = len(posts)
        else:
            context["items"] = items
            n = len(items)
        task = self.site.generic_post_list_renderer(
            lang,
            [],
            os.path.join(kw['output_folder'], self.site.path("archive", name, lang)),
            template_name,
            kw['filters'],
            context,
        )

        task_cfg = {1: kw, 2: n}
        if deps_translatable is not None:
            task_cfg[3] = deps_translatable
        task['uptodate'] = task['uptodate'] + [config_changed(task_cfg, 'nikola.plugins.task.archive')]
        task['basename'] = self.name
        return task
Example #18
0
 def _render_classification_overview(self, classification_name, template, lang, context, kw):
     # Prepare rendering
     context["permalink"] = self.site.link("{}_index".format(classification_name), None, lang)
     if "pagekind" not in context:
         context["pagekind"] = ["list", "tags_page"]
     output_name = os.path.join(self.site.config['OUTPUT_FOLDER'], self.site.path('{}_index'.format(classification_name), None, lang))
     blinker.signal('generate_classification_overview').send({
         'site': self.site,
         'classification_name': classification_name,
         'lang': lang,
         'context': context,
         'kw': kw,
         'output_name': output_name,
     })
     task = self.site.generic_post_list_renderer(
         lang,
         [],
         output_name,
         template,
         kw['filters'],
         context,
     )
     task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.taxonomies:page')]
     task['basename'] = str(self.name)
     yield task
Example #19
0
    def task_generate_posts(self):
        """Generate post files for the blog entries."""
        def gen_id(entry):
            h = hashlib.md5()
            h.update(entry.feed.name.encode('utf8'))
            h.update(entry.guid)
            return h.hexdigest()

        def generate_post(entry):
            unique_id = gen_id(entry)
            meta_path = os.path.join('posts', unique_id + '.meta')
            post_path = os.path.join('posts', unique_id + '.txt')
            with codecs.open(meta_path, 'wb+', 'utf8') as fd:
                fd.write('%s\n' % entry.title.replace('\n', ' '))
                fd.write('%s\n' % unique_id)
                fd.write('%s\n' % entry.date.strftime('%Y/%m/%d %H:%M'))
                fd.write('\n')
                fd.write('%s\n' % entry.link)
            with codecs.open(post_path, 'wb+', 'utf8') as fd:
                fd.write('.. raw:: html\n\n')
                content = entry.content
                if not content:
                    content = 'Sin contenido'
                for line in content.splitlines():
                    fd.write('    %s\n' % line)

        for entry in Entry.select().order_by(Entry.date.desc()):
            entry_id = gen_id(entry)
            yield {
                'basename': self.name,
                'targets': [os.path.join('posts', entry_id + '.meta'), os.path.join('posts', entry_id + '.txt')],
                'name': entry_id,
                'actions': [(generate_post, (entry,))],
                'uptodate': [config_changed({1: entry})]
            }
Example #20
0
    def _generate_posts_task(self, kw, name, lang, posts, title, deps_translatable=None):
        posts = sorted(posts, key=lambda a: a.date)
        posts.reverse()
        if kw['archives_are_indexes']:
            def page_link(i, displayed_i, num_pages, force_addition, extension=None):
                feed = "_atom" if extension == ".atom" else ""
                return adjust_name_for_index_link(self.site.link("archive" + feed, name, lang), i, displayed_i,
                                                  lang, self.site, force_addition, extension)

            def page_path(i, displayed_i, num_pages, force_addition, extension=None):
                feed = "_atom" if extension == ".atom" else ""
                return adjust_name_for_index_path(self.site.path("archive" + feed, name, lang), i, displayed_i,
                                                  lang, self.site, force_addition, extension)

            uptodate = []
            if deps_translatable is not None:
                uptodate += [config_changed(deps_translatable, 'nikola.plugins.task.archive')]
            yield self.site.generic_index_renderer(
                lang,
                posts,
                title,
                "archiveindex.tmpl",
                {"archive_name": name,
                 "is_feed_stale": kw["is_feed_stale"]},
                kw,
                str(self.name),
                page_link,
                page_path,
                uptodate)
        else:
            yield self._prepare_task(kw, name, lang, posts, None, "list_post.tmpl", title, deps_translatable)
Example #21
0
    def tag_page_as_list(self, tag, lang, post_list, kw, is_category):
        """Render a single flat link list with this tag's posts."""
        kind = "category" if is_category else "tag"
        template_name = "tag.tmpl"
        output_name = os.path.join(kw['output_folder'], self.site.path(
            kind, tag, lang))
        context = {}
        context["lang"] = lang
        title = self._get_title(tag, is_category)
        if is_category:
            context["category"] = tag
            context["category_path"] = self.site.parse_category_name(tag)
        context["tag"] = title
        context["title"] = self._get_indexes_title(tag, title, is_category, lang, kw["messages"])
        context["posts"] = post_list
        context["permalink"] = self.site.link(kind, tag, lang)
        context["kind"] = kind
        context["description"] = self._get_description(tag, is_category, lang)
        if is_category:
            context["subcategories"] = self._get_subcategories(tag)
        context["pagekind"] = ["list", "tag_page"]
        task = self.site.generic_post_list_renderer(
            lang,
            post_list,
            output_name,
            template_name,
            kw['filters'],
            context,
        )
        task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.tags:list')]
        task['basename'] = str(self.name)
        yield task

        if self.site.config['GENERATE_ATOM']:
            yield self.atom_feed_list(kind, tag, lang, post_list, context, kw)
Example #22
0
 def fragment_deps_uptodate(self, lang):
     """Return a list of file dependencies to build this post's fragment."""
     deps = []
     deps += self._get_dependencies(self._dependency_uptodate_fragment[lang])
     deps += self._get_dependencies(self._dependency_uptodate_fragment[None])
     deps.append(utils.config_changed({1: sorted(self.compiler.config_dependencies)}, 'nikola.post.Post.deps_uptodate:compiler:' + self.source_path))
     return deps
Example #23
0
 def _create_authors_page(self, kw):
     """Create a global "all authors" page for each language."""
     template_name = "authors.tmpl"
     kw = kw.copy()
     for lang in kw["translations"]:
         authors = natsort.natsorted([author for author in self._posts_per_author().keys()],
                                     alg=natsort.ns.F | natsort.ns.IC)
         has_authors = (authors != [])
         kw['authors'] = authors
         output_name = os.path.join(
             kw['output_folder'], self.site.path('author_index', None, lang))
         context = {}
         if has_authors:
             context["title"] = kw["messages"][lang]["Authors"]
             context["items"] = [(author, self.site.link("author", author, lang)) for author
                                 in authors]
             context["description"] = context["title"]
         else:
             context["items"] = None
         context["permalink"] = self.site.link("author_index", None, lang)
         context["pagekind"] = ["list", "authors_page"]
         task = self.site.generic_post_list_renderer(
             lang,
             [],
             output_name,
             template_name,
             kw['filters'],
             context,
         )
         task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:page')]
         task['basename'] = str(self.name)
         yield task
Example #24
0
 def gen_tasks(self):
     """Build final pages from metadata and HTML fragments."""
     kw = {
         "post_pages": self.site.config["post_pages"],
         "translations": self.site.config["TRANSLATIONS"],
         "filters": self.site.config["FILTERS"],
     }
     self.site.scan_posts()
     flag = False
     for lang in kw["translations"]:
         for post in self.site.timeline:
             for task in self.site.generic_page_renderer(lang, post,
                                                         kw["filters"]):
                 task['uptodate'] = [config_changed({
                     1: task['uptodate'][0].config,
                     2: kw})]
                 task['basename'] = self.name
                 flag = True
                 yield task
     if flag is False:  # No page rendered, yield a dummy task
         yield {
             'basename': self.name,
             'name': 'None',
             'uptodate': [True],
             'actions': [],
         }
Example #25
0
    def gen_tasks(self):
        """Copy static files into the output folder."""
        self.kw = {
            'image_thumbnail_size': self.site.config['IMAGE_THUMBNAIL_SIZE'],
            'image_thumbnail_format': self.site.config['IMAGE_THUMBNAIL_FORMAT'],
            'max_image_size': self.site.config['MAX_IMAGE_SIZE'],
            'image_folders': self.site.config['IMAGE_FOLDERS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
            'filters': self.site.config['FILTERS'],
            'preserve_exif_data': self.site.config['PRESERVE_EXIF_DATA'],
            'exif_whitelist': self.site.config['EXIF_WHITELIST'],
            'preserve_icc_profiles': self.site.config['PRESERVE_ICC_PROFILES'],
        }

        self.image_ext_list = self.image_ext_list_builtin
        self.image_ext_list.extend(self.site.config.get('EXTRA_IMAGE_EXTENSIONS', []))

        yield self.group_task()
        for src in self.kw['image_folders']:
            dst = self.kw['output_folder']
            filters = self.kw['filters']
            real_dst = os.path.join(dst, self.kw['image_folders'][src])
            for task in self.process_tree(src, real_dst):
                task['basename'] = self.name
                task['uptodate'] = [utils.config_changed(self.kw)]
                yield utils.apply_filters(task, filters)
Example #26
0
    def gen_tasks(self):
        """Generate redirections tasks."""

        kw = {
            'redirections': self.site.config['REDIRECTIONS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
        }

        if not kw['redirections']:
            # If there are no redirections, still needs to create a
            # dummy action so dependencies don't fail
            yield {
                'basename': self.name,
                'name': 'None',
                'uptodate': [True],
                'actions': [],
            }

        else:
            for src, dst in kw["redirections"]:
                src_path = os.path.join(kw["output_folder"], src)
                yield {
                    'basename': self.name,
                    'name': src_path,
                    'targets': [src_path],
                    'actions': [(create_redirect, (src_path, dst))],
                    'clean': True,
                    'uptodate': [utils.config_changed(kw)],
                }
Example #27
0
 def tag_rss(self, tag, lang, posts, kw, is_category):
     """RSS for a single tag / language"""
     kind = "category" if is_category else "tag"
     # Render RSS
     output_name = os.path.normpath(
         os.path.join(kw['output_folder'],
                      self.site.path(kind + "_rss", tag, lang)))
     feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", tag, lang).lstrip('/'))
     deps = []
     deps_uptodate = []
     post_list = sorted(posts, key=lambda a: a.date)
     post_list.reverse()
     for post in post_list:
         deps += post.deps(lang)
         deps_uptodate += post.deps_uptodate(lang)
     task = {
         'basename': str(self.name),
         'name': output_name,
         'file_dep': deps,
         'targets': [output_name],
         'actions': [(utils.generic_rss_renderer,
                     (lang, "{0} ({1})".format(kw["blog_title"](lang), tag),
                      kw["site_url"], None, post_list,
                      output_name, kw["rss_teasers"], kw["rss_plain"], kw['feed_length'],
                      feed_url))],
         'clean': True,
         'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.tags:rss')] + deps_uptodate,
         'task_dep': ['render_posts'],
     }
     return utils.apply_filters(task, kw['filters'])
Example #28
0
 def author_page_as_list(self, author, lang, post_list, kw):
     """Render a single flat link list with this author's posts."""
     kind = "author"
     template_name = "author.tmpl"
     output_name = os.path.join(kw['output_folder'], self.site.path(
         kind, author, lang))
     context = {}
     context["lang"] = lang
     title = self._get_title(author)
     context["author"] = title
     context["title"] = kw["messages"][lang]["Posts by %s"] % title
     context["posts"] = post_list
     context["permalink"] = self.site.link(kind, author, lang)
     context["kind"] = kind
     context["description"] = self._get_description(author, lang)
     context["pagekind"] = ["list", "author_page"]
     task = self.site.generic_post_list_renderer(
         lang,
         post_list,
         output_name,
         template_name,
         kw['filters'],
         context,
     )
     task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:list')]
     task['basename'] = str(self.name)
     yield task
Example #29
0
 def tag_rss(self, tag, lang, posts, kw):
     """RSS for a single tag / language"""
     #Render RSS
     output_name = os.path.join(kw['output_folder'],
         self.site.path("tag_rss", tag, lang))
     output_name = output_name.encode('utf8')
     deps = []
     post_list = [self.site.global_data[post] for post in posts
         if self.site.global_data[post].use_in_feeds]
     post_list.sort(key=lambda a: a.date)
     post_list.reverse()
     for post in post_list:
         deps += post.deps(lang)
     return {
         'basename': str(self.name),
         'name': output_name,
         'file_dep': deps,
         'targets': [output_name],
         'actions': [(utils.generic_rss_renderer,
             (lang, "%s (%s)" % (kw["blog_title"], tag),
             kw["blog_url"], kw["blog_description"],
             post_list, output_name, kw["rss_teasers"]))],
         'clean': True,
         'uptodate': [utils.config_changed(kw)],
     }
Example #30
0
 def list_tags_page(self, kw):
     """a global "all your tags" page for each language"""
     tags = list(self.site.posts_per_tag.keys())
     tags.sort()
     template_name = "tags.tmpl"
     kw['tags'] = tags
     for lang in kw["translations"]:
         output_name = os.path.join(
             kw['output_folder'], self.site.path('tag_index', None, lang))
         output_name = output_name.encode('utf8')
         context = {}
         context["title"] = kw["messages"][lang]["Tags"]
         context["items"] = [(tag, self.site.link("tag", tag, lang))
             for tag in tags]
         context["permalink"] = self.site.link("tag_index", None, lang)
         task = self.site.generic_post_list_renderer(
             lang,
             [],
             output_name,
             template_name,
             kw['filters'],
             context,
         )
         task_cfg = {1: task['uptodate'][0].config, 2: kw}
         task['uptodate'] = [utils.config_changed(task_cfg)]
         yield task
Example #31
0
    def gen_tasks(self):
        """Copy static files into the output folder."""
        self.kw = {
            'image_thumbnail_size': self.site.config['IMAGE_THUMBNAIL_SIZE'],
            'max_image_size': self.site.config['MAX_IMAGE_SIZE'],
            'image_folders': self.site.config['IMAGE_FOLDERS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
            'filters': self.site.config['FILTERS'],
        }

        self.image_ext_list = self.image_ext_list_builtin
        self.image_ext_list.extend(
            self.site.config.get('EXTRA_IMAGE_EXTENSIONS', []))

        yield self.group_task()
        for src in self.kw['image_folders']:
            dst = self.kw['output_folder']
            filters = self.kw['filters']
            real_dst = os.path.join(dst, self.kw['image_folders'][src])
            for task in self.process_tree(src, real_dst):
                task['basename'] = self.name
                task['uptodate'] = [utils.config_changed(self.kw)]
                yield utils.apply_filters(task, filters)
Example #32
0
 def tag_rss(self, tag, lang, posts, kw, is_category):
     """RSS for a single tag / language"""
     kind = "category" if is_category else "tag"
     #Render RSS
     output_name = os.path.normpath(
         os.path.join(kw['output_folder'],
                      self.site.path(kind + "_rss", tag, lang)))
     feed_url = urljoin(
         self.site.config['BASE_URL'],
         self.site.link(kind + "_rss", tag, lang).lstrip('/'))
     deps = []
     post_list = [
         self.site.global_data[post] for post in posts
         if self.site.global_data[post].use_in_feeds
     ]
     post_list.sort(key=lambda a: a.date)
     post_list.reverse()
     for post in post_list:
         deps += post.deps(lang)
     return {
         'basename':
         str(self.name),
         'name':
         output_name,
         'file_dep':
         deps,
         'targets': [output_name],
         'actions': [(utils.generic_rss_renderer,
                      (lang, "{0} ({1})".format(kw["blog_title"],
                                                tag), kw["site_url"],
                       kw["blog_description"], post_list, output_name,
                       kw["rss_teasers"], kw['feed_length'], feed_url))],
         'clean':
         True,
         'uptodate': [utils.config_changed(kw)],
         'task_dep': ['render_posts'],
     }
Example #33
0
    def gen_tasks(self):
        """Render the tag cloud."""
        self.site.scan_posts()
        yield self.group_task()

        # Tag cloud json file
        tag_cloud_data = {}
        for tag, posts in self.site.posts_per_tag.items():
            if tag in self.site.config['HIDDEN_TAGS']:
                continue
            tag_posts = dict(posts=[{'title': post.meta[post.default_lang]['title'],
                                     'date': post.date.strftime('%m/%d/%Y'),
                                     'isodate': post.date.isoformat(),
                                     'url': post.permalink(post.default_lang)}
                                    for post in reversed(sorted(self.site.timeline, key=lambda post: post.date))
                                    if tag in post.alltags])
            tag_cloud_data[tag] = [len(posts), self.site.link(
                'tag', tag, self.site.config['DEFAULT_LANG']), tag_posts]
        output_name = os.path.join(self.site.config['OUTPUT_FOLDER'],
                                   'assets', 'js', 'tag_cloud_data.json')

        def write_tag_data(data):
            """Write tag data into JSON file, for use in tag clouds."""
            utils.makedirs(os.path.dirname(output_name))
            with open(output_name, 'w+') as fd:
                json.dump(data, fd, sort_keys=True)

        task = {
            'basename': str(self.name),
            'name': str(output_name)
        }

        task['uptodate'] = [utils.config_changed(tag_cloud_data, 'nikola.plugins.task.tags:tagdata')]
        task['targets'] = [output_name]
        task['actions'] = [(write_tag_data, [tag_cloud_data])]
        task['clean'] = True
        yield utils.apply_filters(task, self.site.config['FILTERS'])
 def _render_classification_overview(self, classification_name, template,
                                     lang, context, kw):
     # Prepare rendering
     context["permalink"] = self.site.link(
         "{}_index".format(classification_name), None, lang)
     if "pagekind" not in context:
         context["pagekind"] = ["list", "tags_page"]
     output_name = os.path.join(
         self.site.config['OUTPUT_FOLDER'],
         self.site.path('{}_index'.format(classification_name), None, lang))
     blinker.signal('generate_classification_overview').send({
         'site':
         self.site,
         'classification_name':
         classification_name,
         'lang':
         lang,
         'context':
         context,
         'kw':
         kw,
         'output_name':
         output_name,
     })
     task = self.site.generic_post_list_renderer(
         lang,
         [],
         output_name,
         template,
         kw['filters'],
         context,
     )
     task['uptodate'] = task['uptodate'] + [
         utils.config_changed(kw, 'nikola.plugins.task.taxonomies:page')
     ]
     task['basename'] = str(self.name)
     yield task
Example #35
0
    def gen_tasks(self):
        """Generate CSS out of Sass sources."""
        self.compiler_name = self.site.config['SASS_COMPILER']
        self.output_folder = self.site.config['OUTPUT_FOLDER']
        self.theme = self.site.config['THEME']

        # Build targets and write CSS files
        destination_path = os.path.join(self.output_folder, 'assets', 'css',
                                        self.theme + '.css')
        sass_path = os.path.join('themes', self.theme, 'sass')
        target_path = os.path.join(sass_path, 'index.scss')
        sass_dir_size = ''

        def compile_sass(target_path, destination_path):
            try:
                compiled = sass.compile(filename=target_path)
            except OSError:
                utils.req_missing([self.compiler_name],
                                  'build Sass files (and use this theme)',
                                  False, False)

            with open(destination_path, "w+") as outfile:
                outfile.write(compiled)

        if os.path.isfile(target_path):
            sass_dir_size = sum(f.stat().st_size
                                for f in Path(sass_path).glob('**/*')
                                if f.is_file())

            yield {
                'basename': self.name,
                'name': destination_path,
                'targets': [destination_path],
                'actions': ((compile_sass, [target_path, destination_path]), ),
                'uptodate': [utils.config_changed(str(sass_dir_size))],
                'clean': True
            }
Example #36
0
    def generate_feed_task(self,
                           lang,
                           title,
                           link,
                           description,
                           timeline,
                           feed_url,
                           output_name,
                           primary_author=None):
        """Generate a task to create a feed."""
        # Build dependency list
        deps = []
        deps_uptodate = []
        for post in timeline:
            deps += post.deps(lang)
            deps_uptodate += post.deps_uptodate(lang)

        task = {
            'basename':
            str(self.name),
            'name':
            str(output_name),
            'targets': [output_name],
            'file_dep':
            deps,
            'task_dep': ['render_posts', 'render_taxonomies'],
            'actions':
            [(self.generate_feed, (lang, title, link, description, timeline,
                                   feed_url, output_name, primary_author))],
            'uptodate':
            [utils.config_changed(self.kw, 'jsonfeed:' + output_name)] +
            deps_uptodate,
            'clean':
            True
        }

        yield utils.apply_filters(task, self.site.config['FILTERS'])
Example #37
0
    def gen_tasks(self):
        self.site.scan_posts()
        kw = {
            "translations": self.site.config["TRANSLATIONS"],
            "timeline": self.site.timeline,
            "default_lang": self.site.config["DEFAULT_LANG"],
            "show_untranslated_posts":
            self.site.config["SHOW_UNTRANSLATED_POSTS"],
            "demote_headers": self.site.config["DEMOTE_HEADERS"],
        }
        self.tl_changed = False
        yield self.group_task()

        def tl_ch():
            self.tl_changed = True

        yield {
            "basename": self.name,
            "name": "timeline_changes",
            "actions": [tl_ch],
            "uptodate": [utils.config_changed({1: kw["timeline"]})],
        }
        for lang in kw["translations"]:
            deps_dict = copy(kw)
            deps_dict.pop("timeline")
            for post in kw["timeline"]:
                if not should_generate_pdf(self.site, post, lang):
                    self.logger.info("not generating pdf for " + post.title())
                    continue

                yield utils.apply_filters(
                    self.get_task(deps_dict, post, lang),
                    {
                        os.path.splitext(get_pdf_dest(self.site, post, lang))[-1]:
                        self.get_metadata_filters(post, lang)
                    },
                )
Example #38
0
    def gen_tasks(self):
        """Build final pages from metadata and HTML fragments."""
        kw = {
            "post_pages": self.site.config["post_pages"],
            "translations": self.site.config["TRANSLATIONS"],
            "filters": self.site.config["FILTERS"],
            "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
            "demote_headers": self.site.config['DEMOTE_HEADERS'],
        }
        self.site.scan_posts()
        yield self.group_task()
        index_paths = {}
        for lang in kw["translations"]:
            index_paths[lang] = False
            if not self.site.config["DISABLE_INDEXES"]:
                index_paths[lang] = os.path.normpath(os.path.join(self.site.config['OUTPUT_FOLDER'],
                                                     self.site.path('index', '', lang=lang)))

        for lang in kw["translations"]:
            for post in self.site.timeline:
                if not kw["show_untranslated_posts"] and not post.is_translation_available(lang):
                    continue
                if post.is_post:
                    context = {'pagekind': ['post_page']}
                else:
                    context = {'pagekind': ['story_page', 'page_page']}
                for task in self.site.generic_page_renderer(lang, post, kw["filters"], context):
                    if task['name'] == index_paths[lang]:
                        # Issue 3022
                        LOGGER.error(
                            "Post {0!r}: output path ({1}) conflicts with the blog index ({2}). "
                            "Please change INDEX_PATH or disable index generation.".format(
                                post.source_path, task['name'], index_paths[lang]))
                    task['uptodate'] = task['uptodate'] + [config_changed(kw, 'nikola.plugins.task.pages')]
                    task['basename'] = self.name
                    task['task_dep'] = ['render_posts']
                    yield task
Example #39
0
 def _create_authors_page(self, kw):
     """Create a global "all authors" page for each language."""
     template_name = "authors.tmpl"
     kw = kw.copy()
     for lang in kw["translations"]:
         authors = natsort.natsorted(
             [author for author in self._posts_per_author().keys()],
             alg=natsort.ns.F | natsort.ns.IC)
         has_authors = (authors != [])
         kw['authors'] = authors
         output_name = os.path.join(
             kw['output_folder'], self.site.path('author_index', None,
                                                 lang))
         context = {}
         if has_authors:
             context["title"] = kw["messages"][lang]["Authors"]
             context["items"] = [(author,
                                  self.site.link("author", author, lang))
                                 for author in authors]
             context["description"] = context["title"]
         else:
             context["items"] = None
         context["permalink"] = self.site.link("author_index", None, lang)
         context["pagekind"] = ["list", "authors_page"]
         task = self.site.generic_post_list_renderer(
             lang,
             [],
             output_name,
             template_name,
             kw['filters'],
             context,
         )
         task['uptodate'] = task['uptodate'] + [
             utils.config_changed(kw, 'nikola.plugins.task.authors:page')
         ]
         task['basename'] = str(self.name)
         yield task
Example #40
0
    def gen_tasks(self):
        """Create tasks to copy the assets of the whole theme chain.

        If a file is present on two themes, use the version
        from the "youngest" theme.
        """

        kw = {
            "themes": self.site.THEMES,
            "output_folder": self.site.config['OUTPUT_FOLDER'],
            "filters": self.site.config['FILTERS'],
        }

        tasks = {}
        for theme_name in kw['themes']:
            src = os.path.join(utils.get_theme_path(theme_name), 'assets')
            dst = os.path.join(kw['output_folder'], 'assets')
            for task in utils.copy_tree(src, dst):
                if task['name'] in tasks:
                    continue
                tasks[task['name']] = task
                task['uptodate'] = [utils.config_changed(kw)]
                task['basename'] = self.name
                yield utils.apply_filters(task, kw['filters'])
Example #41
0
    def gen_tasks(self):
        urls = [post.permalink() for post in self.site.posts]
        kw = {
            'files_folders': self.site.config['FILES_FOLDERS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
        }

        output_filename = os.path.join(
            kw['output_folder'],
            'assets/js/posts.json',
        )
        output_index = os.path.join(kw['output_folder'], 'random/index.html')

        # Yield a task for Doit
        yield {
            'basename':
            'random_post',
            'targets': (output_filename, output_index),
            'actions': [
                (create_json, (output_filename, urls)),
                (create_index, (output_index, )),
            ],
            'uptodate': [utils.config_changed(kw)],
        }
Example #42
0
    def gen_tasks(self):
        """Copy static files into the output folder."""

        kw = {
            'files_folders': self.site.config['FILES_FOLDERS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
            'filters': self.site.config['FILTERS'],
        }

        flag = False
        for src in kw['files_folders']:
            dst = kw['output_folder']
            filters = kw['filters']
            real_dst = os.path.join(dst, kw['files_folders'][src])
            for task in utils.copy_tree(src, real_dst, link_cutoff=dst):
                flag = True
                task['basename'] = self.name
                task['uptodate'] = [utils.config_changed(kw)]
                yield utils.apply_filters(task, filters)
        if not flag:
            yield {
                'basename': self.name,
                'actions': (),
            }
Example #43
0
 def create_galleries(self):
     """Given a list of galleries, create the output folders."""
     # gallery_path is "gallery/foo/name"
     for gallery_path, input_folder, _ in self.gallery_list:
         # have to use dirname because site.path returns .../index.html
         output_gallery = os.path.dirname(
             os.path.join(self.kw["output_folder"],
                          self.site.path("gallery", gallery_path)))
         output_gallery = os.path.normpath(output_gallery)
         # Task to create gallery in output/
         yield {
             'basename':
             self.name,
             'name':
             output_gallery,
             'actions': [(utils.makedirs, (output_gallery, ))],
             'targets': [output_gallery],
             'clean':
             True,
             'uptodate': [
                 utils.config_changed(
                     self.kw.copy(), 'nikola.plugins.task.galleries:mkdir')
             ],
         }
Example #44
0
 def gen_tasks(self):
     """Build final pages from metadata and HTML fragments."""
     kw = {
         "post_pages": self.site.config["post_pages"],
         "translations": self.site.config["TRANSLATIONS"],
         "filters": self.site.config["FILTERS"],
         "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
         "demote_headers": self.site.config['DEMOTE_HEADERS'],
     }
     self.site.scan_posts()
     yield self.group_task()
     for lang in kw["translations"]:
         for post in self.site.timeline:
             if not kw["show_untranslated_posts"] and not post.is_translation_available(lang):
                 continue
             if post.is_post:
                 context = {'pagekind': ['post_page']}
             else:
                 context = {'pagekind': ['story_page']}
             for task in self.site.generic_page_renderer(lang, post, kw["filters"], context):
                 task['uptodate'] = task['uptodate'] + [config_changed(kw, 'nikola.plugins.task.pages')]
                 task['basename'] = self.name
                 task['task_dep'] = ['render_posts']
                 yield task
Example #45
0
    def gen_tasks(self):

        self.logger = utils.get_logger('speechsynthesizednetcast',
                                       self.site.loghandlers)

        # Deps and config
        kw = {
            "translations": self.site.config['TRANSLATIONS'],
            "blog_title": self.site.config['BLOG_TITLE'],
            "blog_description": self.site.config['BLOG_DESCRIPTION'],
            "site_url": self.site.config['SITE_URL'],
            "output_folder": self.site.config['OUTPUT_FOLDER'],
            "cache_folder": self.site.config['CACHE_FOLDER'],
            "feed_length": self.site.config['FEED_LENGTH'],
            "default_lang": self.site.config['DEFAULT_LANG'],
            "audio_formats": self.default_audio_formats,
            "intro_text": self.default_text_intro,
            "outro_text": self.default_text_outro,
        }

        # Default configuration values
        if 'NETCAST_AUDIO_FORMATS' in self.site.config:
            kw['audio_formats'] = self.site.config['NETCAST_AUDIO_FORMATS']
        if 'NETCAST_INTRO' in self.site.config:
            kw['intro_text'] = self.site.config['NETCAST_INTRO']
        if 'NETCAST_OUTRO' in self.site.config:
            kw['outro_text'] = self.site.config['NETCAST_OUTRO']

        self.test_required_programs([kw['audio_formats']])

        self.site.scan_posts()
        yield self.group_task()

        for lang in kw['translations']:
            feed_deps = []
            posts = [
                x for x in self.site.posts if x.is_translation_available(lang)
            ][:10]
            for post in posts:
                post_recording_path = self.netcast_audio_path(lang=lang,
                                                              post=post,
                                                              format='flac',
                                                              is_cache=True)
                yield {
                    'name':
                    str(post_recording_path),
                    'basename':
                    str(self.name),
                    'targets': [post_recording_path],
                    'file_dep':
                    post.fragment_deps(lang),
                    'uptodate': [utils.config_changed(kw)],
                    'clean':
                    True,
                    'actions':
                    [(self.record_post, [post_recording_path, post, lang])]
                }

                for format in kw['audio_formats']:
                    output_name = self.netcast_audio_path(lang=lang,
                                                          post=post,
                                                          format=format)
                    yield {
                        'name':
                        str(output_name),
                        'basename':
                        str(self.name),
                        'targets': [output_name],
                        'file_dep':
                        [post_recording_path,
                         post.fragment_deps(lang)[0]],
                        'clean':
                        True,
                        'actions': [(self.encode_post, [
                            output_name, post_recording_path, post, lang,
                            format
                        ])]
                    }
                    feed_deps.append(output_name)

            for format in kw['audio_formats']:
                output_name = self.netcast_feed_path(lang=lang, format=format)
                yield {
                    'name':
                    str(output_name),
                    'basename':
                    str(self.name),
                    'targets': [output_name],
                    'file_dep':
                    feed_deps,  # depends on all formats
                    'clean':
                    True,
                    'actions': [(self.netcast_feed_renderer,
                                 [lang, posts, output_name, format])]
                }
Example #46
0
    def gen_tasks(self):
        self.site.scan_posts()

        kw = {
            "translations":
            self.site.config['TRANSLATIONS'],
            "index_display_post_count":
            self.site.config['INDEX_DISPLAY_POST_COUNT'],
            "messages":
            self.site.MESSAGES,
            "index_teasers":
            self.site.config['INDEX_TEASERS'],
            "output_folder":
            self.site.config['OUTPUT_FOLDER'],
            "filters":
            self.site.config['FILTERS'],
            "blog_title":
            self.site.config['BLOG_TITLE'],
            "content_footer":
            self.site.config['CONTENT_FOOTER'],
        }

        # TODO: timeline is global, get rid of it
        posts = [x for x in self.site.timeline if x.use_in_feeds]
        if not posts:
            yield {
                'basename': 'render_mustache',
                'actions': [],
            }
            return

        def write_file(path, post, lang):

            # Prev/Next links
            prev_link = False
            if post.prev_post:
                prev_link = post.prev_post.permalink(lang).replace(
                    ".html", ".json")
            next_link = False
            if post.next_post:
                next_link = post.next_post.permalink(lang).replace(
                    ".html", ".json")
            data = {}

            # Configuration
            for k, v in self.site.config.items():
                if isinstance(v, (str, unicode_str)):  # NOQA
                    data[k] = v

            # Tag data
            tags = []
            for tag in post.tags:
                tags.append({
                    'name': tag,
                    'link': self.site.link("tag", tag, lang)
                })
            data.update({
                "tags": tags,
                "tags?": True if tags else False,
            })

            # Template strings
            for k, v in kw["messages"][lang].items():
                data["message_" + k] = v

            # Post data
            data.update({
                "title":
                post.title(lang),
                "text":
                post.text(lang),
                "prev":
                prev_link,
                "next":
                next_link,
                "date":
                post.date.strftime(self.site.GLOBAL_CONTEXT['date_format']),
            })

            # Comments
            context = dict(post=post, lang=LocaleBorg().current_lang)
            context.update(self.site.GLOBAL_CONTEXT)
            data["comment_html"] = self.site.template_system.render_template(
                'mustache-comment-form.tmpl', None, context).strip()

            # Post translations
            translations = []
            for langname in kw["translations"]:
                if langname == lang:
                    continue
                translations.append({
                    'name':
                    kw["messages"][langname]["Read in English"],
                    'link':
                    "javascript:load_data('%s');" %
                    post.permalink(langname).replace(".html", ".json")
                })
            data["translations"] = translations

            makedirs(os.path.dirname(path))
            with codecs.open(path, 'wb+', 'utf8') as fd:
                fd.write(json.dumps(data))

        for lang in kw["translations"]:
            for i, post in enumerate(posts):
                out_path = post.destination_path(lang, ".json")
                out_file = os.path.join(kw['output_folder'], out_path)
                task = {
                    'basename':
                    'render_mustache',
                    'name':
                    out_file,
                    'file_dep':
                    post.fragment_deps(lang),
                    'targets': [out_file],
                    'actions': [(write_file, (out_file, post, lang))],
                    'task_dep': ['render_posts'],
                    'uptodate': [
                        config_changed({
                            1: post.text(lang),
                            2: post.prev_post,
                            3: post.next_post,
                            4: post.title(lang),
                        })
                    ]
                }
                yield task

        if posts:
            first_post_data = posts[0].permalink(
                self.site.config["DEFAULT_LANG"]).replace(".html", ".json")

        # Copy mustache template
        src = os.path.join(os.path.dirname(__file__), 'mustache-template.html')
        dst = os.path.join(kw['output_folder'], 'mustache-template.html')
        yield {
            'basename': 'render_mustache',
            'name': dst,
            'targets': [dst],
            'file_dep': [src],
            'actions': [(copy_file, (src, dst))],
        }

        # Copy mustache.html with the right starting file in it
        src = os.path.join(os.path.dirname(__file__), 'mustache.html')
        dst = os.path.join(kw['output_folder'], 'mustache.html')

        def copy_mustache():
            with codecs.open(src, 'rb', 'utf8') as in_file:
                with codecs.open(dst, 'wb+', 'utf8') as out_file:
                    data = in_file.read().replace('{{first_post_data}}',
                                                  first_post_data)
                    out_file.write(data)

        yield {
            'basename': 'render_mustache',
            'name': dst,
            'targets': [dst],
            'file_dep': [src],
            'uptodate': [config_changed({1: first_post_data})],
            'actions': [(copy_mustache, [])],
        }
Example #47
0
    def gen_tasks(self):
        """Build similarity data for each post."""
        self.site.scan_posts()
        timeline = [
            p for p in self.site.timeline if not (p.is_draft or p.is_private)
        ]

        kw = {
            "translations": self.site.translations,
            "output_folder": self.site.config["OUTPUT_FOLDER"],
            "similar_count": self.site.config.get('SIMILAR_COUNT', 10)
        }

        stopwords = {}
        for l in self.site.translations:
            stopwords[l] = get_stop_words(l)

        def split_text(text, lang="en"):
            words = text.lower().split()
            return [w for w in words if w not in stopwords[lang]]

        yield self.group_task()

        def tags_similarity(p1, p2):
            t1 = set(p1.tags)
            t2 = set(p2.tags)
            if not (t1 and t2):
                return 0
            # Totally making this up
            return 2.0 * len(t1.intersection(t2)) / (len(t1) + len(t2))

        def title_similarity(p1, p2):
            t1 = set(split_text(p1.title()))
            t2 = set(split_text(p2.title()))
            if not (t1 and t2):
                return 0
            # Totally making this up
            return 2.0 * len(t1.intersection(t2)) / (len(t1) + len(t2))

        indexes = {}
        dictionaries = {}
        lsis = {}

        def create_idx(indexes, dictionaries, lsis, lang):
            texts = []
            for p in timeline:
                texts.append(
                    split_text(p.text(strip_html=True, lang=lang), lang=lang))
            dictionary = gensim.corpora.Dictionary(texts)
            corpus = [dictionary.doc2bow(text) for text in texts]
            lsi = gensim.models.LsiModel(corpus,
                                         id2word=dictionary,
                                         num_topics=2)
            indexes[lang] = gensim.similarities.MatrixSimilarity(lsi[corpus])
            dictionaries[lang] = dictionary
            lsis[lang] = lsi

        def write_similar(path,
                          post,
                          lang,
                          indexes=indexes,
                          dictionaries=dictionaries,
                          lsis=lsis):
            if lang not in dictionaries:
                create_idx(indexes, dictionaries, lsis, lang)
            doc = split_text(post.text(lang), lang)
            vec_bow = dictionaries[lang].doc2bow(doc)
            vec_lsi = lsis[lang][vec_bow]
            body_sims = indexes[lang][vec_lsi]

            tag_sims = [tags_similarity(post, p) for p in timeline]
            title_sims = [title_similarity(post, p) for p in timeline]
            full_sims = [
                tag_sims[i] + title_sims[i] + body_sims[i] * 1.5
                for i in range(len(timeline))
            ]
            full_sims = sorted(enumerate(full_sims), key=lambda item: -item[1])
            idx = timeline.index(post)
            related = [(timeline[s[0]], s[1], tag_sims[s[0]], title_sims[s[0]],
                        body_sims[s[0]])
                       for s in full_sims[:kw['similar_count'] + 1]
                       if s[0] != idx]
            data = []
            for p, score, tag, title, body in related:
                data.append({
                    'url': '/' + p.destination_path(sep='/'),
                    'title': p.title(),
                    'score': score,
                    'detailed_score': [tag, title, float(body)],
                })
            with open(path, 'w+') as outf:
                json.dump(data, outf)

        for lang in self.site.translations:
            file_dep = [p.translated_source_path(lang) for p in timeline]
            uptodate = utils.config_changed({1: kw}, 'similarity')
            for i, post in enumerate(timeline):
                out_name = os.path.join(
                    kw['output_folder'],
                    post.destination_path(lang=lang)) + '.related.json'
                task = {
                    'basename': self.name,
                    'name': out_name,
                    'targets': [out_name],
                    'actions': [(write_similar, (out_name, post, lang))],
                    'file_dep': file_dep,
                    'uptodate': [uptodate],
                    'clean': True,
                }
                yield task
Example #48
0
    def gen_tasks(self):
        """Generate RSS feeds."""
        kw = {
            "translations": self.site.config["TRANSLATIONS"],
            "filters": self.site.config["FILTERS"],
            "blog_title": self.site.config["BLOG_TITLE"],
            "site_url": self.site.config["SITE_URL"],
            "base_url": self.site.config["BASE_URL"],
            "blog_description": self.site.config["BLOG_DESCRIPTION"],
            "output_folder": self.site.config["OUTPUT_FOLDER"],
            "feed_teasers": self.site.config["FEED_TEASERS"],
            "feed_plain": self.site.config["FEED_PLAIN"],
            "show_untranslated_posts":
            self.site.config['SHOW_UNTRANSLATED_POSTS'],
            "feed_length": self.site.config['FEED_LENGTH'],
            "feed_previewimage": self.site.config["FEED_PREVIEWIMAGE"],
            "tzinfo": self.site.tzinfo,
            "feed_read_more_link": self.site.config["FEED_READ_MORE_LINK"],
            "feed_links_append_query":
            self.site.config["FEED_LINKS_APPEND_QUERY"],
        }
        self.site.scan_posts()
        # Check for any changes in the state of use_in_feeds for any post.
        # Issue #934
        kw['use_in_feeds_status'] = ''.join(
            ['T' if x.use_in_feeds else 'F' for x in self.site.timeline])
        yield self.group_task()
        for lang in kw["translations"]:
            output_name = os.path.join(kw['output_folder'],
                                       self.site.path("rss", None, lang))
            deps = []
            deps_uptodate = []
            if kw["show_untranslated_posts"]:
                posts = self.site.posts[:kw['feed_length']]
            else:
                posts = [
                    x for x in self.site.posts
                    if x.is_translation_available(lang)
                ][:kw['feed_length']]
            for post in posts:
                deps += post.deps(lang)
                deps_uptodate += post.deps_uptodate(lang)

            feed_url = urljoin(self.site.config['BASE_URL'],
                               self.site.link("rss", None, lang).lstrip('/'))

            task = {
                'basename':
                'generate_rss',
                'name':
                os.path.normpath(output_name),
                'file_dep':
                deps,
                'targets': [output_name],
                'actions':
                [(utils.generic_rss_renderer,
                  (lang, kw["blog_title"](lang), kw["site_url"],
                   kw["blog_description"](lang), posts, output_name,
                   kw["feed_teasers"], kw["feed_plain"], kw['feed_length'],
                   feed_url, _enclosure, kw["feed_links_append_query"]))],
                'task_dep': ['render_posts'],
                'clean':
                True,
                'uptodate':
                [utils.config_changed(kw, 'nikola.plugins.task.rss')] +
                deps_uptodate,
            }
            yield utils.apply_filters(task, kw['filters'])
Example #49
0
    def gen_tasks(self):
        """Build HTML fragments from metadata and text."""
        self.site.scan_posts()
        kw = {
            "translations": self.site.config["TRANSLATIONS"],
            "timeline": self.site.timeline,
            "default_lang": self.site.config["DEFAULT_LANG"],
            "show_untranslated_posts":
            self.site.config['SHOW_UNTRANSLATED_POSTS'],
            "demote_headers": self.site.config['DEMOTE_HEADERS'],
        }
        self.tl_changed = False

        yield self.group_task()

        def tl_ch():
            self.tl_changed = True

        yield {
            'basename': self.name,
            'name': 'timeline_changes',
            'actions': [tl_ch],
            'uptodate': [utils.config_changed({1: kw['timeline']})],
        }

        for lang in kw["translations"]:
            deps_dict = copy(kw)
            deps_dict.pop('timeline')
            for post in kw['timeline']:
                if not post.is_translation_available(
                        lang
                ) and not self.site.config['SHOW_UNTRANSLATED_POSTS']:
                    continue
                # Extra config dependencies picked from config
                for p in post.fragment_deps(lang):
                    if p.startswith('####MAGIC####CONFIG:'):
                        k = p.split('####MAGIC####CONFIG:', 1)[-1]
                        deps_dict[k] = self.site.config.get(k)
                dest = post.translated_base_path(lang)
                file_dep = [
                    p for p in post.fragment_deps(lang)
                    if not p.startswith("####MAGIC####")
                ]
                extra_targets = post.compiler.get_extra_targets(
                    post, lang, dest)
                task = {
                    'basename':
                    self.name,
                    'name':
                    dest,
                    'file_dep':
                    file_dep,
                    'targets': [dest] + extra_targets,
                    'actions': [
                        (post.compile, (lang, )),
                        (update_deps, (
                            post,
                            lang,
                        )),
                    ],
                    'clean':
                    True,
                    'uptodate': [
                        utils.config_changed(
                            deps_dict, 'nikola.plugins.task.posts'), lambda p=
                        post, l=lang: self.dependence_on_timeline(p, l)
                    ] + post.fragment_deps_uptodate(lang),
                    'task_dep': ['render_posts:timeline_changes']
                }

                # Apply filters specified in the metadata
                ff = [x.strip() for x in post.meta('filters', lang).split(',')]
                flist = []
                for i, f in enumerate(ff):
                    if not f:
                        continue
                    _f = self.site.filters.get(f)
                    if _f is not None:  # A registered filter
                        flist.append(_f)
                    else:
                        flist.append(f)
                yield utils.apply_filters(task,
                                          {os.path.splitext(dest)[-1]: flist})
Example #50
0
    def gen_tasks(self):
        """Render the tag pages and feeds."""

        kw = {
            "translations":
            self.site.config["TRANSLATIONS"],
            "blog_title":
            self.site.config["BLOG_TITLE"],
            "site_url":
            self.site.config["SITE_URL"],
            "base_url":
            self.site.config["BASE_URL"],
            "messages":
            self.site.MESSAGES,
            "output_folder":
            self.site.config['OUTPUT_FOLDER'],
            "filters":
            self.site.config['FILTERS'],
            'tag_path':
            self.site.config['TAG_PATH'],
            "tag_pages_are_indexes":
            self.site.config['TAG_PAGES_ARE_INDEXES'],
            "tag_pages_descriptions":
            self.site.config['TAG_PAGES_DESCRIPTIONS'],
            'category_path':
            self.site.config['CATEGORY_PATH'],
            'category_prefix':
            self.site.config['CATEGORY_PREFIX'],
            "category_pages_are_indexes":
            self.site.config['CATEGORY_PAGES_ARE_INDEXES'],
            "category_pages_descriptions":
            self.site.config['CATEGORY_PAGES_DESCRIPTIONS'],
            "generate_rss":
            self.site.config['GENERATE_RSS'],
            "rss_teasers":
            self.site.config["RSS_TEASERS"],
            "rss_plain":
            self.site.config["RSS_PLAIN"],
            "show_untranslated_posts":
            self.site.config['SHOW_UNTRANSLATED_POSTS'],
            "feed_length":
            self.site.config['FEED_LENGTH'],
            "taglist_minimum_post_count":
            self.site.config['TAGLIST_MINIMUM_POSTS'],
            "tzinfo":
            self.site.tzinfo,
            "pretty_urls":
            self.site.config['PRETTY_URLS'],
            "strip_indexes":
            self.site.config['STRIP_INDEXES'],
            "index_file":
            self.site.config['INDEX_FILE'],
        }

        self.site.scan_posts()
        yield self.group_task()

        yield self.list_tags_page(kw)

        if not self.site.posts_per_tag and not self.site.posts_per_category:
            return

        if kw['category_path'] == kw['tag_path']:
            tags = {
                self.slugify_name(tag): tag
                for tag in self.site.posts_per_tag.keys()
            }
            categories = {
                kw['category_prefix'] + self.slugify_name(category): category
                for category in self.site.posts_per_category.keys()
            }
            intersect = set(tags.keys()) & set(categories.keys())
            if len(intersect) > 0:
                for slug in intersect:
                    utils.LOGGER.error(
                        "Category '{0}' and tag '{1}' both have the same slug '{2}'!"
                        .format(categories[slug], tags[slug], slug))
                sys.exit(1)

        tag_list = list(self.site.posts_per_tag.items())
        cat_list = list(self.site.posts_per_category.items())

        def render_lists(tag, posts, is_category=True):
            post_list = sorted(posts, key=lambda a: a.date)
            post_list.reverse()
            for lang in kw["translations"]:
                if kw["show_untranslated_posts"]:
                    filtered_posts = post_list
                else:
                    filtered_posts = [
                        x for x in post_list
                        if x.is_translation_available(lang)
                    ]
                if kw["generate_rss"]:
                    yield self.tag_rss(tag, lang, filtered_posts, kw,
                                       is_category)
                # Render HTML
                if kw['category_pages_are_indexes'] if is_category else kw[
                        'tag_pages_are_indexes']:
                    yield self.tag_page_as_index(tag, lang, filtered_posts, kw,
                                                 is_category)
                else:
                    yield self.tag_page_as_list(tag, lang, filtered_posts, kw,
                                                is_category)

        for tag, posts in tag_list:
            for task in render_lists(tag, posts, False):
                yield task

        for tag, posts in cat_list:
            if tag == '':  # This is uncategorized posts
                continue
            for task in render_lists(tag, posts, True):
                yield task

        # Tag cloud json file
        tag_cloud_data = {}
        for tag, posts in self.site.posts_per_tag.items():
            tag_posts = dict(
                posts=[{
                    'title': post.meta[post.default_lang]['title'],
                    'date': post.date.strftime('%m/%d/%Y'),
                    'isodate': post.date.isoformat(),
                    'url': post.permalink(post.default_lang)
                } for post in reversed(
                    sorted(self.site.timeline, key=lambda post: post.date))
                       if tag in post.alltags])
            tag_cloud_data[tag] = [
                len(posts),
                self.site.link('tag', tag, self.site.config['DEFAULT_LANG']),
                tag_posts
            ]
        output_name = os.path.join(kw['output_folder'], 'assets', 'js',
                                   'tag_cloud_data.json')

        def write_tag_data(data):
            utils.makedirs(os.path.dirname(output_name))
            with open(output_name, 'w+') as fd:
                json.dump(data, fd)

        if self.site.config['WRITE_TAG_CLOUD']:
            task = {'basename': str(self.name), 'name': str(output_name)}

            task['uptodate'] = [
                utils.config_changed(tag_cloud_data,
                                     'nikola.plugins.task.tags:tagdata')
            ]
            task['targets'] = [output_name]
            task['actions'] = [(write_tag_data, [tag_cloud_data])]
            task['clean'] = True
            yield utils.apply_filters(task, kw['filters'])
Example #51
0
 def _create_tags_page(self,
                       kw,
                       include_tags=True,
                       include_categories=True):
     """a global "all your tags/categories" page for each language"""
     tags = list([
         tag for tag in self.site.posts_per_tag.keys()
         if len(self.site.posts_per_tag[tag]) >=
         kw["taglist_minimum_post_count"]
     ])
     categories = list(self.site.posts_per_category.keys())
     # We want our tags to be sorted case insensitive
     tags.sort(key=lambda a: a.lower())
     categories.sort(key=lambda a: a.lower())
     has_tags = (tags != ['']) and include_tags
     has_categories = (categories != ['']) and include_categories
     template_name = "tags.tmpl"
     kw = kw.copy()
     if include_tags:
         kw['tags'] = tags
     if include_categories:
         kw['categories'] = categories
     for lang in kw["translations"]:
         output_name = os.path.join(
             kw['output_folder'],
             self.site.path('tag_index' if has_tags else 'category_index',
                            None, lang))
         output_name = output_name
         context = {}
         if has_categories and has_tags:
             context["title"] = kw["messages"][lang]["Tags and Categories"]
         elif has_categories:
             context["title"] = kw["messages"][lang]["Categories"]
         else:
             context["title"] = kw["messages"][lang]["Tags"]
         if has_tags:
             context["items"] = [(tag, self.site.link("tag", tag, lang))
                                 for tag in tags]
         else:
             context["items"] = None
         if has_categories:
             context["cat_items"] = [(tag,
                                      self.site.link("category", tag, lang))
                                     for tag in categories]
         else:
             context["cat_items"] = None
         context["permalink"] = self.site.link(
             "tag_index" if has_tags else "category_index", None, lang)
         context["description"] = context["title"]
         task = self.site.generic_post_list_renderer(
             lang,
             [],
             output_name,
             template_name,
             kw['filters'],
             context,
         )
         task['uptodate'] = task['uptodate'] + [
             utils.config_changed(kw, 'nikola.plugins.task.tags:page')
         ]
         task['basename'] = str(self.name)
         yield task
Example #52
0
    def gen_tasks(self):
        """Generate Windows Live Tiles and notifications."""
        kw = {
            "default_lang": self.site.config["DEFAULT_LANG"],
            "site_url": self.site.config["BASE_URL"],
            "output_folder": self.site.config["OUTPUT_FOLDER"],
            "show_untranslated_posts":
            self.site.config["SHOW_UNTRANSLATED_POSTS"],
            "windows_live_tiles": self.site.config["WINDOWS_LIVE_TILES"],
        }

        msapplication_assets = os.path.join(kw["output_folder"], "assets",
                                            "msapplication")
        if not os.path.exists(msapplication_assets):
            os.makedirs(msapplication_assets)

        self.site.scan_posts()
        yield self.group_task()

        deps = []
        if kw["show_untranslated_posts"]:
            posts = self.site.posts[:5]
        else:
            posts = [
                x for x in self.site.posts
                if x.is_translation_available(kw["default_lang"])
            ][:5]
        for post in posts:
            deps += post.deps(kw["default_lang"])

        for i, post in zip(range(len(posts)), posts):
            notification_deps = post.deps(kw["default_lang"])
            output_name = os.path.join(
                msapplication_assets,
                "tile_notification" + str(i + 1) + ".xml")
            titles = {
                "maintitle": post.title(kw["default_lang"]),
                "title1": posts[0].title(kw["default_lang"]),
                "title2": posts[1].title(kw["default_lang"]),
                "title3": posts[2].title(kw["default_lang"])
            }

            yield {
                "basename":
                "windows_live_tiles",
                "name":
                os.path.normpath(output_name),
                "file_dep":
                notification_deps,
                "targets": [output_name],
                "actions": [(self.generate_notification_tile,
                             (output_name, kw["default_lang"],
                              kw["windows_live_tiles"]["tileimages"], titles,
                              post.meta[kw["default_lang"]]["previewimage"]))],
                "task_dep": ["render_posts"],
                "clean":
                True,
                "uptodate": [utils.config_changed(kw)],
            }

        browserconfig_output_name = os.path.join(kw["output_folder"],
                                                 "browserconfig.xml")
        yield {
            "basename":
            "windows_live_tiles",
            "name":
            os.path.normpath(browserconfig_output_name),
            "file_dep":
            deps,
            "targets": [browserconfig_output_name],
            "actions": [(self.generate_browserconfig,
                         (browserconfig_output_name, kw["windows_live_tiles"],
                          len(posts)))],
            "task_dep": ["render_posts"],
            "clean":
            True,
            "uptodate": [utils.config_changed(kw)],
        }
Example #53
0
    def gen_tasks(self):
        """Bundle assets."""
        kw = {
            'filters': self.site.config['FILTERS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
            'cache_folder': self.site.config['CACHE_FOLDER'],
            'theme_bundles': get_theme_bundles(self.site.THEMES),
            'themes': self.site.THEMES,
            'files_folders': self.site.config['FILES_FOLDERS'],
            'code_color_scheme': self.site.config['CODE_COLOR_SCHEME'],
        }

        def build_bundle(output, inputs):
            out_dir = os.path.join(kw['output_folder'],
                                   os.path.dirname(output))
            inputs = [
                os.path.join(out_dir, os.path.relpath(i, out_dir))
                for i in inputs if os.path.isfile(i)
            ]
            with open(os.path.join(out_dir, os.path.basename(output)),
                      'wb+') as out_fh:
                for i in inputs:
                    with open(i, 'rb') as in_fh:
                        shutil.copyfileobj(in_fh, out_fh)
                    out_fh.write(b'\n')

        yield self.group_task()

        if self.site.config['USE_BUNDLES']:
            for name, _files in kw['theme_bundles'].items():
                output_path = os.path.join(kw['output_folder'], name)
                dname = os.path.dirname(name)
                files = []
                for fname in _files:
                    # paths are relative to dirname
                    files.append(os.path.join(dname, fname))
                file_dep = [
                    os.path.join(kw['output_folder'], fname) for fname in files
                    if utils.get_asset_path(fname,
                                            self.site.THEMES,
                                            self.site.config['FILES_FOLDERS'],
                                            output_dir=kw['output_folder'])
                    or fname == os.path.join('assets', 'css', 'code.css')
                ]
                # code.css will be generated by us if it does not exist in
                # FILES_FOLDERS or theme assets.  It is guaranteed that the
                # generation will happen before this task.
                task = {
                    'file_dep':
                    list(file_dep),
                    'task_dep': ['copy_assets', 'copy_files'],
                    'basename':
                    str(self.name),
                    'name':
                    str(output_path),
                    'actions': [(build_bundle, (name, file_dep))],
                    'targets': [output_path],
                    'uptodate': [
                        utils.config_changed({
                            1: kw,
                            2: file_dep
                        }, 'nikola.plugins.task.bundles')
                    ],
                    'clean':
                    True,
                }
                yield utils.apply_filters(task, kw['filters'])
Example #54
0
    def gen_tasks(self):
        """Render the tag pages and feeds."""

        kw = {
            "translations":
            self.site.config["TRANSLATIONS"],
            "blog_title":
            self.site.config["BLOG_TITLE"],
            "blog_url":
            self.site.config["BLOG_URL"],
            "blog_description":
            self.site.config["BLOG_DESCRIPTION"],
            "messages":
            self.site.MESSAGES,
            "output_folder":
            self.site.config['OUTPUT_FOLDER'],
            "filters":
            self.site.config['FILTERS'],
            "tag_pages_are_indexes":
            self.site.config['TAG_PAGES_ARE_INDEXES'],
            "index_display_post_count":
            self.site.config['INDEX_DISPLAY_POST_COUNT'],
            "index_teasers":
            self.site.config['INDEX_TEASERS'],
        }

        if not self.site.posts_per_tag:
            yield {
                'basename': self.name,
                'actions': [],
            }
            return

        def page_name(tagname, i, lang):
            """Given tag, n, returns a page name."""
            name = self.site.path("tag", tag, lang)
            if i:
                name = name.replace('.html', '-%s.html' % i)
            return name

        for tag, posts in self.site.posts_per_tag.items():
            post_list = [self.site.global_data[post] for post in posts]
            post_list.sort(cmp=lambda a, b: cmp(a.date, b.date))
            post_list.reverse()
            for lang in kw["translations"]:
                #Render RSS
                output_name = os.path.join(
                    kw['output_folder'], self.site.path("tag_rss", tag, lang))
                deps = []
                post_list = [
                    self.site.global_data[post] for post in posts
                    if self.site.global_data[post].use_in_feeds
                ]
                post_list.sort(cmp=lambda a, b: cmp(a.date, b.date))
                post_list.reverse()
                for post in post_list:
                    deps += post.deps(lang)
                yield {
                    'name':
                    output_name.encode('utf8'),
                    'file_dep':
                    deps,
                    'targets': [output_name],
                    'actions': [(utils.generic_rss_renderer,
                                 (lang, "%s (%s)" % (kw["blog_title"], tag),
                                  kw["blog_url"], kw["blog_description"],
                                  post_list, output_name))],
                    'clean':
                    True,
                    'uptodate': [utils.config_changed(kw)],
                    'basename':
                    self.name
                }

                # Render HTML
                if kw['tag_pages_are_indexes']:
                    # We render a sort of index page collection using only
                    # this tag's posts.

                    # FIXME: deduplicate this with render_indexes
                    template_name = "index.tmpl"
                    # Split in smaller lists
                    lists = []
                    while post_list:
                        lists.append(
                            post_list[:kw["index_display_post_count"]])
                        post_list = post_list[kw["index_display_post_count"]:]
                    num_pages = len(lists)
                    for i, post_list in enumerate(lists):
                        context = {}
                        # On a tag page, the feeds include the tag's feeds
                        rss_link = \
                        """<link rel="alternate" type="application/rss+xml" """\
                        """type="application/rss+xml" title="RSS for tag """\
                        """%s (%s)" href="%s">""" % \
                            (tag, lang, self.site.link("tag_rss", tag, lang))
                        context['rss_link'] = rss_link
                        output_name = os.path.join(kw['output_folder'],
                                                   page_name(tag, i, lang))
                        context["title"] = kw["messages"][lang][
                            u"Posts about %s:"] % tag
                        context["prevlink"] = None
                        context["nextlink"] = None
                        context['index_teasers'] = kw['index_teasers']
                        if i > 1:
                            context["prevlink"] = os.path.basename(
                                page_name(tag, i - 1, lang))
                        if i == 1:
                            context["prevlink"] = os.path.basename(
                                page_name(tag, 0, lang))
                        if i < num_pages - 1:
                            context["nextlink"] = os.path.basename(
                                page_name(tag, i + 1, lang))
                        context["permalink"] = self.site.link("tag", tag, lang)
                        context["tag"] = tag
                        for task in self.site.generic_post_list_renderer(
                                lang,
                                post_list,
                                output_name,
                                template_name,
                                kw['filters'],
                                context,
                        ):
                            task['uptodate'] = task.get('updtodate', []) +\
                                            [utils.config_changed(kw)]
                            task['basename'] = self.name
                            yield task
                else:
                    # We render a single flat link list with this tag's posts
                    template_name = "tag.tmpl"
                    output_name = os.path.join(
                        kw['output_folder'], self.site.path("tag", tag, lang))
                    context = {}
                    context["lang"] = lang
                    context["title"] = kw["messages"][lang][
                        u"Posts about %s:"] % tag
                    context["items"] = [
                        ("[%s] %s" % (post.date, post.title(lang)),
                         post.permalink(lang)) for post in post_list
                    ]
                    context["permalink"] = self.site.link("tag", tag, lang)
                    context["tag"] = tag
                    for task in self.site.generic_post_list_renderer(
                            lang,
                            post_list,
                            output_name,
                            template_name,
                            kw['filters'],
                            context,
                    ):
                        task['uptodate'] = task.get('updtodate', []) +\
                                        [utils.config_changed(kw)]
                        task['basename'] = self.name
                        yield task

        # And global "all your tags" page
        tags = self.site.posts_per_tag.keys()
        tags.sort()
        template_name = "tags.tmpl"
        kw['tags'] = tags
        for lang in kw["translations"]:
            output_name = os.path.join(kw['output_folder'],
                                       self.site.path('tag_index', None, lang))
            context = {}
            context["title"] = kw["messages"][lang][u"Tags"]
            context["items"] = [(tag, self.site.link("tag", tag, lang))
                                for tag in tags]
            context["permalink"] = self.site.link("tag_index", None, lang)
            for task in self.site.generic_post_list_renderer(
                    lang,
                [],
                    output_name,
                    template_name,
                    kw['filters'],
                    context,
            ):
                task['uptodate'] = task.get('updtodate', []) +\
                    [utils.config_changed(kw)]
                yield task
Example #55
0
    def gen_tasks(self):
        """Render image galleries."""
        self.image_ext_list = self.image_ext_list_builtin
        self.image_ext_list.extend(
            self.site.config.get('EXTRA_IMAGE_EXTENSIONS', []))

        for k, v in self.site.GLOBAL_CONTEXT['template_hooks'].items():
            self.kw['||template_hooks|{0}||'.format(k)] = v.calculate_deps()

        self.site.scan_posts()
        yield self.group_task()

        template_name = "gallery.tmpl"

        # Create all output folders
        for task in self.create_galleries():
            yield task

        # For each gallery:
        for gallery, input_folder, output_folder in self.gallery_list:

            # Create subfolder list
            folder_list = [
                (x, x.split(os.sep)[-2])
                for x in glob.glob(os.path.join(gallery, '*') + os.sep)
            ]

            # Parse index into a post (with translations)
            post = self.parse_index(gallery, input_folder, output_folder)

            # Create image list, filter exclusions
            image_list = self.get_image_list(gallery)

            # Create thumbnails and large images in destination
            for image in image_list:
                for task in self.create_target_images(image, input_folder):
                    yield task

            # Remove excluded images
            for image in self.get_excluded_images(gallery):
                for task in self.remove_excluded_image(image, input_folder):
                    yield task

            for lang in self.kw['translations']:
                # save navigation links as dependencies
                self.kw['navigation_links|{0}'.format(lang)] = self.kw[
                    'global_context']['navigation_links'](lang)

            # Create index.html for each language
            for lang in self.kw['translations']:

                dst = os.path.join(self.kw['output_folder'],
                                   self.site.path("gallery", gallery, lang))
                dst = os.path.normpath(dst)

                for k in self.site._GLOBAL_CONTEXT_TRANSLATABLE:
                    self.kw[k] = self.site.GLOBAL_CONTEXT[k](lang)

                context = {}

                # Do we have a metadata file?
                meta_path, order, captions, img_metadata = self.find_metadata(
                    gallery, lang)
                context['meta_path'] = meta_path
                context['order'] = order
                context['captions'] = captions
                context["lang"] = lang
                if post:
                    context["title"] = post.title(lang)
                else:
                    context["title"] = os.path.basename(gallery)
                context["description"] = None

                image_name_list = [os.path.basename(p) for p in image_list]

                if captions:
                    img_titles = []
                    for fn in image_name_list:
                        if fn in captions:
                            img_titles.append(captions[fn])
                        else:
                            if self.kw['use_filename_as_title']:
                                img_titles.append(fn)
                            else:
                                img_titles.append('')
                            self.logger.debug(
                                "Image {0} found in gallery but not listed in {1}"
                                .format(fn, context['meta_path']))
                elif self.kw['use_filename_as_title']:
                    img_titles = []
                    for fn in image_name_list:
                        name_without_ext = os.path.splitext(
                            os.path.basename(fn))[0]
                        img_titles.append(
                            utils.unslugify(name_without_ext, lang))
                else:
                    img_titles = [''] * len(image_name_list)

                thumbs = [
                    '.thumbnail'.join(os.path.splitext(p)) for p in image_list
                ]
                thumbs = [
                    os.path.join(self.kw['output_folder'], output_folder,
                                 os.path.relpath(t, input_folder))
                    for t in thumbs
                ]
                dst_img_list = [
                    os.path.join(output_folder,
                                 os.path.relpath(t, input_folder))
                    for t in image_list
                ]
                dest_img_list = [
                    os.path.join(self.kw['output_folder'], t)
                    for t in dst_img_list
                ]

                folders = []

                # Generate friendly gallery names
                for path, folder in folder_list:
                    fpost = self.parse_index(path, input_folder, output_folder)
                    if fpost:
                        ft = fpost.title(lang) or folder
                    else:
                        ft = folder
                    if not folder.endswith('/'):
                        folder += '/'
                    folders.append((folder, ft))

                context["gallery_path"] = gallery
                context["folders"] = natsort.natsorted(folders,
                                                       alg=natsort.ns.F
                                                       | natsort.ns.IC)
                context["crumbs"] = utils.get_crumbs(gallery,
                                                     index_folder=self,
                                                     lang=lang)
                context["permalink"] = self.site.link("gallery", gallery, lang)
                context["enable_comments"] = self.kw['comments_in_galleries']
                context["thumbnail_size"] = self.kw["thumbnail_size"]
                context["pagekind"] = ["gallery_front"]

                if post:
                    yield {
                        'basename':
                        self.name,
                        'name':
                        post.translated_base_path(lang),
                        'targets': [post.translated_base_path(lang)],
                        'file_dep':
                        post.fragment_deps(lang),
                        'actions': [(post.compile, [lang])],
                        'uptodate': [
                            utils.config_changed(
                                self.kw.copy(),
                                'nikola.plugins.task.galleries:post')
                        ] + post.fragment_deps_uptodate(lang)
                    }
                    context['post'] = post
                else:
                    context['post'] = None
                file_dep = self.site.template_system.template_deps(
                    template_name) + image_list + thumbs
                file_dep_dest = self.site.template_system.template_deps(
                    template_name) + dest_img_list + thumbs
                if post:
                    file_dep += [
                        post.translated_base_path(l)
                        for l in self.kw['translations']
                    ]
                    file_dep_dest += [
                        post.translated_base_path(l)
                        for l in self.kw['translations']
                    ]

                context["pagekind"] = ["gallery_page"]

                yield utils.apply_filters(
                    {
                        'basename':
                        self.name,
                        'name':
                        dst,
                        'file_dep':
                        file_dep,
                        'targets': [dst],
                        'actions':
                        [(self.render_gallery_index,
                          (template_name, dst, context.copy(), dest_img_list,
                           img_titles, thumbs, img_metadata))],
                        'clean':
                        True,
                        'uptodate': [
                            utils.config_changed(
                                {
                                    1: self.kw.copy(),
                                    2:
                                    self.site.config["COMMENTS_IN_GALLERIES"],
                                    3: context.copy(),
                                }, 'nikola.plugins.task.galleries:gallery')
                        ],
                    }, self.kw['filters'])

                # RSS for the gallery
                if self.kw["generate_rss"]:
                    rss_dst = os.path.join(
                        self.kw['output_folder'],
                        self.site.path("gallery_rss", gallery, lang))
                    rss_dst = os.path.normpath(rss_dst)

                    yield utils.apply_filters(
                        {
                            'basename':
                            self.name,
                            'name':
                            rss_dst,
                            'file_dep':
                            file_dep_dest,
                            'targets': [rss_dst],
                            'actions':
                            [(self.gallery_rss,
                              (image_list, dst_img_list, img_titles, lang,
                               self.site.link("gallery_rss", gallery, lang),
                               rss_dst, context['title']))],
                            'clean':
                            True,
                            'uptodate': [
                                utils.config_changed({
                                    1: self.kw.copy(),
                                }, 'nikola.plugins.task.galleries:rss')
                            ],
                        }, self.kw['filters'])
Example #56
0
    def gen_tasks(self):
        """Bundle assets using WebAssets."""
        kw = {
            'filters': self.site.config['FILTERS'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
            'cache_folder': self.site.config['CACHE_FOLDER'],
            'theme_bundles': get_theme_bundles(self.site.THEMES),
            'themes': self.site.THEMES,
            'files_folders': self.site.config['FILES_FOLDERS'],
            'code_color_scheme': self.site.config['CODE_COLOR_SCHEME'],
        }

        def build_bundle(output, inputs):
            out_dir = os.path.join(kw['output_folder'],
                                   os.path.dirname(output))
            inputs = [
                os.path.relpath(i, out_dir) for i in inputs
                if os.path.isfile(i)
            ]
            cache_dir = os.path.join(kw['cache_folder'], 'webassets')
            utils.makedirs(cache_dir)
            env = webassets.Environment(out_dir,
                                        os.path.dirname(output),
                                        cache=cache_dir)
            if inputs:
                bundle = webassets.Bundle(*inputs,
                                          output=os.path.basename(output))
                env.register(output, bundle)
                # This generates the file
                try:
                    env[output].build(force=True)
                except Exception as e:
                    self.logger.error("Failed to build bundles.")
                    self.logger.exception(e)
                    self.logger.notice(
                        "Try running ``nikola clean`` and building again.")
            else:
                with open(os.path.join(out_dir, os.path.basename(output)),
                          'wb+'):
                    pass  # Create empty file

        yield self.group_task()
        if (webassets is not None
                and self.site.config['USE_BUNDLES'] is not False):
            for name, _files in kw['theme_bundles'].items():
                output_path = os.path.join(kw['output_folder'], name)
                dname = os.path.dirname(name)
                files = []
                for fname in _files:
                    # paths are relative to dirname
                    files.append(os.path.join(dname, fname))
                file_dep = [
                    os.path.join(kw['output_folder'], fname) for fname in files
                    if utils.get_asset_path(fname,
                                            self.site.THEMES,
                                            self.site.config['FILES_FOLDERS'],
                                            output_dir=kw['output_folder'])
                    or fname == os.path.join('assets', 'css', 'code.css')
                ]
                # code.css will be generated by us if it does not exist in
                # FILES_FOLDERS or theme assets.  It is guaranteed that the
                # generation will happen before this task.
                task = {
                    'file_dep':
                    list(file_dep),
                    'task_dep': ['copy_assets', 'copy_files'],
                    'basename':
                    str(self.name),
                    'name':
                    str(output_path),
                    'actions': [(build_bundle, (name, file_dep))],
                    'targets': [output_path],
                    'uptodate': [
                        utils.config_changed({
                            1: kw,
                            2: file_dep
                        }, 'nikola.plugins.task.bundles')
                    ],
                    'clean':
                    True,
                }
                yield utils.apply_filters(task, kw['filters'])
Example #57
0
    def create_target_images(self, img, input_path):
        """Copy images to output."""
        gallery_name = os.path.dirname(img)
        output_gallery = os.path.dirname(
            os.path.join(self.kw["output_folder"],
                         self.site.path("gallery_global", gallery_name)))
        # Do thumbnails and copy originals
        # img is "galleries/name/image_name.jpg"
        # img_name is "image_name.jpg"
        # fname, ext are "image_name", ".jpg"
        # thumb_path is
        # "output/GALLERY_PATH/name/image_name.thumbnail.jpg"
        img_name = os.path.basename(img)
        fname, ext = os.path.splitext(img_name)
        thumb_path = os.path.join(output_gallery,
                                  ".thumbnail".join([fname, ext]))
        # thumb_path is "output/GALLERY_PATH/name/image_name.jpg"
        orig_dest_path = os.path.join(output_gallery, img_name)
        yield utils.apply_filters(
            {
                'basename':
                self.name,
                'name':
                thumb_path,
                'file_dep': [img],
                'targets': [thumb_path],
                'actions':
                [(self.resize_image,
                  (img, thumb_path, self.kw['thumbnail_size'], True,
                   self.kw['preserve_exif_data'], self.kw['exif_whitelist'],
                   self.kw['preserve_icc_profiles']))],
                'clean':
                True,
                'uptodate': [
                    utils.config_changed(
                        {1: self.kw['thumbnail_size']},
                        'nikola.plugins.task.galleries:resize_thumb')
                ],
            }, self.kw['filters'])

        yield utils.apply_filters(
            {
                'basename':
                self.name,
                'name':
                orig_dest_path,
                'file_dep': [img],
                'targets': [orig_dest_path],
                'actions':
                [(self.resize_image,
                  (img, orig_dest_path, self.kw['max_image_size'], True,
                   self.kw['preserve_exif_data'], self.kw['exif_whitelist'],
                   self.kw['preserve_icc_profiles']))],
                'clean':
                True,
                'uptodate': [
                    utils.config_changed(
                        {1: self.kw['max_image_size']},
                        'nikola.plugins.task.galleries:resize_max')
                ],
            }, self.kw['filters'])
Example #58
0
    def gen_tasks(self):
        """Render image galleries."""

        kw = {
            'thumbnail_size': self.site.config['THUMBNAIL_SIZE'],
            'max_image_size': self.site.config['MAX_IMAGE_SIZE'],
            'output_folder': self.site.config['OUTPUT_FOLDER'],
            'cache_folder': self.site.config['CACHE_FOLDER'],
            'default_lang': self.site.config['DEFAULT_LANG'],
            'blog_description': self.site.config['BLOG_DESCRIPTION'],
            'use_filename_as_title': self.site.config['USE_FILENAME_AS_TITLE'],
            'gallery_path': self.site.config['GALLERY_PATH']
        }

        # FIXME: lots of work is done even when images don't change,
        # which should be moved into the task.

        template_name = "gallery.tmpl"

        gallery_list = []
        for root, dirs, files in os.walk(kw['gallery_path']):
            gallery_list.append(root)
        if not gallery_list:
            yield {
                'basename': str('render_galleries'),
                'actions': [],
            }
            return

        # gallery_path is "gallery/name"
        for gallery_path in gallery_list:
            # gallery_name is "name"
            splitted = gallery_path.split(os.sep)[1:]
            if not splitted:
                gallery_name = ''
            else:
                gallery_name = os.path.join(*splitted)

            # Task to create gallery in output/
            # output_gallery is "output/GALLERY_PATH/name"
            output_gallery = os.path.dirname(
                os.path.join(kw["output_folder"],
                             self.site.path("gallery", gallery_name, None)))
            output_name = os.path.join(output_gallery,
                                       self.site.config['INDEX_FILE'])
            if not os.path.isdir(output_gallery):
                yield {
                    'basename': str('render_galleries'),
                    'name': output_gallery,
                    'actions': [(os.makedirs, (output_gallery, ))],
                    'targets': [output_gallery],
                    'clean': True,
                    'uptodate': [utils.config_changed(kw)],
                }

            # Gather image_list contains "gallery/name/image_name.jpg"
            image_list = glob.glob(gallery_path + "/*jpg") +\
                glob.glob(gallery_path + "/*JPG") +\
                glob.glob(gallery_path + "/*png") +\
                glob.glob(gallery_path + "/*PNG")

            # Filter ignored images
            try:
                exclude_path = os.path.join(gallery_path, "exclude.meta")
                try:
                    f = open(exclude_path, 'r')
                    excluded_image_name_list = f.read().split()
                except IOError:
                    excluded_image_name_list = []
                excluded_image_list = [
                    "{0}/{1}".format(gallery_path, i)
                    for i in excluded_image_name_list
                ]
                image_set = set(image_list) - set(excluded_image_list)
                image_list = list(image_set)
            except IOError:
                pass

            # List of sub-galleries
            folder_list = [
                x.split(os.sep)[-2]
                for x in glob.glob(os.path.join(gallery_path, '*') + os.sep)
            ]

            crumbs = utils.get_crumbs(gallery_path)

            image_list = [x for x in image_list if "thumbnail" not in x]
            # Sort by date
            image_list.sort(key=lambda a: self.image_date(a))
            image_name_list = [os.path.basename(x) for x in image_list]

            # Do thumbnails and copy originals
            thumbs = []
            for img, img_name in list(zip(image_list, image_name_list)):
                # img is "galleries/name/image_name.jpg"
                # img_name is "image_name.jpg"
                # fname, ext are "image_name", ".jpg"
                fname, ext = os.path.splitext(img_name)
                # thumb_path is
                # "output/GALLERY_PATH/name/image_name.thumbnail.jpg"
                thumb_path = os.path.join(output_gallery,
                                          ".thumbnail".join([fname, ext]))
                # thumb_path is "output/GALLERY_PATH/name/image_name.jpg"
                orig_dest_path = os.path.join(output_gallery, img_name)
                thumbs.append(os.path.basename(thumb_path))
                yield {
                    'basename':
                    str('render_galleries'),
                    'name':
                    thumb_path,
                    'file_dep': [img],
                    'targets': [thumb_path],
                    'actions': [(self.resize_image, (img, thumb_path,
                                                     kw['thumbnail_size']))],
                    'clean':
                    True,
                    'uptodate': [utils.config_changed(kw)],
                }
                yield {
                    'basename':
                    str('render_galleries'),
                    'name':
                    orig_dest_path,
                    'file_dep': [img],
                    'targets': [orig_dest_path],
                    'actions': [(self.resize_image, (img, orig_dest_path,
                                                     kw['max_image_size']))],
                    'clean':
                    True,
                    'uptodate': [utils.config_changed(kw)],
                }

            # Remove excluded images
            if excluded_image_name_list:
                for img, img_name in zip(excluded_image_list,
                                         excluded_image_name_list):
                    # img_name is "image_name.jpg"
                    # fname, ext are "image_name", ".jpg"
                    fname, ext = os.path.splitext(img_name)
                    excluded_thumb_dest_path = os.path.join(
                        output_gallery, ".thumbnail".join([fname, ext]))
                    excluded_dest_path = os.path.join(output_gallery, img_name)
                    yield {
                        'basename':
                        str('render_galleries_clean'),
                        'name':
                        excluded_thumb_dest_path,
                        'file_dep': [exclude_path],
                        #'targets': [excluded_thumb_dest_path],
                        'actions':
                        [(utils.remove_file, (excluded_thumb_dest_path, ))],
                        'clean':
                        True,
                        'uptodate': [utils.config_changed(kw)],
                    }
                    yield {
                        'basename': str('render_galleries_clean'),
                        'name': excluded_dest_path,
                        'file_dep': [exclude_path],
                        #'targets': [excluded_dest_path],
                        'actions':
                        [(utils.remove_file, (excluded_dest_path, ))],
                        'clean': True,
                        'uptodate': [utils.config_changed(kw)],
                    }

            # Use galleries/name/index.txt to generate a blurb for
            # the gallery, if it exists.

            index_path = os.path.join(gallery_path, "index.txt")
            cache_dir = os.path.join(kw["cache_folder"], 'galleries')
            if not os.path.isdir(cache_dir):
                os.makedirs(cache_dir)
            index_dst_path = os.path.join(
                cache_dir,
                str(
                    hashlib.sha224(index_path.encode('utf-8')).hexdigest() +
                    '.html'))
            if os.path.exists(index_path):
                compile_html = self.site.get_compiler(index_path).compile_html
                yield {
                    'basename': str('render_galleries'),
                    'name': index_dst_path,
                    'file_dep': [index_path],
                    'targets': [index_dst_path],
                    'actions':
                    [(compile_html, [index_path, index_dst_path, True])],
                    'clean': True,
                    'uptodate': [utils.config_changed(kw)],
                }

            context = {}
            context["lang"] = kw["default_lang"]
            context["title"] = os.path.basename(gallery_path)
            context["description"] = kw["blog_description"]
            if kw['use_filename_as_title']:
                img_titles = [
                    'id="{0}" alt="{1}" title="{2}"'.format(
                        fn[:-4], fn[:-4], utils.unslugify(fn[:-4]))
                    for fn in image_name_list
                ]
            else:
                img_titles = [''] * len(image_name_list)
            # In the future, remove images from context, use photo_array
            context["images"] = list(zip(image_name_list, thumbs, img_titles))
            context["folders"] = folder_list
            context["crumbs"] = crumbs
            context["permalink"] = self.site.link("gallery", gallery_name,
                                                  None)
            context["enable_comments"] = (
                self.site.config["COMMENTS_IN_GALLERIES"])
            context["thumbnail_size"] = kw["thumbnail_size"]

            file_dep = self.site.template_system.template_deps(
                template_name) + image_list

            yield {
                'basename':
                str('render_galleries'),
                'name':
                output_name,
                'file_dep':
                file_dep,
                'targets': [output_name],
                'actions':
                [(self.render_gallery_index,
                  (template_name, output_name, context, index_dst_path,
                   image_name_list, thumbs, file_dep, kw))],
                'clean':
                True,
                'uptodate': [
                    utils.config_changed({
                        1:
                        kw,
                        2:
                        self.site.config['GLOBAL_CONTEXT'],
                        3:
                        self.site.config["COMMENTS_IN_GALLERIES"],
                        4:
                        context,
                    })
                ],
            }
Example #59
0
    def gen_tasks(self):
        """Generate a sitemap."""
        kw = {
            "base_url":
            self.site.config["BASE_URL"],
            "site_url":
            self.site.config["SITE_URL"],
            "output_folder":
            self.site.config["OUTPUT_FOLDER"],
            "strip_indexes":
            self.site.config["STRIP_INDEXES"],
            "index_file":
            self.site.config["INDEX_FILE"],
            "sitemap_include_fileless_dirs":
            self.site.config["SITEMAP_INCLUDE_FILELESS_DIRS"],
            "mapped_extensions":
            self.site.config.get(
                'MAPPED_EXTENSIONS',
                ['.atom', '.html', '.htm', '.php', '.xml', '.rss']),
            "robots_exclusions":
            self.site.config["ROBOTS_EXCLUSIONS"],
            "filters":
            self.site.config["FILTERS"],
            "translations":
            self.site.config["TRANSLATIONS"],
            "tzinfo":
            self.site.config['__tzinfo__'],
            "sitemap_plugin_revision":
            1,
        }

        output = kw['output_folder']
        base_url = kw['base_url']
        mapped_exts = kw['mapped_extensions']

        output_path = kw['output_folder']
        sitemapindex_path = os.path.join(output_path, "sitemapindex.xml")
        sitemap_path = os.path.join(output_path, "sitemap.xml")
        base_path = get_base_path(kw['base_url'])
        sitemapindex = {}
        urlset = {}

        def scan_locs():
            """Scan site locations."""
            for root, dirs, files in os.walk(output, followlinks=True):
                if not dirs and not files and not kw[
                        'sitemap_include_fileless_dirs']:
                    continue  # Totally empty, not on sitemap
                path = os.path.relpath(root, output)
                # ignore the current directory.
                if path == '.':
                    path = syspath = ''
                else:
                    syspath = path + os.sep
                    path = path.replace(os.sep, '/') + '/'
                lastmod = self.get_lastmod(root)
                loc = urljoin(base_url, base_path + path)
                if kw['index_file'] in files and kw[
                        'strip_indexes']:  # ignore folders when not stripping urls
                    post = self.site.post_per_file.get(syspath +
                                                       kw['index_file'])
                    if post and (post.is_draft or post.is_private
                                 or post.publish_later):
                        continue
                    alternates = []
                    if post:
                        for lang in post.translated_to:
                            alt_url = post.permalink(lang=lang, absolute=True)
                            if encodelink(loc) == alt_url:
                                continue
                            alternates.append(
                                alternates_format.format(lang, alt_url))
                    urlset[loc] = loc_format.format(encodelink(loc), lastmod,
                                                    ''.join(alternates))
                for fname in files:
                    if kw['strip_indexes'] and fname == kw['index_file']:
                        continue  # We already mapped the folder
                    if os.path.splitext(fname)[-1] in mapped_exts:
                        real_path = os.path.join(root, fname)
                        path = os.path.relpath(real_path, output)
                        if path.endswith(
                                kw['index_file']) and kw['strip_indexes']:
                            # ignore index files when stripping urls
                            continue
                        if not robot_fetch(path):
                            continue

                        # read in binary mode to make ancient files work
                        fh = open(real_path, 'rb')
                        filehead = fh.read(1024)
                        fh.close()

                        if path.endswith('.html') or path.endswith(
                                '.htm') or path.endswith('.php'):
                            # Ignores "html" files without doctype
                            if b'<!doctype html' not in filehead.lower():
                                continue

                            # Ignores "html" files with noindex robot directives
                            robots_directives = [
                                b'<meta content=noindex name=robots',
                                b'<meta content=none name=robots',
                                b'<meta name=robots content=noindex',
                                b'<meta name=robots content=none'
                            ]
                            lowquothead = filehead.lower().decode(
                                'utf-8', 'ignore').replace('"',
                                                           '').encode('utf-8')
                            if any([
                                    robot_directive in lowquothead
                                    for robot_directive in robots_directives
                            ]):
                                continue

                        # put Atom and RSS in sitemapindex[] instead of in urlset[],
                        # sitemap_path is included after it is generated
                        if path.endswith('.xml') or path.endswith(
                                '.atom') or path.endswith('.rss'):
                            known_elm_roots = (b'<feed', b'<rss', b'<urlset')
                            if any([
                                    elm_root in filehead.lower()
                                    for elm_root in known_elm_roots
                            ]) and path != sitemap_path:
                                path = path.replace(os.sep, '/')
                                lastmod = self.get_lastmod(real_path)
                                loc = urljoin(base_url, base_path + path)
                                sitemapindex[loc] = sitemap_format.format(
                                    encodelink(loc), lastmod)
                                continue
                            else:
                                continue  # ignores all XML files except those presumed to be RSS
                        post = self.site.post_per_file.get(syspath)
                        if post and (post.is_draft or post.is_private
                                     or post.publish_later):
                            continue
                        path = path.replace(os.sep, '/')
                        lastmod = self.get_lastmod(real_path)
                        loc = urljoin(base_url, base_path + path)
                        alternates = []
                        if post:
                            for lang in post.translated_to:
                                alt_url = post.permalink(lang=lang,
                                                         absolute=True)
                                if encodelink(loc) == alt_url:
                                    continue
                                alternates.append(
                                    alternates_format.format(lang, alt_url))
                        urlset[loc] = loc_format.format(
                            encodelink(loc), lastmod, '\n'.join(alternates))

        def robot_fetch(path):
            """Check if robots can fetch a file."""
            for rule in kw["robots_exclusions"]:
                robot = robotparser.RobotFileParser()
                robot.parse(["User-Agent: *", "Disallow: {0}".format(rule)])
                if not robot.can_fetch("*", '/' + path):
                    return False  # not robot food
            return True

        def write_sitemap():
            """Write sitemap to file."""
            # Have to rescan, because files may have been added between
            # task dep scanning and task execution
            with io.open(sitemap_path, 'w+', encoding='utf8') as outf:
                outf.write(urlset_header)
                for k in sorted(urlset.keys()):
                    outf.write(urlset[k])
                outf.write(urlset_footer)
            sitemap_url = urljoin(base_url, base_path + "sitemap.xml")
            sitemapindex[sitemap_url] = sitemap_format.format(
                sitemap_url, self.get_lastmod(sitemap_path))

        def write_sitemapindex():
            """Write sitemap index."""
            with io.open(sitemapindex_path, 'w+', encoding='utf8') as outf:
                outf.write(sitemapindex_header)
                for k in sorted(sitemapindex.keys()):
                    outf.write(sitemapindex[k])
                outf.write(sitemapindex_footer)

        def scan_locs_task():
            """Yield a task to calculate the dependencies of the sitemap.

            Other tasks can depend on this output, instead of having
            to scan locations.
            """
            scan_locs()

            # Generate a list of file dependencies for the actual generation
            # task, so rebuilds are triggered.  (Issue #1032)
            output = kw["output_folder"]
            file_dep = []

            for i in urlset.keys():
                p = os.path.join(output,
                                 urlparse(i).path.replace(base_path, '', 1))
                if not p.endswith('sitemap.xml') and not os.path.isdir(p):
                    file_dep.append(p)
                if os.path.isdir(p) and os.path.exists(
                        os.path.join(p, 'index.html')):
                    file_dep.append(p + 'index.html')

            for i in sitemapindex.keys():
                p = os.path.join(output,
                                 urlparse(i).path.replace(base_path, '', 1))
                if not p.endswith('sitemap.xml') and not os.path.isdir(p):
                    file_dep.append(p)
                if os.path.isdir(p) and os.path.exists(
                        os.path.join(p, 'index.html')):
                    file_dep.append(p + 'index.html')

            return {'file_dep': file_dep}

        yield {
            "basename": "_scan_locs",
            "name": "sitemap",
            "actions": [(scan_locs_task)]
        }

        yield self.group_task()
        yield apply_filters(
            {
                "basename":
                "sitemap",
                "name":
                sitemap_path,
                "targets": [sitemap_path],
                "actions": [(write_sitemap, )],
                "uptodate":
                [config_changed(kw, 'nikola.plugins.task.sitemap:write')],
                "clean":
                True,
                "task_dep": ["render_site"],
                "calc_dep": ["_scan_locs:sitemap"],
            }, kw['filters'])
        yield apply_filters(
            {
                "basename":
                "sitemap",
                "name":
                sitemapindex_path,
                "targets": [sitemapindex_path],
                "actions": [(write_sitemapindex, )],
                "uptodate": [
                    config_changed(kw,
                                   'nikola.plugins.task.sitemap:write_index')
                ],
                "clean":
                True,
                "file_dep": [sitemap_path]
            }, kw['filters'])
Example #60
0
    def gen_tasks(self):
        """Generate CSS out of LESS sources."""
        self.compiler_name = self.site.config['LESS_COMPILER']
        self.compiler_options = self.site.config['LESS_OPTIONS']

        kw = {
            'cache_folder': self.site.config['CACHE_FOLDER'],
            'themes': self.site.THEMES,
        }
        tasks = {}

        # Find where in the theme chain we define the LESS targets
        # There can be many *.less in the folder, but we only will build
        # the ones listed in less/targets
        if os.path.isfile(os.path.join(self.sources_folder, "targets")):
            targets_path = os.path.join(self.sources_folder, "targets")
        else:
            targets_path = utils.get_asset_path(os.path.join(self.sources_folder, "targets"), self.site.THEMES)
        try:
            with codecs.open(targets_path, "rb", "utf-8") as inf:
                targets = [x.strip() for x in inf.readlines()]
        except Exception:
            targets = []

        for task in utils.copy_tree(self.sources_folder, os.path.join(kw['cache_folder'], self.sources_folder)):
            if task['name'] in tasks:
                continue
            task['basename'] = 'prepare_less_sources'
            tasks[task['name']] = task
            yield task

        for theme_name in kw['themes']:
            src = os.path.join(utils.get_theme_path(theme_name), self.sources_folder)
            for task in utils.copy_tree(src, os.path.join(kw['cache_folder'], self.sources_folder)):
                task['basename'] = 'prepare_less_sources'
                yield task

        # Build targets and write CSS files
        base_path = utils.get_theme_path(self.site.THEMES[0])
        dst_dir = os.path.join(self.site.config['OUTPUT_FOLDER'], 'assets', 'css')
        # Make everything depend on all sources, rough but enough
        deps = []
        if os.path.isfile(os.path.join(self.sources_folder, "targets")):
            deps += glob.glob(os.path.join(kw['cache_folder'], self.sources_folder,
                                           '*{0}'.format(self.sources_ext)))
        else:
            deps += glob.glob(os.path.join(base_path, self.sources_folder,
                                           '*{0}'.format(self.sources_ext)))

        def compile_target(target, dst):
            utils.makedirs(dst_dir)
            src = os.path.join(kw['cache_folder'], self.sources_folder, target)
            run_in_shell = sys.platform == 'win32'
            try:
                compiled = subprocess.check_output([self.compiler_name] + self.compiler_options + [src], shell=run_in_shell)
            except OSError:
                utils.req_missing([self.compiler_name],
                                  'build LESS files (and use this theme)',
                                  False, False)
            with open(dst, "wb+") as outf:
                outf.write(compiled)

        yield self.group_task()

        for target in targets:
            dst = os.path.join(dst_dir, target.replace(self.sources_ext, ".css"))
            yield {
                'basename': self.name,
                'name': dst,
                'targets': [dst],
                'file_dep': deps,
                'task_dep': ['prepare_less_sources'],
                'actions': ((compile_target, [target, dst]), ),
                'uptodate': [utils.config_changed(kw)],
                'clean': True
            }