<commit_before>"""
Result lists.

Licensed under MIT
Copyright (c) 2013 - 2015 Isaac Muse <isaacmuse@gmail.com>

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.
"""
from __future__ import unicode_literals
from time import ctime
import wx
import decimal
import os
import functools
from .dynamic_lists import DynamicList, USE_SAMPLE_SIZE
from ..actions import fileops
from ..localization import _
from .. import data
from ... import util

CONTENT_PATH = 0
CONTENT_LINE = 1
CONTENT_MATCH = 2
CONTENT_EXT = 3
CONTENT_TEXT = 4
CONTENT_KEY = 5
CONTENT_COL = 6
CONTENT_ENC = 7

FILE_NAME = 0
FILE_MATCH = 1
FILE_EXT = 2
FILE_SIZE = 3
FILE_PATH = 4
FILE_ENC = 5
FILE_MOD = 6
FILE_CRE = 7
FILE_LINE = 8
FILE_COL = 9

class ContextMenu(wx.Menu):
    """Context Menu."""

    def __init__(self, parent, menu, pos):
        """Attach the context menu to to the parent with the defined items."""

        wx.Menu.__init__(self)
        self._callbacks = {}

        for i in menu:
            menuid = wx.NewId()
            item = wx.MenuItem(self, menuid, i[0])
            self._callbacks[menuid] = i[1]
            self.Append(item)
            if len(i) > 2 and not i[2]:
                self.Enable(menuid, False)
            self.Bind(wx.EVT_MENU, self.on_callback, item)

        parent.PopupMenu(self, pos)

    def on_callback(self, event):
        """Execute the menu item callback."""

        menuid = event.GetId()
        self._callbacks[menuid](event)
        event.Skip()

class ResultFileList(DynamicList):
    """ResultFileList."""

    def __init__(self, parent):
        """Init ResultFileList object."""

        self.localize()

        super(ResultFileList, self).__init__(
            parent,
            [
                self.FILE,
                self.MATCHES,
                self.EXTENSION,
                self.SIZE,
                self.PATH,
                self.ENCODING,
                self.MODIFIED,
                self.CREATED
            ]
        )
        self.last_moused = (-1, "")
        self.Bind(wx.EVT_LEFT_DCLICK, self.on_dclick)
        self.Bind(wx.EVT_MOTION, self.on_motion)
        self.Bind(wx.EVT_ENTER_WINDOW, self.on_enter_window)
        self.Bind(wx.EVT_RIGHT_DOWN, self.on_rclick)

    def localize(self):
        """Translate strings."""

        self.FILE = _("File")
        self.SIZE = _("Size")
        self.MATCHES = _("Matches")
        self.EXTENSION = _('Extensions')
        self.PATH = _("Path")
        self.ENCODING = _("Encoding")
        self.MODIFIED = _("Modified")
        self.CREATED = _("Created")
        self.REVEAL_LABEL = {
            "windows": _("Reveal in Explorer"),
            "osx": _("Reveal in Finder"),
            "linux": _("Reveal in File Manager")
        }

    def create_image_list(self):
        """Create the image list."""

        self.images = wx.ImageList(16, 16)
        self.doc = self.images.Add(data.get_bitmap('doc.png'))
        self.bin = self.images.Add(data.get_bitmap('binary.png'))
        self.sort_up = self.images.Add(data.get_bitmap('su.png'))
        self.sort_down = self.images.Add(data.get_bitmap('sd.png'))
        self.SetImageList(self.images, wx.IMAGE_LIST_SMALL)

    def set_match(self, obj, file_search=False):
        """Set match."""

        if file_search:
            self.set_item_map(
                obj.name,
                os.path.basename(obj.name),
                0,
                obj.ext,
                decimal.Decimal(obj.size) / decimal.Decimal(1024),
                os.path.dirname(obj.name),
                '',
                obj.modified,
                obj.created,
                1,
                1
            )
        else:
            item_id = "%d" % obj.info.id
            if item_id in self.itemDataMap:
                self.increment_match_count(item_id)
            else:
                self.set_item_map(
                    item_id,
                    os.path.basename(obj.info.name),
                    1,
                    obj.info.ext,
                    decimal.Decimal(obj.info.size) / decimal.Decimal(1024),
                    os.path.dirname(obj.info.name),
                    obj.info.encoding,
                    obj.info.modified,
                    obj.info.created,
                    obj.match.lineno,
                    obj.match.colno
                )

    def on_enter_window(self, event):
        """Reset last moused over item tracker on mouse entering the window."""

        self.last_moused = (-1, "")
        event.Skip()

    def on_motion(self, event):
        """Display full file path in status bar on item mouseover."""

        if self.complete:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                actual_item = self.itemIndexMap[item]
                if actual_item != self.last_moused[0]:
                    d = self.itemDataMap[actual_item]
                    self.last_moused = (actual_item, os.path.join(d[FILE_PATH], d[FILE_NAME]))
                self.GetParent().GetParent().GetParent().GetParent().m_statusbar.set_timed_status(self.last_moused[1])
        event.Skip()

    def get_item_text(self, item, col, absolute=False):
        """Return the text for the given item and col."""

        if not absolute:
            item = self.itemIndexMap[item]
        if col == FILE_SIZE:
            return '%.2fKB' % round(self.itemDataMap[item][FILE_SIZE], 2)
        elif col in (FILE_MOD, FILE_CRE):
            return ctime(self.itemDataMap[item][col])
        else:
            return util.to_ustr(self.itemDataMap[item][col])

    def OnGetItemImage(self, item):
        """Override method to get the image for the given item."""

        encoding = self.itemDataMap[self.itemIndexMap[item]][FILE_ENC]
        return 1 if encoding == "BIN" else 0

    def increment_match_count(self, idx):
        """Increment the match count of the given item."""

        entry = list(self.itemDataMap[idx])
        entry[FILE_MATCH] += 1
        self.itemDataMap[idx] = tuple(entry)
        # Sample the first "size_sample" to determine
        # column width for when table first loads
        if idx <= self.last_idx_sized or not USE_SAMPLE_SIZE:
            text = self.get_item_text(idx, FILE_MATCH, True)
            lw = self.dc.GetFullTextExtent(text)[0]
            width = lw + 30
            if width > self.widest_cell[FILE_MATCH]:
                self.widest_cell[FILE_MATCH] = width

    def on_dclick(self, event):
        """Open file at in editor with optional line and column argument."""

        with self.wait:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                filename = self.GetItem(item, col=0).GetText()
                path = self.GetItem(item, col=FILE_PATH).GetText()
                line = str(self.get_map_item(item, col=FILE_LINE))
                col = str(self.get_map_item(item, col=FILE_COL))
                fileops.open_editor(os.path.join(os.path.normpath(path), filename), line, col)
        event.Skip()

    def on_rclick(self, event):
        """Show context menu on right click."""

        target = None
        enabled = False
        with self.wait:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                filename = self.GetItem(item, col=FILE_NAME).GetText()
                path = self.GetItem(item, col=FILE_PATH).GetText()
                target = os.path.join(path, filename)
                selected = self.IsSelected(item)
                select_count = self.GetSelectedItemCount()
                enabled = not selected or (selected and select_count == 1)
                # Select if not already
                if not selected:
                    self.Select(item)
        if target is not None:
            # Open menu
            ContextMenu(
                self,
                [
                    (self.REVEAL_LABEL[util.platform()], functools.partial(fileops.reveal, target=target), enabled)
                ],
                pos
            )
        event.Skip()

class ResultContentList(DynamicList):
    """ResultContentList."""

    def __init__(self, parent):
        """Init ResultContentFileList object."""

        self.localize()

        super(ResultContentList, self).__init__(
            parent,
            [
                self.FILE,
                self.LINE,
                self.MATCHES,
                self.EXTENSION,
                self.CONTEXT
            ]
        )
        self.last_moused = (-1, "")
        self.Bind(wx.EVT_LEFT_DCLICK, self.on_dclick)
        self.Bind(wx.EVT_MOTION, self.on_motion)
        self.Bind(wx.EVT_ENTER_WINDOW, self.on_enter_window)

    def localize(self):
        """Translate strings."""

        self.FILE = _("File")
        self.LINE = _("Line")
        self.MATCHES = _("Matches")
        self.EXTENSION = _("Extension")
        self.CONTEXT = _("Context")

    def create_image_list(self):
        """Create the image list."""

        self.images = wx.ImageList(16, 16)
        self.doc = self.images.Add(data.get_bitmap('doc.png'))
        self.bin = self.images.Add(data.get_bitmap('binary.png'))
        self.sort_up = self.images.Add(data.get_bitmap('su.png'))
        self.sort_down = self.images.Add(data.get_bitmap('sd.png'))
        self.SetImageList(self.images, wx.IMAGE_LIST_SMALL)

    def on_enter_window(self, event):
        """Reset last moused over item tracker on mouse entering the window."""

        self.last_moused = (-1, "")
        event.Skip()

    def on_motion(self, event):
        """Display full file path in status bar on item mouseover."""

        if self.complete:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                actual_item = self.itemIndexMap[item]
                if actual_item != self.last_moused[0]:
                    pth = self.itemDataMap[actual_item][CONTENT_PATH]
                    self.last_moused = (actual_item, os.path.join(pth[1], pth[0]))
                self.GetParent().GetParent().GetParent().GetParent().m_statusbar.set_timed_status(self.last_moused[1])
        event.Skip()

    def get_item_text(self, item, col, absolute=False):
        """Return the text for the given item and col."""

        if not absolute:
            item = self.itemIndexMap[item]
        if col == CONTENT_PATH:
            return util.to_ustr(self.itemDataMap[item][CONTENT_PATH][0])
        else:
            return util.to_ustr(self.itemDataMap[item][col])

    def increment_match_count(self, idx):
        """Increment the match count of the given item."""

        entry = list(self.itemDataMap[idx])
        entry[CONTENT_MATCH] += 1
        self.itemDataMap[idx] = tuple(entry)
        # Sample the first "size_sample" to determine
        # column width for when table first loads
        if idx <= self.last_idx_sized or not USE_SAMPLE_SIZE:
            text = self.get_item_text(idx, CONTENT_MATCH, True)
            lw = self.dc.GetFullTextExtent(text)[0]
            width = lw + 30
            if width > self.widest_cell[CONTENT_MATCH]:
                self.widest_cell[CONTENT_MATCH] = width

    def set_match(self, obj):
        """Set the match."""

        item_id = "%d:%d" % (obj.info.id, obj.match.lineno)
        if item_id in self.itemDataMap:
            self.increment_match_count(item_id)
        else:
            self.set_item_map(
                item_id,
                (os.path.basename(obj.info.name), os.path.dirname(obj.info.name)),
                obj.match.lineno,
                1,
                obj.info.ext,
                obj.match.lines.replace("\r", "").split("\n")[0],
                "%d" % obj.info.id,
                obj.match.colno,
                obj.info.encoding
            )

    def OnGetItemImage(self, item):
        """Override method to get the image for the given item."""

        encoding = self.itemDataMap[self.itemIndexMap[item]][CONTENT_ENC]
        return 1 if encoding == "BIN" else 0

    def on_dclick(self, event):
        """Open file at in editor with optional line and column argument."""

        with self.wait:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                filename = self.GetItem(item, col=CONTENT_PATH).GetText()
                line = self.GetItem(item, col=CONTENT_LINE).GetText()
                file_row = self.get_map_item(item, col=CONTENT_KEY)
                col = str(self.get_map_item(item, col=CONTENT_COL))
                path = self.GetParent().GetParent().GetParent().GetParent().m_result_file_list.get_map_item(
                    file_row, col=FILE_PATH, absolute=True
                )
                fileops.open_editor(os.path.join(os.path.normpath(path), filename), line, col)
        event.Skip()
