<commit_before>#!/usr/bin/env python
# coding: utf-8

"""
Rename a string in CamelCase, snake_case and ALL_CAPS_CASE
in code and filenames in one go.
"""

__version__ = '0.1.1'
__author__ = 'Daniel Krikun'
__license__ = 'MIT'

import sys
import logging
import argparse
import os
import fnmatch
import io
import difflib
import shutil
import re

# whole word options
WHOLE_WORD = 2
ALLOW_UNDERSCORES = 1
ANY_SEQUENCE = 0

def is_binary(filename):
    """Return true if the given filename is binary.
    @raise EnvironmentError: if the file does not exist or cannot be accessed.
    @attention: found @ http://bytes.com/topic/python/answers/21222-determine-file-type-binary-text on 6/08/2010
    @author: Trent Mick <TrentM@ActiveState.com>
    @author: Jorge Orpinel <jorge@orpinel.com>"""
    fin = open(filename, 'rb')
    try:
        CHUNKSIZE = 1024
        while 1:
            chunk = fin.read(CHUNKSIZE)
            if '\0' in chunk: # found null byte
                return True
            if len(chunk) < CHUNKSIZE:
                break # done
    # A-wooo! Mira, python no necesita el "except:". Achis... Que listo es.
    finally:
        fin.close()

    return False

# copied from massedit.py by Jérôme Lecomte
def get_paths(patterns, start_dir=None, max_depth=1):
    """Retrieve files that match any of the patterns."""

    # Shortcut: if there is only one pattern, make sure we process just that.
    if len(patterns) == 1 and not start_dir:
        pattern = patterns[0]
        directory = os.path.dirname(pattern)
        if directory:
            patterns = [os.path.basename(pattern)]
            start_dir = directory
            max_depth = 1

    if not start_dir:
        start_dir = os.getcwd()
    for root, dirs, files in os.walk(start_dir):  # pylint: disable=W0612
        if max_depth is not None:
            relpath = os.path.relpath(root, start=start_dir)
            depth = len(relpath.split(os.sep))
            if depth > max_depth:
                continue
        names = []
        for pattern in patterns:
            names += fnmatch.filter(files, pattern)
        for name in names:
            path = os.path.join(root, name)
            yield path

def parse_cmdline_args():
    """Parse command-line arguments."""

    parser = argparse.ArgumentParser(description='Rename a string in CamelCase'
                                     ', snake_case and ALL_CAPS in one go')
    parser.add_argument('--version', action='version',
                        version='%(prog)s {}'.format(__version__))
    word_group = parser.add_mutually_exclusive_group()
    word_group.add_argument('-w', '--word', action='store_true',
                            help='force SOURCE to match only whole words')
    word_group.add_argument('--almost-word', action='store_true',
                            help='like -w, but also allow for any number of '
                            'surrounding underscores')
    parser.add_argument('-d', '--diff', action='store_true',
                        help='shows diff instead of modifying files inplace')
    parser.add_argument('-f', '--text-only', action='store_true',
                        help='only perform search/replace in file contents, do'
                        'not rename any files')
    verbosity_group = parser.add_mutually_exclusive_group()
    verbosity_group.add_argument('-V', '--verbose', action='store_true',
                                 help='be verbose')
    verbosity_group.add_argument('-q', '--silent', action='store_true',
                                 help='be silent')
    parser.add_argument('source', metavar='SOURCE',
                        help='source string to be renamed')
    parser.add_argument('dest', metavar='DEST',
                        help='string to replace with')
    parser.add_argument('patterns', metavar='PATTERN', nargs='+',
                        help='shell-like file name patterns to process')
    return parser.parse_args()

def is_snake_case(id_name):
    """Check if id_name is written in snake case.

    Actually, it is restricted to a certain subset of snake case, so that
    we can guarantee camel->snake->camel roundtrip.

    >>> is_snake_case('')
    False
    >>> is_snake_case('_')
    False
    >>> is_snake_case('h')
    True
    >>> is_snake_case('hello_world')
    True
    >>> is_snake_case(' hello_world ')
    False
    >>> is_snake_case('_hello')
    False
    >>> is_snake_case('hello_')
    False
    >>> is_snake_case('__hello_world__')
    False
    >>> is_snake_case('_hello6_wor7d_')
    False
    >>> is_snake_case('hello6_wor7d')
    True
    >>> is_snake_case('hello__world')
    False
    >>> is_snake_case('hello-world')
    False
    >>> is_snake_case('HelloWorld')
    False
    >>> is_snake_case('ab6')
    True
    >>> is_snake_case('ab_6')
    False
    >>> is_snake_case('6_ab')
    False
    >>> is_snake_case('ab_6_ab6')
    False
    """

    snake_case_re = re.compile(r"""
            [a-z][a-z0-9]*      # first word is required, start w/ alpha
            (_[a-z][a-z0-9]*)*  # any number of words follow
            $
            """, re.VERBOSE)

    return snake_case_re.match(id_name) is not None

def is_camel_case(id_name):
    """Check if id_name is written in camel case.

    >>> is_camel_case('')
    False
    >>> is_camel_case('_')
    False
    >>> is_camel_case('h')
    False
    >>> is_camel_case('H')
    True
    >>> is_camel_case('HW')
    False
    >>> is_camel_case('hW')
    False
    >>> is_camel_case('hWW')
    False
    >>> is_camel_case('WhWhWhW')
    True
    >>> is_camel_case('HelloWorld')
    True
    >>> is_camel_case('HWorld')
    False
    >>> is_camel_case('Hello6orld')
    True
    >>> is_camel_case('hello_world')
    False
    >>> is_camel_case('_Hello')
    False
    >>> is_camel_case('Hello_')
    False
    >>> is_camel_case('hello-world')
    False
    >>> is_camel_case('HelloWorld')
    True
    >>> is_camel_case('HelloGoodWorld77')
    True
    """

    camel_case_re = re.compile(r"""
            ([A-Z](?![A-Z])[a-z0-9]*)+    # neg lookahead is to exclude
                                          # e.g HWorld
            $
            """, re.VERBOSE)

    return camel_case_re.match(id_name) is not None

def snake2camel(id_name):
    """Change id_name from snake to camel, provided it is in snake case,
    or else return id_name intact.

    >>> snake2camel('hello_world')
    'HelloWorld'
    >>> snake2camel('HelloWorld')
    'HelloWorld'
    >>> snake2camel('hello9')
    'Hello9'
    >>> snake2camel('hello9world')
    'Hello9world'
    >>> snake2camel('hello9_world')
    'Hello9World'
    >>> snake2camel('h')
    'H'
    >>> snake2camel('hw')
    'Hw'
    >>> snake2camel('hello_good_world77')
    'HelloGoodWorld77'
    """

    if not is_snake_case(id_name):
        return id_name

    word_start = re.compile(r'(\A|_)[a-z]')
    return word_start.sub(lambda x: x.group().lstrip('_').upper(), id_name)

def camel2snake(id_name):
    """Change id_name from camel to snake, provided it is in camel case,
    or else return id_name intact.

    >>> camel2snake('HelloWorld')
    'hello_world'
    >>> camel2snake('hello_world')
    'hello_world'
    >>> camel2snake('Hello8orld')
    'hello8orld'
    >>> camel2snake('H')
    'h'
    >>> camel2snake('Hw')
    'hw'
    >>> camel2snake('HelloGoodWorld77')
    'hello_good_world77'
    """

    if not is_camel_case(id_name):
        return id_name

    word_start = re.compile(r'[A-Z]')
    almost_ready = word_start.sub(lambda x: '_' + x.group().lower(), id_name)
    return almost_ready.lstrip('_')

def edit_line(src, dest, line, word_option=ANY_SEQUENCE):
    """Rename in a single line of text.

    >>> edit_line('hello_world', 'whats_up', 'hi hello_world <3')
    'hi whats_up <3'
    >>> edit_line('hello_world', 'whats_up', 'hi HelloWorld HELLO_WORLD <3')
    'hi WhatsUp WHATS_UP <3'
    >>> edit_line('HelloWorld', 'WhatsUp', 'hi HelloWorld HELLO_WORLD <3')
    'hi WhatsUp WHATS_UP <3'
    >>> edit_line('hello__world', 'WhatsUp', 'hi hello__world HELLO_WORLD <3')
    'hi WhatsUp HELLO_WORLD <3'
    >>> edit_line('hello_world', 'whats_up', 'hi hello_world <3', WHOLE_WORD)
    'hi whats_up <3'
    >>> edit_line('hl_wrld', 'whats_up', 'hiRhl_wrldR<3', ANY_SEQUENCE)
    'hiRwhats_upR<3'
    >>> edit_line('hl_wrld', 'whats_up', 'hiRhl_wrldR<3', WHOLE_WORD)
    'hiRhl_wrldR<3'
    >>> edit_line('hl_wrld', 'whats_up', 'hiRhl_wrldR<3', ALLOW_UNDERSCORES)
    'hiRhl_wrldR<3'
    >>> edit_line('hl_wrld', 'whats_up', '___hl_wrld__', ANY_SEQUENCE)
    '___whats_up__'
    >>> edit_line('hl_wrld', 'whats_up', '___hl_wrld__', ALLOW_UNDERSCORES)
    '___whats_up__'
    >>> edit_line('hl_wrld', 'whats_up', '___hl_wrld__', WHOLE_WORD)
    '___hl_wrld__'
    >>> edit_line('hl_wrld', 'whats_up', '___HlWrld__', ALLOW_UNDERSCORES)
    '___WhatsUp__'
    >>> edit_line('hex_clck', 'hacker_clck', '_HEX_CLCK_H', ALLOW_UNDERSCORES)
    '_HACKER_CLCK_H'
    """

    src_snake = camel2snake(src)
    dest_snake = camel2snake(dest)
    src_camel = snake2camel(src)
    dest_camel = snake2camel(dest)
    src_all_caps = src_snake.upper()
    dest_all_caps = dest_snake.upper()

    # if not recognized as snake or camel, both transforms will leave its
    # input string intact

    recognized = src_snake != src_camel and dest_snake != dest_camel
    if not recognized:
        logging.debug('case not recognized, performing plain search/replace')
        return line.replace(src, dest)

    if word_option == ANY_SEQUENCE:
        line = line.replace(src_snake, dest_snake)
        line = line.replace(src_camel, dest_camel)
        return line.replace(src_all_caps, dest_all_caps)

    if word_option == WHOLE_WORD:
        template = r'\b{}\b'

        src_snake = template.format(src_snake)
        src_camel = template.format(src_camel)
        src_all_caps = template.format(src_all_caps)

        line = re.sub(src_snake, dest_snake, line)
        line = re.sub(src_camel, dest_camel, line)
        return re.sub(src_all_caps, dest_all_caps, line)

    if word_option == ALLOW_UNDERSCORES:
        src_template = r'(\b|(_+)){}((_+)|\b)'
        dest_template = r'\1{}\3'

        src_snake = src_template.format(src_snake)
        src_camel = src_template.format(src_camel)
        src_all_caps = src_template.format(src_all_caps)

        dest_snake = dest_template.format(dest_snake)
        dest_camel = dest_template.format(dest_camel)
        dest_all_caps = dest_template.format(dest_all_caps)

        logging.debug('underscore caps: {}->{}'.format(src_all_caps,
                      dest_all_caps))
        line = re.sub(src_snake, dest_snake, line)
        line = re.sub(src_camel, dest_camel, line)
        return re.sub(src_all_caps, dest_all_caps, line)

