nicoulaj/rainbow

View on GitHub
rainbow/build.py

Summary

Maintainability
A
1 hr
Test Coverage
A
92%
# ----------------------------------------------------------------------
# rainbow, a terminal colorizer - https://github.com/nicoulaj/rainbow
# copyright (c) 2010-2018 rainbow contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------

import errno

import gzip
import logging
import os
import shutil
from distutils.command.build import build
from distutils.command.clean import clean
from distutils.core import Command
from distutils.dir_util import remove_tree
from distutils.errors import DistutilsOptionError

from .filter import FILTERS, FILTER_GROUPS


class Build(build):  # no cover
    def run(self):
        self.run_command("build_completion_bash")
        self.run_command("build_completion_zsh")
        self.run_command("build_man_page")
        build.run(self)


class Clean(clean):  # no cover

    def __init__(self, dist):
        clean.__init__(self, dist)
        self.user_options += [
            ('paths=', 'p', 'paths'),
        ]

    def initialize_options(self):
        super(clean, self).initialize_options()
        self.paths = None

    def finalize_options(self):
        clean.finalize_options(self)
        if self.paths is None:  # no cover
            raise DistutilsOptionError('"paths" option is required')

    def run(self):
        clean.run(self)
        if self.all:
            for path in [path.strip() for path in self.paths.split(',')]:
                if os.path.isdir(path):
                    remove_tree(path)
                elif os.path.isfile(path):
                    self.announce("removing '%s'" % path)
                    os.remove(path)
                else:
                    self.announce("'%s' does not exist -- can't clean it" % path)


class GenerateCompletion(Command):
    description = 'Generate shell completion script.'

    user_options = [
        ('shell=', 'S', 'shell (bash or zsh)'),
        ('output=', 'O', 'output file')
    ]

    def initialize_options(self):
        self.shell = None
        self.output = None

    def finalize_options(self):
        if self.shell is None:  # no cover
            raise DistutilsOptionError('"shell" option is required')
        if self.output is None:  # no cover
            raise DistutilsOptionError('"output" option is required')

    def run(self):
        self.announce('generating %s completion -> %s' % (self.shell, self.output))

        makeparentdirs(self.output)

        try:
            from jinja2 import Environment, FileSystemLoader
            Environment(loader=FileSystemLoader('templates')) \
                .get_template('completion.%s' % self.shell) \
                .stream(filters=FILTERS) \
                .dump(self.output)
        except ImportError:
            logging.warning('Jinja is not installed, skipping %s completion generation' % self.shell)


class GenerateManPage(Command):
    description = 'Generate man page.'

    user_options = [
        ('output=', 'O', 'output file')
    ]

    def initialize_options(self):
        self.output = None

    def finalize_options(self):
        if self.output is None:  # no cover
            raise DistutilsOptionError('"output" option is required')

    def run(self):
        self.announce('generating man page -> %s' % self.output)

        makeparentdirs(self.output)

        try:
            from jinja2 import Environment, FileSystemLoader
            Environment(loader=FileSystemLoader('templates')) \
                .get_template('rainbow.man') \
                .stream(filter_groups=FILTER_GROUPS) \
                .dump(self.output)

            file_in = None
            file_out = None
            try:
                file_in = open(self.output, 'rb')
                file_out = gzip.open(self.output + '.gz', 'wb')
                shutil.copyfileobj(file_in, file_out)
            finally:
                if file_in:
                    file_in.close()
                if file_out:
                    file_out.close()
        except ImportError:
            logging.warning('Jinja is not installed, skipping man page generation')


def makeparentdirs(path):
    directory = os.path.dirname(path)
    if not os.path.exists(directory):  # no cover
        try:
            os.makedirs(directory)
        except OSError as e:
            if e.errno != errno.EEXIST:
                raise