<commit_msg>Allow opening multiple items in the editor<commit_after>"""
Result lists.

Licensed under MIT
Copyright (c) 2013 - 2015 Isaac Muse <isaacmuse@gmail.com>

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.
"""
from __future__ import unicode_literals
from time import ctime
import wx
import decimal
import os
import functools
from .dynamic_lists import DynamicList, USE_SAMPLE_SIZE
from ..actions import fileops
from ..localization import _
from .. import data
from ... import util

CONTENT_PATH = 0
CONTENT_LINE = 1
CONTENT_MATCH = 2
CONTENT_EXT = 3
CONTENT_TEXT = 4
CONTENT_KEY = 5
CONTENT_COL = 6
CONTENT_ENC = 7

FILE_NAME = 0
FILE_MATCH = 1
FILE_EXT = 2
FILE_SIZE = 3
FILE_PATH = 4
FILE_ENC = 5
FILE_MOD = 6
FILE_CRE = 7
FILE_LINE = 8
FILE_COL = 9

class ContextMenu(wx.Menu):
    """Context Menu."""

    def __init__(self, parent, menu, pos):
        """Attach the context menu to to the parent with the defined items."""

        wx.Menu.__init__(self)
        self._callbacks = {}

        for i in menu:
            menuid = wx.NewId()
            item = wx.MenuItem(self, menuid, i[0])
            self._callbacks[menuid] = i[1]
            self.Append(item)
            if len(i) > 2 and not i[2]:
                self.Enable(menuid, False)
            self.Bind(wx.EVT_MENU, self.on_callback, item)

        parent.PopupMenu(self, pos)

    def on_callback(self, event):
        """Execute the menu item callback."""

        menuid = event.GetId()
        self._callbacks[menuid](event)
        event.Skip()

class ResultFileList(DynamicList):
    """ResultFileList."""

    def __init__(self, parent):
        """Init ResultFileList object."""

        self.localize()

        super(ResultFileList, self).__init__(
            parent,
            [
                self.FILE,
                self.MATCHES,
                self.EXTENSION,
                self.SIZE,
                self.PATH,
                self.ENCODING,
                self.MODIFIED,
                self.CREATED
            ],
            False
        )
        self.last_moused = (-1, "")
        self.Bind(wx.EVT_LEFT_DCLICK, self.on_dclick)
        self.Bind(wx.EVT_MOTION, self.on_motion)
        self.Bind(wx.EVT_ENTER_WINDOW, self.on_enter_window)
        self.Bind(wx.EVT_RIGHT_DOWN, self.on_rclick)

    def localize(self):
        """Translate strings."""

        self.FILE = _("File")
        self.SIZE = _("Size")
        self.MATCHES = _("Matches")
        self.EXTENSION = _('Extensions')
        self.PATH = _("Path")
        self.ENCODING = _("Encoding")
        self.MODIFIED = _("Modified")
        self.CREATED = _("Created")
        self.EDITOR_LABEL = _("Open in Editor")
        self.REVEAL_LABEL = {
            "windows": _("Reveal in Explorer"),
            "osx": _("Reveal in Finder"),
            "linux": _("Reveal in File Manager")
        }

    def create_image_list(self):
        """Create the image list."""

        self.images = wx.ImageList(16, 16)
        self.doc = self.images.Add(data.get_bitmap('doc.png'))
        self.bin = self.images.Add(data.get_bitmap('binary.png'))
        self.sort_up = self.images.Add(data.get_bitmap('su.png'))
        self.sort_down = self.images.Add(data.get_bitmap('sd.png'))
        self.SetImageList(self.images, wx.IMAGE_LIST_SMALL)

    def set_match(self, obj, file_search=False):
        """Set match."""

        if file_search:
            self.set_item_map(
                obj.name,
                os.path.basename(obj.name),
                0,
                obj.ext,
                decimal.Decimal(obj.size) / decimal.Decimal(1024),
                os.path.dirname(obj.name),
                '',
                obj.modified,
                obj.created,
                1,
                1
            )
        else:
            item_id = "%d" % obj.info.id
            if item_id in self.itemDataMap:
                self.increment_match_count(item_id)
            else:
                self.set_item_map(
                    item_id,
                    os.path.basename(obj.info.name),
                    1,
                    obj.info.ext,
                    decimal.Decimal(obj.info.size) / decimal.Decimal(1024),
                    os.path.dirname(obj.info.name),
                    obj.info.encoding,
                    obj.info.modified,
                    obj.info.created,
                    obj.match.lineno,
                    obj.match.colno
                )

    def on_enter_window(self, event):
        """Reset last moused over item tracker on mouse entering the window."""

        self.last_moused = (-1, "")
        event.Skip()

    def on_motion(self, event):
        """Display full file path in status bar on item mouseover."""

        if self.complete:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                actual_item = self.itemIndexMap[item]
                if actual_item != self.last_moused[0]:
                    d = self.itemDataMap[actual_item]
                    self.last_moused = (actual_item, os.path.join(d[FILE_PATH], d[FILE_NAME]))
                self.GetParent().GetParent().GetParent().GetParent().m_statusbar.set_timed_status(self.last_moused[1])
        event.Skip()

    def get_item_text(self, item, col, absolute=False):
        """Return the text for the given item and col."""

        if not absolute:
            item = self.itemIndexMap[item]
        if col == FILE_SIZE:
            return '%.2fKB' % round(self.itemDataMap[item][FILE_SIZE], 2)
        elif col in (FILE_MOD, FILE_CRE):
            return ctime(self.itemDataMap[item][col])
        else:
            return util.to_ustr(self.itemDataMap[item][col])

    def OnGetItemImage(self, item):
        """Override method to get the image for the given item."""

        encoding = self.itemDataMap[self.itemIndexMap[item]][FILE_ENC]
        return 1 if encoding == "BIN" else 0

    def increment_match_count(self, idx):
        """Increment the match count of the given item."""

        entry = list(self.itemDataMap[idx])
        entry[FILE_MATCH] += 1
        self.itemDataMap[idx] = tuple(entry)
        # Sample the first "size_sample" to determine
        # column width for when table first loads
        if idx <= self.last_idx_sized or not USE_SAMPLE_SIZE:
            text = self.get_item_text(idx, FILE_MATCH, True)
            lw = self.dc.GetFullTextExtent(text)[0]
            width = lw + 30
            if width > self.widest_cell[FILE_MATCH]:
                self.widest_cell[FILE_MATCH] = width

    def on_dclick(self, event):
        """Open file at in editor with optional line and column argument."""

        with self.wait:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                filename = self.GetItem(item, col=0).GetText()
                path = self.GetItem(item, col=FILE_PATH).GetText()
                line = str(self.get_map_item(item, col=FILE_LINE))
                col = str(self.get_map_item(item, col=FILE_COL))
                fileops.open_editor(os.path.join(os.path.normpath(path), filename), line, col)
        event.Skip()

    def open_editor(self, event, item):
        """Open file(s) in editor."""

        if item != -1:
            target = None
            with self.wait:
                filename = self.GetItem(item, col=FILE_NAME).GetText()
                path = self.GetItem(item, col=FILE_PATH).GetText()
                target = os.path.join(path, filename)
                line = str(self.get_map_item(item, col=FILE_LINE))
                col = str(self.get_map_item(item, col=FILE_COL))
            if target:
                fileops.open_editor(target, line, col)
        else:
            item = self.GetFirstSelected()
            while item != -1:
                target = None
                with self.wait:
                    filename = self.GetItem(item, col=FILE_NAME).GetText()
                    path = self.GetItem(item, col=FILE_PATH).GetText()
                    target = os.path.join(path, filename)
                    line = str(self.get_map_item(item, col=FILE_LINE))
                    col = str(self.get_map_item(item, col=FILE_COL))
                if target:
                    fileops.open_editor(target, line, col)
                item = self.GetNextSelected(item)

    def on_rclick(self, event):
        """Show context menu on right click."""

        target = None
        enabled = False
        with self.wait:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                filename = self.GetItem(item, col=FILE_NAME).GetText()
                path = self.GetItem(item, col=FILE_PATH).GetText()
                target = os.path.join(path, filename)
                selected = self.IsSelected(item)
                select_count = self.GetSelectedItemCount()
                enabled = not selected or (selected and select_count == 1)
                # Select if not already
                if not selected:
                    s = self.GetFirstSelected()
                    while s != -1:
                        if s != item:
                            self.Select(s, False)
                        s = self.GetNextSelected(s)
        if target is not None:
            if not enabled:
                item = -1
            # Open menu
            ContextMenu(
                self,
                [
                    (self.REVEAL_LABEL[util.platform()], functools.partial(fileops.reveal, target=target), enabled),
                    (self.EDITOR_LABEL, functools.partial(self.open_editor, item=item), True)
                ],
                pos
            )
        event.Skip()

