Exemple #1
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        name = options['name']
        swatch = options['swatch']
        if not swatch:
            LOGGER.error('The -s option is mandatory')
            sys.exit(1)
        parent = options['parent']
        version = ''

        # See if we need bootswatch for bootstrap v2 or v3
        themes = utils.get_theme_chain(parent)
        if 'bootstrap3' not in themes and 'bootstrap3-jinja' not in themes:
            version = '2'
        elif 'bootstrap' not in themes and 'bootstrap-jinja' not in themes:
            LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap')
        elif 'bootstrap3-gradients' in themes or 'bootstrap3-gradients-jinja' in themes:
            LOGGER.warn('"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family')

        LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = 'http://bootswatch.com'
            if version:
                url += '/' + version
            url = '/'.join((url, swatch, fname))
            LOGGER.info("Downloading: " + url)
            data = requests.get(url).text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data.encode('utf-8'))

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent.encode('utf-8'))
        LOGGER.notice('Theme created.  Change the THEME setting to "{0}" to use it.'.format(name))
Exemple #2
0
    def new_theme(self, name, engine, parent):
        """Create a new theme."""
        base = 'themes'
        themedir = os.path.join(base, name)
        LOGGER.info("Creating theme {0} with parent {1} and engine {2} in {3}".format(name, parent, engine, themedir))
        if not os.path.exists(base):
            os.mkdir(base)
            LOGGER.info("Created directory {0}".format(base))

        # Check if engine and parent match
        engine_file = utils.get_asset_path('engine', utils.get_theme_chain(parent, self.site.themes_dirs))
        with io.open(engine_file, 'r', encoding='utf-8') as fh:
            parent_engine = fh.read().strip()

        if parent_engine != engine:
            LOGGER.error("Cannot use engine {0} because parent theme '{1}' uses {2}".format(engine, parent, parent_engine))
            return 2

        # Create theme
        if not os.path.exists(themedir):
            os.mkdir(themedir)
            LOGGER.info("Created directory {0}".format(themedir))
        else:
            LOGGER.error("Theme already exists")
            return 2

        with io.open(os.path.join(themedir, 'parent'), 'w', encoding='utf-8') as fh:
            fh.write(parent + '\n')
            LOGGER.info("Created file {0}".format(os.path.join(themedir, 'parent')))
        with io.open(os.path.join(themedir, 'engine'), 'w', encoding='utf-8') as fh:
            fh.write(engine + '\n')
            LOGGER.info("Created file {0}".format(os.path.join(themedir, 'engine')))

        LOGGER.info("Theme {0} created successfully.".format(themedir))
        LOGGER.notice('Remember to set THEME="{0}" in conf.py to use this theme.'.format(name))
Exemple #3
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        name = options['name']
        swatch = options['swatch']
        if not swatch:
            LOGGER.error('The -s option is mandatory')
            return 1
        parent = options['parent']
        version = ''

        # See if we need bootswatch for bootstrap v2 or v3
        themes = utils.get_theme_chain(parent)
        if 'bootstrap3' not in themes and 'bootstrap3-jinja' not in themes:
            version = '2'
        elif 'bootstrap' not in themes and 'bootstrap-jinja' not in themes:
            LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap')
        elif 'bootstrap3-gradients' in themes or 'bootstrap3-gradients-jinja' in themes:
            LOGGER.warn('"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family')

        LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = 'https://bootswatch.com'
            if version:
                url += '/' + version
            url = '/'.join((url, swatch, fname))
            LOGGER.info("Downloading: " + url)
            data = requests.get(url).text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data.encode('utf-8'))

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent.encode('utf-8'))
        LOGGER.notice('Theme created.  Change the THEME setting to "{0}" to use it.'.format(name))
Exemple #4
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        if requests is None:
            utils.req_missing(['requests'], 'install Bootswatch themes')

        name = options['name']
        swatch = options['swatch']
        parent = options['parent']
        version = ''

        # See if we need bootswatch for bootstrap v2 or v3
        themes = utils.get_theme_chain(parent)
        if 'bootstrap3' not in themes:
            version = '2'
        elif 'bootstrap' not in themes:
            LOGGER.warn(
                '"bootswatch_theme" only makes sense for themes that use bootstrap'
            )

        LOGGER.notice("Creating '{0}' theme from '{1}' and '{2}'".format(
            name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = '/'.join(('http://bootswatch.com', version, swatch, fname))
            LOGGER.notice("Downloading: " + url)
            data = requests.get(url).text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data.encode('utf-8'))

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent.encode('utf-8'))
        LOGGER.notice(
            'Theme created. Change the THEME setting to "{0}" to use '
            'it.'.format(name))
def build_demo(theme, themes_dir, demo_source, demo_destination):
    demo_destination = os.path.abspath(demo_destination)
    if os.path.isdir(demo_source):
        shutil.rmtree(demo_source)
    if os.path.isdir(demo_destination):
        shutil.rmtree(demo_destination)
    sys.stderr.write('=> Building {}...\n'.format(theme))
    subprocess.check_call(["nikola", "init", "-qd", demo_source], stdout=subprocess.PIPE)
    os.symlink(os.path.abspath(themes_dir), os.path.abspath("/".join([demo_source, "themes"])))

    conf_path = "/".join([demo_source, "conf.py"])
    book_path = "/".join([demo_source, "templates", "book.tmpl"])
    lorem_path = "/".join([demo_source, "posts", "lorem-ipsum.rst"])
    # Get custom required settings from the theme
    themes = utils.get_theme_chain(theme, themes_dirs=[themes_dir, 'themes'])
    engine_path = utils.get_asset_path('engine', themes)
    extra_conf_path = utils.get_asset_path('conf.py.sample', themes)
    extra_conf = ''
    if extra_conf_path:
        extra_conf = io.open(extra_conf_path, 'r', encoding="utf-8").read()
    if engine_path:
        engine = io.open(engine_path, 'r', encoding="utf-8").read().strip()
        if engine == 'jinja':
            shutil.copy('book-jinja.tmpl', book_path)

    with io.open(conf_path, "a", encoding="utf-8") as conf:
        conf.write(u"\n\nTHEME = '{0}'\nUSE_BUNDLES = False\nOUTPUT_FOLDER = '{1}'\nSOCIAL_BUTTONS_CODE = ''\nUSE_BASE_TAG = False\n\n{2}\n".format(theme, demo_destination, extra_conf))

    shutil.copy(LOREM_BASE, lorem_path)

    with cd(demo_source):
        subprocess.check_call(["nikola", "build"], stdout=subprocess.PIPE)

    sys.stderr.write('=> Done building {}\n'.format(theme))