def edit_text(src, dest, text_lines, word_option=ANY_SEQUENCE):
    """Rename in lines of text."""

    return [edit_line(src, dest, line, word_option) for line in text_lines]

def process_file(src, dest, word_option, path,  # pylint: disable=R0913
                 diff, text_only):
    """Rename in a file."""

    if is_binary(path):
        return

    if not text_only:
        new_path = edit_line(src, dest, path, word_option)
    else:
        new_path = path

    try:
        with io.open(path, 'r', encoding='utf-8') as in_file:
            in_lines = in_file.readlines()
    except IOError as e:
        logging.warn('could not read file: {0}, error message: {1}'
                .format(path, e))
        return
    except UnicodeDecodeError as e:
        logging.debug('could not read file: {0}, error message: {1}'
                .format(path, e))
        return

    out_lines = list(edit_text(src, dest, in_lines, word_option))

    if diff:
        diffs = difflib.unified_diff(in_lines, out_lines,
                                     fromfile=path, tofile=new_path)
        for line in diffs:
            sys.stdout.write(line)
    else:
        try:
            with io.open(new_path, 'w', encoding='utf-8') as out_file:
                out_file.writelines(out_lines)
        except IOError as e:
            logging.warn('could not read file: {0}, error message: {1}'
                    .format(path, e))

        if new_path != path:
            shutil.copymode(path, new_path)
            try:
                os.unlink(path)
            except OSError as e:
                logging.warn('could not delete file: {0}, error message: {1}'
                        .format(path,e))
                return

def main():
    """Main here."""

    args = parse_cmdline_args()
    severity_level = logging.DEBUG if args.verbose else logging.WARNING
    if args.silent:
        severity_level = logging.CRITICAL
    logging.basicConfig(stream=sys.stderr, level=severity_level)
    logging.debug(args)

    word_option = ANY_SEQUENCE
    if args.word:
        word_option = WHOLE_WORD
    elif args.almost_word:
        word_option = ALLOW_UNDERSCORES

    pathes = get_paths(args.patterns, start_dir=None, max_depth=None)
    for path in pathes:
        logging.debug('renaming in {}'.format(path))

        process_file(args.source, args.dest, word_option, path,
                     args.diff, args.text_only)

if __name__ == "__main__":
    sys.exit(main())
<commit_msg>Catch more exceptions<commit_after>#!/usr/bin/env python
# coding: utf-8

"""
Rename a string in CamelCase, snake_case and ALL_CAPS_CASE
in code and filenames in one go.
"""

__version__ = '0.1.1'
__author__ = 'Daniel Krikun'
__license__ = 'MIT'

import sys
import logging
import argparse
import os
import fnmatch
import io
import difflib
import shutil
import re

# whole word options
WHOLE_WORD = 2
ALLOW_UNDERSCORES = 1
ANY_SEQUENCE = 0

def is_binary(filename):
    """Return true if the given filename is binary.
    @raise EnvironmentError: if the file does not exist or cannot be accessed.
    @attention: found @ http://bytes.com/topic/python/answers/21222-determine-file-type-binary-text on 6/08/2010
    @author: Trent Mick <TrentM@ActiveState.com>
    @author: Jorge Orpinel <jorge@orpinel.com>"""
    fin = open(filename, 'rb')
    try:
        CHUNKSIZE = 1024
        while 1:
            chunk = fin.read(CHUNKSIZE)
            if '\0' in chunk: # found null byte
                return True
            if len(chunk) < CHUNKSIZE:
                break # done
    # A-wooo! Mira, python no necesita el "except:". Achis... Que listo es.
    finally:
        fin.close()

    return False

# copied from massedit.py by Jérôme Lecomte
def get_paths(patterns, start_dir=None, max_depth=1):
    """Retrieve files that match any of the patterns."""

    # Shortcut: if there is only one pattern, make sure we process just that.
    if len(patterns) == 1 and not start_dir:
        pattern = patterns[0]
        directory = os.path.dirname(pattern)
        if directory:
            patterns = [os.path.basename(pattern)]
            start_dir = directory
            max_depth = 1

    if not start_dir:
        start_dir = os.getcwd()
    for root, dirs, files in os.walk(start_dir):  # pylint: disable=W0612
        if max_depth is not None:
            relpath = os.path.relpath(root, start=start_dir)
            depth = len(relpath.split(os.sep))
            if depth > max_depth:
                continue
        names = []
        for pattern in patterns:
            names += fnmatch.filter(files, pattern)
        for name in names:
            path = os.path.join(root, name)
            yield path

def parse_cmdline_args():
    """Parse command-line arguments."""

    parser = argparse.ArgumentParser(description='Rename a string in CamelCase'
                                     ', snake_case and ALL_CAPS in one go')
    parser.add_argument('--version', action='version',
                        version='%(prog)s {}'.format(__version__))
    word_group = parser.add_mutually_exclusive_group()
    word_group.add_argument('-w', '--word', action='store_true',
                            help='force SOURCE to match only whole words')
    word_group.add_argument('--almost-word', action='store_true',
                            help='like -w, but also allow for any number of '
                            'surrounding underscores')
    parser.add_argument('-d', '--diff', action='store_true',
                        help='shows diff instead of modifying files inplace')
    parser.add_argument('-f', '--text-only', action='store_true',
                        help='only perform search/replace in file contents, do'
                        'not rename any files')
    verbosity_group = parser.add_mutually_exclusive_group()
    verbosity_group.add_argument('-V', '--verbose', action='store_true',
                                 help='be verbose')
    verbosity_group.add_argument('-q', '--silent', action='store_true',
                                 help='be silent')
    parser.add_argument('source', metavar='SOURCE',
                        help='source string to be renamed')
    parser.add_argument('dest', metavar='DEST',
                        help='string to replace with')
    parser.add_argument('patterns', metavar='PATTERN', nargs='+',
                        help='shell-like file name patterns to process')
    return parser.parse_args()

def is_snake_case(id_name):
    """Check if id_name is written in snake case.

    Actually, it is restricted to a certain subset of snake case, so that
    we can guarantee camel->snake->camel roundtrip.

    >>> is_snake_case('')
    False
    >>> is_snake_case('_')
    False
    >>> is_snake_case('h')
    True
    >>> is_snake_case('hello_world')
    True
    >>> is_snake_case(' hello_world ')
    False
    >>> is_snake_case('_hello')
    False
    >>> is_snake_case('hello_')
    False
    >>> is_snake_case('__hello_world__')
    False
    >>> is_snake_case('_hello6_wor7d_')
    False
    >>> is_snake_case('hello6_wor7d')
    True
    >>> is_snake_case('hello__world')
    False
    >>> is_snake_case('hello-world')
    False
    >>> is_snake_case('HelloWorld')
    False
    >>> is_snake_case('ab6')
    True
    >>> is_snake_case('ab_6')
    False
    >>> is_snake_case('6_ab')
    False
    >>> is_snake_case('ab_6_ab6')
    False
    """

    snake_case_re = re.compile(r"""
            [a-z][a-z0-9]*      # first word is required, start w/ alpha
            (_[a-z][a-z0-9]*)*  # any number of words follow
            $
            """, re.VERBOSE)

    return snake_case_re.match(id_name) is not None

def is_camel_case(id_name):
    """Check if id_name is written in camel case.

    >>> is_camel_case('')
    False
    >>> is_camel_case('_')
    False
    >>> is_camel_case('h')
    False
    >>> is_camel_case('H')
    True
    >>> is_camel_case('HW')
    False
    >>> is_camel_case('hW')
    False
    >>> is_camel_case('hWW')
    False
    >>> is_camel_case('WhWhWhW')
    True
    >>> is_camel_case('HelloWorld')
    True
    >>> is_camel_case('HWorld')
    False
    >>> is_camel_case('Hello6orld')
    True
    >>> is_camel_case('hello_world')
    False
    >>> is_camel_case('_Hello')
    False
    >>> is_camel_case('Hello_')
    False
    >>> is_camel_case('hello-world')
    False
    >>> is_camel_case('HelloWorld')
    True
    >>> is_camel_case('HelloGoodWorld77')
    True
    """

    camel_case_re = re.compile(r"""
            ([A-Z](?![A-Z])[a-z0-9]*)+    # neg lookahead is to exclude
                                          # e.g HWorld
            $
            """, re.VERBOSE)

    return camel_case_re.match(id_name) is not None

def snake2camel(id_name):
    """Change id_name from snake to camel, provided it is in snake case,
    or else return id_name intact.

    >>> snake2camel('hello_world')
    'HelloWorld'
    >>> snake2camel('HelloWorld')
    'HelloWorld'
    >>> snake2camel('hello9')
    'Hello9'
    >>> snake2camel('hello9world')
    'Hello9world'
    >>> snake2camel('hello9_world')
    'Hello9World'
    >>> snake2camel('h')
    'H'
    >>> snake2camel('hw')
    'Hw'
    >>> snake2camel('hello_good_world77')
    'HelloGoodWorld77'
    """

    if not is_snake_case(id_name):
        return id_name

    word_start = re.compile(r'(\A|_)[a-z]')
    return word_start.sub(lambda x: x.group().lstrip('_').upper(), id_name)

