<commit_before># coding: utf-8
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.

from __future__ import division, unicode_literals

import os
import glob

import numpy as np
from monty.json import jsanitize
from monty.json import MSONable
scipy_old_piecewisepolynomial = True
try:
    from scipy.interpolate import PiecewisePolynomial
except ImportError:
    from scipy.interpolate import CubicSpline
    scipy_old_piecewisepolynomial = False

from pymatgen.util.plotting_utils import get_publication_quality_plot
from pymatgen.io.vasp import Poscar, Outcar

"""
Some reimplementation of Henkelman's Transition State Analysis utilities,
which are originally in Perl. Additional features beyond those offered by
Henkelman's utilities will be added.

This allows the usage and customization in Python.
"""

__author__ = 'Shyue Ping Ong'
__copyright__ = 'Copyright 2013, The Materials Virtual Lab'
__version__ = '0.1'
__maintainer__ = 'Shyue Ping Ong'
__email__ = 'ongsp@ucsd.edu'
__date__ = '6/1/15'

class NEBAnalysis(MSONable):
    """
    An NEBAnalysis class.
    """

    def __init__(self, r, energies, forces, structures, **kwargs):
        """
        Initializes an NEBAnalysis from the cumulative root mean squared distances
        between structures, the energies, the forces, the structures and the
        interpolation_order for the analysis.

        Args:
            r: Root mean square distances between structures
            energies: Energies of each structure along reaction coordinate
            forces: Tangent forces along the reaction coordinate.
            structures ([Structure]): List of Structures along reaction
                coordinate.
        """
        self.r = np.array(r)
        self.energies = np.array(energies)
        self.forces = np.array(forces)
        self.structures = structures

        # We do a piecewise interpolation between the points. Each spline (
        # cubic by default) is constrained by the boundary conditions of the
        # energies and the tangent force, i.e., the derivative of
        # the energy at each pair of points.
        if 'spline_options' in kwargs:
            spline_options = kwargs['spline_options']
        else:
            spline_options = None
        self.setup_spline(spline_options=spline_options)

    def setup_spline(self, spline_options=None):
        if scipy_old_piecewisepolynomial:
            if spline_options:
                raise RuntimeError('Option for saddle point not available with old scipy implementation')
            self.spline = PiecewisePolynomial(
                self.r, np.array([self.energies, -self.forces]).T,
                orders=3)
        else:
            # New scipy implementation for scipy > 0.18.0
            if spline_options:
                if 'saddle_point' in spline_options and spline_options['saddle_point'] == 'zero_slope':
                    imax = np.argmax(self.energies)
                    self.spline = CubicSpline(x=self.r[:imax + 1], y=self.energies[:imax + 1],
                                              bc_type=((1, 0.0), (1, 0.0)))
                    cspline2 = CubicSpline(x=self.r[imax:], y=self.energies[imax:],
                                           bc_type=((1, 0.0), (1, 0.0)))
                    self.spline.extend(c=cspline2.c, x=cspline2.x[1:])
                else:
                    self.spline = CubicSpline(x=self.r, y=self.energies, bc_type=((1, 0.0), (1, 0.0)))
            else:
                self.spline = CubicSpline(x=self.r, y=self.energies, bc_type=((1, 0.0), (1, 0.0)))

    @classmethod
    def from_outcars(cls, outcars, structures, **kwargs):
        """
        Initializes an NEBAnalysis from Outcar and Structure objects. Use
        the static constructors, e.g., :class:`from_dir` instead if you
        prefer to have these automatically generated from a directory of NEB
        calculations.

        Args:
            outcars ([Outcar]): List of Outcar objects. Note that these have
                to be ordered from start to end along reaction coordinates.
            structures ([Structure]): List of Structures along reaction
                coordinate. Must be same length as outcar.
            interpolation_order (int): Order of polynomial to use to
                interpolate between images. Same format as order parameter in
                scipy.interplotate.PiecewisePolynomial.
        """
        if len(outcars) != len(structures):
            raise ValueError("# of Outcars must be same as # of Structures")

        # Calculate cumulative root mean square distance between structures,
        # which serves as the reaction coordinate. Note that these are
        # calculated from the final relaxed structures as the coordinates may
        # have changed from the initial interpolation.
        r = [0]
        prev = structures[0]
        for st in structures[1:]:
            dists = np.array([s2.distance(s1) for s1, s2 in zip(prev, st)])
            r.append(np.sqrt(np.sum(dists ** 2)))
            prev = st
        r = np.cumsum(r)

        energies = []
        forces = []
        for i, o in enumerate(outcars):
            o.read_neb()
            energies.append(o.data["energy"])
            if i in [0, len(outcars) - 1]:
                forces.append(0)
            else:
                forces.append(o.data["tangent_force"])
        energies = np.array(energies)
        energies -= energies[0]
        forces = np.array(forces)
        r = np.array(r)
        return cls(r=r, energies=energies, forces=forces, structures=structures, **kwargs)

    def get_extrema(self, normalize_rxn_coordinate=True):
        """
        Returns the positions of the extrema along the MEP. Both local
        minimums and maximums are returned.

        Args:
            normalize_rxn_coordinate (bool): Whether to normalize the
                reaction coordinate to between 0 and 1. Defaults to True.

        Returns:
            (min_extrema, max_extrema), where the extrema are given as
            [(x1, y1), (x2, y2), ...].
        """
        x = np.arange(0, np.max(self.r), 0.01)
        y = self.spline(x) * 1000

        scale = 1 if not normalize_rxn_coordinate else 1 / self.r[-1]
        min_extrema = []
        max_extrema = []
        for i in range(1, len(x) - 1):
            if y[i] < y[i-1] and y[i] < y[i+1]:
                min_extrema.append((x[i] * scale, y[i]))
            elif y[i] > y[i-1] and y[i] > y[i+1]:
                max_extrema.append((x[i] * scale, y[i]))
        return min_extrema, max_extrema

    def get_plot(self, normalize_rxn_coordinate=True, label_barrier=True):
        """
        Returns the NEB plot. Uses Henkelman's approach of spline fitting
        each section of the reaction path based on tangent force and energies.

        Args:
            normalize_rxn_coordinate (bool): Whether to normalize the
                reaction coordinate to between 0 and 1. Defaults to True.
            label_barrier (bool): Whether to label the maximum barrier.

        Returns:
            matplotlib.pyplot object.
        """
        plt = get_publication_quality_plot(12, 8)
        scale = 1 if not normalize_rxn_coordinate else 1 / self.r[-1]
        x = np.arange(0, np.max(self.r), 0.01)
        y = self.spline(x) * 1000
        plt.plot(self.r * scale, self.energies * 1000, 'ro',
                 x * scale, y, 'k-', linewidth=2, markersize=10)
        plt.xlabel("Reaction coordinate")
        plt.ylabel("Energy (meV)")
        plt.ylim((np.min(y) - 10, np.max(y) * 1.02 + 20))
        if label_barrier:
            data = zip(x * scale, y)
            barrier = max(data, key=lambda d: d[1])
            plt.plot([0, barrier[0]], [barrier[1], barrier[1]], 'k--')
            plt.annotate('%.0f meV' % barrier[1],
                         xy=(barrier[0] / 2, barrier[1] * 1.02),
                         xytext=(barrier[0] / 2, barrier[1] * 1.02),
                         horizontalalignment='center')
        plt.tight_layout()
        return plt

    @classmethod
    def from_dir(cls, root_dir, relaxation_dirs=None, **kwargs):
        """
        Initializes a NEBAnalysis object from a directory of a NEB run.
        Note that OUTCARs must be present in all image directories. For the
        terminal OUTCARs from relaxation calculations, you can specify the
        locations using relaxation_dir. If these are not specified, the code
        will attempt to look for the OUTCARs in 00 and 0n directories,
        followed by subdirs "start", "end" or "initial", "final" in the
        root_dir. These are just some typical conventions used
        preferentially in Shyue Ping's MAVRL research group. For the
        non-terminal points, the CONTCAR is read to obtain structures. For
        terminal points, the POSCAR is used. The image directories are
        assumed to be the only directories that can be resolved to integers.
        E.g., "00", "01", "02", "03", "04", "05", "06". The minimum
        sub-directory structure that can be parsed is of the following form (
        a 5-image example is shown):

        00:
        - POSCAR
        - OUTCAR
        01, 02, 03, 04, 05:
        - CONTCAR
        - OUTCAR
        06:
        - POSCAR
        - OUTCAR

        Args:
            root_dir (str): Path to the root directory of the NEB calculation.
            relaxation_dirs (tuple): This specifies the starting and ending
                relaxation directories from which the OUTCARs are read for the
                terminal points for the energies.

        Returns:
            NEBAnalysis object.
        """
        neb_dirs = []

        for d in os.listdir(root_dir):
            pth = os.path.join(root_dir, d)
            if os.path.isdir(pth) and d.isdigit():
                i = int(d)
                neb_dirs.append((i, pth))
        neb_dirs = sorted(neb_dirs, key=lambda d: d[0])
        outcars = []
        structures = []

        # Setup the search sequence for the OUTCARs for the terminal
        # directories.
        terminal_dirs = []
        if relaxation_dirs is not None:
            terminal_dirs.append(relaxation_dirs)
        terminal_dirs.append((neb_dirs[0][1], neb_dirs[-1][1]))
        terminal_dirs.append([os.path.join(root_dir, d)
                              for d in ["start", "end"]])
        terminal_dirs.append([os.path.join(root_dir, d)
                              for d in ["initial", "final"]])

        for i, d in neb_dirs:
            outcar = glob.glob(os.path.join(d, "OUTCAR*"))
            contcar = glob.glob(os.path.join(d, "CONTCAR*"))
            poscar = glob.glob(os.path.join(d, "POSCAR*"))
            terminal = i == 0 or i == neb_dirs[-1][0]
            if terminal:
                found = False
                for ds in terminal_dirs:
                    od = ds[0] if i == 0 else ds[1]
                    outcar = glob.glob(os.path.join(od, "OUTCAR*"))
                    if outcar:
                        outcar = sorted(outcar)
                        outcars.append(Outcar(outcar[-1]))
                        found = True
                        break
                if not found:
                    raise ValueError("OUTCAR cannot be found for terminal "
                                     "point %s" % d)
                structures.append(Poscar.from_file(poscar[0]).structure)
            else:
                outcars.append(Outcar(outcar[0]))
                structures.append(Poscar.from_file(contcar[0]).structure)
        return NEBAnalysis.from_outcars(outcars, structures, **kwargs)

    def as_dict(self):
        """
        Dict representation of NEBAnalysis.

        Returns:
            JSON serializable dict representation.
        """
        return {"@module": self.__class__.__module__,
                "@class": self.__class__.__name__,
                'r': jsanitize(self.r),
                'energies': jsanitize(self.energies),
                'forces': jsanitize(self.forces),
                'structures': [s.as_dict() for s in self.structures]}<commit_msg>Fix spline option code. Really super repeititve.<commit_after># coding: utf-8