Exemple #6
0
def init_theme(theme):
    t_path = "/".join(["sites", theme])
    o_path = os.path.abspath("/".join(["output", "v7", theme]))
    if os.path.isdir(t_path):
        shutil.rmtree(t_path)
    if os.path.isdir(o_path):
        shutil.rmtree(o_path)
    subprocess.check_call(["nikola", "init", "-qd", t_path],
                          stdout=subprocess.PIPE)
    os.symlink(os.path.abspath("v7"),
               os.path.abspath("/".join([t_path, "themes"])))

    conf_path = "/".join([t_path, "conf.py"])
    # Get custom required settings from the theme
    themes = utils.get_theme_chain(theme, _themes_dir='v7')
    extra_conf_path = utils.get_asset_path('conf.py.sample',
                                           themes,
                                           _themes_dir='v7')
    extra_conf = ''
    if extra_conf_path:
        extra_conf = io.open(extra_conf_path, 'r', encoding="utf-8").read()

    with io.open(conf_path, "a", encoding="utf-8") as conf:
        conf.write(
            u"\n\n{2}\n\nTHEME = '{0}'\n\nUSE_BUNDLES = False\n\nOUTPUT_FOLDER = '{1}'\n\nSOCIAL_BUTTONS_CODE = ''\nUSE_BASE_TAG = False\n"
            .format(theme, o_path, extra_conf))
Exemple #7
0
def get_data(theme):
    data = {}
    data['chain'] = utils.get_theme_chain(theme, DIR)
    data['name'] = theme
    readme = utils.get_asset_path('README.md', data['chain'], _themes_dir=DIR)
    conf_sample = utils.get_asset_path('conf.py.sample', data['chain'], _themes_dir=DIR)
    if readme:
        data['readme'] = io.open(readme, 'r', encoding='utf-8').read()
    else:
        data['readme'] = 'No README.md file available.'

    if conf_sample:
        data['confpy'] = pygments.highlight(
            io.open(conf_sample, 'r', encoding='utf-8').read(),
            PythonLexer(), HtmlFormatter(cssclass='code'))
    else:
        data['confpy'] = None

    data['bootswatch'] = ('bootstrap' in data['chain'] or
        'bootstrap-jinja' in data['chain'] or
        'bootstrap3-jinja' in data['chain'] or
        'bootstrap3' in data['chain']) and \
        'bootstrap3-gradients' not in data['chain']
    data['engine'] = utils.get_template_engine(data['chain'], DIR)
    data['chain'] = data['chain'][::-1]

    data['allver'] = []
    for v in ALL_VERSIONS_SUPPORTED:
        if glob.glob('v{0}/*'.format(v)):
            data['allver'].append(v)

    return data
def build_demo(theme, themes_dir, demo_source, demo_destination):
    demo_destination = os.path.abspath(demo_destination)
    if os.path.isdir(demo_source):
        shutil.rmtree(demo_source)
    if os.path.isdir(demo_destination):
        shutil.rmtree(demo_destination)
    sys.stderr.write('=> Building {}...\n'.format(theme))
    subprocess.check_call(["nikola", "init", "-qd", demo_source], stdout=subprocess.PIPE)
    os.symlink(os.path.abspath(themes_dir), os.path.abspath("/".join([demo_source, "themes"])))

    conf_path = "/".join([demo_source, "conf.py"])
    book_path = "/".join([demo_source, "templates", "book.tmpl"])
    lorem_path = "/".join([demo_source, "posts", "lorem-ipsum.rst"])
    # Get custom required settings from the theme
    themes = utils.get_theme_chain(theme, themes_dirs=[themes_dir, 'themes'])
    engine_path = utils.get_asset_path('engine', themes)
    extra_conf_path = utils.get_asset_path('conf.py.sample', themes)
    extra_conf = ''
    if extra_conf_path:
        extra_conf = io.open(extra_conf_path, 'r', encoding="utf-8").read()
    if engine_path:
        engine = io.open(engine_path, 'r', encoding="utf-8").read().strip()
        if engine == 'jinja':
            shutil.copy('book-jinja.tmpl', book_path)

    with io.open(conf_path, "a", encoding="utf-8") as conf:
        conf.write(u"\n\nTHEME = '{0}'\nUSE_BUNDLES = False\nOUTPUT_FOLDER = '{1}'\nSOCIAL_BUTTONS_CODE = ''\nUSE_BASE_TAG = False\n\n{2}\n".format(theme, demo_destination, extra_conf))

    shutil.copy(LOREM_BASE, lorem_path)

    with cd(demo_source):
        subprocess.check_call(["nikola", "build"], stdout=subprocess.PIPE)

    sys.stderr.write('=> Done building {}\n'.format(theme))
Exemple #9
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        if requests is None:
            utils.req_missing(["requests"], "install Bootswatch themes")

        name = options["name"]
        swatch = options["swatch"]
        parent = options["parent"]
        version = ""

        # See if we need bootswatch for bootstrap v2 or v3
        themes = utils.get_theme_chain(parent)
        if "bootstrap3" not in themes:
            version = "2"
        elif "bootstrap" not in themes:
            LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap')
        elif "bootstrap3-gradients" in themes or "bootstrap3-gradients-jinja" in themes:
            LOGGER.warn('"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family')

        LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
        utils.makedirs(os.path.join("themes", name, "assets", "css"))
        for fname in ("bootstrap.min.css", "bootstrap.css"):
            url = "/".join(("http://bootswatch.com", version, swatch, fname))
            LOGGER.info("Downloading: " + url)
            data = requests.get(url).text
            with open(os.path.join("themes", name, "assets", "css", fname), "wb+") as output:
                output.write(data.encode("utf-8"))

        with open(os.path.join("themes", name, "parent"), "wb+") as output:
            output.write(parent.encode("utf-8"))
        LOGGER.notice('Theme created.  Change the THEME setting to "{0}" to use it.'.format(name))
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        if requests is None:
            utils.req_missing(['requests'], 'install Bootswatch themes')

        name = options['name']
        swatch = options['swatch']
        parent = options['parent']
        version = ''

        # See if we need bootswatch for bootstrap v2 or v3
        themes = utils.get_theme_chain(parent)
        if 'bootstrap3' not in themes:
            version = '2'
        elif 'bootstrap' not in themes:
            LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap')

        LOGGER.notice("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = '/'.join(('http://bootswatch.com', version, swatch, fname))
            LOGGER.notice("Downloading: " + url)
            data = requests.get(url).text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data.encode('utf-8'))

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent.encode('utf-8'))
        LOGGER.notice('Theme created. Change the THEME setting to "{0}" to use '
                      'it.'.format(name))
Exemple #11
0
def get_data(theme):
    data = {}
    data['chain'] = utils.get_theme_chain(theme)
    data['name'] = theme
    readme = utils.get_asset_path('README.md', data['chain'])
    conf_sample = utils.get_asset_path('conf.py.sample', data['chain'])
    if readme:
        data['readme'] = codecs.open(readme, 'r', 'utf8').read()
    else:
        data['readme'] = 'No README.md file available.'

    if conf_sample:
        data['confpy'] = pygments.highlight(
            codecs.open(conf_sample, 'r', 'utf8').read(),
            PythonLexer(), HtmlFormatter(cssclass='code'))
    else:
        data['confpy'] = None

    data['bootswatch'] = ('bootstrap' in data['chain'] or
        'bootstrap-jinja' in data['chain'] or
        'bootstrap3-jinja' in data['chain'] or
        'bootstrap3' in data['chain']) and \
        'bootstrap3-gradients' not in data['chain']
    data['engine'] = utils.get_template_engine(data['chain'])
    data['chain'] = data['chain'][::-1]
    return data
