<commit_before>import pygame
import random
from constants import *

class Screen:

    """
    Class that controls the screen. This class is responsible for
    drawing to the screen
    """

    def __init__(self):
        # Screen elements
        self.screen = pygame.display.set_mode((SCREEN_HEIGHT, SCREEN_WIDTH))
        pygame.display.set_caption("Minesweeper Pre-Alpha")
        self.__initial_draw()

    def draw_grid(self, click_grid, color_grid):
        for row in range(0, ROWS):
            for column in range(0, COLUMNS):
                # Only draw to the screen if the block is marked
                # as to-draw
                if click_grid[row][column] == 1:
                    pygame.draw.rect(self.screen, color_grid[row][column],
                                    (column * GRID_WIDTH + (column + 1) * MARGIN,
                                     row * GRID_HEIGHT + (row + 1) * MARGIN,
                                     GRID_WIDTH,
                                     GRID_HEIGHT))

    def __initial_draw(self):
        """
        Draw initial game board. All blocks should initially be
        white
        """
        for row in range(0, ROWS):
            for column in range(0, COLUMNS):
                pygame.draw.rect(self.screen, WHITE,
                                (column * GRID_WIDTH + (column + 1) * MARGIN,
                                 row * GRID_HEIGHT + (row + 1) * MARGIN,
                                 GRID_WIDTH,
                                 GRID_HEIGHT))

