<commit_before># -*- coding: utf-8 -*-
"""lonetwin's pimped-up pythonrc

A custom pythonrc which provides colored prompts, intelligent tab completion
pretty-printing, shortcut to open your $EDITOR with the last executed command
and it also retains history.

Ideas borrowed from:
    * http://eseth.org/2008/pimping-pythonrc.html
        (which co-incidentally reused something I wrote back in 2005 !! Ain't
        sharing great ?)
    * http://igotgenes.blogspot.in/2009/01/tab-completion-and-history-in-python.html

This file is executed when the Python interactive shell is started if
$PYTHONSTARTUP is in your environment and points to this file.

If you have any other good ideas please feel free to leave a comment.
"""
import sys
import os
import signal
import readline, rlcompleter
import atexit
import pprint
import subprocess
from tempfile import mkstemp
from code import InteractiveConsole

# Intelligent Tab completion support borrowed from
# http://igotgenes.blogspot.in/2009/01/tab-completion-and-history-in-python.html
class IrlCompleter(rlcompleter.Completer):
    """
    This class enables a "tab" insertion if there's no text for
    completion.

    The default "tab" is four spaces. You can initialize with '\t' as
    the tab if you wish to use a genuine tab.
    """

    def __init__(self, tab='    ', namespace = None):
        self.tab = tab
        rlcompleter.Completer.__init__(self, namespace)

    def complete(self, text, state):
        if text == '':
            return None if state > 0 else self.tab
        else:
            return rlcompleter.Completer.complete(self, text, state)

# Enable History
HISTFILE="%s/.pyhistory" % os.environ["HOME"]

# Read the existing history if there is one
if os.path.exists(HISTFILE):
    readline.read_history_file(HISTFILE)

# Set maximum number of items that will be written to the history file
readline.set_history_length(300)

atexit.register(lambda :readline.write_history_file(HISTFILE))

# Enable Color Prompts
# - borrowed from fabric (also used in botosh)
def _color_fn(code):
    def inner(text, bold=False, readline_workaround=False):
        # - reason for readline_workaround: http://bugs.python.org/issue20359
        if readline_workaround:
            return "\001\033[%sm\002%s\001\033[0m\002" % ('1;%d' % code if bold else str(code), text)
        else:
            return "\033[%sm%s\033[0m" % ('1;%d' % code if bold else str(code), text)
    return inner

# add any colors you might need.
_red   = _color_fn(31)
_green = _color_fn(32)
_cyan  = _color_fn(36)

# - if we are a remote connection, modify the ps1
if os.environ.get('SSH_CONNECTION'):
    this_host = os.environ['SSH_CONNECTION'].split()[-2]
    sys.ps1 = _green('[%s]>>> ' % this_host, readline_workaround=True)
    sys.ps2 = _red('[%s]... '   % this_host, readline_workaround=True)
else:
    sys.ps1 = _green('>>> ', readline_workaround=True)
    sys.ps2 = _red('... ', readline_workaround=True)

# Enable Pretty Printing for stdout
# - get terminal size for passing width param to pprint. Queried just once at
# startup
try:
    _rows, _cols = subprocess.check_output('stty size', shell=True).strip().split()
except:
    _cols = 80

def my_displayhook(value):
    if value is not None:
        try:
            import __builtin__
            __builtin__._ = value
        except ImportError:
            __builtins__._ = value

        import re
        formatted = pprint.pformat(value, width=_cols)
        if issubclass(type(value), dict):
            for k in value.keys():
                formatted = re.sub(
                        r'["\'\\]+(%s)["\'\\]+: ' % k,
                        lambda m: "'%s': " % _red(m.group(1), bold=True),
                        formatted)
        print(formatted)

sys.displayhook = my_displayhook

# Start an external editor with \e
EDITOR = os.environ.get('EDITOR', 'vi')
EDIT_CMD = '\e'
SH_EXEC  = '!'

class EditableBufferInteractiveConsole(InteractiveConsole, object):
    def __init__(self, *args, **kwargs):
        self.last_buffer = [] # This holds the last executed statements
        self.buffer = []      # This holds the statement to be executed
        super(EditableBufferInteractiveConsole, self).__init__(*args, **kwargs)

    def resetbuffer(self):
        self.last_buffer.extend(self.buffer)
        return super(EditableBufferInteractiveConsole, self).resetbuffer()

    def raw_input(self, *args):
        line = super(EditableBufferInteractiveConsole, self).raw_input(*args)
        if line == EDIT_CMD:
            fd, tmpfl = mkstemp('.py')
            for line in self.last_buffer:
                os.write(fd, '%s\n' % (line if line.startswith('#') else '# %s' % line))
            os.close(fd)
            os.system('%s %s' % (EDITOR, tmpfl))
            line = open(tmpfl).read()
            os.unlink(tmpfl)
            tmpfl = ''
            lines = line.split('\n')
            self.write(_cyan(">>> %s\n" % '\n... '.join(line for line in lines if not line.startswith('#'))))
            for stmt in lines[:-1]:
                if not stmt.startswith('#'):
                    self.push(stmt)
            line = lines[-1]

        if line.startswith(SH_EXEC):
            import __builtin__
            cmd = line.strip(SH_EXEC)
            if cmd:
                out, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                        shell=True).communicate()
                print (err and _red(err)) or (out and _green(out))
                __builtin__._ = (out, err)
            else:
                os.kill(os.getpid(), signal.SIGSTOP)
            line = ''
        return line

    def write(self, data):
        sys.stderr.write(_red(data, bold=True))

# Welcome message
WELCOME = _cyan("""\
You've got color, tab completion, pretty-printing, an editable input buffer
(via the '\e' command) and shell command execution (via the '!' command).

History will be saved in %s when you exit.

The '\e' command will open %s with the history for the current
session. On closing the editor any lines not starting with '#' will be executed
(only one statement can be executed at a time)

The '!' command without anything following it will suspend this process, use fg
to get back.

If the '!' command is followed by any text, the text will be executed in %s
and the output/error will be displayed. Additionally '_' will contain the tuple
(<stdout>, <stderror>) for the execution of the command.
""" % (HISTFILE, EDITOR, os.environ.get('SHELL', '$SHELL')))

# - create our pimped out console
__c = EditableBufferInteractiveConsole()

# - turn on the completer
# you could change this line to bind another key instead of tab.
readline.parse_and_bind('tab: complete')
readline.set_completer(IrlCompleter(tab='\t', namespace=__c.locals).complete)

# - fire it up !
__c.interact(banner=WELCOME)

# Exit the Python shell on exiting the InteractiveConsole
sys.exit()
<commit_msg>Added pathname tab-completion<commit_after># -*- coding: utf-8 -*-
"""lonetwin's pimped-up pythonrc

A custom pythonrc which provides colored prompts, intelligent tab completion
pretty-printing, shortcut to open your $EDITOR with the last executed command
and it also retains history.

Ideas borrowed from:
    * http://eseth.org/2008/pimping-pythonrc.html
        (which co-incidentally reused something I wrote back in 2005 !! Ain't
        sharing great ?)
    * http://igotgenes.blogspot.in/2009/01/tab-completion-and-history-in-python.html

This file is executed when the Python interactive shell is started if
$PYTHONSTARTUP is in your environment and points to this file.

If you have any other good ideas please feel free to leave a comment.
"""
import sys
import os
import signal
import readline, rlcompleter
import atexit
import pprint
import glob
import subprocess
from tempfile import mkstemp
from code import InteractiveConsole

# Intelligent Tab completion support borrowed from
# http://igotgenes.blogspot.in/2009/01/tab-completion-and-history-in-python.html
class IrlCompleter(rlcompleter.Completer):
    """
    This class enables a "tab" insertion if there's no text for
    completion.

    The default "tab" is four spaces. You can initialize with '\t' as
    the tab if you wish to use a genuine tab.
    """

    def __init__(self, tab='    ', namespace = None):
        self.tab = tab
        # - remove / from the delimiters to enable path completion
        readline.set_completer_delims(
                readline.get_completer_delims().replace('/', ''))
        rlcompleter.Completer.__init__(self, namespace)

    def complete(self, text, state):
        if text == '':
            return None if state > 0 else self.tab
        else:
            matches = rlcompleter.Completer.complete(self, text, state)
            if matches is None:
                if '/' in text:
                    try:
                        matches = glob.glob(text+'*')[state]
                    except IndexError:
                        return None
        return matches

# Enable History
HISTFILE="%s/.pyhistory" % os.environ["HOME"]

# Read the existing history if there is one
if os.path.exists(HISTFILE):
    readline.read_history_file(HISTFILE)

# Set maximum number of items that will be written to the history file
readline.set_history_length(300)

atexit.register(lambda :readline.write_history_file(HISTFILE))

# Enable Color Prompts
# - borrowed from fabric (also used in botosh)
def _color_fn(code):
    def inner(text, bold=False, readline_workaround=False):
        # - reason for readline_workaround: http://bugs.python.org/issue20359
        if readline_workaround:
            return "\001\033[%sm\002%s\001\033[0m\002" % ('1;%d' % code if bold else str(code), text)
        else:
            return "\033[%sm%s\033[0m" % ('1;%d' % code if bold else str(code), text)
    return inner

# add any colors you might need.
_red   = _color_fn(31)
_green = _color_fn(32)
_cyan  = _color_fn(36)

# - if we are a remote connection, modify the ps1
if os.environ.get('SSH_CONNECTION'):
    this_host = os.environ['SSH_CONNECTION'].split()[-2]
    sys.ps1 = _green('[%s]>>> ' % this_host, readline_workaround=True)
    sys.ps2 = _red('[%s]... '   % this_host, readline_workaround=True)
else:
    sys.ps1 = _green('>>> ', readline_workaround=True)
    sys.ps2 = _red('... ', readline_workaround=True)

# Enable Pretty Printing for stdout
# - get terminal size for passing width param to pprint. Queried just once at
# startup
try:
    _rows, _cols = subprocess.check_output('stty size', shell=True).strip().split()
except:
    _cols = 80

def my_displayhook(value):
    if value is not None:
        try:
            import __builtin__
            __builtin__._ = value
        except ImportError:
            __builtins__._ = value

        import re
        formatted = pprint.pformat(value, width=_cols)
        if issubclass(type(value), dict):
            for k in value.keys():
                formatted = re.sub(
                        r'["\'\\]+(%s)["\'\\]+: ' % k,
                        lambda m: "'%s': " % _red(m.group(1), bold=True),
                        formatted)
        print(formatted)

sys.displayhook = my_displayhook

