예제 #1
0
def confirm(question):
    """Prompts user to confirm with (y/n)."""
    # Python 2to3 compatbility
    response = input(color_text('[?] ', 'yellow') +
                     color_text(question, 'cyan') + '? (y/n) ')

    if response in ['y', 'yes']:
        return True
예제 #2
0
def header(string, logger=None):
    """Prints a header."""
    if logger:
        logger.info(string)

    if get_os() == 'Windows':
        print('==> ' + string)
    else:
        print(color_text('==> ', 'green') + color_text(string, 'white'))
예제 #3
0
    def config(self, ref, diff=False, config=None, update=False, set_env=None, **kwargs):
        app, service = self.parse_app_ref(ref, kwargs, app_only=True)

        app_config = yield self._remote_exec('config', app)

        parser_env = set_env or app_config['env']

        if diff or (not update and not set_env):
            old_config = YamlConfig(source=unicode(app_config['source']), app_name=app, env=parser_env)
            old_config.load(process=False)
            from collections import OrderedDict

            yaml.add_representer(unicode, yaml.representer.SafeRepresenter.represent_unicode)
            yaml.add_representer(OrderedDict, self.represent_ordereddict)
            olds = yaml.dump(old_config.config, default_flow_style=False)

        if not update and not diff and not set_env:
            x = PrettyTable(["Name", "Value"], hrules=ALL, align='l', header=False)
            x.align = "l"
            x.add_row(['Config', olds])
            x.add_row(['Environment', app_config['env']])
            x.add_row(['Path', app_config['path']])
            print(x)

        else:
            if config:
                config_file = os.path.expanduser(config)
            else:
                config_file = 'mcloud.yml'

            new_config = YamlConfig(file=config_file, app_name=app, env=parser_env)
            new_config.load(process=False)

            if diff:
                yaml.add_representer(unicode, yaml.representer.SafeRepresenter.represent_unicode)
                yaml.add_representer(OrderedDict, self.represent_ordereddict)
                news = yaml.dump(new_config.config, default_flow_style=False)

                if olds == news:
                    print('Configs are identical.')
                else:

                    for line in unified_diff(olds.splitlines(1), news.splitlines(1)):
                        if line.endswith('\n'):
                            line = line[0:-1]
                        if line.startswith('+'):
                            print color_text(line, color='green')
                        elif line.startswith('-'):
                            print color_text(line, color='red')
                        else:
                            print line
            else:
                if set_env and not update:
                    yield self._remote_exec('update', app, env=set_env)
                else:
                    yield self._remote_exec('update', app, config=new_config.export(), env=set_env)
예제 #4
0
    def call(self, to=None, **kwargs):

        try:
            host = config.get_command_host(name=to)
        except KeyError:
            raise Exception('Host alias not found.')

        settings = inject.instance('settings')

        uuid_ = uuid.uuid1()

        for line in self.command['commands']:

            line = line.replace('{host}', host)
            line = line.replace('{uuid}', uuid_)

            print(color_text(line, color='white', bcolor='blue'))

            params = line.split(' ')
            args = arg_parser.parse_args(params)

            args.argv0 = sys.argv[0]

            client = ApiRpcClient(host='127.0.0.1', settings=settings)

            if isinstance(args.func, str):
                yield getattr(client, args.func)(**vars(args))
            else:
                yield args.func(**vars(args))
예제 #5
0
    def call(self, to=None, **kwargs):

        try:
            host = config.get_command_host(name=to)
        except KeyError:
            raise Exception('Host alias not found.')

        settings = inject.instance('settings')

        uuid_ = uuid.uuid1()

        for line in self.command['commands']:

            line = line.replace('{host}', host)
            line = line.replace('{uuid}', uuid_)

            print(color_text(line, color='white', bcolor='blue'))

            params = line.split(' ')
            args = arg_parser.parse_args(params)

            args.argv0 = sys.argv[0]

            client = ApiRpcClient(host='127.0.0.1', settings=settings)

            if isinstance(args.func, str):
                yield getattr(client, args.func)(**vars(args))
            else:
                yield args.func(**vars(args))
예제 #6
0
def success(string, logger=None):
    """Prints a success message."""
    if logger:
        logger.info(string)
    if get_os() == 'Windows':
        print('[+] ' + string)
    else:
        print(color_text('[✓] ', 'green') + string)
