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

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

from openbase.openbase_core import OpenbaseCore
from osv import fields, osv
import calendar
from mx.DateTime.mxDateTime import strptime
from datetime import datetime
from datetime import timedelta
from lxml import etree
from lxml.builder import E
import re
from tools.translate import _
import netsvc
class openstc_patrimoine_contract(OpenbaseCore):
    _name = "openstc.patrimoine.contract"

    def _get_patrimony_name(self, cr, uid, ids, name ,args, context=None):
        ret = {}
        for contract in self.browse(cr, uid, ids, context=context):
            name = ''
            if contract.patrimoine_is_equipment:
                if contract.equipment_id:
                    name = contract.equipment_id.name_template
            elif contract.site_id:
                name = contract.site_id.name
            ret.update({contract.id:name})
        return ret

    """ @note: bubble-up name_search of patrimoine_name to equipment_id.name and site_id.name"""
    def _search_func_patrimoine_name(self, cr, uid, obj, name, args, context=None):
        search_args = []
        for arg in args:
            search_args.extend(['|',('equipment_id.name',arg[1],arg[2]),('site_id.name',arg[1],arg[2])])
        return search_args

    def _get_provider_name(self, cr, uid, ids, name, args, context=None):
        ret = {}.fromkeys(ids, '')
        for contract in self.browse(cr, uid, ids, context=context):
            name = ''
            if contract.internal_inter:
                name = contract.technical_service_id.name if contract.technical_service_id else ''
            else:
                name = contract.supplier_id.name if contract.supplier_id else ''
            ret[contract.id] = name
        return ret

    def _search_func_provider_name(self, cr, uid, obj, name, args, context=None):
        search_args = []
        for arg in args:
            search_args.extend(['|',('technical_service_id.name',arg[1],arg[2]),('partner_id.name',arg[1],arg[2])])
        return search_args

    def _search_warning_delay(self, cr, uid, obj ,name, args, context=None):
        ret = []
        cr.execute(''' select id from openstc_patrimoine_contract
        where date(date_end_order) - date(now()) < 30 + deadline_delay;''')
        ids = cr.fetchall()
        if ids:
            for f,o,v in args:
                ret.append(('id','in' if v else 'not in',ids))
        else:
            ret.append(('id','=',0))
        return ret

    _AVAILABLE_STATE_VALUES = [('draft','Draft'),('wait','Wait'),('confirm','Confirm'),('done','Done'), ('cancel','Cancel')]

    """ @return: list of tuples of available 'type renewals' (key,value)
    @note: Override this method to update this list instead of its private name-like method"""
    def get_type_renewal_values(self, cr, uid, context=None):
        return [('auto','Tacite'),('manual','Express'), ('none','Aucun')]

    def _get_type_renewal_values(self, cr, uid, context=None):
        return self.get_type_renewal_values(cr, uid, context=context)

    """ @note: return True if deadline_delay has expired, False otherwise"""
    def _get_delay_passed(self,cr, uid, ids, name ,args,context=None):
        ret = {}.fromkeys(ids, {'delay_passed': False, 'warning_delay':False})
        for contract in self.browse(cr, uid, ids, context=context):
            if contract.state not in ('done','cancel'):
                delta = datetime.strptime(contract.date_end_order, '%Y-%m-%d') - datetime.now()
                contract_remaining_duration = delta.total_seconds() / (3600.0 *24.0)
                #Delay the user has for confirming / canceling renewal
                renewal_remaining_delay = contract_remaining_duration -  contract.deadline_delay
                warning_delay = 30 #@TODO: move it to an ir.property
                ret[contract.id] = {'delay_passed': renewal_remaining_delay <= 0,
                                     'warning_delay': renewal_remaining_delay < warning_delay,
                                     'remaining_delay': renewal_remaining_delay}
        return ret

    _actions = {
        'update':lambda self,cr,uid,record,groups_code: record.state in ('draft','wait'),
        'delete':lambda self,cr,uid,record,groups_code: record.state in ('draft','wait'),
        'confirm':lambda self,cr,uid,record,groups_code: record.state in ('wait',),
        #'done':lambda self,cr,uid,record,groups_code: record.state in ('confirm',),
        'renew':lambda self,cr,uid,record,groups_code: record.state not in ('cancel', 'done','draft'),
        'close':lambda self,cr,uid,record,groups_code: record.state not in ('cancel', 'done','draft'),
        'cancel':lambda self,cr,uid,record,groups_code: record.state in ('confirm',),
        }

    """ write the priority of the record according to its state and the values of 'order' list variable """
    def _get_state_order(self, cr, uid, ids, name, args, context=None):
        order = ['draft','wait','confirm','done']
        max_order = len(order)
        ret = {}.fromkeys(ids, max_order)
        for contract in self.browse(cr, uid, ids, context=context):
            ret[contract.id] = order.index(contract.state) if contract.state in order else max_order
        return ret

    _columns = {
        'name':fields.char('Name',size=128,required=True),
        "description":fields.text('Description'),
        "new_description":fields.text('Description of the new contract'),
        'sequence':fields.char('Sequence',size=32),
        'category_id':fields.many2one('openstc.patrimoine.contract.type', 'Category', required=True, select=True),

        'patrimoine_is_equipment':fields.boolean('Is Equipment', required=True),
        'equipment_id':fields.many2one('openstc.equipment','Equipment', select=True),
        'patrimoine_name':fields.function(_get_patrimony_name,type='char', select=True, fnct_search=_search_func_patrimoine_name, string='Patrimony',store=False),
        'site_id':fields.many2one('openstc.site','Site', select=True),
        'internal_inter':fields.boolean('En régie',select=True),
        'supplier_id':fields.many2one('res.partner','Supplier', domain=[('supplier','=',True)], select=True),
        'technical_service_id':fields.many2one('openstc.service','Internal Service', domain=[('technical','=',True)],help="Technical service that will work according to this contract", select=True),
        'provider_name': fields.function(_get_provider_name, type='char',  fnct_search=_search_func_provider_name, string='Provider', store=False),

        'date_start_order':fields.date('Date Start Contract', help="Start Date of the application of the contract", select=True),
        'new_date_start_order':fields.date('Date Start of the new Contract', help="Start Date of the application of the new contract"),
        'date_order':fields.date('Date order'),
        'date_end_order':fields.date('Date end Contract',help='Date of the end of this contract. When ended, you could extend it\'s duration or create a new contract.', select=True),
        'new_date_end_order':fields.date('Date end new Contract',help='Date of the end of the new contract'),
        'deadline_delay':fields.integer('Delay (days)'),
        'type_renewal':fields.selection(_get_type_renewal_values, 'Type renewal'),
        'delay_passed':fields.function(_get_delay_passed, multi="delay", method=True, type='boolean', string='To renew', store=False),
        'warning_delay':fields.function(_get_delay_passed, multi="delay", fnct_search= _search_warning_delay,  method=True, type='boolean', string='Near to be renewed', store=False),
        'remaining_delay':fields.function(_get_delay_passed, multi="delay", method=True, type="integer", string="contract remaining duration", store=False),

        'state':fields.selection(_AVAILABLE_STATE_VALUES, 'State', readonly=True, required=True),
        'state_order':fields.function(_get_state_order, method=True, required=False, type='integer', store=True),

        'cancel_reason':fields.text('Cancel Reason'),
        }

    _defaults = {
        'sequence':lambda self,cr,uid,ctx: self.pool.get("ir.sequence").next_by_code(cr, uid, 'contract.number', ctx),
        'state':lambda *a: 'draft',
        'internal_inter':lambda *a: False,
        'date_order':fields.date.context_today,
        'patrimoine_is_equipment':lambda *a: False,
        'type_renewal': lambda *a: 'auto',
        }

    _order = "state_order"

    """ @return: dict containing values for future renewal contract :
    * new date start : current date end
    * new date end : new date start + duration of the original contract"""
    def update_new_contract_values(self, cr, uid, ids):
        for contract in self.browse(cr, uid, ids):
            date_end = datetime.strptime(contract.date_end_order, '%Y-%m-%d')
            date_start = datetime.strptime(contract.date_start_order, '%Y-%m-%d')
            delta = date_end - date_start
            new_date_end = date_end + delta
            vals = {'new_description':contract.description,
                    'new_date_start_order':contract.date_end_order,
                    'new_date_end_order': new_date_end.strftime('%Y-%m-%d')}
            contract.write(vals)
        return True

    def wkf_draft(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'draft'},context=context)
        return True

    def wkf_redraft(self, cr, uid, ids, context=None):

        return True

    def wkf_wait(self, cr, uid, ids, context=None):
        self.update_new_contract_values(cr, uid, ids)
        self.write(cr, uid, ids, {'state':'wait'},context=context)
        return True

    def wkf_confirm(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'confirm'},context=context)
        return True

    def wkf_done(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'done'},context=context)
        return True

    def wkf_renew(self, cr, uid, ids, context=None):
        return self.renew(cr, uid, ids, context=context)

    def wkf_no_renew(self, cr, uid, ids, context=None):
        return True

    def wkf_cancel(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'cancel'},context=context)
        return True

    def onchange_patrimoine_is_equipment(self, cr, uid, ids, patrimoine_is_equipment=False):
        if patrimoine_is_equipment:
            return {'value':{'site_id':False}}
        return {'value':{'equipment_id':False}}

    """@note: Return specific values for the newly created contract
    same duration as original contract, new contract begin at date_end of original one """
    def prepare_default_values_renewed_contract(self, cr, uid, original_contract, context=None):
        return {
            'date_start_order':original_contract.new_date_start_order,
            'date_end_order':original_contract.new_date_end_order,
            'description':original_contract.new_description
            }

    """ @note: for each contract, create a new one with same setting"""
    def renew(self, cr, uid, ids, context=None):
        for contract in self.browse(cr, uid, ids ,context=context):
            vals = self.prepare_default_values_renewed_contract(cr, uid, contract, context=context)
            new_id = self.copy(cr, uid, contract.id, vals, context=context)
        return True

    def write(self, cr, uid, ids, vals, context=None):
        wkf_service = netsvc.LocalService('workflow')
        signal = False
        if 'wkf_evolve' in vals:
            signal = vals.pop('wkf_evolve')
        super(openstc_patrimoine_contract, self).write(cr, uid, ids, vals, context=context)
        if signal:
            for id in ids:
                wkf_service.trg_validate(uid, 'openstc.patrimoine.contract', id, signal, cr)
        return True