def camel2snake(id_name):
    """Change id_name from camel to snake, provided it is in camel case,
    or else return id_name intact.

    >>> camel2snake('HelloWorld')
    'hello_world'
    >>> camel2snake('hello_world')
    'hello_world'
    >>> camel2snake('Hello8orld')
    'hello8orld'
    >>> camel2snake('H')
    'h'
    >>> camel2snake('Hw')
    'hw'
    >>> camel2snake('HelloGoodWorld77')
    'hello_good_world77'
    """

    if not is_camel_case(id_name):
        return id_name

    word_start = re.compile(r'[A-Z]')
    almost_ready = word_start.sub(lambda x: '_' + x.group().lower(), id_name)
    return almost_ready.lstrip('_')

def edit_line(src, dest, line, word_option=ANY_SEQUENCE):
    """Rename in a single line of text.

    >>> edit_line('hello_world', 'whats_up', 'hi hello_world <3')
    'hi whats_up <3'
    >>> edit_line('hello_world', 'whats_up', 'hi HelloWorld HELLO_WORLD <3')
    'hi WhatsUp WHATS_UP <3'
    >>> edit_line('HelloWorld', 'WhatsUp', 'hi HelloWorld HELLO_WORLD <3')
    'hi WhatsUp WHATS_UP <3'
    >>> edit_line('hello__world', 'WhatsUp', 'hi hello__world HELLO_WORLD <3')
    'hi WhatsUp HELLO_WORLD <3'
    >>> edit_line('hello_world', 'whats_up', 'hi hello_world <3', WHOLE_WORD)
    'hi whats_up <3'
    >>> edit_line('hl_wrld', 'whats_up', 'hiRhl_wrldR<3', ANY_SEQUENCE)
    'hiRwhats_upR<3'
    >>> edit_line('hl_wrld', 'whats_up', 'hiRhl_wrldR<3', WHOLE_WORD)
    'hiRhl_wrldR<3'
    >>> edit_line('hl_wrld', 'whats_up', 'hiRhl_wrldR<3', ALLOW_UNDERSCORES)
    'hiRhl_wrldR<3'
    >>> edit_line('hl_wrld', 'whats_up', '___hl_wrld__', ANY_SEQUENCE)
    '___whats_up__'
    >>> edit_line('hl_wrld', 'whats_up', '___hl_wrld__', ALLOW_UNDERSCORES)
    '___whats_up__'
    >>> edit_line('hl_wrld', 'whats_up', '___hl_wrld__', WHOLE_WORD)
    '___hl_wrld__'
    >>> edit_line('hl_wrld', 'whats_up', '___HlWrld__', ALLOW_UNDERSCORES)
    '___WhatsUp__'
    >>> edit_line('hex_clck', 'hacker_clck', '_HEX_CLCK_H', ALLOW_UNDERSCORES)
    '_HACKER_CLCK_H'
    """

    src_snake = camel2snake(src)
    dest_snake = camel2snake(dest)
    src_camel = snake2camel(src)
    dest_camel = snake2camel(dest)
    src_all_caps = src_snake.upper()
    dest_all_caps = dest_snake.upper()

    # if not recognized as snake or camel, both transforms will leave its
    # input string intact

    recognized = src_snake != src_camel and dest_snake != dest_camel
    if not recognized:
        logging.debug('case not recognized, performing plain search/replace')
        return line.replace(src, dest)

    if word_option == ANY_SEQUENCE:
        line = line.replace(src_snake, dest_snake)
        line = line.replace(src_camel, dest_camel)
        return line.replace(src_all_caps, dest_all_caps)

    if word_option == WHOLE_WORD:
        template = r'\b{}\b'

        src_snake = template.format(src_snake)
        src_camel = template.format(src_camel)
        src_all_caps = template.format(src_all_caps)

        line = re.sub(src_snake, dest_snake, line)
        line = re.sub(src_camel, dest_camel, line)
        return re.sub(src_all_caps, dest_all_caps, line)

    if word_option == ALLOW_UNDERSCORES:
        src_template = r'(\b|(_+)){}((_+)|\b)'
        dest_template = r'\1{}\3'

        src_snake = src_template.format(src_snake)
        src_camel = src_template.format(src_camel)
        src_all_caps = src_template.format(src_all_caps)

        dest_snake = dest_template.format(dest_snake)
        dest_camel = dest_template.format(dest_camel)
        dest_all_caps = dest_template.format(dest_all_caps)

        logging.debug('underscore caps: {}->{}'.format(src_all_caps,
                      dest_all_caps))
        line = re.sub(src_snake, dest_snake, line)
        line = re.sub(src_camel, dest_camel, line)
        return re.sub(src_all_caps, dest_all_caps, line)

def edit_text(src, dest, text_lines, word_option=ANY_SEQUENCE):
    """Rename in lines of text."""

    return [edit_line(src, dest, line, word_option) for line in text_lines]

def process_file(src, dest, word_option, path,  # pylint: disable=R0913
                 diff, text_only):
    """Rename in a file."""

    if is_binary(path):
        return

    if not text_only:
        new_path = edit_line(src, dest, path, word_option)
    else:
        new_path = path

    try:
        with io.open(path, 'r', encoding='utf-8') as in_file:
            in_lines = in_file.readlines()
    except IOError as e:
        logging.warn('could not read file: {0}, error message: {1}'
                .format(path, e))
        return
    except UnicodeDecodeError as e:
        logging.debug('could not read file: {0}, error message: {1}'
                .format(path, e))
        return

    out_lines = list(edit_text(src, dest, in_lines, word_option))

    if diff:
        diffs = difflib.unified_diff(in_lines, out_lines,
                                     fromfile=path, tofile=new_path)
        for line in diffs:
            sys.stdout.write(line)
    else:
        try:
            with io.open(new_path, 'w', encoding='utf-8') as out_file:
                out_file.writelines(out_lines)
        except IOError as e:
            logging.warn('could not read file: {0}, error message: {1}'
                    .format(path, e))

        if new_path != path:
            try:
                shutil.copymode(path, new_path)
                os.unlink(path)
            except OSError as e:
                logging.warn('could not delete file: {0}, error message: {1}'
                        .format(path,e))
                return

def main():
    """Main here."""

    args = parse_cmdline_args()
    severity_level = logging.DEBUG if args.verbose else logging.WARNING
    if args.silent:
        severity_level = logging.CRITICAL
    logging.basicConfig(stream=sys.stderr, level=severity_level)
    logging.debug(args)

    word_option = ANY_SEQUENCE
    if args.word:
        word_option = WHOLE_WORD
    elif args.almost_word:
        word_option = ALLOW_UNDERSCORES

    pathes = get_paths(args.patterns, start_dir=None, max_depth=None)
    for path in pathes:
        logging.debug('renaming in {}'.format(path))

        process_file(args.source, args.dest, word_option, path,
                     args.diff, args.text_only)

if __name__ == "__main__":
    sys.exit(main())
<|endoftext|>


<commit_before>#!/usr/bin/python

# Copyright (c) 2016, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import errno
import hmac
import os
import sys

from base64 import b16encode
from hashlib import sha256

from Crypto.Cipher import AES
from Crypto.Util import Counter

from fuse import FUSE, FuseOSError, Operations

__version__ = '0.1'

BLOCK_MASK = 15
BLOCK_SIZE = 16
BUFFER = 1024*16
MAC_SIZE = 16
VERIFY = True

class RencFS(Operations):
    def __init__(self, root, key, decrypt):
        self.root = root
        self.hmac = hmac.new(key[:16], digestmod=sha256)
        self.aes_ecb = AES.new(key[16:], AES.MODE_ECB)
        self.keys = {}
        self.decrypt = decrypt

    # Helpers

    def _fullpath(self, partial):
        if partial.startswith('/'):
            partial = partial[1:]
        path = os.path.join(self.root, partial)
        return path

    def _mac(self, path, h=''):
        pos, hmac = 0, self.hmac.copy()
        with open(self._fullpath(path)) as f:
            if self.decrypt:
                f.seek(MAC_SIZE)
                pos = MAC_SIZE
            while True:
                d = f.read(BUFFER)
                if not d:
                    break
                if self.decrypt:
                    pos, d = len(d), self._enc(h, pos, d)
                hmac.update(d)
        return hmac.digest()[:MAC_SIZE]

    def _getkey(self, path):
        if path in self.keys:
            return self.keys[path]
        if self.decrypt:
            h = open(self._fullpath(path)).read(MAC_SIZE)
            h = self.aes_ecb.decrypt(h)
            if VERIFY and h != self._mac(path, h):
                raise FuseOSError(errno.EPERM)
        else:
            h = self._mac(path)
        self.keys[path] = h
        return h

    def _enc(self, key, offset, data):
        if self.decrypt:
            offset -= MAC_SIZE
        index = offset // BLOCK_SIZE
        ctr = Counter.new(128, initial_value=index)
        aes = AES.new(key, AES.MODE_CTR, counter=ctr)
        if not offset & BLOCK_MASK:
            return aes.encrypt(data)
        data = '\0' * (offset & BLOCK_MASK) + data
        return aes.encrypt(data)[offset & BLOCK_MASK:]

    # Filesystem methods

    def access(self, path, mode):
        full_path = self._fullpath(path)
        if not os.access(full_path, mode):
            raise FuseOSError(errno.EACCES)

    def getattr(self, path, fh=None):
        full_path = self._fullpath(path)
        st = os.lstat(full_path)
        st = dict((key, getattr(st, key)) for key in (
            'st_atime', 'st_ctime', 'st_gid', 'st_mode',
            'st_mtime', 'st_nlink', 'st_size', 'st_uid'
        ))
        if self.decrypt:
            st['st_size'] -= MAC_SIZE
        else:
            st['st_size'] += MAC_SIZE
        return st

    def readdir(self, path, fh):
        full_path = self._fullpath(path)

        dirents = ['.', '..']
        if os.path.isdir(full_path):
            dirents.extend(os.listdir(full_path))
        for r in dirents:
            yield r

    def readlink(self, path):
        pathname = os.readlink(self._fullpath(path))
        if pathname.startswith("/"):
            # Path name is absolute, sanitize it.
            return os.path.relpath(pathname, self.root)
        else:
            return pathname

    def statfs(self, path):
        full_path = self._fullpath(path)
        stv = os.statvfs(full_path)
        return dict((key, getattr(stv, key)) for key in (
            'f_bavail', 'f_bfree', 'f_blocks', 'f_bsize', 'f_favail',
            'f_ffree', 'f_files', 'f_flag', 'f_frsize', 'f_namemax'
        ))

    def utimens(self, path, times=None):
        return os.utime(self._fullpath(path), times)

    # File methods

    def open(self, path, flags):
        full_path = self._fullpath(path)
        return os.open(full_path, flags)

    def create(self, path, mode, fi=None):
        raise FuseOSError(errno.EROFS)

    def read(self, path, length, offset, fh):
        data = ''
        h = self._getkey(path)
        if self.decrypt:
            offset += MAC_SIZE
        elif offset < MAC_SIZE:
            data = self.aes_ecb.encrypt(h)[offset:]
            length -= MAC_SIZE - offset
            offset = 0
        else:
            offset -= MAC_SIZE
        os.lseek(fh, offset, os.SEEK_SET)
        data += self._enc(h, offset, os.read(fh, length))
        return data

    def release(self, path, fh):
        self.keys.pop(path, None)
        return os.close(fh)

