<commit_before>#!/usr/bin/python3
from lsgame import LSGameEngine
import lsanimate
import lsexplosion

import Colors
import Shapes

import random
import time

wait=time.sleep

class Cell(object):
    def __init__(self, is_mine, is_visible=False, is_flagged=False):
        self.is_mine = is_mine
        self.is_visible = is_visible
        self.is_flagged = is_flagged
        self.is_defused = False

    def show(self):
        self.is_visible = True

    def flag(self):
        self.is_flagged = not self.is_flagged

    def place_mine(self):
        self.is_mine = True

    def set_defused(self):
        if self.is_mine:
            self.is_defused = True

class Board():

    def __init__(self):
        super().__init__()
        self.is_playing = True

    def create_board(self, rows, cols, mines):
        print("creating board")
        self.board = tuple([tuple([Cell(False) for col in range(cols)])
                            for row in range(rows)])
        available_pos = list(range((rows) * (cols)))
        print("creating mines")
        for i in range(mines):
            new_pos = random.choice(available_pos)
            available_pos.remove(new_pos)
            (row_id, col_id) = random.randint(0, rows-1), random.randint(0, cols-1) #(new_pos // (cols), new_pos % (rows))
            self.place_mine(row_id, col_id)
        self.is_playing = True
        return

    def getCellState(self,row_id, col_id):
        # print ("min_repr for: ",row_id,col_id)
        cell = self.board[row_id][col_id]
        if cell.is_defused:
            return "D"
        elif cell.is_visible:
            if cell.is_mine:
                return "M"
            else:
                surr = self.count_surrounding(row_id, col_id)
                return str(surr) if surr else " "
        elif cell.is_flagged:
            return "F"
        else:
            return "."  #u"\uff18"

    def set_display(self, display):
        print("setting display")
        self.display = display

    def show(self, row_id, col_id):
        self.showingMultiple = False
        #print("given:", row_id, col_id, "board:", len(self.board), len(self.board[0]))
        cell = self.board[row_id][col_id]
        if not cell.is_visible:
            #print("board.show", row_id, col_id)
            cell.show()
            # self.display.show(row_id, col_id)
            if (cell.is_mine and not cell.is_flagged):
                self.is_playing = False
                print("mine'd!")
            elif self.is_solved():
                self.is_playing = False
            elif self.count_surrounding(row_id, col_id) == 0:
                self.showingMultiple = True
                for (surr_row, surr_col) in self.get_neighbours(row_id, col_id):
                    if self.is_in_range(surr_row, surr_col):
                        self.show(surr_row, surr_col)

    def show_all(self):
        for row in self.board:
            for cell in row:
                cell.show()

    def flag(self, row_id, col_id):
        cell = self.board[row_id][col_id]
        if not cell.is_visible:
            cell.flag()
        else:
            print("Cannot add flag, cell already visible.")

    def place_mine(self, row_id, col_id):
        self.board[row_id][col_id].place_mine()

    def count_surrounding(self, row_id, col_id):
        return sum(1 for (surr_row, surr_col) in self.get_neighbours(row_id, col_id)
                        if (self.is_in_range(surr_row, surr_col) and
                            self.board[surr_row][surr_col].is_mine))

    def get_neighbours(self, row_id, col_id):
        SURROUNDING = ((-1, -1), (-1,  0), (-1,  1),
                       (0 , -1),           (0 ,  1),
                       (1 , -1), (1 ,  0), (1 ,  1))
        return ((row_id + surr_row, col_id + surr_col) for (surr_row, surr_col) in SURROUNDING)

    def is_in_range(self, row_id, col_id):
        return 0 <= row_id < len(self.board) and 0 <= col_id < len(self.board[0])

    def remaining_mines(self):
        remaining = 0
        for row in self.board:
            for cell in row:
                if cell.is_mine and not cell.is_visible:
                    remaining += 1
                if cell.is_flagged:
                    remaining -= 1
        return remaining

    def remaining_hidden(self):
        remaining = 0
        for row in self.board:
            for cell in row:
                if not cell.is_visible:
                    remaining += 1
        return remaining

    def set_all_defused(self):
        for row in self.board:
            for cell in row:
                cell.set_defused()
        self.is_playing = False

    def is_solved(self):
        #return all((cell.is_visible or cell.is_flagged) for row in self.board for cell in row)
        #print("Remaining Mines: ", self.remaining_mines(), " Remaining Hidden: ", self.remaining_hidden())
        return self.remaining_mines() == self.remaining_hidden()

    def list_mines(self):
        r = 0
        c = 0
        out = []
        for row in self.board:
            for cell in row:
                if cell.is_mine is True:
                    rowCol = (r, c)
                    out.append(rowCol)
                c += 1
            r += 1
            c = 0
        return out

class Minesweeper():
    def __init__(self, display, audio, rows, cols):
        board = Board()
        mines = random.randint(int(cols*rows*.1), int(cols*rows*.3))
        if mines is 0:
            mines = 1
        print("{:d} mines...".format(mines))
        board.create_board(rows, cols, mines)
        self.board = board
        self.audio = audio
        self.display = display
        self.rows = rows
        self.cols = cols
        self.ended = False
        self.animatingEnd = False
        self.audio.loadSong('BetweenGames1.wav', 'between1')
        self.audio.loadSong('BetweenGames2.wav', 'between2')
        self.audio.loadSong('BetweenGames3.wav', 'between3')
        self.audio.loadSong('BetweenGames4.wav', 'between4')
        self.audio.shuffleSongs()
        #handles events is required to be defined
        self.handlesEvents = False
        self.audio.setSongVolume(0)
        self.songsQuiet = False
        self.firstStep = True
        self.updateBoard(self.board)

        # Confirmed that both sounsd play simultaneously
        # self.audio.playSound('StartUp.wav')
        # self.audio.playSound('Explosion.wav')

    def heartbeat(self, sensorsChanged):
        if self.board.is_playing:
            playSound = True
            for move in sensorsChanged:
                if self.songsQuiet:
                    self.songsQuiet = True
                if self.board.board[move.row][move.col].is_visible:
                    playSound = False
                if self.firstStep and self.board.board[move.row][move.col].is_mine:
                    self.board.board[move.row][move.col].is_mine = False
                    print("Saved from the mine!")
                self.firstStep = False
                self.board.show(move.row, move.col)
                if self.board.board[move.row][move.col].is_mine:
                    self.audio.playSound("Explosion.wav")
                elif playSound:
                    self.audio.playSound("Blop.wav")
                self.lastMove = move
            self.updateBoard(self.board)
        elif not self.board.is_playing and not self.animatingEnd:
            if self.board.is_solved():
                print("Well done! You solved the board!")
                self.endAnim = EndAnimation(True, self.display, (self.lastMove.row, self.lastMove.col), self.board.list_mines())
                self.animatingEnd = True
                self.audio.playSound("Success.wav")
            else:
                #self.audio.playSound("Explosion.wav")
                self.board.show_all()
                self.endAnim = EndAnimation(False, self.display, (self.lastMove.row, self.lastMove.col), self.board.list_mines())
                self.animatingEnd = True
        elif self.animatingEnd:
            frame = self.endAnim.getFrame()
            if frame:
                #update display of each tile
                frame.setFrame()
                wait(1)
            if self.endAnim.ended:
                print("ended")
                self.ended = True
        #push changed tiles to display

    # currently this is just iterating across all the cells in the internal game state and pushing
    # the corresponding shape/color to the display for the given tile's position. a slightly better design would
    # be to only need to push info for the tiles that have actually changed
    def updateBoard(self, board):
        for row in range(0, self.rows):
            for col in range(0, self.cols):
                if board != None:
                    cell = board.getCellState(row, col)
                    if cell == "D":
                        self.display.set(row, col, Shapes.DASH, Colors.MAGENTA)
                    elif cell == '.':
                        self.display.set(row, col, Shapes.ZERO, Colors.GREEN)
                    elif cell == ' ' or cell == '':
                        self.display.set(row, col, Shapes.DASH, Colors.BLACK)
                    elif cell == 'M':
                        self.display.set(row, col, Shapes.ZERO, Colors.RED)
                    elif cell == 'F':
                        break
                    else:
                        self.display.set(row, col, Shapes.digitToHex(int(cell)), Colors.YELLOW)
        return

    def ended(self):
        return self.ended

    if __name__ == "__main__":
        print("Test code goes here")

class EndAnimation:
    def __init__(self, win, display, lastMove, mines):
        self.rows = display.rows
        self.cols = display.cols
        print(self.rows)
        print(self.cols)
        self.ended = False
        self.currentFrame = None
        self.frames = []
        frame = display
        if win:
            frame.setAllColor(Colors.CYAN)
            self.frames.append(frame)

            frame.setAllColor(Colors.BLUE)
            self.frames.append(frame)

            frame.setAllColor(Colors.GREEN)
            self.frames.append(frame)

            frame.setAllColor(Colors.CYAN)
            self.frames.append(frame)

            frame.setAllColor(Colors.BLUE)
            self.frames.append(frame)

            frame.setAllColor(Colors.GREEN)
            self.frames.append(frame)
        else:
            print(mines)
#            groundZero = (Shapes.DASH, Shapes.OFF, Shapes.OFF)
#            redEight = (Shapes.EIGHT, Shapes.OFF, Shapes.OFF)
#            redZero = (Shapes.ZERO, Shapes.OFF, Shapes.OFF)
#            off = (Shapes.OFF, Shapes.OFF, Shapes.OFF)
#            redBottom = (8,0,0)
#            redTop = (64,0,0)
#            redRight = (48,0,0)
#            redLeft = (6,0,0)
#            redRightBottom = (24,0,0)
#            redLeftBottom = (12,0,0)
#            redRightTop = (96,0,0)
#            redLeftTop = (66,0,0)

            losingAnimation = lsanimate.LSAnimation()

            frame = lsexplosion.LSExplosion(self.rows, self.cols, lastMove, mines)

            for frameNum in range(0,50):
                frame.flamefront()
                losingAnimation.addFrame(frame.get())

            losingAnimation.deleteFrame(7) # Because I'm too lazy to do it right
            losingAnimation.deleteFrame(7) # Yes, we need both of these

#            blastRadius = lsanimate.LSFrameGen(display.rows, display.cols)
#            eventHorizon = lsanimate.LSFrameGen(display.rows, display.cols)
#            blastRadius.fill(off)
#            blastRadius.edit(lastMove.row, lastMove.col, groundZero)
#            eventHorizon.fill(redEight)
#            eventHorizon.edit(lastMove.row, lastMove.col, off)
#
#            losingAnimation.addFrame(blastRadius.get())
#            losingAnimation.addFrame(eventHorizon.get())
#
#            blastRadius.edit(lastMove.row, lastMove.col, redZero)
#
#            losingAnimation.addFrame(blastRadius.get())
#            losingAnimation.addFrame(eventHorizon.get())
#
#            blastRadius.edit(lastMove.row, lastMove.col, off)
#            blastRadius.edit(lastMove.row+1, lastMove.col, redTop)
#            blastRadius.edit(lastMove.row-1, lastMove.col, redBottom)
#            blastRadius.edit(lastMove.row, lastMove.col+1, redLeft)
#            blastRadius.edit(lastMove.row, lastMove.col-1, redRight)
#
#            eventHorizon.edit(lastMove.row+1, lastMove.col, off)
#            eventHorizon.edit(lastMove.row-1, lastMove.col, off)
#            eventHorizon.edit(lastMove.row, lastMove.col+1, off)
#            eventHorizon.edit(lastMove.row, lastMove.col-1, off)
#
#            losingAnimation.addFrame(blastRadius.get())
#            losingAnimation.addFrame(eventHorizon.get())

        # Testing
            losingAnimation.play(display)

    def getFrame(self):
        if len(self.frames) is 0:
            self.ended = True
            return None
        if self.currentFrame and self.currentFrame.heartbeats > 0:
            self.currentFrame.heartbeats -= 1
        else:
            self.currentFrame = self.frames.pop()
        return self.currentFrame