class Game:

    """
    This class holds all the game elements. It renders the game and
    controls user input.
    """

    def __init__(self):
        """
        Sets up the initial game state, and starts the game
        """
        self.mine_grid = self.generate_mine_grid()
        self.mine_neighbor_grid = self.get_mine_neighbor_grid(self.mine_grid)
        self.color_grid = self.get_color_grid(
            self.mine_grid,
            self.mine_neighbor_grid)

        self.pygame_initialize()
        self.clock = pygame.time.Clock()
        self.game_screen = Screen()
        self.main_loop()

    def pygame_initialize(self):
        """
        Initializes all pygame-related things. Put font initialization
        here.
        """
        pygame.init()

    def generate_mine_grid(self):
        """
        Creates a randomly generated grid of mines.
        Ideally, this should happen after the first click by the user.
        """
        mine_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]
        laid_mines = 0
        assert(MINES < ROWS * COLUMNS)

        # Generate mines randomly.
        while laid_mines < MINES:
            row = random.randrange(0, ROWS)
            column = random.randrange(0, COLUMNS)
            if mine_grid[row][column] == 0:
                mine_grid[row][column] = 1
                laid_mines += 1

        return mine_grid

    def get_mine_neighbor_grid(self, mine_grid):
        """
        Creates the grid that holds how many mine-neighbors each space
        has. In the original, this is the number that is displayed on
        the block after they have been clicked.
        """
        mine_neighbor_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]
        for row in range(ROWS):
            for column in range(COLUMNS):
                mine_neighbor_grid[row][
                    column] = self.__count_mine_neighbors(row, column, mine_grid)

        return mine_neighbor_grid

    def get_color_grid(self, mine_grid, mine_neighbor_grid):
        """
        Creates a ROWS by COLUMNS grid that holds what color each
        block should be. This is based on the amount of mine-neighbors
        each block has.
        """
        color_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]
        for row in range(ROWS):
            for column in range(COLUMNS):
                if mine_grid[row][column] == 1:
                    color_grid[row][column] = RED
                elif mine_neighbor_grid[row][column] == 0:
                    color_grid[row][column] = BLUE
                elif mine_neighbor_grid[row][column] == 1:
                    color_grid[row][column] = CYAN
                elif mine_neighbor_grid[row][column] == 2:
                    color_grid[row][column] = DARKGREEN
                elif mine_neighbor_grid[row][column] == 3:
                    color_grid[row][column] = GREEN
                elif mine_neighbor_grid[row][column] == 4:
                    color_grid[row][column] = LITEGREEN
                elif mine_neighbor_grid[row][column] == 5:
                    color_grid[row][column] = PURPLE
                elif mine_neighbor_grid[row][column] == 6:
                    color_grid[row][column] = PINK
                elif mine_neighbor_grid[row][column] == 7:
                    color_grid[row][column] = YELLOW
                elif mine_neighbor_grid[row][column] == 8:
                    color_grid[row][column] = ORANGE

        return color_grid

    def game_over(self):
        """
        This controls what happens when the user clicks on a mine.
        """
        self.game_screen.screen.fill(BLACK)

        font = pygame.font.SysFont('Ubuntu', 24, True, False)
        text = font.render("Congraturaisins!", True, PURPLE)
        self.game_screen.screen.blit(text, [SCREEN_WIDTH // 7, 5])

        text = font.render("You lose!", True, WHITE)
        self.game_screen.screen.blit(text, [SCREEN_WIDTH // 3, 100])

    def main_loop(self):
        """
        This is the main loop of the program. It draws to the screen
        at appropriate times and controls the events of the game.
        """
        done = False

        # Variable to be used to check whether the game needs to be
        # re-drawn
        new_click = False
        game_over = False

        # This grid changes during gameplay, so I initialize it in
        # the main game loop
        click_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]

        while not done:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = True
                if event.type == pygame.MOUSEBUTTONDOWN and not game_over:
                    mouse_pos = self.mouse_down(click_grid, game_over)
                    new_click = True

            # If the user has clicked since the last iteration, handle
            # the event, check the game over status, and
            # redraw the screen.
            if new_click:
                # Get the row and column of the block clicked
                row_clicked, column_clicked = self.find_row_and_column_clicked(
                    mouse_pos)
                click_grid, game_over = self.click_block_event(
                    row_clicked, column_clicked, click_grid, game_over)
                self.game_screen.draw_grid(click_grid, self.color_grid)
                new_click = False

            elif game_over:
                self.game_over()

            # Update the screen with what is drawn.
            pygame.display.flip()

            self.clock.tick(60)

    def mouse_down(self, click_grid, game_over):
        """
        Update the click_grid list when the user clicks a grid.
        """
        pos = pygame.mouse.get_pos()
        return pos

    def find_row_and_column_clicked(self, mouse_pos):
        """
        Returns row and column from mouse click position
        """

        # Find the row and column the user clicked on.
        column_clicked = mouse_pos[0] // (GRID_WIDTH + MARGIN)
        row_clicked = mouse_pos[1] // (GRID_HEIGHT + MARGIN)

        # If the user clicks below the final row, count it as the final row.
        if row_clicked >= ROWS:
            row_clicked = ROWS - 1
        if column_clicked >= COLUMNS:
            column_clicked = COLUMNS - 1

        return row_clicked, column_clicked

    def click_block_event(
        self,
        row_clicked,
        column_clicked,
        click_grid,
            game_over):
        """
        Handles what occurs when a row and column are clicked.
        Returns the updated click_grid and the game_over variable.
        """
        click_grid[row_clicked][column_clicked] = 1

        # End the game if the user has clicked on a mine
        if self.mine_grid[row_clicked][column_clicked] == 1:
            game_over = True

        # Reveal the neighbors of the clicked block
        elif self.mine_neighbor_grid[row_clicked][column_clicked] == 0:
            self.__reveal_neighbors(
                row_clicked,
                column_clicked,
                click_grid,
                self.mine_neighbor_grid)

        return click_grid, game_over

    def __count_mine_neighbors(self, row, column, mine_grid):
        mine_neighbor_count = 0

        # Check whether the block is on an edge.
        left = row >= 1
        right = row < ROWS - 1
        up = column >= 1
        down = column < COLUMNS - 1

        # Check left, up-left, and down-left for mines.
        if left:
            if mine_grid[row - 1][column] == 1:
                mine_neighbor_count += 1
            if up and mine_grid[row - 1][column - 1] == 1:
                mine_neighbor_count += 1
            if down and mine_grid[row - 1][column + 1] == 1:
                mine_neighbor_count += 1

        # Check right, up-right, and down-right for mines.
        if right:
            if mine_grid[row + 1][column] == 1:
                mine_neighbor_count += 1
            if up and mine_grid[row + 1][column - 1] == 1:
                mine_neighbor_count += 1
            if down and mine_grid[row + 1][column + 1] == 1:
                mine_neighbor_count += 1

        # Check up and down for mines.
        if up and mine_grid[row][column - 1] == 1:
            mine_neighbor_count += 1
        if down and mine_grid[row][column + 1] == 1:
            mine_neighbor_count += 1

        return mine_neighbor_count

    def __reveal_neighbors(self, row, column, click_grid, mine_neighbor_grid):
        """
        Reveals all blocks next to a input block if the block has no
        mine-neighbors. If the block has no mine-neighbors,
        """
        assert mine_neighbor_grid[row][column] == 0

        on_top_border = row == 0
        on_bottom_border = row == ROWS - 1
        on_left_border = column == 0
        on_right_border = column == COLUMNS - 1

        # If statements are necessary to prevent an out of range error.
        if not on_right_border:
            neighborless_right = mine_neighbor_grid[row][column + 1] == 0
            clicked_right = click_grid[row][column + 1] == 1
            click_grid[row][column + 1] = 1
        if not on_top_border:
            neighborless_up = mine_neighbor_grid[row - 1][column] == 0
            clicked_up = click_grid[row - 1][column] == 1
            click_grid[row - 1][column] = 1
        if not on_bottom_border:
            neighborless_down = mine_neighbor_grid[row + 1][column] == 0
            clicked_down = click_grid[row + 1][column] == 1
            click_grid[row + 1][column] = 1
        if not on_left_border:
            neighborless_left = mine_neighbor_grid[row][column - 1] == 0
            clicked_left = click_grid[row][column - 1] == 1
            click_grid[row][column - 1] = 1

        # Call the function on the neighbors that have no mine-neighbors
        if not on_right_border and neighborless_right and not clicked_right:
            self.__reveal_neighbors(
                row,
                column + 1,
                click_grid,
                mine_neighbor_grid)

        if not on_left_border and neighborless_left and not clicked_left:
            self.__reveal_neighbors(
                row,
                column - 1,
                click_grid,
                mine_neighbor_grid)

        if not on_top_border and neighborless_up and not clicked_up:
            self.__reveal_neighbors(
                row - 1,
                column,
                click_grid,
                mine_neighbor_grid)

        if not on_bottom_border and neighborless_down and not clicked_down:
            self.__reveal_neighbors(
                row + 1,
                column,
                click_grid,
                mine_neighbor_grid)

        return click_grid

def main():
    pygame.init()
    game = Game()
    pygame.quit()

if __name__ == "__main__":
    main()
<commit_msg>Add comments to reveal neighbors method.<commit_after>import pygame
import random
from constants import *

class Screen:

    """
    Class that controls the screen. This class is responsible for
    drawing to the screen
    """

    def __init__(self):
        # Screen elements
        self.screen = pygame.display.set_mode((SCREEN_HEIGHT, SCREEN_WIDTH))
        pygame.display.set_caption("Minesweeper Pre-Alpha")
        self.__initial_draw()

    def draw_grid(self, click_grid, color_grid):
        for row in range(0, ROWS):
            for column in range(0, COLUMNS):
                # Only draw to the screen if the block is marked
                # as to-draw
                if click_grid[row][column] == 1:
                    pygame.draw.rect(self.screen, color_grid[row][column],
                                    (column * GRID_WIDTH + (column + 1) * MARGIN,
                                     row * GRID_HEIGHT + (row + 1) * MARGIN,
                                     GRID_WIDTH,
                                     GRID_HEIGHT))

    def __initial_draw(self):
        """
        Draw initial game board. All blocks should initially be
        white
        """
        for row in range(0, ROWS):
            for column in range(0, COLUMNS):
                pygame.draw.rect(self.screen, WHITE,
                                (column * GRID_WIDTH + (column + 1) * MARGIN,
                                 row * GRID_HEIGHT + (row + 1) * MARGIN,
                                 GRID_WIDTH,
                                 GRID_HEIGHT))

class Game:

    """
    This class holds all the game elements. It renders the game and
    controls user input.
    """

    def __init__(self):
        """
        Sets up the initial game state, and starts the game
        """
        self.mine_grid = self.generate_mine_grid()
        self.mine_neighbor_grid = self.get_mine_neighbor_grid(self.mine_grid)
        self.color_grid = self.get_color_grid(
            self.mine_grid,
            self.mine_neighbor_grid)

        self.pygame_initialize()
        self.clock = pygame.time.Clock()
        self.game_screen = Screen()
        self.main_loop()

    def pygame_initialize(self):
        """
        Initializes all pygame-related things. Put font initialization
        here.
        """
        pygame.init()

    def generate_mine_grid(self):
        """
        Creates a randomly generated grid of mines.
        Ideally, this should happen after the first click by the user.
        """
        mine_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]
        laid_mines = 0
        assert(MINES < ROWS * COLUMNS)

        # Generate mines randomly.
        while laid_mines < MINES:
            row = random.randrange(0, ROWS)
            column = random.randrange(0, COLUMNS)
            if mine_grid[row][column] == 0:
                mine_grid[row][column] = 1
                laid_mines += 1

        return mine_grid

    def get_mine_neighbor_grid(self, mine_grid):
        """
        Creates the grid that holds how many mine-neighbors each space
        has. In the original, this is the number that is displayed on
        the block after they have been clicked.
        """
        mine_neighbor_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]
        for row in range(ROWS):
            for column in range(COLUMNS):
                mine_neighbor_grid[row][
                    column] = self.__count_mine_neighbors(row, column, mine_grid)

        return mine_neighbor_grid

    def get_color_grid(self, mine_grid, mine_neighbor_grid):
        """
        Creates a ROWS by COLUMNS grid that holds what color each
        block should be. This is based on the amount of mine-neighbors
        each block has.
        """
        color_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]
        for row in range(ROWS):
            for column in range(COLUMNS):
                if mine_grid[row][column] == 1:
                    color_grid[row][column] = RED
                elif mine_neighbor_grid[row][column] == 0:
                    color_grid[row][column] = BLUE
                elif mine_neighbor_grid[row][column] == 1:
                    color_grid[row][column] = CYAN
                elif mine_neighbor_grid[row][column] == 2:
                    color_grid[row][column] = DARKGREEN
                elif mine_neighbor_grid[row][column] == 3:
                    color_grid[row][column] = GREEN
                elif mine_neighbor_grid[row][column] == 4:
                    color_grid[row][column] = LITEGREEN
                elif mine_neighbor_grid[row][column] == 5:
                    color_grid[row][column] = PURPLE
                elif mine_neighbor_grid[row][column] == 6:
                    color_grid[row][column] = PINK
                elif mine_neighbor_grid[row][column] == 7:
                    color_grid[row][column] = YELLOW
                elif mine_neighbor_grid[row][column] == 8:
                    color_grid[row][column] = ORANGE

        return color_grid

    def game_over(self):
        """
        This controls what happens when the user clicks on a mine.
        """
        self.game_screen.screen.fill(BLACK)

        font = pygame.font.SysFont('Ubuntu', 24, True, False)
        text = font.render("Congraturaisins!", True, PURPLE)
        self.game_screen.screen.blit(text, [SCREEN_WIDTH // 7, 5])

        text = font.render("You lose!", True, WHITE)
        self.game_screen.screen.blit(text, [SCREEN_WIDTH // 3, 100])

    def main_loop(self):
        """
        This is the main loop of the program. It draws to the screen
        at appropriate times and controls the events of the game.
        """
        done = False

        # Variable to be used to check whether the game needs to be
        # re-drawn
        new_click = False
        game_over = False

        # This grid changes during gameplay, so I initialize it in
        # the main game loop
        click_grid = [[0 for x in range(COLUMNS)] for y in range(ROWS)]

        while not done:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    done = True
                if event.type == pygame.MOUSEBUTTONDOWN and not game_over:
                    mouse_pos = self.mouse_down(click_grid, game_over)
                    new_click = True

            # If the user has clicked since the last iteration, handle
            # the event, check the game over status, and
            # redraw the screen.
            if new_click:
                # Get the row and column of the block clicked
                row_clicked, column_clicked = self.find_row_and_column_clicked(
                    mouse_pos)
                click_grid, game_over = self.click_block_event(
                    row_clicked, column_clicked, click_grid, game_over)
                self.game_screen.draw_grid(click_grid, self.color_grid)
                new_click = False

            elif game_over:
                self.game_over()

            # Update the screen with what is drawn.
            pygame.display.flip()

            self.clock.tick(60)

    def mouse_down(self, click_grid, game_over):
        """
        Update the click_grid list when the user clicks a grid.
        """
        pos = pygame.mouse.get_pos()
        return pos

    def find_row_and_column_clicked(self, mouse_pos):
        """
        Returns row and column from mouse click position
        """

        # Find the row and column the user clicked on.
        column_clicked = mouse_pos[0] // (GRID_WIDTH + MARGIN)
        row_clicked = mouse_pos[1] // (GRID_HEIGHT + MARGIN)

        # If the user clicks below the final row, count it as the final row.
        if row_clicked >= ROWS:
            row_clicked = ROWS - 1
        if column_clicked >= COLUMNS:
            column_clicked = COLUMNS - 1

        return row_clicked, column_clicked

    def click_block_event(
        self,
        row_clicked,
        column_clicked,
        click_grid,
            game_over):
        """
        Handles what occurs when a row and column are clicked.
        Returns the updated click_grid and the game_over variable.
        """
        click_grid[row_clicked][column_clicked] = 1

        # End the game if the user has clicked on a mine
        if self.mine_grid[row_clicked][column_clicked] == 1:
            game_over = True

        # Reveal the neighbors of the clicked block
        elif self.mine_neighbor_grid[row_clicked][column_clicked] == 0:
            self.__reveal_neighbors(
                row_clicked,
                column_clicked,
                click_grid,
                self.mine_neighbor_grid)

        return click_grid, game_over

    def __count_mine_neighbors(self, row, column, mine_grid):
        mine_neighbor_count = 0

        # Check whether the block is on an edge.
        left = row >= 1
        right = row < ROWS - 1
        up = column >= 1
        down = column < COLUMNS - 1

        # Check left, up-left, and down-left for mines.
        if left:
            if mine_grid[row - 1][column] == 1:
                mine_neighbor_count += 1
            if up and mine_grid[row - 1][column - 1] == 1:
                mine_neighbor_count += 1
            if down and mine_grid[row - 1][column + 1] == 1:
                mine_neighbor_count += 1

        # Check right, up-right, and down-right for mines.
        if right:
            if mine_grid[row + 1][column] == 1:
                mine_neighbor_count += 1
            if up and mine_grid[row + 1][column - 1] == 1:
                mine_neighbor_count += 1
            if down and mine_grid[row + 1][column + 1] == 1:
                mine_neighbor_count += 1

        # Check up and down for mines.
        if up and mine_grid[row][column - 1] == 1:
            mine_neighbor_count += 1
        if down and mine_grid[row][column + 1] == 1:
            mine_neighbor_count += 1

        return mine_neighbor_count

    def __reveal_neighbors(self, row, column, click_grid, mine_neighbor_grid):
        """
        Reveals all blocks next to a input block if the block has no
        mine-neighbors. If the block has no mine-neighbors, and one of its
        neighbors has no mine-neighbors, call this function on those neighbors
        """
        assert mine_neighbor_grid[row][column] == 0

        # Check to see if the block is on a border
        on_top_border = row == 0
        on_bottom_border = row == ROWS - 1
        on_left_border = column == 0
        on_right_border = column == COLUMNS - 1

        # Reveal the neighbors, if they exist. Check to see if the
        # neighbors themselves have mine-neighbors. Also, check to see
        # if the neighbors are already clicked.
        # If statements are necessary to prevent an out of range error.
        if not on_right_border:
            neighborless_right = mine_neighbor_grid[row][column + 1] == 0
            clicked_right = click_grid[row][column + 1] == 1
            click_grid[row][column + 1] = 1
        if not on_top_border:
            neighborless_up = mine_neighbor_grid[row - 1][column] == 0
            clicked_up = click_grid[row - 1][column] == 1
            click_grid[row - 1][column] = 1
        if not on_bottom_border:
            neighborless_down = mine_neighbor_grid[row + 1][column] == 0
            clicked_down = click_grid[row + 1][column] == 1
            click_grid[row + 1][column] = 1
        if not on_left_border:
            neighborless_left = mine_neighbor_grid[row][column - 1] == 0
            clicked_left = click_grid[row][column - 1] == 1
            click_grid[row][column - 1] = 1

        # Call the function on the neighbors that have no mine-neighbors
        if not on_right_border and neighborless_right and not clicked_right:
            self.__reveal_neighbors(
                row,
                column + 1,
                click_grid,
                mine_neighbor_grid)

        if not on_left_border and neighborless_left and not clicked_left:
            self.__reveal_neighbors(
                row,
                column - 1,
                click_grid,
                mine_neighbor_grid)

        if not on_top_border and neighborless_up and not clicked_up:
            self.__reveal_neighbors(
                row - 1,
                column,
                click_grid,
                mine_neighbor_grid)

        if not on_bottom_border and neighborless_down and not clicked_down:
            self.__reveal_neighbors(
                row + 1,
                column,
                click_grid,
                mine_neighbor_grid)

        return click_grid

def main():
    pygame.init()
    game = Game()
    pygame.quit()

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


<commit_before>import errno
import fcntl
import os
import select
import shlex
from subprocess import Popen, PIPE
import sys
import tempfile
import traceback

from . import __version__

from .helpers import Error, IntegrityError
from .repository import Repository

import msgpack

BUFSIZE = 10 * 1024 * 1024

class ConnectionClosed(Error):
    """Connection closed by remote host"""

class ConnectionClosedWithHint(ConnectionClosed):
    """Connection closed by remote host. {}"""

class PathNotAllowed(Error):
    """Repository path not allowed"""

class InvalidRPCMethod(Error):
    """RPC method {} is not valid"""

class RepositoryServer:  # pragma: no cover
    rpc_methods = (
        '__len__',
        'check',
        'commit',
        'delete',
        'destroy',
        'get',
        'list',
        'negotiate',
        'open',
        'put',
        'repair',
        'rollback',
        'save_key',
        'load_key',
        'break_lock',
    )

    def __init__(self, restrict_to_paths):
        self.repository = None
        self.restrict_to_paths = restrict_to_paths

    def serve(self):
        stdin_fd = sys.stdin.fileno()
        stdout_fd = sys.stdout.fileno()
        # Make stdin non-blocking
        fl = fcntl.fcntl(stdin_fd, fcntl.F_GETFL)
        fcntl.fcntl(stdin_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
        # Make stdout blocking
        fl = fcntl.fcntl(stdout_fd, fcntl.F_GETFL)
        fcntl.fcntl(stdout_fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
        unpacker = msgpack.Unpacker(use_list=False)
        while True:
            r, w, es = select.select([stdin_fd], [], [], 10)
            if r:
                data = os.read(stdin_fd, BUFSIZE)
                if not data:
                    return
                unpacker.feed(data)
                for unpacked in unpacker:
                    if not (isinstance(unpacked, tuple) and len(unpacked) == 4):
                        raise Exception("Unexpected RPC data format.")
                    type, msgid, method, args = unpacked
                    method = method.decode('ascii')
                    try:
                        if method not in self.rpc_methods:
                            raise InvalidRPCMethod(method)
                        try:
                            f = getattr(self, method)
                        except AttributeError:
                            f = getattr(self.repository, method)
                        res = f(*args)
                    except BaseException as e:
                        exc = "Remote Traceback by Borg %s%s%s" % (__version__, os.linesep, traceback.format_exc())
                        os.write(stdout_fd, msgpack.packb((1, msgid, e.__class__.__name__, exc)))
                    else:
                        os.write(stdout_fd, msgpack.packb((1, msgid, None, res)))
            if es:
                return

    def negotiate(self, versions):
        return 1

    def open(self, path, create=False, lock_wait=None, lock=True):
        path = os.fsdecode(path)
        if path.startswith('/~'):
            path = path[1:]
        path = os.path.realpath(os.path.expanduser(path))
        if self.restrict_to_paths:
            for restrict_to_path in self.restrict_to_paths:
                if path.startswith(os.path.realpath(restrict_to_path)):
                    break
            else:
                raise PathNotAllowed(path)
        self.repository = Repository(path, create, lock_wait=lock_wait, lock=lock)
        return self.repository.id

class RemoteRepository:
    extra_test_args = []
    remote_path = 'borg'
    # default umask, overriden by --umask, defaults to read/write only for owner
    umask = 0o077

    class RPCError(Exception):
        def __init__(self, name):
            self.name = name

    def __init__(self, location, create=False, lock_wait=None, lock=True):
        self.location = location
        self.preload_ids = []
        self.msgid = 0
        self.to_send = b''
        self.cache = {}
        self.ignore_responses = set()
        self.responses = {}
        self.unpacker = msgpack.Unpacker(use_list=False)
        self.p = None
        # XXX: ideally, the testsuite would subclass Repository and
        # override ssh_cmd() instead of this crude hack, although
        # __testsuite__ is not a valid domain name so this is pretty
        # safe.
        if location.host == '__testsuite__':
            args = [sys.executable, '-m', 'borg.archiver', 'serve' ] + self.extra_test_args
        else:  # pragma: no cover
            args = self.ssh_cmd(location)
        self.p = Popen(args, bufsize=0, stdin=PIPE, stdout=PIPE)
        self.stdin_fd = self.p.stdin.fileno()
        self.stdout_fd = self.p.stdout.fileno()
        fcntl.fcntl(self.stdin_fd, fcntl.F_SETFL, fcntl.fcntl(self.stdin_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
        fcntl.fcntl(self.stdout_fd, fcntl.F_SETFL, fcntl.fcntl(self.stdout_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
        self.r_fds = [self.stdout_fd]
        self.x_fds = [self.stdin_fd, self.stdout_fd]

        try:
            version = self.call('negotiate', 1)
        except ConnectionClosed:
            raise ConnectionClosedWithHint('Is borg working on the server?')
        if version != 1:
            raise Exception('Server insisted on using unsupported protocol version %d' % version)
        self.id = self.call('open', location.path, create, lock_wait, lock)

    def __del__(self):
        self.close()

    def __repr__(self):
        return '<%s %s>' % (self.__class__.__name__, self.location.canonical_path())

    def umask_flag(self):
        return ['--umask', '%03o' % self.umask]

    def ssh_cmd(self, location):
        args = shlex.split(os.environ.get('BORG_RSH', 'ssh'))
        if location.port:
            args += ['-p', str(location.port)]
        if location.user:
            args.append('%s@%s' % (location.user, location.host))
        else:
            args.append('%s' % location.host)
        # use local umask also for the remote process
        args += [self.remote_path, 'serve'] + self.umask_flag()
        return args

    def call(self, cmd, *args, **kw):
        for resp in self.call_many(cmd, [args], **kw):
            return resp

    def call_many(self, cmd, calls, wait=True, is_preloaded=False):
        if not calls:
            return

        def fetch_from_cache(args):
            msgid = self.cache[args].pop(0)
            if not self.cache[args]:
                del self.cache[args]
            return msgid

        calls = list(calls)
        waiting_for = []
        w_fds = [self.stdin_fd]
        while wait or calls:
            while waiting_for:
                try:
                    error, res = self.responses.pop(waiting_for[0])
                    waiting_for.pop(0)
                    if error:
                        if error == b'DoesNotExist':
                            raise Repository.DoesNotExist(self.location.orig)
                        elif error == b'AlreadyExists':
                            raise Repository.AlreadyExists(self.location.orig)
                        elif error == b'CheckNeeded':
                            raise Repository.CheckNeeded(self.location.orig)
                        elif error == b'IntegrityError':
                            raise IntegrityError(res)
                        elif error == b'PathNotAllowed':
                            raise PathNotAllowed(*res)
                        elif error == b'ObjectNotFound':
                            raise Repository.ObjectNotFound(res[0], self.location.orig)
                        elif error == b'InvalidRPCMethod':
                            raise InvalidRPCMethod(*res)
                        else:
                            raise self.RPCError(res.decode('utf-8'))
                    else:
                        yield res
                        if not waiting_for and not calls:
                            return
                except KeyError:
                    break
            r, w, x = select.select(self.r_fds, w_fds, self.x_fds, 1)
            if x:
                raise Exception('FD exception occurred')
            if r:
                data = os.read(self.stdout_fd, BUFSIZE)
                if not data:
                    raise ConnectionClosed()
                self.unpacker.feed(data)
                for unpacked in self.unpacker:
                    if not (isinstance(unpacked, tuple) and len(unpacked) == 4):
                        raise Exception("Unexpected RPC data format.")
                    type, msgid, error, res = unpacked
                    if msgid in self.ignore_responses:
                        self.ignore_responses.remove(msgid)
                    else:
                        self.responses[msgid] = error, res
            if w:
                while not self.to_send and (calls or self.preload_ids) and len(waiting_for) < 100:
                    if calls:
                        if is_preloaded:
                            if calls[0] in self.cache:
                                waiting_for.append(fetch_from_cache(calls.pop(0)))
                        else:
                            args = calls.pop(0)
                            if cmd == 'get' and args in self.cache:
                                waiting_for.append(fetch_from_cache(args))
                            else:
                                self.msgid += 1
                                waiting_for.append(self.msgid)
                                self.to_send = msgpack.packb((1, self.msgid, cmd, args))
                    if not self.to_send and self.preload_ids:
                        args = (self.preload_ids.pop(0),)
                        self.msgid += 1
                        self.cache.setdefault(args, []).append(self.msgid)
                        self.to_send = msgpack.packb((1, self.msgid, cmd, args))

                if self.to_send:
                    try:
                        self.to_send = self.to_send[os.write(self.stdin_fd, self.to_send):]
                    except OSError as e:
                        # io.write might raise EAGAIN even though select indicates
                        # that the fd should be writable
                        if e.errno != errno.EAGAIN:
                            raise
                if not self.to_send and not (calls or self.preload_ids):
                    w_fds = []
        self.ignore_responses |= set(waiting_for)

    def check(self, repair=False):
        return self.call('check', repair)

    def commit(self, *args):
        return self.call('commit')

    def rollback(self, *args):
        return self.call('rollback')

    def destroy(self):
        return self.call('destroy')

    def __len__(self):
        return self.call('__len__')

    def list(self, limit=None, marker=None):
        return self.call('list', limit, marker)

    def get(self, id_):
        for resp in self.get_many([id_]):
            return resp

    def get_many(self, ids, is_preloaded=False):
        for resp in self.call_many('get', [(id_,) for id_ in ids], is_preloaded=is_preloaded):
            yield resp

    def put(self, id_, data, wait=True):
        return self.call('put', id_, data, wait=wait)

    def delete(self, id_, wait=True):
        return self.call('delete', id_, wait=wait)

    def save_key(self, keydata):
        return self.call('save_key', keydata)

    def load_key(self):
        return self.call('load_key')

    def break_lock(self):
        return self.call('break_lock')

    def close(self):
        if self.p:
            self.p.stdin.close()
            self.p.stdout.close()
            self.p.wait()
            self.p = None

    def preload(self, ids):
        self.preload_ids += ids

class RepositoryCache:
    """A caching Repository wrapper

    Caches Repository GET operations using a local temporary Repository.
    """
    def __init__(self, repository):
        self.repository = repository
        tmppath = tempfile.mkdtemp(prefix='borg-tmp')
        self.caching_repo = Repository(tmppath, create=True, exclusive=True)

    def __del__(self):
        self.caching_repo.destroy()

    def get(self, key):
        return next(self.get_many([key]))

    def get_many(self, keys):
        unknown_keys = [key for key in keys if key not in self.caching_repo]
        repository_iterator = zip(unknown_keys, self.repository.get_many(unknown_keys))
        for key in keys:
            try:
                yield self.caching_repo.get(key)
            except Repository.ObjectNotFound:
                for key_, data in repository_iterator:
                    if key_ == key:
                        self.caching_repo.put(key, data)
                        yield data
                        break
        # Consume any pending requests
        for _ in repository_iterator:
            pass

def cache_if_remote(repository):
    if isinstance(repository, RemoteRepository):
        return RepositoryCache(repository)
    return repository
<commit_msg>increase rpc protocol version to 2<commit_after>import errno
import fcntl
import os
import select
import shlex
from subprocess import Popen, PIPE
import sys
import tempfile
import traceback

from . import __version__

from .helpers import Error, IntegrityError
from .repository import Repository

import msgpack

RPC_PROTOCOL_VERSION = 2

BUFSIZE = 10 * 1024 * 1024

class ConnectionClosed(Error):
    """Connection closed by remote host"""

class ConnectionClosedWithHint(ConnectionClosed):
    """Connection closed by remote host. {}"""

class PathNotAllowed(Error):
    """Repository path not allowed"""

class InvalidRPCMethod(Error):
    """RPC method {} is not valid"""

class RepositoryServer:  # pragma: no cover
    rpc_methods = (
        '__len__',
        'check',
        'commit',
        'delete',
        'destroy',
        'get',
        'list',
        'negotiate',
        'open',
        'put',
        'repair',
        'rollback',
        'save_key',
        'load_key',
        'break_lock',
    )

    def __init__(self, restrict_to_paths):
        self.repository = None
        self.restrict_to_paths = restrict_to_paths

    def serve(self):
        stdin_fd = sys.stdin.fileno()
        stdout_fd = sys.stdout.fileno()
        # Make stdin non-blocking
        fl = fcntl.fcntl(stdin_fd, fcntl.F_GETFL)
        fcntl.fcntl(stdin_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
        # Make stdout blocking
        fl = fcntl.fcntl(stdout_fd, fcntl.F_GETFL)
        fcntl.fcntl(stdout_fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
        unpacker = msgpack.Unpacker(use_list=False)
        while True:
            r, w, es = select.select([stdin_fd], [], [], 10)
            if r:
                data = os.read(stdin_fd, BUFSIZE)
                if not data:
                    return
                unpacker.feed(data)
                for unpacked in unpacker:
                    if not (isinstance(unpacked, tuple) and len(unpacked) == 4):
                        raise Exception("Unexpected RPC data format.")
                    type, msgid, method, args = unpacked
                    method = method.decode('ascii')
                    try:
                        if method not in self.rpc_methods:
                            raise InvalidRPCMethod(method)
                        try:
                            f = getattr(self, method)
                        except AttributeError:
                            f = getattr(self.repository, method)
                        res = f(*args)
                    except BaseException as e:
                        exc = "Remote Traceback by Borg %s%s%s" % (__version__, os.linesep, traceback.format_exc())
                        os.write(stdout_fd, msgpack.packb((1, msgid, e.__class__.__name__, exc)))
                    else:
                        os.write(stdout_fd, msgpack.packb((1, msgid, None, res)))
            if es:
                return

    def negotiate(self, versions):
        return RPC_PROTOCOL_VERSION

    def open(self, path, create=False, lock_wait=None, lock=True):
        path = os.fsdecode(path)
        if path.startswith('/~'):
            path = path[1:]
        path = os.path.realpath(os.path.expanduser(path))
        if self.restrict_to_paths:
            for restrict_to_path in self.restrict_to_paths:
                if path.startswith(os.path.realpath(restrict_to_path)):
                    break
            else:
                raise PathNotAllowed(path)
        self.repository = Repository(path, create, lock_wait=lock_wait, lock=lock)
        return self.repository.id

class RemoteRepository:
    extra_test_args = []
    remote_path = 'borg'
    # default umask, overriden by --umask, defaults to read/write only for owner
    umask = 0o077

    class RPCError(Exception):
        def __init__(self, name):
            self.name = name

    def __init__(self, location, create=False, lock_wait=None, lock=True):
        self.location = location
        self.preload_ids = []
        self.msgid = 0
        self.to_send = b''
        self.cache = {}
        self.ignore_responses = set()
        self.responses = {}
        self.unpacker = msgpack.Unpacker(use_list=False)
        self.p = None
        # XXX: ideally, the testsuite would subclass Repository and
        # override ssh_cmd() instead of this crude hack, although
        # __testsuite__ is not a valid domain name so this is pretty
        # safe.
        if location.host == '__testsuite__':
            args = [sys.executable, '-m', 'borg.archiver', 'serve' ] + self.extra_test_args
        else:  # pragma: no cover
            args = self.ssh_cmd(location)
        self.p = Popen(args, bufsize=0, stdin=PIPE, stdout=PIPE)
        self.stdin_fd = self.p.stdin.fileno()
        self.stdout_fd = self.p.stdout.fileno()
        fcntl.fcntl(self.stdin_fd, fcntl.F_SETFL, fcntl.fcntl(self.stdin_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
        fcntl.fcntl(self.stdout_fd, fcntl.F_SETFL, fcntl.fcntl(self.stdout_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
        self.r_fds = [self.stdout_fd]
        self.x_fds = [self.stdin_fd, self.stdout_fd]

        try:
            version = self.call('negotiate', RPC_PROTOCOL_VERSION)
        except ConnectionClosed:
            raise ConnectionClosedWithHint('Is borg working on the server?')
        if version != RPC_PROTOCOL_VERSION:
            raise Exception('Server insisted on using unsupported protocol version %d' % version)
        self.id = self.call('open', location.path, create, lock_wait, lock)

    def __del__(self):
        self.close()

    def __repr__(self):
        return '<%s %s>' % (self.__class__.__name__, self.location.canonical_path())

    def umask_flag(self):
        return ['--umask', '%03o' % self.umask]

    def ssh_cmd(self, location):
        args = shlex.split(os.environ.get('BORG_RSH', 'ssh'))
        if location.port:
            args += ['-p', str(location.port)]
        if location.user:
            args.append('%s@%s' % (location.user, location.host))
        else:
            args.append('%s' % location.host)
        # use local umask also for the remote process
        args += [self.remote_path, 'serve'] + self.umask_flag()
        return args

    def call(self, cmd, *args, **kw):
        for resp in self.call_many(cmd, [args], **kw):
            return resp

    def call_many(self, cmd, calls, wait=True, is_preloaded=False):
        if not calls:
            return

        def fetch_from_cache(args):
            msgid = self.cache[args].pop(0)
            if not self.cache[args]:
                del self.cache[args]
            return msgid

        calls = list(calls)
        waiting_for = []
        w_fds = [self.stdin_fd]
        while wait or calls:
            while waiting_for:
                try:
                    error, res = self.responses.pop(waiting_for[0])
                    waiting_for.pop(0)
                    if error:
                        if error == b'DoesNotExist':
                            raise Repository.DoesNotExist(self.location.orig)
                        elif error == b'AlreadyExists':
                            raise Repository.AlreadyExists(self.location.orig)
                        elif error == b'CheckNeeded':
                            raise Repository.CheckNeeded(self.location.orig)
                        elif error == b'IntegrityError':
                            raise IntegrityError(res)
                        elif error == b'PathNotAllowed':
                            raise PathNotAllowed(*res)
                        elif error == b'ObjectNotFound':
                            raise Repository.ObjectNotFound(res[0], self.location.orig)
                        elif error == b'InvalidRPCMethod':
                            raise InvalidRPCMethod(*res)
                        else:
                            raise self.RPCError(res.decode('utf-8'))
                    else:
                        yield res
                        if not waiting_for and not calls:
                            return
                except KeyError:
                    break
            r, w, x = select.select(self.r_fds, w_fds, self.x_fds, 1)
            if x:
                raise Exception('FD exception occurred')
            if r:
                data = os.read(self.stdout_fd, BUFSIZE)
                if not data:
                    raise ConnectionClosed()
                self.unpacker.feed(data)
                for unpacked in self.unpacker:
                    if not (isinstance(unpacked, tuple) and len(unpacked) == 4):
                        raise Exception("Unexpected RPC data format.")
                    type, msgid, error, res = unpacked
                    if msgid in self.ignore_responses:
                        self.ignore_responses.remove(msgid)
                    else:
                        self.responses[msgid] = error, res
            if w:
                while not self.to_send and (calls or self.preload_ids) and len(waiting_for) < 100:
                    if calls:
                        if is_preloaded:
                            if calls[0] in self.cache:
                                waiting_for.append(fetch_from_cache(calls.pop(0)))
                        else:
                            args = calls.pop(0)
                            if cmd == 'get' and args in self.cache:
                                waiting_for.append(fetch_from_cache(args))
                            else:
                                self.msgid += 1
                                waiting_for.append(self.msgid)
                                self.to_send = msgpack.packb((1, self.msgid, cmd, args))
                    if not self.to_send and self.preload_ids:
                        args = (self.preload_ids.pop(0),)
                        self.msgid += 1
                        self.cache.setdefault(args, []).append(self.msgid)
                        self.to_send = msgpack.packb((1, self.msgid, cmd, args))

                if self.to_send:
                    try:
                        self.to_send = self.to_send[os.write(self.stdin_fd, self.to_send):]
                    except OSError as e:
                        # io.write might raise EAGAIN even though select indicates
                        # that the fd should be writable
                        if e.errno != errno.EAGAIN:
                            raise
                if not self.to_send and not (calls or self.preload_ids):
                    w_fds = []
        self.ignore_responses |= set(waiting_for)

    def check(self, repair=False):
        return self.call('check', repair)

    def commit(self, *args):
        return self.call('commit')

    def rollback(self, *args):
        return self.call('rollback')

    def destroy(self):
        return self.call('destroy')

    def __len__(self):
        return self.call('__len__')

    def list(self, limit=None, marker=None):
        return self.call('list', limit, marker)

    def get(self, id_):
        for resp in self.get_many([id_]):
            return resp

    def get_many(self, ids, is_preloaded=False):
        for resp in self.call_many('get', [(id_,) for id_ in ids], is_preloaded=is_preloaded):
            yield resp

    def put(self, id_, data, wait=True):
        return self.call('put', id_, data, wait=wait)

    def delete(self, id_, wait=True):
        return self.call('delete', id_, wait=wait)

    def save_key(self, keydata):
        return self.call('save_key', keydata)

    def load_key(self):
        return self.call('load_key')

    def break_lock(self):
        return self.call('break_lock')

    def close(self):
        if self.p:
            self.p.stdin.close()
            self.p.stdout.close()
            self.p.wait()
            self.p = None

    def preload(self, ids):
        self.preload_ids += ids

class RepositoryCache:
    """A caching Repository wrapper

    Caches Repository GET operations using a local temporary Repository.
    """
    def __init__(self, repository):
        self.repository = repository
        tmppath = tempfile.mkdtemp(prefix='borg-tmp')
        self.caching_repo = Repository(tmppath, create=True, exclusive=True)

    def __del__(self):
        self.caching_repo.destroy()

    def get(self, key):
        return next(self.get_many([key]))

    def get_many(self, keys):
        unknown_keys = [key for key in keys if key not in self.caching_repo]
        repository_iterator = zip(unknown_keys, self.repository.get_many(unknown_keys))
        for key in keys:
            try:
                yield self.caching_repo.get(key)
            except Repository.ObjectNotFound:
                for key_, data in repository_iterator:
                    if key_ == key:
                        self.caching_repo.put(key, data)
                        yield data
                        break
        # Consume any pending requests
        for _ in repository_iterator:
            pass

def cache_if_remote(repository):
    if isinstance(repository, RemoteRepository):
        return RepositoryCache(repository)
    return repository
<|endoftext|>


<commit_before># pylint: disable=too-few-public-methods

#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2016 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
# Copyright (C) 2019 Frédéric Pierret <frederic.pierret@qubes-os.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""" Exits sucessfull if the provided domains exists, else returns failure """

import sys

import qubesadmin.tools
import qubesadmin.vm

parser = qubesadmin.tools.QubesArgumentParser(description=__doc__,
                                              vmname_nargs='+')
parser.add_argument("--running", action="store_true", dest="running",
                    default=False,
                    help="Determine if (any of given) VM is running")
parser.add_argument("--paused", action="store_true", dest="paused",
                    default=False,
                    help="Determine if (any of given) VM is paused")
parser.add_argument("--template", action="store_true", dest="template",
                    default=False,
                    help="Determine if (any of given) VM is a template")
parser.add_argument("--networked", action="store_true", dest="networked",
                    default=False,
                    help="Determine if (any of given) VM can reach network")

def print_msg(log, domains, status):
    """Print message in appropriate form about given domain(s)"""
    if not domains:
        log.info("None of qubes: {!s}".format(', '.join(status)))
    else:
        for vm in sorted(domains):
            log.info("{!s}: {!s}".format(vm.name, ', '.join(status)))

def get_filters(args):
    """Get status and check functions"""
    filters = []

    if args.running:
        filters.append({'status': 'running', 'check': lambda x: x.is_running()})
    if args.paused:
        filters.append({'status': 'paused', 'check': lambda x: x.is_paused()})
    if args.template:
        filters.append(
            {'status': 'template', 'check': lambda x: x.klass == 'TemplateVM'})
    if args.networked:
        filters.append(
            {'status': 'networked', 'check': lambda x: x.is_networked()})

    return filters

def main(args=None, app=None):
    """Main function of qvm-check tool"""
    args = parser.parse_args(args, app=app)
    domains = args.domains
    return_code = 0

    log = args.app.log
    log.name = "qvm-check"

    status = []
    filters = get_filters(args)
    filtered_domains = set(domains)
    if filters:
        for filt in filters:
            status.append(filt['status'])
            check = filt['check']
            filtered_domains = filtered_domains.intersection(
                [vm for vm in domains if check(vm)])

        filtered_domains = list(filtered_domains)

        if set(domains) & set(filtered_domains) != set(domains):
            if not filtered_domains:
                return_code = 1
            else:
                return_code = 3

        if args.verbose:
            print_msg(log, filtered_domains, status)
    else:
        if not domains:
            return_code = 1
        elif args.verbose:
            print_msg(log, domains, ["exists"])

    return return_code

if __name__ == '__main__':
    sys.exit(main())
<commit_msg>qvm-check: fix from Marek's comment<commit_after># pylint: disable=too-few-public-methods

#
# The Qubes OS Project, http://www.qubes-os.org
#
# Copyright (C) 2016 Bahtiar `kalkin-` Gadimov <bahtiar@gadimov.de>
# Copyright (C) 2019 Frédéric Pierret <frederic.pierret@qubes-os.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
""" Exits sucessfull if the provided domains exists, else returns failure """

import sys

import qubesadmin.tools
import qubesadmin.vm

parser = qubesadmin.tools.QubesArgumentParser(description=__doc__,
                                              vmname_nargs='+')
parser.add_argument("--running", action="store_true", dest="running",
                    default=False,
                    help="Determine if (any of given) VM is running")
parser.add_argument("--paused", action="store_true", dest="paused",
                    default=False,
                    help="Determine if (any of given) VM is paused")
parser.add_argument("--template", action="store_true", dest="template",
                    default=False,
                    help="Determine if (any of given) VM is a template")
parser.add_argument("--networked", action="store_true", dest="networked",
                    default=False,
                    help="Determine if (any of given) VM can reach network")

def print_msg(log, domains, status):
    """Print message in appropriate form about given domain(s)"""
    if not domains:
        log.info("None of qubes: {!s}".format(', '.join(status)))
    else:
        for vm in sorted(list(domains)):
            log.info("{!s}: {!s}".format(vm.name, ', '.join(status)))

def get_filters(args):
    """Get status and check functions"""
    filters = []

    if args.running:
        filters.append({'status': 'running', 'check': lambda x: x.is_running()})
    if args.paused:
        filters.append({'status': 'paused', 'check': lambda x: x.is_paused()})
    if args.template:
        filters.append(
            {'status': 'template', 'check': lambda x: x.klass == 'TemplateVM'})
    if args.networked:
        filters.append(
            {'status': 'networked', 'check': lambda x: x.is_networked()})

    return filters

def main(args=None, app=None):
    """Main function of qvm-check tool"""
    args = parser.parse_args(args, app=app)
    domains = args.domains
    return_code = 0

    log = args.app.log
    log.name = "qvm-check"

    status = []
    filters = get_filters(args)
    filtered_domains = set(domains)
    if filters:
        for filt in filters:
            status.append(filt['status'])
            check = filt['check']
            filtered_domains = filtered_domains.intersection(
                [vm for vm in domains if check(vm)])

        if set(domains) & set(filtered_domains) != set(domains):
            if not filtered_domains:
                return_code = 1
            else:
                return_code = 3

        if args.verbose:
            print_msg(log, filtered_domains, status)
    else:
        if not domains:
            return_code = 1
        elif args.verbose:
            print_msg(log, domains, ["exists"])

    return return_code

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


<commit_before>from django.db import models
from cms.models import CMSPlugin, Page
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from filer.fields.image import FilerImageField
from links import schema
import mptt

from urlparse import urlparse  # for tree version of ExternalLinks
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned # for tree version of ExternalLinks

from django.conf import settings
PLUGIN_HEADING_LEVELS = settings.PLUGIN_HEADING_LEVELS
PLUGIN_HEADING_LEVEL_DEFAULT = settings.PLUGIN_HEADING_LEVEL_DEFAULT

class LinkMethodsMixin(object):

    def __unicode__(self):
        return unicode(self.destination_content_object)

    def _smart_get_attribute_for_destination(self, field_basename):
        '''
        fetches the correct value based on override fields and the destination object
        wrapper:
          - check if the local model has a attribute named 'text_override', if
            it does and it has a value return that
          - lookup on the wrapped destination object to see if it has a value
        '''
        override_value = getattr(self, "%s_override" % field_basename, None)
        if override_value:
            return override_value
        value = getattr(self.wrapped_destination_obj, field_basename, '')
        return value

    @property
    def wrapped_destination_obj(self):
        # get the wrapped object
        return schema.get_wrapper(self.destination_content_object.__class__)(self.destination_content_object)

    """
    The properties of any link attribute - as in {{ link.attribute }} *must* be listed
    here - otherwise, simply nothing will be returned.

    If an attribute matches:

    1.  is it an override attribute from the link instance? If so, use that. Otherwise:

    2.  look at the application's link_schema, and see what that returns. If there's nothing in there:

    3.  look at links.schema_registry.LinkWrapper. Returns the matching attribute from the model in the application's
        link_schema; otherwise:

    4.  looks at widgetry.views.SearchItemWrapper and looks for the attribute there. If it matches, return that, or the fallback

    """

    @property
    def text(self):
        return self._smart_get_attribute_for_destination('text')

    @property
    def short_text(self):
        return self._smart_get_attribute_for_destination('short_text')

    @property
    def url(self):
        return self._smart_get_attribute_for_destination('url')

    @property
    def heading(self):
        return self._smart_get_attribute_for_destination('heading')

    @property
    def description(self):
        return self._smart_get_attribute_for_destination('description')

    @property
    def image(self):
        return self._smart_get_attribute_for_destination('image')

    @property
    def optional_title(self):
        if self.html_title_element:
            return self.html_title_element
        else:
            return ""

    @property
    def metadata(self):
        return self._smart_get_attribute_for_destination('metadata')

    @property
    def thumbnail_url(self):
        return self._smart_get_attribute_for_destination('thumbnail_url')

class BaseLink(models.Model):
    """
    All links, whether placed using the Admin Inline mechanism or as plugins, require this information
    """
    destination_content_type = models.ForeignKey(ContentType, verbose_name="Type", related_name = "links_to_%(class)s")
    destination_object_id = models.PositiveIntegerField(verbose_name="Item")
    destination_content_object = generic.GenericForeignKey('destination_content_type', 'destination_object_id')

    class Meta:
        abstract = True
        ordering = ['id',]

class Link(BaseLink, LinkMethodsMixin):
    """
    Abstract base class for links that appear in lists - used by ObjectLinks and links.GenericLinkListPluginItem
    """
    include_description = models.BooleanField(help_text=u"Also display metadata")
    text_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the default link text")
    description_override = models.TextField(max_length=256, null=True,
        blank=True, help_text="Override the link default description text")
    heading_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the link destination's default group heading")
    metadata_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the link destination's default metadata")
    html_title_attribute = models.CharField(max_length=256, null=True, blank=True,
        help_text="Add an HTML title attribute")

    class Meta:
        abstract = True

class ObjectLink(Link):
    """
    When content_object object is rendered via its view, {% links %} in the template will display all the instances of this model that match its content_object field.
    """

    class Meta:
        verbose_name = "Link"

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id') # the content object the link is attached to

"""
As well as links to objects within the system, we need to maintain a database of links to external web resources
"""
class ExternalLink(models.Model):
    """
    Links to external sites
    """
    title = models.CharField(max_length=256)
    # this would have unique = True, but it makes it too hard to migrate from databases with duplicates
    url = models.CharField(max_length=255)
    external_site = models.ForeignKey('ExternalSite', related_name="links",
        null=True, blank=True)
    description = models.TextField(max_length=256, null=True, blank=True)
    kind = models.ForeignKey('LinkType', blank=True, null = True, related_name='links')

    class Meta:
        ordering = ['title',]

    def __unicode__(self):
        return self.title or self.url

    def save(self, *args, **kwargs):
        # here we either find the ExternalSite to attach to, or create it if it doesn't exist
        # split url into component parts
        purl = urlparse(self.url)

        # apply scheme (clean() has already checked that it's permissible, but check again because we save in housekeeping too)
        try:
            self.kind = LinkType.objects.get(scheme = purl.scheme)
        except ObjectDoesNotExist:
            # don't save
            return

        # get domain name
        domain = purl.netloc.partition(":")[0]

        # if we can find an exact domain match, make that the one
        try:
            self.external_site = ExternalSite.objects.get(domain=domain)
        # if we can't, we'll have to make it
        except (ObjectDoesNotExist, MultipleObjectsReturned):
            external_site = ExternalSite(domain=domain, site=domain)
            external_site.save()
            self.external_site = external_site
        super(ExternalLink, self).save(*args, **kwargs)

class LinkType(models.Model):
    scheme = models.CharField(max_length=50, help_text=u"e.g. 'http', 'mailto', etc",
        unique=True)
    name = models.CharField(max_length=50, help_text=u"e.g. 'Hypertext', 'email', etc")

    def __unicode__(self):
        return self.scheme

class ExternalSite(models.Model):
    site = models.CharField(max_length=50,help_text = u"e.g. 'BBC News', 'Welsh Assembly Goverment', etc", null = True)
    domain = models.CharField(max_length=256, null = True, blank = True,)
    parent = models.ForeignKey('self', blank=True, null = True, related_name='children') # for tree version of ExternalLinks

    class Meta:
        ordering = ['site',]

    def __unicode__(self):
        # if this site is unnamed, let's see if it has a named ancestor
        if self.site == self.domain:
            # get a list of domains like: cf.ac.uk, ac.uk, uk
            for domain in self.get_ancestors(ascending = True):
                # has this one been given a name?
                if domain.site != domain.domain:
                    return domain.site
        return self.site

    def save(self):

        # to-do: strip off port, if it exists

        # find the domain's parent domain
        parent_domain = self.domain.partition(".")[-1]

        # assuming that this domain exists
        if not self.domain == "":
            try:
                # try giving it an existing parent
                self.parent = ExternalSite.objects.get(domain = parent_domain)
            except ObjectDoesNotExist:
                # no such parent? better create it
                parent = ExternalSite(domain = parent_domain, site = parent_domain)

                # check that it will have a domain attribute
                if parent.domain:
                    # save it, then assign a FK to it
                    parent.save()
                    self.parent = parent
            super(ExternalSite, self).save()
        else:
            # we won't create a nameless domain!
            pass

try:
    mptt.register(ExternalSite)
except mptt.AlreadyRegistered:
    pass

class GenericLinkListPlugin(CMSPlugin):
    INSERTION_MODES = (
        (0, u"Inline in text"),
        (1, u"Unordered List -
"),
        (2, u"Paragraphs -
"),
        )
    insert_as = models.PositiveSmallIntegerField(choices = INSERTION_MODES, default = 1)
    use_link_icons = models.BooleanField(help_text = "Place an icon on each link below (links in lists only)")
    separator = models.CharField(help_text = "Applies to Inline links only; default is ', '", max_length=20, null = True, blank = True, default = ", ")
    final_separator = models.CharField(help_text = "Applies to Inline links only; default is ' and '", max_length=20, null = True, blank = True, default = " and ")

class GenericLinkListPluginItem(Link):
    plugin = models.ForeignKey(GenericLinkListPlugin, related_name="links")
    key_link = models.BooleanField(help_text="Make this item stand out (for links in lists only)")

    class Meta:
        ordering = ['id',]

class CarouselPlugin(CMSPlugin):
    """
    The carousel inserted into a Page
    """
    CAROUSEL_WIDTHS = (
        (u'Widths relative to the containing column', (
            (100.0, u"100%"),
            (75.0, u"75%"),
            (66.7, u"66%"),
            (50.0, u"50%"),
            (33.3, u"33%"),
            (25.0, u"25%"),
            )
        ),
        ('Deprecated - do not use', (
            (1.0, u'Full'),
            (1.33, u'Three-quarters of the page'),
            (1.5, u'Two-thirds of the page'),
            (2.0, u'Half of the page'),
            (3.0, u'One-third of the page'),
            (4.0, u'One-quarter of the page'),
            )
        ),
    )
    ASPECT_RATIOS = (
        (2.5, u'5x2'),
        (2.0, u'2x1'),
        (1.5, u'3x2'),
        (1.333, u'4x3'),
        (1.0, u'Square'),
        (.75, u'3x4'),
        (.667, u'2x3'),
    )
    #class Meta:
        #permissions = (("is_a_boss", "Is a boss"),)
    name = models.CharField(max_length=50)
    width = models.FloatField(choices=CAROUSEL_WIDTHS, default=100.0)
    aspect_ratio = models.FloatField(null=True, blank=True,
         choices=ASPECT_RATIOS, default=1.5)
    #height = models.PositiveIntegerField(null=True, blank=True)

class CarouselPluginItem(BaseLink, LinkMethodsMixin):
    """
    The item in a carousel - basically a Link, with an image
    """
    plugin = models.ForeignKey(CarouselPlugin, related_name="carousel_item")
    image = FilerImageField()
    link_title = models.CharField(max_length=35)

class FocusOnPluginEditor(CMSPlugin):
    heading_level = models.PositiveSmallIntegerField(choices = PLUGIN_HEADING_LEVELS, default = PLUGIN_HEADING_LEVEL_DEFAULT)

class FocusOnPluginItemEditor(BaseLink):
    plugin = models.ForeignKey(FocusOnPluginEditor, related_name="focuson_items")
    text_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the default link text")
    short_text_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the default Focus on title text")
    description_override = models.TextField(max_length=256, null=True, blank=True,
        help_text = "Override the item's default description")
    image_override = FilerImageField(blank=True, null=True,)
<commit_msg>Focuson fixed, yay<commit_after>from django.db import models
from cms.models import CMSPlugin, Page
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from filer.fields.image import FilerImageField
from links import schema
import mptt

from urlparse import urlparse  # for tree version of ExternalLinks
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned # for tree version of ExternalLinks

from django.conf import settings
PLUGIN_HEADING_LEVELS = settings.PLUGIN_HEADING_LEVELS
PLUGIN_HEADING_LEVEL_DEFAULT = settings.PLUGIN_HEADING_LEVEL_DEFAULT

class LinkMethodsMixin(object):

    def __unicode__(self):
        return unicode(self.destination_content_object)

    def _smart_get_attribute_for_destination(self, field_basename):
        '''
        fetches the correct value based on override fields and the destination object
        wrapper:
          - check if the local model has a attribute named 'text_override', if
            it does and it has a value return that
          - lookup on the wrapped destination object to see if it has a value
        '''
        override_value = getattr(self, "%s_override" % field_basename, None)
        if override_value:
            return override_value
        value = getattr(self.wrapped_destination_obj, field_basename, '')
        return value

    @property
    def wrapped_destination_obj(self):
        # get the wrapped object
        return schema.get_wrapper(self.destination_content_object.__class__)(self.destination_content_object)

    """
    The properties of any link attribute - as in {{ link.attribute }} *must* be listed
    here - otherwise, simply nothing will be returned.

    If an attribute matches:

    1.  is it an override attribute from the link instance? If so, use that. Otherwise:

    2.  look at the application's link_schema, and see what that returns. If there's nothing in there:

    3.  look at links.schema_registry.LinkWrapper. Returns the matching attribute from the model in the application's
        link_schema; otherwise:

    4.  looks at widgetry.views.SearchItemWrapper and looks for the attribute there. If it matches, return that, or the fallback

    """

    @property
    def text(self):
        return self._smart_get_attribute_for_destination('text')

    @property
    def short_text(self):
        return self._smart_get_attribute_for_destination('short_text')

    @property
    def url(self):
        return self._smart_get_attribute_for_destination('url')

    @property
    def heading(self):
        return self._smart_get_attribute_for_destination('heading')

    @property
    def description(self):
        return self._smart_get_attribute_for_destination('description')

    @property
    def image(self):
        return self._smart_get_attribute_for_destination('image')

    @property
    def optional_title(self):
        if self.html_title_element:
            return self.html_title_element
        else:
            return ""

    @property
    def metadata(self):
        return self._smart_get_attribute_for_destination('metadata')

    @property
    def thumbnail_url(self):
        return self._smart_get_attribute_for_destination('thumbnail_url')

class BaseLink(models.Model):
    """
    All links, whether placed using the Admin Inline mechanism or as plugins, require this information
    """
    destination_content_type = models.ForeignKey(ContentType, verbose_name="Type", related_name = "links_to_%(class)s")
    destination_object_id = models.PositiveIntegerField(verbose_name="Item")
    destination_content_object = generic.GenericForeignKey('destination_content_type', 'destination_object_id')

    class Meta:
        abstract = True
        ordering = ['id',]

class Link(BaseLink, LinkMethodsMixin):
    """
    Abstract base class for links that appear in lists - used by ObjectLinks and links.GenericLinkListPluginItem
    """
    include_description = models.BooleanField(help_text=u"Also display metadata")
    text_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the default link text")
    description_override = models.TextField(max_length=256, null=True,
        blank=True, help_text="Override the link default description text")
    heading_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the link destination's default group heading")
    metadata_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the link destination's default metadata")
    html_title_attribute = models.CharField(max_length=256, null=True, blank=True,
        help_text="Add an HTML title attribute")

    class Meta:
        abstract = True

class ObjectLink(Link):
    """
    When content_object object is rendered via its view, {% links %} in the template will display all the instances of this model that match its content_object field.
    """

    class Meta:
        verbose_name = "Link"

    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id') # the content object the link is attached to

"""
As well as links to objects within the system, we need to maintain a database of links to external web resources
"""
class ExternalLink(models.Model):
    """
    Links to external sites
    """
    title = models.CharField(max_length=256)
    # this would have unique = True, but it makes it too hard to migrate from databases with duplicates
    url = models.CharField(max_length=255)
    external_site = models.ForeignKey('ExternalSite', related_name="links",
        null=True, blank=True)
    description = models.TextField(max_length=256, null=True, blank=True)
    kind = models.ForeignKey('LinkType', blank=True, null = True, related_name='links')

    class Meta:
        ordering = ['title',]

    def __unicode__(self):
        return self.title or self.url

    def save(self, *args, **kwargs):
        # here we either find the ExternalSite to attach to, or create it if it doesn't exist
        # split url into component parts
        purl = urlparse(self.url)

        # apply scheme (clean() has already checked that it's permissible, but check again because we save in housekeeping too)
        try:
            self.kind = LinkType.objects.get(scheme = purl.scheme)
        except ObjectDoesNotExist:
            # don't save
            return

        # get domain name
        domain = purl.netloc.partition(":")[0]

        # if we can find an exact domain match, make that the one
        try:
            self.external_site = ExternalSite.objects.get(domain=domain)
        # if we can't, we'll have to make it
        except (ObjectDoesNotExist, MultipleObjectsReturned):
            external_site = ExternalSite(domain=domain, site=domain)
            external_site.save()
            self.external_site = external_site
        super(ExternalLink, self).save(*args, **kwargs)

class LinkType(models.Model):
    scheme = models.CharField(max_length=50, help_text=u"e.g. 'http', 'mailto', etc",
        unique=True)
    name = models.CharField(max_length=50, help_text=u"e.g. 'Hypertext', 'email', etc")

    def __unicode__(self):
        return self.scheme

class ExternalSite(models.Model):
    site = models.CharField(max_length=50,help_text = u"e.g. 'BBC News', 'Welsh Assembly Goverment', etc", null = True)
    domain = models.CharField(max_length=256, null = True, blank = True,)
    parent = models.ForeignKey('self', blank=True, null = True, related_name='children') # for tree version of ExternalLinks

    class Meta:
        ordering = ['site',]

    def __unicode__(self):
        # if this site is unnamed, let's see if it has a named ancestor
        if self.site == self.domain:
            # get a list of domains like: cf.ac.uk, ac.uk, uk
            for domain in self.get_ancestors(ascending = True):
                # has this one been given a name?
                if domain.site != domain.domain:
                    return domain.site
        return self.site

    def save(self):

        # to-do: strip off port, if it exists

        # find the domain's parent domain
        parent_domain = self.domain.partition(".")[-1]

        # assuming that this domain exists
        if not self.domain == "":
            try:
                # try giving it an existing parent
                self.parent = ExternalSite.objects.get(domain = parent_domain)
            except ObjectDoesNotExist:
                # no such parent? better create it
                parent = ExternalSite(domain = parent_domain, site = parent_domain)

                # check that it will have a domain attribute
                if parent.domain:
                    # save it, then assign a FK to it
                    parent.save()
                    self.parent = parent
            super(ExternalSite, self).save()
        else:
            # we won't create a nameless domain!
            pass

try:
    mptt.register(ExternalSite)
except mptt.AlreadyRegistered:
    pass

class GenericLinkListPlugin(CMSPlugin):
    INSERTION_MODES = (
        (0, u"Inline in text"),
        (1, u"Unordered List -
"),
        (2, u"Paragraphs -
"),
        )
    insert_as = models.PositiveSmallIntegerField(choices = INSERTION_MODES, default = 1)
    use_link_icons = models.BooleanField(help_text = "Place an icon on each link below (links in lists only)")
    separator = models.CharField(help_text = "Applies to Inline links only; default is ', '", max_length=20, null = True, blank = True, default = ", ")
    final_separator = models.CharField(help_text = "Applies to Inline links only; default is ' and '", max_length=20, null = True, blank = True, default = " and ")

class GenericLinkListPluginItem(Link):
    plugin = models.ForeignKey(GenericLinkListPlugin, related_name="links")
    key_link = models.BooleanField(help_text="Make this item stand out (for links in lists only)")

    class Meta:
        ordering = ['id',]

class CarouselPlugin(CMSPlugin):
    """
    The carousel inserted into a Page
    """
    CAROUSEL_WIDTHS = (
        (u'Widths relative to the containing column', (
            (100.0, u"100%"),
            (75.0, u"75%"),
            (66.7, u"66%"),
            (50.0, u"50%"),
            (33.3, u"33%"),
            (25.0, u"25%"),
            )
        ),
        ('Deprecated - do not use', (
            (1.0, u'Full'),
            (1.33, u'Three-quarters of the page'),
            (1.5, u'Two-thirds of the page'),
            (2.0, u'Half of the page'),
            (3.0, u'One-third of the page'),
            (4.0, u'One-quarter of the page'),
            )
        ),
    )
    ASPECT_RATIOS = (
        (2.5, u'5x2'),
        (2.0, u'2x1'),
        (1.5, u'3x2'),
        (1.333, u'4x3'),
        (1.0, u'Square'),
        (.75, u'3x4'),
        (.667, u'2x3'),
    )
    #class Meta:
        #permissions = (("is_a_boss", "Is a boss"),)
    name = models.CharField(max_length=50)
    width = models.FloatField(choices=CAROUSEL_WIDTHS, default=100.0)
    aspect_ratio = models.FloatField(null=True, blank=True,
         choices=ASPECT_RATIOS, default=1.5)
    #height = models.PositiveIntegerField(null=True, blank=True)

class CarouselPluginItem(BaseLink, LinkMethodsMixin):
    """
    The item in a carousel - basically a Link, with an image
    """
    plugin = models.ForeignKey(CarouselPlugin, related_name="carousel_item")
    image = FilerImageField()
    link_title = models.CharField(max_length=35)

class FocusOnPluginEditor(CMSPlugin):
    heading_level = models.PositiveSmallIntegerField(choices = PLUGIN_HEADING_LEVELS, default = PLUGIN_HEADING_LEVEL_DEFAULT)

class FocusOnPluginItemEditor(LinkMethodsMixin, BaseLink):
    plugin = models.ForeignKey(FocusOnPluginEditor, related_name="focuson_items")
    text_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the default link text")
    short_text_override = models.CharField(max_length=256, null=True, blank=True,
        help_text="Override the default Focus on title text")
    description_override = models.TextField(max_length=256, null=True, blank=True,
        help_text = "Override the item's default description")
    image_override = FilerImageField(blank=True, null=True,)
<|endoftext|>


<commit_before>"Logging functions for Mininet."

import logging
from logging import Logger
import types

LEVELS = { 'debug': logging.DEBUG,
          'info': logging.INFO,
          'warning': logging.WARNING,
          'error': logging.ERROR,
          'critical': logging.CRITICAL }

# change this to logging.INFO to get printouts when running unit tests
LOGLEVELDEFAULT = logging.WARNING

#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
LOGMSGFORMAT = '%(message)s'

# Modified from python2.5/__init__.py
class StreamHandlerNoNewline( logging.StreamHandler ):
    """StreamHandler that doesn't print newlines by default.
       Since StreamHandler automatically adds newlines, define a mod to more
       easily support interactive mode when we want it, or errors-only logging
       for running unit tests."""

    def emit( self, record ):
        """Emit a record.
           If a formatter is specified, it is used to format the record.
           The record is then written to the stream with a trailing newline
           [ N.B. this may be removed depending on feedback ]. If exception
           information is present, it is formatted using
           traceback.printException and appended to the stream."""
        try:
            msg = self.format( record )
            fs = '%s' # was '%s\n'
            if not hasattr( types, 'UnicodeType' ): #if no unicode support...
                self.stream.write( fs % msg )
            else:
                try:
                    self.stream.write( fs % msg )
                except UnicodeError:
                    self.stream.write( fs % msg.encode( 'UTF-8' ) )
            self.flush()
        except ( KeyboardInterrupt, SystemExit ):
            raise
        except:
            self.handleError( record )

class Singleton( type ):
    """Singleton pattern from Wikipedia
       See http://en.wikipedia.org/wiki/SingletonPattern#Python

       Intended to be used as a __metaclass_ param, as shown for the class
       below.

       Changed cls first args to mcs to satisfy pylint."""

    def __init__( mcs, name, bases, dict_ ):
        super( Singleton, mcs ).__init__( name, bases, dict_ )
        mcs.instance = None

    def __call__( mcs, *args, **kw ):
        if mcs.instance is None:
            mcs.instance = super( Singleton, mcs ).__call__( *args, **kw )
            return mcs.instance

class MininetLogger( Logger, object ):
    """Mininet-specific logger
       Enable each mininet .py file to with one import:

       from mininet.log import [lg, info, error]

       ...get a default logger that doesn't require one newline per logging
       call.

       Inherit from object to ensure that we have at least one new-style base
       class, and can then use the __metaclass__ directive, to prevent this
       error:

       TypeError: Error when calling the metaclass bases
       a new-style class can't have only classic bases

       If Python2.5/logging/__init__.py defined Filterer as a new-style class,
       via Filterer( object ): rather than Filterer, we wouldn't need this.

       Use singleton pattern to ensure only one logger is ever created."""

    __metaclass__ = Singleton

    def __init__( self ):

        Logger.__init__( self, "mininet" )

        # create console handler
        ch = StreamHandlerNoNewline()
        # create formatter
        formatter = logging.Formatter( LOGMSGFORMAT )
        # add formatter to ch
        ch.setFormatter( formatter )
        # add ch to lg
        self.addHandler( ch )

        self.setLogLevel()

    def setLogLevel( self, levelname=None ):
        """Setup loglevel.
           Convenience function to support lowercase names.

           levelName: level name from LEVELS"""
        level = LOGLEVELDEFAULT
        if levelname != None:
            if levelname not in LEVELS:
                raise Exception( 'unknown loglevel seen in set_loglevel' )
            else:
                level = LEVELS.get( levelname, level )

        self.setLevel( level )
        self.handlers[ 0 ].setLevel( level )

lg = MininetLogger()
info, warn, error = lg.info, lg.warn, lg.error
<commit_msg>Added debug() convenience function.<commit_after>"Logging functions for Mininet."

import logging
from logging import Logger
import types

LEVELS = { 'debug': logging.DEBUG,
          'info': logging.INFO,
          'warning': logging.WARNING,
          'error': logging.ERROR,
          'critical': logging.CRITICAL }

# change this to logging.INFO to get printouts when running unit tests
LOGLEVELDEFAULT = logging.WARNING

#default: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
LOGMSGFORMAT = '%(message)s'

# Modified from python2.5/__init__.py
class StreamHandlerNoNewline( logging.StreamHandler ):
    """StreamHandler that doesn't print newlines by default.
       Since StreamHandler automatically adds newlines, define a mod to more
       easily support interactive mode when we want it, or errors-only logging
       for running unit tests."""

    def emit( self, record ):
        """Emit a record.
           If a formatter is specified, it is used to format the record.
           The record is then written to the stream with a trailing newline
           [ N.B. this may be removed depending on feedback ]. If exception
           information is present, it is formatted using
           traceback.printException and appended to the stream."""
        try:
            msg = self.format( record )
            fs = '%s' # was '%s\n'
            if not hasattr( types, 'UnicodeType' ): #if no unicode support...
                self.stream.write( fs % msg )
            else:
                try:
                    self.stream.write( fs % msg )
                except UnicodeError:
                    self.stream.write( fs % msg.encode( 'UTF-8' ) )
            self.flush()
        except ( KeyboardInterrupt, SystemExit ):
            raise
        except:
            self.handleError( record )

class Singleton( type ):
    """Singleton pattern from Wikipedia
       See http://en.wikipedia.org/wiki/SingletonPattern#Python

       Intended to be used as a __metaclass_ param, as shown for the class
       below.

       Changed cls first args to mcs to satisfy pylint."""

    def __init__( mcs, name, bases, dict_ ):
        super( Singleton, mcs ).__init__( name, bases, dict_ )
        mcs.instance = None

    def __call__( mcs, *args, **kw ):
        if mcs.instance is None:
            mcs.instance = super( Singleton, mcs ).__call__( *args, **kw )
            return mcs.instance

class MininetLogger( Logger, object ):
    """Mininet-specific logger
       Enable each mininet .py file to with one import:

       from mininet.log import [lg, info, error]

       ...get a default logger that doesn't require one newline per logging
       call.

       Inherit from object to ensure that we have at least one new-style base
       class, and can then use the __metaclass__ directive, to prevent this
       error:

       TypeError: Error when calling the metaclass bases
       a new-style class can't have only classic bases

       If Python2.5/logging/__init__.py defined Filterer as a new-style class,
       via Filterer( object ): rather than Filterer, we wouldn't need this.

       Use singleton pattern to ensure only one logger is ever created."""

    __metaclass__ = Singleton

    def __init__( self ):

        Logger.__init__( self, "mininet" )

        # create console handler
        ch = StreamHandlerNoNewline()
        # create formatter
        formatter = logging.Formatter( LOGMSGFORMAT )
        # add formatter to ch
        ch.setFormatter( formatter )
        # add ch to lg
        self.addHandler( ch )

        self.setLogLevel()

    def setLogLevel( self, levelname=None ):
        """Setup loglevel.
           Convenience function to support lowercase names.

           levelName: level name from LEVELS"""
        level = LOGLEVELDEFAULT
        if levelname != None:
            if levelname not in LEVELS:
                raise Exception( 'unknown loglevel seen in set_loglevel' )
            else:
                level = LEVELS.get( levelname, level )

        self.setLevel( level )
        self.handlers[ 0 ].setLevel( level )

lg = MininetLogger()
info, warn, error, debug = lg.info, lg.warn, lg.error, lg.debug
<|endoftext|>


<commit_before># Copyright (C) 2007-2011 Samuel Abels.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
"""
TTY utilities.
"""
import os
import sys
import struct
from subprocess import Popen, PIPE

def _get_terminal_size(fd):
    try:
        import fcntl
        import termios
    except ImportError:
        return None
    s = struct.pack('HHHH', 0, 0, 0, 0)
    try:
        x = fcntl.ioctl(fd, termios.TIOCGWINSZ, s)
    except IOError:
        return None
    try:
        rows, cols, x_pixels, y_pixels = struct.unpack('HHHH', x)
    except struct.error:
        return None
    return rows, cols

def get_terminal_size():
    """
    Returns the number of lines and columns of the current terminal.
    It attempts several strategies to determine the size and if all fail,
    it returns (80, 25).

    @rtype:  int, int
    @return: The rows and columns of the terminal.
    """
    # Try stdin, stdout, stderr.
    for fd in (sys.stdout.fileno(),
               sys.stdin.fileno(),
               sys.stderr.fileno()):
        try:
            rows, cols = _get_terminal_size(fd)
        except TypeError:
            pass
        else:
            return rows, cols

    # Try os.ctermid()
    try:
        fd = os.open(os.ctermid(), os.O_RDONLY)
    except OSError:
        pass
    else:
        try:
            rows, cols = _get_terminal_size(fd)
        except TypeError:
            pass
        finally:
            os.close(fd)

    # Try `stty size`
    devnull = open(os.devnull, 'w')
    process = Popen(['stty', 'size'], stderr = devnull, stdout = PIPE)
    errcode = process.wait()
    output  = process.stdout.read()
    devnull.close()
    try:
        rows, cols = output.split()
        return int(rows), int(cols)
    except (ValueError, TypeError):
        pass

    # Try environment variables.
    try:
        return tuple(int(os.getenv(var)) for var in ('LINES', 'COLUMNS'))
    except (ValueError, TypeError):
        pass

    # Give up.
    return 25, 80
<commit_msg>Exscript.util.tty.get_terminal_size(): fix: don't fail if stdout/stderr/stdin have no fileno().<commit_after># Copyright (C) 2007-2011 Samuel Abels.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
"""
TTY utilities.
"""
import os
import sys
import struct
from subprocess import Popen, PIPE

def _get_terminal_size(fd):
    try:
        import fcntl
        import termios
    except ImportError:
        return None
    s = struct.pack('HHHH', 0, 0, 0, 0)
    try:
        x = fcntl.ioctl(fd, termios.TIOCGWINSZ, s)
    except IOError: # Window size ioctl not supported.
        return None
    try:
        rows, cols, x_pixels, y_pixels = struct.unpack('HHHH', x)
    except struct.error:
        return None
    return rows, cols

def get_terminal_size():
    """
    Returns the number of lines and columns of the current terminal.
    It attempts several strategies to determine the size and if all fail,
    it returns (80, 25).

    @rtype:  int, int
    @return: The rows and columns of the terminal.
    """
    # Collect a list of viable input channels that may tell us something
    # about the terminal dimensions.
    fileno_list = []
    try:
        fileno_list.append(sys.stdout.fileno())
    except AttributeError:
        # Channel was redirected to an object that has no fileno()
        pass
    try:
        fileno_list.append(sys.stdin.fileno())
    except AttributeError:
        pass
    try:
        fileno_list.append(sys.stderr.fileno())
    except AttributeError:
        pass

    # Ask each channel for the terminal window size.
    for fd in fileno_list:
        try:
            rows, cols = _get_terminal_size(fd)
        except TypeError:
            # _get_terminal_size() returned None.
            pass
        else:
            return rows, cols

    # Try os.ctermid()
    try:
        fd = os.open(os.ctermid(), os.O_RDONLY)
    except OSError:
        # The device pointed to by os.ctermid() does not exist.
        pass
    else:
        try:
            rows, cols = _get_terminal_size(fd)
        except TypeError:
            # _get_terminal_size() returned None.
            pass
        else:
            return rows, cols
        finally:
            os.close(fd)

    # Try `stty size`
    devnull = open(os.devnull, 'w')
    process = Popen(['stty', 'size'], stderr = devnull, stdout = PIPE)
    errcode = process.wait()
    output  = process.stdout.read()
    devnull.close()
    try:
        rows, cols = output.split()
        return int(rows), int(cols)
    except (ValueError, TypeError):
        pass

    # Try environment variables.
    try:
        return tuple(int(os.getenv(var)) for var in ('LINES', 'COLUMNS'))
    except (ValueError, TypeError):
        pass

    # Give up.
    return 25, 80
<|endoftext|>