Exemple #1
0
def _find_mupdf():
    _mupdf['found'] = False
    _mupdf['version'] = None
    _mupdf['mutool'] = []
    _mupdf['mudraw'] = []
    _mupdf['mudraw_trace_args'] = []
    if (mutool := process.find_executable(('mutool', ))) is None:
        return log.debug('mutool executable not found')
Exemple #2
0
 def is_available():
     global _pdf_possible
     if _pdf_possible is not None:
         return _pdf_possible
     global _mutool_exec, _mudraw_exec, _mudraw_trace_args
     mutool = process.find_executable((u'mutool', ))
     _pdf_possible = False
     version = None
     if mutool is None:
         log.debug('mutool executable not found')
     else:
         _mutool_exec = [mutool]
         # Find MuPDF version; assume 1.6 version since
         # the '-v' switch is only supported from 1.7 onward...
         version = '1.6'
         proc = process.popen([mutool, '-v'],
                              stdout=process.NULL,
                              stderr=process.PIPE)
         try:
             output = proc.stderr.read()
             if output.startswith('mutool version '):
                 version = output[15:].rstrip()
         finally:
             proc.stderr.close()
             proc.wait()
         version = LooseVersion(version)
         if version >= LooseVersion('1.8'):
             # Mutool executable with draw support.
             _mudraw_exec = [mutool, 'draw']
             _mudraw_trace_args = ['-F', 'trace']
             _pdf_possible = True
         else:
             # Separate mudraw executable.
             mudraw = process.find_executable((u'mudraw', ))
             if mudraw is None:
                 log.debug('mudraw executable not found')
             else:
                 _mudraw_exec = [mudraw]
                 if version >= LooseVersion('1.7'):
                     _mudraw_trace_args = ['-F', 'trace']
                 else:
                     _mudraw_trace_args = ['-x']
                 _pdf_possible = True
     if _pdf_possible:
         log.info('Using MuPDF version: %s', version)
         log.debug('mutool: %s', ' '.join(_mutool_exec))
         log.debug('mudraw: %s', ' '.join(_mudraw_exec))
         log.debug('mudraw trace arguments: %s',
                   ' '.join(_mudraw_trace_args))
     else:
         log.info('MuPDF not available.')
     return _pdf_possible
 def is_available():
     global _pdf_possible
     if _pdf_possible is not None:
         return _pdf_possible
     mutool = process.find_executable(('mutool', ))
     _pdf_possible = False
     version = None
     if mutool is None:
         log.debug('mutool executable not found')
     else:
         _mutool_exec.append(mutool)
         # Find MuPDF version; assume 1.6 version since
         # the '-v' switch is only supported from 1.7 onward...
         version = (1, 6)
         with process.popen([mutool, '-v'],
                            stdout=process.NULL,
                            stderr=process.PIPE,
                            universal_newlines=True) as proc:
             output = re.match(
                 r'mutool version '
                 r'(?P<version>[\d.]+)([^\d].*)?', proc.stderr.read())
             if output:
                 version = tuple(
                     map(int,
                         output.group('version').split('.')))
         if version >= (1, 8):
             # Mutool executable with draw support.
             _mudraw_exec.extend((mutool, 'draw', '-q'))
             _mudraw_trace_args.extend(('-F', 'trace'))
             _pdf_possible = True
         else:
             # Separate mudraw executable.
             mudraw = process.find_executable(('mudraw', ))
             if mudraw is None:
                 log.debug('mudraw executable not found')
             else:
                 _mudraw_exec.append(mudraw)
                 if version >= (1, 7):
                     _mudraw_trace_args.extend(('-F', 'trace'))
                 else:
                     _mudraw_trace_args.append('-x')
                 _pdf_possible = True
     if _pdf_possible:
         log.info('Using MuPDF version: %s', '.'.join(map(str, version)))
         log.debug('mutool: %s', ' '.join(_mutool_exec))
         log.debug('mudraw: %s', ' '.join(_mudraw_exec))
         log.debug('mudraw trace arguments: %s',
                   ' '.join(_mudraw_trace_args))
     else:
         log.info('MuPDF not available.')
     return _pdf_possible