def main():
    gameEngine = LSGameEngine(Minesweeper)
    gameEngine.beginLoop()

if __name__ == '__main__':
    main()
<commit_msg>Revert "Revert "fixing list_mines()""<commit_after>#!/usr/bin/python3
from lsgame import LSGameEngine
import lsanimate
import lsexplosion

import Colors
import Shapes

import random
import time

wait=time.sleep

class Cell(object):
    def __init__(self, is_mine, is_visible=False, is_flagged=False):
        self.is_mine = is_mine
        self.is_visible = is_visible
        self.is_flagged = is_flagged
        self.is_defused = False

    def show(self):
        self.is_visible = True

    def flag(self):
        self.is_flagged = not self.is_flagged

    def place_mine(self):
        self.is_mine = True

    def set_defused(self):
        if self.is_mine:
            self.is_defused = True

class Board():

    def __init__(self):
        super().__init__()
        self.is_playing = True

    def create_board(self, rows, cols, mines):
        print("creating board")
        self.board = tuple([tuple([Cell(False) for col in range(cols)])
                            for row in range(rows)])
        available_pos = list(range((rows) * (cols)))
        print("creating mines")
        for i in range(mines):
            new_pos = random.choice(available_pos)
            available_pos.remove(new_pos)
            (row_id, col_id) = random.randint(0, rows-1), random.randint(0, cols-1) #(new_pos // (cols), new_pos % (rows))
            self.place_mine(row_id, col_id)
        self.is_playing = True
        return

    def getCellState(self,row_id, col_id):
        # print ("min_repr for: ",row_id,col_id)
        cell = self.board[row_id][col_id]
        if cell.is_defused:
            return "D"
        elif cell.is_visible:
            if cell.is_mine:
                return "M"
            else:
                surr = self.count_surrounding(row_id, col_id)
                return str(surr) if surr else " "
        elif cell.is_flagged:
            return "F"
        else:
            return "."  #u"\uff18"

    def set_display(self, display):
        print("setting display")
        self.display = display

    def show(self, row_id, col_id):
        self.showingMultiple = False
        #print("given:", row_id, col_id, "board:", len(self.board), len(self.board[0]))
        cell = self.board[row_id][col_id]
        if not cell.is_visible:
            #print("board.show", row_id, col_id)
            cell.show()
            # self.display.show(row_id, col_id)
            if (cell.is_mine and not cell.is_flagged):
                self.is_playing = False
                print("mine'd!")
            elif self.is_solved():
                self.is_playing = False
            elif self.count_surrounding(row_id, col_id) == 0:
                self.showingMultiple = True
                for (surr_row, surr_col) in self.get_neighbours(row_id, col_id):
                    if self.is_in_range(surr_row, surr_col):
                        self.show(surr_row, surr_col)

    def show_all(self):
        for row in self.board:
            for cell in row:
                cell.show()

    def flag(self, row_id, col_id):
        cell = self.board[row_id][col_id]
        if not cell.is_visible:
            cell.flag()
        else:
            print("Cannot add flag, cell already visible.")

    def place_mine(self, row_id, col_id):
        self.board[row_id][col_id].place_mine()

    def count_surrounding(self, row_id, col_id):
        return sum(1 for (surr_row, surr_col) in self.get_neighbours(row_id, col_id)
                        if (self.is_in_range(surr_row, surr_col) and
                            self.board[surr_row][surr_col].is_mine))

    def get_neighbours(self, row_id, col_id):
        SURROUNDING = ((-1, -1), (-1,  0), (-1,  1),
                       (0 , -1),           (0 ,  1),
                       (1 , -1), (1 ,  0), (1 ,  1))
        return ((row_id + surr_row, col_id + surr_col) for (surr_row, surr_col) in SURROUNDING)

    def is_in_range(self, row_id, col_id):
        return 0 <= row_id < len(self.board) and 0 <= col_id < len(self.board[0])

    def remaining_mines(self):
        remaining = 0
        for row in self.board:
            for cell in row:
                if cell.is_mine and not cell.is_visible:
                    remaining += 1
                if cell.is_flagged:
                    remaining -= 1
        return remaining

    def remaining_hidden(self):
        remaining = 0
        for row in self.board:
            for cell in row:
                if not cell.is_visible:
                    remaining += 1
        return remaining

    def set_all_defused(self):
        for row in self.board:
            for cell in row:
                cell.set_defused()
        self.is_playing = False

    def is_solved(self):
        #return all((cell.is_visible or cell.is_flagged) for row in self.board for cell in row)
        #print("Remaining Mines: ", self.remaining_mines(), " Remaining Hidden: ", self.remaining_hidden())
        return self.remaining_mines() == self.remaining_hidden()

    def list_mines(self):
        r = 0
        c = 0
        out = []
        for row in self.board:
            for cell in row:
                if cell.is_mine is True:
                    rowCol = (r, c)
                    out.append(rowCol)
                c += 1
            r += 1
            c = 0
        return out

class Minesweeper():
    def __init__(self, display, audio, rows, cols):
        board = Board()
        mines = random.randint(int(cols*rows*.1), int(cols*rows*.3))
        if mines is 0:
            mines = 1
        print("{:d} mines...".format(mines))
        board.create_board(rows, cols, mines)
        self.board = board
        self.audio = audio
        self.display = display
        self.rows = rows
        self.cols = cols
        self.ended = False
        self.animatingEnd = False
        self.audio.loadSong('BetweenGames1.wav', 'between1')
        self.audio.loadSong('BetweenGames2.wav', 'between2')
        self.audio.loadSong('BetweenGames3.wav', 'between3')
        self.audio.loadSong('BetweenGames4.wav', 'between4')
        self.audio.shuffleSongs()
        #handles events is required to be defined
        self.handlesEvents = False
        self.audio.setSongVolume(0)
        self.songsQuiet = False
        self.firstStep = True
        self.updateBoard(self.board)

        # Confirmed that both sounsd play simultaneously
        # self.audio.playSound('StartUp.wav')
        # self.audio.playSound('Explosion.wav')

    def heartbeat(self, sensorsChanged):
        if self.board.is_playing:
            playSound = True
            for move in sensorsChanged:
                if self.songsQuiet:
                    self.songsQuiet = True
                if self.board.board[move.row][move.col].is_visible:
                    playSound = False
                if self.firstStep and self.board.board[move.row][move.col].is_mine:
                    self.board.board[move.row][move.col].is_mine = False
                    print("Saved from the mine!")
                self.firstStep = False
                self.board.show(move.row, move.col)
                if self.board.board[move.row][move.col].is_mine:
                    self.audio.playSound("Explosion.wav")
                elif playSound:
                    self.audio.playSound("Blop.wav")
                self.lastMove = move
            self.updateBoard(self.board)
        elif not self.board.is_playing and not self.animatingEnd:
            if self.board.is_solved():
                print("Well done! You solved the board!")
                self.endAnim = EndAnimation(True, self.display, (self.lastMove.row, self.lastMove.col), self.board.list_mines())
                self.animatingEnd = True
                self.audio.playSound("Success.wav")
            else:
                #self.audio.playSound("Explosion.wav")
                self.board.show_all()
                self.endAnim = EndAnimation(False, self.display, (self.lastMove.row, self.lastMove.col), self.board.list_mines())
                self.animatingEnd = True
        elif self.animatingEnd:
            EndAnimation.animation.play(self.display)
            if self.endAnim.ended:
                print("ended")
                self.ended = True
        #push changed tiles to display

    # currently this is just iterating across all the cells in the internal game state and pushing
    # the corresponding shape/color to the display for the given tile's position. a slightly better design would
    # be to only need to push info for the tiles that have actually changed
    def updateBoard(self, board):
        for row in range(0, self.rows):
            for col in range(0, self.cols):
                if board != None:
                    cell = board.getCellState(row, col)
                    if cell == "D":
                        self.display.set(row, col, Shapes.DASH, Colors.MAGENTA)
                    elif cell == '.':
                        self.display.set(row, col, Shapes.ZERO, Colors.GREEN)
                    elif cell == ' ' or cell == '':
                        self.display.set(row, col, Shapes.DASH, Colors.BLACK)
                    elif cell == 'M':
                        self.display.set(row, col, Shapes.ZERO, Colors.RED)
                    elif cell == 'F':
                        break
                    else:
                        self.display.set(row, col, Shapes.digitToHex(int(cell)), Colors.YELLOW)
        return

    def ended(self):
        return self.ended

    if __name__ == "__main__":
        print("Test code goes here")

class EndAnimation:
    def __init__(self, win, display, lastMove, mines):
        self.rows = display.rows
        self.cols = display.cols
        print(self.rows)
        print(self.cols)
        self.ended = False
        self.currentFrame = None
        self.frames = []
        frame = display
        if win:
            redDash = (1, 0, 0)
            greenDash = (0, 1, 0)
            blueDash = (0, 0, 126)

            winningAnimation = lsanimate.LSAnimation()

            frame = lsanimate.LSFrameGen(3,3)

            for _ in range(0,100):
                for i in range(0,3):
                    frame.edit(0,i,redDash)
                    frame.edit(1,i,greenDash)
                    frame.edit(2,i,blueDash)
                winningAnimation.addFrame(frame.get())
                for i in range(0,3):
                    frame.edit(0,i,redDash)
                    frame.edit(1,i,greenDash)
                    frame.edit(2,i,blueDash)
                winningAnimation.addFrame(frame.get())
                for i in range(0,3):
                    frame.edit(0,i,redDash)
                    frame.edit(1,i,greenDash)
                    frame.edit(2,i,blueDash)
                winningAnimation.addFrame(frame.get())

                self.animation = winningAnimation

        else:

            losingAnimation = lsanimate.LSAnimation()

            frame = lsexplosion.LSExplosion(self.rows, self.cols, lastMove, mines)

            for frameNum in range(0,50):
                frame.flamefront()
                losingAnimation.addFrame(frame.get())

            losingAnimation.deleteFrame(7) # Because I'm too lazy to do it right
            losingAnimation.deleteFrame(7) # Yes, we need both of these

            self.animation = losingAnimation

    def getFrame(self):
        if len(self.frames) is 0:
            self.ended = True
            return None
        if self.currentFrame and self.currentFrame.heartbeats > 0:
            self.currentFrame.heartbeats -= 1
        else:
            self.currentFrame = self.frames.pop()
        return self.currentFrame

def main():
    gameEngine = LSGameEngine(Minesweeper)
    gameEngine.beginLoop()

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


<commit_before>#!/usr/bin/python

# Author:      Marco Squarcina <lavish@gmail.com>
# License:     MIT, see LICENSE for details

import getopt, os, sys
import string, codecs, re

try:
	import markdown
except ImportError:
	sys.stderr.write("Module markdown not found.\n")