예제 #7
0
def error(string, logger=None):
    """Prints a error message."""
    if logger:
        logger.error(string)
    if get_os() == 'Windows':
        print('[x] ' + string)
    else:
        print(color_text('[✗] ', 'magenta') + string)
예제 #8
0
def warning(string, logger=None):
    """Prints a warning message."""
    if logger:
        logger.warning(string)
    if get_os() == 'Windows':
        print('[!] ' + string)
    else:
        print(color_text('[!] ', 'yellow') + string)
예제 #9
0
def info(string, logger=None):
    """Prints a info message."""
    if logger:
        logger.info(string)
    if get_os() == 'Windows':
        print('[i] ' + string)
    else:
        print(color_text('[i] ', 'cyan') + string)
예제 #10
0
def subheader(string, logger=None):
    """Prints a subheader."""
    if logger:
        logger.info(string)

    if get_os() == 'Windows':
        print('==> ' + string)
    else:
        print(color_text('==> ', 'blue') + string)
예제 #11
0
파일: main.py 프로젝트: hydface2/mcloud
            def call_command():
                client = ApiRpcClient(host=args.host, settings=settings)
                interrupt_manager.append(ClientProcessInterruptHandler(client))

                try:
                    yield getattr(client, args.func)(**vars(args))
                except Exception as e:
                    label = type(e)
                    if isinstance(e, ValueError):
                        label = 'error'
                    else:
                        label = str(label)

                    print '\n  %s: %s\n' % (
                        color_text(label, color='cyan'),
                        color_text(str(e), color='yellow'),
                    )

                interrupt_manager.manual_interrupt()
예제 #12
0
            def call_command():
                client = ApiRpcClient(host=args.host, settings=settings)
                interrupt_manager.append(ClientProcessInterruptHandler(client))

                try:
                    yield getattr(client, args.func)(**vars(args))
                except Exception as e:
                    label = type(e)
                    if isinstance(e, ValueError):
                        label = 'error'
                    else:
                        label = str(label)

                    print '\n  %s: %s\n' % (
                        color_text(label, color='cyan'),
                        color_text(str(e), color='yellow'),
                    )

                interrupt_manager.manual_interrupt()
예제 #13
0
def test():
    print "COLORS LIST :"
    for color in colors.COLOR_CODE_TEXT:
        print colors.color_text("My Text", color), color

    print ""
    print "------------------------------"
    print "BACKGROUND COLORS LIST :"
    for bcolor in colors.COLOR_CODE_BG:
        print colors.color_text("My Text", bcolor=bcolor), bcolor

    print ""
    print "------------------------------"
    print "EFFECTS :"
    for effect in colors.COLOR_EFFET:
        print colors.color_text("My Text", effect=effect), effect

    print ""
    print "------------------------------"
    print "ALL :"
    for color in colors.COLOR_CODE_TEXT:
        for bcolor in colors.COLOR_CODE_BG:
            for effect in colors.COLOR_EFFET:
                print colors.color_text("My Text", color, bcolor, effect), color.ljust(10), bcolor.ljust(10), effect