Exemple #4
0
 def is_available():
     global _pdf_possible
     if _pdf_possible is not None:
         return _pdf_possible
     global _mutool_exec, _mudraw_exec, _mudraw_trace_args
     mutool = process.find_executable((u"mutool",))
     _pdf_possible = False
     version = None
     if mutool is None:
         log.debug("mutool executable not found")
     else:
         _mutool_exec = [mutool]
         # Find MuPDF version; assume 1.6 version since
         # the '-v' switch is only supported from 1.7 onward...
         version = "1.6"
         proc = process.popen([mutool, "-v"], stdout=process.NULL, stderr=process.PIPE)
         try:
             output = proc.stderr.read()
             if output.startswith("mutool version "):
                 version = output[15:].rstrip()
         finally:
             proc.stderr.close()
             proc.wait()
         version = LooseVersion(version)
         if version >= LooseVersion("1.8"):
             # Mutool executable with draw support.
             _mudraw_exec = [mutool, "draw"]
             _mudraw_trace_args = ["-F", "trace"]
             _pdf_possible = True
         else:
             # Separate mudraw executable.
             mudraw = process.find_executable((u"mudraw",))
             if mudraw is None:
                 log.debug("mudraw executable not found")
             else:
                 _mudraw_exec = [mudraw]
                 if version >= LooseVersion("1.7"):
                     _mudraw_trace_args = ["-F", "trace"]
                 else:
                     _mudraw_trace_args = ["-x"]
                 _pdf_possible = True
     if _pdf_possible:
         log.info("Using MuPDF version: %s", version)
         log.debug("mutool: %s", " ".join(_mutool_exec))
         log.debug("mudraw: %s", " ".join(_mudraw_exec))
         log.debug("mudraw trace arguments: %s", " ".join(_mudraw_trace_args))
     else:
         log.info("MuPDF not available.")
     return _pdf_possible
Exemple #5
0
 def is_available():
     global _pdf_possible
     if _pdf_possible is not None:
         return _pdf_possible
     mutool = process.find_executable(('mutool', ))
     _pdf_possible = False
     version = None
     if mutool is None:
         log.debug('mutool executable not found')
     else:
         _mutool_exec.append(mutool)
         # Find MuPDF version; assume 1.6 version since
         # the '-v' switch is only supported from 1.7 onward...
         version = '1.6'
         with process.popen([mutool, '-v'],
                            stdout=process.NULL,
                            stderr=process.PIPE,
                            universal_newlines=True) as proc:
             output = proc.stderr.read()
             if output.startswith('mutool version '):
                 version = output[15:].rstrip()
         version = LooseVersion(version)
         if version >= LooseVersion('1.8'):
             # Mutool executable with draw support.
             _mudraw_exec.extend((mutool, 'draw', '-q'))
             _mudraw_trace_args.extend(('-F', 'trace'))
             _pdf_possible = True
         else:
             # Separate mudraw executable.
             mudraw = process.find_executable(('mudraw', ))
             if mudraw is None:
                 log.debug('mudraw executable not found')
             else:
                 _mudraw_exec.append(mudraw)
                 if version >= LooseVersion('1.7'):
                     _mudraw_trace_args.extend(('-F', 'trace'))
                 else:
                     _mudraw_trace_args.append('-x')
                 _pdf_possible = True
     if _pdf_possible:
         log.info('Using MuPDF version: %s', version)
         log.debug('mutool: %s', ' '.join(_mutool_exec))
         log.debug('mudraw: %s', ' '.join(_mudraw_exec))
         log.debug('mudraw trace arguments: %s',
                   ' '.join(_mudraw_trace_args))
     else:
         log.info('MuPDF not available.')
     return _pdf_possible
