From 5c07196044bde620424534bd21710352a741954a Mon Sep 17 00:00:00 2001 From: nickpandolfi Date: Fri, 30 Dec 2016 02:01:27 -0500 Subject: [PATCH] Config development and cleaning --- TODO.txt | 1 + cyther/configuration.py | 117 ++++++++++++++++++++++++++++++++++------ cyther/definitions.py | 12 +++++ cyther/project.py | 5 +- cyther/tools.py | 11 +++- 5 files changed, 125 insertions(+), 21 deletions(-) diff --git a/TODO.txt b/TODO.txt index f1fd936..fd7edc0 100644 --- a/TODO.txt +++ b/TODO.txt @@ -60,6 +60,7 @@ FUTURE UPDATES Get cyther to modify distutils imported at runtime to compile everything instead of distutils Make 'path(root='.')' work + Q) Can I use the Python source code from PSF to literally figure out where the include/runtime dirs were installed? Q) Even bother getting Cyther to work with python 2 or pypy(3)? Q) Whats up with pypi version badge doing '?.?.?' Q) Can ar recompile static libraries? (http://www.linux.org/threads/gnu-binutils.6544/) diff --git a/cyther/configuration.py b/cyther/configuration.py index e970ba4..1b71bba 100644 --- a/cyther/configuration.py +++ b/cyther/configuration.py @@ -7,15 +7,41 @@ import os from .files import path, USER +from .searcher import find from .tools import read_dict_from_file, write_dict_to_file, get_input +from .definitions import CONFIG_FILE_NAME, VER, DOT_VER + + +class IncludeDirectoryError(Exception): + """A custom error used to denote an error with your include directories""" + none = "No include directory found for this version of python" + no_default = "There appears to be no default include directory; Cyther " \ + "was not able to find a suitable directory to default to" + + def __init__(self, *args, **kwargs): + super(IncludeDirectoryError, self).__init__(*args, **kwargs) -CONFIG_FILE_NAME = '.cyther' INCLUDE_DIRS_KEY = 'include_search_directory' RUNTIME_DIRS_KEY = 'runtime_search_directory' RUNTIME_KEY = 'runtime_libraries' +def purge_configs(): + """ + These will delete any configs found in either the current directory or the + user's home directory + """ + user_config = path(CONFIG_FILE_NAME, root=USER) + inplace_config = path(CONFIG_FILE_NAME) + + if os.path.isfile(user_config): + os.remove(user_config) + + if os.path.isfile(inplace_config): + os.remove(inplace_config) + + def write_config_file(file_path, data): """ Writes a config data structure (dict for now) to the file path specified @@ -84,11 +110,7 @@ def get_config(): NO_CONFIGS_EXIST = "No configs were found, it's safe " \ "to make the config file anywhere\n" -COMPLEX_PROMPT = "Where do you want to make the config file? " \ - "[user/inplace/default/''=exit]: " - -COMPLEX_REDO_PROMPT = "Incorrect response, must be 'user', 'inplace', " \ - "'default', or '' (empty) to exit: " +COMPLEX_PROMPT = "Where do you want to make the config file?" def _complex_decision(*, guided): @@ -122,9 +144,7 @@ def _complex_decision(*, guided): print(NO_CONFIGS_EXIST) # Get the user's response to said situation ^ - response = get_input(COMPLEX_PROMPT, - ('user', 'inplace', 'default', ''), - redo_prompt=COMPLEX_REDO_PROMPT) + response = get_input(COMPLEX_PROMPT,('user', 'inplace', 'default', '')) # Decide what to do based on the user's error checked response if response == 'user': @@ -139,19 +159,17 @@ def _complex_decision(*, guided): else: result = default - return result + return result, code -SIMPLE_PROMPT = "Do you want to overwrite '{}'? [y/n]: " -SIMPLE_REDO_PROMPT = "Incorrect response, must be 'y' or 'n': " +SIMPLE_PROMPT = "Do you want to overwrite '{}'?" def _simple_decision(directory, *, guided): config_name = path(CONFIG_FILE_NAME, root=directory) if os.path.isfile(config_name): if guided: - response = get_input(SIMPLE_PROMPT.format(config_name), ('y', 'n'), - redo_prompt=SIMPLE_REDO_PROMPT) + response = get_input(SIMPLE_PROMPT.format(config_name), ('y', 'n')) if response == 'n': exit() return config_name @@ -164,19 +182,86 @@ def _make_config_location(*, guided): if path() == path(USER): result = _simple_decision(current, guided=guided) else: - result = _complex_decision(guided=guided) + result, code = _complex_decision(guided=guided) else: result = _simple_decision(current, guided=guided) return result +INCLUDE_PROMPT = "Choose the number of one of the listed include directories" \ + " above, or enter 'default' to do what Cyther thinks is best" + + +# TODO Implement support if there was only one include dir found by 'find' +def _make_include_dirs(*, guided): + include_dirs = find(['include', 'Python.h'], content="Py_PYTHON_H") + + include = None + for include_path in include_dirs: + # TODO This is your current condition... This may not be accurate + if VER in include_path or DOT_VER in include_path: + if not include: + include = os.path.dirname(include_path) + else: + if not guided: + raise Exception() + + if guided: + checker = [] + for offset, include_path in enumerate(include_dirs): + number = offset + 1 + print("{}): '{}'\n".format(number, include_path)) + checker.append(number) + + response = get_input(INCLUDE_PROMPT, tuple(checker) + ('default', '')) + if not response: + exit() + return + elif response == 'default': + if not include: + raise IncludeDirectoryError(IncludeDirectoryError.no_default) + else: + offset = int(response) - 1 + include = include_dirs[offset] + else: + if not include: + raise IncludeDirectoryError(IncludeDirectoryError.none) + + return include + + +def _make_runtime_dirs(*, guided): + return [] + + +def _make_runtime(*, guided): + return '' + + +def make_config_data(*, guided): + """ + Makes the data necessary to construct a functional config file + """ + config_data = {} + config_data[INCLUDE_DIRS_KEY] = _make_include_dirs(guided=guided) + config_data[RUNTIME_DIRS_KEY] = _make_runtime_dirs(guided=guided) + config_data[RUNTIME_KEY] = _make_runtime(guided=guided) + + return config_data + + def make_config(guided=False): """ Options: --auto, --guided, --manual Places for the file: --inplace, --user """ - return _make_config_location(guided=guided) + config_path = _make_config_location(guided=guided) + + config_data = make_config_data(guided=guided) + + write_config_file(config_path, config_data) + #return config_path def generate_configurations(): diff --git a/cyther/definitions.py b/cyther/definitions.py index 9e2e1e3..5dc3479 100644 --- a/cyther/definitions.py +++ b/cyther/definitions.py @@ -1,4 +1,16 @@ +import sys + +CACHE_NAME = "__cythercache__" +CONFIG_FILE_NAME = '.cyther' + +MAJOR = str(sys.version_info.major) +MINOR = str(sys.version_info.minor) +VER = MAJOR + MINOR +DOT_VER = MAJOR + '.' + MINOR + +############################################################################### + FINE = 0 ERROR_PASSOFF = 1 SKIPPED_COMPILATION = 1337 diff --git a/cyther/project.py b/cyther/project.py index 5cdfb89..5a5181b 100644 --- a/cyther/project.py +++ b/cyther/project.py @@ -7,8 +7,7 @@ from .tools import get_input from .files import path, ISDIR - -CACHE_NAME = "__cythercache__" +from .definitions import CACHE_NAME def assure_cache(project_path=None): @@ -54,7 +53,7 @@ def purge_project(): print("\tNothing was found in the cache") check_response = get_input("Delete all these files? (^)" - "[y/n]: ", ('y', 'n')) + "[y/n]: ", ('y', 'n')) if check_response == 'y': for filepath in to_delete: os.remove(filepath) diff --git a/cyther/tools.py b/cyther/tools.py index 8bb1236..c4b6127 100644 --- a/cyther/tools.py +++ b/cyther/tools.py @@ -38,8 +38,7 @@ def read_dict_from_file(file_path): RESPONSES_ERROR = "Argument 'acceptableResponses' cannot be of type: '{}'" -# TODO Make get_input take the 'check' parameter and inject it into the prompt -def get_input(prompt, check, *, redo_prompt=None): +def get_input(prompt, check, *, redo_prompt=None, repeat_prompt=False): """ Ask the user to input something on the terminal level, check their response and ask again if they didn't answer correctly @@ -47,6 +46,14 @@ def get_input(prompt, check, *, redo_prompt=None): if isinstance(check, str): check = (check,) + prompt += " [{}]: ".format('/'.join(check)) + + if repeat_prompt: + redo_prompt = prompt + elif not redo_prompt: + redo_prompt = "Incorrect input, please choose from {}: " \ + "".format(str(check)) + if callable(check): def checker(r): return check(r) elif isinstance(check, tuple):