class ResultContentList(DynamicList):
    """ResultContentList."""

    def __init__(self, parent):
        """Init ResultContentFileList object."""

        self.localize()

        super(ResultContentList, self).__init__(
            parent,
            [
                self.FILE,
                self.LINE,
                self.MATCHES,
                self.EXTENSION,
                self.CONTEXT
            ],
        )
        self.last_moused = (-1, "")
        self.Bind(wx.EVT_LEFT_DCLICK, self.on_dclick)
        self.Bind(wx.EVT_MOTION, self.on_motion)
        self.Bind(wx.EVT_ENTER_WINDOW, self.on_enter_window)

    def localize(self):
        """Translate strings."""

        self.FILE = _("File")
        self.LINE = _("Line")
        self.MATCHES = _("Matches")
        self.EXTENSION = _("Extension")
        self.CONTEXT = _("Context")

    def create_image_list(self):
        """Create the image list."""

        self.images = wx.ImageList(16, 16)
        self.doc = self.images.Add(data.get_bitmap('doc.png'))
        self.bin = self.images.Add(data.get_bitmap('binary.png'))
        self.sort_up = self.images.Add(data.get_bitmap('su.png'))
        self.sort_down = self.images.Add(data.get_bitmap('sd.png'))
        self.SetImageList(self.images, wx.IMAGE_LIST_SMALL)

    def on_enter_window(self, event):
        """Reset last moused over item tracker on mouse entering the window."""

        self.last_moused = (-1, "")
        event.Skip()

    def on_motion(self, event):
        """Display full file path in status bar on item mouseover."""

        if self.complete:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                actual_item = self.itemIndexMap[item]
                if actual_item != self.last_moused[0]:
                    pth = self.itemDataMap[actual_item][CONTENT_PATH]
                    self.last_moused = (actual_item, os.path.join(pth[1], pth[0]))
                self.GetParent().GetParent().GetParent().GetParent().m_statusbar.set_timed_status(self.last_moused[1])
        event.Skip()

    def get_item_text(self, item, col, absolute=False):
        """Return the text for the given item and col."""

        if not absolute:
            item = self.itemIndexMap[item]
        if col == CONTENT_PATH:
            return util.to_ustr(self.itemDataMap[item][CONTENT_PATH][0])
        else:
            return util.to_ustr(self.itemDataMap[item][col])

    def increment_match_count(self, idx):
        """Increment the match count of the given item."""

        entry = list(self.itemDataMap[idx])
        entry[CONTENT_MATCH] += 1
        self.itemDataMap[idx] = tuple(entry)
        # Sample the first "size_sample" to determine
        # column width for when table first loads
        if idx <= self.last_idx_sized or not USE_SAMPLE_SIZE:
            text = self.get_item_text(idx, CONTENT_MATCH, True)
            lw = self.dc.GetFullTextExtent(text)[0]
            width = lw + 30
            if width > self.widest_cell[CONTENT_MATCH]:
                self.widest_cell[CONTENT_MATCH] = width

    def set_match(self, obj):
        """Set the match."""

        item_id = "%d:%d" % (obj.info.id, obj.match.lineno)
        if item_id in self.itemDataMap:
            self.increment_match_count(item_id)
        else:
            self.set_item_map(
                item_id,
                (os.path.basename(obj.info.name), os.path.dirname(obj.info.name)),
                obj.match.lineno,
                1,
                obj.info.ext,
                obj.match.lines.replace("\r", "").split("\n")[0],
                "%d" % obj.info.id,
                obj.match.colno,
                obj.info.encoding
            )

    def OnGetItemImage(self, item):
        """Override method to get the image for the given item."""

        encoding = self.itemDataMap[self.itemIndexMap[item]][CONTENT_ENC]
        return 1 if encoding == "BIN" else 0

    def on_dclick(self, event):
        """Open file at in editor with optional line and column argument."""

        with self.wait:
            pos = event.GetPosition()
            item = self.HitTestSubItem(pos)[0]
            if item != -1:
                filename = self.GetItem(item, col=CONTENT_PATH).GetText()
                line = self.GetItem(item, col=CONTENT_LINE).GetText()
                file_row = self.get_map_item(item, col=CONTENT_KEY)
                col = str(self.get_map_item(item, col=CONTENT_COL))
                path = self.GetParent().GetParent().GetParent().GetParent().m_result_file_list.get_map_item(
                    file_row, col=FILE_PATH, absolute=True
                )
                fileops.open_editor(os.path.join(os.path.normpath(path), filename), line, col)
        event.Skip()
<|endoftext|>


<commit_before>"""
Notify windows.

Copyright (c) 2013 - 2016 Isaac Muse <isaacmuse@gmail.com>
License: MIT
"""
import traceback
import winsound
import ctypes
import ctypes.wintypes as wintypes
import os

__all__ = ("get_notify", "alert", "setup", "windows_icons", "destroy")

if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
    WPARAM = ctypes.c_ulong
    LPARAM = ctypes.c_long
    LRESULT = ctypes.c_long
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
    WPARAM = ctypes.c_ulonglong
    LPARAM = ctypes.c_longlong
    LRESULT = ctypes.c_longlong
HANDLE = ctypes.c_void_p
WNDPROCTYPE = WNDPROC = ctypes.CFUNCTYPE(LRESULT, HANDLE, ctypes.c_uint, WPARAM, LPARAM)

WM_DESTROY = 2
IMAGE_ICON = 1
LR_LOADFROMFILE = 16
LR_DEFAULTSIZE = 64
IDI_APPLICATION = 1
WS_OVERLAPPED = 0
WS_SYSMENU = 524288
CW_USEDEFAULT = -2147483648
WM_USER = 1024

NIM_ADD = 0x00
NIM_MODIFY = 0x01
NIM_DELETE = 0x02
NIM_SETVERSION = 0x04
NIF_MESSAGE = 0x01
NIF_ICON = 0x02
NIF_TIP = 0x04
NIF_STATE = 0x08
NIF_INFO = 0x10
NIF_REALTIME = 0x40
NIF_SHOWTIP = 0x80
NIIF_INFO = 0x1
NIIF_WARNING = 0x2
NIIF_ERROR = 0x3
NIIF_NOSOUND = 0x10
NIFF_USER = 0x00000004

NIS_HIDDEN = 0x01

HWND_MESSAGE = -3

NIN_BALLOONSHOW = WM_USER + 2
NIN_BALLOONHIDE = WM_USER + 3
NIN_BALLOONTIMEOUT = WM_USER + 4
NIN_BALLOONUSERCLICK = WM_USER + 5

class WndClassEx(ctypes.Structure):
    """The `WNDCLASSEX` structure."""

    _fields_ = [
        ("cbSize", ctypes.c_uint),
        ("style", ctypes.c_uint),
        ("lpfnWndProc", WNDPROCTYPE),
        ("cbClsExtra", ctypes.c_int),
        ("cbWndExtra", ctypes.c_int),
        ("hInstance", HANDLE),
        ("hIcon", HANDLE),
        ("hCursor", HANDLE),
        ("hbrBackground", HANDLE),
        ("lpszMenuName", wintypes.LPCWSTR),
        ("lpszClassName", wintypes.LPCWSTR),
        ("hIconSm", HANDLE)
    ]

class NotifyIconData(ctypes.Structure):
    """The `NOTIFYICONDATA` structure."""

    _fields_ = [
        ("cbSize", ctypes.c_uint),
        ("hWnd", HANDLE),
        ("uID", ctypes.c_uint),
        ("uFlags", ctypes.c_uint),
        ("uCallbackMessage", ctypes.c_uint),
        ("hIcon", HANDLE),
        ("szTip", ctypes.c_wchar * 128),
        ("dwState", ctypes.c_uint),
        ("dwStateMask", ctypes.c_uint),
        ("szInfo", ctypes.c_wchar * 256),
        ("uVersion", ctypes.c_uint),
        ("szInfoTitle", ctypes.c_wchar * 64),
        ("dwInfoFlags", ctypes.c_uint),
        ("guidItem", ctypes.c_char * 16),
        ("hBalloonIcon", HANDLE),
    ]

class Options:
    """Notification options."""

    notify = None
    instance = None
    sound = None

    @classmethod
    def clear(cls):
        """Clear."""

        cls.notify = None
        cls.instance = None
        cls.sound = None

def _alert(sound=None):
    """Play an alert sound for the OS."""

    if sound is None and Options.sound is not None:
        sound = Options.sound

    try:
        if sound:
            winsound.PlaySound(sound, winsound.SND_FILENAME)
    except Exception:
        pass

def alert():
    """Alert."""

    _alert()

class WinNotifyLevel:
    """Windows notification level."""

    ICON_INFORMATION = 0x01
    ICON_WARNING = 0x02
    ICON_ERROR = 0x04

windows_icons = {
    "Info": WinNotifyLevel.ICON_INFORMATION,
    "Warning": WinNotifyLevel.ICON_WARNING,
    "Error": WinNotifyLevel.ICON_ERROR
}

def notify_win_fallback(title, message, sound, icon, fallback):
    """Notify win calls the fallback."""

    fallback(title, message, sound)

class WindowsNotify:
    """Windows notification class."""

    window_handle = None
    taskbar_icon = None
    wc = None

    def __init__(self, app_name, icon, tooltip=None):
        """
        Create the taskbar for the application and register it.

        Show nothing by default until called.
        """

        def winproc(hwnd, msg, wparam, lparam):
            """Handle `winproc` events."""

            if msg == WM_USER + 20 and lparam in (NIN_BALLOONTIMEOUT, NIN_BALLOONUSERCLICK):
                pass
            return hwnd

        self.tooltip = tooltip
        self.visible = False
        self.app_name = app_name

        # Register window class
        wc = WndClassEx()
        self.hinst = wc.hInstance = ctypes.windll.kernel32.GetModuleHandleW(None)
        wc.cbSize = ctypes.sizeof(wc)
        wc.lpszClassName = ctypes.c_wchar_p(app_name + "Taskbar")
        wc.lpfnWndProc = WNDPROCTYPE(winproc)
        wc.style = 0
        wc.cbClsExtra = 0
        wc.cbWndExtra = 0
        wc.hIcon = 0
        wc.hCursor = 0
        wc.hbrBackground = 0

        if WindowsNotify.wc is not None:
            self._destroy_window()
            ctypes.windll.user32.UnregisterClassW(wc.lpszClassName, None)
            WindowsNotify.wc = wc
        ctypes.windll.user32.RegisterClassExW(ctypes.byref(wc))
        WindowsNotify.wc = wc

        self.hicon = self.get_icon(icon)

        self._show_notification('', '', False, self.hicon)

    def get_icon(self, icon):
        """
        Get icon.

        Try to load the given icon from the path given,
        else default to generic application icon from the OS.
        """

        if WindowsNotify.taskbar_icon is not None:
            ctypes.windll.user32.DestroyIcon(wintypes.HICON(WindowsNotify.taskbar_icon))
            WindowsNotify.taskbar_icon = None

        icon_flags = LR_LOADFROMFILE
        try:
            if icon is None:
                raise ValueError("Icon is not available")
            hicon = ctypes.windll.user32.LoadImageW(
                self.hinst, icon,
                IMAGE_ICON,
                0, 0, icon_flags
            )
        except Exception:
            hicon = ctypes.windll.user32.LoadIconA(0, IDI_APPLICATION)
        WindowsNotify.taskbar_icon = hicon

        return hicon

    def show_notification(self, title, msg, sound, icon, fallback):
        """
        Attempt to show notifications.

        Provide fallback for consistency with other notification methods.
        """

        try:
            self._show_notification(title, msg, sound, icon)
        except Exception:
            print(traceback.format_exc())
            fallback(title, msg, sound)

    def _get_window(self):
        """Create the Window."""

        if WindowsNotify.window_handle:
            hwnd = WindowsNotify.window_handle
        else:
            hwnd = ctypes.windll.user32.FindWindowExW(
                HWND_MESSAGE, None, WindowsNotify.wc.lpszClassName, None
            )
        if not hwnd:
            style = WS_OVERLAPPED | WS_SYSMENU
            hwnd = ctypes.windll.user32.CreateWindowExW(
                0, WindowsNotify.wc.lpszClassName, WindowsNotify.wc.lpszClassName, style,
                0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
                HWND_MESSAGE, 0, self.hinst, None
            )
            if hwnd:
                WindowsNotify.window_handle = hwnd
                ctypes.windll.user32.UpdateWindow(hwnd)
        return hwnd

    def _destroy_window(self):
        """Destroy the window."""

        if WindowsNotify.window_handle:
            if self.visible:
                res = NotifyIconData()
                res.cbSize = ctypes.sizeof(res)
                res.hWnd = WindowsNotify.window_handle
                res.uID = 0
                res.uFlags = 0
                res.uVersion = 4

                ctypes.windll.shell32.Shell_NotifyIconW(NIM_DELETE, ctypes.byref(res))
                ctypes.windll.user32.UpdateWindow(WindowsNotify.window_handle)
            self.visible = False

            ctypes.windll.user32.DestroyWindow(WindowsNotify.window_handle)
            WindowsNotify.window_handle = None

    def _show_notification(self, title, msg, sound, icon):
        """Call windows API to show notification."""

        icon_level = 0
        if icon & WinNotifyLevel.ICON_INFORMATION:
            icon_level |= NIIF_INFO
        elif icon & WinNotifyLevel.ICON_WARNING:
            icon_level |= NIIF_WARNING
        elif icon & WinNotifyLevel.ICON_ERROR:
            icon_level |= NIIF_ERROR

        hwnd = self._get_window()

        if hwnd:
            res = NotifyIconData()
            res.cbSize = ctypes.sizeof(res)
            res.hWnd = hwnd
            res.uID = 0
            # `NIF_SHOWTIP` and `NIF_TIP` is probably not needed for Windows 8+, but maybe for 7?
            res.uFlags = NIF_INFO | NIF_ICON | NIF_STATE | NIF_SHOWTIP | NIF_TIP | NIF_MESSAGE
            res.uCallbackMessage = WM_USER + 20
            res.hIcon = self.hicon
            res.szTip = self.app_name[:128]
            res.uVersion = 4
            res.szInfo = msg[:256]
            res.szInfoTitle = title[:64]
            res.dwInfoFlags = icon_level | NIIF_NOSOUND | NIFF_USER

            if not ctypes.windll.shell32.Shell_NotifyIconW(NIM_MODIFY, ctypes.byref(res)):
                if not self.visible and WindowsNotify.window_handle:
                    ctypes.windll.shell32.Shell_NotifyIconW(NIM_ADD, ctypes.byref(res))
                    ctypes.windll.shell32.Shell_NotifyIconW(NIM_SETVERSION, ctypes.byref(res))
                self.visible = WindowsNotify.window_handle is not None

            if sound:
                alert()

    def destroy(self):
        """Destroy."""

        self._destroy_window()