Exemple #6
0
 def _find_lha_executable():
     """ Tries to start lha, and returns either 'lha' if
     it was started successfully or None otherwise. """
     global _lha_executable
     if _lha_executable == -1:
         _lha_executable = process.find_executable((u'lha',))
     return _lha_executable
Exemple #7
0
 def _find_unzip_executable():
     """ Tries to run unzip, and returns 'unzip' on success.
     Returns None on failure. """
     global _zip_executable
     if -1 == _zip_executable:
         _zip_executable = process.find_executable((u'unzip', ))
     return _zip_executable
Exemple #8
0
 def _find_7z_executable():
     """ Tries to start 7z, and returns either '7z' if
     it was started successfully or None otherwise. """
     global _7z_executable
     if _7z_executable == -1:
         _7z_executable = process.find_executable((u'7z', ))
     return _7z_executable
 def _find_7z_executable():
     """ Tries to start 7z, and returns either '7z' if
     it was started successfully or None otherwise. """
     global _7z_executable
     if _7z_executable == -1:
         _7z_executable = process.find_executable((u'7z',))
     return _7z_executable
Exemple #10
0
 def _find_unzip_executable():
     """ Tries to run unzip, and returns 'unzip' on success.
     Returns None on failure. """
     global _zip_executable
     if -1 == _zip_executable:
         _zip_executable = process.find_executable((u"unzip",))
     return _zip_executable
Exemple #11
0
 def _find_lha_executable():
     ''' Tries to start lha, and returns either 'lha' if
     it was started successfully or None otherwise. '''
     global _lha_executable
     if _lha_executable == -1:
         _lha_executable = process.find_executable(('lha', ))
     return _lha_executable
Exemple #12
0
 def _find_unrar_executable():
     """ Tries to start rar/unrar, and returns either 'rar' or 'unrar' if
     one of them was started successfully.
     Returns None if neither could be started. """
     global _rar_executable
     if _rar_executable == -1:
         _rar_executable = process.find_executable((u'unrar', u'rar'))
     return _rar_executable
Exemple #13
0
    def is_executable(self, window):
        """ Check if a name is executable. This name can be either
        a relative path, when the executable is in PATH, or an
        absolute path. """
        args = self.parse(window)
        if len(args) == 0:
            return False

        if self.is_valid_workdir(window):
            workdir = self.parse(window, text=self.get_cwd())[0]
        else:
            workdir = os.getcwd()

        exe = process.find_executable((args[0],), workdir=workdir)

        return exe is not None
Exemple #14
0
    def is_executable(self, window):
        ''' Check if a name is executable. This name can be either
        a relative path, when the executable is in PATH, or an
        absolute path. '''
        args = self.parse(window)
        if len(args) == 0:
            return False

        if self.is_valid_workdir(window):
            workdir = self.parse(window, text=self.get_cwd())[0]
        else:
            workdir = os.getcwd()

        exe = process.find_executable((args[0], ), workdir=workdir)

        return exe is not None
Exemple #15
0
def _find_unrar_executable():
    ''' Tries to start rar/unrar, and returns either 'rar' or 'unrar' if
        one of them was started successfully.
        Returns None if neither could be started. '''

    if 'path' not in _rar_executable:
        path = process.find_executable(('unrar-nonfree', 'unrar', 'rar'),
                                       is_valid_candidate=_is_not_unrar_free)
        _rar_executable['path'] = path
        if path is not None:
            with process.popen([path], text=True) as proc:
                # only check first line
                line = proc.stdout.read().strip().splitlines()[0].split()
                if line[0]=='UNRAR':
                    log.debug('unrar version: %s', line[1])

    return _rar_executable['path']