Exemple #12
0
def test_get_asset_path():
    assert get_asset_path('assets/css/nikola_rst.css',
                          get_theme_chain('bootstrap4', ['themes'])).replace(
        '\\', '/').endswith('nikola/data/themes/base/assets/css/nikola_rst.css')
    assert get_asset_path('assets/css/theme.css',
                          get_theme_chain('bootstrap4', ['themes'])).replace(
        '\\', '/').endswith(
        'nikola/data/themes/bootstrap4/assets/css/theme.css')
    assert get_asset_path(
        'nikola.py', get_theme_chain('bootstrap4', ['themes']),
        {'nikola': ''}).replace(
        '\\', '/').endswith('nikola/nikola.py')
    assert get_asset_path('nikola.py', get_theme_chain(
        'bootstrap4', ['themes']), {'nikola': 'nikola'}) is None
    assert get_asset_path(
        'nikola/nikola.py', get_theme_chain('bootstrap4', ['themes']),
        {'nikola': 'nikola'}).replace(
        '\\', '/').endswith('nikola/nikola.py')
Exemple #13
0
def test_get_asset_path(path, files_folders, expected_path_end):
    theme_chain = get_theme_chain("bootstrap4", ["themes"])
    asset_path = get_asset_path(path, theme_chain, files_folders)

    if expected_path_end:
        asset_path = asset_path.replace("\\", "/")
        assert asset_path.endswith(expected_path_end)
    else:
        assert asset_path is None
Exemple #14
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        name = options['name']
        swatch = options['swatch']
        if not swatch:
            LOGGER.error('The -s option is mandatory')
            return 1
        parent = options['parent']
        version = '4'

        # Check which Bootstrap version to use
        themes = utils.get_theme_chain(parent, self.site.themes_dirs)
        if _check_for_theme('bootstrap', themes) or _check_for_theme(
                'bootstrap-jinja', themes):
            version = '2'
        elif _check_for_theme('bootstrap3', themes) or _check_for_theme(
                'bootstrap3-jinja', themes):
            version = '3'
        elif _check_for_theme('bootstrap4', themes) or _check_for_theme(
                'bootstrap4-jinja', themes):
            version = '4'
        elif not _check_for_theme('bootstrap4',
                                  themes) and not _check_for_theme(
                                      'bootstrap4-jinja', themes):
            LOGGER.warn(
                '"bootswatch_theme" only makes sense for themes that use bootstrap'
            )
        elif _check_for_theme('bootstrap3-gradients',
                              themes) or _check_for_theme(
                                  'bootstrap3-gradients-jinja', themes):
            LOGGER.warn(
                '"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family'
            )

        LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(
            name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = 'https://bootswatch.com'
            if version:
                url += '/' + version
            url = '/'.join((url, swatch, fname))
            LOGGER.info("Downloading: " + url)
            r = requests.get(url)
            if r.status_code > 299:
                LOGGER.error('Error {} getting {}', r.status_code, url)
                exit(1)
            data = r.text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data.encode('utf-8'))

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent.encode('utf-8'))
        LOGGER.notice(
            'Theme created.  Change the THEME setting to "{0}" to use it.'.
            format(name))
Exemple #15
0
    def new_theme(self, name, engine, parent, create_legacy_meta=False):
        """Create a new theme."""
        base = 'themes'
        themedir = os.path.join(base, name)
        LOGGER.info(
            "Creating theme {0} with parent {1} and engine {2} in {3}".format(
                name, parent, engine, themedir))
        if not os.path.exists(base):
            os.mkdir(base)
            LOGGER.info("Created directory {0}".format(base))

        # Check if engine and parent match
        parent_engine = utils.get_template_engine(
            utils.get_theme_chain(parent, self.site.themes_dirs))

        if parent_engine != engine:
            LOGGER.error(
                "Cannot use engine {0} because parent theme '{1}' uses {2}".
                format(engine, parent, parent_engine))
            return 2

        # Create theme
        if not os.path.exists(themedir):
            os.mkdir(themedir)
            LOGGER.info("Created directory {0}".format(themedir))
        else:
            LOGGER.error("Theme already exists")
            return 2

        cp = configparser.ConfigParser()
        cp['Theme'] = {'engine': engine, 'parent': parent}

        theme_meta_path = os.path.join(themedir, name + '.theme')
        with io.open(theme_meta_path, 'w', encoding='utf-8') as fh:
            cp.write(fh)
            LOGGER.info("Created file {0}".format(theme_meta_path))

        if create_legacy_meta:
            with io.open(os.path.join(themedir, 'parent'),
                         'w',
                         encoding='utf-8') as fh:
                fh.write(parent + '\n')
                LOGGER.info("Created file {0}".format(
                    os.path.join(themedir, 'parent')))
            with io.open(os.path.join(themedir, 'engine'),
                         'w',
                         encoding='utf-8') as fh:
                fh.write(engine + '\n')
                LOGGER.info("Created file {0}".format(
                    os.path.join(themedir, 'engine')))

        LOGGER.info("Theme {0} created successfully.".format(themedir))
        LOGGER.info(
            'Remember to set THEME="{0}" in conf.py to use this theme.'.format(
                name))
Exemple #16
0
def test_get_asset_path():
    assert get_asset_path(
        'assets/css/rst.css',
        get_theme_chain('bootstrap3', ['themes'])).replace(
            '\\', '/').endswith('nikola/data/themes/base/assets/css/rst.css')
    assert get_asset_path(
        'assets/css/theme.css',
        get_theme_chain('bootstrap3', ['themes'])).replace(
            '\\',
            '/').endswith('nikola/data/themes/bootstrap3/assets/css/theme.css')
    assert get_asset_path('nikola.py',
                          get_theme_chain('bootstrap3', ['themes']), {
                              'nikola': ''
                          }).replace('\\', '/').endswith('nikola/nikola.py')
    assert get_asset_path('nikola.py', get_theme_chain(
        'bootstrap3', ['themes']), {'nikola': 'nikola'}) is None
    assert get_asset_path('nikola/nikola.py',
                          get_theme_chain('bootstrap3', ['themes']), {
                              'nikola': 'nikola'
                          }).replace('\\', '/').endswith('nikola/nikola.py')