def main(mountpoint, root, rawkey, decrypt):
    key = sha256(rawkey).digest()
    FUSE(RencFS(root, key, decrypt), mountpoint, nothreads=True, foreground=True)

if __name__ == '__main__':
    main(sys.argv[2], sys.argv[1], sys.argv[3], '-d' in sys.argv)
<commit_msg>Use fh as key and avoid reopening file<commit_after>#!/usr/bin/python

# Copyright (c) 2016, Jan Varho
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

import errno
import hmac
import os
import sys

from base64 import b16encode
from hashlib import sha256

from Crypto.Cipher import AES
from Crypto.Util import Counter

from fuse import FUSE, FuseOSError, Operations

__version__ = '0.1'

BLOCK_MASK = 15
BLOCK_SIZE = 16
BUFFER_SIZE = 1024*16
MAC_SIZE = 16
VERIFY = True

class RencFS(Operations):
    def __init__(self, root, key, decrypt):
        self.root = root
        self.hmac = hmac.new(key[:16], digestmod=sha256)
        self.aes_ecb = AES.new(key[16:], AES.MODE_ECB)
        self.keys = {}
        self.decrypt = decrypt

    # Helpers

    def _fullpath(self, partial):
        if partial.startswith('/'):
            partial = partial[1:]
        path = os.path.join(self.root, partial)
        return path

    def _mac(self, fh, h=''):
        pos, hmac = 0, self.hmac.copy()
        if self.decrypt:
            pos = MAC_SIZE
        os.lseek(fh, pos, os.SEEK_SET)
        while True:
            d = os.read(fh, BUFFER_SIZE)
            if not d:
                break
            if self.decrypt:
                pos, d = len(d), self._enc(h, pos, d)
            hmac.update(d)
        return hmac.digest()[:MAC_SIZE]

    def _getkey(self, fh):
        if fh in self.keys:
            return self.keys[fh]
        if self.decrypt:
            os.lseek(fh, 0, os.SEEK_SET)
            h = self.aes_ecb.decrypt(os.read(fh, MAC_SIZE))
            if VERIFY and h != self._mac(fh, h):
                raise FuseOSError(errno.EPERM)
        else:
            h = self._mac(fh)
        self.keys[fh] = h
        return h

    def _enc(self, key, offset, data):
        if self.decrypt:
            offset -= MAC_SIZE
        index = offset // BLOCK_SIZE
        ctr = Counter.new(128, initial_value=index)
        aes = AES.new(key, AES.MODE_CTR, counter=ctr)
        if not offset & BLOCK_MASK:
            return aes.encrypt(data)
        data = '\0' * (offset & BLOCK_MASK) + data
        return aes.encrypt(data)[offset & BLOCK_MASK:]

    # Filesystem methods

    def access(self, path, mode):
        full_path = self._fullpath(path)
        if not os.access(full_path, mode):
            raise FuseOSError(errno.EACCES)

    def getattr(self, path, fh=None):
        full_path = self._fullpath(path)
        st = os.lstat(full_path)
        st = dict((key, getattr(st, key)) for key in (
            'st_atime', 'st_ctime', 'st_gid', 'st_mode',
            'st_mtime', 'st_nlink', 'st_size', 'st_uid'
        ))
        if self.decrypt:
            st['st_size'] -= MAC_SIZE
        else:
            st['st_size'] += MAC_SIZE
        return st

    def readdir(self, path, fh):
        full_path = self._fullpath(path)

        dirents = ['.', '..']
        if os.path.isdir(full_path):
            dirents.extend(os.listdir(full_path))
        for r in dirents:
            yield r

    def readlink(self, path):
        pathname = os.readlink(self._fullpath(path))
        if pathname.startswith("/"):
            # Path name is absolute, sanitize it.
            return os.path.relpath(pathname, self.root)
        else:
            return pathname

    def statfs(self, path):
        full_path = self._fullpath(path)
        stv = os.statvfs(full_path)
        return dict((key, getattr(stv, key)) for key in (
            'f_bavail', 'f_bfree', 'f_blocks', 'f_bsize', 'f_favail',
            'f_ffree', 'f_files', 'f_flag', 'f_frsize', 'f_namemax'
        ))

    def utimens(self, path, times=None):
        return os.utime(self._fullpath(path), times)

    # File methods

    def open(self, path, flags):
        full_path = self._fullpath(path)
        return os.open(full_path, flags)

    def create(self, path, mode, fi=None):
        raise FuseOSError(errno.EROFS)

    def read(self, path, length, offset, fh):
        data = ''
        h = self._getkey(fh)
        if self.decrypt:
            offset += MAC_SIZE
        elif offset < MAC_SIZE:
            data = self.aes_ecb.encrypt(h)[offset:]
            length -= MAC_SIZE - offset
            offset = 0
        else:
            offset -= MAC_SIZE
        os.lseek(fh, offset, os.SEEK_SET)
        data += self._enc(h, offset, os.read(fh, length))
        return data

    def release(self, path, fh):
        self.keys.pop(fh, None)
        return os.close(fh)

def main(mountpoint, root, rawkey, decrypt):
    key = sha256(rawkey).digest()
    FUSE(RencFS(root, key, decrypt), mountpoint, nothreads=True, foreground=True)

if __name__ == '__main__':
    main(sys.argv[2], sys.argv[1], sys.argv[3], '-d' in sys.argv)
<|endoftext|>


<commit_before>#   Author: Jeremy Schulman (nwkautomaniac@gmail.com)
#
#   This code is free software: you can redistribute it and/or modify
#   it under the terms of the MIT License.
#
#   The author provides no warranties regarding the software, which is
#   provided "AS-IS" and your use of this software is entirely at your
#   own risk.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR DAMAGES OF ANY
#   KIND RELATING TO USE OF THE SOFTWARE, INCLUDING WITHOUT LIMITATION
#   ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#   DAMAGES; ANY PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION, HOWEVER CAUSED AND ON ANY
#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#   (INCLUDING NEGLIGENCE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os
import jinja2
import csv

TEMPLATE_FILENAME = 'cisco.j2'
CSVDATA_FILENAME = 'hosts_data.csv'

## ---------------------------------------------------------------------------
## create a jinja2 environment and load the template file
## ---------------------------------------------------------------------------

env = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.getcwd()),
    trim_blocks=True, lstrip_blocks=True)

template = env.get_template(TEMPLATE_FILENAME)

## ---------------------------------------------------------------------------
## define a function that will transform the "vlan_name_<n>" and "vlan_id_<n>"
## into a new dictionary called 'vlans'
## ---------------------------------------------------------------------------

def transform_vlan_data(row):
    # the first thing we want to do is remove all fields that start with
    # "vlan_" from the original dictionary.  we only want to keep the
    # fields that do not have a value of "0" as the csv-data uses "0" to
    # indicate a non-used vlan.  The result is a dictionary.

    vlan_fields = {
        field_name: field_value
        for field_name, field_value in row.items()
        if field_name.startswith('vlan_') and row.pop(field_name)
        if field_value != '0'
    }

    # now that we have that field list, we want to map the "vlan_name_<n>"
    # values to the actual "vlan_id_<n>" values.  we want to create a new
    # entry in the original dictionary called 'vlans' to store this new
    # vlan dictionary.  We also need to handle the case when the vlan name
    # has whitespace; so covert spaces to underscoores (_).

    row['vlans'] = {
        vlan_fields[f].replace(' ', '_'): vlan_fields[f.replace('name', 'id')]
        for f in vlan_fields if f.startswith('vlan_name')
    }

## ---------------------------------------------------------------------------
## now read the CSV file, processing each row, and creating a
## rendered file for each 'hostname'
## ---------------------------------------------------------------------------

for row in csv.DictReader(open(CSVDATA_FILENAME)):
    transform_vlan_data(row)
    with open(row['hostname'] + '.txt', 'w+') as f:
        f.write(template.render(row))

##
## all done!
##
<commit_msg>updates<commit_after>#   Author: Jeremy Schulman (nwkautomaniac@gmail.com)
#
#   This code is free software: you can redistribute it and/or modify
#   it under the terms of the MIT License.
#
#   The author provides no warranties regarding the software, which is
#   provided "AS-IS" and your use of this software is entirely at your
#   own risk.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR DAMAGES OF ANY
#   KIND RELATING TO USE OF THE SOFTWARE, INCLUDING WITHOUT LIMITATION
#   ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
#   DAMAGES; ANY PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
#   DATA, OR PROFITS; OR BUSINESS INTERRUPTION, HOWEVER CAUSED AND ON ANY
#   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
#   (INCLUDING NEGLIGENCE), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import os
import jinja2
import csv

TEMPLATE_FILENAME = 'cisco.j2'
CSVDATA_FILENAME = 'hosts_data.csv'

## ---------------------------------------------------------------------------
## define a function that will transform the "vlan_name_<n>" and "vlan_id_<n>"
## into a new dictionary called 'vlans'
## ---------------------------------------------------------------------------