Exemple #16
0
    def _find_unrar_executable():
        """ Tries to start rar/unrar, and returns either 'rar' or 'unrar' if
        one of them was started successfully.
        Returns None if neither could be started. """
        global _rar_executable
        if _rar_executable == -1:
            if 'win32' == sys.platform:
                is_not_unrar_free = lambda exe: True
            else:

                def is_not_unrar_free(exe):
                    real_exe = exe
                    while os.path.islink(real_exe):
                        real_exe = os.readlink(real_exe)
                    if real_exe.endswith(os.path.sep + 'unrar-free'):
                        log.warning(
                            'RAR executable %s is unrar-free, ignoring', exe)
                        return False
                    return True

            _rar_executable = process.find_executable(
                (u'unrar-nonfree', u'unrar', u'rar'),
                is_valid_candidate=is_not_unrar_free)
        return _rar_executable
Exemple #17
0
    def test_find_executable(self):
        cleanup = []
        try:
            root_dir = tempfile.mkdtemp(dir=u'test', prefix=u'tmp.path.')
            # cleanup.append(lambda: shutil.rmtree(root_dir))

            if 'win32' == sys.platform:
                orig_exe_dir = process._exe_dir
                cleanup.append(
                    lambda: setattr(process, '_exe_dir', orig_exe_dir))
                process._exe_dir = 'dir4'
                tree = (
                    ('bin1.exe', 'rx'),
                    ('bin3.exe', 'rx'),
                    ('dir1/bin1.exe', 'rx'),
                    ('dir1/bin2', 'rx'),
                    ('dir2/bin1.exe', 'rx'),
                    ('dir3/bin2.exe', 'rx'),
                    ('dir3/bin4.exe', 'rx'),
                    ('dir3/dir/bin2.exe', 'rx'),
                    ('dir4/bin4.exe', 'rx'),
                    ('dir4/bin5.exe', 'rx'),
                )
                tests = (
                    # Absolute path, unchanged.
                    ([sys.executable], None, sys.executable),
                    # Same without .exe extension.
                    ([sys.executable[:-4]], None, sys.executable),
                    # Must still be valid, though...
                    (['C:/invalid/invalid'], None, None),
                    # bin1 in workdir should be picked up.
                    (['bin1.exe'], None, 'bin1.exe'),
                    (['bad', 'bin1.exe'], None, 'bin1.exe'),
                    # Same without .exe extension.
                    (['bin1'], None, 'bin1.exe'),
                    # bin2 in dir1 or bin2 @ind dir3 should not be picked up.
                    (['bin2'], None, 'dir3/bin2.exe'),
                    # Candidate with a directory component.
                    (['./bin3'], None, 'bin3.exe'),
                    # And a custom working directory.
                    (['dir/bin2'], 'dir3', 'dir3/dir/bin2.exe'),
                    # Check main executable directory is searched too.
                    # (with higher priority than PATH)
                    (['bin4'], None, 'dir4/bin4.exe'),
                    # And work directory.
                    (['bin4'], 'dir3', 'dir4/bin4.exe'),
                )
            else:
                tree = (
                    ('bin1', 'rx'),
                    ('bin3', 'rx'),
                    ('dir1/bin1', 'rx'),
                    ('dir1/bin2', 'r '),
                    ('dir2/bin1', 'rx'),
                    ('dir2/bin2', '  '),
                    ('dir3/bin1', 'rx'),
                    ('dir3/bin2', 'rx'),
                    ('dir3/bin3', 'r '),
                    ('dir3/bin4', 'rx'),
                    ('dir3/dir/bin2', 'rx'),
                    ('dir3/dir/bin3', 'rw '),
                )
                tests = (
                    # Absolute path, unchanged.
                    (['/bin/true'], None, '/bin/true'),
                    # Must still be valid, though...
                    (['/invalid/invalid'], None, None),
                    # bin1 in workdir should not be picked up.
                    (['bin1'], None, 'dir1/bin1'),
                    # Check all candidates.
                    (['bad', 'bin1'], None, 'dir1/bin1'),
                    # bin2 in dir1 should not be picked up (not executable).
                    (['bin2'], None, 'dir3/bin2'),
                    # Same with bin3.
                    (['bin3'], None, None),
                    # Candidate with a directory component.
                    (['./bin3'], None, 'bin3'),
                    # And a custom working directory.
                    (['dir/bin2'], 'dir3', 'dir3/dir/bin2'),
                    # But must still be valid...
                    (['dir/bin3'], 'dir3', None),
                )

            _create_tree(root_dir, tree)

            root_dir = os.path.abspath(root_dir)

            orig_path = os.environ['PATH']
            cleanup.append(lambda: os.environ.__setitem__('PATH', orig_path))
            os.environ['PATH'] = os.pathsep.join('dir1 dir2 dir3'.split())

            orig_cwd = os.getcwd()
            cleanup.append(lambda: os.chdir(orig_cwd))
            os.chdir(root_dir)

            for candidates, workdir, expected in tests:
                if expected is not None:
                    if not os.path.isabs(expected):
                        expected = os.path.join(root_dir, expected)
                    expected = os.path.normpath(expected)
                result = process.find_executable(candidates, workdir=workdir)
                msg = ('find_executable(%s, workdir=%s) failed; '
                       'returned %s instead of %s' % (
                           candidates,
                           workdir,
                           result,
                           expected,
                       ))
                self.assertEqual(result, expected, msg=msg)

        finally:
            for fn in reversed(cleanup):
                fn()