def parse_theme_info(post, pkg_dir, config):
    theme = os.path.basename(pkg_dir)
    data = {}
    data['name'] = theme
    out_path = post.folder_relative + '/' + theme
    demo_dir = config['demo_screenshots_map'].get(out_path, out_path)
    data['previewimage'] = '/' + demo_dir + '.png'
    data['previewimage_thumbnail'] = '/' + demo_dir + '.thumbnail.png'
    data['demo_link'] = '/' + demo_dir + '/demo/'
    conf_sample = os.path.join(pkg_dir, 'conf.py.sample')
    engine = os.path.join(pkg_dir, 'engine')
    parent = os.path.join(pkg_dir, 'parent')

    if os.path.exists(conf_sample):
        post.add_dependency(conf_sample)
        with io.open(conf_sample, 'r', encoding='utf-8') as f:
            data['confpy'] = pygments.highlight(
                f.read(),
                PythonLexer(), utils.NikolaPygmentsHTML(theme + '_conf_sample', linenos=False))
    else:
        data['confpy'] = None

    if os.path.exists(engine):
        post.add_dependency(engine)
        with io.open(engine, 'r', encoding='utf-8') as f:
            data['engine'] = f.read().strip()
    else:
        data['engine'] = 'mako'

    if os.path.exists(parent):
        post.add_dependency(parent)
        with io.open(parent, 'r', encoding='utf-8') as f:
            data['parent'] = f.read().strip()
    elif theme == 'base':
        pass
    else:
        raise ValueError("Theme {0} has no parent.".format(theme))

    data['chain'] = utils.get_theme_chain(theme, [os.path.dirname(pkg_dir), 'themes'])
    data['chain'] = [os.path.basename(i) for i in reversed(data['chain'])]
    data['bootswatch'] = (('bootstrap' in data['chain'] or
                           'bootstrap-jinja' in data['chain'] or
                           'bootstrap3-jinja' in data['chain'] or
                           'bootstrap3' in data['chain']) and
                          'bootstrap3-gradients' not in data['chain'])
    data['tags'] = 'theme,' + data['engine']

    return data
def sanity_check(theme=None):
    if theme is None:  # Check them all
        for theme in theme_list():
            sanity_check(theme)
        return
    themes = utils.get_theme_chain(theme, themes_dirs=['v7'])
    themes_bn = [os.path.basename(i) for i in themes]
    engine = utils.get_template_engine(themes)

    # Inheritance checks

    # All themes must inherit from base
    if themes_bn[-1] != 'base':
        error("theme {0} doesn't inherit from base".format(theme))
    # All jinja themes must inherit from base-jinja
    if engine == "jinja" and "base-jinja" not in themes_bn:
        error("theme {0} is jinja-based and doesn't inherit from base-jinja".format(theme))
    # All mako themes must NOT inherit from base-jinja
    if engine == "mako" and "base-jinja" in themes_bn:
        error("theme {0} is mako-based and inherits from base-jinja".format(theme))

    # Detect exact asset duplication in theme chain
    for root, dirs, files in os.walk("v7/"+theme):
        for f in files:
            path = "/".join([root, f])
            asset = path.split("/", 2)[-1]
            r, p1, p2 = is_asset_duplicated(asset, themes)
            if r:
                error("duplicated asset: {0} {1}".format(p1, p2))

    # Detect deprecated names and anonymous namespaces
    for root, dirs, files in os.walk("v7/"+theme+"/templates"):
        for f in files:
            path = "/".join([root, f])
            with io.open(path, "r", encoding="utf-8") as inf:
                data = inf.read()
            for k, exceptions in blacklist:
                if k in data and f not in exceptions:
                    error("theme '{0}' contains deprecated name '{1}' in {2}".format(theme, k, path))

    # Ensure the theme has a README.md
    if utils.get_asset_path('README.md', themes) is None:
        error("theme '{0}' has no README.md".format(theme))

    # Ensure the theme has a meta file
    if utils.get_asset_path(theme + '.theme', themes) is None:
        warning("theme '{0}' has no {0}.theme meta file".format(theme))
Exemple #19
0
def get_data(theme):
    data = {}
    data['name'] = theme
    readme = utils.get_asset_path('README', [theme])
    if readme:
        data['readme'] = open(readme).read()
    else:
        data['readme'] = 'No readme file available'
    data['chain'] = utils.get_theme_chain(theme)
    data['bootswatch'] = ('bootstrap' in data['chain'] or
        'bootstrap-jinja' in data['chain'] or
        'bootstrap3-jinja' in data['chain'] or
        'bootstrap3' in data['chain']) and \
        'bootstrap3-gradients' not in data['chain']
    data['engine'] = utils.get_template_engine(data['chain'])
    data['chain'] = data['chain'][::-1]
    return data
Exemple #20
0
    def new_theme(self, name, engine, parent):
        """Create a new theme."""
        base = 'themes'
        themedir = os.path.join(base, name)
        LOGGER.info(
            "Creating theme {0} with parent {1} and engine {2} in {3}".format(
                name, parent, engine, themedir))
        if not os.path.exists(base):
            os.mkdir(base)
            LOGGER.info("Created directory {0}".format(base))

        # Check if engine and parent match
        engine_file = utils.get_asset_path(
            'engine', utils.get_theme_chain(parent, self.site.themes_dirs))
        with io.open(engine_file, 'r', encoding='utf-8') as fh:
            parent_engine = fh.read().strip()

        if parent_engine != engine:
            LOGGER.error(
                "Cannot use engine {0} because parent theme '{1}' uses {2}".
                format(engine, parent, parent_engine))
            return 2

        # Create theme
        if not os.path.exists(themedir):
            os.mkdir(themedir)
            LOGGER.info("Created directory {0}".format(themedir))
        else:
            LOGGER.error("Theme already exists")
            return 2

        with io.open(os.path.join(themedir, 'parent'), 'w',
                     encoding='utf-8') as fh:
            fh.write(parent + '\n')
            LOGGER.info("Created file {0}".format(
                os.path.join(themedir, 'parent')))
        with io.open(os.path.join(themedir, 'engine'), 'w',
                     encoding='utf-8') as fh:
            fh.write(engine + '\n')
            LOGGER.info("Created file {0}".format(
                os.path.join(themedir, 'engine')))

        LOGGER.info("Theme {0} created successfully.".format(themedir))
        LOGGER.notice(
            'Remember to set THEME="{0}" in conf.py to use this theme.'.format(
                name))