def transform_vlan_data(row):
    # the first thing we want to do is remove all fields that start with
    # "vlan_" from the original dictionary.  we only want to keep the
    # fields that do not have a value of "0" as the csv-data uses "0" to
    # indicate a non-used vlan.  The result is a dictionary.

    vlan_fields = {
        field_name: field_value
        for field_name, field_value in row.items()
        if field_name.startswith('vlan_') and row.pop(field_name)
        if field_value != '0'
    }

    # now that we have that field list, we want to map the "vlan_name_<n>"
    # values to the actual "vlan_id_<n>" values.  we want to create a new
    # entry in the original dictionary called 'vlans' to store this new
    # vlan dictionary.  We also need to handle the case when the vlan name
    # has whitespace; so covert spaces to underscoores (_).

    row['vlans'] = {
        vlan_fields[f].replace(' ', '_'): vlan_fields[f.replace('name', 'id')]
        for f in vlan_fields if f.startswith('vlan_name')
    }

## ---------------------------------------------------------------------------
## create a jinja2 environment and load the template file
## ---------------------------------------------------------------------------

env = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.getcwd()),
    trim_blocks=True, lstrip_blocks=True)

template = env.get_template(TEMPLATE_FILENAME)

## ---------------------------------------------------------------------------
## now read the CSV file, processing each row, and creating a
## rendered file for each 'hostname'
## ---------------------------------------------------------------------------

for row in csv.DictReader(open(CSVDATA_FILENAME)):
    transform_vlan_data(row)
    with open(row['hostname'] + '.txt', 'w+') as f:
        f.write(template.render(row))

##
## all done!
##
<|endoftext|>


<commit_before>
#
# This source file is part of appleseed.
# Visit http://appleseedhq.net/ for additional information and resources.
#
# This software is released under the MIT license.
#
# Copyright (c) 2014-2017 The appleseedhq Organization
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

import array
import os
import struct
import subprocess
import sys
import threading
from shutil import copyfile

import bpy
from extensions_framework import util as efutil

from . import project_file_writer
from . import util
from .properties.scene import threads

class RenderAppleseed(bpy.types.RenderEngine):
    bl_idname = 'APPLESEED_RENDER'
    bl_label = 'appleseed'
    bl_use_preview = True

    # This lock allows to serialize renders.
    render_lock = threading.Lock()

    def __init__(self):
        pass

    def update(self, data, scene):
        pass

    def render(self, scene):
        with RenderAppleseed.render_lock:
            if self.is_preview:
                if not bpy.app.background:
                    self.__render_material_preview(scene)
            elif self.is_animation:
                frame_current = scene.frame_start
                while frame_current <= scene.frame_end:
                    scene.frame_set(frame_current)
                    self.__render_scene(scene)
                    frame_current += scene.frame_step
            else:
                self.__render_scene(scene)

    def __render_scene(self, scene):
        """
        Export and render the scene.
        """

        # Write project file and export meshes.
        bpy.ops.appleseed.export()

        if scene.appleseed.project_path == '':
            self.report({'INFO'}, "Please first specify a project path in the appleseed render settings.")
            return

        # Make sure the project directory exists.
        project_dir = util.realpath(scene.appleseed.project_path)
        if not os.path.exists(project_dir):
            try:
                os.makedirs(project_dir)
            except os.error:
                self.report({"ERROR"}, "The project directory could not be created. Check directory permissions.")
                return

        # Build the file path for the appleseed project.
        project_filepath = scene.name
        if not project_filepath.endswith(".appleseed"):
            project_filepath += ".appleseed"
        project_filepath = os.path.join(project_dir, project_filepath)

        # Render the project.
        self.__render_project_file(scene, project_filepath)

    def __render_material_preview(self, scene):
        """
        Export and render the material preview scene.
        """

        # Don't render material thumbnails.
        (width, height) = util.get_render_resolution(scene)
        print(width, height)
        if width <= 96:
            return

        # Collect objects and their materials in a object -> [materials] dictionary.
        objects_materials = {}
        for obj in (obj for obj in scene.objects if obj.is_visible(scene) and not obj.hide_render):
            for mat in util.get_instance_materials(obj):
                if mat is not None:
                    if obj.name not in objects_materials.keys():
                        objects_materials[obj] = []
                    objects_materials[obj].append(mat)

        # Find objects that are likely to be the preview objects.
        preview_objects = [o for o in objects_materials.keys() if o.name.startswith('preview')]
        if not preview_objects:
            return

        # Find the materials attached to the likely preview object.
        likely_materials = objects_materials[preview_objects[0]]
        if not likely_materials:
            return

        # Build the path to the template preview project in the add-on directory.
        preview_template_dir = os.path.join(os.sep.join(util.realpath(__file__).split(os.sep)[:-1]), "mat_preview")

        # Build the path to the output preview project.
        preview_output_dir = os.path.join(efutil.temp_directory(), "mat_preview")
        preview_project_filepath = os.path.join(preview_output_dir, "mat_preview.appleseed")

        # Copy preview scene assets.
        if not os.path.isdir(preview_output_dir):
            os.mkdir(preview_output_dir)
        existing_files = os.listdir(preview_output_dir)
        for item in os.listdir(preview_template_dir):
            if item not in existing_files:
                copyfile(os.path.join(preview_template_dir, item), os.path.join(preview_output_dir, item))

        prev_mat = likely_materials[0]
        prev_type = prev_mat.preview_render_type.lower()

        # Export the project.
        exporter = project_file_writer.Exporter()
        file_written = exporter.export_preview(scene,
                                               preview_project_filepath,
                                               preview_template_dir,
                                               prev_mat,
                                               prev_type,
                                               width,
                                               height)
        if not file_written:
            print('Error while exporting -- check the console for details.')
            return

        # Render the project.
        self.__render_project_file(scene, preview_project_filepath)

    def __render_project_file(self, scene, project_filepath):
        # Get the absolute path to the executable directory.
        as_bin_path = util.realpath(bpy.context.user_preferences.addons['blenderseed'].preferences.appleseed_bin_path)
        if as_bin_path == '':
            self.report({'ERROR'}, "The path to appleseed.cli executable has not been specified. Set the path in the add-on user preferences.")
            return
        appleseed_exe = os.path.join(as_bin_path, "appleseed.cli")

        # If running Linux/macOS, add the binary path to environment.
        if sys.platform != "win32":
            os.environ['LD_LIBRARY_PATH'] = as_bin_path

        # Compute render resolution.
        (width, height) = util.get_render_resolution(scene)

        # Compute render window.
        x0, y0, x1, y1 = 0, 0, width, height
        if scene.render.use_border:
            x0 = int(scene.render.border_min_x * width)
            x1 = int(scene.render.border_max_x * width)
            y0 = height - int(scene.render.border_min_y * height)
            y1 = height - int(scene.render.border_max_y * height)

        # Launch appleseed.cli.
        cmd = (appleseed_exe,
               project_filepath,
               '--to-stdout',
               '--threads', str(threads),
               '--message-verbosity', 'warning',
               '--resolution', str(width), str(height),
               '--window', str(x0), str(y0), str(x1), str(y1))
        process = subprocess.Popen(cmd, cwd=as_bin_path, env=os.environ.copy(), stdout=subprocess.PIPE)

        self.update_stats("", "appleseed: Rendering")

        # Update while rendering.
        while not self.test_break():
            # Wait for the next chunk header from the process's stdout.
            chunk_header_data = os.read(process.stdout.fileno(), 2 * 4)
            if not chunk_header_data:
                break

            # Decode chunk header.
            chunk_header = struct.unpack("II", chunk_header_data)
            chunk_type = chunk_header[0]
            chunk_size = chunk_header[1]

            # Ignore unknown chunks.
            # Known chunk types:
            #   1 = tile, protocol version 1
            if chunk_type != 1:
                os.read(process.stdout.fileno(), chunk_size)
                continue

            # Read and decode tile header.
            tile_header = struct.unpack("IIIII", os.read(process.stdout.fileno(), 5 * 4))
            tile_x = tile_header[0]
            tile_y = tile_header[1]
            tile_w = tile_header[2]
            tile_h = tile_header[3]
            tile_c = tile_header[4]

            # Read tile data.
            tile_size = 4 * tile_w * tile_h * tile_c
            tile_data = bytes()
            while len(tile_data) < tile_size and not self.test_break():
                tile_data += os.read(process.stdout.fileno(), tile_size - len(tile_data))
            if self.test_break():
                break

            # Optional debug message.
            if False:
                print("Received tile: x={0} y={1} w={2} h={3} c={4}".format(tile_x, tile_y, tile_w, tile_h, tile_c))

            # Update image.
            result = self.begin_result(tile_x, height - tile_y - tile_h, tile_w, tile_h)
            layer = result.layers[0] if bpy.app.version < (2, 74, 4) else result.layers[0].passes[0]
            floats = array.array('f')
            floats.fromstring(tile_data)
            pix = []
            for y in range(tile_h - 1, -1, -1):
                stride = tile_w * 4
                start_index = y * stride
                end_index = start_index + stride
                pix.extend(floats[i:i + 4] for i in range(start_index, end_index, 4))
            layer.rect = pix
            self.end_result(result)

        # Make sure the appleseed.cli process has terminated.
        process.kill()
<commit_msg>Remove debug output<commit_after>
#
# This source file is part of appleseed.
# Visit http://appleseedhq.net/ for additional information and resources.
#
# This software is released under the MIT license.
#
# Copyright (c) 2014-2017 The appleseedhq Organization
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#

import array
import os
import struct
import subprocess
import sys
import threading
from shutil import copyfile

import bpy
from extensions_framework import util as efutil

from . import project_file_writer
from . import util
from .properties.scene import threads