Exemple #18
0
from mcomix import i18n, process

import tempfile
import shutil
import time
import sys
import os


# Find fc-cache.exe
fc_cache_exe = process.find_executable((
    'fc-cache',
    'c:/Python27/Lib/site-packages/gnome/fc-cache.exe',
))


# Update cache, while displaying a status dialog so the user know something is happening.
def update(args=[], notification_delay=3, notification_duration=3):
    '''Update fontconfig cache by calling fc-cache.exe manually.

    The function will block until fc-cache.exe has finished. If the update
    takes more than <notification_delay> seconds, a notification window will be
    shown for at least <notification_duration> seconds.
    '''

    cmd = [fc_cache_exe]
    cmd.extend(args)
    proc = process.popen(cmd, stdout=process.NULL)

    notif_time = time.time() + notification_delay
Exemple #19
0
from mcomix import i18n, process

import tempfile
import shutil
import time
import sys
import os

# Find fc-cache.exe
fc_cache_exe = process.find_executable((
    'fc-cache',
    'c:/Python27/Lib/site-packages/gnome/fc-cache.exe',
))


# Update cache, while displaying a status dialog so the user know something is happening.
def update(args=[], notification_delay=3, notification_duration=3):
    '''Update fontconfig cache by calling fc-cache.exe manually.

    The function will block until fc-cache.exe has finished. If the update
    takes more than <notification_delay> seconds, a notification window will be
    shown for at least <notification_duration> seconds.
    '''

    cmd = [fc_cache_exe]
    cmd.extend(args)
    proc = process.popen(cmd, stdout=process.NULL)

    notif_time = time.time() + notification_delay
    end_time = notif_time + notification_duration
Exemple #20
0
                       stdout=process.NULL,
                       stderr=process.PIPE,
                       text=True) as proc:
        if output := re.match(r'mutool version (?P<version>[\d.]+)([^\d].*)?',
                              proc.stderr.read()):
            _mupdf['version'] = tuple(
                map(int,
                    output.group('version').split('.')))
    if _mupdf['version'] >= (1, 8):
        # Mutool executable with draw support.
        _mupdf['found'] = True
        _mupdf['mudraw'].extend((mutool, 'draw', '-q'))
        _mupdf['mudraw_trace_args'].extend(('-F', 'trace'))
        return
    # Separate mudraw executable.
    if (mudraw := process.find_executable(('mudraw', ))) is None:
        return log.debug('mudraw executable not found')
    _mupdf['found'] = True
    _mupdf['mudraw'].append(mudraw)
    if _mupdf['version'] >= (1, 7):
        _mupdf['mudraw_trace_args'].extend(('-F', 'trace'))
    else:
        _mupdf['mudraw_trace_args'].append('-x')