Exemple #21
0
    def new_theme(self, name, engine, parent, create_legacy_meta=False):
        """Create a new theme."""
        base = 'themes'
        themedir = os.path.join(base, name)
        LOGGER.info("Creating theme {0} with parent {1} and engine {2} in {3}".format(name, parent, engine, themedir))
        if not os.path.exists(base):
            os.mkdir(base)
            LOGGER.info("Created directory {0}".format(base))

        # Check if engine and parent match
        parent_engine = utils.get_template_engine(utils.get_theme_chain(parent, self.site.themes_dirs))

        if parent_engine != engine:
            LOGGER.error("Cannot use engine {0} because parent theme '{1}' uses {2}".format(engine, parent, parent_engine))
            return 2

        # Create theme
        if not os.path.exists(themedir):
            os.mkdir(themedir)
            LOGGER.info("Created directory {0}".format(themedir))
        else:
            LOGGER.error("Theme already exists")
            return 2

        cp = configparser.ConfigParser()
        cp['Theme'] = {
            'engine': engine,
            'parent': parent
        }

        theme_meta_path = os.path.join(themedir, name + '.theme')
        with io.open(theme_meta_path, 'w', encoding='utf-8') as fh:
            cp.write(fh)
            LOGGER.info("Created file {0}".format(theme_meta_path))

        if create_legacy_meta:
            with io.open(os.path.join(themedir, 'parent'), 'w', encoding='utf-8') as fh:
                fh.write(parent + '\n')
                LOGGER.info("Created file {0}".format(os.path.join(themedir, 'parent')))
            with io.open(os.path.join(themedir, 'engine'), 'w', encoding='utf-8') as fh:
                fh.write(engine + '\n')
                LOGGER.info("Created file {0}".format(os.path.join(themedir, 'engine')))

        LOGGER.info("Theme {0} created successfully.".format(themedir))
        LOGGER.notice('Remember to set THEME="{0}" in conf.py to use this theme.'.format(name))
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        name = options['name']
        swatch = options['swatch']
        if not swatch:
            LOGGER.error('The -s option is mandatory')
            return 1
        parent = options['parent']
        version = '4'

        # Check which Bootstrap version to use
        themes = utils.get_theme_chain(parent, self.site.themes_dirs)
        if _check_for_theme('bootstrap', themes) or _check_for_theme('bootstrap-jinja', themes):
            version = '2'
        elif _check_for_theme('bootstrap3', themes) or _check_for_theme('bootstrap3-jinja', themes):
            version = '3'
        elif _check_for_theme('bootstrap4', themes) or _check_for_theme('bootstrap4-jinja', themes):
            version = '4'
        elif not _check_for_theme('bootstrap4', themes) and not _check_for_theme('bootstrap4-jinja', themes):
            LOGGER.warn('"bootswatch_theme" only makes sense for themes that use bootstrap')
        elif _check_for_theme('bootstrap3-gradients', themes) or _check_for_theme('bootstrap3-gradients-jinja', themes):
            LOGGER.warn('"bootswatch_theme" doesn\'t work well with the bootstrap3-gradients family')

        LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = 'https://bootswatch.com'
            if version:
                url += '/' + version
            url = '/'.join((url, swatch, fname))
            LOGGER.info("Downloading: " + url)
            r = requests.get(url)
            if r.status_code > 299:
                LOGGER.error('Error {} getting {}', r.status_code, url)
                exit(1)
            data = r.text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data.encode('utf-8'))

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent.encode('utf-8'))
        LOGGER.notice('Theme created.  Change the THEME setting to "{0}" to use it.'.format(name))
Exemple #23
0
def init_theme(theme):
    t_path = "/".join(["sites", theme])
    o_path = os.path.abspath("/".join(["output", "v6", theme]))
    if os.path.isdir(t_path):
        shutil.rmtree(t_path)
    if os.path.isdir(o_path):
        shutil.rmtree(o_path)
    subprocess.check_call(["nikola", "init", "--demo", t_path], stdout=subprocess.PIPE)
    os.symlink(os.path.abspath("themes"), os.path.abspath("/".join([t_path, "themes"])))

    conf_path = "/".join([t_path,"conf.py"])
    # Get custom required settings from the theme
    themes = utils.get_theme_chain(theme)
    extra_conf_path = utils.get_asset_path('conf.py.sample', themes)
    extra_conf = ''
    if extra_conf_path:
        extra_conf = open(extra_conf_path, 'r').read()

    with codecs.open(conf_path, "a", "utf-8") as conf:
        conf.write("\n\n{2}\n\nTHEME = '{0}'\n\nOUTPUT_FOLDER = '{1}'\n\nSOCIAL_BUTTONS_CODE = ''\n".format(theme, o_path, extra_conf))
Exemple #24
0
def read_theme(theme):
    # Gather this theme's data
    theme_name = os.path.basename(theme)
    data = {}
    data['name'] = theme_name
    readme = os.path.join(theme, 'README.md')
    if os.path.isfile(readme):
        with codecs.open(readme, 'r', 'utf8') as inf:
            data['readme'] = inf.read()
    else:
        data['readme'] = ''

    themes = utils.get_theme_chain(theme_name)
    data['engine'] = utils.get_template_engine(themes)

    if 'bootstrap3' in themes:
        data['bs_version'] = 3
    elif 'bootstrap' in themes:
        data['bs_version'] = 2
    else:
        data['bs_version'] = 0
Exemple #25
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        if requests is None:
            print(
                'To use the bootswatch_theme command, you need to install the '
                '"requests" package.')
            return

        name = options['name']
        swatch = options['swatch']
        parent = options['parent']

        # See if we need bootswatch v2 or v3
        themes = utils.get_theme_chain(parent)
        version = '2'
        if 'bootstrap3' in themes:
            version = ''
        elif 'bootstrap' not in themes:
            print(
                'WARNING: bootswatch_theme only makes sense for themes that use bootstrap'
            )

        print("Creating '{0}' theme from '{1}' and '{2}'".format(
            name, swatch, parent))
        try:
            os.makedirs(os.path.join('themes', name, 'assets', 'css'))
        except:
            pass
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = '/'.join(('http://bootswatch.com', version, swatch, fname))
            print("Downloading: ", url)
            data = requests.get(url).text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data)

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent)
        print('Theme created. Change the THEME setting to "{0}" to use '
              'it.'.format(name))
Exemple #26
0
def read_theme(theme):
    # Gather this theme's data
    theme_name = os.path.basename(theme)
    data = {}
    data['name'] = theme_name
    readme = os.path.join(theme, 'README.md')
    if os.path.isfile(readme):
        with codecs.open(readme, 'r', 'utf8') as inf:
            data['readme'] = inf.read()
    else:
        data['readme'] = ''

    themes = utils.get_theme_chain(theme_name)
    data['engine'] = utils.get_template_engine(themes)


    if 'bootstrap3' in themes:
        data['bs_version'] = 3
    elif 'bootstrap' in themes:
        data['bs_version'] = 2
    else:
        data['bs_version'] = 0
Exemple #27
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        if requests is None:
            print('To use the bootswatch_theme command, you need to install the '
                  '"requests" package.')
            return

        name = options['name']
        swatch = options['swatch']
        parent = options['parent']
        version = ''

        # See if we need bootswatch for bootstrap v2 or v3
        themes = utils.get_theme_chain(parent)
        if 'bootstrap3' not in themes:
            version = '2'
        elif 'bootstrap' not in themes:
            print('WARNING: bootswatch_theme only makes sense for themes that use bootstrap')

        print("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch,
                                                                 parent))
        try:
            os.makedirs(os.path.join('themes', name, 'assets', 'css'))
        except:
            pass
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            url = '/'.join(('http://bootswatch.com', version, swatch, fname))
            print("Downloading: ", url)
            data = requests.get(url).text
            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'wb+') as output:
                output.write(data.encode('utf-8'))

        with open(os.path.join('themes', name, 'parent'), 'wb+') as output:
            output.write(parent.encode('utf-8'))
        print('Theme created. Change the THEME setting to "{0}" to use '
              'it.'.format(name))