# Start an external editor with \e
EDITOR = os.environ.get('EDITOR', 'vi')
EDIT_CMD = '\e'
SH_EXEC  = '!'

class EditableBufferInteractiveConsole(InteractiveConsole, object):
    def __init__(self, *args, **kwargs):
        self.last_buffer = [] # This holds the last executed statements
        self.buffer = []      # This holds the statement to be executed
        super(EditableBufferInteractiveConsole, self).__init__(*args, **kwargs)

    def resetbuffer(self):
        self.last_buffer.extend(self.buffer)
        return super(EditableBufferInteractiveConsole, self).resetbuffer()

    def raw_input(self, *args):
        line = super(EditableBufferInteractiveConsole, self).raw_input(*args)
        if line == EDIT_CMD:
            fd, tmpfl = mkstemp('.py')
            for line in self.last_buffer:
                os.write(fd, '%s\n' % (line if line.startswith('#') else '# %s' % line))
            os.close(fd)
            os.system('%s %s' % (EDITOR, tmpfl))
            line = open(tmpfl).read()
            os.unlink(tmpfl)
            tmpfl = ''
            lines = line.split('\n')
            self.write(_cyan(">>> %s\n" % '\n... '.join(line for line in lines if not line.startswith('#'))))
            for stmt in lines[:-1]:
                if not stmt.startswith('#'):
                    self.push(stmt)
            line = lines[-1]

        if line.startswith(SH_EXEC):
            import __builtin__
            cmd = line.strip(SH_EXEC)
            if cmd:
                out, err = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                                        shell=True).communicate()
                print (err and _red(err)) or (out and _green(out))
                __builtin__._ = (out, err)
            else:
                os.kill(os.getpid(), signal.SIGSTOP)
            line = ''
        return line

    def write(self, data):
        sys.stderr.write(_red(data, bold=True))

# Welcome message
WELCOME = _cyan("""\
You've got color, tab completion, pretty-printing, an editable input buffer
(via the '\e' command) and shell command execution (via the '!' command).

History will be saved in %s when you exit.

The '\e' command will open %s with the history for the current
session. On closing the editor any lines not starting with '#' will be executed
(only one statement can be executed at a time)

The '!' command without anything following it will suspend this process, use fg
to get back.

If the '!' command is followed by any text, the text will be executed in %s
and the output/error will be displayed. Additionally '_' will contain the tuple
(<stdout>, <stderror>) for the execution of the command.
""" % (HISTFILE, EDITOR, os.environ.get('SHELL', '$SHELL')))

# - create our pimped out console
__c = EditableBufferInteractiveConsole()

# - turn on the completer
# you could change this line to bind another key instead of tab.
readline.parse_and_bind('tab: complete')
readline.set_completer(IrlCompleter(tab='\t', namespace=__c.locals).complete)

# - fire it up !
__c.interact(banner=WELCOME)

# Exit the Python shell on exiting the InteractiveConsole
sys.exit()
<|endoftext|>


<commit_before># Constants.
#
# Copyright (C) 2016 g10 Code GmbH
#
# This file is part of GPGME.
#
# GPGME is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# GPGME is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
# Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, see <https://www.gnu.org/licenses/>.

from __future__ import absolute_import, print_function, unicode_literals

from gpg import util
# Globals may need to be set prior to module import, if so this prevents PEP8
# compliance, but better that than code breakage.
util.process_constants('GPGME_', globals())

# For convenience, we import the modules here.
from . import data, keylist, sig, tofu  # The subdirs.
# The remaining modules can no longer fit on one line.
from . import create, event, import_type, keysign, md, pk, protocol, sigsum
from . import status, validity

del absolute_import, print_function, unicode_literals, util

# This was a bad idea (though I get why it was done):
#
# # A complication arises because 'import' is a reserved keyword.
# # Import it as 'Import' instead.
# globals()['Import'] = getattr(
#     __import__('', globals(), locals(), [str('import')], 1), "import")

__all__ = [
    'data', 'event', 'import_type', 'keysign', 'keylist', 'md', 'pk',
    'protocol', 'sig', 'sigsum', 'status', 'tofu', 'validity', 'create'
]

# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact.  We
# implement gpg.Context.op_edit using gpgme_op_interact, so the
# callbacks will be called with string keywords instead of numeric
# status messages.  Code that is using these constants will continue
# to work.

STATUS_ABORT = "ABORT"
STATUS_ALREADY_SIGNED = "ALREADY_SIGNED"
STATUS_ATTRIBUTE = "ATTRIBUTE"
STATUS_BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED"
STATUS_BAD_PASSPHRASE = "BAD_PASSPHRASE"
STATUS_BADARMOR = "BADARMOR"
STATUS_BADMDC = "BADMDC"
STATUS_BADSIG = "BADSIG"
STATUS_BEGIN_DECRYPTION = "BEGIN_DECRYPTION"
STATUS_BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION"
STATUS_BEGIN_SIGNING = "BEGIN_SIGNING"
STATUS_BEGIN_STREAM = "BEGIN_STREAM"
STATUS_CARDCTRL = "CARDCTRL"
STATUS_DECRYPTION_FAILED = "DECRYPTION_FAILED"
STATUS_DECRYPTION_INFO = "DECRYPTION_INFO"
STATUS_DECRYPTION_OKAY = "DECRYPTION_OKAY"
STATUS_DELETE_PROBLEM = "DELETE_PROBLEM"
STATUS_ENC_TO = "ENC_TO"
STATUS_END_DECRYPTION = "END_DECRYPTION"
STATUS_END_ENCRYPTION = "END_ENCRYPTION"
STATUS_END_STREAM = "END_STREAM"
STATUS_ENTER = "ENTER"
STATUS_ERRMDC = "ERRMDC"
STATUS_ERROR = "ERROR"
STATUS_ERRSIG = "ERRSIG"
STATUS_EXPKEYSIG = "EXPKEYSIG"
STATUS_EXPSIG = "EXPSIG"
STATUS_FAILURE = "FAILURE"
STATUS_FILE_DONE = "FILE_DONE"
STATUS_FILE_ERROR = "FILE_ERROR"
STATUS_FILE_START = "FILE_START"
STATUS_GET_BOOL = "GET_BOOL"
STATUS_GET_HIDDEN = "GET_HIDDEN"
STATUS_GET_LINE = "GET_LINE"
STATUS_GOOD_PASSPHRASE = "GOOD_PASSPHRASE"
STATUS_GOODMDC = "GOODMDC"
STATUS_GOODSIG = "GOODSIG"
STATUS_GOT_IT = "GOT_IT"
STATUS_IMPORT_OK = "IMPORT_OK"
STATUS_IMPORT_PROBLEM = "IMPORT_PROBLEM"
STATUS_IMPORT_RES = "IMPORT_RES"
STATUS_IMPORTED = "IMPORTED"
STATUS_INQUIRE_MAXLEN = "INQUIRE_MAXLEN"
STATUS_INV_RECP = "INV_RECP"
STATUS_INV_SGNR = "INV_SGNR"
STATUS_KEY_CONSIDERED = "KEY_CONSIDERED"
STATUS_KEY_CREATED = "KEY_CREATED"
STATUS_KEY_NOT_CREATED = "KEY_NOT_CREATED"
STATUS_KEYEXPIRED = "KEYEXPIRED"
STATUS_KEYREVOKED = "KEYREVOKED"
STATUS_LEAVE = "LEAVE"
STATUS_MISSING_PASSPHRASE = "MISSING_PASSPHRASE"
STATUS_MOUNTPOINT = "MOUNTPOINT"
STATUS_NEED_PASSPHRASE = "NEED_PASSPHRASE"
STATUS_NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN"
STATUS_NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM"
STATUS_NEWSIG = "NEWSIG"
STATUS_NO_PUBKEY = "NO_PUBKEY"
STATUS_NO_RECP = "NO_RECP"
STATUS_NO_SECKEY = "NO_SECKEY"
STATUS_NO_SGNR = "NO_SGNR"
STATUS_NODATA = "NODATA"
STATUS_NOTATION_DATA = "NOTATION_DATA"
STATUS_NOTATION_FLAGS = "NOTATION_FLAGS"
STATUS_NOTATION_NAME = "NOTATION_NAME"
STATUS_PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED"
STATUS_PKA_TRUST_BAD = "PKA_TRUST_BAD"
STATUS_PKA_TRUST_GOOD = "PKA_TRUST_GOOD"
STATUS_PLAINTEXT = "PLAINTEXT"
STATUS_PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH"
STATUS_POLICY_URL = "POLICY_URL"
STATUS_PROGRESS = "PROGRESS"
STATUS_REVKEYSIG = "REVKEYSIG"
STATUS_RSA_OR_IDEA = "RSA_OR_IDEA"
STATUS_SC_OP_FAILURE = "SC_OP_FAILURE"
STATUS_SC_OP_SUCCESS = "SC_OP_SUCCESS"
STATUS_SESSION_KEY = "SESSION_KEY"
STATUS_SHM_GET = "SHM_GET"
STATUS_SHM_GET_BOOL = "SHM_GET_BOOL"
STATUS_SHM_GET_HIDDEN = "SHM_GET_HIDDEN"
STATUS_SHM_INFO = "SHM_INFO"
STATUS_SIG_CREATED = "SIG_CREATED"
STATUS_SIG_ID = "SIG_ID"
STATUS_SIG_SUBPACKET = "SIG_SUBPACKET"
STATUS_SIGEXPIRED = "SIGEXPIRED"
STATUS_SUCCESS = "SUCCESS"
STATUS_TOFU_STATS = "TOFU_STATS"
STATUS_TOFU_STATS_LONG = "TOFU_STATS_LONG"
STATUS_TOFU_USER = "TOFU_USER"
STATUS_TRUNCATED = "TRUNCATED"
STATUS_TRUST_FULLY = "TRUST_FULLY"
STATUS_TRUST_MARGINAL = "TRUST_MARGINAL"
STATUS_TRUST_NEVER = "TRUST_NEVER"
STATUS_TRUST_ULTIMATE = "TRUST_ULTIMATE"
STATUS_TRUST_UNDEFINED = "TRUST_UNDEFINED"
STATUS_UNEXPECTED = "UNEXPECTED"
STATUS_USERID_HINT = "USERID_HINT"
STATUS_VALIDSIG = "VALIDSIG"
<commit_msg>python: import type<commit_after># Constants.
#
# Copyright (C) 2016 g10 Code GmbH
#
# This file is part of GPGME.
#
# GPGME is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2.1 of the
# License, or (at your option) any later version.
#
# GPGME is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
# Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, see <https://www.gnu.org/licenses/>.