예제 #14
0
def main():
    '''
    Main scrit bootstrap function
    '''
    PATH = False
    POIS = False
    SEGMENT_PATHS = False

    pathNumber = sys.argv[1]
    ce = sys.argv[2]
    if len(sys.argv) > 3:
        raise IOError('Only 2 paramaters. If second parament has blanck space, use \' or "')
    WDPath = WD+pathNumber+'/'
    try:

        def getTypologies(rPoi,*keys):
            '''
            Fnction to buil script insert for manytomany typologyes relation in pois
            :return: string
            '''
            qRes = []
            for field in TYPOLOGY_MAP.keys():
                if field != keys[0] and rPoi[field]:
                    qRes.append("INSERT INTO typologies_pois (typology_id,poi_id) VALUES({},{})".format(TYPOLOGY_MAP[field],rPoi['id']))
            return qRes

        #check if directory exixts:

        if not os.path.exists(WDPath):
            raise IOError('Directory {} not exist!'.format(pathNumber))

        #Define our connection string
        conn_string = "host='{}' dbname='{}' user='******' password='******'".format(PG_HOST,PG_DB,PG_USER,PG_PASSWORD)

        # print the connection string we will use to connect
        print "Connecting to database\n	->%s" % (conn_string)

        # get a connection, if a connect cannot be made an exception will be raised here
        conn = psycopg2.connect(conn_string)

        # conn.cursor will return a cursor object, you can use this cursor to perform queries
        cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
        print "Connected!\n"



        #sentieri
        if os.path.exists(WDPath+'sentiero_'+pathNumber+'.shp'):
            # get current path_id
            cursor.execute("SELECT id from paths WHERE nome = '{}'".format(pathNumber))
            pathRow = cursor.fetchone()
            conn.commit()
            OLD_PATH_ID = pathRow['id'] if pathRow and 'id' in pathRow else None


            #before erase data from db based on name!! is not safe
            qDeletePath = "DELETE FROM paths WHERE nome = '{}'".format(pathNumber)
            cursor.execute(qDeletePath)
            conn.commit()
            PATH = True
            cmdPATH = "ogr2ogr -update -addFields -geomfield 'the_geom' -f PostgreSQL 'PG:dbname={} user={} password={} host={}' {}sentiero_{}.shp -nlt PROMOTE_TO_MULTI -nln public.paths".format(PG_DB,PG_USER,PG_PASSWORD,PG_HOST,WDPath,pathNumber)
            os.system(cmdPATH)
            print colors.color_text("== LOAD PATH SHP DONE! ==", color="green")

        if not PATH:
            return False

        cursor.execute("SELECT se,id from paths ORDER by id DESC limit 1")
        pathRow = cursor.fetchone()
        conn.commit()
        #we get the SE key
        SE = pathRow['se']
        PATH_ID = pathRow['id']

        # update users_paths table
        if OLD_PATH_ID is not None:
            cursor.execute("UPDATE  users_paths set path_id={} where path_id={}".format(PATH_ID, OLD_PATH_ID))
            conn.commit()



        #punti notevoli
        if os.path.exists(WDPath+'puntinotevoli_'+pathNumber+'.shp'):
            qDeletePoi = "DELETE FROM pois WHERE se = '{}'".format(SE)
            cursor.execute(qDeletePoi)
            conn.commit()
            POIS = True
            cmdPOI = "ogr2ogr -update -addFields -geomfield 'the_geom' -f PostgreSQL 'PG:dbname={} user={} password={} host={}' {}puntinotevoli_{}.shp -nlt POINT -nln public.pois".format(PG_DB,PG_USER,PG_PASSWORD,PG_HOST,WDPath,pathNumber)
            out = os.system(cmdPOI)
            print colors.color_text("== LOAD POI SHP DONE! ==", color="green")


        #tratte
        if os.path.exists(WDPath+'tratte_'+pathNumber+'.shp'):
            qDeleteSegment = "DELETE FROM path_segments WHERE se = '{}'".format(SE)
            cursor.execute(qDeleteSegment)
            conn.commit()
            SEGMENT_PATHS = True
            cmdSEGMENT = "ogr2ogr -update -addFields -geomfield 'the_geom' -f PostgreSQL 'PG:dbname={} user={} password={} host={}' {}tratte_{}.shp -nlt PROMOTE_TO_MULTI -nln public.path_segments".format(PG_DB,PG_USER,PG_PASSWORD,PG_HOST,WDPath,pathNumber)
            os.system(cmdSEGMENT)
            print colors.color_text("== LOAD SEGMENTS SHP DONE! ==", color="green")


        #circuito escursionistico
        qItinerary = "SELECT * FROM itineraries WHERE name='{}'".format(ce)
        cursor.execute(qItinerary)
        recordsItinerary = cursor.fetchone()
        if not recordsItinerary:
            qInsertItinerary = "INSERT INTO itineraries (name,description) VALUES ('{}','')".format(ce)
            cursor.execute(qInsertItinerary)
            cursor.execute(qItinerary)
            recordsItinerary = cursor.fetchone()
        ITINERARY_ID = recordsItinerary['id']


        # COPYNG AND OTHER FOR PATH
        #==================================================
        copyingFieds = [
            "color = '#FF0000'",
            'width = 6',
            'data_ins = {}'.format(int(time.time())),
            'data_mod = data_ins'

        ]
        q = "UPDATE paths SET {} WHERE se = '{}'".format(', '.join(copyingFieds),SE)
        cursor.execute(q)
        print colors.color_text("== COPYING PATH FIELDS DONE! ==", color="green")


        # adding to itinerary PATH
        #-----------------------------------------
        q = "INSERT INTO itineraries_paths (itinerary_id,path_id) VALUES ({},{})".format(ITINERARY_ID,PATH_ID)
        cursor.execute(q)
        print colors.color_text("== ADD PATH TO ITINERARY DONE! ==", color="green")


        # hightlitings path
        #-----------------------------------------
        fileProfile = WDPath+'profile/'+pathNumber+'.csv'
        fieldsProfile = ['x','y','cds2d','z','cds3d','slopdeg']
        #first we delete if exists
        qDelete = "DELETE FROM heights_profile_paths WHERE path_id = {}".format(PATH_ID)
        cursor.execute(qDelete)
        if os.path.exists(fileProfile):
            qMaster = "INSERT INTO heights_profile_paths (path_id,"+','.join(fieldsProfile)+") VALUES ({},{},{},{},{},{},{})"
            with open(fileProfile, 'rb') as csvfile:
                profileReader = csv.DictReader(csvfile)
                for r in profileReader:
                    if r['slopdeg'] == '':
                        r['slopdeg'] = 'null'
                    rValues = [PATH_ID] + [r[k] for k in fieldsProfile]
                    q = qMaster.format(*rValues)
                    cursor.execute(q)
            print colors.color_text("== COPYING PATH HEIGHTS DONE! ==", color="green")


        # COPYNG AND OTHER FOR POI
        #==================================================
        if POIS:
            copyingFieds = [
                # for test
                'data_ins = {}'.format(int(time.time())),
                'data_mod = data_ins'


            ]

            q = "UPDATE pois SET {} WHERE se = '{}'".format(', '.join(copyingFieds),SE)
            cursor.execute(q)
            print colors.color_text("== COPYING POI FIELDS DONE! ==", color="green")


         # adding to itinerary PATH
        #-----------------------------------------

        # adding to itinerary PATH
        #-----------------------------------------
        if POIS:
            q = "SELECT * FROM pois WHERE se='{}'".format(SE)
            cursor.execute(q)
            pois = cursor.fetchall()
            for poi in pois:
                q = "INSERT INTO itineraries_pois (itinerary_id,poi_id) VALUES ({},{})".format(ITINERARY_ID,poi['id'])
                cursor.execute(q)
            print colors.color_text("== ADD POIS TO ITINERARY DONE! ==", color="green")


        # imaging poi
        #-----------------------------------------
        if POIS:
            fieldsImage = ['file','description','data_ins','data_mod','norder']
            fielsImage = glob.glob(WDPath+'Foto/*.*')
            qPois = "SELECT * FROM pois WHERE  se='{}'".format(SE)
            cursor.execute(qPois)
            recordsPois = cursor.fetchall()
            for rPoi in recordsPois:
                if rPoi['photo'] is not None:
                    qImageDelete = "DELETE FROM image_pois WHERE poi_id = {}".format(rPoi['id'])
                    cursor.execute(qImageDelete)
                    #check if files exists
                    jpgFile = WDPath+'Foto/{}.JPG'.format(rPoi['photo'])
                    JPGFile = WDPath+'Foto/{}.jpg'.format(rPoi['photo'])
                    if os.path.exists(jpgFile):
                        fileToCopy = jpgFile
                    elif os.path.exists(JPGFile):
                        fileToCopy = JPGFile
                    else:
                        fileToCopy = None

                    #copy file and inset into db
                    if fileToCopy:
                        newFileName = os.path.basename(fileToCopy).replace('.','_{}.'.format(pathNumber))
                        copy2(fileToCopy, IMGD+newFileName)
                        print colors.color_text("== IMAGE POI {} COPIED! ==".format(newFileName), color="yellow")
                        # resize image for thumbnail
                        dimentionWH = 80
                        img = Image.open(IMGD+newFileName)
                        if(img.size[0] >= img.size[1]):
                            wpercent = (dimentionWH / float(img.size[0]))
                            wsize = dimentionWH
                            hsize = int((float(img.size[1]) * float(wpercent)))
                        else:
                            wpercent = (dimentionWH / float(img.size[1]))
                            wsize = int((float(img.size[0]) * float(wpercent)))
                            hsize = dimentionWH

                        img = img.resize((wsize, hsize), PIL.Image.ANTIALIAS)
                        img.save(IMGDTHB+newFileName)
                        print colors.color_text("== THUMBNAIL IMAGE POI {} CREATED! ==".format(newFileName), color="yellow")

                        now = int(time.time())
                        qImage = "INSERT INTO image_pois (poi_id,"+','.join(fieldsImage)+") VALUES ({},{},{},{},{},{})".format(
                            rPoi['id'],
                            "'{}'".format(newFileName),
                            'null',
                            now,
                            now,
                            0
                        )
                        cursor.execute(qImage)

                #SELECT TYPOLOGY ID
                #-----------------------------
                print rPoi['id']
                if rPoi['fatt_degr'] is not None:
                    print colors.color_text("== DEGRADO! ==", color="red")
                    qPoi = "UPDATE pois SET typology_id={} WHERE id={}".format(TYPOLOGY_MAP['fatt_degr'],rPoi['id'])
                    qTypologiesPoi = getTypologies(rPoi,'fatt_degr')
                elif reduce(operator.or_,[bool(rPoi[k]) for k in PT_INTER_TYPOLOGY_ORDER.keys()]):
                    print colors.color_text("== PT INTERSESSE! ==", color="green")
                    print [bool(rPoi[k]) for k in PT_INTER_TYPOLOGY_ORDER.keys()]
                    #select order:
                    #########################
                    typology_order = 0
                    for k in PT_INTER_TYPOLOGY_ORDER.keys():
                        if rPoi[k] and PT_INTER_TYPOLOGY_ORDER[k] >= typology_order:
                            typology_order = PT_INTER_TYPOLOGY_ORDER[k]
                            typology_id = TYPOLOGY_MAP[k]
                            typology_key = k
                    qPoi = "UPDATE pois SET typology_id={} WHERE id={}".format(typology_id,rPoi['id'])
                    qTypologiesPoi = getTypologies(rPoi,typology_key)
                else:
                    print colors.color_text("== SEGNALETICA! ==", color="green")
                    if rPoi['nuov_segna']:
                        qPoi = "UPDATE pois SET typology_id={}, publish=false WHERE id={}".format(TYPOLOGY_MAP['nuov_segna'],rPoi['id'])
                        qTypologiesPoi = getTypologies(rPoi,'nuov_segna')
                    elif rPoi['stato_segn']:
                        qPoi = "UPDATE pois SET typology_id={}, publish=false WHERE id={}".format(TYPOLOGY_MAP['stato_segn'],rPoi['id'])
                        qTypologiesPoi = getTypologies(rPoi,'stato_segn')
                    else:
                        qPoi = "UPDATE pois SET typology_id={} WHERE id={}".format(TYPOLOGY_MAP['tipo_segna'],rPoi['id'])
                        qTypologiesPoi = getTypologies(rPoi,'tipo_segna')
                cursor.execute(qPoi)
                for qtp in qTypologiesPoi:
                    cursor.execute(qtp)
            print colors.color_text("== COPYING AND INSERTING POI IMAGES DONE! ==", color="green")



        conn.commit()
        conn.close()


    except:
        print "Unexpected error:", sys.exc_info()[0]
        raise