def init_theme(theme):
    t_path = "/".join(["sites", theme])
    o_path = os.path.abspath("/".join(["output", "v7", theme]))
    if os.path.isdir(t_path):
        shutil.rmtree(t_path)
    if os.path.isdir(o_path):
        shutil.rmtree(o_path)
    subprocess.check_call(["nikola", "init", "-qd", t_path], stdout=subprocess.PIPE)
    os.symlink(os.path.abspath("v7"), os.path.abspath("/".join([t_path, "themes"])))

    conf_path = "/".join([t_path, "conf.py"])
    # Get custom required settings from the theme
    themes = utils.get_theme_chain(theme, _themes_dir="v7")
    extra_conf_path = utils.get_asset_path("conf.py.sample", themes, _themes_dir="v7")
    extra_conf = ""
    if extra_conf_path:
        extra_conf = io.open(extra_conf_path, "r", encoding="utf-8").read()

    with io.open(conf_path, "a", encoding="utf-8") as conf:
        conf.write(
            "\n\n{2}\n\nTHEME = '{0}'\n\nUSE_BUNDLES = False\n\nOUTPUT_FOLDER = '{1}'\n\nSOCIAL_BUTTONS_CODE = ''\nUSE_BASE_TAG = False\n".format(
                theme, o_path, extra_conf
            )
        )
Exemple #29
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        name = options['name']
        swatch = options['swatch']
        if not swatch:
            LOGGER.error('The -s option is mandatory')
            return 1
        parent = options['parent']
        version = '4'

        # Check which Bootstrap version to use
        themes = utils.get_theme_chain(parent, self.site.themes_dirs)
        if _check_for_theme('bootstrap', themes) or _check_for_theme('bootstrap-jinja', themes):
            version = '2'
        elif _check_for_theme('bootstrap3', themes) or _check_for_theme('bootstrap3-jinja', themes):
            version = '3'
        elif _check_for_theme('bootstrap4', themes) or _check_for_theme('bootstrap4-jinja', themes):
            version = '4'
        elif not _check_for_theme('bootstrap4', themes) and not _check_for_theme('bootstrap4-jinja', themes):
            LOGGER.warning(
                '"subtheme" only makes sense for themes that use bootstrap')
        elif _check_for_theme('bootstrap3-gradients', themes) or _check_for_theme('bootstrap3-gradients-jinja', themes):
            LOGGER.warning(
                '"subtheme" doesn\'t work well with the bootstrap3-gradients family')

        LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(
            name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            if swatch in [
                    'bubblegum', 'business-tycoon', 'charming', 'daydream',
                    'executive-suite', 'good-news', 'growth', 'harbor', 'hello-world',
                    'neon-glow', 'pleasant', 'retro', 'vibrant-sea', 'wizardry']:  # Hackerthemes
                LOGGER.info(
                    'Hackertheme-based subthemes often require you use a custom font for full effect.')
                if version != '4':
                    LOGGER.error(
                        'The hackertheme subthemes are only available for Bootstrap 4.')
                    return 1
                if fname == 'bootstrap.css':
                    url = 'https://raw.githubusercontent.com/HackerThemes/theme-machine/master/dist/{swatch}/css/bootstrap4-{swatch}.css'.format(
                        swatch=swatch)
                else:
                    url = 'https://raw.githubusercontent.com/HackerThemes/theme-machine/master/dist/{swatch}/css/bootstrap4-{swatch}.min.css'.format(
                        swatch=swatch)
            else:  # Bootswatch
                url = 'https://bootswatch.com'
                if version:
                    url += '/' + version
                url = '/'.join((url, swatch, fname))
            LOGGER.info("Downloading: " + url)
            r = requests.get(url)
            if r.status_code > 299:
                LOGGER.error('Error {} getting {}', r.status_code, url)
                return 1
            data = r.text

            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'w+') as output:
                output.write(data)

        with open(os.path.join('themes', name, '%s.theme' % name), 'w+') as output:
            parent_theme_data_path = utils.get_asset_path(
                '%s.theme' % parent, themes)
            cp = configparser.ConfigParser()
            cp.read(parent_theme_data_path)
            cp['Theme']['parent'] = parent
            cp['Family'] = {'family': cp['Family']['family']}
            cp.write(output)

        LOGGER.info(
            'Theme created.  Change the THEME setting to "{0}" to use it.'.format(name))
Exemple #30
0
    def _execute(self, options, args):
        """Given a swatch name and a parent theme, creates a custom theme."""
        name = options['name']
        swatch = options['swatch']
        if not swatch:
            LOGGER.error('The -s option is mandatory')
            return 1
        parent = options['parent']
        version = '4'

        # Check which Bootstrap version to use
        themes = utils.get_theme_chain(parent, self.site.themes_dirs)
        if _check_for_theme('bootstrap', themes) or _check_for_theme('bootstrap-jinja', themes):
            version = '2'
        elif _check_for_theme('bootstrap3', themes) or _check_for_theme('bootstrap3-jinja', themes):
            version = '3'
        elif _check_for_theme('bootstrap4', themes) or _check_for_theme('bootstrap4-jinja', themes):
            version = '4'
        elif not _check_for_theme('bootstrap4', themes) and not _check_for_theme('bootstrap4-jinja', themes):
            LOGGER.warn(
                '"subtheme" only makes sense for themes that use bootstrap')
        elif _check_for_theme('bootstrap3-gradients', themes) or _check_for_theme('bootstrap3-gradients-jinja', themes):
            LOGGER.warn(
                '"subtheme" doesn\'t work well with the bootstrap3-gradients family')

        LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(
            name, swatch, parent))
        utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
        for fname in ('bootstrap.min.css', 'bootstrap.css'):
            if swatch in [
                    'bubblegum', 'business-tycoon', 'charming', 'daydream',
                    'executive-suite', 'good-news', 'growth', 'harbor', 'hello-world',
                    'neon-glow', 'pleasant', 'retro', 'vibrant-sea', 'wizardry']:  # Hackerthemes
                LOGGER.info(
                    'Hackertheme-based subthemes often require you use a custom font for full effect.')
                if version != '4':
                    LOGGER.error(
                        'The hackertheme subthemes are only available for Bootstrap 4.')
                    return 1
                if fname == 'bootstrap.css':
                    url = 'https://raw.githubusercontent.com/HackerThemes/theme-machine/master/dist/{swatch}/css/bootstrap4-{swatch}.css'.format(
                        swatch=swatch)
                else:
                    url = 'https://raw.githubusercontent.com/HackerThemes/theme-machine/master/dist/{swatch}/css/bootstrap4-{swatch}.min.css'.format(
                        swatch=swatch)
            else:  # Bootswatch
                url = 'https://bootswatch.com'
                if version:
                    url += '/' + version
                url = '/'.join((url, swatch, fname))
            LOGGER.info("Downloading: " + url)
            r = requests.get(url)
            if r.status_code > 299:
                LOGGER.error('Error {} getting {}', r.status_code, url)
                return 1
            data = r.text

            with open(os.path.join('themes', name, 'assets', 'css', fname),
                      'w+') as output:
                output.write(data)

        with open(os.path.join('themes', name, '%s.theme' % name), 'w+') as output:
            parent_theme_data_path = utils.get_asset_path(
                '%s.theme' % parent, themes)
            cp = configparser.ConfigParser()
            cp.read(parent_theme_data_path)
            cp['Theme']['parent'] = parent
            cp['Family'] = {'family': cp['Family']['family']}
            cp.write(output)

        LOGGER.notice(
            'Theme created.  Change the THEME setting to "{0}" to use it.'.format(name))