class RenderAppleseed(bpy.types.RenderEngine):
    bl_idname = 'APPLESEED_RENDER'
    bl_label = 'appleseed'
    bl_use_preview = True

    # This lock allows to serialize renders.
    render_lock = threading.Lock()

    def __init__(self):
        pass

    def update(self, data, scene):
        pass

    def render(self, scene):
        with RenderAppleseed.render_lock:
            if self.is_preview:
                if not bpy.app.background:
                    self.__render_material_preview(scene)
            elif self.is_animation:
                frame_current = scene.frame_start
                while frame_current <= scene.frame_end:
                    scene.frame_set(frame_current)
                    self.__render_scene(scene)
                    frame_current += scene.frame_step
            else:
                self.__render_scene(scene)

    def __render_scene(self, scene):
        """
        Export and render the scene.
        """

        # Write project file and export meshes.
        bpy.ops.appleseed.export()

        if scene.appleseed.project_path == '':
            self.report({'INFO'}, "Please first specify a project path in the appleseed render settings.")
            return

        # Make sure the project directory exists.
        project_dir = util.realpath(scene.appleseed.project_path)
        if not os.path.exists(project_dir):
            try:
                os.makedirs(project_dir)
            except os.error:
                self.report({"ERROR"}, "The project directory could not be created. Check directory permissions.")
                return

        # Build the file path for the appleseed project.
        project_filepath = scene.name
        if not project_filepath.endswith(".appleseed"):
            project_filepath += ".appleseed"
        project_filepath = os.path.join(project_dir, project_filepath)

        # Render the project.
        self.__render_project_file(scene, project_filepath)

    def __render_material_preview(self, scene):
        """
        Export and render the material preview scene.
        """

        # Don't render material thumbnails.
        (width, height) = util.get_render_resolution(scene)
        if width <= 96:
            return

        # Collect objects and their materials in a object -> [materials] dictionary.
        objects_materials = {}
        for obj in (obj for obj in scene.objects if obj.is_visible(scene) and not obj.hide_render):
            for mat in util.get_instance_materials(obj):
                if mat is not None:
                    if obj.name not in objects_materials.keys():
                        objects_materials[obj] = []
                    objects_materials[obj].append(mat)

        # Find objects that are likely to be the preview objects.
        preview_objects = [o for o in objects_materials.keys() if o.name.startswith('preview')]
        if not preview_objects:
            return

        # Find the materials attached to the likely preview object.
        likely_materials = objects_materials[preview_objects[0]]
        if not likely_materials:
            return

        # Build the path to the template preview project in the add-on directory.
        preview_template_dir = os.path.join(os.sep.join(util.realpath(__file__).split(os.sep)[:-1]), "mat_preview")

        # Build the path to the output preview project.
        preview_output_dir = os.path.join(efutil.temp_directory(), "mat_preview")
        preview_project_filepath = os.path.join(preview_output_dir, "mat_preview.appleseed")

        # Copy preview scene assets.
        if not os.path.isdir(preview_output_dir):
            os.mkdir(preview_output_dir)
        existing_files = os.listdir(preview_output_dir)
        for item in os.listdir(preview_template_dir):
            if item not in existing_files:
                copyfile(os.path.join(preview_template_dir, item), os.path.join(preview_output_dir, item))

        prev_mat = likely_materials[0]
        prev_type = prev_mat.preview_render_type.lower()

        # Export the project.
        exporter = project_file_writer.Exporter()
        file_written = exporter.export_preview(scene,
                                               preview_project_filepath,
                                               preview_template_dir,
                                               prev_mat,
                                               prev_type,
                                               width,
                                               height)
        if not file_written:
            print('Error while exporting -- check the console for details.')
            return

        # Render the project.
        self.__render_project_file(scene, preview_project_filepath)

    def __render_project_file(self, scene, project_filepath):
        # Get the absolute path to the executable directory.
        as_bin_path = util.realpath(bpy.context.user_preferences.addons['blenderseed'].preferences.appleseed_bin_path)
        if as_bin_path == '':
            self.report({'ERROR'}, "The path to appleseed.cli executable has not been specified. Set the path in the add-on user preferences.")
            return
        appleseed_exe = os.path.join(as_bin_path, "appleseed.cli")

        # If running Linux/macOS, add the binary path to environment.
        if sys.platform != "win32":
            os.environ['LD_LIBRARY_PATH'] = as_bin_path

        # Compute render resolution.
        (width, height) = util.get_render_resolution(scene)

        # Compute render window.
        x0, y0, x1, y1 = 0, 0, width, height
        if scene.render.use_border:
            x0 = int(scene.render.border_min_x * width)
            x1 = int(scene.render.border_max_x * width)
            y0 = height - int(scene.render.border_min_y * height)
            y1 = height - int(scene.render.border_max_y * height)

        # Launch appleseed.cli.
        cmd = (appleseed_exe,
               project_filepath,
               '--to-stdout',
               '--threads', str(threads),
               '--message-verbosity', 'warning',
               '--resolution', str(width), str(height),
               '--window', str(x0), str(y0), str(x1), str(y1))
        process = subprocess.Popen(cmd, cwd=as_bin_path, env=os.environ.copy(), stdout=subprocess.PIPE)

        self.update_stats("", "appleseed: Rendering")

        # Update while rendering.
        while not self.test_break():
            # Wait for the next chunk header from the process's stdout.
            chunk_header_data = os.read(process.stdout.fileno(), 2 * 4)
            if not chunk_header_data:
                break

            # Decode chunk header.
            chunk_header = struct.unpack("II", chunk_header_data)
            chunk_type = chunk_header[0]
            chunk_size = chunk_header[1]

            # Ignore unknown chunks.
            # Known chunk types:
            #   1 = tile, protocol version 1
            if chunk_type != 1:
                os.read(process.stdout.fileno(), chunk_size)
                continue

            # Read and decode tile header.
            tile_header = struct.unpack("IIIII", os.read(process.stdout.fileno(), 5 * 4))
            tile_x = tile_header[0]
            tile_y = tile_header[1]
            tile_w = tile_header[2]
            tile_h = tile_header[3]
            tile_c = tile_header[4]

            # Read tile data.
            tile_size = 4 * tile_w * tile_h * tile_c
            tile_data = bytes()
            while len(tile_data) < tile_size and not self.test_break():
                tile_data += os.read(process.stdout.fileno(), tile_size - len(tile_data))
            if self.test_break():
                break

            # Optional debug message.
            if False:
                print("Received tile: x={0} y={1} w={2} h={3} c={4}".format(tile_x, tile_y, tile_w, tile_h, tile_c))

            # Update image.
            result = self.begin_result(tile_x, height - tile_y - tile_h, tile_w, tile_h)
            layer = result.layers[0] if bpy.app.version < (2, 74, 4) else result.layers[0].passes[0]
            floats = array.array('f')
            floats.fromstring(tile_data)
            pix = []
            for y in range(tile_h - 1, -1, -1):
                stride = tile_w * 4
                start_index = y * stride
                end_index = start_index + stride
                pix.extend(floats[i:i + 4] for i in range(start_index, end_index, 4))
            layer.rect = pix
            self.end_result(result)

        # Make sure the appleseed.cli process has terminated.
        process.kill()
<|endoftext|>


<commit_before>#! /usr/bin/python2
# render.py - Render the complete website.
# Author: Franck Michea < franck.michea@gmail.com >

import argparse
import os
import shutil
import sys

import lpbm.articles
import lpbm.authors
import lpbm.categories
import lpbm.rss
import lpbm.templates

def clean_tree():
    # Cleaning output tree.
    if os.path.isdir(lpbm.constants.ROOT_OUTPUT):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT)
    if os.path.isdir(lpbm.constants.ROOT_OUTPUT_STYLESHEETS):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT_STYLESHEETS)
    if os.path.isdir(lpbm.constants.ROOT_OUTPUT_IMAGES):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT_IMAGES)

def build_blog(ct_mgr, aut_mgr, art_mgr):
    lpbm.templates.render(art_mgr, aut_mgr, cat_mgr)

    if os.path.isdir(lpbm.constants.ROOT_OUTPUT_IMAGES):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT_IMAGES)
    shutil.copytree(lpbm.constants.ROOT_IMAGES,
                    lpbm.constants.ROOT_OUTPUT_IMAGES)

def build_rss(cat_mgr, aut_mgr, art_mgr):
    lpbm.rss.render(art_mgr, aut_mgr, cat_mgr)

if __name__ == '__main__':
    # Command line arguments.
    parser = argparse.ArgumentParser(
        description='Lightweight Personal Blog Maker'
    )
    parser.add_argument('-c', '--clean', action='store_true', default=False,
                        help='Clean output tree before generation.')
    parser.add_argument('-B', '--no-blog', action='store_true', default=False,
                        help='Avoid generating blog.')
    parser.add_argument('-R', '--no-rss', action='store_true', default=False,
                        help='Avoid generating RSS.')
    args = parser.parse_args(sys.argv[1:])

    # Doing what is asked.
    if args.clean: clean_tree()

    # Parsing articles, authors and generating categories.
    if not args.no_blog or not args.no_rss:
        cat_mgr = lpbm.categories.CategoryManager('Categories')
        aut_mgr = lpbm.authors.AuthorsManager()
        art_mgr = lpbm.articles.ArticlesManager(aut_mgr, cat_mgr)

    # Generating what is asked.
    if not args.no_blog:
        build_blog(cat_mgr, aut_mgr, art_mgr)
    if not args.no_rss:
        build_rss(cat_mgr, aut_mgr, art_mgr)
<commit_msg>Copy images from the source directory<commit_after>#! /usr/bin/python2
# render.py - Render the complete website.
# Author: Franck Michea < franck.michea@gmail.com >

import argparse
import os
import shutil
import sys

import lpbm.articles
import lpbm.authors
import lpbm.categories
import lpbm.rss
import lpbm.templates

def clean_tree():
    # Cleaning output tree.
    if os.path.isdir(lpbm.constants.ROOT_OUTPUT):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT)
    if os.path.isdir(lpbm.constants.ROOT_OUTPUT_STYLESHEETS):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT_STYLESHEETS)
    if os.path.isdir(lpbm.constants.ROOT_OUTPUT_IMAGES):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT_IMAGES)

def build_blog(ct_mgr, aut_mgr, art_mgr):
    lpbm.templates.render(art_mgr, aut_mgr, cat_mgr)

    if os.path.isdir(lpbm.constants.ROOT_OUTPUT_IMAGES):
        shutil.rmtree(lpbm.constants.ROOT_OUTPUT_IMAGES)
    os.makedirs(lpbm.constants.ROOT_OUTPUT_IMAGES)

    # Copy images using os.system, like a man.
    os.system("cp -R '%s'/* '%s'/* '%s' >/dev/null 2>&1" % (
        lpbm.constants.ROOT_IMAGES,
        lpbm.constants.ROOT_SRC_IMAGES,
        lpbm.constants.ROOT_OUTPUT_IMAGES
    ))