openstc_patrimoine_contract()

class openstc_patrimoine_contract_intervention_type(OpenbaseCore):
    _name = "openstc.patrimoine.contract.type"

    _actions = {
        'update':lambda self,cr,uid,record,groups_code: True,
        'delete':lambda self,cr,uid,record,groups_code: True,

        }

    _columns = {
        'name':fields.char('Name',size=128, required=True),
        'code':fields.char('Name',size=32, required=False),
        'parent_id':fields.many2one('openstc.patrimoine.contract.type', 'Parent'),
        }

openstc_patrimoine_contract_intervention_type()

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:<commit_msg>added 'original_contract_id' field to contracts model; prepared write() method to return updated contracts (used by front-end to fetch updated records)<commit_after># -*- coding: utf-8 -*-

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

from openbase.openbase_core import OpenbaseCore
from osv import fields, osv
import calendar
from mx.DateTime.mxDateTime import strptime
from datetime import datetime
from datetime import timedelta
from lxml import etree
from lxml.builder import E
import re
from tools.translate import _
import netsvc
class openstc_patrimoine_contract(OpenbaseCore):
    _name = "openstc.patrimoine.contract"
    _parent_name = 'original_contract_id'

    def _get_patrimony_name(self, cr, uid, ids, name ,args, context=None):
        ret = {}
        for contract in self.browse(cr, uid, ids, context=context):
            name = ''
            if contract.patrimoine_is_equipment:
                if contract.equipment_id:
                    name = contract.equipment_id.name_template
            elif contract.site_id:
                name = contract.site_id.name
            ret.update({contract.id:name})
        return ret

    """ @note: bubble-up name_search of patrimoine_name to equipment_id.name and site_id.name"""
    def _search_func_patrimoine_name(self, cr, uid, obj, name, args, context=None):
        search_args = []
        for arg in args:
            search_args.extend(['|',('equipment_id.name',arg[1],arg[2]),('site_id.name',arg[1],arg[2])])
        return search_args

    def _get_provider_name(self, cr, uid, ids, name, args, context=None):
        ret = {}.fromkeys(ids, '')
        for contract in self.browse(cr, uid, ids, context=context):
            name = ''
            if contract.internal_inter:
                name = contract.technical_service_id.name if contract.technical_service_id else ''
            else:
                name = contract.supplier_id.name if contract.supplier_id else ''
            ret[contract.id] = name
        return ret

    def _search_func_provider_name(self, cr, uid, obj, name, args, context=None):
        search_args = []
        for arg in args:
            search_args.extend(['|',('technical_service_id.name',arg[1],arg[2]),('partner_id.name',arg[1],arg[2])])
        return search_args

    def _search_warning_delay(self, cr, uid, obj ,name, args, context=None):
        ret = []
        cr.execute(''' select id from openstc_patrimoine_contract
        where date(date_end_order) - date(now()) < 30 + deadline_delay;''')
        ids = cr.fetchall()
        if ids:
            for f,o,v in args:
                ret.append(('id','in' if v else 'not in',ids))
        else:
            ret.append(('id','=',0))
        return ret

    _AVAILABLE_STATE_VALUES = [('draft','Draft'),('wait','Wait'),('confirm','Confirm'),('done','Done'), ('cancel','Cancel')]

    """ @return: list of tuples of available 'type renewals' (key,value)
    @note: Override this method to update this list instead of its private name-like method"""
    def get_type_renewal_values(self, cr, uid, context=None):
        return [('auto','Tacite'),('manual','Express'), ('none','Aucun')]

    def _get_type_renewal_values(self, cr, uid, context=None):
        return self.get_type_renewal_values(cr, uid, context=context)

    """ @note: return True if deadline_delay has expired, False otherwise"""
    def _get_delay_passed(self,cr, uid, ids, name ,args,context=None):
        ret = {}.fromkeys(ids, {'delay_passed': False, 'warning_delay':False})
        for contract in self.browse(cr, uid, ids, context=context):
            if contract.state not in ('done','cancel'):
                delta = datetime.strptime(contract.date_end_order, '%Y-%m-%d') - datetime.now()
                contract_remaining_duration = delta.total_seconds() / (3600.0 *24.0)
                #Delay the user has for confirming / canceling renewal
                renewal_remaining_delay = contract_remaining_duration -  contract.deadline_delay
                warning_delay = 30 #@TODO: move it to an ir.property
                ret[contract.id] = {'delay_passed': renewal_remaining_delay <= 0,
                                     'warning_delay': renewal_remaining_delay < warning_delay,
                                     'remaining_delay': renewal_remaining_delay}
        return ret

    _actions = {
        'update':lambda self,cr,uid,record,groups_code: record.state in ('draft',),
        'delete':lambda self,cr,uid,record,groups_code: record.state in ('draft','wait'),
        'confirm':lambda self,cr,uid,record,groups_code: record.state in ('wait',),
        #'done':lambda self,cr,uid,record,groups_code: record.state in ('confirm',),
        'renew':lambda self,cr,uid,record,groups_code: record.state not in ('cancel', 'done','draft'),
        'close':lambda self,cr,uid,record,groups_code: record.state not in ('cancel', 'done','draft'),
        'cancel':lambda self,cr,uid,record,groups_code: record.state in ('confirm',),
        'redraft': lambda self,cr,uid,record,groups_code: record.state in ('wait',),
        }

    """ write the priority of the record according to its state and the values of 'order' list variable """
    def _get_state_order(self, cr, uid, ids, name, args, context=None):
        order = ['draft','wait','confirm','done']
        max_order = len(order)
        ret = {}.fromkeys(ids, max_order)
        for contract in self.browse(cr, uid, ids, context=context):
            ret[contract.id] = order.index(contract.state) if contract.state in order else max_order
        return ret

    _columns = {
        'name':fields.char('Name',size=128,required=True),
        "description":fields.text('Description'),
        "new_description":fields.text('Description of the new contract'),
        'sequence':fields.char('Sequence',size=32),
        'category_id':fields.many2one('openstc.patrimoine.contract.type', 'Category', required=True, select=True),
        'original_contract_id':fields.many2one('openstc.patrimoine.contract', 'original contract'),

        'patrimoine_is_equipment':fields.boolean('Is Equipment', required=True),
        'equipment_id':fields.many2one('openstc.equipment','Equipment', select=True),
        'patrimoine_name':fields.function(_get_patrimony_name,type='char', select=True, fnct_search=_search_func_patrimoine_name, string='Patrimony',store=False),
        'site_id':fields.many2one('openstc.site','Site', select=True),
        'internal_inter':fields.boolean('En régie',select=True),
        'supplier_id':fields.many2one('res.partner','Supplier', domain=[('supplier','=',True)], select=True),
        'technical_service_id':fields.many2one('openstc.service','Internal Service', domain=[('technical','=',True)],help="Technical service that will work according to this contract", select=True),
        'provider_name': fields.function(_get_provider_name, type='char',  fnct_search=_search_func_provider_name, string='Provider', store=False),

        'date_start_order':fields.date('Date Start Contract', help="Start Date of the application of the contract", select=True),
        'new_date_start_order':fields.date('Date Start of the new Contract', help="Start Date of the application of the new contract"),
        'date_order':fields.date('Date order'),
        'date_end_order':fields.date('Date end Contract',help='Date of the end of this contract. When ended, you could extend it\'s duration or create a new contract.', select=True),
        'new_date_end_order':fields.date('Date end new Contract',help='Date of the end of the new contract'),
        'deadline_delay':fields.integer('Delay (days)'),
        'type_renewal':fields.selection(_get_type_renewal_values, 'Type renewal'),
        'delay_passed':fields.function(_get_delay_passed, multi="delay", method=True, type='boolean', string='To renew', store=False),
        'warning_delay':fields.function(_get_delay_passed, multi="delay", fnct_search= _search_warning_delay,  method=True, type='boolean', string='Near to be renewed', store=False),
        'remaining_delay':fields.function(_get_delay_passed, multi="delay", method=True, type="integer", string="contract remaining duration", store=False),

        'state':fields.selection(_AVAILABLE_STATE_VALUES, 'State', readonly=True, required=True),
        'state_order':fields.function(_get_state_order, method=True, required=False, type='integer', store=True),

        'cancel_reason':fields.text('Cancel Reason'),
        }

    _defaults = {
        'sequence':lambda self,cr,uid,ctx: self.pool.get("ir.sequence").next_by_code(cr, uid, 'contract.number', ctx),
        'state':lambda *a: 'draft',
        'internal_inter':lambda *a: False,
        'date_order':fields.date.context_today,
        'patrimoine_is_equipment':lambda *a: False,
        'type_renewal': lambda *a: 'auto',
        }

    _order = "state_order"

    """ @return: dict containing values for future renewal contract :
    * new date start : current date end
    * new date end : new date start + duration of the original contract"""
    def update_new_contract_values(self, cr, uid, ids):
        for contract in self.browse(cr, uid, ids):
            date_end = datetime.strptime(contract.date_end_order, '%Y-%m-%d')
            date_start = datetime.strptime(contract.date_start_order, '%Y-%m-%d')
            delta = date_end - date_start
            new_date_end = date_end + delta
            vals = {'new_description':contract.description,
                    'new_date_start_order':contract.date_end_order,
                    'new_date_end_order': new_date_end.strftime('%Y-%m-%d')}
            contract.write(vals)
        return True

    def wkf_draft(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'draft'},context=context)
        return True

    def wkf_redraft(self, cr, uid, ids, context=None):

        return True

    def wkf_wait(self, cr, uid, ids, context=None):
        self.update_new_contract_values(cr, uid, ids)
        self.write(cr, uid, ids, {'state':'wait'},context=context)
        return True

    def wkf_confirm(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'confirm'},context=context)
        return True

    def wkf_done(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'done'},context=context)
        return True

    def wkf_renew(self, cr, uid, ids, context=None):
        return self.renew(cr, uid, ids, context=context)

    def wkf_no_renew(self, cr, uid, ids, context=None):
        return True

    def wkf_cancel(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {'state':'cancel'},context=context)
        return True

    def onchange_patrimoine_is_equipment(self, cr, uid, ids, patrimoine_is_equipment=False):
        if patrimoine_is_equipment:
            return {'value':{'site_id':False}}
        return {'value':{'equipment_id':False}}

    """@note: Return specific values for the newly created contract
    same duration as original contract, new contract begin at date_end of original one """
    def prepare_default_values_renewed_contract(self, cr, uid, original_contract, context=None):
        return {
            'date_start_order':original_contract.new_date_start_order,
            'date_end_order':original_contract.new_date_end_order,
            'description':original_contract.new_description,
            'original_contract_id':original_contract.id
            }

    """ @note: for each contract, create a new one with same setting"""
    def renew(self, cr, uid, ids, context=None):
        ret = []
        for contract in self.browse(cr, uid, ids ,context=context):
            vals = self.prepare_default_values_renewed_contract(cr, uid, contract, context=context)
            new_id = self.copy(cr, uid, contract.id, vals, context=context)
            ret.append(new_id)
        return ret

    def write(self, cr, uid, ids, vals, context=None):
        wkf_service = netsvc.LocalService('workflow')
        signal = False
        if 'wkf_evolve' in vals:
            signal = vals.pop('wkf_evolve')
        super(openstc_patrimoine_contract, self).write(cr, uid, ids, vals, context=context)
        ret = []
        if signal:
            for id in ids:
                wkf_service.trg_validate(uid, 'openstc.patrimoine.contract', id, signal, cr)
                #try to fetch updated values (work fine for renew action)
                #but if other records are updated without having a link with current id, it won't be returned in 'ret' list
                ret.extend(self.search(cr, uid, [('original_contract_id','child_of', id)], context=context))
        return ret if ret else True