Exemple #31
0
def parse_theme_info(post, pkg_dir, config):
    theme = os.path.basename(pkg_dir)
    data = {}
    data['name'] = theme
    out_path = post.folder_relative + '/' + theme
    demo_dir = config['demo_screenshots_map'].get(out_path, out_path)
    data['previewimage'] = '/' + demo_dir + '.png'
    data['previewimage_thumbnail'] = '/' + demo_dir + '.thumbnail.png'
    data['demo_link'] = '/' + demo_dir + '/demo/'
    conf_sample = os.path.join(pkg_dir, 'conf.py.sample')
    ini = os.path.join(pkg_dir, theme + '.theme')
    engine = os.path.join(pkg_dir, 'engine')
    parent = os.path.join(pkg_dir, 'parent')

    data['chain'] = utils.get_theme_chain(theme, [os.path.dirname(pkg_dir), 'themes'])
    data['chain'] = [os.path.basename(i) for i in reversed(data['chain'])]

    if os.path.exists(conf_sample):
        post.add_dependency(conf_sample)
        with io.open(conf_sample, 'r', encoding='utf-8') as f:
            data['confpy'] = pygments.highlight(
                f.read(),
                PythonLexer(), utils.NikolaPygmentsHTML(theme + '_conf_sample', linenos=False))
    else:
        data['confpy'] = None

    if os.path.exists(ini):
        post.add_dependency(ini)
        c = configparser.ConfigParser()
        c.read(ini)
        data['parent'] = c.get('Theme', 'parent', fallback=None)
        data['engine'] = c.get('Theme', 'engine', fallback='mako')
        data['bootswatch'] = c.getboolean('Nikola', 'bootswatch', fallback=False)
        data['tags'] = 'theme,' + data['engine']
        theme_tags = c.get('Theme', 'tags', fallback='')
        if theme_tags:
            data['tags'] += ',' + theme_tags

        if data['parent'] is None and theme != 'base':
            raise ValueError("Theme {0} has no parent.".format(theme))
    else:
        if os.path.exists(engine):
            post.add_dependency(engine)
            with io.open(engine, 'r', encoding='utf-8') as f:
                data['engine'] = f.read().strip()
        else:
            data['engine'] = 'mako'

        if os.path.exists(parent):
            post.add_dependency(parent)
            with io.open(parent, 'r', encoding='utf-8') as f:
                data['parent'] = f.read().strip()
        elif theme == 'base':
            pass
        else:
            raise ValueError("Theme {0} has no parent.".format(theme))
        data['bootswatch'] = (('bootstrap' in data['chain'] or
                               'bootstrap-jinja' in data['chain'] or
                               'bootstrap3-jinja' in data['chain'] or
                               'bootstrap3' in data['chain']) and
                              'bootstrap3-gradients' not in data['chain'])
        data['tags'] = 'theme,' + data['engine']

    return data
def parse_theme_info(post, pkg_dir, config):
    theme = os.path.basename(pkg_dir)
    data = {}
    data['name'] = theme
    out_path = post.folder_relative + '/' + theme
    demo_dir = config['demo_screenshots_map'].get(out_path, out_path)
    data['previewimage'] = '/' + demo_dir + '.png'
    data['previewimage_thumbnail'] = '/' + demo_dir + '.thumbnail.png'
    data['demo_link'] = '/' + demo_dir + '/demo/'
    conf_sample = os.path.join(pkg_dir, 'conf.py.sample')
    ini = os.path.join(pkg_dir, theme + '.theme')
    engine = os.path.join(pkg_dir, 'engine')
    parent = os.path.join(pkg_dir, 'parent')

    data['chain'] = utils.get_theme_chain(theme,
                                          [os.path.dirname(pkg_dir), 'themes'])
    data['chain'] = [os.path.basename(i) for i in reversed(data['chain'])]

    if os.path.exists(conf_sample):
        post.add_dependency(conf_sample)
        with io.open(conf_sample, 'r', encoding='utf-8') as f:
            data['confpy'] = pygments.highlight(
                f.read(), PythonLexer(),
                utils.NikolaPygmentsHTML(theme + '_conf_sample',
                                         linenos=False))
    else:
        data['confpy'] = None

    if os.path.exists(ini):
        post.add_dependency(ini)
        c = configparser.ConfigParser()
        c.read(ini)
        data['parent'] = c.get('Theme', 'parent', fallback=None)
        data['engine'] = c.get('Theme', 'engine', fallback='mako')
        data['family'] = c.get('Family', 'family', fallback=theme)
        data['family_head'] = data['family'] == theme
        if data['engine'] == 'mako':
            data['family_mako_version'] = theme
            _other = c.get('Family', 'jinja_version', fallback=None)
            data['family_jinja_version'] = _other
            data['show_family_data'] = bool(_other)
        else:
            data['family_jinja_version'] = theme
            _other = c.get('Family', 'mako_version', fallback=None)
            data['family_mako_version'] = _other
            data['show_family_data'] = bool(_other)

        data['family_variants'] = [
            i.strip()
            for i in c.get('Family', 'variants', fallback='').split(',')
        ]
        data['family_variants'] = [i for i in data['family_variants']
                                   if i]  # remove empty strings
        _variants_count = len(data['family_variants'])
        data[
            'family_variants_text'] = '1 variant' if _variants_count == 1 else '{0} variants'.format(
                _variants_count)

        data['show_family_data'] = data['show_family_data'] or bool(
            data['family_variants'])
        data['bootswatch'] = c.getboolean('Nikola',
                                          'bootswatch',
                                          fallback=False)
        data['tags'] = 'newmeta,theme,' + data['engine']
        data['license'] = c.get('Theme', 'license', fallback=None)
        data['author'] = c.get('Theme', 'author', fallback=None)
        data['author_url'] = c.get('Theme', 'author_url', fallback=None)
        data['author_url'] = c.get('Theme', 'author_url', fallback=None)
        based_on = c.get('Theme', 'based_on', fallback=None)
        based_on_list = []
        if based_on:
            for i in based_on.split(','):
                i = i.strip()
                m = re.match("(.*?) ?<(.*?)>", i)
                if m:
                    based_on_list.append('<a href="{0[1]}">{0[0]}</a>'.format(
                        m.groups()))
                else:
                    based_on_list.append(i)

        data['based_on'] = ', '.join(based_on_list)

        theme_tags = c.get('Theme', 'tags', fallback='')
        if theme_tags:
            data['tags'] += ',' + theme_tags

        if data['parent'] is None and theme != 'base':
            raise ValueError("Theme {0} has no parent.".format(theme))
    else:
        # Old-style metadata
        if os.path.exists(engine):
            post.add_dependency(engine)
            with io.open(engine, 'r', encoding='utf-8') as f:
                data['engine'] = f.read().strip()
        else:
            data['engine'] = 'mako'

        if os.path.exists(parent):
            post.add_dependency(parent)
            with io.open(parent, 'r', encoding='utf-8') as f:
                data['parent'] = f.read().strip()
        elif theme == 'base':
            pass
        else:
            raise ValueError("Theme {0} has no parent.".format(theme))
        data['bootswatch'] = (('bootstrap' in data['chain']
                               or 'bootstrap-jinja' in data['chain']
                               or 'bootstrap3-jinja' in data['chain']
                               or 'bootstrap3' in data['chain'])
                              and 'bootstrap3-gradients' not in data['chain'])
        data['tags'] = 'theme,' + data['engine']
        data['family'] = theme
        data['family_head'] = True
        data['family_{0}_version'.format(data['engine'])] = theme

    return data