예제 #15
0
파일: shell.py 프로젝트: hydface2/mcloud
def green(text):
    print(color_text(text, color='green'))
예제 #16
0
파일: shell.py 프로젝트: hydface2/mcloud
def yellow(text):
    print(color_text(text, color='blue', bcolor='yellow'))
예제 #17
0
파일: shell.py 프로젝트: hydface2/mcloud
def mcloud_shell(host_ref=None):

    settings = inject.instance('settings')
    interrupt_manager = inject.instance('interrupt_manager')

    readline.parse_and_bind('tab: complete')

    if host_ref:
        app, host = host_ref.split('@')
        state = {
            'app': app,
            'host': host,
        }
    else:
        state = {
            'app': None,
            'host': 'me',
        }

    def use(name, **kwargs):
        if '@' in name:
            app, host = name.split('@')
            if host.strip() == '':
                host = 'me'
            if app.strip() == '':
                app = None

            state['app'] = app
            state['host'] = host
        else:
            state['app'] = name

    cmd = subparsers.add_parser('use')
    cmd.add_argument('name', help='Application name', default=None, nargs='?')
    cmd.set_defaults(func=use)

    from mcloud.logo import logo
    print(logo)

    histfile = os.path.join(os.path.expanduser("~"), ".mcloud_history")
    try:
        readline.read_history_file(histfile)
    except IOError:
        pass

    interrupt_manager.append(ShellCancelInterruptHandler())  # prevent stop reactor on Ctrl + C

    line = ''
    while line != 'exit':

        print('')
        prompt = 'mcloud: %s@%s> ' % (state['app'] or '~', state['host'])

        try:
            line = None

            yield sleep(0.05)

            line = raw_input(color_text(prompt, color='white', bcolor='blue') + ' ').strip()

            if line.startswith('!'):
                os.system(line[1:])
                continue

            if line == '':
                continue

            if line == 'exit':
                break

            readline.write_history_file(histfile)

            params = line.split(' ')
            args = arg_parser.parse_args(params)

            args.argv0 = sys.argv[0]

            if args.host:
                host = args.host
            elif state['host'] == 'me' or not state['host']:
                # manual variable
                if 'MCLOUD_HOST' in os.environ:
                    host = os.environ['MCLOUD_HOST']

                # automatic when using docker container-link
                elif 'MCLOUD_PORT' in os.environ:
                    host = os.environ['MCLOUD_PORT']
                    if host.startswith('tcp://'):
                        host = host[6:]
                else:
                    host = '127.0.0.1'

            else:
                host = state['host']

            if ':' in host:
                host, port = host.split(':')
            else:
                port = 7080

            client = ApiRpcClient(host=host, port=port, settings=settings)
            interrupt_manager.append(ClientProcessInterruptHandler(client))

            for key, val in state.items():
                if not hasattr(args, key) or not getattr(args, key):
                    setattr(args, key, val)

            if isinstance(args.func, str):
                yield getattr(client, args.func)(**vars(args))
            else:
                yield args.func(**vars(args))


        except SystemExit:
            pass

        except EOFError:
            print('')
            break

        except KeyboardInterrupt:
            print('')
            pass

        except Exception as e:
            print '\n  %s\n' % color_text(e.message, color='yellow')

    reactor.callFromThread(reactor.stop)