from __future__ import absolute_import, print_function, unicode_literals

from gpg import util
# Globals may need to be set prior to module import, if so this prevents PEP8
# compliance, but better that than code breakage.
util.process_constants('GPGME_', globals())

# For convenience, we import the modules here.
from . import data, keylist, sig, tofu  # The subdirs.
# The remaining modules can no longer fit on one line.
from . import create, event, import_type, keysign, md, pk, protocol, sigsum
from . import status, validity

del absolute_import, print_function, unicode_literals, util

__all__ = [
    'data', 'event', 'import_type', 'keysign', 'keylist', 'md', 'pk',
    'protocol', 'sig', 'sigsum', 'status', 'tofu', 'validity', 'create'
]

# GPGME 1.7 replaced gpgme_op_edit with gpgme_op_interact.  We
# implement gpg.Context.op_edit using gpgme_op_interact, so the
# callbacks will be called with string keywords instead of numeric
# status messages.  Code that is using these constants will continue
# to work.

STATUS_ABORT = "ABORT"
STATUS_ALREADY_SIGNED = "ALREADY_SIGNED"
STATUS_ATTRIBUTE = "ATTRIBUTE"
STATUS_BACKUP_KEY_CREATED = "BACKUP_KEY_CREATED"
STATUS_BAD_PASSPHRASE = "BAD_PASSPHRASE"
STATUS_BADARMOR = "BADARMOR"
STATUS_BADMDC = "BADMDC"
STATUS_BADSIG = "BADSIG"
STATUS_BEGIN_DECRYPTION = "BEGIN_DECRYPTION"
STATUS_BEGIN_ENCRYPTION = "BEGIN_ENCRYPTION"
STATUS_BEGIN_SIGNING = "BEGIN_SIGNING"
STATUS_BEGIN_STREAM = "BEGIN_STREAM"
STATUS_CARDCTRL = "CARDCTRL"
STATUS_DECRYPTION_FAILED = "DECRYPTION_FAILED"
STATUS_DECRYPTION_INFO = "DECRYPTION_INFO"
STATUS_DECRYPTION_OKAY = "DECRYPTION_OKAY"
STATUS_DELETE_PROBLEM = "DELETE_PROBLEM"
STATUS_ENC_TO = "ENC_TO"
STATUS_END_DECRYPTION = "END_DECRYPTION"
STATUS_END_ENCRYPTION = "END_ENCRYPTION"
STATUS_END_STREAM = "END_STREAM"
STATUS_ENTER = "ENTER"
STATUS_ERRMDC = "ERRMDC"
STATUS_ERROR = "ERROR"
STATUS_ERRSIG = "ERRSIG"
STATUS_EXPKEYSIG = "EXPKEYSIG"
STATUS_EXPSIG = "EXPSIG"
STATUS_FAILURE = "FAILURE"
STATUS_FILE_DONE = "FILE_DONE"
STATUS_FILE_ERROR = "FILE_ERROR"
STATUS_FILE_START = "FILE_START"
STATUS_GET_BOOL = "GET_BOOL"
STATUS_GET_HIDDEN = "GET_HIDDEN"
STATUS_GET_LINE = "GET_LINE"
STATUS_GOOD_PASSPHRASE = "GOOD_PASSPHRASE"
STATUS_GOODMDC = "GOODMDC"
STATUS_GOODSIG = "GOODSIG"
STATUS_GOT_IT = "GOT_IT"
STATUS_IMPORT_OK = "IMPORT_OK"
STATUS_IMPORT_PROBLEM = "IMPORT_PROBLEM"
STATUS_IMPORT_RES = "IMPORT_RES"
STATUS_IMPORTED = "IMPORTED"
STATUS_INQUIRE_MAXLEN = "INQUIRE_MAXLEN"
STATUS_INV_RECP = "INV_RECP"
STATUS_INV_SGNR = "INV_SGNR"
STATUS_KEY_CONSIDERED = "KEY_CONSIDERED"
STATUS_KEY_CREATED = "KEY_CREATED"
STATUS_KEY_NOT_CREATED = "KEY_NOT_CREATED"
STATUS_KEYEXPIRED = "KEYEXPIRED"
STATUS_KEYREVOKED = "KEYREVOKED"
STATUS_LEAVE = "LEAVE"
STATUS_MISSING_PASSPHRASE = "MISSING_PASSPHRASE"
STATUS_MOUNTPOINT = "MOUNTPOINT"
STATUS_NEED_PASSPHRASE = "NEED_PASSPHRASE"
STATUS_NEED_PASSPHRASE_PIN = "NEED_PASSPHRASE_PIN"
STATUS_NEED_PASSPHRASE_SYM = "NEED_PASSPHRASE_SYM"
STATUS_NEWSIG = "NEWSIG"
STATUS_NO_PUBKEY = "NO_PUBKEY"
STATUS_NO_RECP = "NO_RECP"
STATUS_NO_SECKEY = "NO_SECKEY"
STATUS_NO_SGNR = "NO_SGNR"
STATUS_NODATA = "NODATA"
STATUS_NOTATION_DATA = "NOTATION_DATA"
STATUS_NOTATION_FLAGS = "NOTATION_FLAGS"
STATUS_NOTATION_NAME = "NOTATION_NAME"
STATUS_PINENTRY_LAUNCHED = "PINENTRY_LAUNCHED"
STATUS_PKA_TRUST_BAD = "PKA_TRUST_BAD"
STATUS_PKA_TRUST_GOOD = "PKA_TRUST_GOOD"
STATUS_PLAINTEXT = "PLAINTEXT"
STATUS_PLAINTEXT_LENGTH = "PLAINTEXT_LENGTH"
STATUS_POLICY_URL = "POLICY_URL"
STATUS_PROGRESS = "PROGRESS"
STATUS_REVKEYSIG = "REVKEYSIG"
STATUS_RSA_OR_IDEA = "RSA_OR_IDEA"
STATUS_SC_OP_FAILURE = "SC_OP_FAILURE"
STATUS_SC_OP_SUCCESS = "SC_OP_SUCCESS"
STATUS_SESSION_KEY = "SESSION_KEY"
STATUS_SHM_GET = "SHM_GET"
STATUS_SHM_GET_BOOL = "SHM_GET_BOOL"
STATUS_SHM_GET_HIDDEN = "SHM_GET_HIDDEN"
STATUS_SHM_INFO = "SHM_INFO"
STATUS_SIG_CREATED = "SIG_CREATED"
STATUS_SIG_ID = "SIG_ID"
STATUS_SIG_SUBPACKET = "SIG_SUBPACKET"
STATUS_SIGEXPIRED = "SIGEXPIRED"
STATUS_SUCCESS = "SUCCESS"
STATUS_TOFU_STATS = "TOFU_STATS"
STATUS_TOFU_STATS_LONG = "TOFU_STATS_LONG"
STATUS_TOFU_USER = "TOFU_USER"
STATUS_TRUNCATED = "TRUNCATED"
STATUS_TRUST_FULLY = "TRUST_FULLY"
STATUS_TRUST_MARGINAL = "TRUST_MARGINAL"
STATUS_TRUST_NEVER = "TRUST_NEVER"
STATUS_TRUST_ULTIMATE = "TRUST_ULTIMATE"
STATUS_TRUST_UNDEFINED = "TRUST_UNDEFINED"
STATUS_UNEXPECTED = "UNEXPECTED"
STATUS_USERID_HINT = "USERID_HINT"
STATUS_VALIDSIG = "VALIDSIG"
<|endoftext|>


<commit_before>#!/usr/bin/env python

"""
    See LICENSE.txt file for copyright and license details.
"""

"""
    A bar plot with income and expense levels.
"""
import numpy as np
import matplotlib.pyplot as plt
from decimal import Decimal
import sys
from subprocess import call
from constant import *

class PlotIncomeVsExpenses():
    """
        Plot income vs expenses.
    """
    def __init__(self):
        """
            Init
        """
        self.x_array = []
        self.y_array = []
        self.profit = []
        self.dat_file = ''

    def prepare_data(pive_type = PlotIncomeVsExpensesType.ALL_DATA_UNTIL_NOW):
        """
            Extract the data we want to plot from ledger.
        """
        #TODO: change $2 etc. to the correct input value from the cli parameters
        #TODO: implement ledger_file var?
        try:
            if pive_type == PlotIncomeVsExpensesType.ALL_DATA_FOR_GIVEN_PERIOD_TOTAL:
                call(['sh', 'ledger -f {} --real -s -d "T&l<=1" -b $2 -e $3 bal -Equity -^assets expenses income > income_vs_expenses.dat'.format(ledger_file)])
            elif pive_type == PlotIncomeVsExpensesType.ALL_DATA_FOR_GIVEN_PERIOD:
                call(['sh', 'ledger -f $1 --real -s -d "T&l<=1" --begin $2 --end $3 bal --period-sort --monthly -Equity -^assets expenses income > income_vs_expenses.dat'])
            elif pive_type == PlotIncomeVsExpensesType.ALL_DATA_FOR_GIVEN_YEAR:
                call(['sh', 'ledger -f $1 --real -s -p $2 -d "T&l<=1" bal --period-sort --yearly -Equity -^assets expenses income > income_vs_expenses.dat'])
            elif pive_type == PlotIncomeVsExpensesType.ALL_DATA_UNTIL_NOW:
                call(['sh', 'ledger -f $1 --real -s -d "T&l<=1" bal -Equity -^assets expenses income > income_vs_expenses.dat'])
        except:
            print 'Error: could not prepare the ledger data.'

    def load_data(self):
        """
            Load data
        """
        var_data = open(self.dat_file, 'r').read()
        var_data_array = var_data.split('\n')
        i = 0
        for line in var_data_array:
            i += 1
            # skip the last 2 lines of the output
            if (len(line)>1) and (i<len(var_data_array) - 2):
                self.x_array.append(abs(float(line.strip().split(' ')[0].strip())))
                self.y_array.append(i)

    def autolabel(self, rects):
        """
          Automatic labels.
        """
        # attach some text labels
        for rect in rects:
            height = rect.get_height()
            ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, '{}'.format(int(height)),
                    ha='center', va='bottom')

    def plot_data(self):
        """
            Plots the loaded data.
        """
        N = 1
        income = self.x_array[0]
        expenses = self.x_array[1]

        ind = np.arange(N)  # the x locations for the groups
        width = 0.15       # the width of the bars
        fig, ax = plt.subplots()
        rects1 = ax.bar(ind, expenses, width, color='r')
        rects2 = ax.bar(ind+width, income, width, color='g')
        rects3 = ax.bar(ind+2*width, (expenses - income), width, color='b')
        # add some labels/text
        ax.set_ylabel('Value (EUR)')
        title_year = ''
        if len(sys.argv) > 2:
            title_year = ' - {}'.format(sys.argv[2].strip()) #TODO: use the year from the input!
        ax.set_title('Income vs. expenses{}'.format(title_year))
        ax.set_xticks(ind+width)
        #ax.set_xticklabels( ('2014') ) #TODO: use the year from the input? But do we need this?
        ax.legend((rects1[0], rects2[0], rects3[0]), ('Expenses', 'Income', 'Profit'))
        autolabel(rects1)
        autolabel(rects2)
        autolabel(rects3)
        plt.show()