try:
	import textile
except ImportError:
	sys.stderr.write("Module textile not found.\n")

# class definition

class Node(object):
	def __init__(self, src_pathname, parent = None):
		self.src_pathname = src_pathname
		self.dst_pathname = get_dst_pathname(src_pathname)
		self.src_file = os.path.basename(self.src_pathname)
		self.dst_file = os.path.basename(self.dst_pathname)
		self.name = get_name(self.dst_pathname)
		self.parent = parent
		self.children = []

	def add_child(self, obj):
		self.children.append(obj)

# functions definition

def syntax(pathname):
	"""Returns the markup language used in the given pathname."""

	for lang in template.src_ext.keys():
		if(template.src_ext[lang] == pathname.split('.')[-1]):
				return lang
	return ''

def hasindex(pathname):
	"""Check if there's an index file in the given directory pathname."""

	for lang in template.src_ext.keys():
		if(os.path.isfile(pathname + "/index." + template.src_ext[lang])):
			return True
	return False

def get_dst_pathname(src_pathname):
	"""Get destionation pathname from source pathname."""

	# replace extension
	dst_pathname = os.path.splitext(src_pathname)
	if dst_pathname[1]:
		dst_pathname = os.path.join(dst_pathname[0] + '.' + template.dst_ext)
	dst_pathname = ''.join(dst_pathname)
	# change destination dir
	dst_pathname = string.join(template.dst_dir.split('/') + dst_pathname.split('/')[len(template.src_dir.split('/')):], '/')
	# remove index numbers for dirs and files
	return re.sub('\/\d+_', '/', dst_pathname)

def get_name(dst_pathname):
	"""Get page name from destionation pathname."""

	name = os.path.basename(dst_pathname)
	name = os.path.splitext(name)[0]
	return name.replace('_', ' ')

def menu(node):
	"""Given a node, returns a multine string of the menu code."""

	menu = "
\n"
	for n in sorted(node.parent.children, key=lambda n: n.src_pathname):
		# and index page or a hidden file, no need to include them
		if(n.dst_file.startswith("index.")
		or n.src_file in template.hidden):
			continue
		# a page
		elif not n.children:
			menu += '\t
' + n.name + '
\n'
		# a directory
		else:
			menu += '\t
'
			menu += n.name + '
\n'
	menu += "
"
	return menu

def path(node):
	"""Given a node, returns a string of the breadcrumb navigation path code."""

	# a bit dirty... there's space for improvements
	path = ""
	path_list = []
	j = 0
	while node.parent:
		path_list.append(node.name)
		node = node.parent
	path_list.append(template.home)
	if path_list[0] == "index":
		path_list.remove("index")
	else:
		j = -1
	for i in range(len(path_list)-1, -1, -1):
		if i == 0:
			path += path_list[i]
		else:
			path += ''
			path += path_list[i]
			path += ' ' + template.path_separator + ' '
	return path

def write_page(node):
	"""Given a node, write on the file system its corresponding page."""

	# open source file
	h_src_pathname = codecs.open(node.src_pathname, "r", "utf-8");
	src_content = h_src_pathname.read()
	h_src_pathname.close()
	# build page
	dst_content = template.header(node)
	if(syntax(node.src_pathname) == "markdown"
	and "markdown" in template.src_ext):
		dst_content += markdown.markdown(src_content)
	elif(syntax(node.src_pathname) == "textile"
	and "textile" in template.src_ext):
		dst_content += textile.textile(src_content)
	dst_content += template.footer(node)
	dst_content = dst_content.replace("%%%PATH%%%", path(node))
	dst_content = dst_content.replace("%%%MENU%%%", menu(node))
	# write destionation file
	h_dst_pathname = codecs.open(node.dst_pathname, "w", "utf-8")
	h_dst_pathname.write(dst_content)
	h_dst_pathname.close()

def build_tree(node):
	"""Given a node, recursively create a tree representing the sources file
	hierarchy starting from that node."""

	for file in os.listdir(node.src_pathname):
		pathname = os.path.join(node.src_pathname, file)
		# do not add nodes for links and files starting with '.'
		if(os.path.islink(pathname)
		or file[0] == "."):
			continue
		# add nodes for files with an allowed extension
		elif(os.path.isfile(pathname) and syntax(pathname)):
			node.add_child(Node(pathname, node))
		# add nodes for directories and go on building the tree
		elif(os.path.isdir(pathname) and hasindex(pathname)):
			node.add_child(Node(pathname, node))
			# -1 used to specify the last added node
			build_tree(node.children[-1])

def write_tree(node, margin = ''):
	"""Given a node, recursively write all the corresponding pages on the file
	system."""

	# a directory
	if node.children:
		# create the destination dir, if possible
		try:
			os.makedirs(node.dst_pathname)
		except OSError:
			pass
		else:
			print margin + "creating -> " + node.dst_pathname
		# recursivly call write_tree against current node
		for nodes in node.children:
			write_tree(nodes, margin + '    ')
	# a file
	else:
		print margin + "writing  -> " + node.dst_pathname
		write_page(node)

def main():
	global template

	# set default arguments
	src_dir = dst_dir = None
	template_module = 'templates.default'
	# parse options
	try:
		opts, args = getopt.getopt(sys.argv[1:], "ht:s:d:v", ["help", "template=", "src_dir=", "dst_dir=", "version"])
	except getopt.GetoptError, err:
		sys.stderr.write('Incorrect usage, see -h for help\n')
		sys.exit(1)
	for o, a in opts:
		if o in ("-v", "--version"):
			print 'Version foo'
			sys.exit(0)
		elif o in ("-h", "--help"):
			print 'Usage: minimalsite.py [source_dir [destination_dir]]'
			sys.exit(0)
		elif o in ("-t", "--template"):
			template_module = 'templates.' + a
		elif o in ("-s", "--src_dir"):
			src_dir = a
		elif o in ("-d", "--dst_dir"):
			dst_dir = a
		else:
			assert False, "unhandled option"
	# load template
	__import__(template_module)
	template = sys.modules[template_module]
	# check markup modules
	if not sys.modules['markdown']:
		del template.src_ext['markdown']
	if not sys.modules['textile']:
		del template.src_ext['textile']
	if not template.src_ext:
		sys.stderr.write("No modules for parsing files found. See README for requirements\n")
		sys.exit(3)
	# check src and dst directories
	if src_dir:
		template.src_dir = os.path.abspath(src_dir)
	if dst_dir:
		template.dst_dir = os.path.abspath(dst_dir)
	if not os.path.isdir(template.src_dir):
		sys.stderr.write('"' + template.src_dir + '" is not a directory, aborting\n')
		sys.exit(2)
	if not os.path.isdir(template.dst_dir):
		sys.stderr.write('"' + template.dst_dir + '" is not a directory, aborting\n')
		sys.exit(2)
	# start writing the site
	print 'Processing files in "' + template.src_dir + '":\n'
	root = Node(template.src_dir)
	build_tree(root)
	write_tree(root)
	print '\n... Done!'

if __name__ == "__main__":
    main()
<commit_msg>Fixed usage output<commit_after>#!/usr/bin/python

# Author:      Marco Squarcina <lavish@gmail.com>
# License:     MIT, see LICENSE for details

import getopt, os, sys
import string, codecs, re

try:
	import markdown
except ImportError:
	sys.stderr.write("Module markdown not found.\n")
try:
	import textile
except ImportError:
	sys.stderr.write("Module textile not found.\n")

# class definition

class Node(object):
	def __init__(self, src_pathname, parent = None):
		self.src_pathname = src_pathname
		self.dst_pathname = get_dst_pathname(src_pathname)
		self.src_file = os.path.basename(self.src_pathname)
		self.dst_file = os.path.basename(self.dst_pathname)
		self.name = get_name(self.dst_pathname)
		self.parent = parent
		self.children = []

	def add_child(self, obj):
		self.children.append(obj)

# functions definition

def syntax(pathname):
	"""Returns the markup language used in the given pathname."""

	for lang in template.src_ext.keys():
		if(template.src_ext[lang] == pathname.split('.')[-1]):
				return lang
	return ''

def hasindex(pathname):
	"""Check if there's an index file in the given directory pathname."""

	for lang in template.src_ext.keys():
		if(os.path.isfile(pathname + "/index." + template.src_ext[lang])):
			return True
	return False

def get_dst_pathname(src_pathname):
	"""Get destionation pathname from source pathname."""

	# replace extension
	dst_pathname = os.path.splitext(src_pathname)
	if dst_pathname[1]:
		dst_pathname = os.path.join(dst_pathname[0] + '.' + template.dst_ext)
	dst_pathname = ''.join(dst_pathname)
	# change destination dir
	dst_pathname = string.join(template.dst_dir.split('/') + dst_pathname.split('/')[len(template.src_dir.split('/')):], '/')
	# remove index numbers for dirs and files
	return re.sub('\/\d+_', '/', dst_pathname)

def get_name(dst_pathname):
	"""Get page name from destionation pathname."""

	name = os.path.basename(dst_pathname)
	name = os.path.splitext(name)[0]
	return name.replace('_', ' ')

def menu(node):
	"""Given a node, returns a multine string of the menu code."""

	menu = "
\n"
	for n in sorted(node.parent.children, key=lambda n: n.src_pathname):
		# and index page or a hidden file, no need to include them
		if(n.dst_file.startswith("index.")
		or n.src_file in template.hidden):
			continue
		# a page
		elif not n.children:
			menu += '\t
' + n.name + '
\n'
		# a directory
		else:
			menu += '\t
'
			menu += n.name + '
\n'
	menu += "
"
	return menu

def path(node):
	"""Given a node, returns a string of the breadcrumb navigation path code."""

	# a bit dirty... there's space for improvements
	path = ""
	path_list = []
	j = 0
	while node.parent:
		path_list.append(node.name)
		node = node.parent
	path_list.append(template.home)
	if path_list[0] == "index":
		path_list.remove("index")
	else:
		j = -1
	for i in range(len(path_list)-1, -1, -1):
		if i == 0:
			path += path_list[i]
		else:
			path += ''
			path += path_list[i]
			path += ' ' + template.path_separator + ' '
	return path

def write_page(node):
	"""Given a node, write on the file system its corresponding page."""

	# open source file
	h_src_pathname = codecs.open(node.src_pathname, "r", "utf-8");
	src_content = h_src_pathname.read()
	h_src_pathname.close()
	# build page
	dst_content = template.header(node)
	if(syntax(node.src_pathname) == "markdown"
	and "markdown" in template.src_ext):
		dst_content += markdown.markdown(src_content)
	elif(syntax(node.src_pathname) == "textile"
	and "textile" in template.src_ext):
		dst_content += textile.textile(src_content)
	dst_content += template.footer(node)
	dst_content = dst_content.replace("%%%PATH%%%", path(node))
	dst_content = dst_content.replace("%%%MENU%%%", menu(node))
	# write destionation file
	h_dst_pathname = codecs.open(node.dst_pathname, "w", "utf-8")
	h_dst_pathname.write(dst_content)
	h_dst_pathname.close()