openstc_patrimoine_contract()

class openstc_patrimoine_contract_intervention_type(OpenbaseCore):
    _name = "openstc.patrimoine.contract.type"

    _actions = {
        'update':lambda self,cr,uid,record,groups_code: True,
        'delete':lambda self,cr,uid,record,groups_code: True,

        }

    _columns = {
        'name':fields.char('Name',size=128, required=True),
        'code':fields.char('Name',size=32, required=False),
        'parent_id':fields.many2one('openstc.patrimoine.contract.type', 'Parent'),
        }

openstc_patrimoine_contract_intervention_type()

# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.contrib.sites.models import get_current_site
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django import template
from django.conf import settings

from opps.articles.utils import set_context_data
from opps.channels.models import Channel

class OppsView(object):
    context_object_name = "context"
    paginate_by = settings.OPPS_PAGINATE_BY
    limit = settings.OPPS_VIEWS_LIMIT
    site = None
    slug = None
    channel = None
    channel_long_slug = []

    def check_longslug(self):
        self.long_slug = self.kwargs.get('channel__long_slug', None)
        try:
            if not self.long_slug:
                Channel.objects.get_homepage(site=self.site).long_slug
        except AttributeError:
            pass

    def set_folder(self):
        domain_folder = self.type
        if self.site.id > 1:
            domain_folder = "{0}/{1}".format(self.site, self.type)

        if self.request.META.get('HTTP_X_OPPS_MOBILE'):
            domain_folder = "mobile/{}".format(domain_folder)
        return domain_folder

class OppsList(OppsView, ListView):

    def get_context_data(self, **kwargs):
        return set_context_data(self, OppsList, **kwargs)

    @property
    def template_name(self):
        domain_folder = self.set_folder()

        if self.channel:
            if self.channel.group and self.channel.parent:
                try:
                    _template = '{0}/_{1}.html'.format(
                        domain_folder, self.channel.parent.long_slug)
                    template.loader.get_template(_template)
                    return _template
                except template.TemplateDoesNotExist:
                    pass

        return '{0}/{1}.html'.format(domain_folder, self.long_slug)

    @property
    def queryset(self):
        self.site = get_current_site(self.request)

        self.check_longslug()
        if not self.long_slug:
            return None

        self.channel = get_object_or_404(Channel, site=self.site,
                                         long_slug=self.long_slug,
                                         date_available__lte=timezone.now(),
                                         published=True)

        self.channel_long_slug = [self.long_slug]
        for children in self.channel.get_children():
            self.channel_long_slug.append(children)
        self.article = self.model.objects.filter(
            site=self.site,
            channel_long_slug__in=self.channel_long_slug,
            date_available__lte=timezone.now(),
            published=True)[:self.limit]

        return self.article

class OppsDetail(OppsView, DetailView):

    def get_context_data(self, **kwargs):
        return set_context_data(self, OppsDetail, **kwargs)

    @property
    def template_name(self):
        domain_folder = self.set_folder()

        try:
            _template = '{0}/{1}/{2}.html'.format(
                domain_folder, self.long_slug, self.slug)
            template.loader.get_template(_template)
        except template.TemplateDoesNotExist:
            _template = '{0}/{1}.html'.format(domain_folder, self.long_slug)
        return _template

    @property
    def queryset(self):
        self.site = get_current_site(self.request)
        self.slug = self.kwargs.get('slug')

        self.check_longslug()
        if not self.long_slug:
            return None

        self.channel = get_object_or_404(Channel, site=self.site,
                                         long_slug=self.long_slug,
                                         date_available__lte=timezone.now(),
                                         published=True)

        self.channel_long_slug = [self.long_slug]
        self.channel_long_slug.append(
            [children.long_slug for children in self.channel.get_children()])

        self.article = self.model.objects.filter(
            site=self.site,
            channel_long_slug=self.long_slug,
            slug=self.slug,
            date_available__lte=timezone.now(),
            published=True)
        return self.article
<commit_msg>Remove OppsView, set var on class father<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.contrib.sites.models import get_current_site
from django.shortcuts import get_object_or_404
from django.utils import timezone
from django import template
from django.conf import settings

from opps.articles.utils import set_context_data
from opps.channels.models import Channel

class OppsList(ListView):

    context_object_name = "context"
    paginate_by = settings.OPPS_PAGINATE_BY
    limit = settings.OPPS_VIEWS_LIMIT
    site = None
    slug = None
    channel = None
    channel_long_slug = []

    def get_context_data(self, **kwargs):
        return set_context_data(self, OppsList, **kwargs)

    @property
    def template_name(self):

        domain_folder = self.type
        if self.site.id > 1:
            domain_folder = "{0}/{1}".format(self.site, self.type)

        if self.request.META.get('HTTP_X_OPPS_MOBILE'):
            domain_folder = "mobile/{}".format(domain_folder)
        return domain_folder

        if self.channel:
            if self.channel.group and self.channel.parent:
                try:
                    _template = '{0}/_{1}.html'.format(
                        domain_folder, self.channel.parent.long_slug)
                    template.loader.get_template(_template)
                    return _template
                except template.TemplateDoesNotExist:
                    pass

        return '{0}/{1}.html'.format(domain_folder, self.long_slug)

    @property
    def queryset(self):
        self.site = get_current_site(self.request)

        self.long_slug = self.kwargs.get('channel__long_slug', None)
        try:
            if not self.long_slug:
                Channel.objects.get_homepage(site=self.site).long_slug
        except AttributeError:
            pass

        if not self.long_slug:
            return None

        self.channel = get_object_or_404(Channel, site=self.site,
                                         long_slug=self.long_slug,
                                         date_available__lte=timezone.now(),
                                         published=True)

        self.channel_long_slug = [self.long_slug]
        for children in self.channel.get_children():
            self.channel_long_slug.append(children)
        self.article = self.model.objects.filter(
            site=self.site,
            channel_long_slug__in=self.channel_long_slug,
            date_available__lte=timezone.now(),
            published=True)[:self.limit]

        return self.article

class OppsDetail(DetailView):

    context_object_name = "context"
    paginate_by = settings.OPPS_PAGINATE_BY
    limit = settings.OPPS_VIEWS_LIMIT
    site = None
    slug = None
    channel = None
    channel_long_slug = []

    def get_context_data(self, **kwargs):
        return set_context_data(self, OppsDetail, **kwargs)

    @property
    def template_name(self):
        domain_folder = self.type
        if self.site.id > 1:
            domain_folder = "{0}/{1}".format(self.site, self.type)

        if self.request.META.get('HTTP_X_OPPS_MOBILE'):
            domain_folder = "mobile/{}".format(domain_folder)
        return domain_folder

        try:
            _template = '{0}/{1}/{2}.html'.format(
                domain_folder, self.long_slug, self.slug)
            template.loader.get_template(_template)
        except template.TemplateDoesNotExist:
            _template = '{0}/{1}.html'.format(domain_folder, self.long_slug)
        return _template

    @property
    def queryset(self):
        self.site = get_current_site(self.request)
        self.slug = self.kwargs.get('slug')

        self.long_slug = self.kwargs.get('channel__long_slug', None)
        try:
            if not self.long_slug:
                Channel.objects.get_homepage(site=self.site).long_slug
        except AttributeError:
            pass

        if not self.long_slug:
            return None

        self.channel = get_object_or_404(Channel, site=self.site,
                                         long_slug=self.long_slug,
                                         date_available__lte=timezone.now(),
                                         published=True)

        self.channel_long_slug = [self.long_slug]
        self.channel_long_slug.append(
            [children.long_slug for children in self.channel.get_children()])

        self.article = self.model.objects.filter(
            site=self.site,
            channel_long_slug=self.long_slug,
            slug=self.slug,
            date_available__lte=timezone.now(),
            published=True)
        return self.article