if __name__ == "__main__":
    plot = PlotIncomeVsExpenses()
    plot.dat_file = sys.argv[1].strip()
    plot.prepare_data()
    plot.load_data() # load x_array and y_array
    plot.plot_data()
    plot = None
<commit_msg>prepare_data improvements.<commit_after>#!/usr/bin/env python

"""
    See LICENSE.txt file for copyright and license details.
"""

"""
    A bar plot with income and expense levels.
"""
import numpy as np
import matplotlib.pyplot as plt
from decimal import Decimal
import sys
from subprocess import call
from constant import *

class PlotIncomeVsExpenses():
    """
        Plot income vs expenses.
    """
    def __init__(self):
        """
            Init
        """
        self.x_array = []
        self.y_array = []
        self.profit = []
        self.dat_file = ''

    def prepare_data(ledger_file, year, start_date, end_date, pive_type = PlotIncomeVsExpensesType.ALL_DATA_UNTIL_NOW):
        """
            Extract the data we want to plot from ledger.
        """
        #TODO: change $2 etc. to the correct input value from the cli parameters
        #TODO: implement ledger_file var?
        try:
            if pive_type == PlotIncomeVsExpensesType.ALL_DATA_FOR_GIVEN_PERIOD_TOTAL:
                call(['sh', 'ledger -f {} --real -s -d "T&l<=1" --begin {} --end {} bal -Equity -^assets expenses income > income_vs_expenses.dat'.format(ledger_file, start_date, end_date)])
            elif pive_type == PlotIncomeVsExpensesType.ALL_DATA_FOR_GIVEN_PERIOD:
                call(['sh', 'ledger -f {} --real -s -d "T&l<=1" --begin {} --end {} bal --period-sort --monthly -Equity -^assets expenses income > income_vs_expenses.dat'.format(ledger_file, start_date, end_date)])
            elif pive_type == PlotIncomeVsExpensesType.ALL_DATA_FOR_GIVEN_YEAR:
                call(['sh', 'ledger -f {} --real -s -p {} -d "T&l<=1" bal --period-sort --yearly -Equity -^assets expenses income > income_vs_expenses.dat'.format(ledger_file, year)])
            elif pive_type == PlotIncomeVsExpensesType.ALL_DATA_UNTIL_NOW:
                call(['sh', 'ledger -f {} --real -s -d "T&l<=1" bal -Equity -^assets expenses income > income_vs_expenses.dat'.format(ledger_file)])
        except:
            print 'Error: could not prepare the ledger data.'

    def load_data(self):
        """
            Load data
        """
        var_data = open(self.dat_file, 'r').read()
        var_data_array = var_data.split('\n')
        i = 0
        for line in var_data_array:
            i += 1
            # skip the last 2 lines of the output
            if (len(line)>1) and (i<len(var_data_array) - 2):
                self.x_array.append(abs(float(line.strip().split(' ')[0].strip())))
                self.y_array.append(i)

    def autolabel(self, rects):
        """
          Automatic labels.
        """
        # attach some text labels
        for rect in rects:
            height = rect.get_height()
            ax.text(rect.get_x()+rect.get_width()/2., 1.05*height, '{}'.format(int(height)),
                    ha='center', va='bottom')

    def plot_data(self):
        """
            Plots the loaded data.
        """
        N = 1
        income = self.x_array[0]
        expenses = self.x_array[1]

        ind = np.arange(N)  # the x locations for the groups
        width = 0.15       # the width of the bars
        fig, ax = plt.subplots()
        rects1 = ax.bar(ind, expenses, width, color='r')
        rects2 = ax.bar(ind+width, income, width, color='g')
        rects3 = ax.bar(ind+2*width, (expenses - income), width, color='b')
        # add some labels/text
        ax.set_ylabel('Value (EUR)')
        title_year = ''
        if len(sys.argv) > 2:
            title_year = ' - {}'.format(sys.argv[2].strip()) #TODO: use the year from the input!
        ax.set_title('Income vs. expenses{}'.format(title_year))
        ax.set_xticks(ind+width)
        #ax.set_xticklabels( ('2014') ) #TODO: use the year from the input? But do we need this?
        ax.legend((rects1[0], rects2[0], rects3[0]), ('Expenses', 'Income', 'Profit'))
        autolabel(rects1)
        autolabel(rects2)
        autolabel(rects3)
        plt.show()

if __name__ == "__main__":
    plot = PlotIncomeVsExpenses()
    plot.dat_file = sys.argv[1].strip()
    plot.prepare_data()
    plot.load_data() # load x_array and y_array
    plot.plot_data()
    plot = None
<|endoftext|>


<commit_before>"""A library for controlling Homebrew through Python."""

import getpass
import logging
import os
import pwd
import shutil
import subprocess
from itertools import chain

log = logging.getLogger(__name__)

def workflow(settings, fix_repo=False):
    """Run an entire Homebrew update workflow."""
    if not is_installed():
        # todo: install homebrew if not installed
        raise Exception("Homebrew must be installed")

    if fix_repo:
        fix_repository()

    ensure_correct_permissions()
    ensure_command_line_tools_installed()

    update()

    update_taps(settings.get('taps', []))
    update_formulas(settings.get('formulas', []))
    update_casks(settings.get('casks', []))

    run_post_install(settings['post_install'])

def get_installed_formulas():
    log.info("Getting installed formulas")
    return _get_command_output(['brew', 'list'])

def get_installed_casks():
    log.info("Getting installed casks")
    return _get_command_output(['brew', 'cask', 'list'])

def get_installed_taps():
    log.info("Getting installed taps")
    return _get_command_output(['brew', 'tap'])

def install_formula(formula):
    log.info(f"Installing formula: {formula}")
    if isinstance(formula, str):
        formula = [formula]
    _execute(['brew', 'install', *formula])

def install_cask(cask):
    # note: brew cask doesn't support upgrade yet:
    # https://github.com/caskroom/homebrew-cask/issues/4678

    log.info(f"Installing cask: {cask}")
    _execute(['brew', 'cask', 'install', cask])

def install_tap(tap):
    log.info(f"Installing tap: {tap}")
    _execute(['brew', 'tap', tap])

def cleanup_formulas():
    log.info("Running cleanup: formulas")
    _execute(['brew', 'cleanup'])

def cleanup_casks():
    log.info("Running cleanup: casks")
    _execute(['brew', 'cask', 'cleanup'])

def update():
    log.info("Updating Homebrew")
    _execute(['brew', 'update'])

def upgrade():
    log.info("Running upgrade")
    # Homebrew can return an error code in cases that aren't errors:
    # https://github.com/Homebrew/homebrew/issues/27048
    # so, catch any error here and make sure to inspect the output for problems
    try:
        _execute(['brew', 'upgrade'])
    except:
        pass

def install_missing(type, expected):
    assert type in ('formula', 'cask', 'tap')
    get_installed = globals()[f'get_installed_{type}s']
    install = globals()[f'install_{type}']

    log.info(f"Expected {type}s are: {', '.join(sorted(expected))}")
    installed = get_installed()
    log.info(f"Currently installed {type}s are: {', '.join(installed)}")

    missing = sorted(set(expected) - set(installed))
    if missing:
        log.info(f"Missing {type}s are: {', '.join(missing)}")
        for item in missing:
            install(item)
    else:
        log.info(f"No missing {type}s")

def update_formulas(formulas):
    log.info("Updating formulas")
    upgrade()
    install_missing('formula', formulas)
    cleanup_formulas()

    # possible todo: remove things not in settings, but that'd delete things you installed manually
    # maybe provide option to list things that "shouldn't" be installed so they can be
    # removed manually

def update_casks(casks):
    install_missing('cask', casks)
    cleanup_casks()

def update_taps(taps):
    install_missing('tap', taps)

def ensure_command_line_tools_installed():
    """Ensure command line tools are installed."""
    log.info("Ensuring command line tools are installed")
    try:
        _execute(['xcode-select', '--install'])
    except subprocess.CalledProcessError as error:
        if error.returncode == 1:
            log.info("Command line tools already installed")
        else:
            raise

def ensure_correct_permissions(*args, **kwargs):
    """Ensure that the Homebrew formula installation directory has correct permissions."""
    user = getpass.getuser()
    uid = os.stat('/usr/local').st_uid
    local_owner = pwd.getpwuid(uid).pw_name

    log.debug(f"Currently logged in user is {user!r}, owner of /usr/local is {local_owner!r}")

    if user != local_owner:
        log.info("Fixing permissions on /usr/local before running Homebrew")
        # stupid that there's a shutil.chown but no shutil.chown -R
        cmd = ['sudo', 'chown', '-R', user, '/usr/local']
        _execute(cmd)

def is_installed():
    """Return True if Homebrew command is installed."""
    return bool(shutil.which('brew'))

def install():
    """Install Homebrew on a system that doesn't have it."""
    # http://brew.sh/
    # ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    pass

def run_post_install(post_install):
    """
    Run any post-install operations.

    'post_install' is a list of shell commands. Each shell command can be a string or a list
    of strings. If a string, will pass shell=True to the subprocess call.

    """
    if not post_install:
        return

    log.info("Running post-install operations")
    for cmd in post_install:
        _execute(cmd)

def fix_repository():
    # http://stackoverflow.com/questions/14113427/brew-update-failed
    log.info("Fixing Homebrew repository")
    _execute('cd `brew --prefix`; git reset --hard origin/master')

def get_formula_uses(formula, installed=True):
    """Get the formulas that depend on the specified formula."""
    log.info(
        f"Getting {'installed' if installed else 'all'} formulas that depend on formula: {formula}")
    cmd = ['brew', 'uses']
    if installed:
        cmd += ['--installed']
    cmd += [formula]
    return _get_command_output(cmd)

