parameters: (admin, with_hints=True, verbose=True)
docstring: Handle admin commands.
docstring_summary: Handle admin commands.
docstring_tokens: Handle admin commands .
function: def admin_mode(admin, with_hints=True, verbose=True):
      """Handle admin commands.
      """
      banner = dedent("""\
      ---------------------------------------------------------------
                           WELCOME TO ADMIN MODE
  
                       You will be guided through the
                      possibilities by answering a few
                     questions. This mode will help you
                            configure the file:
                %s
      ---------------------------------------------------------------\
      """ % S_MANAGER.sources_conf_path)
  
      help_ = dedent("""
      Sources status
      (*) status      : display short data source status
      (*) fullstatus  : display full data source configuration
  
      Add/Edit sources definition
      (*) add         : add a new data source
      (*) edit        : edit an existing data source
      (*) zshautocomp : update Zsh autocomplete file
  
      Update data
      (*) update      : download and show updates for sources with master remotes
      (*) forceupdate : download and force update of sources with master remotes
  
      Danger Zone!
      (*) drop        : drop all information for one data source
      (*) restore     : factory reset of all data sources information
      (*) fullrestore : restore, and clean the cache %s
      """ % S_MANAGER.cache_dir)
  
      questions = {
          'command'   : '[ 0 ] Command: ',
          'source'    : '[ 1 ] Source name: ',
          'path'      : '[2/8] Path: ',
          'local'     : '[   ] Is the path local to the installation directory [%s]? ',
          'extract'   : '[   ] Which file in archive? ',
          'copy_1'    : '[   ] Copy %s in %s and use as source path from there [yN]? ',
          'copy_2'    : '[   ] Use %s as source path from %s [yN]? ',
          'delimiter' : '[3/8] Delimiter: ',
          'headers'   : '[4/8] Headers: ',
          'key_fields': '[5/8] Key field(s): ',
          'index'     : '[6/8] Index: ',
          'join'      : '[7/8] Join clause: ',
          'confirm'   : '[8/8] Confirm [Yn]? ',
          'new'       : '[   ] Add new %s [yN]? ',
          'update_zsh': '[   ] Update Zsh autocomplete [yN]? ',
      }
  
      hints = {
          'source'    : dedent("""
                        HINT * Enter a new name to define a new source.
                        """),
          'paths'     : dedent("""
                        HINT * Paths can be urls or normal file paths.
                             * zip archives are supported.
                             * For remote files and archives, temporary
                             * files will be put in the cache directory:
                             * %s
                             * These files may be used as data sources paths.
                             * Add several paths to have a failover mechanism.
                             * Leave empty to delete path.
                        """ % S_MANAGER.cache_dir),
          'delimiter' : dedent("""
                        HINT * The delimiter is the character delimiting fields.
                             * Leave empty to split every character.
                        """),
          'headers'   : dedent("""
                        HINT * Headers are column names, separated with "%s".
                             * lat and lng will be guessed for new sources.
                        """ % SPLIT),
          'key_fields': dedent("""
                        HINT * Key fields are fields used to generate keys,
                             * use "%s" if several fields.
                             * Leave empty to use line numbers as keys.
                        """ % SPLIT),
          'indices'   : dedent("""
                        HINT * Indices are a list of index to speed up some queries.
                             * For multiple fields index, separate with "%s".
                             * Leave empty to delete index.
                        """ % SPLIT),
          'join'      : dedent("""
                        HINT * Join clauses are useful to say that a key can be found
                             * in another data source. Use the "field{base:external_field}"
                             * syntax to define one.
                             * Leave empty to delete join clause.
                        """),
      }
  
      # Was banner displayed
      bannered = False
  
      if len(admin) < 1:
          print banner
          bannered = True
          print help_
          command = ask_till_ok(questions['command'], ALLOWED_COMMANDS, show=False)
      else:
          command = admin[0]
  
      if command not in ALLOWED_COMMANDS:
          error('wrong_value', command, ALLOWED_COMMANDS)
  
      # These ones do not need the second argument source_name
      if command == 'restore':
          S_MANAGER.restore(clean_cache=False)
          S_MANAGER.update_autocomplete(verbose=False)
          return
  
      if command == 'fullrestore':
          S_MANAGER.restore(clean_cache=True)
          S_MANAGER.update_autocomplete(verbose=False)
          return
  
      if command == 'update':
          S_MANAGER.check_data_updates()
          return
  
      if command == 'forceupdate':
          S_MANAGER.check_data_updates(force=True)
          return
  
      if command == 'zshautocomp':
          status = S_MANAGER.update_autocomplete(verbose=True)
          if status:
              print '\n===== Restart shell now.'
          return
  
      if len(admin) < 2:
          if not bannered:
              print banner
              bannered = True
          if command in ['status', 'fullstatus']:
              two_col_print(sorted(S_MANAGER) + ['*'])
              source_name = ask_till_ok(questions['source'], sorted(S_MANAGER) + ['*', ''], show=False)
  
          elif command in ['drop']:
              two_col_print(sorted(S_MANAGER))
              source_name = ask_till_ok(questions['source'], sorted(S_MANAGER), show=False)
  
          elif command in ['edit']:
              if with_hints:
                  print hints['source'],
              two_col_print(sorted(S_MANAGER))
              source_name = ask_till_ok(questions['source'],
                                        is_ok = lambda r: r,
                                        fail_message='-/!\- Cannot be empty')
          else:
              # add
              if with_hints:
                  print hints['source']
              source_name = ask_till_ok(questions['source'],
                                        is_ok = lambda r: r,
                                        fail_message='-/!\- Cannot be empty')
      else:
          source_name = admin[1]
  
      # None is not allowed for drop and edit
      if source_name in ('', '*'):
          source_name = None
  
      if command == 'status':
          print S_MANAGER.build_status(source_name)
          return
  
      if command == 'fullstatus':
          S_MANAGER.full_status(source_name)
          return
  
      # Source name cannot be None past that point
      if source_name is None:
          error('not_allowed', None)
  
      if command == 'drop':
          S_MANAGER.drop(source_name)
          S_MANAGER.save()
          return
  
      if command in ('add', 'edit'):
          if source_name not in S_MANAGER:
              S_MANAGER.add(source_name)
              if command == 'edit':
                  print '----- New source "%s" created! Switching to "add" mode.' % source_name
                  command = 'add'
          else:
              if command == 'add':
                  print '----- Source "%s" exists! Switch to "edit" mode.' % source_name
                  command = 'edit'
  
          # We get existing conf
          conf = S_MANAGER.get(source_name)
          if conf is None:
              conf = {}
  
          def_paths      = conf.get('paths',      DEFAULTS['paths'])
          def_delimiter  = conf.get('delimiter',  DEFAULTS['delimiter'])
          def_headers    = conf.get('headers',    DEFAULTS['headers'])
          def_key_fields = conf.get('key_fields', DEFAULTS['key_fields'])
          def_indices    = conf.get('indices',    DEFAULTS['indices'])
          def_join       = conf.get('join',       DEFAULTS['join'])
  
          get_empty_path  = lambda : { 'file': '', 'local': False }
          get_empty_index = lambda : ''
          get_empty_join  = lambda : { 'fields' : [], 'with' : [''] }
  
          if not def_paths:
              if command == 'add':
                  def_paths = [get_empty_path()]
              else:
                  def_paths = []
          else:
              def_paths = S_MANAGER.convert_paths_format(def_paths)
  
          if not def_indices:
              if command == 'add':
                  def_indices = []
                  #def_indices = [get_empty_index()]
              else:
                  def_indices = []
  
          if not def_join:
              if command == 'add':
                  def_join = []
                  #def_join = [get_empty_join()]
              else:
                  def_join = []
  
          # We will add non empty values here
          new_conf = {
              'paths'   : [],
              'indices' : [],
              'join'    : [],
          }
  
          # Fake first line for sources without paths
          first_l = ''
  
          # 1. Paths
          if with_hints:
              print hints['paths']
          i = 0
          while True:
              if i < len(def_paths):
                  ref_path = def_paths[i]
                  i += 1
              else:
                  # We add a new empty path if the user wants to add another one
                  add_another = ask_till_ok(questions['new'] % 'path', boolean=True)
  
                  if add_another:
                      ref_path = get_empty_path()
                  else:
                      break
  
              path, filename = admin_path(ref_path, source_name, questions, verbose)
  
              if path is None:
                  continue
  
              new_conf['paths'].append(path)
  
              try:
                  with open(filename) as fl:
                      first_l = fl.next().rstrip()
              except IOError:
                  print
                  print '!!!!! Could not open "%s". Check the path.' % filename
                  return
  
              # No need to download and check the first lines for known files
              if to_CLI('path', ref_path) != to_CLI('path', path):
                  print
                  print '>>>> first line >>>>'
                  print first_l
                  print '<<<<<<<<<<<<<<<<<<<<'
  
                  def_delimiter  = guess_delimiter(first_l)
                  def_headers    = guess_headers(first_l, def_delimiter)
                  def_key_fields = guess_key_fields(first_l, def_delimiter, def_headers)
  
  
          # 2. Delimiter
          if with_hints:
              print hints['delimiter']
          delimiter = ask_input(questions['delimiter'], to_CLI('delimiter', def_delimiter))
          new_conf['delimiter'] = delimiter
  
          if to_CLI('delimiter', def_delimiter) != to_CLI('delimiter', delimiter):
              def_headers    = guess_headers(first_l, delimiter)
              def_key_fields = guess_key_fields(first_l, delimiter, def_headers)
  
  
          # 3. Headers
          if with_hints:
              print hints['headers']
          headers = ask_input(questions['headers'], to_CLI('headers', def_headers)).strip()
          if not headers:
              headers = []
          else:
              headers = headers.split(SPLIT)
  
          join, subdelimiters = clean_headers(headers)
          new_conf['headers'] = headers
  
          if join:
              new_conf['join'] = join
              print '----- Detected join %s' % str(join)
  
          if subdelimiters:
              new_conf['subdelimiters'] = subdelimiters
              print '----- Detected subdelimiters %s' % str(subdelimiters)
  
          if to_CLI('headers', def_headers) != to_CLI('headers', headers):
              def_key_fields = guess_key_fields(first_l, delimiter, headers)
  
  
          # 4. Key fields
          if with_hints:
              print hints['key_fields']
          key_fields = ask_input(questions['key_fields'], to_CLI('key_fields', def_key_fields)).strip()
          key_fields = split_if_several(key_fields)
  
          if not key_fields:
              new_conf['key_fields'] = None
          else:
              new_conf['key_fields'] = key_fields
  
  
          # 5. Indices
          if with_hints:
              print hints['indices']
          i = 0
          while True:
              if i < len(def_indices):
                  ref_index = def_indices[i]
                  i += 1
              else:
                  # We add a new empty path if the user wants to add another one
                  add_another = ask_till_ok(questions['new'] % 'index', boolean=True)
  
                  if add_another:
                      ref_index = get_empty_index()
                  else:
                      break
  
              index = ask_input(questions['index'], to_CLI('index', ref_index)).strip()
              if not index:
                  print '----- Empty index, deleted'
              else:
                  index = split_if_several(index)
                  new_conf['indices'].append(index)
  
  
          # 6. Join
          if with_hints:
              print hints['join']
          i = 0
          while True:
              if i < len(def_join):
                  ref_join = def_join[i]
                  i += 1
              else:
                  # We add a new empty path if the user wants to add another one
                  add_another = ask_till_ok(questions['new'] % 'join', boolean=True)
  
                  if add_another:
                      ref_join = get_empty_join()
                  else:
                      break
  
              m_join = ask_input(questions['join'], to_CLI('join', ref_join)).strip()
              m_join = clean_headers(m_join.split(SPLIT))[0]
  
              if not m_join:
                  print '----- Empty join, deleted'
              else:
                  m_join[0]['fields'] = split_if_several(m_join[0]['fields'])
  
                  if len(m_join[0]['with']) > 1:
                      m_join[0]['with'][1] = split_if_several(m_join[0]['with'][1])
  
                  new_conf['join'].extend(m_join)
  
          # Removing non-changes
          old_conf = {}
          for option, config in new_conf.items():
              if option in conf:
                  if config == conf[option]:
                      del new_conf[option]
                  else:
                      old_conf[option] = conf[option]
  
          if not new_conf:
              print '\n===== No changes'
              return
  
          print
          print '--- [before]'
          print S_MANAGER.convert({ source_name : old_conf })
  
          print '+++ [after]'
          print S_MANAGER.convert({ source_name : new_conf })
  
          confirm = ask_till_ok(questions['confirm'], boolean=True, default=True)
  
          if not confirm:
              print '\n===== Aborted'
              return
  
          S_MANAGER.update(source_name, new_conf)
          S_MANAGER.save()
          print '\n===== Changes saved to %s' % S_MANAGER.sources_conf_path
  
          update_zsh = ask_till_ok(questions['update_zsh'], boolean=True, default=False)
          if update_zsh:
              status = S_MANAGER.update_autocomplete(verbose=True)
              if status:
                  print '\n===== Restart shell now.'