@staticmethod
def NotifyWin(title, msg, sound, icon, fallback):
    """Notify for windows."""

    Options.instance.show_notification(title, msg, sound, icon, fallback)

def setup(app_name, icon, **kwargs):
    """Setup."""

    sound = kwargs.get('sound')
    if sound is not None and os.path.exists(sound):
        Options.sound = sound

    try:
        if icon is None or not os.path.exists(icon):
            raise ValueError("Icon does not appear to be valid")
    except Exception:
        icon = None

    Options.instance = WindowsNotify(app_name, icon, app_name)
    Options.notify = NotifyWin

def destroy():
    """Destroy."""

    if Options.instance is not None:
        Options.instance.destroy()

    Options.clear()
    Options.notify = notify_win_fallback

def get_notify():
    """Get the notification."""

    return Options.notify

Options.notify = notify_win_fallback
<commit_msg>Fix for icon handling in notifications<commit_after>"""
Notify windows.

Copyright (c) 2013 - 2016 Isaac Muse <isaacmuse@gmail.com>
License: MIT
"""
import traceback
import winsound
import ctypes
import ctypes.wintypes as wintypes
import os

__all__ = ("get_notify", "alert", "setup", "windows_icons", "destroy")

if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
    WPARAM = ctypes.c_ulong
    LPARAM = ctypes.c_long
    LRESULT = ctypes.c_long
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
    WPARAM = ctypes.c_ulonglong
    LPARAM = ctypes.c_longlong
    LRESULT = ctypes.c_longlong
HANDLE = ctypes.c_void_p
WNDPROCTYPE = WNDPROC = ctypes.CFUNCTYPE(LRESULT, HANDLE, ctypes.c_uint, WPARAM, LPARAM)

WM_DESTROY = 2
IMAGE_ICON = 1
LR_LOADFROMFILE = 16
LR_DEFAULTSIZE = 64
IDI_APPLICATION = 1
WS_OVERLAPPED = 0
WS_SYSMENU = 524288
CW_USEDEFAULT = -2147483648
WM_USER = 1024

NIM_ADD = 0x00
NIM_MODIFY = 0x01
NIM_DELETE = 0x02
NIM_SETVERSION = 0x04
NIF_MESSAGE = 0x01
NIF_ICON = 0x02
NIF_TIP = 0x04
NIF_STATE = 0x08
NIF_INFO = 0x10
NIF_REALTIME = 0x40
NIF_SHOWTIP = 0x80
NIIF_INFO = 0x1
NIIF_WARNING = 0x2
NIIF_ERROR = 0x3
NIIF_NOSOUND = 0x10
NIFF_USER = 0x00000004

NIS_HIDDEN = 0x01

HWND_MESSAGE = -3

NIN_BALLOONSHOW = WM_USER + 2
NIN_BALLOONHIDE = WM_USER + 3
NIN_BALLOONTIMEOUT = WM_USER + 4
NIN_BALLOONUSERCLICK = WM_USER + 5

class WndClassEx(ctypes.Structure):
    """The `WNDCLASSEX` structure."""

    _fields_ = [
        ("cbSize", ctypes.c_uint),
        ("style", ctypes.c_uint),
        ("lpfnWndProc", WNDPROCTYPE),
        ("cbClsExtra", ctypes.c_int),
        ("cbWndExtra", ctypes.c_int),
        ("hInstance", HANDLE),
        ("hIcon", HANDLE),
        ("hCursor", HANDLE),
        ("hbrBackground", HANDLE),
        ("lpszMenuName", wintypes.LPCWSTR),
        ("lpszClassName", wintypes.LPCWSTR),
        ("hIconSm", HANDLE)
    ]

class NotifyIconData(ctypes.Structure):
    """The `NOTIFYICONDATA` structure."""

    _fields_ = [
        ("cbSize", ctypes.c_uint),
        ("hWnd", HANDLE),
        ("uID", ctypes.c_uint),
        ("uFlags", ctypes.c_uint),
        ("uCallbackMessage", ctypes.c_uint),
        ("hIcon", HANDLE),
        ("szTip", ctypes.c_wchar * 128),
        ("dwState", ctypes.c_uint),
        ("dwStateMask", ctypes.c_uint),
        ("szInfo", ctypes.c_wchar * 256),
        ("uVersion", ctypes.c_uint),
        ("szInfoTitle", ctypes.c_wchar * 64),
        ("dwInfoFlags", ctypes.c_uint),
        ("guidItem", ctypes.c_char * 16),
        ("hBalloonIcon", HANDLE),
    ]

class Options:
    """Notification options."""

    notify = None
    instance = None
    sound = None

    @classmethod
    def clear(cls):
        """Clear."""

        cls.notify = None
        cls.instance = None
        cls.sound = None

def _alert(sound=None):
    """Play an alert sound for the OS."""

    if sound is None and Options.sound is not None:
        sound = Options.sound

    try:
        if sound:
            winsound.PlaySound(sound, winsound.SND_FILENAME)
    except Exception:
        pass

def alert():
    """Alert."""

    _alert()

class WinNotifyLevel:
    """Windows notification level."""

    ICON_INFORMATION = 0x01
    ICON_WARNING = 0x02
    ICON_ERROR = 0x04

windows_icons = {
    "Info": WinNotifyLevel.ICON_INFORMATION,
    "Warning": WinNotifyLevel.ICON_WARNING,
    "Error": WinNotifyLevel.ICON_ERROR
}

def notify_win_fallback(title, message, sound, icon, fallback):
    """Notify win calls the fallback."""

    fallback(title, message, sound)

class WindowsNotify:
    """Windows notification class."""

    window_handle = None
    taskbar_icon = None
    wc = None

    def __init__(self, app_name, icon, tooltip=None):
        """
        Create the taskbar for the application and register it.

        Show nothing by default until called.
        """

        def winproc(hwnd, msg, wparam, lparam):
            """Handle `winproc` events."""

            if msg == WM_USER + 20 and lparam in (NIN_BALLOONTIMEOUT, NIN_BALLOONUSERCLICK):
                pass
            return hwnd

        self.tooltip = tooltip
        self.visible = False
        self.app_name = app_name

        # Register window class
        wc = WndClassEx()
        self.hinst = wc.hInstance = ctypes.windll.kernel32.GetModuleHandleW(None)
        wc.cbSize = ctypes.sizeof(wc)
        wc.lpszClassName = ctypes.c_wchar_p(app_name + "Taskbar")
        wc.lpfnWndProc = WNDPROCTYPE(winproc)
        wc.style = 0
        wc.cbClsExtra = 0
        wc.cbWndExtra = 0
        wc.hIcon = 0
        wc.hCursor = 0
        wc.hbrBackground = 0

        if WindowsNotify.wc is not None:
            self._destroy_window()
            ctypes.windll.user32.UnregisterClassW(wc.lpszClassName, None)
            WindowsNotify.wc = wc
        ctypes.windll.user32.RegisterClassExW(ctypes.byref(wc))
        WindowsNotify.wc = wc

        self.hicon = self.get_icon(icon)

        self._show_notification('', '', False, 0)

    def get_icon(self, icon):
        """
        Get icon.

        Try to load the given icon from the path given,
        else default to generic application icon from the OS.
        """

        if WindowsNotify.taskbar_icon is not None:
            ctypes.windll.user32.DestroyIcon(wintypes.HICON(WindowsNotify.taskbar_icon))
            WindowsNotify.taskbar_icon = None

        hicon = wintypes.HICON()
        try:
            if icon is None:
                raise ValueError("Icon is not available")
            ctypes.windll.comctl32.LoadIconWithScaleDown(
                None, icon, 48, 48, ctypes.byref(hicon)
            )
        except Exception:
            hicon = ctypes.windll.user32.LoadIconA(0, IDI_APPLICATION)
        WindowsNotify.taskbar_icon = hicon

        return hicon

    def show_notification(self, title, msg, sound, icon, fallback):
        """
        Attempt to show notifications.

        Provide fallback for consistency with other notification methods.
        """

        try:
            self._show_notification(title, msg, sound, icon)
        except Exception:
            print(traceback.format_exc())
            fallback(title, msg, sound)

    def _get_window(self):
        """Create the Window."""

        if WindowsNotify.window_handle:
            hwnd = WindowsNotify.window_handle
        else:
            hwnd = ctypes.windll.user32.FindWindowExW(
                HWND_MESSAGE, None, WindowsNotify.wc.lpszClassName, None
            )
        if not hwnd:
            style = WS_OVERLAPPED | WS_SYSMENU
            hwnd = ctypes.windll.user32.CreateWindowExW(
                0, WindowsNotify.wc.lpszClassName, WindowsNotify.wc.lpszClassName, style,
                0, 0, CW_USEDEFAULT, CW_USEDEFAULT,
                HWND_MESSAGE, 0, self.hinst, None
            )
            if hwnd:
                WindowsNotify.window_handle = hwnd
                ctypes.windll.user32.UpdateWindow(hwnd)
        return hwnd

    def _destroy_window(self):
        """Destroy the window."""

        if WindowsNotify.window_handle:
            if self.visible:
                res = NotifyIconData()
                res.cbSize = ctypes.sizeof(res)
                res.hWnd = WindowsNotify.window_handle
                res.uID = 0
                res.uFlags = 0
                res.uVersion = 4

                ctypes.windll.shell32.Shell_NotifyIconW(NIM_DELETE, ctypes.byref(res))
                ctypes.windll.user32.UpdateWindow(WindowsNotify.window_handle)
            self.visible = False

            ctypes.windll.user32.DestroyWindow(WindowsNotify.window_handle)
            WindowsNotify.window_handle = None

    def _show_notification(self, title, msg, sound, icon):
        """Call windows API to show notification."""

        icon_level = 0
        if icon & WinNotifyLevel.ICON_INFORMATION:
            icon_level |= NIIF_INFO
        elif icon & WinNotifyLevel.ICON_WARNING:
            icon_level |= NIIF_WARNING
        elif icon & WinNotifyLevel.ICON_ERROR:
            icon_level |= NIIF_ERROR

        hwnd = self._get_window()

        if hwnd:
            res = NotifyIconData()
            res.cbSize = ctypes.sizeof(res)
            res.hWnd = hwnd
            res.uID = 0
            # `NIF_SHOWTIP` and `NIF_TIP` is probably not needed for Windows 8+, but maybe for 7?
            res.uFlags = NIF_INFO | NIF_ICON | NIF_STATE | NIF_SHOWTIP | NIF_TIP | NIF_MESSAGE
            res.uCallbackMessage = WM_USER + 20
            res.hIcon = self.hicon
            res.szTip = self.app_name[:128]
            res.uVersion = 4
            res.szInfo = msg[:256]
            res.szInfoTitle = title[:64]
            res.dwInfoFlags = icon_level | NIIF_NOSOUND | NIFF_USER

            if not ctypes.windll.shell32.Shell_NotifyIconW(NIM_MODIFY, ctypes.byref(res)):
                if not self.visible and WindowsNotify.window_handle:
                    ctypes.windll.shell32.Shell_NotifyIconW(NIM_ADD, ctypes.byref(res))
                    ctypes.windll.shell32.Shell_NotifyIconW(NIM_SETVERSION, ctypes.byref(res))
                self.visible = WindowsNotify.window_handle is not None

            if sound:
                alert()

    def destroy(self):
        """Destroy."""

        self._destroy_window()