def build_tree(node):
	"""Given a node, recursively create a tree representing the sources file
	hierarchy starting from that node."""

	for file in os.listdir(node.src_pathname):
		pathname = os.path.join(node.src_pathname, file)
		# do not add nodes for links and files starting with '.'
		if(os.path.islink(pathname)
		or file[0] == "."):
			continue
		# add nodes for files with an allowed extension
		elif(os.path.isfile(pathname) and syntax(pathname)):
			node.add_child(Node(pathname, node))
		# add nodes for directories and go on building the tree
		elif(os.path.isdir(pathname) and hasindex(pathname)):
			node.add_child(Node(pathname, node))
			# -1 used to specify the last added node
			build_tree(node.children[-1])

def write_tree(node, margin = ''):
	"""Given a node, recursively write all the corresponding pages on the file
	system."""

	# a directory
	if node.children:
		# create the destination dir, if possible
		try:
			os.makedirs(node.dst_pathname)
		except OSError:
			pass
		else:
			print margin + "creating -> " + node.dst_pathname
		# recursivly call write_tree against current node
		for nodes in node.children:
			write_tree(nodes, margin + '    ')
	# a file
	else:
		print margin + "writing  -> " + node.dst_pathname
		write_page(node)

def main():
	global template

	# set default arguments
	src_dir = dst_dir = None
	template_module = 'templates.default'
	# parse options
	try:
		opts, args = getopt.getopt(sys.argv[1:], "ht:s:d:v", ["help", "template=", "src_dir=", "dst_dir=", "version"])
	except getopt.GetoptError, err:
		sys.stderr.write('Incorrect usage, see -h for help\n')
		sys.exit(1)
	for o, a in opts:
		if o in ("-v", "--version"):
			print 'minimalsite-0.5 by Marco Squarcina, see LICENSE for details'
			sys.exit(0)
		elif o in ("-h", "--help"):
			print 'Usage: minimalsite.py [-v|--version] [-t|--template template] [-s|--src_dir source_dir] [-d|--dst_dir destination_dir]'
			sys.exit(0)
		elif o in ("-t", "--template"):
			template_module = 'templates.' + a
		elif o in ("-s", "--src_dir"):
			src_dir = a
		elif o in ("-d", "--dst_dir"):
			dst_dir = a
		else:
			assert False, "unhandled option"
	# load template
	__import__(template_module)
	template = sys.modules[template_module]
	# check markup modules
	if not sys.modules['markdown']:
		del template.src_ext['markdown']
	if not sys.modules['textile']:
		del template.src_ext['textile']
	if not template.src_ext:
		sys.stderr.write("No modules for parsing files found. See README for requirements\n")
		sys.exit(3)
	# check src and dst directories
	if src_dir:
		template.src_dir = os.path.abspath(src_dir)
	if dst_dir:
		template.dst_dir = os.path.abspath(dst_dir)
	if not os.path.isdir(template.src_dir):
		sys.stderr.write('"' + template.src_dir + '" is not a directory, aborting\n')
		sys.exit(2)
	if not os.path.isdir(template.dst_dir):
		sys.stderr.write('"' + template.dst_dir + '" is not a directory, aborting\n')
		sys.exit(2)
	# start writing the site
	print 'Processing files in "' + template.src_dir + '":\n'
	root = Node(template.src_dir)
	build_tree(root)
	write_tree(root)
	print '\n... Done!'

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


<commit_before>#
# Copyright (c) 2005-2008 rPath, Inc.
#
# All rights reserved
#

import re, os, sys
import pwd
from mint import config
from mint import projects
from mint import schema
from conary.lib import util
from conary import dbstore
from conary import versions
import conary.errors
import conary.server.schema
from conary.conaryclient import cmdline

schemaCutoff = 37
knownGroupVersions = ('3\.1\.(\d{2}|[56789])(\.\d+)?$', '4\..*')

staticPaths = ['config', 'logs', 'installable_iso.conf',
               'toolkit', 'iso_gen.conf', 'live_iso.conf',
               'bootable_image.conf']
# toolkit is linked to outgoing job server architecture.

def backup(cfg, out, backupMirrors = False):
    reposContentsDir = cfg.reposContentsDir.split(' ')
    backupPath = os.path.join(cfg.dataPath, 'tmp', 'backup')
    print >> out, backupPath
    util.mkdirChain(backupPath)
    dumpPath = os.path.join(backupPath, 'db.dump')
    if cfg.dbDriver == 'sqlite':
        util.execute("echo '.dump' | sqlite3 %s > %s" % (cfg.dbPath, dumpPath))
    extraArgs = ""
    if not backupMirrors:
        extraArgs = " WHERE NOT external OR backupExternal"
    if cfg.reposDBDriver == 'sqlite':
        db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
        cu = db.cursor()
        cu.execute("SELECT hostname, domainname FROM Projects%s" % extraArgs)
        for reposDir in ['.'.join(x) for x in cu.fetchall()]:
            cu.execute("SELECT toName FROM RepNameMap WHERE fromName=?",
                    reposDir)
            res = cu.fetchone()
            reposDir = res and res[0] or reposDir
            reposDBPath = cfg.reposDBPath % reposDir
            dumpPath = os.path.join(backupPath, '%s.dump' % reposDir)
            if os.path.exists(reposDBPath):
                util.execute("echo '.dump' | sqlite3 %s > %s" % \
                              (reposDBPath, dumpPath))
                print >> out, reposContentsDir[0] % reposDir
    elif cfg.reposDBDriver == 'postgresql':
        db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
        cu = db.cursor()
        cu.execute("SELECT hostname, domainname FROM Projects%s" % extraArgs)
        for reposDir in ['.'.join(x) for x in cu.fetchall()]:
            reposDbName = reposDir.translate(projects.transTables['postgresql'])
            dbUser = cfg.reposDBPath.split('@')[0]
            dumpPath = os.path.join(backupPath, '%s.dump' % reposDbName)
            rdb = dbstore.connect(cfg.reposDBPath % 'postgres', 'postgresql')
            rcu = rdb.cursor()
            rcu.execute("SELECT datname FROM pg_database WHERE datname=?",
                         reposDbName)
            if rcu.fetchone():
                util.execute("pg_dump -U %s -c -O -d %s > %s" %\
                             (dbUser, reposDbName, dumpPath))
                print >> out, reposContentsDir[0] % reposDir
            rdb.close()

    for d in staticPaths:
        path = os.path.join(cfg.dataPath, d)
        if os.path.exists(path):
            print >> out, path

    # Handle configs separately so we can exclude rbuilder.conf
    backup_path = os.path.join(cfg.dataPath, 'config')
    if os.path.exists(backup_path):
        for config_file in os.listdir(backup_path):
            if config_file != 'rbuilder.conf':
                path = os.path.join(backup_path, config_file)
                print >> out, path

def restore(cfg):
    backupPath = os.path.join(cfg.dataPath, 'tmp', 'backup')
    dumpPath = os.path.join(backupPath, 'db.dump')
    if cfg.dbDriver == 'sqlite':
        if os.path.exists(cfg.dbPath):
            os.unlink(cfg.dbPath)
        util.execute("sqlite3 %s < %s" % (cfg.dbPath, dumpPath))
    db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
    schema.loadSchema(db, cfg, should_migrate=True)
    cu = db.cursor()
    cu.execute("SELECT hostname, domainname, projectId FROM Projects")
    for hostname, domainname, projectId in [x for x in cu.fetchall()]:
        repo = hostname + '.' + domainname
        cu.execute('SELECT toName FROM RepNameMap WHERE fromName=?', repo)
        r = cu.fetchone()
        if r:
            repo = r[0]
        dumpPath =  os.path.join(backupPath, repo).translate(projects.transTables[cfg.reposDBDriver]) + '.dump'
        reposPath = os.path.join(cfg.reposPath, repo)
        if os.path.exists(dumpPath):
            util.mkdirChain(os.path.join(reposPath, 'tmp'))
            if cfg.reposDBDriver == 'sqlite':
                dbPath = cfg.reposDBPath % repo
                if os.path.exists(dbPath):
                    os.unlink(dbPath)
                util.execute('sqlite3 %s < %s' % (dbPath, dumpPath))
                rdb = dbstore.connect(dbPath, cfg.reposDBDriver)
                conary.server.schema.loadSchema(rdb, doMigrate=True)
                rdb.close()
            elif cfg.reposDBDriver == 'postgresql':
                pgRepo = repo.translate(projects.transTables['postgresql'])
                dbPath = cfg.reposDBPath % pgRepo
                rdb = dbstore.connect('%s' % (cfg.reposDBPath % 'postgres'),
                                      cfg.reposDBDriver)
                rcu = rdb.cursor()
                rcu.execute("SELECT datname FROM pg_database WHERE datname=?",
                             pgRepo)
                if rcu.fetchone():
                    rcu.execute("DROP DATABASE %s" % pgRepo)
                    rcu.execute("CREATE DATABASE %s ENCODING 'UTF8'" % pgRepo)
                rdb.close()

                dbUser = cfg.reposDBPath.split('@')[0]
                util.execute('cat %s | psql -U %s %s'% (dumpPath, dbUser, pgRepo))
                rdb = dbstore.connect('%s' % (cfg.reposDBPath % 'postgres'),
                                      cfg.reposDBDriver)
                conary.server.schema.loadSchema(rdb, doMigrate=True)
                rdb.close()
        else:
            cu.execute("SELECT * FROM InboundMirrors WHERE targetProjectId=?", projectId)
            localMirror = cu.fetchone_dict()
            if localMirror:
                if not os.path.exists(reposPath):
                    # revert Labels table to pre-mirror settings
                    cu.execute( \
                            "UPDATE Labels SET url=?, username=?, password=?" \
                                " WHERE projectId=?",
                        localMirror['sourceUrl'],
                        localMirror['sourceUsername'],
                        localMirror['sourcePassword'], projectId)

                    cu.execute("DELETE FROM RepNameMap WHERE toName=?", repo)
                    cu.execute( \
                        "DELETE FROM InboundMirrors WHERE inboundMirrorId=?",
                        localMirror['inboundMirrorId'])

    # delete package index to ensure we don't reference troves until they're
    # restored.
    try:
        cu.execute('DELETE FROM PackageIndex')
        cu.execute('DELETE FROM PackageIndexMark')
    except:
        # this masks errors, since it does re-raise but we don't care.
        # impact and cost are negligible.
        db.rollback()
    else:
        db.commit()

def prerestore(cfg):
    util.execute("service httpd stop")
    for repo in os.listdir(cfg.reposPath):
        reposPath = os.path.join(cfg.reposPath, repo)
        util.rmtree(reposPath, ignore_errors = True)

def clean(cfg):
    backupPath = os.path.join(cfg.dataPath, 'tmp', 'backup')
    util.rmtree(backupPath, ignore_errors = True)

def metadata(cfg, out):
    db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
    cu = db.cursor()
    cu.execute("SELECT COALESCE(MAX(version), 0) FROM DatabaseVersion")
    schemaVersion = cu.fetchone()[0]
    print >> out, "rBuilder_schemaVersion=%d" % schemaVersion
    cu.execute("SELECT COALESCE(MAX(minor), 0) FROM DatabaseVersion")
    schemaMinor = cu.fetchone()[0]
    print >> out, "rBuilder_schemaMinor=%d" % schemaMinor
    sys.stdout.flush()

# XXX This version is used internally since our handler expects
#     an exception, while rAPA expects a True/False return.
def _isValid(cfg, input):
    if not isValid(cfg, input):
        raise RuntimeError("Invalid Backup")