# Copyright (c) Pymatgen Development Team.
# Distributed under the terms of the MIT License.

from __future__ import division, unicode_literals

import os
import glob

import numpy as np
from monty.json import jsanitize
from monty.json import MSONable
scipy_old_piecewisepolynomial = True
try:
    from scipy.interpolate import PiecewisePolynomial
except ImportError:
    from scipy.interpolate import CubicSpline
    scipy_old_piecewisepolynomial = False

from pymatgen.util.plotting_utils import get_publication_quality_plot
from pymatgen.io.vasp import Poscar, Outcar

"""
Some reimplementation of Henkelman's Transition State Analysis utilities,
which are originally in Perl. Additional features beyond those offered by
Henkelman's utilities will be added.

This allows the usage and customization in Python.
"""

__author__ = 'Shyue Ping Ong'
__copyright__ = 'Copyright 2013, The Materials Virtual Lab'
__version__ = '0.1'
__maintainer__ = 'Shyue Ping Ong'
__email__ = 'ongsp@ucsd.edu'
__date__ = '6/1/15'

class NEBAnalysis(MSONable):
    """
    An NEBAnalysis class.
    """

    def __init__(self, r, energies, forces, structures, spline_options=None,
                 **kwargs):
        """
        Initializes an NEBAnalysis from the cumulative root mean squared distances
        between structures, the energies, the forces, the structures and the
        interpolation_order for the analysis.

        Args:
            r: Root mean square distances between structures
            energies: Energies of each structure along reaction coordinate
            forces: Tangent forces along the reaction coordinate.
            structures ([Structure]): List of Structures along reaction
                coordinate.
        """
        self.r = np.array(r)
        self.energies = np.array(energies)
        self.forces = np.array(forces)
        self.structures = structures
        self.spline_options = spline_options if spline_options is not None \
            else {}

        # We do a piecewise interpolation between the points. Each spline (
        # cubic by default) is constrained by the boundary conditions of the
        # energies and the tangent force, i.e., the derivative of
        # the energy at each pair of points.

        if scipy_old_piecewisepolynomial:
            if self.spline_options:
                raise RuntimeError('Option for saddle point not available with'
                                   'old scipy implementation')
            self.spline = PiecewisePolynomial(
                self.r, np.array([self.energies, -self.forces]).T,
                orders=3)
        else:
            # New scipy implementation for scipy > 0.18.0
            if self.spline_options.get('saddle_point', '') == 'zero_slope':
                imax = np.argmax(self.energies)
                self.spline = CubicSpline(x=self.r[:imax + 1],
                                          y=self.energies[:imax + 1],
                                          bc_type=((1, 0.0), (1, 0.0)))
                cspline2 = CubicSpline(x=self.r[imax:], y=self.energies[imax:],
                                       bc_type=((1, 0.0), (1, 0.0)))
                self.spline.extend(c=cspline2.c, x=cspline2.x[1:])
            else:
                self.spline = CubicSpline(x=self.r, y=self.energies,
                                          bc_type=((1, 0.0), (1, 0.0)))

    @classmethod
    def from_outcars(cls, outcars, structures, **kwargs):
        """
        Initializes an NEBAnalysis from Outcar and Structure objects. Use
        the static constructors, e.g., :class:`from_dir` instead if you
        prefer to have these automatically generated from a directory of NEB
        calculations.

        Args:
            outcars ([Outcar]): List of Outcar objects. Note that these have
                to be ordered from start to end along reaction coordinates.
            structures ([Structure]): List of Structures along reaction
                coordinate. Must be same length as outcar.
            interpolation_order (int): Order of polynomial to use to
                interpolate between images. Same format as order parameter in
                scipy.interplotate.PiecewisePolynomial.
        """
        if len(outcars) != len(structures):
            raise ValueError("# of Outcars must be same as # of Structures")

        # Calculate cumulative root mean square distance between structures,
        # which serves as the reaction coordinate. Note that these are
        # calculated from the final relaxed structures as the coordinates may
        # have changed from the initial interpolation.
        r = [0]
        prev = structures[0]
        for st in structures[1:]:
            dists = np.array([s2.distance(s1) for s1, s2 in zip(prev, st)])
            r.append(np.sqrt(np.sum(dists ** 2)))
            prev = st
        r = np.cumsum(r)

        energies = []
        forces = []
        for i, o in enumerate(outcars):
            o.read_neb()
            energies.append(o.data["energy"])
            if i in [0, len(outcars) - 1]:
                forces.append(0)
            else:
                forces.append(o.data["tangent_force"])
        energies = np.array(energies)
        energies -= energies[0]
        forces = np.array(forces)
        r = np.array(r)
        return cls(r=r, energies=energies, forces=forces, structures=structures, **kwargs)

    def get_extrema(self, normalize_rxn_coordinate=True):
        """
        Returns the positions of the extrema along the MEP. Both local
        minimums and maximums are returned.

        Args:
            normalize_rxn_coordinate (bool): Whether to normalize the
                reaction coordinate to between 0 and 1. Defaults to True.

        Returns:
            (min_extrema, max_extrema), where the extrema are given as
            [(x1, y1), (x2, y2), ...].
        """
        x = np.arange(0, np.max(self.r), 0.01)
        y = self.spline(x) * 1000

        scale = 1 if not normalize_rxn_coordinate else 1 / self.r[-1]
        min_extrema = []
        max_extrema = []
        for i in range(1, len(x) - 1):
            if y[i] < y[i-1] and y[i] < y[i+1]:
                min_extrema.append((x[i] * scale, y[i]))
            elif y[i] > y[i-1] and y[i] > y[i+1]:
                max_extrema.append((x[i] * scale, y[i]))
        return min_extrema, max_extrema

    def get_plot(self, normalize_rxn_coordinate=True, label_barrier=True):
        """
        Returns the NEB plot. Uses Henkelman's approach of spline fitting
        each section of the reaction path based on tangent force and energies.

        Args:
            normalize_rxn_coordinate (bool): Whether to normalize the
                reaction coordinate to between 0 and 1. Defaults to True.
            label_barrier (bool): Whether to label the maximum barrier.

        Returns:
            matplotlib.pyplot object.
        """
        plt = get_publication_quality_plot(12, 8)
        scale = 1 if not normalize_rxn_coordinate else 1 / self.r[-1]
        x = np.arange(0, np.max(self.r), 0.01)
        y = self.spline(x) * 1000
        plt.plot(self.r * scale, self.energies * 1000, 'ro',
                 x * scale, y, 'k-', linewidth=2, markersize=10)
        plt.xlabel("Reaction coordinate")
        plt.ylabel("Energy (meV)")
        plt.ylim((np.min(y) - 10, np.max(y) * 1.02 + 20))
        if label_barrier:
            data = zip(x * scale, y)
            barrier = max(data, key=lambda d: d[1])
            plt.plot([0, barrier[0]], [barrier[1], barrier[1]], 'k--')
            plt.annotate('%.0f meV' % barrier[1],
                         xy=(barrier[0] / 2, barrier[1] * 1.02),
                         xytext=(barrier[0] / 2, barrier[1] * 1.02),
                         horizontalalignment='center')
        plt.tight_layout()
        return plt

    @classmethod
    def from_dir(cls, root_dir, relaxation_dirs=None, **kwargs):
        """
        Initializes a NEBAnalysis object from a directory of a NEB run.
        Note that OUTCARs must be present in all image directories. For the
        terminal OUTCARs from relaxation calculations, you can specify the
        locations using relaxation_dir. If these are not specified, the code
        will attempt to look for the OUTCARs in 00 and 0n directories,
        followed by subdirs "start", "end" or "initial", "final" in the
        root_dir. These are just some typical conventions used
        preferentially in Shyue Ping's MAVRL research group. For the
        non-terminal points, the CONTCAR is read to obtain structures. For
        terminal points, the POSCAR is used. The image directories are
        assumed to be the only directories that can be resolved to integers.
        E.g., "00", "01", "02", "03", "04", "05", "06". The minimum
        sub-directory structure that can be parsed is of the following form (
        a 5-image example is shown):

        00:
        - POSCAR
        - OUTCAR
        01, 02, 03, 04, 05:
        - CONTCAR
        - OUTCAR
        06:
        - POSCAR
        - OUTCAR

        Args:
            root_dir (str): Path to the root directory of the NEB calculation.
            relaxation_dirs (tuple): This specifies the starting and ending
                relaxation directories from which the OUTCARs are read for the
                terminal points for the energies.

        Returns:
            NEBAnalysis object.
        """
        neb_dirs = []

        for d in os.listdir(root_dir):
            pth = os.path.join(root_dir, d)
            if os.path.isdir(pth) and d.isdigit():
                i = int(d)
                neb_dirs.append((i, pth))
        neb_dirs = sorted(neb_dirs, key=lambda d: d[0])
        outcars = []
        structures = []

        # Setup the search sequence for the OUTCARs for the terminal
        # directories.
        terminal_dirs = []
        if relaxation_dirs is not None:
            terminal_dirs.append(relaxation_dirs)
        terminal_dirs.append((neb_dirs[0][1], neb_dirs[-1][1]))
        terminal_dirs.append([os.path.join(root_dir, d)
                              for d in ["start", "end"]])
        terminal_dirs.append([os.path.join(root_dir, d)
                              for d in ["initial", "final"]])

        for i, d in neb_dirs:
            outcar = glob.glob(os.path.join(d, "OUTCAR*"))
            contcar = glob.glob(os.path.join(d, "CONTCAR*"))
            poscar = glob.glob(os.path.join(d, "POSCAR*"))
            terminal = i == 0 or i == neb_dirs[-1][0]
            if terminal:
                found = False
                for ds in terminal_dirs:
                    od = ds[0] if i == 0 else ds[1]
                    outcar = glob.glob(os.path.join(od, "OUTCAR*"))
                    if outcar:
                        outcar = sorted(outcar)
                        outcars.append(Outcar(outcar[-1]))
                        found = True
                        break
                if not found:
                    raise ValueError("OUTCAR cannot be found for terminal "
                                     "point %s" % d)
                structures.append(Poscar.from_file(poscar[0]).structure)
            else:
                outcars.append(Outcar(outcar[0]))
                structures.append(Poscar.from_file(contcar[0]).structure)
        return NEBAnalysis.from_outcars(outcars, structures, **kwargs)

    def as_dict(self):
        """
        Dict representation of NEBAnalysis.

        Returns:
            JSON serializable dict representation.
        """
        return {"@module": self.__class__.__module__,
                "@class": self.__class__.__name__,
                'r': jsanitize(self.r),
                'energies': jsanitize(self.energies),
                'forces': jsanitize(self.forces),
                'structures': [s.as_dict() for s in self.structures]}<|endoftext|>