def build_rss(cat_mgr, aut_mgr, art_mgr):
    lpbm.rss.render(art_mgr, aut_mgr, cat_mgr)

if __name__ == '__main__':
    # Command line arguments.
    parser = argparse.ArgumentParser(
        description='Lightweight Personal Blog Maker'
    )
    parser.add_argument('-c', '--clean', action='store_true', default=False,
                        help='Clean output tree before generation.')
    parser.add_argument('-B', '--no-blog', action='store_true', default=False,
                        help='Avoid generating blog.')
    parser.add_argument('-R', '--no-rss', action='store_true', default=False,
                        help='Avoid generating RSS.')
    args = parser.parse_args(sys.argv[1:])

    # Doing what is asked.
    if args.clean: clean_tree()

    # Parsing articles, authors and generating categories.
    if not args.no_blog or not args.no_rss:
        cat_mgr = lpbm.categories.CategoryManager('Categories')
        aut_mgr = lpbm.authors.AuthorsManager()
        art_mgr = lpbm.articles.ArticlesManager(aut_mgr, cat_mgr)

    # Generating what is asked.
    if not args.no_blog:
        build_blog(cat_mgr, aut_mgr, art_mgr)
    if not args.no_rss:
        build_rss(cat_mgr, aut_mgr, art_mgr)
<|endoftext|>


<commit_before>import glfw

import moderngl
from demosys.scene import camera
from demosys.view import screenshot
from demosys.opengl import FBO
from demosys import context
from .base import Window

class GLFW_Window(Window):
    min_glfw_version = (3, 2, 1)

    def __init__(self):
        super().__init__()

        if not glfw.init():
            raise ValueError("Failed to initialize glfw")

        self.check_glfw_version()

        glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, self.gl_version.major)
        glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, self.gl_version.minor)
        glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
        glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
        glfw.window_hint(glfw.RESIZABLE, self.resizable)
        glfw.window_hint(glfw.DOUBLEBUFFER, True)
        glfw.window_hint(glfw.DEPTH_BITS, 24)

        monitor = None
        if self.fullscreen:
            # Use the primary monitors current resolution
            monitor = glfw.get_primary_monitor()
            mode = glfw.get_video_mode(monitor)

            self.width, self.height = mode.size.width, mode.size.height
            print("picked fullscreen mode:", mode)

        print("Window size:", self.width, self.height)
        self.window = glfw.create_window(self.width, self.height, self.title, monitor, None)

        if not self.window:
            glfw.terminate()
            raise ValueError("Failed to create window")

        if not self.cursor:
            glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED)

        # Get the actual buffer size of the window
        # This is important for some displays like Apple's Retina as reported window sizes are virtual
        self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window)
        print("Frame buffer size:", self.buffer_width, self.buffer_height)
        print("Actual window size:", glfw.get_window_size(self.window))

        glfw.make_context_current(self.window)

        # The number of screen updates to wait from the time glfwSwapBuffers
        # was called before swapping the buffers and returning
        if self.vsync:
            glfw.swap_interval(1)

        glfw.set_key_callback(self.window, self.key_event_callback)
        glfw.set_cursor_pos_callback(self.window, self.mouse_event_callback)
        glfw.set_window_size_callback(self.window, self.window_resize_callback)

        # Create mederngl context from existing context
        self.ctx = moderngl.create_context()
        self.fbo = FBO()
        self.fbo.ctx = self.ctx
        self.fbo.fbo = self.ctx.screen
        self.fbo.default_framebuffer = True
        context.WINDOW = self
        self.set_default_viewport()

    def use(self):
        self.ctx.screen.use()

    def should_close(self):
        return glfw.window_should_close(self.window)

    def close(self):
        glfw.set_window_should_close(self.window, True)

    def swap_buffers(self):
        self.frames += 1
        glfw.swap_buffers(self.window)
        self.poll_events()

    def resize(self, width, height):
        self.width = width
        self.height = height
        self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window)
        print("Resize:", self.width, self.height, self.buffer_width, self.buffer_height)
        super().resize(width, height)

    def terminate(self):
        glfw.terminate()

    def poll_events(self):
        """Poll events from glfw"""
        glfw.poll_events()

    def check_glfw_version(self):
        """Ensure glfw version is compatible"""
        print("glfw version: {} (python wrapper version {})".format(glfw.get_version(), glfw.__version__))
        if glfw.get_version() < self.min_glfw_version:
            raise ValueError("Please update glfw binaries to version {} or later".format(self.min_glfw_version))

    def key_event_callback(self, window, key, scancode, action, mods):
        """
        Key event callback for glfw

        :param window: Window event origin
        :param key: The keyboard key that was pressed or released.
        :param scancode: The system-specific scancode of the key.
        :param action: GLFW_PRESS, GLFW_RELEASE or GLFW_REPEAT
        :param mods: Bit field describing which modifier keys were held down.
        """
        # print("Key event:", key, scancode, action, mods)

        # The well-known standard key for quick exit
        if key == glfw.KEY_ESCAPE:
            self.close()
            return

        # Toggle pause time
        if key == glfw.KEY_SPACE and action == glfw.PRESS:
            self.timer.toggle_pause()

        # Camera movement
        # Right
        if key == glfw.KEY_D:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.RIGHT, True)
            elif action == glfw.RELEASE:
                self.sys_camera.move_state(camera.RIGHT, False)
        # Left
        elif key == glfw.KEY_A:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.LEFT, True)
            elif action == glfw.RELEASE:
                self.sys_camera.move_state(camera.LEFT, False)
        # Forward
        elif key == glfw.KEY_W:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.FORWARD, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.FORWARD, False)
        # Backwards
        elif key == glfw.KEY_S:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.BACKWARD, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.BACKWARD, False)

        # UP
        elif key == glfw.KEY_Q:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.UP, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.UP, False)

        # Down
        elif key == glfw.KEY_E:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.DOWN, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.DOWN, False)

        # Screenshots
        if key == glfw.KEY_X and action == glfw.PRESS:
            screenshot.create()

        if key == glfw.KEY_R and action == glfw.PRESS:
            self.resources.shaders.reload()

        # Forward the event to the effect manager
        self.manager.key_event(key, scancode, action, mods)

    def mouse_event_callback(self, window, xpos, ypos):
        """
        Mouse event callback from glfw

        :param window: The window
        :param xpos: viewport x pos
        :param ypos: viewport y pos
        """
        self.sys_camera.rot_state(xpos, ypos)

    def window_resize_callback(self, window, width, height):
        """
        Window resize callback for glfw

        :param window: The window
        :param width: New width
        :param height: New height
        """
        print("Resize", width, height)
        self.resize(width, height)
<commit_msg>glfw init bug<commit_after>import glfw

import moderngl
from demosys.scene import camera
from demosys.view import screenshot
from demosys.opengl import FBO
from demosys import context
from .base import Window

class GLFW_Window(Window):
    min_glfw_version = (3, 2, 1)

    def __init__(self):
        super().__init__()

        if not glfw.init():
            raise ValueError("Failed to initialize glfw")

        self.check_glfw_version()

        glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, self.gl_version.major)
        glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, self.gl_version.minor)
        glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
        glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
        glfw.window_hint(glfw.RESIZABLE, self.resizable)
        glfw.window_hint(glfw.DOUBLEBUFFER, True)
        glfw.window_hint(glfw.DEPTH_BITS, 24)

        monitor = None
        if self.fullscreen:
            # Use the primary monitors current resolution
            monitor = glfw.get_primary_monitor()
            mode = glfw.get_video_mode(monitor)

            self.width, self.height = mode.size.width, mode.size.height
            print("picked fullscreen mode:", mode)

        print("Window size:", self.width, self.height)
        self.window = glfw.create_window(self.width, self.height, self.title, monitor, None)

        if not self.window:
            glfw.terminate()
            raise ValueError("Failed to create window")

        if not self.cursor:
            glfw.set_input_mode(self.window, glfw.CURSOR, glfw.CURSOR_DISABLED)

        # Get the actual buffer size of the window
        # This is important for some displays like Apple's Retina as reported window sizes are virtual
        self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window)
        print("Frame buffer size:", self.buffer_width, self.buffer_height)
        print("Actual window size:", glfw.get_window_size(self.window))

        glfw.make_context_current(self.window)

        # The number of screen updates to wait from the time glfwSwapBuffers
        # was called before swapping the buffers and returning
        if self.vsync:
            glfw.swap_interval(1)

        glfw.set_key_callback(self.window, self.key_event_callback)
        glfw.set_cursor_pos_callback(self.window, self.mouse_event_callback)
        glfw.set_window_size_callback(self.window, self.window_resize_callback)

        # Create mederngl context from existing context
        self.ctx = moderngl.create_context()
        context.WINDOW = self
        self.fbo = FBO()
        self.fbo.ctx = self.ctx
        self.fbo.fbo = self.ctx.screen
        self.fbo.default_framebuffer = True
        self.set_default_viewport()

    def use(self):
        self.ctx.screen.use()

    def should_close(self):
        return glfw.window_should_close(self.window)

    def close(self):
        glfw.set_window_should_close(self.window, True)

    def swap_buffers(self):
        self.frames += 1
        glfw.swap_buffers(self.window)
        self.poll_events()

    def resize(self, width, height):
        self.width = width
        self.height = height
        self.buffer_width, self.buffer_height = glfw.get_framebuffer_size(self.window)
        print("Resize:", self.width, self.height, self.buffer_width, self.buffer_height)
        super().resize(width, height)

    def terminate(self):
        glfw.terminate()

    def poll_events(self):
        """Poll events from glfw"""
        glfw.poll_events()

    def check_glfw_version(self):
        """Ensure glfw version is compatible"""
        print("glfw version: {} (python wrapper version {})".format(glfw.get_version(), glfw.__version__))
        if glfw.get_version() < self.min_glfw_version:
            raise ValueError("Please update glfw binaries to version {} or later".format(self.min_glfw_version))

    def key_event_callback(self, window, key, scancode, action, mods):
        """
        Key event callback for glfw

        :param window: Window event origin
        :param key: The keyboard key that was pressed or released.
        :param scancode: The system-specific scancode of the key.
        :param action: GLFW_PRESS, GLFW_RELEASE or GLFW_REPEAT
        :param mods: Bit field describing which modifier keys were held down.
        """
        # print("Key event:", key, scancode, action, mods)

        # The well-known standard key for quick exit
        if key == glfw.KEY_ESCAPE:
            self.close()
            return

        # Toggle pause time
        if key == glfw.KEY_SPACE and action == glfw.PRESS:
            self.timer.toggle_pause()

        # Camera movement
        # Right
        if key == glfw.KEY_D:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.RIGHT, True)
            elif action == glfw.RELEASE:
                self.sys_camera.move_state(camera.RIGHT, False)
        # Left
        elif key == glfw.KEY_A:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.LEFT, True)
            elif action == glfw.RELEASE:
                self.sys_camera.move_state(camera.LEFT, False)
        # Forward
        elif key == glfw.KEY_W:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.FORWARD, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.FORWARD, False)
        # Backwards
        elif key == glfw.KEY_S:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.BACKWARD, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.BACKWARD, False)

        # UP
        elif key == glfw.KEY_Q:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.UP, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.UP, False)

        # Down
        elif key == glfw.KEY_E:
            if action == glfw.PRESS:
                self.sys_camera.move_state(camera.DOWN, True)
            if action == glfw.RELEASE:
                self.sys_camera.move_state(camera.DOWN, False)

        # Screenshots
        if key == glfw.KEY_X and action == glfw.PRESS:
            screenshot.create()

        if key == glfw.KEY_R and action == glfw.PRESS:
            self.resources.shaders.reload()

        # Forward the event to the effect manager
        self.manager.key_event(key, scancode, action, mods)

    def mouse_event_callback(self, window, xpos, ypos):
        """
        Mouse event callback from glfw

        :param window: The window
        :param xpos: viewport x pos
        :param ypos: viewport y pos
        """
        self.sys_camera.rot_state(xpos, ypos)

    def window_resize_callback(self, window, width, height):
        """
        Window resize callback for glfw

        :param window: The window
        :param width: New width
        :param height: New height
        """
        print("Resize", width, height)
        self.resize(width, height)
