Source code for grasp.config

"""
Manage a persistent configuration for the database.
"""
import os
import configparser
import readline

CONFIG_FILE = os.path.expanduser("~/.grasp")
"""The PATH to the config file."""

config = configparser.ConfigParser()
"""A globally accessible ConfigParger object, initialized with CONFIG_FILE."""

config.read(CONFIG_FILE)

__all__ = ['config', 'CONFIG_FILE', 'init_config', 'init_config_interactive',
           'write_config']


###############################################################################
#                        Config Manipulation Functions                        #
###############################################################################


[docs]def init_config_interactive(): """Interact with the user to create a new config. Uses readline autocompletion to make setup easier. """ # Use tab completion t = tabCompleter() readline.set_completer_delims('\t') readline.parse_and_bind("tab: complete") # Get permission t.createListCompleter(['y', 'n']) readline.set_completer(t.listCompleter) print("Do you want to initialize your config at {}" .format(CONFIG_FILE)) print("This will erase your current configuration (if it exists)") choice = input("Initialize config? [y/N] ").strip().lower() if not choice == 'y': return # Get choices with tab completion t.createListCompleter(["sqlite", "mysql", "postgresql"]) readline.set_completer(t.listCompleter) print("What kind of database do you want to use?") db_type = input('sqlite/postgres/mysql ').strip().lower() setup_other = False file_path, host, user, passwd, host_string = ('',)*5 # Initialize for sqlite if db_type.lower() == 'sqlite': readline.set_completer(t.pathCompleter) print("Where would you like to put the db file?") file_path = os.path.expanduser(input('PATH: [~/grasp.db] ')).strip(' ').lower() if not file_path: file_path = os.path.expanduser('~/grasp.db') setup_other = True if input("Also setup postgres/mysql auth? [y/N] ") \ == 'y' else False # Initialize for other elif db_type.lower() == 'postgresql' or db_type.lower() == 'mysql': setup_other = True else: print("Invalid db choice {}".format(db_type)) return 1 if setup_other: readline.set_completer() print("Your database needs to already be configured for " "it to work. i.e. the user, password, and database need " "to already exist. Please enter the required info below.") host = input('hostname [localhost]: ') host = host if host else 'localhost' user = input('username: ') passwd = input('password: ') init_config(db_type, file_path, host, user, passwd)
[docs]def init_config(db_type, db_file='', db_host='', db_user='', db_pass=''): """Create an initial config file. Args: db_type: 'sqlite/mysql/postgresql' db_file: PATH to sqlite database file db_host: Hostname for mysql or postgresql server db_user: Username for mysql or postgresql server db_pass: Password for mysql or postgresql server (not secure) Returns: None: NoneType """ if os.path.exists(CONFIG_FILE): os.remove(CONFIG_FILE) config['DEFAULT'] = {'DatabaseType': db_type} config['sqlite'] = {'DatabaseFile': db_file} config['other'] = {'DatabaseHost': db_host, 'DatabaseUser': db_user, 'DatabasePass': db_pass} write_config() # Make config only accessible to user os.chmod(CONFIG_FILE, 0o600)
[docs]def write_config(): """Write the current config to CONFIG_FILE.""" with open(CONFIG_FILE, 'w') as fout: config.write(fout)
############################################################################### # Completion # ############################################################################### class tabCompleter(object): """ A tab completer that can either complete from the filesystem or from a list. Taken from: `https://gist.github.com/iamatypeofwalrus/5637895`_ """ def _listdir(self, root): "List directory 'root' appending the path separator to subdirs." res = [] for name in os.listdir(root): path = os.path.join(root, name) if os.path.isdir(path): name += os.sep res.append(name) return res def _complete_path(self, path=None): "Perform completion of filesystem path." if not path: return os.listdir('.') path = os.path.expanduser(path) dirname, rest = os.path.split(path) tmp = dirname if dirname else '.' res = [os.path.join(dirname, p) for p in os.listdir(tmp) if p.startswith(rest)] # more than one match, or single match which does not exist (typo) if len(res) > 1 or not os.path.exists(path): return res # resolved to a single directory, so return list of files below it if os.path.isdir(path): return [os.path.join(path, p) for p in os.listdir(path)] # exact file match terminates this completion return [path + ' '] def pathCompleter(self, test, state): """ This is the tab completer for systems paths. Only tested on *nix systems """ line = readline.get_line_buffer() if not line: return self._complete_path('.')[state] else: return self._complete_path(line)[state] def createListCompleter(self,ll): """ This is a closure that creates a method that autocompletes from the given list. Since the autocomplete function can't be given a list to complete from a closure is used to create the listCompleter function with a list to complete from. """ def listCompleter(text,state): line = readline.get_line_buffer() if not line: return [c + " " for c in ll][state] else: return [c + " " for c in ll if c.startswith(line)][state] self.listCompleter = listCompleter