def get_formula_dependencies(formula):
    """Get dependencies for the specified formula."""
    log.info(f"Getting dependencies for formula: {formula}")
    return _get_command_output(['brew', 'deps', formula])

def get_installed_formulas_with_dependencies():
    """Get a dictionary mapping formulas to their dependencies."""
    return {
        formula: get_formula_dependencies(formula)
        for formula in get_installed_formulas()
    }

def get_leaf_formulas():
    """Get the formulas that are not the dependencies of other formulas."""
    formulas_with_deps = get_installed_formulas_with_dependencies()
    all_deps = set(chain.from_iterable(deps for deps in formulas_with_deps.values()))
    all_formulas = set(formulas_with_deps.keys())
    return all_formulas - all_deps

def _get_command_output(cmd):
    """Execute the specified command, parse its output, and return a list of items in the output."""
    # bytes.decode defaults to utf-8, which *should* also be the default system encoding
    # but I suppose to really do this correctly I should check that. However, pretty sure
    # all Homebrew package names should be ascii anyway so it's fine
    log.debug(f"Executing: {cmd!r}")
    return subprocess.check_output(cmd).decode().splitlines()

def _execute(cmd, shell=False):
    log.debug(f"Executing: {cmd!r}")
    subprocess.check_call(cmd, shell=isinstance(cmd, str))
<commit_msg>Don't save cached Homebrew downloads<commit_after>"""A library for controlling Homebrew through Python."""

import getpass
import logging
import os
import pwd
import shutil
import subprocess
from itertools import chain

log = logging.getLogger(__name__)

def workflow(settings, fix_repo=False):
    """Run an entire Homebrew update workflow."""
    if not is_installed():
        # todo: install homebrew if not installed
        raise Exception("Homebrew must be installed")

    if fix_repo:
        fix_repository()

    ensure_correct_permissions()
    ensure_command_line_tools_installed()

    update()

    update_taps(settings.get('taps', []))
    update_formulas(settings.get('formulas', []))
    update_casks(settings.get('casks', []))

    run_post_install(settings['post_install'])

def get_installed_formulas():
    log.info("Getting installed formulas")
    return _get_command_output(['brew', 'list'])

def get_installed_casks():
    log.info("Getting installed casks")
    return _get_command_output(['brew', 'cask', 'list'])

def get_installed_taps():
    log.info("Getting installed taps")
    return _get_command_output(['brew', 'tap'])

def install_formula(formula):
    log.info(f"Installing formula: {formula}")
    if isinstance(formula, str):
        formula = [formula]
    _execute(['brew', 'install', *formula])

def install_cask(cask):
    # note: brew cask doesn't support upgrade yet:
    # https://github.com/caskroom/homebrew-cask/issues/4678

    log.info(f"Installing cask: {cask}")
    _execute(['brew', 'cask', 'install', cask])

def install_tap(tap):
    log.info(f"Installing tap: {tap}")
    _execute(['brew', 'tap', tap])

def cleanup_formulas():
    log.info("Running cleanup: formulas")
    _execute(['brew', 'cleanup', '-s'])

def cleanup_casks():
    log.info("Running cleanup: casks")
    _execute(['brew', 'cask', 'cleanup'])

def update():
    log.info("Updating Homebrew")
    _execute(['brew', 'update'])

def upgrade():
    log.info("Running upgrade")
    # Homebrew can return an error code in cases that aren't errors:
    # https://github.com/Homebrew/homebrew/issues/27048
    # so, catch any error here and make sure to inspect the output for problems
    try:
        _execute(['brew', 'upgrade'])
    except:
        pass

def install_missing(type, expected):
    assert type in ('formula', 'cask', 'tap')
    get_installed = globals()[f'get_installed_{type}s']
    install = globals()[f'install_{type}']

    log.info(f"Expected {type}s are: {', '.join(sorted(expected))}")
    installed = get_installed()
    log.info(f"Currently installed {type}s are: {', '.join(installed)}")

    missing = sorted(set(expected) - set(installed))
    if missing:
        log.info(f"Missing {type}s are: {', '.join(missing)}")
        for item in missing:
            install(item)
    else:
        log.info(f"No missing {type}s")

def update_formulas(formulas):
    log.info("Updating formulas")
    upgrade()
    install_missing('formula', formulas)
    cleanup_formulas()

    # possible todo: remove things not in settings, but that'd delete things you installed manually
    # maybe provide option to list things that "shouldn't" be installed so they can be
    # removed manually

def update_casks(casks):
    install_missing('cask', casks)
    cleanup_casks()

def update_taps(taps):
    install_missing('tap', taps)

def ensure_command_line_tools_installed():
    """Ensure command line tools are installed."""
    log.info("Ensuring command line tools are installed")
    try:
        _execute(['xcode-select', '--install'])
    except subprocess.CalledProcessError as error:
        if error.returncode == 1:
            log.info("Command line tools already installed")
        else:
            raise

def ensure_correct_permissions(*args, **kwargs):
    """Ensure that the Homebrew formula installation directory has correct permissions."""
    user = getpass.getuser()
    uid = os.stat('/usr/local').st_uid
    local_owner = pwd.getpwuid(uid).pw_name

    log.debug(f"Currently logged in user is {user!r}, owner of /usr/local is {local_owner!r}")

    if user != local_owner:
        log.info("Fixing permissions on /usr/local before running Homebrew")
        # stupid that there's a shutil.chown but no shutil.chown -R
        cmd = ['sudo', 'chown', '-R', user, '/usr/local']
        _execute(cmd)

def is_installed():
    """Return True if Homebrew command is installed."""
    return bool(shutil.which('brew'))

def install():
    """Install Homebrew on a system that doesn't have it."""
    # http://brew.sh/
    # ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    pass

def run_post_install(post_install):
    """
    Run any post-install operations.

    'post_install' is a list of shell commands. Each shell command can be a string or a list
    of strings. If a string, will pass shell=True to the subprocess call.

    """
    if not post_install:
        return

    log.info("Running post-install operations")
    for cmd in post_install:
        _execute(cmd)

def fix_repository():
    # http://stackoverflow.com/questions/14113427/brew-update-failed
    log.info("Fixing Homebrew repository")
    _execute('cd `brew --prefix`; git reset --hard origin/master')

def get_formula_uses(formula, installed=True):
    """Get the formulas that depend on the specified formula."""
    log.info(
        f"Getting {'installed' if installed else 'all'} formulas that depend on formula: {formula}")
    cmd = ['brew', 'uses']
    if installed:
        cmd += ['--installed']
    cmd += [formula]
    return _get_command_output(cmd)

def get_formula_dependencies(formula):
    """Get dependencies for the specified formula."""
    log.info(f"Getting dependencies for formula: {formula}")
    return _get_command_output(['brew', 'deps', formula])

def get_installed_formulas_with_dependencies():
    """Get a dictionary mapping formulas to their dependencies."""
    return {
        formula: get_formula_dependencies(formula)
        for formula in get_installed_formulas()
    }

def get_leaf_formulas():
    """Get the formulas that are not the dependencies of other formulas."""
    formulas_with_deps = get_installed_formulas_with_dependencies()
    all_deps = set(chain.from_iterable(deps for deps in formulas_with_deps.values()))
    all_formulas = set(formulas_with_deps.keys())
    return all_formulas - all_deps

def _get_command_output(cmd):
    """Execute the specified command, parse its output, and return a list of items in the output."""
    # bytes.decode defaults to utf-8, which *should* also be the default system encoding
    # but I suppose to really do this correctly I should check that. However, pretty sure
    # all Homebrew package names should be ascii anyway so it's fine
    log.debug(f"Executing: {cmd!r}")
    return subprocess.check_output(cmd).decode().splitlines()

def _execute(cmd, shell=False):
    log.debug(f"Executing: {cmd!r}")
    subprocess.check_call(cmd, shell=isinstance(cmd, str))
<|endoftext|>


<commit_before>#!/usr/bin/env python

# Copyright 2009-2014 Eucalyptus Systems, Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#    http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import json
from pprint import pformat
from shutil import copyfile
import difflib