@staticmethod
def NotifyWin(title, msg, sound, icon, fallback):
    """Notify for windows."""

    Options.instance.show_notification(title, msg, sound, icon, fallback)

def setup(app_name, icon, **kwargs):
    """Setup."""

    sound = kwargs.get('sound')
    if sound is not None and os.path.exists(sound):
        Options.sound = sound

    try:
        if icon is None or not os.path.exists(icon):
            raise ValueError("Icon does not appear to be valid")
    except Exception:
        icon = None

    Options.instance = WindowsNotify(app_name, icon, app_name)
    Options.notify = NotifyWin

def destroy():
    """Destroy."""

    if Options.instance is not None:
        Options.instance.destroy()

    Options.clear()
    Options.notify = notify_win_fallback

def get_notify():
    """Get the notification."""

    return Options.notify

Options.notify = notify_win_fallback
<|endoftext|>


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

"""
Mutliple Read Property

This application has a static list of points that it would like to read.  It reads the
values of each of them in turn and then quits.
"""

from collections import deque

from bacpypes.debugging import bacpypes_debugging, ModuleLogger
from bacpypes.consolelogging import ConfigArgumentParser

from bacpypes.core import run, deferred
from bacpypes.task import RecurringTask

from bacpypes.pdu import Address
from bacpypes.object import get_datatype

from bacpypes.apdu import ReadPropertyRequest, Error, AbortPDU, ReadPropertyACK
from bacpypes.primitivedata import Unsigned
from bacpypes.constructeddata import Array

from bacpypes.app import BIPSimpleApplication
from bacpypes.service.device import LocalDeviceObject

# some debugging
_debug = 0
_log = ModuleLogger(globals())

# point list
point_list = [
    ('1.2.3.4', 'analogValue', 1, 'presentValue'),
    ('1.2.3.4', 'analogValue', 2, 'presentValue'),
    ]

#
#   PrairieDog
#

@bacpypes_debugging
class PrairieDog(BIPSimpleApplication, RecurringTask):

    def __init__(self, interval, *args):
        if _debug: PrairieDog._debug("__init__ %r, %r", interval, args)
        BIPSimpleApplication.__init__(self, *args)
        RecurringTask.__init__(self, interval * 1000)

        # keep track of requests to line up responses
        self._request = None

        # start out idle
        self.is_busy = False
        self.point_queue = deque()
        self.response_values = []

        # install it
        self.install_task()

    def process_task(self):
        if _debug: PrairieDog._debug("process_task")
        global point_list

        # check to see if we're idle
        if self.is_busy:
            if _debug: PrairieDog._debug("    - busy")
            return

        # now we are busy
        self.is_busy = True

        # turn the point list into a queue
        self.point_queue = deque(point_list)

        # clean out the list of the response values
        self.response_values = []

        # fire off the next request
        self.next_request()

    def next_request(self):
        if _debug: PrairieDog._debug("next_request")

        # check to see if we're done
        if not self.point_queue:
            if _debug: PrairieDog._debug("    - done")

            # dump out the results
            for request, response in zip(point_list, self.response_values):
                print(request, response)

            # no longer busy
            self.is_busy = False

            return

        # get the next request
        addr, obj_type, obj_inst, prop_id = self.point_queue.popleft()

        # build a request
        self._request = ReadPropertyRequest(
            objectIdentifier=(obj_type, obj_inst),
            propertyIdentifier=prop_id,
            )
        self._request.pduDestination = Address(addr)
        if _debug: PrairieDog._debug("    - request: %r", self._request)

        # forward it along
        BIPSimpleApplication.request(self, self._request)

    def confirmation(self, apdu):
        if _debug: PrairieDog._debug("confirmation %r", apdu)

        if isinstance(apdu, Error):
            if _debug: PrairieDog._debug("    - error: %r", apdu)
            self.response_values.append(apdu)

        elif isinstance(apdu, AbortPDU):
            if _debug: PrairieDog._debug("    - abort: %r", apdu)
            self.response_values.append(apdu)

        elif (isinstance(self._request, ReadPropertyRequest)) and (isinstance(apdu, ReadPropertyACK)):
            # find the datatype
            datatype = get_datatype(apdu.objectIdentifier[0], apdu.propertyIdentifier)
            if _debug: PrairieDog._debug("    - datatype: %r", datatype)
            if not datatype:
                raise TypeError("unknown datatype")

            # special case for array parts, others are managed by cast_out
            if issubclass(datatype, Array) and (apdu.propertyArrayIndex is not None):
                if apdu.propertyArrayIndex == 0:
                    value = apdu.propertyValue.cast_out(Unsigned)
                else:
                    value = apdu.propertyValue.cast_out(datatype.subtype)
            else:
                value = apdu.propertyValue.cast_out(datatype)
            if _debug: PrairieDog._debug("    - value: %r", value)

            # save the value
            self.response_values.append(value)

        # fire off another request
        deferred(self.next_request)

#
#   __main__
#

def main():
    # parse the command line arguments
    parser = ConfigArgumentParser(description=__doc__)

    # add an argument for interval
    parser.add_argument('interval', type=int,
          help='repeat rate in seconds',
          )

    # now parse the arguments
    args = parser.parse_args()

    if _debug: _log.debug("initialization")
    if _debug: _log.debug("    - args: %r", args)

    # make a device object
    this_device = LocalDeviceObject(
        objectName=args.ini.objectname,
        objectIdentifier=int(args.ini.objectidentifier),
        maxApduLengthAccepted=int(args.ini.maxapdulengthaccepted),
        segmentationSupported=args.ini.segmentationsupported,
        vendorIdentifier=int(args.ini.vendoridentifier),
        )

    # make a dog
    this_application = PrairieDog(args.interval, this_device, args.ini.address)
    if _debug: _log.debug("    - this_application: %r", this_application)

    # get the services supported
    services_supported = this_application.get_services_supported()
    if _debug: _log.debug("    - services_supported: %r", services_supported)

    # let the device object know
    this_device.protocolServicesSupported = services_supported.value

    _log.debug("running")

    run()

    _log.debug("fini")

if __name__ == "__main__":
    main()
<commit_msg>update API<commit_after>#!/usr/bin/env python

"""
Recurring Read Property

This application has a static list of points that it would like to read.  It
reads the values of each of them in turn and then quits.
"""

from collections import deque

from bacpypes.debugging import bacpypes_debugging, ModuleLogger
from bacpypes.consolelogging import ConfigArgumentParser

from bacpypes.core import run, deferred
from bacpypes.task import RecurringTask

from bacpypes.pdu import Address
from bacpypes.object import get_datatype

from bacpypes.apdu import ReadPropertyRequest, Error, AbortPDU, ReadPropertyACK
from bacpypes.primitivedata import Unsigned
from bacpypes.constructeddata import Array

from bacpypes.app import BIPSimpleApplication
from bacpypes.service.device import LocalDeviceObject

# some debugging
_debug = 0
_log = ModuleLogger(globals())

# point list
point_list = [
    ('1.2.3.4', 'analogValue', 1, 'presentValue'),
    ('1.2.3.4', 'analogValue', 2, 'presentValue'),
    ]

#
#   PrairieDog
#

@bacpypes_debugging
class PrairieDog(BIPSimpleApplication, RecurringTask):

    def __init__(self, interval, *args):
        if _debug: PrairieDog._debug("__init__ %r %r", interval, args)
        BIPSimpleApplication.__init__(self, *args)
        RecurringTask.__init__(self, interval * 1000)

        # no longer busy
        self.is_busy = False

        # install the task
        self.install_task()

    def process_task(self):
        if _debug: PrairieDog._debug("process_task")
        global point_list

        # check to see if we're idle
        if self.is_busy:
            if _debug: PrairieDog._debug("    - busy")
            return

        # now we are busy
        self.is_busy = True

        # turn the point list into a queue
        self.point_queue = deque(point_list)

        # clean out the list of the response values
        self.response_values = []

        # fire off the next request
        self.next_request()

    def next_request(self):
        if _debug: PrairieDog._debug("next_request")

        # check to see if we're done
        if not self.point_queue:
            if _debug: PrairieDog._debug("    - done")

            # dump out the results
            for request, response in zip(point_list, self.response_values):
                print(request, response)

            # no longer busy
            self.is_busy = False

            return

        # get the next request
        addr, obj_type, obj_inst, prop_id = self.point_queue.popleft()

        # build a request
        request = ReadPropertyRequest(
            objectIdentifier=(obj_type, obj_inst),
            propertyIdentifier=prop_id,
            )
        request.pduDestination = Address(addr)
        if _debug: PrairieDog._debug("    - request: %r", request)

        # send the request
        iocb = self.request(request)
        if _debug: PrairieDog._debug("    - iocb: %r", iocb)

        # set a callback for the response
        iocb.add_callback(self.complete_request)

    def complete_request(self, iocb):
        if _debug: PrairieDog._debug("complete_request %r", iocb)

        if iocb.ioResponse:
            apdu = iocb.ioResponse

            # find the datatype
            datatype = get_datatype(apdu.objectIdentifier[0], apdu.propertyIdentifier)
            if _debug: PrairieDog._debug("    - datatype: %r", datatype)
            if not datatype:
                raise TypeError("unknown datatype")

            # special case for array parts, others are managed by cast_out
            if issubclass(datatype, Array) and (apdu.propertyArrayIndex is not None):
                if apdu.propertyArrayIndex == 0:
                    value = apdu.propertyValue.cast_out(Unsigned)
                else:
                    value = apdu.propertyValue.cast_out(datatype.subtype)
            else:
                value = apdu.propertyValue.cast_out(datatype)
            if _debug: PrairieDog._debug("    - value: %r", value)

            # save the value
            self.response_values.append(value)

        if iocb.ioError:
            if _debug: PrairieDog._debug("    - error: %r", iocb.ioError)
            self.response_values.append(iocb.ioError)

        # fire off another request
        deferred(self.next_request)