예제 #18
0
def prompt(question):
    """Prompts user for input."""
    # Python 2to3 compatbility
    response = input(color_text('[?] ', 'yellow') +
                     color_text(question, 'cyan') + ' ')
    return response
예제 #19
0
    def config(self,
               ref,
               diff=False,
               config=None,
               update=False,
               set_env=None,
               **kwargs):
        app, service = self.parse_app_ref(ref, kwargs, app_only=True)

        app_config = yield self._remote_exec('config', app)

        parser_env = set_env or app_config['env']

        if diff or (not update and not set_env):
            old_config = YamlConfig(source=unicode(app_config['source']),
                                    app_name=app,
                                    env=parser_env)
            old_config.load(process=False)
            from collections import OrderedDict

            yaml.add_representer(
                unicode, yaml.representer.SafeRepresenter.represent_unicode)
            yaml.add_representer(OrderedDict, self.represent_ordereddict)
            olds = yaml.dump(old_config.config, default_flow_style=False)

        if not update and not diff and not set_env:
            x = PrettyTable(["Name", "Value"],
                            hrules=ALL,
                            align='l',
                            header=False)
            x.align = "l"
            x.add_row(['Config', olds])
            x.add_row(['Environment', app_config['env']])
            x.add_row(['Path', app_config['path']])
            print(x)

        else:
            if config:
                config_file = os.path.expanduser(config)
            else:
                config_file = 'mcloud.yml'

            new_config = YamlConfig(file=config_file,
                                    app_name=app,
                                    env=parser_env)
            new_config.load(process=False)

            if diff:
                yaml.add_representer(
                    unicode,
                    yaml.representer.SafeRepresenter.represent_unicode)
                yaml.add_representer(OrderedDict, self.represent_ordereddict)
                news = yaml.dump(new_config.config, default_flow_style=False)

                if olds == news:
                    print('Configs are identical.')
                else:

                    for line in unified_diff(olds.splitlines(1),
                                             news.splitlines(1)):
                        if line.endswith('\n'):
                            line = line[0:-1]
                        if line.startswith('+'):
                            print color_text(line, color='green')
                        elif line.startswith('-'):
                            print color_text(line, color='red')
                        else:
                            print line
            else:
                if set_env and not update:
                    yield self._remote_exec('update', app, env=set_env)
                else:
                    yield self._remote_exec('update',
                                            app,
                                            config=new_config.export(),
                                            env=set_env)