def isValid(cfg, input):
    data = input.read()
    metaData = dict()
    for x in data.splitlines():
        if '=' in x:
           k, v = x.split('=', 1)
           metaData[k] = v
    schemaVersion = int(metaData.get('rBuilder_schemaVersion', 0))
    if schemaVersion == 0 or schemaVersion < schemaCutoff:
        return False
    NVF = metaData.get('NVF')
    if not NVF:
        return False
    verStr = cmdline.parseTroveSpec(NVF)[1]
    try:
        trailingVer = versions.VersionFromString(verStr).trailingRevision().version
    except conary.errors.ParseError:
        return False
    foundMatch = False
    for pat in knownGroupVersions:
        if re.match(pat, trailingVer):
            foundMatch = True
            break
    return foundMatch

def usage(out = sys.stderr):
    print >> out, sys.argv[0] + ":"
    print >> out, "    [b/backup]: back up databases and issue manifest."
    print >> out, "    [r/restore]: restore databases."
    print >> out, "    [c/clean]: clean up temporary files used during backup."
    print >> out, "    [m/metadata]: print appliance metadata in name=value format."
    print >> out, "    [isValid]: determine if metadata on stdin is for a compatible backup."
    print >> out, "    [prerestore]: prepare to restore databases."

def handle(func, *args, **kwargs):
    errno = 0
    if kwargs.pop('dropPriv', True):
        apacheUID, apacheGID = pwd.getpwnam('apache')[2:4]
        os.setgid(apacheGID)
        os.setuid(apacheUID)
    try:
        func(*args, **kwargs)
    except:
        exception, e, bt = sys.exc_info()
        if exception in (OSError, IOError):
            errno = e.errno
        else:
            errno = 1
        import traceback
        print >> sys.stderr, ''.join(traceback.format_tb(bt))
        print >> sys.stderr, exception, e
    sys.exit(errno)

def run():
    cfg = config.MintConfig()
    cfg.read(config.RBUILDER_CONFIG)
    migration = bool(os.getenv('RBA_MIGRATION'))
    mode = (len(sys.argv) > 1) and sys.argv[1] or ''
    if mode in ('r', 'restore'):
        handle(restore, cfg)
    elif mode  == 'prerestore':
        handle(prerestore, cfg, dropPriv = False)
    elif mode in ('b', 'backup'):
        handle(backup, cfg, sys.stdout, backupMirrors = migration)
    elif mode in ('c', 'clean'):
        handle(clean, cfg)
    elif mode in ('m', 'metadata'):
        handle(metadata, cfg, sys.stdout)
    elif mode == 'isValid':
        handle(_isValid, cfg, sys.stdin)
    elif mode.upper() in ('?', 'H', 'HELP'):
        usage(out = sys.stdout)
    else:
        usage()

<commit_msg>Branch merge<commit_after>#
# Copyright (c) 2005-2008 rPath, Inc.
#
# All rights reserved
#

import re, os, sys
import pwd
from mint import config
from mint import projects
from mint import schema
from conary.lib import util
from conary import dbstore
from conary import versions
import conary.errors
import conary.server.schema
from conary.conaryclient import cmdline

schemaCutoff = 37
knownGroupVersions = ('3\.1\.(\d{2}|[56789])(\.\d+)?$', '4\..*')

staticPaths = ['logs', 'installable_iso.conf',
               'toolkit', 'iso_gen.conf', 'live_iso.conf',
               'bootable_image.conf']
# toolkit is linked to outgoing job server architecture.

def backup(cfg, out, backupMirrors = False):
    reposContentsDir = cfg.reposContentsDir.split(' ')
    backupPath = os.path.join(cfg.dataPath, 'tmp', 'backup')
    print >> out, backupPath
    util.mkdirChain(backupPath)
    dumpPath = os.path.join(backupPath, 'db.dump')
    if cfg.dbDriver == 'sqlite':
        util.execute("echo '.dump' | sqlite3 %s > %s" % (cfg.dbPath, dumpPath))
    extraArgs = ""
    if not backupMirrors:
        extraArgs = " WHERE NOT external OR backupExternal"
    if cfg.reposDBDriver == 'sqlite':
        db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
        cu = db.cursor()
        cu.execute("SELECT hostname, domainname FROM Projects%s" % extraArgs)
        for reposDir in ['.'.join(x) for x in cu.fetchall()]:
            cu.execute("SELECT toName FROM RepNameMap WHERE fromName=?",
                    reposDir)
            res = cu.fetchone()
            reposDir = res and res[0] or reposDir
            reposDBPath = cfg.reposDBPath % reposDir
            dumpPath = os.path.join(backupPath, '%s.dump' % reposDir)
            if os.path.exists(reposDBPath):
                util.execute("echo '.dump' | sqlite3 %s > %s" % \
                              (reposDBPath, dumpPath))
                print >> out, reposContentsDir[0] % reposDir
    elif cfg.reposDBDriver == 'postgresql':
        db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
        cu = db.cursor()
        cu.execute("SELECT hostname, domainname FROM Projects%s" % extraArgs)
        for reposDir in ['.'.join(x) for x in cu.fetchall()]:
            reposDbName = reposDir.translate(projects.transTables['postgresql'])
            dbUser = cfg.reposDBPath.split('@')[0]
            dumpPath = os.path.join(backupPath, '%s.dump' % reposDbName)
            rdb = dbstore.connect(cfg.reposDBPath % 'postgres', 'postgresql')
            rcu = rdb.cursor()
            rcu.execute("SELECT datname FROM pg_database WHERE datname=?",
                         reposDbName)
            if rcu.fetchone():
                util.execute("pg_dump -U %s -c -O -d %s > %s" %\
                             (dbUser, reposDbName, dumpPath))
                print >> out, reposContentsDir[0] % reposDir
            rdb.close()

    for d in staticPaths:
        path = os.path.join(cfg.dataPath, d)
        if os.path.exists(path):
            print >> out, path

    # Handle configs separately so we can exclude rbuilder.conf
    backup_path = os.path.join(cfg.dataPath, 'config')
    if os.path.exists(backup_path):
        for config_file in os.listdir(backup_path):
            if config_file != 'rbuilder.conf':
                path = os.path.join(backup_path, config_file)
                print >> out, path

def restore(cfg):
    backupPath = os.path.join(cfg.dataPath, 'tmp', 'backup')
    dumpPath = os.path.join(backupPath, 'db.dump')
    if cfg.dbDriver == 'sqlite':
        if os.path.exists(cfg.dbPath):
            os.unlink(cfg.dbPath)
        util.execute("sqlite3 %s < %s" % (cfg.dbPath, dumpPath))
    db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
    schema.loadSchema(db, cfg, should_migrate=True)
    cu = db.cursor()
    cu.execute("SELECT hostname, domainname, projectId FROM Projects")
    for hostname, domainname, projectId in [x for x in cu.fetchall()]:
        repo = hostname + '.' + domainname
        cu.execute('SELECT toName FROM RepNameMap WHERE fromName=?', repo)
        r = cu.fetchone()
        if r:
            repo = r[0]
        dumpPath =  os.path.join(backupPath, repo).translate(projects.transTables[cfg.reposDBDriver]) + '.dump'
        reposPath = os.path.join(cfg.reposPath, repo)
        if os.path.exists(dumpPath):
            util.mkdirChain(os.path.join(reposPath, 'tmp'))
            if cfg.reposDBDriver == 'sqlite':
                dbPath = cfg.reposDBPath % repo
                if os.path.exists(dbPath):
                    os.unlink(dbPath)
                util.execute('sqlite3 %s < %s' % (dbPath, dumpPath))
                rdb = dbstore.connect(dbPath, cfg.reposDBDriver)
                conary.server.schema.loadSchema(rdb, doMigrate=True)
                rdb.close()
            elif cfg.reposDBDriver == 'postgresql':
                pgRepo = repo.translate(projects.transTables['postgresql'])
                dbPath = cfg.reposDBPath % pgRepo
                rdb = dbstore.connect('%s' % (cfg.reposDBPath % 'postgres'),
                                      cfg.reposDBDriver)
                rcu = rdb.cursor()
                rcu.execute("SELECT datname FROM pg_database WHERE datname=?",
                             pgRepo)
                if rcu.fetchone():
                    rcu.execute("DROP DATABASE %s" % pgRepo)
                    rcu.execute("CREATE DATABASE %s ENCODING 'UTF8'" % pgRepo)
                rdb.close()

                dbUser = cfg.reposDBPath.split('@')[0]
                util.execute('cat %s | psql -U %s %s'% (dumpPath, dbUser, pgRepo))
                rdb = dbstore.connect('%s' % (cfg.reposDBPath % 'postgres'),
                                      cfg.reposDBDriver)
                conary.server.schema.loadSchema(rdb, doMigrate=True)
                rdb.close()
        else:
            cu.execute("SELECT * FROM InboundMirrors WHERE targetProjectId=?", projectId)
            localMirror = cu.fetchone_dict()
            if localMirror:
                if not os.path.exists(reposPath):
                    # revert Labels table to pre-mirror settings
                    cu.execute( \
                            "UPDATE Labels SET url=?, username=?, password=?" \
                                " WHERE projectId=?",
                        localMirror['sourceUrl'],
                        localMirror['sourceUsername'],
                        localMirror['sourcePassword'], projectId)

                    cu.execute("DELETE FROM RepNameMap WHERE toName=?", repo)
                    cu.execute( \
                        "DELETE FROM InboundMirrors WHERE inboundMirrorId=?",
                        localMirror['inboundMirrorId'])

    # delete package index to ensure we don't reference troves until they're
    # restored.
    try:
        cu.execute('DELETE FROM PackageIndex')
        cu.execute('DELETE FROM PackageIndexMark')
    except:
        # this masks errors, since it does re-raise but we don't care.
        # impact and cost are negligible.
        db.rollback()
    else:
        db.commit()

def prerestore(cfg):
    util.execute("service httpd stop")
    for repo in os.listdir(cfg.reposPath):
        reposPath = os.path.join(cfg.reposPath, repo)
        util.rmtree(reposPath, ignore_errors = True)

def clean(cfg):
    backupPath = os.path.join(cfg.dataPath, 'tmp', 'backup')
    util.rmtree(backupPath, ignore_errors = True)

def metadata(cfg, out):
    db = dbstore.connect(cfg.dbPath, cfg.dbDriver)
    cu = db.cursor()
    cu.execute("SELECT COALESCE(MAX(version), 0) FROM DatabaseVersion")
    schemaVersion = cu.fetchone()[0]
    print >> out, "rBuilder_schemaVersion=%d" % schemaVersion
    cu.execute("SELECT COALESCE(MAX(minor), 0) FROM DatabaseVersion")
    schemaMinor = cu.fetchone()[0]
    print >> out, "rBuilder_schemaMinor=%d" % schemaMinor
    sys.stdout.flush()

# XXX This version is used internally since our handler expects
#     an exception, while rAPA expects a True/False return.
def _isValid(cfg, input):
    if not isValid(cfg, input):
        raise RuntimeError("Invalid Backup")

def isValid(cfg, input):
    data = input.read()
    metaData = dict()
    for x in data.splitlines():
        if '=' in x:
           k, v = x.split('=', 1)
           metaData[k] = v
    schemaVersion = int(metaData.get('rBuilder_schemaVersion', 0))
    if schemaVersion == 0 or schemaVersion < schemaCutoff:
        return False
    NVF = metaData.get('NVF')
    if not NVF:
        return False
    verStr = cmdline.parseTroveSpec(NVF)[1]
    try:
        trailingVer = versions.VersionFromString(verStr).trailingRevision().version
    except conary.errors.ParseError:
        return False
    foundMatch = False
    for pat in knownGroupVersions:
        if re.match(pat, trailingVer):
            foundMatch = True
            break
    return foundMatch