<|endoftext|>


<commit_before>import datetime
import re

import fixtures
import constants
from authomatic.providers import oauth2

conf = fixtures.get_configuration('vk')

PICTURE = re.compile(r'http://[A-Za-z0-9]+\.vk\.me/[A-Za-z0-9-/]+\.jpg')

CONFIG = {
    'login_xpath': '//*[@id="box"]/div/input[5]',
    'password_xpath': '//*[@id="box"]/div/input[6]',
    'consent_xpaths': [
        '//*[@id="install_allow"]',
    ],
    'consent_wait_seconds': 4,
    'class_': oauth2.VK,
    'scope': oauth2.VK.user_info_scope,
    'offline': True,
    'user': {
        'birth_date': conf.user_birth_date_str,
        'city': re.compile('\d+'),
        'country': re.compile('\d+'),
        'email': None,
        'first_name': conf.user_first_name,
        'gender': re.compile('\d'),
        'id': conf.user_id,
        'last_name': conf.user_last_name,
        'link': None,
        'locale': None,
        'location': re.compile('\d+, \d+'),
        'name': conf.user_name,
        'nickname': None,
        'phone': None,
        'picture': PICTURE,
        'postal_code': None,
        'timezone': re.compile('\d'),
        'username': None,
    },
    'content_should_contain': [
        conf.user_birth_date.strftime('%d.%m.%Y'),
        conf.user_first_name,
        conf.user_id,
        conf.user_last_name,

        # User info JSON keys
        'response', 'uid', 'first_name', 'last_name', 'sex', 'nickname',
        'bdate', 'city', 'country', 'timezone', 'photo_big'
    ],
    # Case insensitive
    'content_should_not_contain':
        conf.no_email +
        conf.no_locale +
        conf.no_phone +
        conf.no_postal_code +
        conf.no_username +
        ['link', conf.user_nickname],
    # True means that any thruthy value is expected
    'credentials': {
        'token_type': None,
        'provider_type_id': '2-13',
        '_expiration_time': None,
        'consumer_key': None,
        'provider_id': None,
        'consumer_secret': None,
        'token': True,
        'token_secret': None,
        '_expire_in': True,
        'provider_name': 'vk',
        'refresh_token': None,
        'provider_type': 'authomatic.providers.oauth2.OAuth2',
        'refresh_status': constants.CREDENTIALS_REFRESH_NOT_SUPPORTED,
    },
}<commit_msg>Updated vk login and password xpaths.<commit_after>import datetime
import re

import fixtures
import constants
from authomatic.providers import oauth2

conf = fixtures.get_configuration('vk')

PICTURE = re.compile(r'http://[A-Za-z0-9]+\.vk\.me/[A-Za-z0-9-/]+\.jpg')

CONFIG = {
    'login_xpath': '//*[@id="box"]/div/input[6]',
    'password_xpath': '//*[@id="box"]/div/input[7]',
    'consent_xpaths': [
        '//*[@id="install_allow"]',
    ],
    'consent_wait_seconds': 4,
    'class_': oauth2.VK,
    'scope': oauth2.VK.user_info_scope,
    'offline': True,
    'user': {
        'birth_date': conf.user_birth_date_str,
        'city': re.compile('\d+'),
        'country': re.compile('\d+'),
        'email': None,
        'first_name': conf.user_first_name,
        'gender': re.compile('\d'),
        'id': conf.user_id,
        'last_name': conf.user_last_name,
        'link': None,
        'locale': None,
        'location': re.compile('\d+, \d+'),
        'name': conf.user_name,
        'nickname': None,
        'phone': None,
        'picture': PICTURE,
        'postal_code': None,
        'timezone': re.compile('\d'),
        'username': None,
    },
    'content_should_contain': [
        conf.user_birth_date.strftime('%d.%m.%Y'),
        conf.user_first_name,
        conf.user_id,
        conf.user_last_name,

        # User info JSON keys
        'response', 'uid', 'first_name', 'last_name', 'sex', 'nickname',
        'bdate', 'city', 'country', 'timezone', 'photo_big'
    ],
    # Case insensitive
    'content_should_not_contain':
        conf.no_email +
        conf.no_locale +
        conf.no_phone +
        conf.no_postal_code +
        conf.no_username +
        ['link', conf.user_nickname],
    # True means that any thruthy value is expected
    'credentials': {
        'token_type': None,
        'provider_type_id': '2-13',
        '_expiration_time': None,
        'consumer_key': None,
        'provider_id': None,
        'consumer_secret': None,
        'token': True,
        'token_secret': None,
        '_expire_in': True,
        'provider_name': 'vk',
        'refresh_token': None,
        'provider_type': 'authomatic.providers.oauth2.OAuth2',
        'refresh_status': constants.CREDENTIALS_REFRESH_NOT_SUPPORTED,
    },
}<|endoftext|>


<commit_before>import sys
import os
import importlib
import re
import shlex
import subprocess
from jadsh.getch import Getch
from jadsh.prompt import Prompt
import jadsh.constants as constants

