import os, re
from distutils import util
from distutils.core import Command
from distutils.errors import DistutilsModuleError
from distutils.version import StrictVersion
 
MINIMUM_VERSION = StrictVersion('0.8.0b2')
 
class GenerateBisonGen(Command):
 
    command_name = 'generate_bgen'
 
    description = "regenerate BisonGen parsers"
 
    user_options = [
        ('force', 'f',
         'force rebuild (ignore timestamps)'),
        ]
 
    boolean_options = ['force']
 
    def initialize_options(self):
        self.bgen_files = None
        self.force = 0
 
    def finalize_options(self):
        self.set_undefined_options('generate', ('force', 'force'))
        self.bgen_files = self.distribution.bgen_files
 
    _include_re = re.compile('<\?include (?P<file>.*(?=\?>))\?>')
    def _find_includes(self, file):
        includes = []
        source = open(file).read()
        base = os.path.dirname(file)
 
        match = self._include_re.search(source)
        while match:
            filename = util.convert_path(match.group('file'))
            include = os.path.normpath(os.path.join(base, filename))
            includes.append(include)
            includes.extend(self._find_includes(include))
            match = self._include_re.search(source, match.end())
        return includes
 
    def get_source_files(self):
        sources = []
        for filename in self.bgen_files:
            sources.append(filename)
            includes = self._find_includes(filename)
            for filename in includes:
                if filename not in sources:
                    sources.append(filename)
        return sources
 
    def get_outputs(self):
        return []
 
    def run(self):
        if not self.bgen_files:
            return
 
        try:
            from BisonGen import Main, __version__
        except ImportError, err:
            failure = str(err)
        else:
            if MINIMUM_VERSION > StrictVersion(__version__):
                failure = "found " + __version__
            else:
                failure = None
 
        if failure:
            msg = "%s requires BisonGen %s (%s)" % (self.command_name,
                                                    MINIMUM_VERSION, failure)
            raise DistutilsModuleError(msg)
 
        outputs = []
        args = ['BisonGen', '--mode=c']
        if self.force:
            args.append('--force')
        if not self.distribution.verbose:
            args.append('--quiet')
        for filename in self.bgen_files:
            outputs.extend(Main.Run(args + [filename]))
        return