def usage(out = sys.stderr):
    print >> out, sys.argv[0] + ":"
    print >> out, "    [b/backup]: back up databases and issue manifest."
    print >> out, "    [r/restore]: restore databases."
    print >> out, "    [c/clean]: clean up temporary files used during backup."
    print >> out, "    [m/metadata]: print appliance metadata in name=value format."
    print >> out, "    [isValid]: determine if metadata on stdin is for a compatible backup."
    print >> out, "    [prerestore]: prepare to restore databases."

def handle(func, *args, **kwargs):
    errno = 0
    if kwargs.pop('dropPriv', True):
        apacheUID, apacheGID = pwd.getpwnam('apache')[2:4]
        os.setgid(apacheGID)
        os.setuid(apacheUID)
    try:
        func(*args, **kwargs)
    except:
        exception, e, bt = sys.exc_info()
        if exception in (OSError, IOError):
            errno = e.errno
        else:
            errno = 1
        import traceback
        print >> sys.stderr, ''.join(traceback.format_tb(bt))
        print >> sys.stderr, exception, e
    sys.exit(errno)

def run():
    cfg = config.MintConfig()
    cfg.read(config.RBUILDER_CONFIG)
    migration = bool(os.getenv('RBA_MIGRATION'))
    mode = (len(sys.argv) > 1) and sys.argv[1] or ''
    if mode in ('r', 'restore'):
        handle(restore, cfg)
    elif mode  == 'prerestore':
        handle(prerestore, cfg, dropPriv = False)
    elif mode in ('b', 'backup'):
        handle(backup, cfg, sys.stdout, backupMirrors = migration)
    elif mode in ('c', 'clean'):
        handle(clean, cfg)
    elif mode in ('m', 'metadata'):
        handle(metadata, cfg, sys.stdout)
    elif mode == 'isValid':
        handle(_isValid, cfg, sys.stdin)
    elif mode.upper() in ('?', 'H', 'HELP'):
        usage(out = sys.stdout)
    else:
        usage()

<|endoftext|>


<commit_before># Copyright (c) 2012 Intel, Inc.
# Copyright (c) 2011-2012 OpenStack Foundation
#Copyright (c) 2017 Georgi Georgiev
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

"""
Filter to add support for Trusted Computing Pools (EXPERIMENTAL).
This is a modified version of the TrustedFilter used by the Nova scheduler.
It schedules storage on trusted hosts.

Configuration options have to be specified in the [trusted_computing] section in cinder.conf

Details on setting up and using an Attestation Service can be found at
the Open Attestation project at:

    https://github.com/OpenAttestation/OpenAttestation
"""

from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import timeutils
from oslo_config import cfg
import requests

from cinder import context
from cinder.i18n import _LW
from cinder import objects
from cinder.scheduler import filters

LOG = logging.getLogger(__name__)
CONF = cfg.CONF

class AttestationService(object):
    # Provide access wrapper to attestation server to get integrity report.

    def __init__(self):
        self.api_url = CONF.trusted_computing.attestation_api_url
        self.host = CONF.trusted_computing.attestation_server
        self.port = CONF.trusted_computing.attestation_port
        self.auth_blob = CONF.trusted_computing.attestation_auth_blob
        self.key_file = None
        self.cert_file = None
        self.ca_file = CONF.trusted_computing.attestation_server_ca_file
        self.request_count = 100
        # If the CA file is not provided, let's check the cert if verification
        # asked
        self.verify = (not CONF.trusted_computing.attestation_insecure_ssl
                       and self.ca_file or True)
        self.cert = (self.cert_file, self.key_file)

    def _do_request(self, method, action_url, body, headers):
        # Connects to the server and issues a request.
        # :returns: result data
        # :raises: IOError if the request fails

        action_url = "https://%s:%d%s/%s" % (self.host, self.port,
                                             self.api_url, action_url)
        try:
            res = requests.request(method, action_url, data=body,
                                   headers=headers, cert=self.cert,
                                   verify=self.verify)
            status_code = res.status_code
            if status_code in (requests.codes.OK,
                               requests.codes.CREATED,
                               requests.codes.ACCEPTED,
                               requests.codes.NO_CONTENT):
                try:
                    return requests.codes.OK, jsonutils.loads(res.text)
                except (TypeError, ValueError):
                    return requests.codes.OK, res.text
            return status_code, None

        except requests.exceptions.RequestException:
            return IOError, None

    def _request(self, cmd, subcmd, hosts):
        body = {}
        body['count'] = len(hosts)
        body['hosts'] = hosts
        cooked = jsonutils.dumps(body)
        headers = {}
        headers['content-type'] = 'application/json'
        headers['Accept'] = 'application/json'
        if self.auth_blob:
            headers['x-auth-blob'] = self.auth_blob
        status, res = self._do_request(cmd, subcmd, cooked, headers)
        return status, res

    def do_attestation(self, hosts):
        """Attests compute nodes through OAT service.

        :param hosts: hosts list to be attested
        :returns: dictionary for trust level and validate time
        """
        result = None

        status, data = self._request("POST", "PollHosts", hosts)
        if data is not None:
            result = data.get('hosts')

        return result

class ComputeAttestationCache(object):
    """Cache for compute node attestation

    Cache compute node's trust level for sometime,
    if the cache is out of date, poll OAT service to flush the
    cache.

    OAT service may have cache also. OAT service's cache valid time
    should be set shorter than trusted filter's cache valid time.
    """

    def __init__(self):
        self.attestservice = AttestationService()
        self.compute_nodes = {}
        admin = context.get_admin_context()

        # Fetch compute node list to initialize the compute_nodes,
        # so that we don't need poll OAT service one by one for each
        # host in the first round that scheduler invokes us.
        computes = objects.ComputeNodeList.get_all(admin)
        for compute in computes:
            host = compute.hypervisor_hostname
            self._init_cache_entry(host)

        # TODO(sfinucan): Remove this warning when the named config options
        # gains a 'min' parameter.
        if CONF.trusted_computing.attestation_auth_timeout < 0:
            LOG.warning(_LW('Future versions of nova will restrict the '
                '"trusted_computing.attestation_auth_timeout" config option '
                'to values >=0. Update your configuration file to mitigate '
                'future upgrade issues.'))

    def _cache_valid(self, host):
        cachevalid = False
        if host in self.compute_nodes:
            node_stats = self.compute_nodes.get(host)
            if not timeutils.is_older_than(
                             node_stats['vtime'],
                             CONF.trusted_computing.attestation_auth_timeout):
                cachevalid = True
        return cachevalid

    def _init_cache_entry(self, host):
        self.compute_nodes[host] = {
            'trust_lvl': 'unknown',
            'vtime': timeutils.normalize_time(
                        timeutils.parse_isotime("1970-01-01T00:00:00Z"))}

    def _invalidate_caches(self):
        for host in self.compute_nodes:
            self._init_cache_entry(host)

    def _update_cache_entry(self, state):
        entry = {}

        host = state['host_name']
        entry['trust_lvl'] = state['trust_lvl']

        try:
            # Normalize as naive object to interoperate with utcnow().
            entry['vtime'] = timeutils.normalize_time(
                            timeutils.parse_isotime(state['vtime']))
        except ValueError:
            try:
                # Mt. Wilson does not necessarily return an ISO8601 formatted
                # `vtime`, so we should try to parse it as a string formatted
                # datetime.
                vtime = timeutils.parse_strtime(state['vtime'], fmt="%c")
                entry['vtime'] = timeutils.normalize_time(vtime)
            except ValueError:
                # Mark the system as un-trusted if get invalid vtime.
                entry['trust_lvl'] = 'unknown'
                entry['vtime'] = timeutils.utcnow()

        self.compute_nodes[host] = entry

    def _update_cache(self):
        self._invalidate_caches()
        states = self.attestservice.do_attestation(
            list(self.compute_nodes.keys()))
        if states is None:
            return
        for state in states:
            self._update_cache_entry(state)

    def get_host_attestation(self, host):
        """Check host's trust level."""
        if host not in self.compute_nodes:
            self._init_cache_entry(host)
        if not self._cache_valid(host):
            self._update_cache()
        level = self.compute_nodes.get(host).get('trust_lvl')
        return level

class ComputeAttestation(object):
    def __init__(self):
        self.caches = ComputeAttestationCache()

    def is_trusted(self, host, trust):
        level = self.caches.get_host_attestation(host)
        return trust == level

class TrustedFilter(filters.BaseBackendFilter):

    def backend_passes(self, host_state, filter_properties):
        return  True

<commit_msg>trusted filter for cinder<commit_after># Copyright (c) 2012 Intel, Inc.
# Copyright (c) 2011-2012 OpenStack Foundation
#Copyright (c) 2017 Georgi Georgiev
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
#    ge0rgi: Adapted Nova Trusted Filter to work for cinder volumes

"""
Filter to add support for Trusted Computing Pools (EXPERIMENTAL).
This is a modified version of the TrustedFilter used by the Nova scheduler.
It schedules storage on trusted hosts.

Configuration options have to be specified in the [trusted_computing] section in cinder.conf

Details on setting up and using an Attestation Service can be found at
the Open Attestation project at:

    https://github.com/OpenAttestation/OpenAttestation
"""

from oslo_log import log as logging
from oslo_serialization import jsonutils
from oslo_utils import timeutils
from oslo_config import cfg
import requests

from cinder.i18n import _LW
from cinder.scheduler import filters

LOG = logging.getLogger(__name__)
CONF = cfg.CONF

class AttestationService(object):
    # Provide access wrapper to attestation server to get integrity report.

    def __init__(self):
        self.api_url = CONF.trusted_computing.attestation_api_url
        self.host = CONF.trusted_computing.attestation_server
        self.port = CONF.trusted_computing.attestation_port
        self.auth_blob = CONF.trusted_computing.attestation_auth_blob
        self.key_file = None
        self.cert_file = None
        self.ca_file = CONF.trusted_computing.attestation_server_ca_file
        self.request_count = 100
        # If the CA file is not provided, let's check the cert if verification
        # asked
        self.verify = (not CONF.trusted_computing.attestation_insecure_ssl
                       and self.ca_file or True)
        self.cert = (self.cert_file, self.key_file)

    def _do_request(self, method, action_url, body, headers):
        # Connects to the server and issues a request.
        # :returns: result data
        # :raises: IOError if the request fails

        action_url = "https://%s:%d%s/%s" % (self.host, self.port,
                                             self.api_url, action_url)
        try:
            res = requests.request(method, action_url, data=body,
                                   headers=headers, cert=self.cert,
                                   verify=self.verify)
            status_code = res.status_code
            if status_code in (requests.codes.OK,
                               requests.codes.CREATED,
                               requests.codes.ACCEPTED,
                               requests.codes.NO_CONTENT):
                try:
                    return requests.codes.OK, jsonutils.loads(res.text)
                except (TypeError, ValueError):
                    return requests.codes.OK, res.text
            return status_code, None

        except requests.exceptions.RequestException:
            return IOError, None

    def _request(self, cmd, subcmd, hosts):
        body = {}
        body['count'] = len(hosts)
        body['hosts'] = hosts
        cooked = jsonutils.dumps(body)
        headers = {}
        headers['content-type'] = 'application/json'
        headers['Accept'] = 'application/json'
        if self.auth_blob:
            headers['x-auth-blob'] = self.auth_blob
        status, res = self._do_request(cmd, subcmd, cooked, headers)
        return status, res

    def do_attestation(self, hosts):
        """Attests compute nodes through OAT service.

        :param hosts: hosts list to be attested
        :returns: dictionary for trust level and validate time
        """
        result = None

        status, data = self._request("POST", "PollHosts", hosts)
        if data is not None:
            result = data.get('hosts')

        return result