class Shell():
    """
    jadsh, Just Another Dumb SHell
    """
    def __init__(self, prompt = Prompt(), stdin = sys.stdin, stdout = sys.stdout, status = constants.SHELL_STATUS_RUN):
        """
        Expects a new Prompt object and the status the shell should start with

        Prompt objects allow easy customization of the prompt
        """
        self.status = status
        self.prompt = prompt
        self.stdin = stdin
        self.stdout = stdout

        self.builtins = {}
        self.history = []
        self.history_position = 0

        # The screen object
        self.screenObject = ""

        # Grab individual characters from standard input
        self.getch = Getch(self.stdin)

        # Output welcome message
        self.welcome()

        # Start the main program loop
        self.loop()

    def welcome(self):
        self.stdout.write("Welcome to jadsh, Just Another Dumb SHell\n")
        self.stdout.write("Type " + self.hilite("help", True) + " for instructions on how to use jadsh\n")

    def screenAppend(self, string):
        """
        Append new strings to the screen object
        """
        self.screenObject += str(string)

    def drawScreen(self):
        """
        Draw the terminal so the user can see it
        """
        # Reset cursor to previous position
        # TODO: Handle edge case when current line is at the bottom of the terminal
        self.screenAppend("\x1b8")

        # Hide the cursor
        self.screenAppend("\x1b[?25l");

        # Clear everything after the current line
        self.screenAppend("\x1b[J\r")

        # Save the current cursor position
        self.screenAppend("\x1b7")

        # Set the terminal title
        title = self.prompt.title("jadsh " + os.getcwd())
        self.screenAppend(title)

        # Generate the prompt
        prompt = self.prompt.generate()
        self.screenAppend(prompt)

        # Display the current input (what the user is typing)
        self.screenAppend(self.user_input)

        self.screenAppend("\x1b[?25h") # Show cursor

        # Calculate cursor position and place at correct spot
        # TODO: Handle edge case when user input goes to more than 1 line
        position = len(self.user_input) - self.cursor_position
        if position > 0:
            # Move cursor backwards
            self.screenAppend("\x1b[" + str(position) + "D")

        # Output everything to the screen
        self.stdout.write(self.screenObject)
        self.stdout.flush()
        self.screenObject = ""

    def loop(self):
        """
        The main program loop

        Draws terminal screen, gets keyboard input, and executes programs as necessary
        """
        self.user_input = ""
        self.cursor_position = 0
        self.saveCursor()
        while self.status == constants.SHELL_STATUS_RUN:
            # Reset cursor position if current command is empty
            if len(self.user_input) == 0 or self.cursor_position < 0: self.cursor_position = 0
            if self.cursor_position > len(self.user_input): self.cursor_position = len(self.user_input)

            # Draw the screen
            self.drawScreen()

            # Keyboard input
            execute = self.keyboardInput()

            # Execute flag has been set, send the current user input to be parsed
            if execute:
                self.parse(self.user_input)
                self.cursor_position = 0
                self.user_input = ""
                self.saveCursor()

    def keyboardInput(self):
        """
        GrscreenObject keyboard input from the terminal and evaluate it as necessary

        @return Boolean
        """
        char_code = -1
        current_char = ""
        execute = False

        # Grab user input (1 character at a time)
        # This method returns the ASCII code of the character, not the actual character
        char_code = self.getch()

        # Error checking
        if char_code is False:
            # Attempt to execute whatever is left
            if self.user_input != "":
                return True
            self.status = constants.SHELL_STATUS_STOP
            return False

        # Escape sequence, handle appropriately
        if char_code >= constants.ARROW_UP:
            if char_code == constants.ARROW_LEFT:
                if self.cursor_position > 0:
                    self.cursor_position -= 1
            elif char_code == constants.ARROW_RIGHT:
                if self.cursor_position < len(self.user_input):
                    self.cursor_position += 1
            # Move by words, rather than characters
            elif char_code == constants.CTRL_ARROW_LEFT:
                if self.cursor_position > 0:
                    # Grab the string before the current cursor
                    past_string = self.user_input[:self.cursor_position]
                    # Get a list of all the words in the string
                    words = past_string.split()
                    # Decrement the cursor by the length of the past string minus the last occurrence of the last word
                    # This handles unknown spaces that were stripped out by the split
                    self.cursor_position -= len(past_string) - past_string.rfind(words[-1])
            elif char_code == constants.CTRL_ARROW_RIGHT:
                if self.cursor_position < len(self.user_input):
                    # Grab the string after the current cursor
                    forward_string = self.user_input[self.cursor_position:]
                    # Get a list of all the words
                    words = forward_string.split()
                    # Increment the cursor position by the index of the found word plus its length
                    # Have to do this because of spaces (I don't know if there is a space in front of the word)
                    self.cursor_position += forward_string.find(words[0]) + len(words[0])
            elif char_code == constants.ARROW_UP:
                if self.history_position < len(self.history):
                    self.history_position += 1
                    self.user_input = self.history[-self.history_position]["input"]
                    self.cursor_position = len(self.user_input)
            elif char_code == constants.ARROW_DOWN:
                if self.history_position > 1:
                    self.history_position -= 1
                    self.user_input = self.history[-self.history_position]["input"]
                    self.cursor_position = len(self.user_input)
                else:
                    self.history_position = 0
                    self.user_input = ""
                    self.cursor_position = 0
            # Delete key
            elif char_code == constants.DEL_KEY:
                if len(self.user_input) > 0:
                    # Reforms user input string based upon cursor position
                    self.user_input = self.user_input[:self.cursor_position] + self.user_input[self.cursor_position + 1:]
            # Move cursor to end of line
            elif char_code == constants.END_KEY:
                self.cursor_position = len(self.user_input)
            # Move cursor to beginning of line
            elif char_code == constants.HOME_KEY:
                self.cursor_position = 0
            return False

        # Convert ASCII code to actual character
        current_char = chr(char_code)

        # Error checking
        if len(current_char) == 0:
            return False

        # Backspace
        if char_code == constants.BACKSPACE:
            if len(self.user_input) > 0:
                self.user_input = self.user_input[:self.cursor_position - 1] + self.user_input[self.cursor_position:]
                if self.cursor_position > 0: self.cursor_position -= 1
        # End of line
        elif char_code == constants.CTRL_C:
            self.cursor_position = 0
            self.user_input = ""
        # End of input
        elif char_code == constants.CTRL_D:
            self.user_input = "exit"
            execute = True
        # Enter, execute the user input as a command
        elif char_code == constants.ENTER or char_code == constants.NEWLINE:
            execute = True
            self.stdout.write("\n")
            self.saveCursor()
        elif char_code == constants.TAB:
            # Ignore tabs for now, eventually we will do tab completion
            return False
        # Ignore these keys
        elif char_code == constants.ESC:
            return False
        # Regular input, add it to the user input at the cursor position
        else:
            self.user_input = self.user_input[:self.cursor_position] + current_char + self.user_input[self.cursor_position:]
            self.cursor_position += 1

        return execute

    def parse(self, string):
        """
        Parse new commands from the user and then pass the commands to be executed
        """
        # Allow commands to be split (so user can enter multiple commands at once)
        commands = re.split('[;]+', string)
        for cmd in commands:
            # Help the user
            if not self.syntax_check(cmd):
                continue

            # Expand variables in place. Allows $VARIABLE and ${VARIABLE}
            cmd = self.expandvars(cmd)

            # Get tokens from user input
            try:
                tokens = self.tokenize(cmd)
            except:
                self.message("jadsh error", "Malformed command")
                return

            # Execute command
            try:
                self.status = self.execute(tokens)
            except OSError as e:
                self.message(tokens[0], "command not found")
                return
            except KeyboardInterrupt:
                return

    def expandvars(self, path, default=None, skip_escaped=True):
        """Expand environment variables of form $var and ${var}.
           If parameter 'skip_escaped' is True, all escaped variable references
           (i.e. preceded by backslashes) are skipped.
           Unknown variables are set to 'default'. If 'default' is None,
           they are left unchanged.
        """
        def replace_var(m):
            return os.environ.get(m.group(2) or m.group(1), m.group(0) if default is None else default)
        reVar = (r'(?<!\\)' if skip_escaped else '') + r'\$(\w+|\{([^}]*)\})'
        return re.sub(reVar, replace_var, path)

    def execute(self, tokens):
        """
        Execute commands from the user

        @return int (a shell status code)
        """
        if len(tokens) == 0: return constants.SHELL_STATUS_RUN

        command = tokens[0]
        args = tokens[1:]

        # Check if builtin command
        if self.builtin(command):
            return self.builtins[command].execute(*args)

        # Open command as a subprocess
        process = subprocess.Popen(tokens, stdin = self.stdin, stdout = self.stdout)

        # Block program execution until process is finished
        process.wait()

        self.history.append({ "command": command, "args": args, "input": self.user_input })

        # Assume all went well, continue
        return constants.SHELL_STATUS_RUN

    def builtin(self, command):
        """
        Check if a command is a builtin

        @return Boolean (is a builtin or not)
        """
        # Check if the command has already been loaded as a builtin
        if command in self.builtins: return True
        try:
            # Attempt to load this command as a module. If it doesn't exist, the function will return false
            mod = importlib.import_module("jadsh.builtins." + command)
            # Generate new builtin object (passing this shell as an argument)
            obj = getattr(mod, command)(self)
            self.builtins[command] = obj
            return True
        except ImportError:
            return False

    def tokenize(self, command):
        """
        Convert a text command into a list of tokens

        shlex handles special cases (like "multi word strings") that a simple split on spaces can't handle

        @return List
        """
        tokens = shlex.split(command)
        return tokens

    def message(self, title, message, status = False):
        """
        Display message in the terminal
        """
        self.stdout.write(self.hilite(str(title) + ": ", status))
        self.stdout.write(str(message))
        self.stdout.write("\n")
        self.saveCursor()

    def saveCursor(self):
        self.stdout.write("\x1b7")

    def resetCursor(self):
        self.stdout.write("\x1b8")

    def hilite(self, string, status = False, bold = False):
        """
        Generate bold, or colored string using ANSI escape codes

        @return String
        """
        attr = []
        if status:
            # green
            attr.append('32')
        else:
            # red
            attr.append('31')
        if bold:
            attr.append('1')
        return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)

    def syntax_check(self, cmd):
        """
        Check the syntax of a command from the user

        This is purely a helper function for users who are used to Bash or another shell

        TODO: Make this function smarter

        @return Boolean
        """
        if not cmd: return True
        if "&&" in cmd:
            self.message("jadsh error", "Unsupported use of &&. In jadsh, please use 'COMMAND; and COMMAND'")
            return False
        if cmd[0] == "$":
            self.message("jadsh error", "Unsupported use of $VARIABLE. In jadsh, variables cannot be used directly. Use 'eval $VARIABLE' instead.")
            return False
        return True<commit_msg>Fix broken comment<commit_after>import sys
import os
import importlib
import re
import shlex
import subprocess
from jadsh.getch import Getch
from jadsh.prompt import Prompt
import jadsh.constants as constants