<commit_before>import os
import json
import cloudstorage as gcs

from flask import Blueprint, request, session
from flask_principal import Permission, RoleNeed

from google.appengine.api import app_identity
from google.appengine.api.images import get_serving_url
from google.appengine.ext import blobstore

from product.model import Product
from user.model import User

from werkzeug.exceptions import HTTPException, Forbidden

admin_permission = Permission(RoleNeed('admin'))

my_default_retry_params = gcs.RetryParams(initial_delay=0.2, max_delay=5.0, backoff_factor=2, max_retry_period=15)
gcs.set_default_retry_params(my_default_retry_params)

product = Blueprint('product', __name__)

@product.route('/category', defaults={'category': None}, methods=['GET'], strict_slashes=False)
@product.route('/category/<string:category>/', methods=['GET'])
def get_all(category=None):
    print category
    if category:
        if category == 'POSSOCOMPRAR':
            user_logged = session['barzinga_user']
            user = User.query().filter(User.email == user_logged["email"]).get()
            products = [p.to_dict() for p in Product.query(Product.price <= user.money).fetch()]
        else:
            products = [p.to_dict() for p in Product.query(Product.category == category).fetch()]
    else :
        products = [p.to_dict() for p in Product.query().fetch()]

    return json.dumps(products)

@product.route('/<int:product_id>', methods=['GET'])
def get_by_id(product_id):
    product = Product.get_by_id(product_id)

    if not product:
        return 'Product id %s not found' % (product_id), 404

    return json.dumps(product.to_dict())

@product.route('/', methods=['POST'])
@admin_permission.require(http_exception=Forbidden())
def add():
    user_logged = session['barzinga_user']
    user_operator = User.query().filter(User.email == user_logged["email"]).get()
    if user_operator.admin:
        bucket_name = os.environ.get('BUCKET_NAME', app_identity.get_default_gcs_bucket_name())
        description = request.form['description']
        category = request.form['category']
        price = float(request.form['price'])
        quantity = int(request.form['quantity'])

        image = request.files['image']
        image_url = None

        if image:
            write_retry_params = gcs.RetryParams(backoff_factor=1.1)
            filename = '/' + bucket_name + '/' + image.filename
            gcs_file = gcs.open(filename, 'w', content_type=image.content_type, retry_params=write_retry_params)
            gcs_file.write(image.read())
            gcs_file.close()

            blobstore_filename = '/gs' + filename
            key = blobstore.create_gs_key(blobstore_filename)

            image_url =  get_serving_url(key)

        product = Product(description=description, price=price, quantity=quantity, category=category, image_url=image_url, bar_code=str(''))
        product.put()

        return '', 204
    else :
        return 'Precisa ser admin para cadastrar produtos', 401