class ComputeAttestationCache(object):
    """Cache for compute node attestation

    Cache compute node's trust level for sometime,
    if the cache is out of date, poll OAT service to flush the
    cache.

    OAT service may have cache also. OAT service's cache valid time
    should be set shorter than trusted filter's cache valid time.
    """

    def __init__(self):
        self.attestservice = AttestationService()
        self.storage_nodes = {}

        # TODO(sfinucan): Remove this warning when the named config options
        # gains a 'min' parameter.
        if CONF.trusted_computing.attestation_auth_timeout < 0:
            LOG.warning(_LW('Future versions of nova will restrict the '
                '"trusted_computing.attestation_auth_timeout" config option '
                'to values >=0. Update your configuration file to mitigate '
                'future upgrade issues.'))

    def _cache_valid(self, host):
        cachevalid = False
        if host in self.storage_nodes:
            node_stats = self.storage_nodes.get(host)
            if not timeutils.is_older_than(
                             node_stats['vtime'],
                             CONF.trusted_computing.attestation_auth_timeout):
                cachevalid = True
        return cachevalid

    def _init_cache_entry(self, host):
        self.storage_nodes[host] = {
            'trust_lvl': 'unknown',
            'vtime': timeutils.normalize_time(
                        timeutils.parse_isotime("1970-01-01T00:00:00Z"))}

    def _invalidate_caches(self):
        for host in self.storage_nodes:
            self._init_cache_entry(host)

    def _update_cache_entry(self, state):
        entry = {}

        host = state['host_name']
        entry['trust_lvl'] = state['trust_lvl']

        try:
            # Normalize as naive object to interoperate with utcnow().
            entry['vtime'] = timeutils.normalize_time(
                            timeutils.parse_isotime(state['vtime']))
        except ValueError:
            try:
                # Mt. Wilson does not necessarily return an ISO8601 formatted
                # `vtime`, so we should try to parse it as a string formatted
                # datetime.
                vtime = timeutils.parse_strtime(state['vtime'], fmt="%c")
                entry['vtime'] = timeutils.normalize_time(vtime)
            except ValueError:
                # Mark the system as un-trusted if get invalid vtime.
                entry['trust_lvl'] = 'unknown'
                entry['vtime'] = timeutils.utcnow()

        self.storage_nodes[host] = entry

    def _update_cache(self):
        self._invalidate_caches()
        states = self.attestservice.do_attestation(
            list(self.storage_nodes.keys()))
        if states is None:
            return
        for state in states:
            self._update_cache_entry(state)

    def get_host_attestation(self, host):
        """Check host's trust level."""
        if host not in self.storage_nodes:
            self._init_cache_entry(host)
        if not self._cache_valid(host):
            self._update_cache()
        level = self.storage_nodes.get(host).get('trust_lvl')
        return level

class ComputeAttestation(object):
    def __init__(self):
        self.caches = ComputeAttestationCache()

    def is_trusted(self, host, trust):
        level = self.caches.get_host_attestation(host)
        return trust == level

class TrustedFilter(filters.BaseBackendFilter):
    def __init__(self):
        self.compute_attestation = ComputeAttestation()

    def backend_passes(self, host_state, filter_properties):
        hostname = host_state.host.split('@')[0]
        if 'trust:trusted_host' in filter_properties["metadata"]:
            return self.compute_attestation.is_trusted(hostname, filter_properties['metadata']['trust:trusted_host'])
        return self.compute_attestation.is_trusted(hostname, CONF.trusted_computing.default_trust_level)

<|endoftext|>


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

from sphinxcontrib.docbook import DocBookBuilder

def setup(app):
    app.add_builder(DocBookBuilder)
<commit_msg>sphinxcontrib/setup.py: Add license header.<commit_after>#!/usr/bin/env python
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
#
# Author: Cyril Roelandt <cyril.roelandt@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from sphinxcontrib.docbook import DocBookBuilder

def setup(app):
    app.add_builder(DocBookBuilder)
<|endoftext|>


<commit_before>import numpy as np
from caid.cad_geometry import cad_geometry, cad_nurbs
from pigasus.utils.manager import context
from pigasus.fit.curfit import curfit
from pigasus.fit.curfit import compute_uk
from caid.cad_geometry import line

def nearest_int(u):
    iu = int(u)
    if u-iu < 0.5:
        return iu
    else:
        return iu+1

def iround(x):
    """
    iround(number) -> integer
    Round a number to the nearest integer.
    """
    return np.array([nearest_int(_x) for _x in x])
#    return np.array([int(round(_x) - .5) + (_x > 0) for _x in x])

def cad_geometry_levels(geo_i, geo_e, d):
    """
    constructs a set of (d-2) curves that lie between
    geo_i (interior) and geo_e (exterior)
    TODO: treate the NURBS case. Only the spline (weights=1) is treated here
    Args:
        geo_i (cad_geometry) : describing a spline curve
        geo_e (cad_geometry) : describing a spline curve
    Output:
        cad_geometry object that contains a list of curves, ordered from the
        interior to the exterior
    """
    geo = cad_geometry()
    nrb_i = geo_i[0]
    nrb_e = geo_e[0]

    U = np.linspace(0.,1.,d+1)
    for u in U[1:-1]:
        P_i = nrb_i.points
        P_e = nrb_e.points

        P   = u * P_i + (1.-u) * P_e

        cad_nrb = cad_nurbs(nrb_i.knots, P)
        geo.append(cad_nrb)

    return geo

def construct_curve_from_points(x,y, px, \
                                knots=None, method='chord', alpha=0.1, nx=None):
    with context():
        #-----------------------------------
        def MakeConstraint(cond, face=None, value=None):
            if cond.lower() == "closed":
                constraint = {}
                constraint['patch_id_m'] = 0
                constraint['face_m']     = 0
                constraint['patch_id_s'] = 0
                constraint['face_s']     = 1
            if cond.lower() == "c0":
                constraint = {}
                constraint['patch_id_m'] = 0
                constraint['face_m']     = face
                constraint['type']       = "C0"
                constraint['values']     = [value]
            if cond.lower() == "c1":
                constraint = {}
                constraint['patch_id_m'] = 0
                constraint['face_m']     = face
                constraint['type']       = "C1"
                constraint['values']     = [value]
            return constraint
        #-----------------------------------

#        #-----------------------------------
#        print(("Approximation using " + method + " knots"))
#        print(("n " + str(nx) + " p ", str(px)))
#        #-----------------------------------

        #-----------------------------------
        # ...
        list_x = list(x) ; list_y = list(y)
        # ...

        # ...
        list_Q = list(zip(list_x, list_y))
        uk = compute_uk(list_Q, method=method)
        U1       = []
        U1      += list(uk)
        list_xk  = []     ; list_yk  = []
        list_xk += list_x ; list_yk += list_y

        lists_uk = [U1]
        lists_xk = [list_xk]
        lists_yk = [list_yk]
        # ...
        #-----------------------------------

        #-----------------------------------
        constraints = []

        # ... C0_COND
        constraint = MakeConstraint("C0", 0, [x[0], y[0]])
        constraints.append(constraint)

        constraint = MakeConstraint("C0", 1, [x[-1], y[-1]])
        constraints.append(constraint)
        #-----------------------------------

        #-----------------------------------
        geo = line(p=[px])
        if knots is not None:
            u = knots
            geo.refine(list_t=[u])
        else:
            ub = patch.knots[0][0]
            ue = patch.knots[0][-1]
            u = np.linspace(ub,ue,nx+1)[1:-1]
            geo.refine(list_t=[u])
        #-----------------------------------

        #-----------------------------------
        fit = curfit(geometry=geo, constraints=constraints, alpha=alpha)
        #-----------------------------------

        #-----------------------------------
        patch_id = 0
        xk = lists_xk[patch_id]
        yk = lists_yk[patch_id]

        geo = fit.construct([xk, yk], uk=lists_uk)
        #-----------------------------------

        fit.PDE.free()

        return geo

<commit_msg>comment pigasus use<commit_after>import numpy as np
from caid.cad_geometry import cad_geometry, cad_nurbs
from caid.cad_geometry import line

def nearest_int(u):
    iu = int(u)
    if u-iu < 0.5:
        return iu
    else:
        return iu+1

def iround(x):
    """
    iround(number) -> integer
    Round a number to the nearest integer.
    """
    return np.array([nearest_int(_x) for _x in x])
#    return np.array([int(round(_x) - .5) + (_x > 0) for _x in x])

def cad_geometry_levels(geo_i, geo_e, d):
    """
    constructs a set of (d-2) curves that lie between
    geo_i (interior) and geo_e (exterior)
    TODO: treate the NURBS case. Only the spline (weights=1) is treated here
    Args:
        geo_i (cad_geometry) : describing a spline curve
        geo_e (cad_geometry) : describing a spline curve
    Output:
        cad_geometry object that contains a list of curves, ordered from the
        interior to the exterior
    """
    geo = cad_geometry()
    nrb_i = geo_i[0]
    nrb_e = geo_e[0]

    U = np.linspace(0.,1.,d+1)
    for u in U[1:-1]:
        P_i = nrb_i.points
        P_e = nrb_e.points

        P   = u * P_i + (1.-u) * P_e

        cad_nrb = cad_nurbs(nrb_i.knots, P)
        geo.append(cad_nrb)

    return geo

def construct_curve_from_points(x,y, px, \
                                knots=None, method='chord', alpha=0.1, nx=None):
    raise()
    with context():
        #-----------------------------------
        def MakeConstraint(cond, face=None, value=None):
            if cond.lower() == "closed":
                constraint = {}
                constraint['patch_id_m'] = 0
                constraint['face_m']     = 0
                constraint['patch_id_s'] = 0
                constraint['face_s']     = 1
            if cond.lower() == "c0":
                constraint = {}
                constraint['patch_id_m'] = 0
                constraint['face_m']     = face
                constraint['type']       = "C0"
                constraint['values']     = [value]
            if cond.lower() == "c1":
                constraint = {}
                constraint['patch_id_m'] = 0
                constraint['face_m']     = face
                constraint['type']       = "C1"
                constraint['values']     = [value]
            return constraint
        #-----------------------------------