class Shell():
    """
    jadsh, Just Another Dumb SHell
    """
    def __init__(self, prompt = Prompt(), stdin = sys.stdin, stdout = sys.stdout, status = constants.SHELL_STATUS_RUN):
        """
        Expects a new Prompt object and the status the shell should start with

        Prompt objects allow easy customization of the prompt
        """
        self.status = status
        self.prompt = prompt
        self.stdin = stdin
        self.stdout = stdout

        self.builtins = {}
        self.history = []
        self.history_position = 0

        # The screen object
        self.screenObject = ""

        # Grab individual characters from standard input
        self.getch = Getch(self.stdin)

        # Output welcome message
        self.welcome()

        # Start the main program loop
        self.loop()

    def welcome(self):
        self.stdout.write("Welcome to jadsh, Just Another Dumb SHell\n")
        self.stdout.write("Type " + self.hilite("help", True) + " for instructions on how to use jadsh\n")

    def screenAppend(self, string):
        """
        Append new strings to the screen object
        """
        self.screenObject += str(string)

    def drawScreen(self):
        """
        Draw the terminal so the user can see it
        """
        # Reset cursor to previous position
        # TODO: Handle edge case when current line is at the bottom of the terminal
        self.screenAppend("\x1b8")

        # Hide the cursor
        self.screenAppend("\x1b[?25l");

        # Clear everything after the current line
        self.screenAppend("\x1b[J\r")

        # Save the current cursor position
        self.screenAppend("\x1b7")

        # Set the terminal title
        title = self.prompt.title("jadsh " + os.getcwd())
        self.screenAppend(title)

        # Generate the prompt
        prompt = self.prompt.generate()
        self.screenAppend(prompt)

        # Display the current input (what the user is typing)
        self.screenAppend(self.user_input)

        self.screenAppend("\x1b[?25h") # Show cursor

        # Calculate cursor position and place at correct spot
        # TODO: Handle edge case when user input goes to more than 1 line
        position = len(self.user_input) - self.cursor_position
        if position > 0:
            # Move cursor backwards
            self.screenAppend("\x1b[" + str(position) + "D")

        # Output everything to the screen
        self.stdout.write(self.screenObject)
        self.stdout.flush()
        self.screenObject = ""

    def loop(self):
        """
        The main program loop

        Draws terminal screen, gets keyboard input, and executes programs as necessary
        """
        self.user_input = ""
        self.cursor_position = 0
        self.saveCursor()
        while self.status == constants.SHELL_STATUS_RUN:
            # Reset cursor position if current command is empty
            if len(self.user_input) == 0 or self.cursor_position < 0: self.cursor_position = 0
            if self.cursor_position > len(self.user_input): self.cursor_position = len(self.user_input)

            # Draw the screen
            self.drawScreen()

            # Keyboard input
            execute = self.keyboardInput()

            # Execute flag has been set, send the current user input to be parsed
            if execute:
                self.parse(self.user_input)
                self.cursor_position = 0
                self.user_input = ""
                self.saveCursor()

    def keyboardInput(self):
        """
        Grab keyboard input from the terminal and evaluate it as necessary

        @return Boolean
        """
        char_code = -1
        current_char = ""
        execute = False

        # Grab user input (1 character at a time)
        # This method returns the ASCII code of the character, not the actual character
        char_code = self.getch()

        # Error checking
        if char_code is False:
            # Attempt to execute whatever is left
            if self.user_input != "":
                return True
            self.status = constants.SHELL_STATUS_STOP
            return False

        # Escape sequence, handle appropriately
        if char_code >= constants.ARROW_UP:
            if char_code == constants.ARROW_LEFT:
                if self.cursor_position > 0:
                    self.cursor_position -= 1
            elif char_code == constants.ARROW_RIGHT:
                if self.cursor_position < len(self.user_input):
                    self.cursor_position += 1
            # Move by words, rather than characters
            elif char_code == constants.CTRL_ARROW_LEFT:
                if self.cursor_position > 0:
                    # Grab the string before the current cursor
                    past_string = self.user_input[:self.cursor_position]
                    # Get a list of all the words in the string
                    words = past_string.split()
                    # Decrement the cursor by the length of the past string minus the last occurrence of the last word
                    # This handles unknown spaces that were stripped out by the split
                    self.cursor_position -= len(past_string) - past_string.rfind(words[-1])
            elif char_code == constants.CTRL_ARROW_RIGHT:
                if self.cursor_position < len(self.user_input):
                    # Grab the string after the current cursor
                    forward_string = self.user_input[self.cursor_position:]
                    # Get a list of all the words
                    words = forward_string.split()
                    # Increment the cursor position by the index of the found word plus its length
                    # Have to do this because of spaces (I don't know if there is a space in front of the word)
                    self.cursor_position += forward_string.find(words[0]) + len(words[0])
            elif char_code == constants.ARROW_UP:
                if self.history_position < len(self.history):
                    self.history_position += 1
                    self.user_input = self.history[-self.history_position]["input"]
                    self.cursor_position = len(self.user_input)
            elif char_code == constants.ARROW_DOWN:
                if self.history_position > 1:
                    self.history_position -= 1
                    self.user_input = self.history[-self.history_position]["input"]
                    self.cursor_position = len(self.user_input)
                else:
                    self.history_position = 0
                    self.user_input = ""
                    self.cursor_position = 0
            # Delete key
            elif char_code == constants.DEL_KEY:
                if len(self.user_input) > 0:
                    # Reforms user input string based upon cursor position
                    self.user_input = self.user_input[:self.cursor_position] + self.user_input[self.cursor_position + 1:]
            # Move cursor to end of line
            elif char_code == constants.END_KEY:
                self.cursor_position = len(self.user_input)
            # Move cursor to beginning of line
            elif char_code == constants.HOME_KEY:
                self.cursor_position = 0
            return False

        # Convert ASCII code to actual character
        current_char = chr(char_code)

        # Error checking
        if len(current_char) == 0:
            return False

        # Backspace
        if char_code == constants.BACKSPACE:
            if len(self.user_input) > 0:
                self.user_input = self.user_input[:self.cursor_position - 1] + self.user_input[self.cursor_position:]
                if self.cursor_position > 0: self.cursor_position -= 1
        # End of line
        elif char_code == constants.CTRL_C:
            self.cursor_position = 0
            self.user_input = ""
        # End of input
        elif char_code == constants.CTRL_D:
            self.user_input = "exit"
            execute = True
        # Enter, execute the user input as a command
        elif char_code == constants.ENTER or char_code == constants.NEWLINE:
            execute = True
            self.stdout.write("\n")
            self.saveCursor()
        elif char_code == constants.TAB:
            # Ignore tabs for now, eventually we will do tab completion
            return False
        # Ignore these keys
        elif char_code == constants.ESC:
            return False
        # Regular input, add it to the user input at the cursor position
        else:
            self.user_input = self.user_input[:self.cursor_position] + current_char + self.user_input[self.cursor_position:]
            self.cursor_position += 1

        return execute

    def parse(self, string):
        """
        Parse new commands from the user and then pass the commands to be executed
        """
        # Allow commands to be split (so user can enter multiple commands at once)
        commands = re.split('[;]+', string)
        for cmd in commands:
            # Help the user
            if not self.syntax_check(cmd):
                continue

            # Expand variables in place. Allows $VARIABLE and ${VARIABLE}
            cmd = self.expandvars(cmd)

            # Get tokens from user input
            try:
                tokens = self.tokenize(cmd)
            except:
                self.message("jadsh error", "Malformed command")
                return

            # Execute command
            try:
                self.status = self.execute(tokens)
            except OSError as e:
                self.message(tokens[0], "command not found")
                return
            except KeyboardInterrupt:
                return

    def expandvars(self, path, default=None, skip_escaped=True):
        """Expand environment variables of form $var and ${var}.
           If parameter 'skip_escaped' is True, all escaped variable references
           (i.e. preceded by backslashes) are skipped.
           Unknown variables are set to 'default'. If 'default' is None,
           they are left unchanged.
        """
        def replace_var(m):
            return os.environ.get(m.group(2) or m.group(1), m.group(0) if default is None else default)
        reVar = (r'(?<!\\)' if skip_escaped else '') + r'\$(\w+|\{([^}]*)\})'
        return re.sub(reVar, replace_var, path)

    def execute(self, tokens):
        """
        Execute commands from the user

        @return int (a shell status code)
        """
        if len(tokens) == 0: return constants.SHELL_STATUS_RUN

        command = tokens[0]
        args = tokens[1:]

        # Check if builtin command
        if self.builtin(command):
            return self.builtins[command].execute(*args)

        # Open command as a subprocess
        process = subprocess.Popen(tokens, stdin = self.stdin, stdout = self.stdout)

        # Block program execution until process is finished
        process.wait()

        self.history.append({ "command": command, "args": args, "input": self.user_input })

        # Assume all went well, continue
        return constants.SHELL_STATUS_RUN

    def builtin(self, command):
        """
        Check if a command is a builtin

        @return Boolean (is a builtin or not)
        """
        # Check if the command has already been loaded as a builtin
        if command in self.builtins: return True
        try:
            # Attempt to load this command as a module. If it doesn't exist, the function will return false
            mod = importlib.import_module("jadsh.builtins." + command)
            # Generate new builtin object (passing this shell as an argument)
            obj = getattr(mod, command)(self)
            self.builtins[command] = obj
            return True
        except ImportError:
            return False

    def tokenize(self, command):
        """
        Convert a text command into a list of tokens

        shlex handles special cases (like "multi word strings") that a simple split on spaces can't handle

        @return List
        """
        tokens = shlex.split(command)
        return tokens

    def message(self, title, message, status = False):
        """
        Display message in the terminal
        """
        self.stdout.write(self.hilite(str(title) + ": ", status))
        self.stdout.write(str(message))
        self.stdout.write("\n")
        self.saveCursor()

    def saveCursor(self):
        self.stdout.write("\x1b7")

    def resetCursor(self):
        self.stdout.write("\x1b8")

    def hilite(self, string, status = False, bold = False):
        """
        Generate bold, or colored string using ANSI escape codes

        @return String
        """
        attr = []
        if status:
            # green
            attr.append('32')
        else:
            # red
            attr.append('31')
        if bold:
            attr.append('1')
        return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)

    def syntax_check(self, cmd):
        """
        Check the syntax of a command from the user

        This is purely a helper function for users who are used to Bash or another shell

        TODO: Make this function smarter

        @return Boolean
        """
        if not cmd: return True
        if "&&" in cmd:
            self.message("jadsh error", "Unsupported use of &&. In jadsh, please use 'COMMAND; and COMMAND'")
            return False
        if cmd[0] == "$":
            self.message("jadsh error", "Unsupported use of $VARIABLE. In jadsh, variables cannot be used directly. Use 'eval $VARIABLE' instead.")
            return False
        return True<|endoftext|>


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

"""
yaspin.yaspin
~~~~~~~~~~~~~

A lightweight terminal spinner.
"""

from __future__ import absolute_import

import functools
import itertools
import sys
import threading
import time

from .base_spinner import default_spinner
from .compat import PY2, builtin_str, str
from .constants import ENCODING
from .helpers import to_unicode
from .termcolor import colored