#
#   __main__
#

def main():
    # parse the command line arguments
    parser = ConfigArgumentParser(description=__doc__)

    # add an argument for interval
    parser.add_argument('interval', type=int,
          help='repeat rate in seconds',
          )

    # now parse the arguments
    args = parser.parse_args()

    if _debug: _log.debug("initialization")
    if _debug: _log.debug("    - args: %r", args)

    # make a device object
    this_device = LocalDeviceObject(
        objectName=args.ini.objectname,
        objectIdentifier=int(args.ini.objectidentifier),
        maxApduLengthAccepted=int(args.ini.maxapdulengthaccepted),
        segmentationSupported=args.ini.segmentationsupported,
        vendorIdentifier=int(args.ini.vendoridentifier),
        )

    # make a dog
    this_application = PrairieDog(args.interval, this_device, args.ini.address)
    if _debug: _log.debug("    - this_application: %r", this_application)

    # get the services supported
    services_supported = this_application.get_services_supported()
    if _debug: _log.debug("    - services_supported: %r", services_supported)

    # let the device object know
    this_device.protocolServicesSupported = services_supported.value

    _log.debug("running")

    run()

    _log.debug("fini")

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


<commit_before>import requirements_creation as req
import csv
import json

def do_it_all():

    with open("generate_requirements.csv", 'r') as f_in:
        csv_reader = csv.reader(f_in)

        headers = []
        requirements = []
        i = 0

        for row in csv_reader:
            if i==0:
                headers = row
            else:
                args = tuple(row[:-1])
                newRequirement = req.Requirement(*args)
                requirements.append(newRequirement)

                print "+++++++++++++++++++"
                jsonString = json.dumps(newRequirement.json)
                print jsonString

            i += 1

if __name__ == "__main__":
    do_it_all()<commit_msg>python script to generate a requirements file<commit_after>import os
import requirements_creation as req
import csv
import json
from optparse import OptionParser

def make_requirements_json(csv_path):

    abs_path = os.path.abspath(csv_path)
    f_name = os.path.splitext(os.path.basename(abs_path))[0]

    with open(csv_path, 'r') as f_in:
        csv_reader = csv.reader(f_in)

        top_level_group = req.TopLevelRequirementsGroup(f_name)
        test_bench_groups = {}

        i = 0
        for row in csv_reader:
            if i != 0:

                args = tuple(row[:-1])
                new_requirement = req.Requirement(*args)

                # Check if there is a group for this testbench
                test_bench_name = row[5]
                if test_bench_name not in test_bench_groups:
                    test_bench_groups[test_bench_name] = req.RequirementsGroup(test_bench_name)

                # Add the requirement to the appropriate group
                test_bench_groups[test_bench_name].children[new_requirement.name] = new_requirement

            i += 1

        top_level_group.children = test_bench_groups

        jsonString = top_level_group.json()

        with open(f_name + '.json', 'w') as f_out:
            json.dump(jsonString, f_out)

if __name__ == "__main__":

    parser = OptionParser()
    parser.add_option("--CSVPATH",
                      help='Table of requirements in csv format: '
                           'name, unit,  description, threshold, objective, test_bench, metric_name, group_name')

    (opts, args) = parser.parse_args()

    if opts.CSVPATH:
        make_requirements_json(opts.CSVPATH)<|endoftext|>


<commit_before>"""Build Environment used for isolation during sdist building
"""

import contextlib
import logging
import os
import pathlib
import sys
import textwrap
import zipfile
from collections import OrderedDict
from sysconfig import get_paths
from types import TracebackType
from typing import TYPE_CHECKING, Iterable, Iterator, List, Optional, Set, Tuple, Type

from pip._vendor.certifi import where
from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet

from pip import __file__ as pip_location
from pip._internal.cli.spinners import open_spinner
from pip._internal.locations import get_platlib, get_prefixed_libs, get_purelib
from pip._internal.utils.subprocess import call_subprocess
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds

if TYPE_CHECKING:
    from pip._internal.index.package_finder import PackageFinder

logger = logging.getLogger(__name__)

class _Prefix:

    def __init__(self, path):
        # type: (str) -> None
        self.path = path
        self.setup = False
        self.bin_dir = get_paths(
            'nt' if os.name == 'nt' else 'posix_prefix',
            vars={'base': path, 'platbase': path}
        )['scripts']
        self.lib_dirs = get_prefixed_libs(path)

@contextlib.contextmanager
def _create_standalone_pip() -> Iterator[str]:
    """Create a zip file containing specified pip installation."""
    source = pathlib.Path(pip_location).resolve().parent
    with TempDirectory() as tmp_dir:
        pip_zip = os.path.join(tmp_dir.path, "pip.zip")
        with zipfile.ZipFile(pip_zip, "w") as zf:
            for child in source.rglob("*"):
                arcname = child.relative_to(source.parent)
                zf.write(child, arcname.as_posix())
        yield os.path.join(pip_zip, "pip")

def _install_requirements(
    standalone_pip: str,
    finder: "PackageFinder",
    requirements: Iterable[str],
    prefix: _Prefix,
    message: str,
) -> None:
    args = [
        sys.executable, standalone_pip, 'install',
        '--ignore-installed', '--no-user', '--prefix', prefix.path,
        '--cert', where(), '--no-warn-script-location',
    ]  # type: List[str]
    if logger.getEffectiveLevel() <= logging.DEBUG:
        args.append('-v')
    for format_control in ('no_binary', 'only_binary'):
        formats = getattr(finder.format_control, format_control)
        args += [
            '--' + format_control.replace('_', '-'),
            ','.join(sorted(formats or {':none:'}))
        ]
    index_urls = finder.index_urls
    if index_urls:
        args.extend(['-i', index_urls[0]])
        for extra_index in index_urls[1:]:
            args.extend(['--extra-index-url', extra_index])
    else:
        args.append('--no-index')
    for link in finder.find_links:
        args.extend(['--find-links', link])
    for host in finder.trusted_hosts:
        args.extend(['--trusted-host', host])
    if finder.allow_all_prereleases:
        args.append('--pre')
    if finder.prefer_binary:
        args.append('--prefer-binary')
    args.append('--')
    args.extend(requirements)
    with open_spinner(message) as spinner:
        call_subprocess(args, spinner=spinner)

class BuildEnvironment:
    """Creates and manages an isolated environment to install build deps
    """

    def __init__(self):
        # type: () -> None
        temp_dir = TempDirectory(
            kind=tempdir_kinds.BUILD_ENV, globally_managed=True
        )

        self._prefixes = OrderedDict(
            (name, _Prefix(os.path.join(temp_dir.path, name)))
            for name in ('normal', 'overlay')
        )

        self._bin_dirs = []  # type: List[str]
        self._lib_dirs = []  # type: List[str]
        for prefix in reversed(list(self._prefixes.values())):
            self._bin_dirs.append(prefix.bin_dir)
            self._lib_dirs.extend(prefix.lib_dirs)

        # Customize site to:
        # - ensure .pth files are honored
        # - prevent access to system site packages
        system_sites = {
            os.path.normcase(site) for site in (get_purelib(), get_platlib())
        }
        self._site_dir = os.path.join(temp_dir.path, 'site')
        if not os.path.exists(self._site_dir):
            os.mkdir(self._site_dir)
        with open(os.path.join(self._site_dir, 'sitecustomize.py'), 'w') as fp:
            fp.write(textwrap.dedent(
                '''
                import os, site, sys

                # First, drop system-sites related paths.
                original_sys_path = sys.path[:]
                known_paths = set()
                for path in {system_sites!r}:
                    site.addsitedir(path, known_paths=known_paths)
                system_paths = set(
                    os.path.normcase(path)
                    for path in sys.path[len(original_sys_path):]
                )
                original_sys_path = [
                    path for path in original_sys_path
                    if os.path.normcase(path) not in system_paths
                ]
                sys.path = original_sys_path

                # Second, add lib directories.
                # ensuring .pth file are processed.
                for path in {lib_dirs!r}:
                    assert not path in sys.path
                    site.addsitedir(path)
                '''
            ).format(system_sites=system_sites, lib_dirs=self._lib_dirs))

    def __enter__(self):
        # type: () -> None
        self._save_env = {
            name: os.environ.get(name, None)
            for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH')
        }

        path = self._bin_dirs[:]
        old_path = self._save_env['PATH']
        if old_path:
            path.extend(old_path.split(os.pathsep))

        pythonpath = [self._site_dir]

        os.environ.update({
            'PATH': os.pathsep.join(path),
            'PYTHONNOUSERSITE': '1',
            'PYTHONPATH': os.pathsep.join(pythonpath),
        })

    def __exit__(
        self,
        exc_type,  # type: Optional[Type[BaseException]]
        exc_val,  # type: Optional[BaseException]
        exc_tb  # type: Optional[TracebackType]
    ):
        # type: (...) -> None
        for varname, old_value in self._save_env.items():
            if old_value is None:
                os.environ.pop(varname, None)
            else:
                os.environ[varname] = old_value

    def check_requirements(self, reqs):
        # type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]]
        """Return 2 sets:
            - conflicting requirements: set of (installed, wanted) reqs tuples
            - missing requirements: set of reqs
        """
        missing = set()
        conflicting = set()
        if reqs:
            ws = WorkingSet(self._lib_dirs)
            for req in reqs:
                try:
                    if ws.find(Requirement.parse(req)) is None:
                        missing.add(req)
                except VersionConflict as e:
                    conflicting.add((str(e.args[0].as_requirement()),
                                     str(e.args[1])))
        return conflicting, missing

    def install_requirements(
        self,
        finder,  # type: PackageFinder
        requirements,  # type: Iterable[str]
        prefix_as_string,  # type: str
        message  # type: str
    ):
        # type: (...) -> None
        prefix = self._prefixes[prefix_as_string]
        assert not prefix.setup
        prefix.setup = True
        if not requirements:
            return
        with _create_standalone_pip() as standalone_pip:
            _install_requirements(
                standalone_pip,
                finder,
                requirements,
                prefix,
                message,
            )

class NoOpBuildEnvironment(BuildEnvironment):
    """A no-op drop-in replacement for BuildEnvironment
    """

    def __init__(self):
        # type: () -> None
        pass

    def __enter__(self):
        # type: () -> None
        pass

    def __exit__(
        self,
        exc_type,  # type: Optional[Type[BaseException]]
        exc_val,  # type: Optional[BaseException]
        exc_tb  # type: Optional[TracebackType]
    ):
        # type: (...) -> None
        pass

    def cleanup(self):
        # type: () -> None
        pass

    def install_requirements(
        self,
        finder,  # type: PackageFinder
        requirements,  # type: Iterable[str]
        prefix_as_string,  # type: str
        message  # type: str
    ):
        # type: (...) -> None
        raise NotImplementedError()
<commit_msg>Better name temp directory<commit_after>"""Build Environment used for isolation during sdist building
"""