function_tokens: def admin_mode ( admin , with_hints = True , verbose = True ) : banner = dedent ( """\
      ---------------------------------------------------------------
                           WELCOME TO ADMIN MODE
  
                       You will be guided through the
                      possibilities by answering a few
                     questions. This mode will help you
                            configure the file:
                %s
      ---------------------------------------------------------------\
      """ % S_MANAGER . sources_conf_path ) help_ = dedent ( """
      Sources status
      (*) status      : display short data source status
      (*) fullstatus  : display full data source configuration
  
      Add/Edit sources definition
      (*) add         : add a new data source
      (*) edit        : edit an existing data source
      (*) zshautocomp : update Zsh autocomplete file
  
      Update data
      (*) update      : download and show updates for sources with master remotes
      (*) forceupdate : download and force update of sources with master remotes
  
      Danger Zone!
      (*) drop        : drop all information for one data source
      (*) restore     : factory reset of all data sources information
      (*) fullrestore : restore, and clean the cache %s
      """ % S_MANAGER . cache_dir ) questions = { 'command' : '[ 0 ] Command: ' , 'source' : '[ 1 ] Source name: ' , 'path' : '[2/8] Path: ' , 'local' : '[   ] Is the path local to the installation directory [%s]? ' , 'extract' : '[   ] Which file in archive? ' , 'copy_1' : '[   ] Copy %s in %s and use as source path from there [yN]? ' , 'copy_2' : '[   ] Use %s as source path from %s [yN]? ' , 'delimiter' : '[3/8] Delimiter: ' , 'headers' : '[4/8] Headers: ' , 'key_fields' : '[5/8] Key field(s): ' , 'index' : '[6/8] Index: ' , 'join' : '[7/8] Join clause: ' , 'confirm' : '[8/8] Confirm [Yn]? ' , 'new' : '[   ] Add new %s [yN]? ' , 'update_zsh' : '[   ] Update Zsh autocomplete [yN]? ' , } hints = { 'source' : dedent ( """
                        HINT * Enter a new name to define a new source.
                        """ ) , 'paths' : dedent ( """
                        HINT * Paths can be urls or normal file paths.
                             * zip archives are supported.
                             * For remote files and archives, temporary
                             * files will be put in the cache directory:
                             * %s
                             * These files may be used as data sources paths.
                             * Add several paths to have a failover mechanism.
                             * Leave empty to delete path.
                        """ % S_MANAGER . cache_dir ) , 'delimiter' : dedent ( """
                        HINT * The delimiter is the character delimiting fields.
                             * Leave empty to split every character.
                        """ ) , 'headers' : dedent ( """
                        HINT * Headers are column names, separated with "%s".
                             * lat and lng will be guessed for new sources.
                        """ % SPLIT ) , 'key_fields' : dedent ( """
                        HINT * Key fields are fields used to generate keys,
                             * use "%s" if several fields.
                             * Leave empty to use line numbers as keys.
                        """ % SPLIT ) , 'indices' : dedent ( """
                        HINT * Indices are a list of index to speed up some queries.
                             * For multiple fields index, separate with "%s".
                             * Leave empty to delete index.
                        """ % SPLIT ) , 'join' : dedent ( """
                        HINT * Join clauses are useful to say that a key can be found
                             * in another data source. Use the "field{base:external_field}"
                             * syntax to define one.
                             * Leave empty to delete join clause.
                        """ ) , } # Was banner displayed bannered = False if len ( admin ) < 1 : print banner bannered = True print help_ command = ask_till_ok ( questions [ 'command' ] , ALLOWED_COMMANDS , show = False ) else : command = admin [ 0 ] if command not in ALLOWED_COMMANDS : error ( 'wrong_value' , command , ALLOWED_COMMANDS ) # These ones do not need the second argument source_name if command == 'restore' : S_MANAGER . restore ( clean_cache = False ) S_MANAGER . update_autocomplete ( verbose = False ) return if command == 'fullrestore' : S_MANAGER . restore ( clean_cache = True ) S_MANAGER . update_autocomplete ( verbose = False ) return if command == 'update' : S_MANAGER . check_data_updates ( ) return if command == 'forceupdate' : S_MANAGER . check_data_updates ( force = True ) return if command == 'zshautocomp' : status = S_MANAGER . update_autocomplete ( verbose = True ) if status : print '\n===== Restart shell now.' return if len ( admin ) < 2 : if not bannered : print banner bannered = True if command in [ 'status' , 'fullstatus' ] : two_col_print ( sorted ( S_MANAGER ) + [ '*' ] ) source_name = ask_till_ok ( questions [ 'source' ] , sorted ( S_MANAGER ) + [ '*' , '' ] , show = False ) elif command in [ 'drop' ] : two_col_print ( sorted ( S_MANAGER ) ) source_name = ask_till_ok ( questions [ 'source' ] , sorted ( S_MANAGER ) , show = False ) elif command in [ 'edit' ] : if with_hints : print hints [ 'source' ] , two_col_print ( sorted ( S_MANAGER ) ) source_name = ask_till_ok ( questions [ 'source' ] , is_ok = lambda r : r , fail_message = '-/!\- Cannot be empty' ) else : # add if with_hints : print hints [ 'source' ] source_name = ask_till_ok ( questions [ 'source' ] , is_ok = lambda r : r , fail_message = '-/!\- Cannot be empty' ) else : source_name = admin [ 1 ] # None is not allowed for drop and edit if source_name in ( '' , '*' ) : source_name = None if command == 'status' : print S_MANAGER . build_status ( source_name ) return if command == 'fullstatus' : S_MANAGER . full_status ( source_name ) return # Source name cannot be None past that point if source_name is None : error ( 'not_allowed' , None ) if command == 'drop' : S_MANAGER . drop ( source_name ) S_MANAGER . save ( ) return if command in ( 'add' , 'edit' ) : if source_name not in S_MANAGER : S_MANAGER . add ( source_name ) if command == 'edit' : print '----- New source "%s" created! Switching to "add" mode.' % source_name command = 'add' else : if command == 'add' : print '----- Source "%s" exists! Switch to "edit" mode.' % source_name command = 'edit' # We get existing conf conf = S_MANAGER . get ( source_name ) if conf is None : conf = { } def_paths = conf . get ( 'paths' , DEFAULTS [ 'paths' ] ) def_delimiter = conf . get ( 'delimiter' , DEFAULTS [ 'delimiter' ] ) def_headers = conf . get ( 'headers' , DEFAULTS [ 'headers' ] ) def_key_fields = conf . get ( 'key_fields' , DEFAULTS [ 'key_fields' ] ) def_indices = conf . get ( 'indices' , DEFAULTS [ 'indices' ] ) def_join = conf . get ( 'join' , DEFAULTS [ 'join' ] ) get_empty_path = lambda : { 'file' : '' , 'local' : False } get_empty_index = lambda : '' get_empty_join = lambda : { 'fields' : [ ] , 'with' : [ '' ] } if not def_paths : if command == 'add' : def_paths = [ get_empty_path ( ) ] else : def_paths = [ ] else : def_paths = S_MANAGER . convert_paths_format ( def_paths ) if not def_indices : if command == 'add' : def_indices = [ ] #def_indices = [get_empty_index()] else : def_indices = [ ] if not def_join : if command == 'add' : def_join = [ ] #def_join = [get_empty_join()] else : def_join = [ ] # We will add non empty values here new_conf = { 'paths' : [ ] , 'indices' : [ ] , 'join' : [ ] , } # Fake first line for sources without paths first_l = '' # 1. Paths if with_hints : print hints [ 'paths' ] i = 0 while True : if i < len ( def_paths ) : ref_path = def_paths [ i ] i += 1 else : # We add a new empty path if the user wants to add another one add_another = ask_till_ok ( questions [ 'new' ] % 'path' , boolean = True ) if add_another : ref_path = get_empty_path ( ) else : break path , filename = admin_path ( ref_path , source_name , questions , verbose ) if path is None : continue new_conf [ 'paths' ] . append ( path ) try : with open ( filename ) as fl : first_l = fl . next ( ) . rstrip ( ) except IOError : print print '!!!!! Could not open "%s". Check the path.' % filename return # No need to download and check the first lines for known files if to_CLI ( 'path' , ref_path ) != to_CLI ( 'path' , path ) : print print '>>>> first line >>>>' print first_l print '<<<<<<<<<<<<<<<<<<<<' def_delimiter = guess_delimiter ( first_l ) def_headers = guess_headers ( first_l , def_delimiter ) def_key_fields = guess_key_fields ( first_l , def_delimiter , def_headers ) # 2. Delimiter if with_hints : print hints [ 'delimiter' ] delimiter = ask_input ( questions [ 'delimiter' ] , to_CLI ( 'delimiter' , def_delimiter ) ) new_conf [ 'delimiter' ] = delimiter if to_CLI ( 'delimiter' , def_delimiter ) != to_CLI ( 'delimiter' , delimiter ) : def_headers = guess_headers ( first_l , delimiter ) def_key_fields = guess_key_fields ( first_l , delimiter , def_headers ) # 3. Headers if with_hints : print hints [ 'headers' ] headers = ask_input ( questions [ 'headers' ] , to_CLI ( 'headers' , def_headers ) ) . strip ( ) if not headers : headers = [ ] else : headers = headers . split ( SPLIT ) join , subdelimiters = clean_headers ( headers ) new_conf [ 'headers' ] = headers if join : new_conf [ 'join' ] = join print '----- Detected join %s' % str ( join ) if subdelimiters : new_conf [ 'subdelimiters' ] = subdelimiters print '----- Detected subdelimiters %s' % str ( subdelimiters ) if to_CLI ( 'headers' , def_headers ) != to_CLI ( 'headers' , headers ) : def_key_fields = guess_key_fields ( first_l , delimiter , headers ) # 4. Key fields if with_hints : print hints [ 'key_fields' ] key_fields = ask_input ( questions [ 'key_fields' ] , to_CLI ( 'key_fields' , def_key_fields ) ) . strip ( ) key_fields = split_if_several ( key_fields ) if not key_fields : new_conf [ 'key_fields' ] = None else : new_conf [ 'key_fields' ] = key_fields # 5. Indices if with_hints : print hints [ 'indices' ] i = 0 while True : if i < len ( def_indices ) : ref_index = def_indices [ i ] i += 1 else : # We add a new empty path if the user wants to add another one add_another = ask_till_ok ( questions [ 'new' ] % 'index' , boolean = True ) if add_another : ref_index = get_empty_index ( ) else : break index = ask_input ( questions [ 'index' ] , to_CLI ( 'index' , ref_index ) ) . strip ( ) if not index : print '----- Empty index, deleted' else : index = split_if_several ( index ) new_conf [ 'indices' ] . append ( index ) # 6. Join if with_hints : print hints [ 'join' ] i = 0 while True : if i < len ( def_join ) : ref_join = def_join [ i ] i += 1 else : # We add a new empty path if the user wants to add another one add_another = ask_till_ok ( questions [ 'new' ] % 'join' , boolean = True ) if add_another : ref_join = get_empty_join ( ) else : break m_join = ask_input ( questions [ 'join' ] , to_CLI ( 'join' , ref_join ) ) . strip ( ) m_join = clean_headers ( m_join . split ( SPLIT ) ) [ 0 ] if not m_join : print '----- Empty join, deleted' else : m_join [ 0 ] [ 'fields' ] = split_if_several ( m_join [ 0 ] [ 'fields' ] ) if len ( m_join [ 0 ] [ 'with' ] ) > 1 : m_join [ 0 ] [ 'with' ] [ 1 ] = split_if_several ( m_join [ 0 ] [ 'with' ] [ 1 ] ) new_conf [ 'join' ] . extend ( m_join ) # Removing non-changes old_conf = { } for option , config in new_conf . items ( ) : if option in conf : if config == conf [ option ] : del new_conf [ option ] else : old_conf [ option ] = conf [ option ] if not new_conf : print '\n===== No changes' return print print '--- [before]' print S_MANAGER . convert ( { source_name : old_conf } ) print '+++ [after]' print S_MANAGER . convert ( { source_name : new_conf } ) confirm = ask_till_ok ( questions [ 'confirm' ] , boolean = True , default = True ) if not confirm : print '\n===== Aborted' return S_MANAGER . update ( source_name , new_conf ) S_MANAGER . save ( ) print '\n===== Changes saved to %s' % S_MANAGER . sources_conf_path update_zsh = ask_till_ok ( questions [ 'update_zsh' ] , boolean = True , default = False ) if update_zsh : status = S_MANAGER . update_autocomplete ( verbose = True ) if status : print '\n===== Restart shell now.'