class PdfArchive(archive_base.BaseArchive):
    ''' Concurrent calls to extract welcome! '''
    support_concurrent_extractions = True

    _fill_image_regex = re.compile(
        r'^\s*<fill_image\b.*\bmatrix="(?P<matrix>[^"]+)".*\bwidth="(?P<width>\d+)".*\bheight="(?P<height>\d+)".*/>\s*$'
Exemple #21
0
    def test_find_executable(self):
        cleanup = []
        try:
            root_dir = tempfile.mkdtemp(dir=u'test', prefix=u'tmp.path.')
            # cleanup.append(lambda: shutil.rmtree(root_dir))

            if 'win32' == sys.platform:
                orig_exe_dir = process._exe_dir
                cleanup.append(lambda: setattr(process, '_exe_dir', orig_exe_dir))
                process._exe_dir = 'dir4'
                tree = (
                    ('bin1.exe'         , 'rx'),
                    ('bin3.exe'         , 'rx'),
                    ('dir1/bin1.exe'    , 'rx'),
                    ('dir1/bin2'        , 'rx'),
                    ('dir2/bin1.exe'    , 'rx'),
                    ('dir3/bin2.exe'    , 'rx'),
                    ('dir3/bin4.exe'    , 'rx'),
                    ('dir3/dir/bin2.exe', 'rx'),
                    ('dir4/bin4.exe'    , 'rx'),
                    ('dir4/bin5.exe'    , 'rx'),
                )
                tests = (
                    # Absolute path, unchanged.
                    ([sys.executable]      , None  , sys.executable     ),
                    # Same without .exe extension.
                    ([sys.executable[:-4]] , None  , sys.executable     ),
                    # Must still be valid, though...
                    (['C:/invalid/invalid'], None  , None               ),
                    # bin1 in workdir should be picked up.
                    (['bin1.exe']          , None  , 'bin1.exe'         ),
                    (['bad', 'bin1.exe']   , None  , 'bin1.exe'         ),
                    # Same without .exe extension.
                    (['bin1']              , None  , 'bin1.exe'         ),
                    # bin2 in dir1 or bin2 @ind dir3 should not be picked up.
                    (['bin2']              , None  , 'dir3/bin2.exe'    ),
                    # Candidate with a directory component.
                    (['./bin3']            , None  , 'bin3.exe'         ),
                    # And a custom working directory.
                    (['dir/bin2']          , 'dir3', 'dir3/dir/bin2.exe'),
                    # Check main executable directory is searched too.
                    # (with higher priority than PATH)
                    (['bin4']              , None  , 'dir4/bin4.exe'    ),
                    # And work directory.
                    (['bin4']              , 'dir3', 'dir4/bin4.exe'    ),
                )
            else:
                tree = (
                    ('bin1'         , 'rx'),
                    ('bin3'         , 'rx'),
                    ('dir1/bin1'    , 'rx'),
                    ('dir1/bin2'    , 'r '),
                    ('dir2/bin1'    , 'rx'),
                    ('dir2/bin2'    , '  '),
                    ('dir3/bin1'    , 'rx'),
                    ('dir3/bin2'    , 'rx'),
                    ('dir3/bin3'    , 'r '),
                    ('dir3/bin4'    , 'rx'),
                    ('dir3/dir/bin2', 'rx'),
                    ('dir3/dir/bin3', 'rw '),
                )
                tests = (
                    # Absolute path, unchanged.
                    (['/bin/true']       , None  , '/bin/true'    ),
                    # Must still be valid, though...
                    (['/invalid/invalid'], None  , None           ),
                    # bin1 in workdir should not be picked up.
                    (['bin1']            , None  , 'dir1/bin1'    ),
                    # Check all candidates.
                    (['bad', 'bin1']     , None  , 'dir1/bin1'    ),
                    # bin2 in dir1 should not be picked up (not executable).
                    (['bin2']            , None  , 'dir3/bin2'    ),
                    # Same with bin3.
                    (['bin3']            , None  , None           ),
                    # Candidate with a directory component.
                    (['./bin3']          , None  , 'bin3'         ),
                    # And a custom working directory.
                    (['dir/bin2']        , 'dir3', 'dir3/dir/bin2'),
                    # But must still be valid...
                    (['dir/bin3']        , 'dir3', None           ),
                )

            _create_tree(root_dir, tree)

            root_dir = os.path.abspath(root_dir)

            orig_path = os.environ['PATH']
            cleanup.append(lambda: os.environ.__setitem__('PATH', orig_path))
            os.environ['PATH'] = os.pathsep.join('dir1 dir2 dir3'.split())

            orig_cwd = os.getcwd()
            cleanup.append(lambda: os.chdir(orig_cwd))
            os.chdir(root_dir)

            for candidates, workdir, expected in tests:
                if expected is not None:
                    if not os.path.isabs(expected):
                        expected = os.path.join(root_dir, expected)
                    expected = os.path.normpath(expected)
                result = process.find_executable(candidates, workdir=workdir)
                msg = (
                    'find_executable(%s, workdir=%s) failed; '
                    'returned %s instead of %s' % (
                        candidates, workdir,
                        result, expected,
                    )
                )
                self.assertEqual(result, expected, msg=msg)

        finally:
            for fn in reversed(cleanup):
                fn()
Exemple #22
0
def run():
    """Run the program."""

    try:
        import pkg_resources

    except ImportError:
        # gettext isn't initialized yet, since pkg_resources is required to find translation files.
        # Thus, localizing these messages is pointless.
        log._print("The package 'pkg_resources' could not be found.")
        log._print("You need to install the 'setuptools' package, which also includes pkg_resources.")
        log._print("Note: On most distributions, 'distribute' supersedes 'setuptools'.")
        wait_and_exit()

    # Load configuration and setup localisation.
    preferences.read_preferences_file()
    from mcomix import i18n
    i18n.install_gettext()

    # Retrieve and parse command line arguments.
    argv = portability.get_commandline_args()
    opts, args = parse_arguments(argv)

    # First things first: set the log level.
    log.setLevel(opts.loglevel)

    # On Windows, update the fontconfig cache manually, before MComix starts
    # using Gtk, since the process may take several minutes, during which the
    # main window will just be frozen if the work is left to Gtk itself...
    if opts.update_fontconfig_cache:
        # First, update fontconfig cache.
        log.debug('starting fontconfig cache update')
        try:
            from mcomix.win32 import fc_cache
            from mcomix import process
            fc_cache.update()
            log.debug('fontconfig cache updated')
        except Exception as e:
            log.error('during fontconfig cache update', exc_info=e)
        # And then replace current MComix process with a fresh one
        # (that will not try to update the cache again).
        exe = sys.argv[0]
        if sys.platform == 'win32' and exe.endswith('.py'):
            # Find the interpreter.
            exe = process.find_executable(('pythonw.exe', 'python.exe'))
            args = [exe, sys.argv[0]]
        else:
            args = [exe]
        if sys.platform == 'win32':
            args.append('--no-update-fontconfig-cache')
        args.extend(argv)
        if '--update-fontconfig-cache' in args:
            args.remove('--update-fontconfig-cache')
        log.debug('restarting MComix from fresh: os.execv(%s, %s)', repr(exe), args)
        try:
            if sys.platform == 'win32':
                # Of course we can't use os.execv on Windows because it will
                # mangle arguments containing spaces or non-ascii characters...
                process.Win32Popen(args)
                sys.exit(0)
            else:
                os.execv(exe, args)
        except Exception as e:
            log.error('os.execv(%s, %s) failed', exe, str(args), exc_info=e)
        wait_and_exit()

    # Check for PyGTK and PIL dependencies.
    try:
        import pygtk
        pygtk.require('2.0')

        import gtk
        assert gtk.gtk_version >= (2, 12, 0)
        assert gtk.pygtk_version >= (2, 12, 0)

        import gobject
        gobject.threads_init()

    except AssertionError:
        log.error( _("You do not have the required versions of GTK+ and PyGTK installed.") )
        log.error( _('Installed GTK+ version is: %s') % \
                  '.'.join([str(n) for n in gtk.gtk_version]) )
        log.error( _('Required GTK+ version is: 2.12.0 or higher') )
        log.error( _('Installed PyGTK version is: %s') % \
                  '.'.join([str(n) for n in gtk.pygtk_version]) )
        log.error( _('Required PyGTK version is: 2.12.0 or higher') )
        wait_and_exit()

    except ImportError:
        log.error( _('Required PyGTK version is: 2.12.0 or higher') )
        log.error( _('No version of PyGTK was found on your system.') )
        log.error( _('This error might be caused by missing GTK+ libraries.') )
        wait_and_exit()

    try:
        import PIL.Image
        assert PIL.Image.VERSION >= '1.1.5'

    except AssertionError:
        log.error( _("You don't have the required version of the Python Imaging"), end=' ')
        log.error( _('Library (PIL) installed.') )
        log.error( _('Installed PIL version is: %s') % Image.VERSION )
        log.error( _('Required PIL version is: 1.1.5 or higher') )
        wait_and_exit()

    except ImportError:
        log.error( _('Python Imaging Library (PIL) 1.1.5 or higher is required.') )
        log.error( _('No version of the Python Imaging Library was found on your system.') )
        wait_and_exit()

    if not os.path.exists(constants.DATA_DIR):
        os.makedirs(constants.DATA_DIR, 0700)

    if not os.path.exists(constants.CONFIG_DIR):
        os.makedirs(constants.CONFIG_DIR, 0700)

    from mcomix import icons
    icons.load_icons()

    open_path = None
    open_page = 1
    if len(args) == 1:
        open_path = args[0]
    elif len(args) > 1:
        open_path = args

    elif preferences.prefs['auto load last file'] \
        and preferences.prefs['path to last file'] \
        and os.path.isfile(preferences.prefs['path to last file']):
        open_path = preferences.prefs['path to last file']
        open_page = preferences.prefs['page of last file']

    # Some languages require a RTL layout
    if preferences.prefs['language'] in ('he', 'fa'):
        gtk.widget_set_default_direction(gtk.TEXT_DIR_RTL)

    gtk.gdk.set_program_class(constants.APPNAME)

    from mcomix import main
    window = main.MainWindow(fullscreen = opts.fullscreen, is_slideshow = opts.slideshow,
            show_library = opts.library, manga_mode = opts.manga,
            double_page = opts.doublepage, zoom_mode = opts.zoommode,
            open_path = open_path, open_page = open_page)
    main.set_main_window(window)

    if 'win32' != sys.platform:
        # Add a SIGCHLD handler to reap zombie processes.
        def on_sigchld(signum, frame):
            try:
                os.waitpid(-1, os.WNOHANG)
            except OSError:
                pass
        signal.signal(signal.SIGCHLD, on_sigchld)

    signal.signal(signal.SIGTERM, lambda: gobject.idle_add(window.terminate_program))
    try:
        gtk.main()
    except KeyboardInterrupt: # Will not always work because of threading.
        window.terminate_program()
 def _find_7z_executable():
     ''' Tries to start 7z, and returns either '7z' if
     it was started successfully or None otherwise. '''
     if 'path' not in _7z_executable:
         _7z_executable['path'] = process.find_executable(('7z', ))
     return _7z_executable['path']