import contextlib
import logging
import os
import pathlib
import sys
import textwrap
import zipfile
from collections import OrderedDict
from sysconfig import get_paths
from types import TracebackType
from typing import TYPE_CHECKING, Iterable, Iterator, List, Optional, Set, Tuple, Type

from pip._vendor.certifi import where
from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet

from pip import __file__ as pip_location
from pip._internal.cli.spinners import open_spinner
from pip._internal.locations import get_platlib, get_prefixed_libs, get_purelib
from pip._internal.utils.subprocess import call_subprocess
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds

if TYPE_CHECKING:
    from pip._internal.index.package_finder import PackageFinder

logger = logging.getLogger(__name__)

class _Prefix:

    def __init__(self, path):
        # type: (str) -> None
        self.path = path
        self.setup = False
        self.bin_dir = get_paths(
            'nt' if os.name == 'nt' else 'posix_prefix',
            vars={'base': path, 'platbase': path}
        )['scripts']
        self.lib_dirs = get_prefixed_libs(path)

@contextlib.contextmanager
def _create_standalone_pip() -> Iterator[str]:
    """Create a zip file containing specified pip installation."""
    source = pathlib.Path(pip_location).resolve().parent
    with TempDirectory(kind="standalone-pip") as tmp_dir:
        pip_zip = os.path.join(tmp_dir.path, "pip.zip")
        with zipfile.ZipFile(pip_zip, "w") as zf:
            for child in source.rglob("*"):
                arcname = child.relative_to(source.parent)
                zf.write(child, arcname.as_posix())
        yield os.path.join(pip_zip, "pip")

def _install_requirements(
    standalone_pip: str,
    finder: "PackageFinder",
    requirements: Iterable[str],
    prefix: _Prefix,
    message: str,
) -> None:
    args = [
        sys.executable, standalone_pip, 'install',
        '--ignore-installed', '--no-user', '--prefix', prefix.path,
        '--cert', where(), '--no-warn-script-location',
    ]  # type: List[str]
    if logger.getEffectiveLevel() <= logging.DEBUG:
        args.append('-v')
    for format_control in ('no_binary', 'only_binary'):
        formats = getattr(finder.format_control, format_control)
        args += [
            '--' + format_control.replace('_', '-'),
            ','.join(sorted(formats or {':none:'}))
        ]
    index_urls = finder.index_urls
    if index_urls:
        args.extend(['-i', index_urls[0]])
        for extra_index in index_urls[1:]:
            args.extend(['--extra-index-url', extra_index])
    else:
        args.append('--no-index')
    for link in finder.find_links:
        args.extend(['--find-links', link])
    for host in finder.trusted_hosts:
        args.extend(['--trusted-host', host])
    if finder.allow_all_prereleases:
        args.append('--pre')
    if finder.prefer_binary:
        args.append('--prefer-binary')
    args.append('--')
    args.extend(requirements)
    with open_spinner(message) as spinner:
        call_subprocess(args, spinner=spinner)

class BuildEnvironment:
    """Creates and manages an isolated environment to install build deps
    """

    def __init__(self):
        # type: () -> None
        temp_dir = TempDirectory(
            kind=tempdir_kinds.BUILD_ENV, globally_managed=True
        )

        self._prefixes = OrderedDict(
            (name, _Prefix(os.path.join(temp_dir.path, name)))
            for name in ('normal', 'overlay')
        )

        self._bin_dirs = []  # type: List[str]
        self._lib_dirs = []  # type: List[str]
        for prefix in reversed(list(self._prefixes.values())):
            self._bin_dirs.append(prefix.bin_dir)
            self._lib_dirs.extend(prefix.lib_dirs)

        # Customize site to:
        # - ensure .pth files are honored
        # - prevent access to system site packages
        system_sites = {
            os.path.normcase(site) for site in (get_purelib(), get_platlib())
        }
        self._site_dir = os.path.join(temp_dir.path, 'site')
        if not os.path.exists(self._site_dir):
            os.mkdir(self._site_dir)
        with open(os.path.join(self._site_dir, 'sitecustomize.py'), 'w') as fp:
            fp.write(textwrap.dedent(
                '''
                import os, site, sys

                # First, drop system-sites related paths.
                original_sys_path = sys.path[:]
                known_paths = set()
                for path in {system_sites!r}:
                    site.addsitedir(path, known_paths=known_paths)
                system_paths = set(
                    os.path.normcase(path)
                    for path in sys.path[len(original_sys_path):]
                )
                original_sys_path = [
                    path for path in original_sys_path
                    if os.path.normcase(path) not in system_paths
                ]
                sys.path = original_sys_path

                # Second, add lib directories.
                # ensuring .pth file are processed.
                for path in {lib_dirs!r}:
                    assert not path in sys.path
                    site.addsitedir(path)
                '''
            ).format(system_sites=system_sites, lib_dirs=self._lib_dirs))

    def __enter__(self):
        # type: () -> None
        self._save_env = {
            name: os.environ.get(name, None)
            for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH')
        }

        path = self._bin_dirs[:]
        old_path = self._save_env['PATH']
        if old_path:
            path.extend(old_path.split(os.pathsep))

        pythonpath = [self._site_dir]

        os.environ.update({
            'PATH': os.pathsep.join(path),
            'PYTHONNOUSERSITE': '1',
            'PYTHONPATH': os.pathsep.join(pythonpath),
        })

    def __exit__(
        self,
        exc_type,  # type: Optional[Type[BaseException]]
        exc_val,  # type: Optional[BaseException]
        exc_tb  # type: Optional[TracebackType]
    ):
        # type: (...) -> None
        for varname, old_value in self._save_env.items():
            if old_value is None:
                os.environ.pop(varname, None)
            else:
                os.environ[varname] = old_value

    def check_requirements(self, reqs):
        # type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]]
        """Return 2 sets:
            - conflicting requirements: set of (installed, wanted) reqs tuples
            - missing requirements: set of reqs
        """
        missing = set()
        conflicting = set()
        if reqs:
            ws = WorkingSet(self._lib_dirs)
            for req in reqs:
                try:
                    if ws.find(Requirement.parse(req)) is None:
                        missing.add(req)
                except VersionConflict as e:
                    conflicting.add((str(e.args[0].as_requirement()),
                                     str(e.args[1])))
        return conflicting, missing

    def install_requirements(
        self,
        finder,  # type: PackageFinder
        requirements,  # type: Iterable[str]
        prefix_as_string,  # type: str
        message  # type: str
    ):
        # type: (...) -> None
        prefix = self._prefixes[prefix_as_string]
        assert not prefix.setup
        prefix.setup = True
        if not requirements:
            return
        with _create_standalone_pip() as standalone_pip:
            _install_requirements(
                standalone_pip,
                finder,
                requirements,
                prefix,
                message,
            )

class NoOpBuildEnvironment(BuildEnvironment):
    """A no-op drop-in replacement for BuildEnvironment
    """

    def __init__(self):
        # type: () -> None
        pass

    def __enter__(self):
        # type: () -> None
        pass

    def __exit__(
        self,
        exc_type,  # type: Optional[Type[BaseException]]
        exc_val,  # type: Optional[BaseException]
        exc_tb  # type: Optional[TracebackType]
    ):
        # type: (...) -> None
        pass

    def cleanup(self):
        # type: () -> None
        pass

    def install_requirements(
        self,
        finder,  # type: PackageFinder
        requirements,  # type: Iterable[str]
        prefix_as_string,  # type: str
        message  # type: str
    ):
        # type: (...) -> None
        raise NotImplementedError()
<|endoftext|>


<commit_before># Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Set of utilities to add commands to a buildbot factory.

This is based on commands.py and adds swarm-specific commands."""

from buildbot.process.properties import WithProperties
from buildbot.steps import shell

from master.factory import commands
from master.log_parser import gtest_command

class SwarmCommands(commands.FactoryCommands):
  """Encapsulates methods to add swarm commands to a buildbot factory"""

  def AddTriggerSwarmTestStep(self, target_platform, swarm_server, data_server,
                              hashtable_dir, data_dest_dir,
                              min_shards, max_shards,
                              manifest_files):
    script_path = self.PathJoin(self._script_dir, 'run_slavelastic.py')

    swarm_request_name_prefix = WithProperties('%s-%s-',
                                               'buildername:-None',
                                               'buildnumber:-None')

    command = [self._python, script_path, '-m', min_shards, '-s', max_shards,
               '-o', target_platform, '-u', swarm_server, '-d', data_server,
               '--hashtable_dir', hashtable_dir,
               '--data-dest-dir', data_dest_dir,
               '-t', swarm_request_name_prefix]
    command.extend(manifest_files)

    self.AddTestStep(shell.ShellCommand, 'trigger_swarm_tests', command)

  def AddGetSwarmTestStep(self, swarm_server, test_name):
    script_path = self.PathJoin(self._script_dir, 'get_swarm_results.py')

    swarm_request_name = WithProperties('%s-%s-' + test_name,
                                        'buildername:-None',
                                        'buildnumber:-None')

    command = [self._python, script_path, '-u', swarm_server,
               swarm_request_name]

    self.AddTestStep(gtest_command.GTestCommand,
                     '%s_swarm' % test_name,
                     command)
<commit_msg>Fix Swarm Command Argument<commit_after># Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""Set of utilities to add commands to a buildbot factory.

This is based on commands.py and adds swarm-specific commands."""

from buildbot.process.properties import WithProperties
from buildbot.steps import shell

from master.factory import commands
from master.log_parser import gtest_command

class SwarmCommands(commands.FactoryCommands):
  """Encapsulates methods to add swarm commands to a buildbot factory"""

  def AddTriggerSwarmTestStep(self, target_platform, swarm_server, data_server,
                              hashtable_dir, data_dest_dir,
                              min_shards, max_shards,
                              manifest_files):
    script_path = self.PathJoin(self._script_dir, 'run_slavelastic.py')

    swarm_request_name_prefix = WithProperties('%s-%s-',
                                               'buildername:-None',
                                               'buildnumber:-None')

    command = [self._python, script_path, '-m', min_shards, '-s', max_shards,
               '-o', target_platform, '-u', swarm_server, '-d', data_server,
               '--hashtable-dir', hashtable_dir,
               '--data-dest-dir', data_dest_dir,
               '-t', swarm_request_name_prefix]
    command.extend(manifest_files)

    self.AddTestStep(shell.ShellCommand, 'trigger_swarm_tests', command)

  def AddGetSwarmTestStep(self, swarm_server, test_name):
    script_path = self.PathJoin(self._script_dir, 'get_swarm_results.py')

    swarm_request_name = WithProperties('%s-%s-' + test_name,
                                        'buildername:-None',
                                        'buildnumber:-None')

    command = [self._python, script_path, '-u', swarm_server,
               swarm_request_name]

    self.AddTestStep(gtest_command.GTestCommand,
                     '%s_swarm' % test_name,
                     command)
<|endoftext|>


<commit_before>#!/usr/bin/python
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""A tool to package a checkout's source and upload it to Google Storage."""

import os
import re
import sys

from common import chromium_utils
from slave import slave_utils

FILENAME = 'chromium-src.tgz'
GSBASE = 'gs://chromium-browser-csindex'