@product.route('/<int:product_id>', methods=['PUT'])
def modify(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    if not product:
        return 'Product id %s not found' % (product_id), 404

    try:
        product.description = request.form['description']
        product.price = float(request.form['price'])
        product.quantity = int(request.form['quantity'])

        product.put()
    except:
        return 'Deu ruim merm\u00E3o', 400

    return '', 204

@product.route('/<int:product_id>/quantity', methods=['PUT'])
def update_quantity(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    product.quantity = int(request.form['quantity'])
    product.put()

    return '', 204

@product.route('/<int:product_id>/add', methods=['PUT'])
def add_quantity(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    product.quantity += int(request.form['quantity'])
    product.put()

    return '', 204

@product.route('/<int:product_id>/bar_code', methods=['PUT'])
def update_bar_code(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    product.bar_code = str(request.form['bar_code'])
    product.put()

    return '', 204

@product.route('/<int:product_id>', methods=['DELETE'])
def delete(product_id):
    product = Product.get_by_id(product_id)

    if not product:
        return 'Product id %s not found' % (product_id), 404

    product.key.delete()

    return '', 204
<commit_msg>Order products by name<commit_after>import os
import json
import cloudstorage as gcs

from flask import Blueprint, request, session
from flask_principal import Permission, RoleNeed

from google.appengine.api import app_identity
from google.appengine.api.images import get_serving_url
from google.appengine.ext import blobstore

from product.model import Product
from user.model import User

from werkzeug.exceptions import HTTPException, Forbidden

admin_permission = Permission(RoleNeed('admin'))

my_default_retry_params = gcs.RetryParams(initial_delay=0.2, max_delay=5.0, backoff_factor=2, max_retry_period=15)
gcs.set_default_retry_params(my_default_retry_params)

product = Blueprint('product', __name__)

@product.route('/category', defaults={'category': None}, methods=['GET'], strict_slashes=False)
@product.route('/category/<string:category>/', methods=['GET'])
def get_all(category=None):
    print category
    if category:
        if category == 'POSSOCOMPRAR':
            user_logged = session['barzinga_user']
            user = User.query().filter(User.email == user_logged["email"]).get()
            products = [p.to_dict() for p in Product.query(Product.price <= user.money).order(Product.description).fetch()]
        else:
            products = [p.to_dict() for p in Product.query(Product.category == category).order(Product.description).fetch()]
    else :
        products = [p.to_dict() for p in Product.query().order(Product.description).fetch()]

    return json.dumps(products)

@product.route('/<int:product_id>', methods=['GET'])
def get_by_id(product_id):
    product = Product.get_by_id(product_id)

    if not product:
        return 'Product id %s not found' % (product_id), 404

    return json.dumps(product.to_dict())

@product.route('/', methods=['POST'])
@admin_permission.require(http_exception=Forbidden())
def add():
    user_logged = session['barzinga_user']
    user_operator = User.query().filter(User.email == user_logged["email"]).get()
    if user_operator.admin:
        bucket_name = os.environ.get('BUCKET_NAME', app_identity.get_default_gcs_bucket_name())
        description = request.form['description']
        category = request.form['category']
        price = float(request.form['price'])
        quantity = int(request.form['quantity'])

        image = request.files['image']
        image_url = None

        if image:
            write_retry_params = gcs.RetryParams(backoff_factor=1.1)
            filename = '/' + bucket_name + '/' + image.filename
            gcs_file = gcs.open(filename, 'w', content_type=image.content_type, retry_params=write_retry_params)
            gcs_file.write(image.read())
            gcs_file.close()

            blobstore_filename = '/gs' + filename
            key = blobstore.create_gs_key(blobstore_filename)

            image_url =  get_serving_url(key)

        product = Product(description=description, price=price, quantity=quantity, category=category, image_url=image_url, bar_code=str(''))
        product.put()

        return '', 204
    else :
        return 'Precisa ser admin para cadastrar produtos', 401

@product.route('/<int:product_id>', methods=['PUT'])
def modify(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    if not product:
        return 'Product id %s not found' % (product_id), 404

    try:
        product.description = request.form['description']
        product.price = float(request.form['price'])
        product.quantity = int(request.form['quantity'])

        product.put()
    except:
        return 'Deu ruim merm\u00E3o', 400

    return '', 204

@product.route('/<int:product_id>/quantity', methods=['PUT'])
def update_quantity(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    product.quantity = int(request.form['quantity'])
    product.put()

    return '', 204

@product.route('/<int:product_id>/add', methods=['PUT'])
def add_quantity(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    product.quantity += int(request.form['quantity'])
    product.put()

    return '', 204

@product.route('/<int:product_id>/bar_code', methods=['PUT'])
def update_bar_code(product_id):
    print product_id
    product = Product.get_by_id(product_id)

    product.bar_code = str(request.form['bar_code'])
    product.put()

    return '', 204

@product.route('/<int:product_id>', methods=['DELETE'])
def delete(product_id):
    product = Product.get_by_id(product_id)

    if not product:
        return 'Product id %s not found' % (product_id), 404

    product.key.delete()

    return '', 204
<|endoftext|>


<commit_before># -*- coding:utf-8 -*-

import locale
import os
import pytest
import datetime

from os.path import join
from sigal.gallery import Album, Media, Image, Video, Gallery

CURRENT_DIR = os.path.dirname(__file__)

REF = {
    'dir1': {
        'title': 'An example gallery',
        'name': 'dir1',
        'thumbnail': 'dir1/test1/thumbnails/11.tn.jpg',
        'subdirs': ['test1', 'test2', 'test3'],
        'medias': [],
    },
    'dir1/test1': {
        'title': 'An example sub-category',
        'name': 'test1',
        'thumbnail': 'test1/thumbnails/11.tn.jpg',
        'subdirs': [],
        'medias': ['11.jpg', 'archlinux-kiss-1024x640.png',
                   'flickr_jerquiaga_2394751088_cc-by-nc.jpg',
                   '50a1d0bc-763d-457e-b634-c87f16a64270.gif'],
    },
    'dir1/test2': {
        'title': 'test2',
        'name': 'test2',
        'thumbnail': 'test2/thumbnails/21.tn.jpg',
        'subdirs': [],
        'medias': ['21.jpg', '22.jpg', 'archlinux-kiss-1024x640.png'],
    },
    'dir1/test3': {
        'title': '01 First title alphabetically',
        'name': 'test3',
        'thumbnail': 'test3/thumbnails/3.tn.jpg',
        'subdirs': [],
        'medias': ['3.jpg'],
    },
    'dir2': {
        'title': 'Another example gallery with a very long name',
        'name': 'dir2',
        'thumbnail': 'dir2/thumbnails/m57_the_ring_nebula-587px.tn.jpg',
        'subdirs': [],
        'medias': ['exo20101028-b-full.jpg',
                   'Hubble Interacting Galaxy NGC 5257.jpg',
                   'Hubble ultra deep field.jpg',
                   'm57_the_ring_nebula-587px.jpg'],
    },
    u'accentué': {
        'title': u'accentué',
        'name': u'accentué',
        'thumbnail': u'accentué/thumbnails/hélicoïde.tn.jpg',
        'subdirs': [],
        'medias': [u'hélicoïde.jpg', 'superdupont_source_wikipedia_en.jpg'],
    },
    'video': {
        'title': 'video',
        'name': 'video',
        'thumbnail': ('video/thumbnails/'
                      'stallman software-freedom-day-low.tn.jpg'),
        'subdirs': [],
        'medias': ['stallman software-freedom-day-low.webm']
    }
}

def test_media(settings):
    m = Media('11.jpg', 'dir1/test1', settings)
    path = join('dir1', 'test1')
    file_path = join(path, '11.jpg')
    thumb = join('thumbnails', '11.tn.jpg')

    assert m.filename == '11.jpg'
    assert m.src_path == join(settings['source'], file_path)
    assert m.dst_path == join(settings['destination'], file_path)
    assert m.thumb_name == thumb
    assert m.thumb_path == join(settings['destination'], path, thumb)
    assert m.title == "Foo Bar"
    assert m.description == "
This is a funny description of this image
"

    assert repr(m) == "<Media>('{}')".format(file_path)
    assert str(m) == file_path

def test_media_orig(settings, tmpdir):
    settings['keep_orig'] = False
    m = Media('11.jpg', 'dir1/test1', settings)
    assert m.big is None

    settings['keep_orig'] = True
    settings['destination'] = str(tmpdir)

    m = Image('11.jpg', 'dir1/test1', settings)
    assert m.big == 'original/11.jpg'

    m = Video('stallman software-freedom-day-low.ogv', 'video', settings)
    assert m.filename == 'stallman software-freedom-day-low.webm'
    assert m.big == 'original/stallman software-freedom-day-low.ogv'
    assert os.path.isfile(join(settings['destination'], m.path, m.big))

    settings['use_orig'] = True

    m = Image('21.jpg', 'dir1/test2', settings)
    assert m.big == '21.jpg'

def test_image(settings, tmpdir):
    settings['destination'] = str(tmpdir)
    m = Image('11.jpg', 'dir1/test1', settings)
    assert m.date == datetime.datetime(2006, 1, 22, 10, 32, 42)
    assert m.exif['datetime'] == u'Sunday, 22. January 2006'

    os.makedirs(join(settings['destination'], 'dir1', 'test1', 'thumbnails'))
    assert m.thumbnail == join('thumbnails', '11.tn.jpg')
    assert os.path.isfile(m.thumb_path)

def test_video(settings, tmpdir):
    settings['destination'] = str(tmpdir)
    m = Video('stallman software-freedom-day-low.ogv', 'video', settings)
    file_path = join('video', 'stallman software-freedom-day-low.webm')
    assert str(m) == file_path
    assert m.dst_path == join(settings['destination'], file_path)

    os.makedirs(join(settings['destination'], 'video', 'thumbnails'))
    assert m.thumbnail == join('thumbnails',
                               'stallman software-freedom-day-low.tn.jpg')
    assert os.path.isfile(m.thumb_path)

@pytest.mark.parametrize("path,album", REF.items())
def test_album(path, album, settings, tmpdir):
    # store current locale
    old_locale = locale.setlocale(locale.LC_ALL)

    # locale.setlocale(locale.LC_ALL, 'fr_FR')
    locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')

    gal = Gallery(settings, ncpu=1)
    a = Album(path, settings, album['subdirs'], album['medias'], gal)

    assert a.title == album['title']
    assert a.name == album['name']
    assert a.subdirs == album['subdirs']
    assert a.thumbnail == album['thumbnail']
    assert [m.filename for m in a.medias] == album['medias']
    assert len(a) == len(album['medias'])

    # restore locale back
    locale.setlocale(locale.LC_ALL, old_locale)

def test_album_medias(settings):
    gal = Gallery(settings, ncpu=1)

    album = REF['dir1/test1']
    a = Album('dir1/test1', settings, album['subdirs'], album['medias'], gal)
    assert list(im.filename for im in a.images) == album['medias']
    assert list(a.videos) == []

    album = REF['video']
    a = Album('video', settings, album['subdirs'], album['medias'], gal)
    assert list(im.filename for im in a.videos) == album['medias']
    assert list(a.images) == []

def test_albums_sort(settings):
    gal = Gallery(settings, ncpu=1)
    album = REF['dir1']
    subdirs = list(album['subdirs'])

    settings['albums_sort_reverse'] = False
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('')
    assert [alb.name for alb in a.albums] == subdirs

    settings['albums_sort_reverse'] = True
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('')
    assert [alb.name for alb in a.albums] == list(reversed(subdirs))

    titles = [im.title for im in a.albums]
    titles.sort()
    settings['albums_sort_reverse'] = False
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('title')
    assert [im.title for im in a.albums] == titles

    settings['albums_sort_reverse'] = True
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('title')
    assert [im.title for im in a.albums] == list(reversed(titles))

def test_medias_sort(settings):
    gal = Gallery(settings, ncpu=1)
    album = REF['dir1/test2']

    settings['medias_sort_reverse'] = True
    a = Album('dir1/test2', settings, album['subdirs'], album['medias'], gal)
    a.sort_medias(settings['medias_sort_attr'])
    assert [im.filename for im in a.images] == list(reversed(album['medias']))

    settings['medias_sort_attr'] = 'date'
    settings['medias_sort_reverse'] = False
    a = Album('dir1/test2', settings, album['subdirs'], album['medias'], gal)
    a.sort_medias(settings['medias_sort_attr'])
    assert [im.filename for im in a.images] == ['22.jpg', '21.jpg',
                                                'archlinux-kiss-1024x640.png']

def test_gallery(settings, tmpdir):
    "Test the Gallery class."

    settings['destination'] = str(tmpdir)
    gal = Gallery(settings, ncpu=1)
    gal.build()

    out_html = os.path.join(settings['destination'], 'index.html')
    assert os.path.isfile(out_html)

    with open(out_html, 'r') as f:
        html = f.read()

    assert '<title>Sigal test gallery</title>' in html

def test_empty_dirs(settings):
    gal = Gallery(settings, ncpu=1)
    assert 'empty' not in gal.albums
    assert 'dir1/empty' not in gal.albums

def test_ignores(settings, tmpdir):
    tmp = str(tmpdir)
    settings['destination'] = tmp
    settings['ignore_directories'] = ['*test2']
    settings['ignore_files'] = ['dir2/Hubble*', '*.png']
    gal = Gallery(settings, ncpu=1)
    gal.build()

    assert 'test2' not in os.listdir(join(tmp, 'dir1'))
    assert 'archlinux-kiss-1024x640.png' not in os.listdir(
        join(tmp, 'dir1', 'test1'))
    assert 'Hubble Interacting Galaxy NGC 5257.jpg' not in os.listdir(
        join(tmp, 'dir2'))
<commit_msg>Test that exception is raised in debug mode.<commit_after># -*- coding:utf-8 -*-

import locale
import logging
import os
import pytest
import datetime

from os.path import join
from sigal.gallery import Album, Media, Image, Video, Gallery
from sigal.video import SubprocessException

CURRENT_DIR = os.path.dirname(__file__)

REF = {
    'dir1': {
        'title': 'An example gallery',
        'name': 'dir1',
        'thumbnail': 'dir1/test1/thumbnails/11.tn.jpg',
        'subdirs': ['test1', 'test2', 'test3'],
        'medias': [],
    },
    'dir1/test1': {
        'title': 'An example sub-category',
        'name': 'test1',
        'thumbnail': 'test1/thumbnails/11.tn.jpg',
        'subdirs': [],
        'medias': ['11.jpg', 'archlinux-kiss-1024x640.png',
                   'flickr_jerquiaga_2394751088_cc-by-nc.jpg',
                   '50a1d0bc-763d-457e-b634-c87f16a64270.gif'],
    },
    'dir1/test2': {
        'title': 'test2',
        'name': 'test2',
        'thumbnail': 'test2/thumbnails/21.tn.jpg',
        'subdirs': [],
        'medias': ['21.jpg', '22.jpg', 'archlinux-kiss-1024x640.png'],
    },
    'dir1/test3': {
        'title': '01 First title alphabetically',
        'name': 'test3',
        'thumbnail': 'test3/thumbnails/3.tn.jpg',
        'subdirs': [],
        'medias': ['3.jpg'],
    },
    'dir2': {
        'title': 'Another example gallery with a very long name',
        'name': 'dir2',
        'thumbnail': 'dir2/thumbnails/m57_the_ring_nebula-587px.tn.jpg',
        'subdirs': [],
        'medias': ['exo20101028-b-full.jpg',
                   'Hubble Interacting Galaxy NGC 5257.jpg',
                   'Hubble ultra deep field.jpg',
                   'm57_the_ring_nebula-587px.jpg'],
    },
    u'accentué': {
        'title': u'accentué',
        'name': u'accentué',
        'thumbnail': u'accentué/thumbnails/hélicoïde.tn.jpg',
        'subdirs': [],
        'medias': [u'hélicoïde.jpg', 'superdupont_source_wikipedia_en.jpg'],
    },
    'video': {
        'title': 'video',
        'name': 'video',
        'thumbnail': ('video/thumbnails/'
                      'stallman software-freedom-day-low.tn.jpg'),
        'subdirs': [],
        'medias': ['stallman software-freedom-day-low.webm']
    }
}

def test_media(settings):
    m = Media('11.jpg', 'dir1/test1', settings)
    path = join('dir1', 'test1')
    file_path = join(path, '11.jpg')
    thumb = join('thumbnails', '11.tn.jpg')

    assert m.filename == '11.jpg'
    assert m.src_path == join(settings['source'], file_path)
    assert m.dst_path == join(settings['destination'], file_path)
    assert m.thumb_name == thumb
    assert m.thumb_path == join(settings['destination'], path, thumb)
    assert m.title == "Foo Bar"
    assert m.description == "
This is a funny description of this image
"

    assert repr(m) == "<Media>('{}')".format(file_path)
    assert str(m) == file_path

def test_media_orig(settings, tmpdir):
    settings['keep_orig'] = False
    m = Media('11.jpg', 'dir1/test1', settings)
    assert m.big is None

    settings['keep_orig'] = True
    settings['destination'] = str(tmpdir)

    m = Image('11.jpg', 'dir1/test1', settings)
    assert m.big == 'original/11.jpg'

    m = Video('stallman software-freedom-day-low.ogv', 'video', settings)
    assert m.filename == 'stallman software-freedom-day-low.webm'
    assert m.big == 'original/stallman software-freedom-day-low.ogv'
    assert os.path.isfile(join(settings['destination'], m.path, m.big))

    settings['use_orig'] = True

    m = Image('21.jpg', 'dir1/test2', settings)
    assert m.big == '21.jpg'

def test_image(settings, tmpdir):
    settings['destination'] = str(tmpdir)
    m = Image('11.jpg', 'dir1/test1', settings)
    assert m.date == datetime.datetime(2006, 1, 22, 10, 32, 42)
    assert m.exif['datetime'] == u'Sunday, 22. January 2006'

    os.makedirs(join(settings['destination'], 'dir1', 'test1', 'thumbnails'))
    assert m.thumbnail == join('thumbnails', '11.tn.jpg')
    assert os.path.isfile(m.thumb_path)

def test_video(settings, tmpdir):
    settings['destination'] = str(tmpdir)
    m = Video('stallman software-freedom-day-low.ogv', 'video', settings)
    file_path = join('video', 'stallman software-freedom-day-low.webm')
    assert str(m) == file_path
    assert m.dst_path == join(settings['destination'], file_path)

    os.makedirs(join(settings['destination'], 'video', 'thumbnails'))
    assert m.thumbnail == join('thumbnails',
                               'stallman software-freedom-day-low.tn.jpg')
    assert os.path.isfile(m.thumb_path)

@pytest.mark.parametrize("path,album", REF.items())
def test_album(path, album, settings, tmpdir):
    # store current locale
    old_locale = locale.setlocale(locale.LC_ALL)

    # locale.setlocale(locale.LC_ALL, 'fr_FR')
    locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')

    gal = Gallery(settings, ncpu=1)
    a = Album(path, settings, album['subdirs'], album['medias'], gal)

    assert a.title == album['title']
    assert a.name == album['name']
    assert a.subdirs == album['subdirs']
    assert a.thumbnail == album['thumbnail']
    assert [m.filename for m in a.medias] == album['medias']
    assert len(a) == len(album['medias'])

    # restore locale back
    locale.setlocale(locale.LC_ALL, old_locale)

def test_album_medias(settings):
    gal = Gallery(settings, ncpu=1)

    album = REF['dir1/test1']
    a = Album('dir1/test1', settings, album['subdirs'], album['medias'], gal)
    assert list(im.filename for im in a.images) == album['medias']
    assert list(a.videos) == []

    album = REF['video']
    a = Album('video', settings, album['subdirs'], album['medias'], gal)
    assert list(im.filename for im in a.videos) == album['medias']
    assert list(a.images) == []

def test_albums_sort(settings):
    gal = Gallery(settings, ncpu=1)
    album = REF['dir1']
    subdirs = list(album['subdirs'])

    settings['albums_sort_reverse'] = False
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('')
    assert [alb.name for alb in a.albums] == subdirs

    settings['albums_sort_reverse'] = True
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('')
    assert [alb.name for alb in a.albums] == list(reversed(subdirs))

    titles = [im.title for im in a.albums]
    titles.sort()
    settings['albums_sort_reverse'] = False
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('title')
    assert [im.title for im in a.albums] == titles

    settings['albums_sort_reverse'] = True
    a = Album('dir1', settings, album['subdirs'], album['medias'], gal)
    a.sort_subdirs('title')
    assert [im.title for im in a.albums] == list(reversed(titles))

def test_medias_sort(settings):
    gal = Gallery(settings, ncpu=1)
    album = REF['dir1/test2']

    settings['medias_sort_reverse'] = True
    a = Album('dir1/test2', settings, album['subdirs'], album['medias'], gal)
    a.sort_medias(settings['medias_sort_attr'])
    assert [im.filename for im in a.images] == list(reversed(album['medias']))

    settings['medias_sort_attr'] = 'date'
    settings['medias_sort_reverse'] = False
    a = Album('dir1/test2', settings, album['subdirs'], album['medias'], gal)
    a.sort_medias(settings['medias_sort_attr'])
    assert [im.filename for im in a.images] == ['22.jpg', '21.jpg',
                                                'archlinux-kiss-1024x640.png']

def test_gallery(settings, tmpdir):
    "Test the Gallery class."

    settings['destination'] = str(tmpdir)
    settings['webm_options'] = ['-missing-option', 'foobar']

    gal = Gallery(settings, ncpu=1)
    gal.build()

    out_html = os.path.join(settings['destination'], 'index.html')
    assert os.path.isfile(out_html)

    with open(out_html, 'r') as f:
        html = f.read()

    assert '<title>Sigal test gallery</title>' in html

    logging.getLogger('sigal').setLevel(logging.DEBUG)
    gal = Gallery(settings, ncpu=1)
    with pytest.raises(SubprocessException):
        gal.build()

def test_empty_dirs(settings):
    gal = Gallery(settings, ncpu=1)
    assert 'empty' not in gal.albums
    assert 'dir1/empty' not in gal.albums

def test_ignores(settings, tmpdir):
    tmp = str(tmpdir)
    settings['destination'] = tmp
    settings['ignore_directories'] = ['*test2']
    settings['ignore_files'] = ['dir2/Hubble*', '*.png']
    gal = Gallery(settings, ncpu=1)
    gal.build()

    assert 'test2' not in os.listdir(join(tmp, 'dir1'))
    assert 'archlinux-kiss-1024x640.png' not in os.listdir(
        join(tmp, 'dir1', 'test1'))
    assert 'Hubble Interacting Galaxy NGC 5257.jpg' not in os.listdir(
        join(tmp, 'dir2'))
<|endoftext|>


<commit_before>"""Implements asyncore-based generic DGRAM transport"""
from socket import SOCK_DGRAM, error
from errno import EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN
from pysnmp.carrier.asynsock.base import AbstractSocketTransport
from pysnmp.carrier import error

class DgramSocketTransport(AbstractSocketTransport):
    sockType = SOCK_DGRAM
    retryCount = 3; retryInterval = 1
    def __init__(self, sock=None, sockMap=None):
        self.__outQueue = []
        AbstractSocketTransport.__init__(self, sock, sockMap)

    def openClientMode(self, iface=None):
        if iface is not None:
            try:
                self.socket.bind(iface)
            except error, why:
                raise error.CarrierError('bind() failed: %s' % why)
        return self

    def openServerMode(self, iface):
        try:
            self.socket.bind(iface)
        except error, why:
            raise error.CarrierError('bind() failed: %s' % why)
        self._iface = iface
        return self

    def rewriteAddress(self, transportAddress): return transportAddress

    def sendMessage(self, outgoingMessage, transportAddress):
        self.__outQueue.append(
            (outgoingMessage, self.rewriteAddress(transportAddress))
            )

    # asyncore API
    def handle_connect(self): pass
    def writable(self): return self.__outQueue
    def handle_write(self):
        outgoingMessage, transportAddress = self.__outQueue.pop()
        try:
            self.socket.sendto(outgoingMessage, transportAddress)
        except error, why:
            if why[0] != EWOULDBLOCK:
                raise error, why
    def readable(self): return 1
    def handle_read(self):
        try:
            incomingMessage, transportAddress = self.socket.recvfrom(65535)
            if not incomingMessage:
                self.handle_close()
                return
            else:
                self._cbFun(self, transportAddress, incomingMessage)
                return
        except error, why:
            # winsock sometimes throws ENOTCONN
            if why[0] in [ECONNRESET, ENOTCONN, ESHUTDOWN]:
                self.handle_close()
                return
            else:
                raise error, why
<commit_msg>minor layout changes<commit_after>"""Implements asyncore-based generic DGRAM transport"""
import socket, errno
from pysnmp.carrier.asynsock.base import AbstractSocketTransport
from pysnmp.carrier import error

class DgramSocketTransport(AbstractSocketTransport):
    sockType = socket.SOCK_DGRAM
    retryCount = 3; retryInterval = 1
    def __init__(self, sock=None, sockMap=None):
        self.__outQueue = []
        AbstractSocketTransport.__init__(self, sock, sockMap)

    def openClientMode(self, iface=None):
        if iface is not None:
            try:
                self.socket.bind(iface)
            except socket.error, why:
                raise error.CarrierError('bind() failed: %s' % why)
        return self

    def openServerMode(self, iface):
        try:
            self.socket.bind(iface)
        except socket.error, why:
            raise error.CarrierError('bind() failed: %s' % why)
        self._iface = iface
        return self

    def rewriteAddress(self, transportAddress): return transportAddress

    def sendMessage(self, outgoingMessage, transportAddress):
        self.__outQueue.append(
            (outgoingMessage, self.rewriteAddress(transportAddress))
            )

    # asyncore API
    def handle_connect(self): pass
    def writable(self): return self.__outQueue
    def handle_write(self):
        outgoingMessage, transportAddress = self.__outQueue.pop()
        try:
            self.socket.sendto(outgoingMessage, transportAddress)
        except socket.error, why:
            if why[0] != socket.EWOULDBLOCK:
                raise socket.error, why
    def readable(self): return 1
    def handle_read(self):
        try:
            incomingMessage, transportAddress = self.socket.recvfrom(65535)
            if not incomingMessage:
                self.handle_close()
                return
            else:
                self._cbFun(self, transportAddress, incomingMessage)
                return
        except socket.error, why:
            # winsock sometimes throws ENOTCONN
            if why[0] in (socket.ECONNRESET, socket.ENOTCONN, socket.ESHUTDOWN):
                self.handle_close()
                return
            else:
                raise socket.error, why
<|endoftext|>


<commit_before>##
## Author(s):
##  - Cedric GESTES <gestes@aldebaran-robotics.com>
##
## Copyright (C) 2010, 2011 Aldebaran Robotics
##

"""Init a new qisrc workspace """

import os
import qitools
import qisrc

def configure_parser(parser):
    """Configure parser for this action """
    qitools.qiworktree.work_tree_parser(parser)
    parser.add_argument("--continue", action="store_true", dest="continue_on_error", help="continue on error")

def do(args):
    """Main entry point"""
    qiwt = qitools.qiworktree.open(args.work_tree, use_env=True)
    for git_project in qiwt.git_projects.values():
        try:
            git = qisrc.git.open(git_project)
            #TODO: replace by try/except?
            if git.is_valid():
                print "pull:", git_project
                git.pull()
        except Exception, e:
            if (args.continue_on_error):
                continue
            else:
                raise

if __name__ == "__main__" :
    import sys
    qitools.cmdparse.sub_command_main(sys.modules[__name__])
<commit_msg>qisrc pull: support --rebase<commit_after>##
## Author(s):
##  - Cedric GESTES <gestes@aldebaran-robotics.com>
##
## Copyright (C) 2010, 2011 Aldebaran Robotics
##

"""Init a new qisrc workspace """

import os
import qitools
import qisrc

def configure_parser(parser):
    """Configure parser for this action """
    qitools.qiworktree.work_tree_parser(parser)
    parser.add_argument("--continue", action="store_true", dest="continue_on_error", help="continue on error")
    parser.add_argument("--rebase", action="store_true", dest="rebase", help="rebase")

def do(args):
    """Main entry point"""
    qiwt = qitools.qiworktree.open(args.work_tree, use_env=True)
    for git_project in qiwt.git_projects.values():
        try:
            git = qisrc.git.open(git_project)
            #TODO: replace by try/except?
            if git.is_valid():
                print "pull:", git_project
                if args.rebase:
                    git.pull('--rebase')
                else:
                    git.pull()
        except Exception, e:
            if (args.continue_on_error):
                continue
            else:
                raise

if __name__ == "__main__" :
    import sys
    qitools.cmdparse.sub_command_main(sys.modules[__name__])
<|endoftext|>


<commit_before>import os
import shutil
import subprocess as sub
import tempfile
import unittest
import logging

logging.basicConfig(format='%(levelname)s:%(filename)s:%(message)s')

def call(cmd, *args, **kwargs):

    if isinstance(cmd, str):
        cmd = cmd.split()

    logging.info('`{}`'.format(' '.join(cmd)))

    try:
        output = sub.check_output(cmd, *args, **kwargs)

    except sub.CalledProcessError as e:
        logging.error("cmd `{}` returned {}\n".format(e.cmd, e.returncode))
        logging.error("The output of the command was: \n")
        logging.error("{}\n".format(e.output))
    return output

def git(cliargs, *args, **kwargs):
    if isinstance(cliargs, str):
        cliargs = cliargs.split()
    cmd = ['git'] + cliargs
    return call(cmd)

def commit(message):
    git('add -A')
    git(['commit', '-m', message])

def read_index(filename):
    objhash = git(['hash-object', filename])
    contents = git('cat-file -p {}'.format(objhash))
    return contents

class Base(unittest.TestCase):

    def setUp(self):
        """ Get me into an initialized git directory! """
        # Configure path to use development git-fat binary script
        self.oldpath = os.environ["PATH"]
        test_dir = os.path.dirname(os.path.realpath(__file__))
        os.environ["PATH"] = ':'.join([test_dir] + self.oldpath.split(':'))

        self.olddir = os.getcwd()

        # Can't test in the repo
        # Easiest way is to do it in temp dir
        self.tempdir = tempfile.mkdtemp(prefix='git-fat-test')
        logging.info("tempdir: {}".format(self.tempdir))

        os.chdir(self.tempdir)

        self.fatstore = os.path.join(self.tempdir, 'fat-store')
        os.mkdir(self.fatstore)

        self.repo = os.path.join(self.tempdir, 'fat-test1')
        git('init {}'.format(self.repo))
        os.chdir(self.repo)

    def _setup_gitfat_files(self):
        with open('.gitfat', 'w') as f:
            f.write('[copy]\nremote={}'.format(self.fatstore))
        with open('.gitattributes', 'w') as f:
            f.write('*.fat filter=fat -crlf')

    def tearDown(self):
        os.chdir(self.olddir)
        shutil.rmtree(self.tempdir)
        os.environ["PATH"] = self.oldpath

class InitTestCase(Base):

    def test_git_fat_init(self):
        with open('.gitfat', 'w') as f:
            f.write('[copy]\nremote={}'.format(self.fatstore))
        out = git('fat init')
        expect = 'Setting filters in .git/config\nCreating .git/fat/objects\nInitialized git-fat'.strip()
        self.assertEqual(out.strip(), expect)
        self.assertTrue(os.path.isdir('.git/fat/objects'))

        out = git('config filter.fat.clean')
        self.assertEqual(out.strip(), 'git-fat filter-clean %f')

        out = git('config filter.fat.smudge')
        self.assertEqual(out.strip(), 'git-fat filter-smudge %f')

    def test_existing_files_pattern_match(self):
        """ Don't convert existing files into git-fat files unless they get renamed """

        expect = 'a fat file'
        with open('a.fat', 'w') as f:
            f.write(expect)

        commit('initial')

        # Setup git-fat after first commit
        self._setup_gitfat_files()
        git('fat init')

        # Initializing git-fat doesn't convert it
        with open('a.fat', 'r') as f:
            actual = f.read()
        self.assertEqual(expect, actual)
        actual = read_index('a.fat')
        self.assertEqual(expect, actual)

        # change the repo without changing a.fat
        with open('README', 'w') as f:
            f.write("something else changed")
        commit('a.fat doesnt change')
        actual = read_index('a.fat')
        self.assertEqual(expect, actual)

        # changing the file alone doesn't convert it
        append_me = '\nmore stuff'
        with open('a.fat', 'a') as f:
            f.write(append_me)
        commit('a.fat changed')
        actual = read_index('a.fat')
        self.assertEqual(expect + append_me, actual)

        # finally, rename the file
        os.rename('a.fat', 'b.fat')
        commit('a.fat->b.fat')
        actual = read_index('b.fat')
        expect = '#$# git-fat ebf646b3730c9f5ec2625081eb488c55000f622e                   21\n'
        self.assertEqual(expect, actual)

class InitRepoTestCase(Base):

    def setUp(self):
        super(InitRepoTestCase, self).setUp()

        self._setup_gitfat_files()
        git('fat init')
        commit('inital')

class FileTypeTestCase(InitRepoTestCase):

    def test_symlink_74bytes(self):
        """ Verify symlinks which match magiclen don't get converted """
        # Create broken symlink
        # is exactly 74 bytes, the magic length
        os.symlink('/oe/dss-oe/dss-add-ons-testing-build/deploy/licenses/common-licenses/GPL-3', 'c.fat')
        git('add c.fat')
        git('commit -m"added_symlink"')
        self.assertTrue(os.path.islink('c.fat'))

    def test_file_with_spaces(self):
        """ Ensure that files with spaces don't make git-fat barf """
        contents = 'This is a fat file\n'
        filename = 'A fat file with spaces.fat'
        with open(filename, 'w') as f:
            f.write(contents)
        commit("Nobody expects a space inafilename")
        self.assertTrue('#$# git-fat ' in read_index(filename))

class GeneralTestCase(InitRepoTestCase):

    def setUp(self):
        super(GeneralTestCase, self).setUp()

        filename = 'a.fat'
        contents = 'a'
        with open(filename, 'w') as f:
            f.write(contents * 1024)
        filename = 'b.fat'
        with open(filename, 'w') as f:
            f.write(contents * 1024 * 1024)
        filename = 'c d e.fat'
        with open(filename, 'w') as f:
            f.write(contents * 2048 * 1024)
        commit("add fatfiles")

    def test_status(self):
        out = git('fat status')
        self.assertEqual(out, '')
        objhash = read_index('b.fat').split()[2]
        path = os.path.join(os.getcwd(), '.git/fat/objects', objhash)
        os.rename(path, os.path.join(self.tempdir, objhash))
        os.remove('b.fat')

        # Need to checkout the file again so that it can be re-smudged
        git('checkout b.fat')

        # get the hash
        out = git('fat status')
        self.assertTrue('Orphan' in out)
        self.assertTrue(objhash in out)

        # Remove the file again
        os.remove('b.fat')
        # commit this time
        commit('remove file')

        os.rename(os.path.join(self.tempdir, objhash), path)
        # get the hash
        out = git('fat status')
        self.assertTrue('Stale' in out)
        self.assertTrue(objhash in out)

    def test_list(self):
        files = ('a.fat', 'b.fat', 'c d e.fat')
        hashes = {f: read_index(f).split()[2] for f in files}

        out = git('fat list')
        lines = out.split('\n')[:-1]  # ignore trailing newline
        for line in lines:
            objhash, filename = line.split(' ', 1)
            self.assertEqual(hashes[filename], objhash)

    def test_find(self):
        contents = 'b'

        filename = 'small.sh'
        with open(filename, 'w') as f:
            f.write(contents * 9990)
        # make sure they don't match our filter first
        filename = 'b.notfat'
        with open(filename, 'w') as f:
            f.write(contents * 1024 * 1024)
        filename = 'c d e.notfat'
        with open(filename, 'w') as f:
            f.write(contents * 2048 * 1024)
        commit('oops, added files not matching .gitattributes')
        out = git('fat find 10000')
        self.assertTrue('b.notfat' in out)
        self.assertTrue('c d e.notfat' in out)
        self.assertTrue('small.sh' not in out)

if __name__ == "__main__":
    logging.basicConfig(format='%(levelname)s:%(filename)s:%(message)s', level=logging.DEBUG)
    unittest.main()
<commit_msg>Coverage working again<commit_after>import os
import shutil
import subprocess as sub
import tempfile
import unittest
import logging
import time

logging.basicConfig(format='%(levelname)s:%(filename)s:%(message)s')

def call(cmd, *args, **kwargs):

    if isinstance(cmd, str):
        cmd = cmd.split()

    logging.info('`{}`'.format(' '.join(cmd)))

    try:
        output = sub.check_output(cmd, *args, **kwargs)

    except sub.CalledProcessError as e:
        logging.error("cmd `{}` returned {}\n".format(e.cmd, e.returncode))
        logging.error("The output of the command was: \n")
        logging.error("{}\n".format(e.output))
    return output

def git(cliargs, *args, **kwargs):
    if isinstance(cliargs, str):
        cliargs = cliargs.split()
    cmd = ['git'] + cliargs
    return call(cmd)

def commit(message):
    git('add -A')
    git(['commit', '-m', message])

def read_index(filename):
    objhash = git(['hash-object', filename])
    contents = git('cat-file -p {}'.format(objhash))
    return contents

class Base(unittest.TestCase):

    def setUp(self):
        """ Get me into an initialized git directory! """
        # Configure path to use development git-fat binary script
        self.oldpath = os.environ["PATH"]
        test_dir = os.path.dirname(os.path.realpath(__file__))
        os.environ["PATH"] = ':'.join([test_dir] + self.oldpath.split(':'))

        self.olddir = os.getcwd()

        # Can't test in the repo
        # Easiest way is to do it in temp dir
        self.tempdir = tempfile.mkdtemp(prefix='git-fat-test')
        logging.info("tempdir: {}".format(self.tempdir))

        os.chdir(self.tempdir)

        self.fatstore = os.path.join(self.tempdir, 'fat-store')
        os.mkdir(self.fatstore)

        self.repo = os.path.join(self.tempdir, 'fat-test1')
        git('init {}'.format(self.repo))
        os.chdir(self.repo)

    def _setup_gitfat_files(self):
        with open('.gitfat', 'w') as f:
            f.write('[copy]\nremote={}'.format(self.fatstore))
        with open('.gitattributes', 'w') as f:
            f.write('*.fat filter=fat -crlf')

    def tearDown(self):
        call('coverage combine')
        os.rename(os.path.join(self.repo, '.coverage'),
            os.path.join(self.olddir, '.coverage.{}'.format(time.time())))
        os.chdir(self.olddir)
        shutil.rmtree(self.tempdir)
        os.environ["PATH"] = self.oldpath

class InitTestCase(Base):

    def test_git_fat_init(self):
        with open('.gitfat', 'w') as f:
            f.write('[copy]\nremote={}'.format(self.fatstore))
        out = git('fat init')
        expect = 'Setting filters in .git/config\nCreating .git/fat/objects\nInitialized git-fat'.strip()
        self.assertEqual(out.strip(), expect)
        self.assertTrue(os.path.isdir('.git/fat/objects'))

        out = git('config filter.fat.clean')
        self.assertEqual(out.strip(), 'git-fat filter-clean %f')

        out = git('config filter.fat.smudge')
        self.assertEqual(out.strip(), 'git-fat filter-smudge %f')

    def test_existing_files_pattern_match(self):
        """ Don't convert existing files into git-fat files unless they get renamed """

        expect = 'a fat file'
        with open('a.fat', 'w') as f:
            f.write(expect)

        commit('initial')

        # Setup git-fat after first commit
        self._setup_gitfat_files()
        git('fat init')

        # Initializing git-fat doesn't convert it
        with open('a.fat', 'r') as f:
            actual = f.read()
        self.assertEqual(expect, actual)
        actual = read_index('a.fat')
        self.assertEqual(expect, actual)

        # change the repo without changing a.fat
        with open('README', 'w') as f:
            f.write("something else changed")
        commit('a.fat doesnt change')
        actual = read_index('a.fat')
        self.assertEqual(expect, actual)

        # changing the file alone doesn't convert it
        append_me = '\nmore stuff'
        with open('a.fat', 'a') as f:
            f.write(append_me)
        commit('a.fat changed')
        actual = read_index('a.fat')
        self.assertEqual(expect + append_me, actual)

        # finally, rename the file
        os.rename('a.fat', 'b.fat')
        commit('a.fat->b.fat')
        actual = read_index('b.fat')
        expect = '#$# git-fat ebf646b3730c9f5ec2625081eb488c55000f622e                   21\n'
        self.assertEqual(expect, actual)

class InitRepoTestCase(Base):

    def setUp(self):
        super(InitRepoTestCase, self).setUp()

        self._setup_gitfat_files()
        git('fat init')
        commit('inital')

class FileTypeTestCase(InitRepoTestCase):

    def test_symlink_74bytes(self):
        """ Verify symlinks which match magiclen don't get converted """
        # Create broken symlink
        # is exactly 74 bytes, the magic length
        os.symlink('/oe/dss-oe/dss-add-ons-testing-build/deploy/licenses/common-licenses/GPL-3', 'c.fat')
        git('add c.fat')
        git('commit -m"added_symlink"')
        self.assertTrue(os.path.islink('c.fat'))

    def test_file_with_spaces(self):
        """ Ensure that files with spaces don't make git-fat barf """
        contents = 'This is a fat file\n'
        filename = 'A fat file with spaces.fat'
        with open(filename, 'w') as f:
            f.write(contents)
        commit("Nobody expects a space inafilename")
        self.assertTrue('#$# git-fat ' in read_index(filename))

class GeneralTestCase(InitRepoTestCase):

    def setUp(self):
        super(GeneralTestCase, self).setUp()

        filename = 'a.fat'
        contents = 'a'
        with open(filename, 'w') as f:
            f.write(contents * 1024)
        filename = 'b.fat'
        with open(filename, 'w') as f:
            f.write(contents * 1024 * 1024)
        filename = 'c d e.fat'
        with open(filename, 'w') as f:
            f.write(contents * 2048 * 1024)
        commit("add fatfiles")

    def test_status(self):
        out = git('fat status')
        self.assertEqual(out, '')
        objhash = read_index('b.fat').split()[2]
        path = os.path.join(os.getcwd(), '.git/fat/objects', objhash)
        os.rename(path, os.path.join(self.tempdir, objhash))
        os.remove('b.fat')

        # Need to checkout the file again so that it can be re-smudged
        git('checkout b.fat')

        # get the hash
        out = git('fat status')
        self.assertTrue('Orphan' in out)
        self.assertTrue(objhash in out)

        # Remove the file again
        os.remove('b.fat')
        # commit this time
        commit('remove file')

        os.rename(os.path.join(self.tempdir, objhash), path)
        # get the hash
        out = git('fat status')
        self.assertTrue('Stale' in out)
        self.assertTrue(objhash in out)

    def test_list(self):
        files = ('a.fat', 'b.fat', 'c d e.fat')
        hashes = {f: read_index(f).split()[2] for f in files}

        out = git('fat list')
        lines = out.split('\n')[:-1]  # ignore trailing newline
        for line in lines:
            objhash, filename = line.split(' ', 1)
            self.assertEqual(hashes[filename], objhash)

    def test_find(self):
        contents = 'b'

        filename = 'small.sh'
        with open(filename, 'w') as f:
            f.write(contents * 9990)
        # make sure they don't match our filter first
        filename = 'b.notfat'
        with open(filename, 'w') as f:
            f.write(contents * 1024 * 1024)
        filename = 'c d e.notfat'
        with open(filename, 'w') as f:
            f.write(contents * 2048 * 1024)
        commit('oops, added files not matching .gitattributes')
        out = git('fat find 10000')
        self.assertTrue('b.notfat' in out)
        self.assertTrue('c d e.notfat' in out)
        self.assertTrue('small.sh' not in out)

if __name__ == "__main__":
    logging.basicConfig(format='%(levelname)s:%(filename)s:%(message)s', level=logging.DEBUG)
    unittest.main()
<|endoftext|>


<commit_before>## Copyright (C) 2011 Aldebaran Robotics

import os
import logging
from qitools.cmdparse    import default_parser
from qitools.configstore import ConfigStore
import qitools.sh

LOGGER = logging.getLogger("QiWorkTree")

class WorkTreeException(Exception):
    """Custom excpetion """
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return self.message

def work_tree_parser(parser):
    """ Parser settings for every action using a toc dir
    """
    default_parser(parser)
    parser.add_argument("--work-tree", help="Use a specific work tree path.")

class QiWorkTree:
    """ This class represent a Qi worktree.
        - work_tree
        - configstore
        - buildable projects
        - git projects
    """

    def __init__(self, work_tree):
        self.work_tree          = work_tree
        self.configstore        = ConfigStore()
        self.buildable_projects = dict()
        self.git_projects       = dict()
        self.user_config_path   = os.path.join(self.work_tree, ".qi", "build.cfg")

        self._load_projects()
        self._load_configuration()

    def _load_projects(self):
        (git_p, src_p) = search_projects(self.work_tree)
        for d in src_p:
            # Get the name of the project from its directory:
            project_name = project_name_from_directory(d)
            self.buildable_projects[project_name] = d
        for d in git_p:
            self.git_projects[os.path.basename(d)] = d

    def _load_configuration(self):
        for name, ppath in self.buildable_projects.iteritems():
            self.configstore.read(os.path.join(ppath, "qibuild.manifest"))
        if os.path.exists(self.user_config_path):
            self.configstore.read(self.user_config_path)
            LOGGER.debug("[Qi] worktree configuration:\n" + str(self.configstore))

def qiworktree_open(work_tree=None, use_env=False):
    """ open a qi worktree
        return a valid QiWorkTree instance
        TODO: explain why we search for manifest
    """
    if not work_tree:
        work_tree = guess_work_tree(use_env)
        LOGGER.debug("found a qi worktree: %s", work_tree)
    if not work_tree:
        work_tree = search_manifest_directory(os.getcwd())
        LOGGER.debug("no work tree found using the project root: %s", work_tree)
    if work_tree is None:
        raise WorkTreeException("Could not find a work tree\n "
            "Here is what you can do :\n"
            " - try from a valid work tree\n"
            " - specify an existing work tree with \"--work-tree PATH\"\n"
            " - create a new work tree with \"qibuild init\"")
    return QiWorkTree(work_tree)

def search_manifest_directory(working_directory):
    """ find the manifest associated to the working_directory, return None if not found """
    cwd     = os.path.normpath(os.path.abspath(working_directory))
    dirname = None

    #for each cwd parent folders, try to see if it match src
    while dirname or cwd:
        if (os.path.exists(os.path.join(cwd, "qibuild.manifest"))):
            return cwd
        (new_cwd, dirname) = os.path.split(cwd)
        if new_cwd == cwd:
            break
        cwd = new_cwd
    return None

def search_projects(directory=None, depth=4):
    """ search for qibuild.manifest files recursively starting from directory
        this function return a list of directory.
    """
    rgit = list()
    rsrc = list()
    if depth == 0:
        return (rgit, rsrc)

    if os.path.exists(os.path.join(directory, ".git")):
        rgit.append(directory)

    if os.path.exists(os.path.join(directory, "qibuild.manifest")):
        rsrc.append(directory)

    subdirs = list()
    try:
        subdirs = os.listdir(directory)
    except OSError:
        pass
    for p in subdirs:
        if os.path.isdir(os.path.join(directory, p)):
            sub_rgit, sub_rsrc = search_projects(os.path.join(directory, p), depth - 1)
            rgit.extend(sub_rgit)
            rsrc.extend(sub_rsrc)
    return (rgit, rsrc)

def guess_work_tree(use_env=False):
    """Look for parent directories until a .toc dir is found somewhere.
    Otherwize, juste use TOC_WORK_TREE environnement
    variable
    """
    from_env = os.environ.get("QI_WORK_TREE")
    if use_env and from_env:
        return from_env
    head = os.getcwd()
    while True:
        d = os.path.join(head, ".qi")
        if os.path.isdir(d):
            return head
        (head, _tail) = os.path.split(head)
        if not _tail:
            break
    return None

def project_name_from_directory(project_dir):
    """Get the project name from the project directory """
    config = qitools.configstore.ConfigStore()
    conf_file = os.path.join(project_dir, "qibuild.manifest")
    config.read(conf_file)
    project_names = config.get("project", default=dict()).keys()
    if len(project_names) != 1:
        mess  = "The file %s is invalid\n" % conf_file
        mess += "It should contains exactly one project section"
        raise Exception(mess)

    return project_names[0]

def create(directory):
    """Create a new Qi worktree in the given directory

    """
    to_create = os.path.join(directory, ".qi")
    qitools.sh.mkdir(to_create, recursive=True)

def worktree_from_args(args):
    """Returns a suitable work tree from the command line
    """
    work_tree = None
    if args.work_tree:
        work_tree = args.work_tree
        work_tree = os.path.abspath(work_tree)
    elif os.environ.get("QI_WORK_TREE"):
        work_tree = os.environ["QI_WORK_TREE"]
        work_tree = os.path.abspath(work_tree)
    else:
        work_tree = os.getcwd()
    return work_tree

<commit_msg>python: fail if two project have the same name in a worktree<commit_after>## Copyright (C) 2011 Aldebaran Robotics

import os
import logging
from qitools.cmdparse    import default_parser
from qitools.configstore import ConfigStore
import qitools.sh

LOGGER = logging.getLogger("QiWorkTree")

class WorkTreeException(Exception):
    """Custom excpetion """
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return self.message

def work_tree_parser(parser):
    """ Parser settings for every action using a toc dir
    """
    default_parser(parser)
    parser.add_argument("--work-tree", help="Use a specific work tree path.")

class QiWorkTree:
    """ This class represent a Qi worktree.
        - work_tree
        - configstore
        - buildable projects
        - git projects
    """

    def __init__(self, work_tree):
        self.work_tree          = work_tree
        self.configstore        = ConfigStore()
        self.buildable_projects = dict()
        self.git_projects       = dict()
        self.user_config_path   = os.path.join(self.work_tree, ".qi", "build.cfg")

        self._load_projects()
        self._load_configuration()

    def _load_projects(self):
        (git_p, src_p) = search_projects(self.work_tree)
        for d in src_p:
            # Get the name of the project from its directory:
            project_name = project_name_from_directory(d)
            if self.buildable_projects.get(project_name):
                raise WorkTreeException("Conflict: two projects have the same name '%s': %s and %s"
                                        % (project_name, self.buildable_projects.get(project_name), d))
            self.buildable_projects[project_name] = d
        for d in git_p:
            self.git_projects[os.path.basename(d)] = d

    def _load_configuration(self):
        for name, ppath in self.buildable_projects.iteritems():
            self.configstore.read(os.path.join(ppath, "qibuild.manifest"))
        if os.path.exists(self.user_config_path):
            self.configstore.read(self.user_config_path)
            LOGGER.debug("[Qi] worktree configuration:\n" + str(self.configstore))

def qiworktree_open(work_tree=None, use_env=False):
    """ open a qi worktree
        return a valid QiWorkTree instance
        TODO: explain why we search for manifest
    """
    if not work_tree:
        work_tree = guess_work_tree(use_env)
        LOGGER.debug("found a qi worktree: %s", work_tree)
    if not work_tree:
        work_tree = search_manifest_directory(os.getcwd())
        LOGGER.debug("no work tree found using the project root: %s", work_tree)
    if work_tree is None:
        raise WorkTreeException("Could not find a work tree\n "
            "Here is what you can do :\n"
            " - try from a valid work tree\n"
            " - specify an existing work tree with \"--work-tree PATH\"\n"
            " - create a new work tree with \"qibuild init\"")
    return QiWorkTree(work_tree)

def search_manifest_directory(working_directory):
    """ find the manifest associated to the working_directory, return None if not found """
    cwd     = os.path.normpath(os.path.abspath(working_directory))
    dirname = None

    #for each cwd parent folders, try to see if it match src
    while dirname or cwd:
        if (os.path.exists(os.path.join(cwd, "qibuild.manifest"))):
            return cwd
        (new_cwd, dirname) = os.path.split(cwd)
        if new_cwd == cwd:
            break
        cwd = new_cwd
    return None

def search_projects(directory=None, depth=4):
    """ search for qibuild.manifest files recursively starting from directory
        this function return a list of directory.
    """
    rgit = list()
    rsrc = list()
    if depth == 0:
        return (rgit, rsrc)

    if os.path.exists(os.path.join(directory, ".git")):
        rgit.append(directory)

    if os.path.exists(os.path.join(directory, "qibuild.manifest")):
        rsrc.append(directory)

    subdirs = list()
    try:
        subdirs = os.listdir(directory)
    except OSError:
        pass
    for p in subdirs:
        if os.path.isdir(os.path.join(directory, p)):
            sub_rgit, sub_rsrc = search_projects(os.path.join(directory, p), depth - 1)
            rgit.extend(sub_rgit)
            rsrc.extend(sub_rsrc)
    return (rgit, rsrc)

def guess_work_tree(use_env=False):
    """Look for parent directories until a .toc dir is found somewhere.
    Otherwize, juste use TOC_WORK_TREE environnement
    variable
    """
    from_env = os.environ.get("QI_WORK_TREE")
    if use_env and from_env:
        return from_env
    head = os.getcwd()
    while True:
        d = os.path.join(head, ".qi")
        if os.path.isdir(d):
            return head
        (head, _tail) = os.path.split(head)
        if not _tail:
            break
    return None

def project_name_from_directory(project_dir):
    """Get the project name from the project directory """
    config = qitools.configstore.ConfigStore()
    conf_file = os.path.join(project_dir, "qibuild.manifest")
    config.read(conf_file)
    project_names = config.get("project", default=dict()).keys()
    if len(project_names) != 1:
        mess  = "The file %s is invalid\n" % conf_file
        mess += "It should contains exactly one project section"
        raise Exception(mess)

    return project_names[0]

def create(directory):
    """Create a new Qi worktree in the given directory

    """
    to_create = os.path.join(directory, ".qi")
    qitools.sh.mkdir(to_create, recursive=True)

def worktree_from_args(args):
    """Returns a suitable work tree from the command line
    """
    work_tree = None
    if args.work_tree:
        work_tree = args.work_tree
        work_tree = os.path.abspath(work_tree)
    elif os.environ.get("QI_WORK_TREE"):
        work_tree = os.environ["QI_WORK_TREE"]
        work_tree = os.path.abspath(work_tree)
    else:
        work_tree = os.getcwd()
    return work_tree

<|endoftext|>