<|endoftext|>


<commit_before># Copyright (c) 2015, DjaoDjin Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""
Function to load site and credentials config files
"""
import os, re, sys

__version__ = '0.2.8-dev'

def locate_config(confname, app_name, prefix='etc', verbose=False):
    """
    Returns absolute path on the filesystem to a config file named *confname*.
    """
    candidates = []
    app_config_dir = ('%s_CONFIG_DIR' % app_name).upper()
    if app_config_dir in os.environ:
        candidate = os.path.join(os.environ[app_config_dir], confname)
        if os.path.isfile(candidate):
            candidates += [candidate]
    candidate = os.path.join(
        os.path.dirname(os.path.dirname(sys.executable)),
        prefix, app_name, confname)
    if os.path.isfile(candidate):
        candidates += [candidate]
    candidate = '/%s/%s/%s' % (prefix, app_name, confname)
    if os.path.isfile(candidate):
        candidates += [candidate]
    if len(candidates) > 0:
        if verbose:
            sys.stderr.write('config loaded from %s\n' % candidates[0])
        return candidates[0]
    else:
        sys.stderr.write(
            'warning: config %s was not found.\n' % confname)
    return None

# Read environment variable first
#pylint: disable=too-many-arguments,too-many-locals,too-many-statements
def load_config(confname, module, app_name,
                prefix='etc', verbose=False, s3_bucket=None, passphrase=None):
    """
    Given a path to a file, parse its lines in ini-like format, and then
    set them in the current namespace.

    Quiet by default. Set verbose to True to see the absolute path to the config
    files printed on stderr.
    """
    from deployutils import crypt # prevent pip install to break.
    content = None
    if s3_bucket:
        try:
            import boto
            bucket_name = s3_bucket
            try:
                conn = boto.connect_s3()
                bucket = conn.get_bucket(bucket_name)
                key = bucket.get_key('%s/%s' % (app_name, confname))
                content = key.get_contents_as_string()
                if verbose:
                    sys.stderr.write(
                        "config loaded from 's3://%s/%s'\n" % (
                        bucket_name, key.name))
            except (boto.exception.NoAuthHandlerFound,
                    boto.exception.S3ResponseError) as _:
                pass
        except ImportError:
            pass

    # We cannot find a deployutils S3 bucket. Let's look on the filesystem.
    if not content:
        confpath = locate_config(
            confname, app_name, prefix=prefix, verbose=verbose)
        if confpath:
            with open(confpath, 'rb') as conffile:
                content = conffile.read()

    if content:
        if passphrase:
            lines = crypt.decrypt(content, passphrase).split('\n')
        else:
            lines = content.split('\n')

        # We used to parse the file line by line. Once Django 1.5
        # introduced ALLOWED_HOSTS (a tuple that definitely belongs
        # to the site.conf set), we had no choice other than resort
        # to eval(value, {}, {}).
        # We are not resorting to import conf module yet but that
        # might be necessary once we use dictionary configs for some
        # of the apps...
        # todo: consider using something like ConfigObj for this:
        # http://www.voidspace.org.uk/python/configobj.html
        for line in lines:
            if not line.startswith('#'):
                look = re.match(r'(\w+)\s*=\s*(.*)', line)
                if look:
                    if 'LOCALSTATEDIR' in look.group(2):
                        value = look.group(2) \
                            % {'LOCALSTATEDIR': module.BASE_DIR + '/var'}
                    else:
                        value = look.group(2)
                    try:
                        #pylint:disable=eval-used
                        setattr(module,
                                look.group(1).upper(), eval(value, {}, {}))
                    except StandardError:
                        raise
        if hasattr(module, 'LOG_FILE'):
            for pathname in [module.LOG_FILE]:
                try:
                    if not os.path.exists(pathname):
                        if not os.path.exists(os.path.dirname(pathname)):
                            os.makedirs(os.path.dirname(pathname))
                        with open(pathname, 'w') as _:
                            pass    # touch file
                    sys.stderr.write('logging app messages in %s\n' % pathname)
                except OSError:
                    sys.stderr.write(
                        'warning: permission denied on %s\n' % pathname)

<commit_msg>release 0.2.8 to pypi<commit_after># Copyright (c) 2015, DjaoDjin Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
#    this list of conditions and the following disclaimer in the documentation
#    and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""
Function to load site and credentials config files
"""
import os, re, sys

__version__ = '0.2.8'

def locate_config(confname, app_name, prefix='etc', verbose=False):
    """
    Returns absolute path on the filesystem to a config file named *confname*.
    """
    candidates = []
    app_config_dir = ('%s_CONFIG_DIR' % app_name).upper()
    if app_config_dir in os.environ:
        candidate = os.path.join(os.environ[app_config_dir], confname)
        if os.path.isfile(candidate):
            candidates += [candidate]
    candidate = os.path.join(
        os.path.dirname(os.path.dirname(sys.executable)),
        prefix, app_name, confname)
    if os.path.isfile(candidate):
        candidates += [candidate]
    candidate = '/%s/%s/%s' % (prefix, app_name, confname)
    if os.path.isfile(candidate):
        candidates += [candidate]
    if len(candidates) > 0:
        if verbose:
            sys.stderr.write('config loaded from %s\n' % candidates[0])
        return candidates[0]
    else:
        sys.stderr.write(
            'warning: config %s was not found.\n' % confname)
    return None

# Read environment variable first
#pylint: disable=too-many-arguments,too-many-locals,too-many-statements
def load_config(confname, module, app_name,
                prefix='etc', verbose=False, s3_bucket=None, passphrase=None):
    """
    Given a path to a file, parse its lines in ini-like format, and then
    set them in the current namespace.

    Quiet by default. Set verbose to True to see the absolute path to the config
    files printed on stderr.
    """
    from deployutils import crypt # prevent pip install to break.
    content = None
    if s3_bucket:
        try:
            import boto
            bucket_name = s3_bucket
            try:
                conn = boto.connect_s3()
                bucket = conn.get_bucket(bucket_name)
                key = bucket.get_key('%s/%s' % (app_name, confname))
                content = key.get_contents_as_string()
                if verbose:
                    sys.stderr.write(
                        "config loaded from 's3://%s/%s'\n" % (
                        bucket_name, key.name))
            except (boto.exception.NoAuthHandlerFound,
                    boto.exception.S3ResponseError) as _:
                pass
        except ImportError:
            pass

    # We cannot find a deployutils S3 bucket. Let's look on the filesystem.
    if not content:
        confpath = locate_config(
            confname, app_name, prefix=prefix, verbose=verbose)
        if confpath:
            with open(confpath, 'rb') as conffile:
                content = conffile.read()

    if content:
        if passphrase:
            lines = crypt.decrypt(content, passphrase).split('\n')
        else:
            lines = content.split('\n')

        # We used to parse the file line by line. Once Django 1.5
        # introduced ALLOWED_HOSTS (a tuple that definitely belongs
        # to the site.conf set), we had no choice other than resort
        # to eval(value, {}, {}).
        # We are not resorting to import conf module yet but that
        # might be necessary once we use dictionary configs for some
        # of the apps...
        # todo: consider using something like ConfigObj for this:
        # http://www.voidspace.org.uk/python/configobj.html
        for line in lines:
            if not line.startswith('#'):
                look = re.match(r'(\w+)\s*=\s*(.*)', line)
                if look:
                    if 'LOCALSTATEDIR' in look.group(2):
                        value = look.group(2) \
                            % {'LOCALSTATEDIR': module.BASE_DIR + '/var'}
                    else:
                        value = look.group(2)
                    try:
                        #pylint:disable=eval-used
                        setattr(module,
                                look.group(1).upper(), eval(value, {}, {}))
                    except StandardError:
                        raise
        if hasattr(module, 'LOG_FILE'):
            for pathname in [module.LOG_FILE]:
                try:
                    if not os.path.exists(pathname):
                        if not os.path.exists(os.path.dirname(pathname)):
                            os.makedirs(os.path.dirname(pathname))
                        with open(pathname, 'w') as _:
                            pass    # touch file
                    sys.stderr.write('logging app messages in %s\n' % pathname)
                except OSError:
                    sys.stderr.write(
                        'warning: permission denied on %s\n' % pathname)

<|endoftext|>