def main(argv):
  if not os.path.exists('src'):
    raise Exception('ERROR: no src directory to package, exiting')

  chromium_utils.RunCommand(['rm', '-f', FILENAME])
  if os.path.exists(FILENAME):
    raise Exception('ERROR: %s cannot be removed, exiting' % FILENAME)

  if chromium_utils.RunCommand(['tar', 'czvf', FILENAME, '--exclude=.svn',
                                'src/']) != 0:
    raise Exception('ERROR: failed to create %s, exiting' % FILENAME)

  status = slave_utils.GSUtilCopyFile(FILENAME, GSBASE)
  if status != 0:
    raise Exception('ERROR: GSUtilCopyFile error %d. "%s" -> "%s"' % (
        status, FILENAME, GSBASE))

  (status, output) = slave_utils.GSUtilListBucket(GSBASE)
  if status != 0:
    raise Exception('ERROR: failed to get list of GSBASE, exiting' % GSBASE)

  regex = re.compile('\s*\d+\s+([-:\w]+)\s+%s/%s\n' % (GSBASE, FILENAME))
  match_data = regex.match(output)
  modified_time = None
  if match_data:
    modified_time = match_data.group(1)
  if not modified_time:
    raise Exception('ERROR: could not get modified_time, exiting')
  print 'Last modified time: %s' % modified_time

  return 0

if '__main__' == __name__:
  sys.exit(main(None))
<commit_msg>Also package o3d and tools directories<commit_after>#!/usr/bin/python
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""A tool to package a checkout's source and upload it to Google Storage."""

import os
import re
import sys

from common import chromium_utils
from slave import slave_utils

FILENAME = 'chromium-src.tgz'
GSBASE = 'gs://chromium-browser-csindex'

def main(argv):
  if not os.path.exists('src'):
    raise Exception('ERROR: no src directory to package, exiting')

  chromium_utils.RunCommand(['rm', '-f', FILENAME])
  if os.path.exists(FILENAME):
    raise Exception('ERROR: %s cannot be removed, exiting' % FILENAME)

  if chromium_utils.RunCommand(['tar', 'czvf', FILENAME, '--exclude=.svn',
                                'src/', 'tools/', 'o3d/']) != 0:
    raise Exception('ERROR: failed to create %s, exiting' % FILENAME)

  status = slave_utils.GSUtilCopyFile(FILENAME, GSBASE)
  if status != 0:
    raise Exception('ERROR: GSUtilCopyFile error %d. "%s" -> "%s"' % (
        status, FILENAME, GSBASE))

  (status, output) = slave_utils.GSUtilListBucket(GSBASE)
  if status != 0:
    raise Exception('ERROR: failed to get list of GSBASE, exiting' % GSBASE)

  regex = re.compile('\s*\d+\s+([-:\w]+)\s+%s/%s\n' % (GSBASE, FILENAME))
  match_data = regex.match(output)
  modified_time = None
  if match_data:
    modified_time = match_data.group(1)
  if not modified_time:
    raise Exception('ERROR: could not get modified_time, exiting')
  print 'Last modified time: %s' % modified_time

  return 0

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


<commit_before>#!/usr/bin/python
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""A tool to package a checkout's source and upload it to Google Storage."""

import os
import re
import sys

from common import chromium_utils
from slave import slave_utils

FILENAME = 'chromium-src.tgz'
GSBASE = 'gs://chromium-browser-csindex'

def main(argv):
  if not os.path.exists('src'):
    raise Exception('ERROR: no src directory to package, exiting')

  chromium_utils.RunCommand(['rm', '-f', FILENAME])
  if os.path.exists(FILENAME):
    raise Exception('ERROR: %s cannot be removed, exiting' % FILENAME)

  if chromium_utils.RunCommand(['tar', 'czvf', FILENAME, '--exclude=.svn',
                                'src/', 'tools/', 'o3d/']) != 0:
    raise Exception('ERROR: failed to create %s, exiting' % FILENAME)

  status = slave_utils.GSUtilCopyFile(FILENAME, GSBASE)
  if status != 0:
    raise Exception('ERROR: GSUtilCopyFile error %d. "%s" -> "%s"' % (
        status, FILENAME, GSBASE))

  (status, output) = slave_utils.GSUtilListBucket(GSBASE)
  if status != 0:
    raise Exception('ERROR: failed to get list of GSBASE, exiting' % GSBASE)

  regex = re.compile('\s*\d+\s+([-:\w]+)\s+%s/%s\n' % (GSBASE, FILENAME))
  match_data = regex.match(output)
  modified_time = None
  if match_data:
    modified_time = match_data.group(1)
  if not modified_time:
    raise Exception('ERROR: could not get modified_time, exiting')
  print 'Last modified time: %s' % modified_time

  return 0

if '__main__' == __name__:
  sys.exit(main(None))
<commit_msg>Use bzip2 instead of gzip to package chromium sources for codesearch<commit_after>#!/usr/bin/python
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""A tool to package a checkout's source and upload it to Google Storage."""

import os
import re
import sys

from common import chromium_utils
from slave import slave_utils

FILENAME = 'chromium-src.tar.bz2'
GSBASE = 'gs://chromium-browser-csindex'

def main(argv):
  if not os.path.exists('src'):
    raise Exception('ERROR: no src directory to package, exiting')

  chromium_utils.RunCommand(['rm', '-f', FILENAME])
  if os.path.exists(FILENAME):
    raise Exception('ERROR: %s cannot be removed, exiting' % FILENAME)

  if chromium_utils.RunCommand(['tar', 'cjvf', FILENAME, '--exclude=.svn',
                                'src/', 'tools/', 'o3d/']) != 0:
    raise Exception('ERROR: failed to create %s, exiting' % FILENAME)

  status = slave_utils.GSUtilCopyFile(FILENAME, GSBASE)
  if status != 0:
    raise Exception('ERROR: GSUtilCopyFile error %d. "%s" -> "%s"' % (
        status, FILENAME, GSBASE))

  (status, output) = slave_utils.GSUtilListBucket(GSBASE)
  if status != 0:
    raise Exception('ERROR: failed to get list of GSBASE, exiting' % GSBASE)

  regex = re.compile('\s*\d+\s+([-:\w]+)\s+%s/%s\n' % (GSBASE, FILENAME))
  match_data = regex.match(output)
  modified_time = None
  if match_data:
    modified_time = match_data.group(1)
  if not modified_time:
    raise Exception('ERROR: could not get modified_time, exiting')
  print 'Last modified time: %s' % modified_time

  return 0

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


<commit_before>import os
import re
import subprocess
import webbrowser

import click

ENTRYPOINTS = 'powershift_cli_plugins'

def server_url():
    # XXX This is only available from Origin 1.4 onwards.
    # command = ['oc', 'whoami', '--show-server']
    # url = subprocess.check_output(command, universal_newlines=True)
    # url = url.strip()

    command = ['oc', 'config', 'view', '--minify', '-o',
            'jsonpath="{.clusters[*].cluster.server}"']

    url = subprocess.check_output(command, universal_newlines=True)
    url = re.sub(r'^\s*"(.*)"\s*$', r'\1', url)

    return url

def server_context():
    command = ['oc', 'whoami', '--show-context']

    context = subprocess.check_output(command, universal_newlines=True)
    context = context.strip()

    return context

def server_token():
    command = ['oc', 'whoami', '--show-token']

    token = subprocess.check_output(command, universal_newlines=True)
    token = token.strip()

    return token

@click.group()
@click.pass_context
def root(ctx):
    """
    PowerShift client for OpenShift.

    This client provides additional functionality useful to users of the
    OpenShift platform. Base functionality is minimal, but can be extended
    by installing additional plugins.

    For more details see:

        https://github.com/getwarped/powershift

    """

@root.command()
def console():
    """
    Open a browser on the OpenShift web console.

    """

    webbrowser.open(server_url())

@root.command()
def server():
    """
    Displays the URL for the OpenShift cluster.

    """

    click.echo(server_url())

@root.group()
def completion():
    """
    Output completion script for specified shell.

    """

    pass

@completion.command()
def bash():
    """
    Output shell completion code for 'bash'.

    To generate the completion code and enable it use:

    \b
        powershift completion bash > powershift-complete.sh
        source powershift-complete.sh

    """

    directory = os.path.dirname(__file__)
    script = os.path.join(directory, 'completion-bash.sh')
    with open(script, encoding='UTF-8') as fp:
        click.echo(fp.read())

def main():
    # Import any plugins for extending the available commands. They
    # should automatically register themselves against the appropriate
    # CLI command group.

    try:
        import pkg_resources
    except ImportError:
        pass
    else:
        entrypoints = pkg_resources.iter_entry_points(group=ENTRYPOINTS)

        for entrypoint in entrypoints:
            __import__(entrypoint.module_name)

    # Call the CLI to process the command line arguments and execute
    # the appropriate action.

    root(obj={})

if __name__ == '__main__':
    main()
<commit_msg>Need to use short options for older OpenShift versions.<commit_after>import os
import re
import subprocess
import webbrowser

import click

ENTRYPOINTS = 'powershift_cli_plugins'

def server_url():
    # XXX This is only available from Origin 1.4 onwards.
    # command = ['oc', 'whoami', '--show-server']
    # url = subprocess.check_output(command, universal_newlines=True)
    # url = url.strip()

    command = ['oc', 'config', 'view', '--minify', '-o',
            'jsonpath="{.clusters[*].cluster.server}"']

    url = subprocess.check_output(command, universal_newlines=True)
    url = re.sub(r'^\s*"(.*)"\s*$', r'\1', url)

    return url

def server_context():
    command = ['oc', 'whoami', '-c']

    context = subprocess.check_output(command, universal_newlines=True)
    context = context.strip()

    return context

def server_token():
    command = ['oc', 'whoami', '-t']

    token = subprocess.check_output(command, universal_newlines=True)
    token = token.strip()

    return token

@click.group()
@click.pass_context
def root(ctx):
    """
    PowerShift client for OpenShift.

    This client provides additional functionality useful to users of the
    OpenShift platform. Base functionality is minimal, but can be extended
    by installing additional plugins.

    For more details see:

        https://github.com/getwarped/powershift

    """

@root.command()
def console():
    """
    Open a browser on the OpenShift web console.

    """

    webbrowser.open(server_url())

@root.command()
def server():
    """
    Displays the URL for the OpenShift cluster.

    """

    click.echo(server_url())

@root.group()
def completion():
    """
    Output completion script for specified shell.

    """

    pass

@completion.command()
def bash():
    """
    Output shell completion code for 'bash'.

    To generate the completion code and enable it use:

    \b
        powershift completion bash > powershift-complete.sh
        source powershift-complete.sh

    """

    directory = os.path.dirname(__file__)
    script = os.path.join(directory, 'completion-bash.sh')
    with open(script, encoding='UTF-8') as fp:
        click.echo(fp.read())

def main():
    # Import any plugins for extending the available commands. They
    # should automatically register themselves against the appropriate
    # CLI command group.

    try:
        import pkg_resources
    except ImportError:
        pass
    else:
        entrypoints = pkg_resources.iter_entry_points(group=ENTRYPOINTS)

        for entrypoint in entrypoints:
            __import__(entrypoint.module_name)

    # Call the CLI to process the command line arguments and execute
    # the appropriate action.

    root(obj={})

if __name__ == '__main__':
    main()
<|endoftext|>