class Config(object):
    """
    Intention of this class is to provide utilities around reading and writing
    CLI environment related configuration.
    """
    def __init__(self,
                 name,
                 config_file_path=None,
                 type=None,
                 version=None,
                 **kwargs):
        '''
        Creates a base Config() object. This object is a basic python
        representation of a textual configuration(file). This configuration
        is currently described using JSON. This class provides utilities to
        read, write, map, save, compare, and validate python attributes to a
        json configuration.
        :param name: string. The name of this config section
        :param config_file_path: Optional.string. Local path this config obj
                                 should read/write
        :param type: Optional. string. Identifier for this config object.
        :param version: Optional. string. can be used to version a config
        :param kwargs: Optional set of key word args which will be passed to
                       to the local user defined _setup() method.
        '''
        self._json_properties = {}
        # Set name and config file path first to allow updating base values
        # from an existing file
        self.add_prop('name', name)
        self.config_file_path = config_file_path
        self.update_from_file()
        #Now overwrite with any params provided
        self.add_prop('type', type)
        self.add_prop('version', version)
        self._setup(**kwargs)

    def _setup(self, **kwargs):
        """
        Optional setup method to be implemented by subclasses.
        This method is called by Config.__init__().
        """
        pass

    def _get_json_property(self, property_name):
        """
        helper method for mapping json to python properties
        """
        return self._json_properties[property_name]

    def _set_json_property(self, property_name, value):
        """
        helper method for mapping json to python properties
        """
        self._json_properties[property_name] = value

    def _del_json_property(self, property_name):
        """
        helper method for mapping json to python properties
        """
        if property_name in self._json_properties:
            self._json_properties.pop(property_name)

    def _get_formatted_conf(self):
        return pformat(vars(self))

    def _get_formatted_conf_from_file(self):
        if self.config_file_path:
            dict = self._get_dict_from_file(self.config_file_path)
            return pformat(dict)

    def _get_keys(self):
        return vars(self).keys()

    def _get_dict_from_file(self, file_path=None):
        """
        Attempts to read in json from an existing file, load and return as
        a dict
        """
        file_path = file_path or self.config_file_path
        newdict = None
        if os.path.exists(str(file_path)) and os.path.getsize(str(file_path)):
            if not os.path.isfile(file_path):
                raise ValueError('config file exists at path and is not '
                                 'a file:' + str(file_path))
            conf_file = open(file_path, 'rb')
            with conf_file:
                data = conf_file.read()
            if data:
                try:
                    newdict = json.loads(data)
                except ValueError as ve:
                    ve.args = (['Failed to load json config from: "{0}". '
                                'ERR: "{1}"'.format(file_path, ve.message)])
                    raise
        return newdict

    def __repr__(self):
        """
        Default string representation of this object will be the formatted
        json configuration
        """
        return self.to_json()

    def add_prop(self,
                 python_name,
                 value=None,
                 json_name=None,
                 docstring=None,
                 validate_callback=None):
        """
        Dynamically add properties which will be used to build json
        representation of this object for configuration purposes. Allows
        values to be accessed as both a local python attribute/property of
        this object, and store that value in a formatted dict for json
        conversion. The setter can also be created with a validation
        method which is called before writing to the json dict storing the
        value. Note that the validator must return the value which will be
        stored. This allows for the value to be formatted/manipulated before
        storing.

        :param python_name: The name of the python property which will be
                            create for this config obj.
        :param json_name: The name used to store the value in self._json_dict
        :param value: optional value to store. Defaults to 'None'
        :param docstring: optional docstring to be used with creating the
                          dynamic python property
        :param validate_callback: optional method, if provided this method can
                                  be used validate or convert the value before
                                  storing.
        Example:
        In [29] def stringcheck(value)
                    assert isinstance(value, str)
                    return value
        In [30] c = Config(name='example')
        In [31] c.add_prop('my_python_string',
                    value='python doesnt like dashes',
                    json_name='my-json-string',
                    docstring='just a string',
                    validate_callback=stringcheck)
        In [32]: print c.my_python_string
        python doesnt like dashes

        In [33]: print c._to_json()
        {
            "my-json-string": "python doesnt like dashes",
            "name": "testconfig",
            "type": null,
            "version": null
        }
        In [34]: c.my_python_string = 'easy to change'

        In [35]: print c.my_python_string
        easy to change

        In [36]: print c._to_json()
        {
            "my-json-string": "easy to change",
            "name": "testconfig",
            "type": null,
            "version": null
        }
        """
        assert python_name
        json_name = json_name or python_name
        docstring = docstring or "Updates json dict for value:'{0}'"\
            .format(json_name)

        def temp_prop_getter(self):
            return self._get_json_property(json_name)

        def temp_prop_setter(self, newvalue):
            # If a validation callback was provided use it, otherwise
            # allow the user to create a local method named
            # by '_validate_' + the python_name provided which will be
            # called. A validation method is optional but if defined,
            # must return the value to be set for this property.
            validate = validate_callback or getattr(self,
                                                    '_validate_' + python_name,
                                                    None)
            if validate:
                newvalue = validate(newvalue)
            return self._set_json_property(json_name, newvalue)

        def temp_prop_delete(self):
            self._del_json_property(json_name)
        temp_prop = property(fget=temp_prop_getter, fset=temp_prop_setter,
                             fdel=temp_prop_delete, doc=docstring)
        setattr(self.__class__, python_name, temp_prop)
        self._set_json_property(json_name, value)

    def del_prop(self, property_name):
        prop = getattr(self, property_name, None)
        if prop:
            if isinstance(prop, property):
                self.__delattr__(property_name)
            else:
                raise ValueError('{0} is not a "property" of this obj'
                                 .format(property_name))

    def update_from_file(self, file_path=None):
        file_path = file_path or self.config_file_path
        newdict = self._get_dict_from_file(file_path=file_path)
        if newdict:
            self.__dict__.update(newdict)

    #todo define how validation methods for each config subclass should be used
    def validate(self):
        """
        Method to validate configuration. This would likely be checks
        against the aggregate config as individual validation checks
        should be done in each property's setter via the validation_callback
        """
        pass

    #todo define how/if this method should be used, examples, etc..
    def send(self, filehandle=None):
        """
        Method which defines how, where, when etc a config should be written.
        For writing to a local path use self.save(), this method is a
        placeholder for possibly writing to a remote server, or submitting
        the json configuration to another process, etc..
        """
        pass

    def diff(self, file_path=None):
        """
        Method to show current values vs those (saved) in a file.
        Will return a formatted string to show the difference
        """
        #Create formatted string representation of dict values
        text1 = self.to_json().splitlines()
        #Create formatted string representation of values in file
        file_path = file_path or self.config_file_path
        file_dict = self._get_dict_from_file(file_path=file_path) or {}
        text2 = json.dumps(file_dict, sort_keys=True, indent=4).splitlines()
        diff = difflib.unified_diff(text2, text1, lineterm='')
        return '\n'.join(diff)

    def save(self, path=None):
        """
        Will write the json configuration to a file at path or by default at
        self.config_file_path.
        """
        path = path or self.config_file_path
        backup_path = path + '.bak'
        config_json = self.to_json()
        if os.path.isfile(path):
            copyfile(path, backup_path)
        save_file = file(path, "w")
        with save_file:
            save_file.write(config_json)
            save_file.flush()

    def to_json(self):
        """
        converts the local dict '_json_properties{} to json
        """
        return json.dumps(self,
                          default=lambda o: o._json_properties,
                          sort_keys=True,
                          indent=4)
<commit_msg>Remove property validation on delete<commit_after>#!/usr/bin/env python

# Copyright 2009-2014 Eucalyptus Systems, Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

#    http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os
import json
from pprint import pformat
from shutil import copyfile
import difflib

class Config(object):
    """
    Intention of this class is to provide utilities around reading and writing
    CLI environment related configuration.
    """
    def __init__(self,
                 name,
                 config_file_path=None,
                 type=None,
                 version=None,
                 **kwargs):
        '''
        Creates a base Config() object. This object is a basic python
        representation of a textual configuration(file). This configuration
        is currently described using JSON. This class provides utilities to
        read, write, map, save, compare, and validate python attributes to a
        json configuration.
        :param name: string. The name of this config section
        :param config_file_path: Optional.string. Local path this config obj
                                 should read/write
        :param type: Optional. string. Identifier for this config object.
        :param version: Optional. string. can be used to version a config
        :param kwargs: Optional set of key word args which will be passed to
                       to the local user defined _setup() method.
        '''
        self._json_properties = {}
        # Set name and config file path first to allow updating base values
        # from an existing file
        self.add_prop('name', name)
        self.config_file_path = config_file_path
        self.update_from_file()
        #Now overwrite with any params provided
        self.add_prop('type', type)
        self.add_prop('version', version)
        self._setup(**kwargs)

    def _setup(self, **kwargs):
        """
        Optional setup method to be implemented by subclasses.
        This method is called by Config.__init__().
        """
        pass

    def _get_json_property(self, property_name):
        """
        helper method for mapping json to python properties
        """
        return self._json_properties[property_name]

    def _set_json_property(self, property_name, value):
        """
        helper method for mapping json to python properties
        """
        self._json_properties[property_name] = value

    def _del_json_property(self, property_name):
        """
        helper method for mapping json to python properties
        """
        if property_name in self._json_properties:
            self._json_properties.pop(property_name)

    def _get_formatted_conf(self):
        return pformat(vars(self))

    def _get_formatted_conf_from_file(self):
        if self.config_file_path:
            dict = self._get_dict_from_file(self.config_file_path)
            return pformat(dict)

    def _get_keys(self):
        return vars(self).keys()

    def _get_dict_from_file(self, file_path=None):
        """
        Attempts to read in json from an existing file, load and return as
        a dict
        """
        file_path = file_path or self.config_file_path
        newdict = None
        if os.path.exists(str(file_path)) and os.path.getsize(str(file_path)):
            if not os.path.isfile(file_path):
                raise ValueError('config file exists at path and is not '
                                 'a file:' + str(file_path))
            conf_file = open(file_path, 'rb')
            with conf_file:
                data = conf_file.read()
            if data:
                try:
                    newdict = json.loads(data)
                except ValueError as ve:
                    ve.args = (['Failed to load json config from: "{0}". '
                                'ERR: "{1}"'.format(file_path, ve.message)])
                    raise
        return newdict

    def __repr__(self):
        """
        Default string representation of this object will be the formatted
        json configuration
        """
        return self.to_json()

    def add_prop(self,
                 python_name,
                 value=None,
                 json_name=None,
                 docstring=None,
                 validate_callback=None):
        """
        Dynamically add properties which will be used to build json
        representation of this object for configuration purposes. Allows
        values to be accessed as both a local python attribute/property of
        this object, and store that value in a formatted dict for json
        conversion. The setter can also be created with a validation
        method which is called before writing to the json dict storing the
        value. Note that the validator must return the value which will be
        stored. This allows for the value to be formatted/manipulated before
        storing.

        :param python_name: The name of the python property which will be
                            create for this config obj.
        :param json_name: The name used to store the value in self._json_dict
        :param value: optional value to store. Defaults to 'None'
        :param docstring: optional docstring to be used with creating the
                          dynamic python property
        :param validate_callback: optional method, if provided this method can
                                  be used validate or convert the value before
                                  storing.
        Example:
        In [29] def stringcheck(value)
                    assert isinstance(value, str)
                    return value
        In [30] c = Config(name='example')
        In [31] c.add_prop('my_python_string',
                    value='python doesnt like dashes',
                    json_name='my-json-string',
                    docstring='just a string',
                    validate_callback=stringcheck)
        In [32]: print c.my_python_string
        python doesnt like dashes

        In [33]: print c._to_json()
        {
            "my-json-string": "python doesnt like dashes",
            "name": "testconfig",
            "type": null,
            "version": null
        }
        In [34]: c.my_python_string = 'easy to change'

        In [35]: print c.my_python_string
        easy to change

        In [36]: print c._to_json()
        {
            "my-json-string": "easy to change",
            "name": "testconfig",
            "type": null,
            "version": null
        }
        """
        assert python_name
        json_name = json_name or python_name
        docstring = docstring or "Updates json dict for value:'{0}'"\
            .format(json_name)

        def temp_prop_getter(self):
            return self._get_json_property(json_name)

        def temp_prop_setter(self, newvalue):
            # If a validation callback was provided use it, otherwise
            # allow the user to create a local method named
            # by '_validate_' + the python_name provided which will be
            # called. A validation method is optional but if defined,
            # must return the value to be set for this property.
            validate = validate_callback or getattr(self,
                                                    '_validate_' + python_name,
                                                    None)
            if validate:
                newvalue = validate(newvalue)
            return self._set_json_property(json_name, newvalue)

        def temp_prop_delete(self):
            self._del_json_property(json_name)
        temp_prop = property(fget=temp_prop_getter, fset=temp_prop_setter,
                             fdel=temp_prop_delete, doc=docstring)
        setattr(self.__class__, python_name, temp_prop)
        self._set_json_property(json_name, value)

    def del_prop(self, property_name):
        prop = getattr(self, property_name, None)
        if prop:
            self.__delattr__(property_name)

    def update_from_file(self, file_path=None):
        file_path = file_path or self.config_file_path
        newdict = self._get_dict_from_file(file_path=file_path)
        if newdict:
            self.__dict__.update(newdict)

    #todo define how validation methods for each config subclass should be used
    def validate(self):
        """
        Method to validate configuration. This would likely be checks
        against the aggregate config as individual validation checks
        should be done in each property's setter via the validation_callback
        """
        pass

    #todo define how/if this method should be used, examples, etc..
    def send(self, filehandle=None):
        """
        Method which defines how, where, when etc a config should be written.
        For writing to a local path use self.save(), this method is a
        placeholder for possibly writing to a remote server, or submitting
        the json configuration to another process, etc..
        """
        pass

    def diff(self, file_path=None):
        """
        Method to show current values vs those (saved) in a file.
        Will return a formatted string to show the difference
        """
        #Create formatted string representation of dict values
        text1 = self.to_json().splitlines()
        #Create formatted string representation of values in file
        file_path = file_path or self.config_file_path
        file_dict = self._get_dict_from_file(file_path=file_path) or {}
        text2 = json.dumps(file_dict, sort_keys=True, indent=4).splitlines()
        diff = difflib.unified_diff(text2, text1, lineterm='')
        return '\n'.join(diff)

    def save(self, path=None):
        """
        Will write the json configuration to a file at path or by default at
        self.config_file_path.
        """
        path = path or self.config_file_path
        backup_path = path + '.bak'
        config_json = self.to_json()
        if os.path.isfile(path):
            copyfile(path, backup_path)
        save_file = file(path, "w")
        with save_file:
            save_file.write(config_json)
            save_file.flush()

    def to_json(self):
        """
        converts the local dict '_json_properties{} to json
        """
        return json.dumps(self,
                          default=lambda o: o._json_properties,
                          sort_keys=True,
                          indent=4)