# TODO: update docstring
class Yaspin(object):
    """Implements a context manager that spawns a daemon thread
    that writes spinner frames into a tty (stdout) during
    context execution.

    Arguments:
        spinner (yaspin.Spinner): Spinner to use.
        text (str): Text to show along with spinner.

    """

    # When Python finds its output attached to a terminal,
    # it sets the sys.stdout.encoding attribute to the terminal's encoding.
    # The print statement's handler will automatically encode unicode
    # arguments into bytes.
    #
    # In Py2 when piping or redirecting output, Python does not detect
    # the desired character set of the output, it sets sys.stdout.encoding
    # to None, and print will invoke the default "ascii" codec.
    #
    # Py3 invokes "UTF-8" codec by default.
    #
    # Thats why in Py2, output should be encoded manually with desired
    # encoding in order to support pipes and redirects.

    def __init__(self, spinner=None, text='', color=None):
        self._spinner = self._set_spinner(spinner)
        self._frames = self._set_frames(self._spinner)
        self._interval = self._set_interval(self._spinner)
        self._cycle = self._set_cycle(self._frames)
        self._text = self._set_text(text)
        self._color = self._set_color(color) if color else color

        self._stop_spin = None
        self._spin_thread = None
        self._last_frame = None

    def __repr__(self):
        repr_ = u'<Yaspin frames={0!s}>'.format(self._frames)
        if PY2:
            return repr_.encode(ENCODING)
        return repr_

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, exc_type, exc_val, traceback):
        # Avoid stop() execution for the 2nd time
        if self._spin_thread.is_alive():
            self.stop()
        return False  # nothing is handled

    def __call__(self, fn):
        @functools.wraps(fn)
        def inner(*args, **kwargs):
            with self:
                return fn(*args, **kwargs)
        return inner

    @property
    def spinner(self):
        return self._spinner

    @spinner.setter
    def spinner(self, sp):
        self._spinner = self._set_spinner(sp)
        self._frames = self._set_frames(self._spinner)
        self._interval = self._set_interval(self._spinner)
        self._cycle = self._set_cycle(self._frames)

    @property
    def text(self):
        return self._text

    @text.setter
    def text(self, txt):
        self._text = self._set_text(txt)

    @property
    def color(self):
        return self._color

    @color.setter
    def color(self, value):
        self._color = self._set_color(value) if value else value

    def start(self):
        if sys.stdout.isatty():
            self._hide_cursor()

        self._stop_spin = threading.Event()
        self._spin_thread = threading.Thread(target=self._spin)
        self._spin_thread.start()

    def stop(self):
        if self._spin_thread:
            self._stop_spin.set()
            self._spin_thread.join()

        sys.stdout.write("\r")
        self._clear_line()

        if sys.stdout.isatty():
            self._show_cursor()

    def ok(self, text="OK"):
        """Set Ok (success) finalizer to a spinner."""
        self._freeze(text)

    def fail(self, text="FAIL"):
        """Set fail finalizer to a spinner."""
        self._freeze(text)

    def _freeze(self, final_text):
        """Stop spinner, compose last frame and 'freeze' it."""
        if PY2:
            final_text = to_unicode(final_text).strip()

        self._last_frame = self._compose_out(final_text,
                                             self._text,
                                             self._color,
                                             mode="last")

        # Should be stopped here, otherwise prints after
        # self._freeze call will mess up the spinner
        self.stop()
        sys.stdout.write(self._last_frame)

    def _spin(self):
        while not self._stop_spin.is_set():
            # Compose output
            spin_phase = next(self._cycle)
            out = self._compose_out(spin_phase, self._text, self._color)

            # Write
            sys.stdout.write(out)
            self._clear_line()
            sys.stdout.flush()

            # Wait
            time.sleep(self._interval)
            sys.stdout.write('\b')

    @staticmethod
    def _compose_out(frame, text, color, mode=None):
        # Ensure Unicode input
        assert isinstance(frame, str)
        assert isinstance(text, str)

        if PY2:
            frame = frame.encode(ENCODING)
            text = text.encode(ENCODING)

        if color and callable(color):
            frame = color(frame)
        if color and not callable(color):
            frame = colored(frame, color)

        if not mode:
            out = "\r{0} {1}".format(frame, text)
        else:
            out = "{0} {1}\n".format(frame, text)

        # Ensure output is bytes for Py2 and Unicode for Py3
        assert isinstance(out, builtin_str)

        return out

    @staticmethod
    def _set_spinner(spinner):
        if not spinner:
            sp = default_spinner

        if hasattr(spinner, "frames") and hasattr(spinner, "interval"):
            if not spinner.frames or not spinner.interval:
                sp = default_spinner
            else:
                sp = spinner
        else:
            sp = default_spinner

        return sp

    @staticmethod
    def _set_frames(spinner):
        if PY2:
            return to_unicode(spinner.frames)
        return spinner.frames

    @staticmethod
    def _set_interval(spinner):
        # Milliseconds to Seconds
        return spinner.interval * 0.001

    @staticmethod
    def _set_cycle(frames):
        return itertools.cycle(frames)

    @staticmethod
    def _set_text(text):
        if PY2:
            return to_unicode(text).strip()
        return text.strip()

    @staticmethod
    def _set_color(color):

        if callable(color):
            return color

        available_text_colors = (
            "red", "green", "yellow", "blue", "magenta", "cyan", "white",
        )

        c_lower = color.lower()

        if c_lower not in available_text_colors:
            raise ValueError(
                "{0}: unsupported text color. Use on of the: {1}"
                .format(c_lower, available_text_colors)
            )

        return c_lower

    @staticmethod
    def _hide_cursor():
        sys.stdout.write("\033[?25l")
        sys.stdout.flush()

    @staticmethod
    def _show_cursor():
        sys.stdout.write("\033[?25h")
        sys.stdout.flush()

    @staticmethod
    def _clear_line():
        sys.stdout.write("\033[K")

# TODO: update docstring
def yaspin(spinner=None, text='', color=None):
    """Display spinner in stdout.

    Can be used as a context manager or as a function decorator.

    Arguments:
        spinner (yaspin.Spinner): Spinner to use.
        text (str): Text to show along with spinner.

    Example::

        # Use as a context manager
        with yaspin():
            some_operations()

        # Context manager with text
        with yaspin(text="Processing..."):
            some_operations()

        # Context manager with custom sequence
        with yaspin(Spinner('-\\|/', 150)):
            some_operations()

        # As decorator
        @yaspin(text="Loading...")
        def foo():
            time.sleep(5)

        foo()

    """
    return Yaspin(spinner=spinner, text=text, color=color)
<commit_msg>update docstrings<commit_after># -*- coding: utf-8 -*-

"""
yaspin.yaspin
~~~~~~~~~~~~~

A lightweight terminal spinner.
"""

from __future__ import absolute_import

import functools
import itertools
import sys
import threading
import time

from .base_spinner import default_spinner
from .compat import PY2, builtin_str, str
from .constants import ENCODING
from .helpers import to_unicode
from .termcolor import colored

class Yaspin(object):
    """Implements a context manager that spawns a thread
    to write spinner frames into a tty (stdout) during
    context execution.
    """

    # When Python finds its output attached to a terminal,
    # it sets the sys.stdout.encoding attribute to the terminal's encoding.
    # The print statement's handler will automatically encode unicode
    # arguments into bytes.
    #
    # In Py2 when piping or redirecting output, Python does not detect
    # the desired character set of the output, it sets sys.stdout.encoding
    # to None, and print will invoke the default "ascii" codec.
    #
    # Py3 invokes "UTF-8" codec by default.
    #
    # Thats why in Py2, output should be encoded manually with desired
    # encoding in order to support pipes and redirects.

    def __init__(self, spinner=None, text='', color=None):
        self._spinner = self._set_spinner(spinner)
        self._frames = self._set_frames(self._spinner)
        self._interval = self._set_interval(self._spinner)
        self._cycle = self._set_cycle(self._frames)
        self._text = self._set_text(text)
        self._color = self._set_color(color) if color else color

        self._stop_spin = None
        self._spin_thread = None
        self._last_frame = None

    def __repr__(self):
        repr_ = u'<Yaspin frames={0!s}>'.format(self._frames)
        if PY2:
            return repr_.encode(ENCODING)
        return repr_

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, exc_type, exc_val, traceback):
        # Avoid stop() execution for the 2nd time
        if self._spin_thread.is_alive():
            self.stop()
        return False  # nothing is handled

    def __call__(self, fn):
        @functools.wraps(fn)
        def inner(*args, **kwargs):
            with self:
                return fn(*args, **kwargs)
        return inner

    @property
    def spinner(self):
        return self._spinner

    @spinner.setter
    def spinner(self, sp):
        self._spinner = self._set_spinner(sp)
        self._frames = self._set_frames(self._spinner)
        self._interval = self._set_interval(self._spinner)
        self._cycle = self._set_cycle(self._frames)

    @property
    def text(self):
        return self._text

    @text.setter
    def text(self, txt):
        self._text = self._set_text(txt)

    @property
    def color(self):
        return self._color

    @color.setter
    def color(self, value):
        self._color = self._set_color(value) if value else value

    def start(self):
        if sys.stdout.isatty():
            self._hide_cursor()

        self._stop_spin = threading.Event()
        self._spin_thread = threading.Thread(target=self._spin)
        self._spin_thread.start()

    def stop(self):
        if self._spin_thread:
            self._stop_spin.set()
            self._spin_thread.join()

        sys.stdout.write("\r")
        self._clear_line()

        if sys.stdout.isatty():
            self._show_cursor()

    def ok(self, text="OK"):
        """Set Ok (success) finalizer to a spinner."""
        self._freeze(text)

    def fail(self, text="FAIL"):
        """Set fail finalizer to a spinner."""
        self._freeze(text)

    def _freeze(self, final_text):
        """Stop spinner, compose last frame and 'freeze' it."""
        if PY2:
            final_text = to_unicode(final_text).strip()

        self._last_frame = self._compose_out(final_text,
                                             self._text,
                                             self._color,
                                             mode="last")

        # Should be stopped here, otherwise prints after
        # self._freeze call will mess up the spinner
        self.stop()
        sys.stdout.write(self._last_frame)

    def _spin(self):
        while not self._stop_spin.is_set():
            # Compose output
            spin_phase = next(self._cycle)
            out = self._compose_out(spin_phase, self._text, self._color)

            # Write
            sys.stdout.write(out)
            self._clear_line()
            sys.stdout.flush()

            # Wait
            time.sleep(self._interval)
            sys.stdout.write('\b')

    @staticmethod
    def _compose_out(frame, text, color, mode=None):
        # Ensure Unicode input
        assert isinstance(frame, str)
        assert isinstance(text, str)

        if PY2:
            frame = frame.encode(ENCODING)
            text = text.encode(ENCODING)

        if color and callable(color):
            frame = color(frame)
        if color and not callable(color):
            frame = colored(frame, color)

        if not mode:
            out = "\r{0} {1}".format(frame, text)
        else:
            out = "{0} {1}\n".format(frame, text)

        # Ensure output is bytes for Py2 and Unicode for Py3
        assert isinstance(out, builtin_str)

        return out

    @staticmethod
    def _set_spinner(spinner):
        if not spinner:
            sp = default_spinner

        if hasattr(spinner, "frames") and hasattr(spinner, "interval"):
            if not spinner.frames or not spinner.interval:
                sp = default_spinner
            else:
                sp = spinner
        else:
            sp = default_spinner

        return sp

    @staticmethod
    def _set_frames(spinner):
        if PY2:
            return to_unicode(spinner.frames)
        return spinner.frames

    @staticmethod
    def _set_interval(spinner):
        # Milliseconds to Seconds
        return spinner.interval * 0.001

    @staticmethod
    def _set_cycle(frames):
        return itertools.cycle(frames)

    @staticmethod
    def _set_text(text):
        if PY2:
            return to_unicode(text).strip()
        return text.strip()

    @staticmethod
    def _set_color(color):

        if callable(color):
            return color

        available_text_colors = (
            "red", "green", "yellow", "blue", "magenta", "cyan", "white",
        )

        c_lower = color.lower()

        if c_lower not in available_text_colors:
            raise ValueError(
                "{0}: unsupported text color. Use on of the: {1}"
                .format(c_lower, available_text_colors)
            )

        return c_lower

    @staticmethod
    def _hide_cursor():
        sys.stdout.write("\033[?25l")
        sys.stdout.flush()

    @staticmethod
    def _show_cursor():
        sys.stdout.write("\033[?25h")
        sys.stdout.flush()

    @staticmethod
    def _clear_line():
        sys.stdout.write("\033[K")