def parse_theme_info(post, pkg_dir, config):
    theme = os.path.basename(pkg_dir)
    data = {}
    data['name'] = theme
    out_path = post.folder_relative + '/' + theme
    demo_dir = config['demo_screenshots_map'].get(out_path, out_path)
    data['previewimage'] = '/' + demo_dir + '.png'
    data['previewimage_thumbnail'] = '/' + demo_dir + '.thumbnail.png'
    data['demo_link'] = '/' + demo_dir + '/demo/'
    conf_sample = os.path.join(pkg_dir, 'conf.py.sample')
    ini = os.path.join(pkg_dir, theme + '.theme')
    engine = os.path.join(pkg_dir, 'engine')
    parent = os.path.join(pkg_dir, 'parent')

    data['chain'] = utils.get_theme_chain(theme, [os.path.dirname(pkg_dir), 'themes'])
    data['chain'] = [os.path.basename(i) for i in reversed(data['chain'])]

    try:
        data['dirver'] = _version_from_path(pkg_dir)
    except Exception:
        data['dirver'] = config['versions_supported'][-1]
    data['slug_versioned'] = 'v{0}/{1}'.format(data['dirver'], theme)
    data['slug_sortable'] = '{1} v{0}'.format(data['dirver'], theme)
    data['allver'] = range(data['dirver'], config['versions_supported'][-1] + 1)

    if os.path.exists(conf_sample):
        post.add_dependency(conf_sample)
        with io.open(conf_sample, 'r', encoding='utf-8') as f:
            data['confpy'] = pygments.highlight(
                f.read(),
                PythonLexer(), utils.NikolaPygmentsHTML(theme + '_conf_sample', linenos=False))
    else:
        data['confpy'] = None

    if os.path.exists(ini):
        post.add_dependency(ini)
        c = configparser.ConfigParser()
        c.read(ini)
        data['parent'] = c.get('Theme', 'parent', fallback=None)
        data['engine'] = c.get('Theme', 'engine', fallback='mako')
        data['family'] = c.get('Family', 'family', fallback=theme)
        data['family_head'] = data['family'] == theme
        if data['engine'] == 'mako':
            data['family_mako_version'] = theme
            _other = c.get('Family', 'jinja_version', fallback=None)
            data['family_jinja_version'] = _other
            data['show_family_data'] = bool(_other)
        else:
            data['family_jinja_version'] = theme
            _other = c.get('Family', 'mako_version', fallback=None)
            data['family_mako_version'] = _other
            data['show_family_data'] = bool(_other)

        data['family_variants'] = [i.strip() for i in c.get('Family', 'variants', fallback='').split(',')]
        data['family_variants'] = [i for i in data['family_variants'] if i]  # remove empty strings
        _variants_count = len(data['family_variants'])
        data['family_variants_text'] = '1 variant' if _variants_count == 1 else '{0} variants'.format(_variants_count)

        data['show_family_data'] = data['show_family_data'] or bool(data['family_variants']) or not data['family_head']
        data['bootswatch'] = c.getboolean('Nikola', 'bootswatch', fallback=False)
        data['tags'] = 'newmeta,theme,' + data['engine'] + ',v{0}'.format(data['dirver'])
        data['license'] = c.get('Theme', 'license', fallback=None)
        data['author'] = c.get('Theme', 'author', fallback=None)
        data['author_url'] = c.get('Theme', 'author_url', fallback=None)
        data['author_url'] = c.get('Theme', 'author_url', fallback=None)
        based_on = c.get('Theme', 'based_on', fallback=None)
        based_on_list = []
        if based_on:
            for i in based_on.split(','):
                i = i.strip()
                m = re.match("(.*?) ?<(.*?)>", i)
                if m:
                    based_on_list.append('<a href="{0[1]}">{0[0]}</a>'.format(
                        m.groups()))
                else:
                    based_on_list.append(i)

        data['based_on'] = ', '.join(based_on_list)

        theme_tags = c.get('Theme', 'tags', fallback='')
        if theme_tags:
            data['tags'] += ',' + theme_tags

        if data['parent'] is None and theme != 'base':
            raise ValueError("Theme {0} has no parent.".format(theme))
    else:
        # Old-style metadata
        if os.path.exists(engine):
            post.add_dependency(engine)
            with io.open(engine, 'r', encoding='utf-8') as f:
                data['engine'] = f.read().strip()
        else:
            data['engine'] = 'mako'

        if os.path.exists(parent):
            post.add_dependency(parent)
            with io.open(parent, 'r', encoding='utf-8') as f:
                data['parent'] = f.read().strip()
        elif theme == 'base':
            pass
        else:
            raise ValueError("Theme {0} has no parent.".format(theme))
        data['bootswatch'] = (('bootstrap' in data['chain'] or
                               'bootstrap-jinja' in data['chain'] or
                               'bootstrap3-jinja' in data['chain'] or
                               'bootstrap3' in data['chain']) and
                              'bootstrap3-gradients' not in data['chain'])
        data['tags'] = 'theme,' + data['engine'] + ',v{0}'.format(data['dirver'])
        data['family'] = theme
        data['family_head'] = True
        data['family_{0}_version'.format(data['engine'])] = theme

    return data