<|endoftext|>


<commit_before>from django.db import models
from django.contrib.auth.models import User

class DatasetLicence(models.Model):
    title = models.CharField(max_length=255)
    short_title = models.CharField(max_length=30)
    url = models.URLField()
    summary = models.TextField()
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

class FileFormat(models.Model):
    extension = models.CharField(max_length=10)
    description = models.TextField()
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

def get_dataset_upload_path(self, instance, filename):
    return '/%s/' % instance.author.username

class Dataset(models.Model):
    title = models.CharField(max_length=255)
    licence = models.ForeignKey('DatasetLicence')
    file = models.FileField(upload_to=get_dataset_upload_path)
    file_format = models.ForeignKey('FileFormat')
    description = models.TextField()
    author = models.ForeignKey(User)
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)
<commit_msg>Add slug field to Dataset model. Using slugs for API looks better than pk.<commit_after>from django.db import models
from django.contrib.auth.models import User

class DatasetLicence(models.Model):
    title = models.CharField(max_length=255)
    short_title = models.CharField(max_length=30)
    url = models.URLField()
    summary = models.TextField()
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

class FileFormat(models.Model):
    extension = models.CharField(max_length=10)
    description = models.TextField()
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)

def get_dataset_upload_path(self, instance, filename):
    return '/%s/' % instance.author.username

class Dataset(models.Model):
    title = models.CharField(max_length=255)
    licence = models.ForeignKey('DatasetLicence')
    file = models.FileField(upload_to=get_dataset_upload_path)
    file_format = models.ForeignKey('FileFormat')
    description = models.TextField()
    author = models.ForeignKey(User)
    slug = models.SlugField(max_length=40)
    updated = models.DateTimeField(auto_now=True)
    created = models.DateTimeField(auto_now_add=True)
<|endoftext|>


<commit_before>import csnBuild
import csnUtility
import os.path

thirdPartyModuleFolder = ""
thirdPartyBinFolder = ""
defaultLibType = "dll"

def GetSourceFileExtensions():
    return ["cxx", "cc", "cpp"]

def GetIncludeFileExtensions():
    return ["h", "hpp", "txx"]

def LoadThirdPartyModule(_subFolder, _name):
    """ Loads third party module _name from subfolder _subFolder of the third party folder """
    assert thirdPartyModuleFolder != ""
    folder = "%s/%s" % (thirdPartyModuleFolder, _subFolder)
    return csnUtility.LoadModule(folder, _name)

def AddApplications(_holderProject, _applicationDependenciesList, _modules, _modulesFolder, _pch = ""):
    """
    Creates application projects and adds them to _holderProject (using _holderProject.AddProject). The holder
    project does not depend on these application projects.
    It is assumed that _modules is a list containing subfolders of _modulesFolder.
    Each subfolder in _modules should contain source files (.cpp, .cxx or .cc), where each source file corresponds to a single application.
    Hence, each source file is used to create a new application project. For example, assuming that the _modulesFolder
    is called 'Applications', the file 'Applications/Small/Tiny.cpp' will be used to build the 'Tiny' application.

    _applicationDependenciesList - List of projects that each new application project is dependent on.
    _modulesFolder - Folder containing subfolders with applications.
    _modules = List of subfolders of _modulesFolder that should be processed.
    _pch - If not "", this is the C++ include file which is used for building a precompiled header file for each application.
    """
    for module in _modules:
        moduleFolder = "%s/%s" % (_modulesFolder, module)
        sourceFiles = []
        headerFiles = []
        for extension in GetSourceFileExtensions():
            sourceFiles.extend(_holderProject.Glob("%s/*.%s" % (moduleFolder, extension)))

        for extension in GetIncludeFileExtensions():
            headerFiles.extend(_holderProject.Glob("%s/*.%s" % (moduleFolder, extension)))

        for sourceFile in sourceFiles:
            if os.path.isdir(sourceFile):
                continue
            (name, ext) = os.path.splitext( os.path.basename(sourceFile) )
            app = csnBuild.Project("%s_%s" % (_holderProject.name, name), "executable", _sourceRootFolder = _holderProject.sourceRootFolder)
            app.AddIncludeFolders([moduleFolder])
            app.AddProjects(_applicationDependenciesList)
            app.AddSources([sourceFile])
            # add header files so that they appear in visual studio
            app.AddSources(headerFiles)
            if( _pch != "" ):
                app.SetPrecompiledHeader(_pch)
            _holderProject.AddProjects([app])

class CilabModuleProject(csnBuild.Project):
    """
    This class is used to build a library coming from the CilabModules folder. Use AddLibraryModules to create libraries
    from source in the libmodules subfolder of a cilab module. Use AddDemos and AddApplications to add executable projects
    based on sources in the 'demos' and 'Applications' subfolders.
    """
    def __init__(self, _name, _type):
        csnBuild.Project.__init__(self, _name, _type)

    def AddLibraryModules(self, _libModules):
        """
        Adds source files (anything matching *.c??) and public include folders to self, using a set of libmodules.
        It is assumed that the root folder of self has a subfolder called libmodules. The subfolders of libmodules should
        contain a subfolder called src (e.g. for mymodule, this would be libmodules/mymodule/src).
        If the src folder has a subfolder called 'stub', it is also added to the source tree.
        _libModules - a list of subfolders of the libmodules folder that should be 'added' to self.
        """
        # add sources
        for libModule in _libModules:
            for stub in ("/stub", ""):
                srcFolder = "libmodules/%s/src%s" % (libModule, stub)
                srcFolderAbs = "%s/%s" % (self.sourceRootFolder, srcFolder)
                if( os.path.exists(srcFolderAbs) ):
                    self.AddIncludeFolders([srcFolder])
                    for extension in GetSourceFileExtensions():
                        self.AddSources(["%s/*.%s" % (srcFolder, extension)], _checkExists = 0)
                    for extension in GetIncludeFileExtensions():
                        self.AddSources(["%s/*.%s" % (srcFolder, extension)], _checkExists = 0)

        if( len(self.sources) == 0 ):
            self.AddSources([csnUtility.GetDummyCppFilename()])

        for libModule in _libModules:
            for stub in ("/stub", ""):
                includeFolder = "libmodules/%s/include%s" % (libModule, stub)
                includeFolderAbs = "%s/%s" % (self.sourceRootFolder, includeFolder)
                if( os.path.exists(includeFolderAbs) ):
                    self.AddIncludeFolders([includeFolder])
                    for extension in GetIncludeFileExtensions():
                        self.AddSources(["%s/*.%s" % (includeFolder, extension)], _checkExists = 0)

    def AddDemos(self, _modules, _pch = "", _applicationDependenciesList = None):
        """
        Creates extra CSnake projects, each project building one demo in the demos subfolder of the current project.
        _modules - List of the subfolders within the demos subfolder that must be scanned for demos.
        _pch - If not "", this is the include file used to generate a precompiled header for each demo.
        """
        dependencies = [self]
        if not _applicationDependenciesList is None:
            dependencies.extend(_applicationDependenciesList)

        demosName = "%sDemos" % self.name
        csnBuild.globalSettings.SetSuperSubCategory("Demos", demosName)
        demosProject = csnBuild.Project(demosName, "dll", _sourceRootFolder = self.sourceRootFolder, _categories = [demosName])
        demosProject.AddSources([csnUtility.GetDummyCppFilename()], _sourceGroup = "CSnakeGeneratedFiles")
        AddApplications(demosProject, dependencies, _modules, "%s/demos" % self.sourceRootFolder, _pch)
        demosProject.AddProjects([self])
        self.AddProjects([demosProject], _dependency = 0)

    def AddApplications(self, _modules, _pch = "", _applicationDependenciesList = None):
        """
        Similar to AddDemos, but works on the Applications subfolder.
        """
        dependencies = [self]
        if not _applicationDependenciesList is None:
            dependencies.extend(_applicationDependenciesList)

        applicationsName = "%sApplications" % self.name
        csnBuild.globalSettings.SetSuperSubCategory("Applications", applicationsName)
        applicationsProject = csnBuild.Project(self.name + "Applications", "dll", _sourceRootFolder = self.sourceRootFolder, _categories = [applicationsName])
        applicationsProject.AddSources([csnUtility.GetDummyCppFilename()], _sourceGroup = "CSnakeGeneratedFiles")
        AddApplications(applicationsProject, dependencies, _modules, "%s/Applications" % self.sourceRootFolder, _pch)
        applicationsProject.AddProjects([self])
        self.AddProjects([applicationsProject], _dependency = 0)