def yaspin(spinner=None, text='', color=None):
    """Display spinner in stdout.

    Can be used as a context manager or as a function decorator.

    Arguments:
        spinner (yaspin.Spinner, optional): Spinner to use.
        text (str, optional): Text to show along with spinner.
        color (str, callable, optional): Color or color style of the spinner.

    Returns:
        yaspin.Yaspin: instance of the Yaspin class.

    Raises:
        ValueError: If unsupported `color` is specified.

    Example::

        # Use as a context manager
        with yaspin():
            some_operations()

        # Context manager with text
        with yaspin(text="Processing..."):
            some_operations()

        # Context manager with custom sequence
        with yaspin(Spinner('-\\|/', 150)):
            some_operations()

        # As decorator
        @yaspin(text="Loading...")
        def foo():
            time.sleep(5)

        foo()

    """
    return Yaspin(spinner=spinner, text=text, color=color)
<|endoftext|>


<commit_before>""" Testing separate debug info loading for base binary with a symlink. """
import os
import time
import lldb
import sys
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil

class TestTargetSymbolsSepDebugSymlink(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    @no_debug_info_test  # Prevent the genaration of the dwarf version of this test
    @skipUnlessPlatform(['linux'])
    @skipIf(hostoslist=["windows"])
    def test_target_symbols_sepdebug_symlink_case(self):
        self.build(clean=True)
        exe = self.getBuildArtifact("dirsymlink/stripped.symlink")

        lldbutil.run_to_name_breakpoint(self, "main", exe_name = exe)
<commit_msg>Skip TestTargetSymbolsSepDebugSymlink on remote targets<commit_after>""" Testing separate debug info loading for base binary with a symlink. """
import os
import time
import lldb
import sys
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil

class TestTargetSymbolsSepDebugSymlink(TestBase):

    mydir = TestBase.compute_mydir(__file__)

    @no_debug_info_test  # Prevent the genaration of the dwarf version of this test
    @skipUnlessPlatform(['linux'])
    @skipIf(hostoslist=["windows"])
    @skipIfRemote # llvm.org/pr36237
    def test_target_symbols_sepdebug_symlink_case(self):
        self.build(clean=True)
        exe = self.getBuildArtifact("dirsymlink/stripped.symlink")

        lldbutil.run_to_name_breakpoint(self, "main", exe_name = exe)
<|endoftext|>


<commit_before>import ssl
import time

import docker
from docker import Client

class DockerCli:
    def __init__(self):
        self.docker_conns = []

        conn = self.__connect_to_custom_tcp()
        if conn:
            self.docker_conns.append(conn)

        conn = self.__connect_to_default_socket()
        if conn:
            self.docker_conns.append(conn)

        if not len(self.docker_conns):
            print " => Cannot find docker connection."
            exit(1)

    def __connect_to_default_socket(self):
        try:
            c = Client(base_url='unix:///var/run/docker.sock')
            c.info()
            return c
        except Exception:
            return None

    def __connect_to_custom_tcp(self):
        num_of_tries = 1
        current_tries = 0
        while True:
            try:
                tls_config = docker.tls.TLSConfig(
                    client_cert=('/root/.docker/cert.pem', '/root/.docker/key.pem'),
                    verify='/root/.docker/ca.pem', ssl_version=ssl.PROTOCOL_TLSv1
                )
                c = Client(base_url='https://localhost:2379', tls=tls_config)
                c.info()
                return c
            except Exception as e:
                if current_tries <= num_of_tries:
                    time.sleep(0.5)
                    current_tries += 1
                else:
                    print " => Skipping connect to custom tcp."
                    return None

    def __remove_tcp_from_port(self, tcp_port):
        return int(tcp_port.replace('/tcp', ''))

    def __get_docker_connection(self):
        if len(self.docker_conns):
            return self.docker_conns
        print " => No docker connection found."
        exit(1)

    def get_ip_and_host_port(self, container, port):
        container_ip = ''
        host_port = 0
        if container['node_ip']:
            container_ip = container['node_ip']
            tcp_port = container['ports'].get('%d/tcp' % port, '')
            if tcp_port:
                host_port = int(tcp_port[0].get('HostPort', 0))
        else:
            container_ip = container['ip']
            tcp_port = container['ports'].get('%d/tcp' % port, '__NOT_FOUND__')
            if tcp_port != '__NOT_FOUND__':
                host_port = port
        return container_ip, host_port

    def get_running_containers(self):
        containers = []
        for docker_conn in self.docker_conns:
            tmp_containers = docker_conn.containers()
            ok_containers = []
            for tmp_container in tmp_containers:
                if tmp_container['Status'] == 'Pending':
                    continue
                tmp_container['more_info'] = docker_conn.inspect_container(tmp_container)
                ok_containers.append(tmp_container)
            containers += ok_containers
        return containers

    def list_containers_filtered(self):
        containers = []
        for container in self.get_running_containers():
            info = container['more_info']
            item = {}
            if info.get('Node', '') != '':
                item['node_ip'] = info['Node']['IP']
            else:
                item['node_ip'] = ''
            item['name'] = container['Names'][0][1:]
            item['ip'] = info['NetworkSettings']['IPAddress']
            item['ports'] = info['NetworkSettings']['Ports']
            containers.append(item)
        return containers<commit_msg>Fix swarm change ip format for Node<commit_after>import ssl
import time

import docker
from docker import Client

class DockerCli:
    def __init__(self):
        self.docker_conns = []

        conn = self.__connect_to_custom_tcp()
        if conn:
            self.docker_conns.append(conn)

        conn = self.__connect_to_default_socket()
        if conn:
            self.docker_conns.append(conn)

        if not len(self.docker_conns):
            print " => Cannot find docker connection."
            exit(1)

    def __connect_to_default_socket(self):
        try:
            c = Client(base_url='unix:///var/run/docker.sock')
            c.info()
            return c
        except Exception:
            return None

    def __connect_to_custom_tcp(self):
        num_of_tries = 1
        current_tries = 0
        while True:
            try:
                tls_config = docker.tls.TLSConfig(
                    client_cert=('/root/.docker/cert.pem', '/root/.docker/key.pem'),
                    verify='/root/.docker/ca.pem', ssl_version=ssl.PROTOCOL_TLSv1
                )
                c = Client(base_url='https://localhost:2379', tls=tls_config)
                c.info()
                return c
            except Exception as e:
                if current_tries <= num_of_tries:
                    time.sleep(0.5)
                    current_tries += 1
                else:
                    print " => Skipping connect to custom tcp."
                    return None

    def __remove_tcp_from_port(self, tcp_port):
        return int(tcp_port.replace('/tcp', ''))

    def __get_docker_connection(self):
        if len(self.docker_conns):
            return self.docker_conns
        print " => No docker connection found."
        exit(1)

    def get_ip_and_host_port(self, container, port):
        container_ip = container['ip']
        host_port = 0
        if container['found_node']:
            tcp_port = container['ports'].get('%d/tcp' % port, '')
            if tcp_port:
                container_ip = tcp_port[0]['HostIp']
                host_port = int(tcp_port[0].get('HostPort', 0))
        else:
            tcp_port = container['ports'].get('%d/tcp' % port, '__NOT_FOUND__')
            if tcp_port != '__NOT_FOUND__':
                host_port = port
        return container_ip, host_port

    def get_running_containers(self):
        containers = []
        for docker_conn in self.docker_conns:
            tmp_containers = docker_conn.containers()
            ok_containers = []
            for tmp_container in tmp_containers:
                if tmp_container['Status'] == 'Pending':
                    continue
                tmp_container['more_info'] = docker_conn.inspect_container(tmp_container)
                ok_containers.append(tmp_container)
            containers += ok_containers
        return containers

    def list_containers_filtered(self):
        containers = []
        for container in self.get_running_containers():
            info = container['more_info']
            item = {}
            if info.get('Node', '') != '':
                item['found_node'] = True
            else:
                item['found_node'] = False
            item['name'] = container['Names'][0][1:]
            item['ip'] = info['NetworkSettings']['IPAddress']
            item['ports'] = info['NetworkSettings']['Ports']
            containers.append(item)
        return containers
<|endoftext|>