#        #-----------------------------------
#        print(("Approximation using " + method + " knots"))
#        print(("n " + str(nx) + " p ", str(px)))
#        #-----------------------------------

        #-----------------------------------
        # ...
        list_x = list(x) ; list_y = list(y)
        # ...

        # ...
        list_Q = list(zip(list_x, list_y))
        uk = compute_uk(list_Q, method=method)
        U1       = []
        U1      += list(uk)
        list_xk  = []     ; list_yk  = []
        list_xk += list_x ; list_yk += list_y

        lists_uk = [U1]
        lists_xk = [list_xk]
        lists_yk = [list_yk]
        # ...
        #-----------------------------------

        #-----------------------------------
        constraints = []

        # ... C0_COND
        constraint = MakeConstraint("C0", 0, [x[0], y[0]])
        constraints.append(constraint)

        constraint = MakeConstraint("C0", 1, [x[-1], y[-1]])
        constraints.append(constraint)
        #-----------------------------------

        #-----------------------------------
        geo = line(p=[px])
        if knots is not None:
            u = knots
            geo.refine(list_t=[u])
        else:
            ub = patch.knots[0][0]
            ue = patch.knots[0][-1]
            u = np.linspace(ub,ue,nx+1)[1:-1]
            geo.refine(list_t=[u])
        #-----------------------------------

        #-----------------------------------
        fit = curfit(geometry=geo, constraints=constraints, alpha=alpha)
        #-----------------------------------

        #-----------------------------------
        patch_id = 0
        xk = lists_xk[patch_id]
        yk = lists_yk[patch_id]

        geo = fit.construct([xk, yk], uk=lists_uk)
        #-----------------------------------

        fit.PDE.free()

        return geo

<|endoftext|>


<commit_before>from typing import Tuple, Callable, Optional, TypeVar, Any, cast, Union

from ..model import Model
from ..config import registry
from ..util import get_width
from ..types import Ragged, Padded, Array

InT = TypeVar("InT")
OutT = TypeVar("OutT")
Mid1T = TypeVar("Mid1T")
Mid2T = TypeVar("Mid2T")

# This implementation is named 'chains' because we have a type-shennanigans
# function 'chain' below.
@registry.layers("chain.v0")
def chains(layer1: Model[InT, Mid1T], layer2: Model[Mid1T, Any], *layers: Model) -> Model[InT, Any]:
    """Compose two models `f` and `g` such that they become layers of a single
    feed-forward model that computes `g(f(x))`.
    Also supports chaining more than 2 layers.
    """
    layers = (layer1, layer2) + layers
    if layers[0]._func is forward:
        layers[0].layers.extend(layers[1:])
        return layers[0]
    model: Model[InT, Any] = Model(
        ">>".join(layer.name for layer in layers),
        forward,
        init=init,
        dims={"nO": None, "nI": None},
        layers=layers,
    )
    if layers[0].has_dim("nI") and layers[-1].has_dim("nO"):
        model.initialize()
    return model

def forward(model: Model[InT, OutT], X: InT, is_train: bool) -> Tuple[OutT, Callable]:
    """Apply the layers of `model` in sequence, feeding the output from one
    layer into the next.
    """
    callbacks = []
    for layer in model.layers:
        Y, inc_layer_grad = layer(X, is_train=is_train)
        callbacks.append(inc_layer_grad)
        X = Y

    def backprop(dY: OutT) -> InT:
        for callback in reversed(callbacks):
            dX = callback(dY)
            dY = dX
        return dX

    return Y, backprop

def init(model: Model, X: Optional[InT] = None, Y: Optional[OutT] = None) -> None:
    if not model.layers:
        return
    if X is None and Y is None:
        for layer in model.layers:
            layer.initialize()
        if model.layers[0].has_dim("nI"):
            model.set_dim("nI", model.layers[0].get_dim("nI"))
        if model.layers[-1].has_dim("nO"):
            model.set_dim("nO", model.layers[-1].get_dim("nO"))
        return
    # Try to set nO on each layer, where available.
    nO = None
    if Y is not None and isinstance(Y, (Ragged, Padded, Array, list)):
        nO = get_width(Y)
    elif model.has_dim("nO"):
        nO = model.get_dim("nO")
    for layer in reversed(model.layers):
        if nO is not None and layer.has_dim("nO") is None:
            layer.set_dim("nO", nO)
        if layer.has_dim("nI"):
            nO = layer.get_dim("nI")
        else:
            break
    for layer in model.layers[:-1]:
        layer.initialize(X=X)
        X = layer.predict(X)
    model.layers[-1].initialize(X=X, Y=Y)
    if model.layers[0].has_dim("nI"):
        model.set_dim("nI", model.layers[0].get_dim("nI"))
    if model.layers[-1].has_dim("nO"):
        model.set_dim("nO", model.layers[-1].get_dim("nO"))

# Unfortunately mypy doesn't support type-level checking on the cardinality
# of variadic arguments: in other words, if you have an *args, you can't have
# a type-checked condition on len(args). But we *can* get sneaky:
# you can have a type-checked condition on *optional* args, and these *will*
# get read by mypy. Hence the trickery below.

Mid3T = TypeVar("Mid3T")
Mid4T = TypeVar("Mid4T")
Mid5T = TypeVar("Mid5T")
Mid6T = TypeVar("Mid6T")
Mid7T = TypeVar("Mid7T")
Mid8T = TypeVar("Mid8T")
Mid9T = TypeVar("Mid9T")

def chain(
    l1: Model[InT, Mid1T],
    l2: Model[Mid1T, Mid2T],
    l3: Optional[Model[Mid2T, Mid3T]] = None,
    l4: Optional[Model[Mid3T, Mid4T]] = None,
    l5: Optional[Model[Mid4T, Mid5T]] = None,
    l6: Optional[Model[Mid5T, Mid6T]] = None,
    l7: Optional[Model[Mid6T, Mid7T]] = None,
    l8: Optional[Model[Mid7T, Mid8T]] = None,
    l9: Optional[Model[Mid8T, Mid9T]] = None,
    *etc: Model
) -> Model[InT, Any]:
    if l3 is None:
        return chain(l1, l2)
    elif l4 is None:
        return chain(l1, l2, l3)
    elif l5 is None:
        return chain(l1, l2, l3, l4)
    elif l6 is None:
        return chain(l1, l2, l3, l4, l5)
    elif l7 is None:
        return chain(l1, l2, l3, l4, l5, l6)
    elif l8 is None:
        return chain(l1, l2, l3, l4, l5, l6, l7)
    elif l9 is None:
        return chain(l1, l2, l3, l4, l5, l6, l7, l8)
    else:
        return chain(l1, l2, l3, l4, l5, l6, l7, l8, l9, *etc)
<commit_msg>Add workaround for pydantic problem<commit_after>from typing import Tuple, Callable, Optional, TypeVar, Any, cast, Union

from ..model import Model
from ..config import registry
from ..util import get_width
from ..types import Ragged, Padded, Array

InT = TypeVar("InT")
OutT = TypeVar("OutT")
Mid1T = TypeVar("Mid1T")
Mid2T = TypeVar("Mid2T")

# TODO: Unhack this when we can
# We currently have an issue with Pydantic when arguments have generic types.
# https://github.com/samuelcolvin/pydantic/issues/1158
# For now we work around the issue by applying the decorator to this blander
# version of the function.
@registry.layers("chain.v0")
def chain_no_types(*layer: Model) -> Model:
    return chains(*layer)

# This implementation is named 'chains' because we have a type-shennanigans
# function 'chain' below.
def chains(layer1: Model[InT, Mid1T], layer2: Model[Mid1T, Any], *layers: Model) -> Model[InT, Any]:
    """Compose two models `f` and `g` such that they become layers of a single
    feed-forward model that computes `g(f(x))`.
    Also supports chaining more than 2 layers.
    """
    layers = (layer1, layer2) + layers
    if layers[0]._func is forward:
        layers[0].layers.extend(layers[1:])
        return layers[0]
    model: Model[InT, Any] = Model(
        ">>".join(layer.name for layer in layers),
        forward,
        init=init,
        dims={"nO": None, "nI": None},
        layers=layers,
    )
    if layers[0].has_dim("nI") and layers[-1].has_dim("nO"):
        model.initialize()
    return model

def forward(model: Model[InT, OutT], X: InT, is_train: bool) -> Tuple[OutT, Callable]:
    """Apply the layers of `model` in sequence, feeding the output from one
    layer into the next.
    """
    callbacks = []
    for layer in model.layers:
        Y, inc_layer_grad = layer(X, is_train=is_train)
        callbacks.append(inc_layer_grad)
        X = Y

    def backprop(dY: OutT) -> InT:
        for callback in reversed(callbacks):
            dX = callback(dY)
            dY = dX
        return dX

    return Y, backprop

def init(model: Model, X: Optional[InT] = None, Y: Optional[OutT] = None) -> None:
    if not model.layers:
        return
    if X is None and Y is None:
        for layer in model.layers:
            layer.initialize()
        if model.layers[0].has_dim("nI"):
            model.set_dim("nI", model.layers[0].get_dim("nI"))
        if model.layers[-1].has_dim("nO"):
            model.set_dim("nO", model.layers[-1].get_dim("nO"))
        return
    # Try to set nO on each layer, where available.
    nO = None
    if Y is not None and isinstance(Y, (Ragged, Padded, Array, list)):
        nO = get_width(Y)
    elif model.has_dim("nO"):
        nO = model.get_dim("nO")
    for layer in reversed(model.layers):
        if nO is not None and layer.has_dim("nO") is None:
            layer.set_dim("nO", nO)
        if layer.has_dim("nI"):
            nO = layer.get_dim("nI")
        else:
            break
    for layer in model.layers[:-1]:
        layer.initialize(X=X)
        X = layer.predict(X)
    model.layers[-1].initialize(X=X, Y=Y)
    if model.layers[0].has_dim("nI"):
        model.set_dim("nI", model.layers[0].get_dim("nI"))
    if model.layers[-1].has_dim("nO"):
        model.set_dim("nO", model.layers[-1].get_dim("nO"))

# Unfortunately mypy doesn't support type-level checking on the cardinality
# of variadic arguments: in other words, if you have an *args, you can't have
# a type-checked condition on len(args). But we *can* get sneaky:
# you can have a type-checked condition on *optional* args, and these *will*
# get read by mypy. Hence the trickery below.

Mid3T = TypeVar("Mid3T")
Mid4T = TypeVar("Mid4T")
Mid5T = TypeVar("Mid5T")
Mid6T = TypeVar("Mid6T")
Mid7T = TypeVar("Mid7T")
Mid8T = TypeVar("Mid8T")
Mid9T = TypeVar("Mid9T")

def chain(
    l1: Model[InT, Mid1T],
    l2: Model[Mid1T, Mid2T],
    l3: Optional[Model[Mid2T, Mid3T]] = None,
    l4: Optional[Model[Mid3T, Mid4T]] = None,
    l5: Optional[Model[Mid4T, Mid5T]] = None,
    l6: Optional[Model[Mid5T, Mid6T]] = None,
    l7: Optional[Model[Mid6T, Mid7T]] = None,
    l8: Optional[Model[Mid7T, Mid8T]] = None,
    l9: Optional[Model[Mid8T, Mid9T]] = None,
    *etc: Model
) -> Model[InT, Any]:
    if l3 is None:
        return chains(l1, l2)
    elif l4 is None:
        return chains(l1, l2, l3)
    elif l5 is None:
        return chains(l1, l2, l3, l4)
    elif l6 is None:
        return chains(l1, l2, l3, l4, l5)
    elif l7 is None:
        return chains(l1, l2, l3, l4, l5, l6)
    elif l8 is None:
        return chains(l1, l2, l3, l4, l5, l6, l7)
    elif l9 is None:
        return chains(l1, l2, l3, l4, l5, l6, l7, l8)
    else:
        return chains(l1, l2, l3, l4, l5, l6, l7, l8, l9, *etc)
<|endoftext|>