class GimiasPluginProject(csnBuild.Project):
    """
    This class is used to build a plugin coming from the CilabApps/Plugins folder. Use AddWidgetModules to add widget
    modules to the plugin.
    """
    def __init__(self, _name):
        csnBuild.Project.__init__(self, _name, "dll", _categories = ["GIMIAS%s" % _name])
        self.installSubFolder = "plugins/%s/lib" % _name
        self.AddIncludeFolders(["."])

    def AddWidgetModules(self, _widgetModules, _holdingFolder = "widgets", _useQt = 1):
        """
        Similar to AddCilabLibraryModules, but this time the source code in the widgets folder is added to self.
        _useQt - If true, adds build rules for the ui and moc files .
        """
        # add sources
        for widgetModule in _widgetModules:
            srcFolder = "%s/%s" % (_holdingFolder, widgetModule)
            srcFolderAbs = "%s/%s" % (self.sourceRootFolder, srcFolder)
            if( os.path.exists(srcFolderAbs) ):
                self.AddIncludeFolders([srcFolder])
                for extension in GetSourceFileExtensions():
                    self.AddSources(["%s/*.%s" % (srcFolder, extension)], _checkExists = 0, _sourceGroup = "Widgets")
                if _useQt:
                    self.AddSources(["%s/*.ui" % srcFolder], _ui = 1, _checkExists = 0, _sourceGroup = "WidgetsUI")

            includeFolder = "%s/%s" % (_holdingFolder, widgetModule)
            includeFolderAbs = "%s/%s" % (self.sourceRootFolder, includeFolder)
            if( os.path.exists(includeFolderAbs) ):
                self.AddIncludeFolders([includeFolder])
                for extension in GetIncludeFileExtensions():
                    self.AddSources(["%s/*.%s" % (includeFolder, extension)], _moc = _useQt and extension == "h", _checkExists = 0, _sourceGroup = "Widgets")
<commit_msg>Now by default NOT using qt<commit_after>import csnBuild
import csnUtility
import os.path

thirdPartyModuleFolder = ""
thirdPartyBinFolder = ""
defaultLibType = "dll"

def GetSourceFileExtensions():
    return ["cxx", "cc", "cpp"]

def GetIncludeFileExtensions():
    return ["h", "hpp", "txx"]

def LoadThirdPartyModule(_subFolder, _name):
    """ Loads third party module _name from subfolder _subFolder of the third party folder """
    assert thirdPartyModuleFolder != ""
    folder = "%s/%s" % (thirdPartyModuleFolder, _subFolder)
    return csnUtility.LoadModule(folder, _name)

def AddApplications(_holderProject, _applicationDependenciesList, _modules, _modulesFolder, _pch = ""):
    """
    Creates application projects and adds them to _holderProject (using _holderProject.AddProject). The holder
    project does not depend on these application projects.
    It is assumed that _modules is a list containing subfolders of _modulesFolder.
    Each subfolder in _modules should contain source files (.cpp, .cxx or .cc), where each source file corresponds to a single application.
    Hence, each source file is used to create a new application project. For example, assuming that the _modulesFolder
    is called 'Applications', the file 'Applications/Small/Tiny.cpp' will be used to build the 'Tiny' application.

    _applicationDependenciesList - List of projects that each new application project is dependent on.
    _modulesFolder - Folder containing subfolders with applications.
    _modules = List of subfolders of _modulesFolder that should be processed.
    _pch - If not "", this is the C++ include file which is used for building a precompiled header file for each application.
    """
    for module in _modules:
        moduleFolder = "%s/%s" % (_modulesFolder, module)
        sourceFiles = []
        headerFiles = []
        for extension in GetSourceFileExtensions():
            sourceFiles.extend(_holderProject.Glob("%s/*.%s" % (moduleFolder, extension)))

        for extension in GetIncludeFileExtensions():
            headerFiles.extend(_holderProject.Glob("%s/*.%s" % (moduleFolder, extension)))

        for sourceFile in sourceFiles:
            if os.path.isdir(sourceFile):
                continue
            (name, ext) = os.path.splitext( os.path.basename(sourceFile) )
            app = csnBuild.Project("%s_%s" % (_holderProject.name, name), "executable", _sourceRootFolder = _holderProject.sourceRootFolder)
            app.AddIncludeFolders([moduleFolder])
            app.AddProjects(_applicationDependenciesList)
            app.AddSources([sourceFile])
            # add header files so that they appear in visual studio
            app.AddSources(headerFiles)
            if( _pch != "" ):
                app.SetPrecompiledHeader(_pch)
            _holderProject.AddProjects([app])

class CilabModuleProject(csnBuild.Project):
    """
    This class is used to build a library coming from the CilabModules folder. Use AddLibraryModules to create libraries
    from source in the libmodules subfolder of a cilab module. Use AddDemos and AddApplications to add executable projects
    based on sources in the 'demos' and 'Applications' subfolders.
    """
    def __init__(self, _name, _type):
        csnBuild.Project.__init__(self, _name, _type)

    def AddLibraryModules(self, _libModules):
        """
        Adds source files (anything matching *.c??) and public include folders to self, using a set of libmodules.
        It is assumed that the root folder of self has a subfolder called libmodules. The subfolders of libmodules should
        contain a subfolder called src (e.g. for mymodule, this would be libmodules/mymodule/src).
        If the src folder has a subfolder called 'stub', it is also added to the source tree.
        _libModules - a list of subfolders of the libmodules folder that should be 'added' to self.
        """
        # add sources
        for libModule in _libModules:
            for stub in ("/stub", ""):
                srcFolder = "libmodules/%s/src%s" % (libModule, stub)
                srcFolderAbs = "%s/%s" % (self.sourceRootFolder, srcFolder)
                if( os.path.exists(srcFolderAbs) ):
                    self.AddIncludeFolders([srcFolder])
                    for extension in GetSourceFileExtensions():
                        self.AddSources(["%s/*.%s" % (srcFolder, extension)], _checkExists = 0)
                    for extension in GetIncludeFileExtensions():
                        self.AddSources(["%s/*.%s" % (srcFolder, extension)], _checkExists = 0)

        if( len(self.sources) == 0 ):
            self.AddSources([csnUtility.GetDummyCppFilename()])

        for libModule in _libModules:
            for stub in ("/stub", ""):
                includeFolder = "libmodules/%s/include%s" % (libModule, stub)
                includeFolderAbs = "%s/%s" % (self.sourceRootFolder, includeFolder)
                if( os.path.exists(includeFolderAbs) ):
                    self.AddIncludeFolders([includeFolder])
                    for extension in GetIncludeFileExtensions():
                        self.AddSources(["%s/*.%s" % (includeFolder, extension)], _checkExists = 0)

    def AddDemos(self, _modules, _pch = "", _applicationDependenciesList = None):
        """
        Creates extra CSnake projects, each project building one demo in the demos subfolder of the current project.
        _modules - List of the subfolders within the demos subfolder that must be scanned for demos.
        _pch - If not "", this is the include file used to generate a precompiled header for each demo.
        """
        dependencies = [self]
        if not _applicationDependenciesList is None:
            dependencies.extend(_applicationDependenciesList)

        demosName = "%sDemos" % self.name
        csnBuild.globalSettings.SetSuperSubCategory("Demos", demosName)
        demosProject = csnBuild.Project(demosName, "dll", _sourceRootFolder = self.sourceRootFolder, _categories = [demosName])
        demosProject.AddSources([csnUtility.GetDummyCppFilename()], _sourceGroup = "CSnakeGeneratedFiles")
        AddApplications(demosProject, dependencies, _modules, "%s/demos" % self.sourceRootFolder, _pch)
        demosProject.AddProjects([self])
        self.AddProjects([demosProject], _dependency = 0)

    def AddApplications(self, _modules, _pch = "", _applicationDependenciesList = None):
        """
        Similar to AddDemos, but works on the Applications subfolder.
        """
        dependencies = [self]
        if not _applicationDependenciesList is None:
            dependencies.extend(_applicationDependenciesList)

        applicationsName = "%sApplications" % self.name
        csnBuild.globalSettings.SetSuperSubCategory("Applications", applicationsName)
        applicationsProject = csnBuild.Project(self.name + "Applications", "dll", _sourceRootFolder = self.sourceRootFolder, _categories = [applicationsName])
        applicationsProject.AddSources([csnUtility.GetDummyCppFilename()], _sourceGroup = "CSnakeGeneratedFiles")
        AddApplications(applicationsProject, dependencies, _modules, "%s/Applications" % self.sourceRootFolder, _pch)
        applicationsProject.AddProjects([self])
        self.AddProjects([applicationsProject], _dependency = 0)

class GimiasPluginProject(csnBuild.Project):
    """
    This class is used to build a plugin coming from the CilabApps/Plugins folder. Use AddWidgetModules to add widget
    modules to the plugin.
    """
    def __init__(self, _name):
        csnBuild.Project.__init__(self, _name, "dll", _categories = ["GIMIAS%s" % _name])
        self.installSubFolder = "plugins/%s/lib" % _name
        self.AddIncludeFolders(["."])

    def AddWidgetModules(self, _widgetModules, _holdingFolder = "widgets", _useQt = 0):
        """
        Similar to AddCilabLibraryModules, but this time the source code in the widgets folder is added to self.
        _useQt - If true, adds build rules for the ui and moc files .
        """
        # add sources
        for widgetModule in _widgetModules:
            srcFolder = "%s/%s" % (_holdingFolder, widgetModule)
            srcFolderAbs = "%s/%s" % (self.sourceRootFolder, srcFolder)
            if( os.path.exists(srcFolderAbs) ):
                self.AddIncludeFolders([srcFolder])
                for extension in GetSourceFileExtensions():
                    self.AddSources(["%s/*.%s" % (srcFolder, extension)], _checkExists = 0, _sourceGroup = "Widgets")
                if _useQt:
                    self.AddSources(["%s/*.ui" % srcFolder], _ui = 1, _checkExists = 0, _sourceGroup = "WidgetsUI")

            includeFolder = "%s/%s" % (_holdingFolder, widgetModule)
            includeFolderAbs = "%s/%s" % (self.sourceRootFolder, includeFolder)
            if( os.path.exists(includeFolderAbs) ):
                self.AddIncludeFolders([includeFolder])
                for extension in GetIncludeFileExtensions():
                    self.AddSources(["%s/*.%s" % (includeFolder, extension)], _moc = _useQt and extension == "h", _checkExists = 0, _sourceGroup = "Widgets")
<|endoftext|>