def clean_exit(self): """Function that exits the CUI cleanly """ LOGGER.write('Exiting pyautogit.') self.close_cleanup() exit()
def handle_open_external_program_command(command, name): """Function used to run commands that open an external program and detatch from pyautogit. Parameters ---------- command : str Command string to run name : str Name of command to run Returns ------- out : str Output string from stdout if success, stderr if failure err : int Error code if failure, 0 otherwise. """ run_command = command.split(' ') try: LOGGER.write('Opening external program with: {}'.format(str(run_command))) proc = Popen(run_command, stdout=PIPE, stderr=PIPE) out, err_messg = proc.communicate() err = proc.returncode if err != 0: out = err_messg.decode() else: out = out.decode() except FileNotFoundError: out = "Program: {} could not be found in system path".format(command.split(' ')[0]) err = -1 except: out = "Unknown error processing function: {}".format(name) err = -1 return out, err
def error_exit(self): """Function that exits the CUI with an error code """ LOGGER.write('Exiting with error!') self.close_cleanup() exit(-1)
def show_menu(self): """Opens the menu using the menu item list for screen manager instance """ LOGGER.write('Opening {} screen menu'.format(self.screen_type)) self.manager.root.show_menu_popup('Full Control Menu', self.menu_choices, self.process_menu_selection)
def open_autogit_window_target(self): """Function that opens a repo control window given a target location """ LOGGER.write('Opening autogit control window on target dir.') self.repo_select_manager.clear_elements() self.repo_control_manager.set_initial_values() self.root.apply_widget_set(self.repo_control_widget_set) self.repo_control_manager.refresh_status()
def open_editor_window(self): """Function that opens an editor window """ LOGGER.write('Opening Editor Window') self.editor_manager.open_new_directory_external(os.getcwd()) self.editor_manager.set_initial_values() self.root.apply_widget_set(self.editor_widget_set) self.current_state == 'editor' self.editor_manager.refresh_status() self.root.move_focus(self.editor_manager.file_menu)
def open_settings_window(self): """Function for opening the settings window """ LOGGER.write('Opening settings window') self.repo_select_manager.clear_elements() self.settings_manager.set_initial_values() self.root.apply_widget_set(self.settings_widget_set) self.root.set_title('pyautogit v{} Settings'.format(__version__)) self.current_state = 'settings' self.settings_manager.refresh_status()
def clone_new_repo(self): """Function that clones new repo from given URL """ new_repo_url = self.clone_new_box.get() LOGGER.write('Cloning new repo {}'.format(new_repo_url)) self.message, self.status = pyautogit.commands.git_clone_new_repo(new_repo_url, self.manager.credentials) self.refresh_status() self.clone_new_box.clear() # Turn off loading popup self.manager.root.stop_loading_popup()
def delete_repo(self, to_delete): """Function that deletes a repo Parameters ---------- to_delete : bool User's response of request for confirmation of deletion """ if to_delete: target = self.repo_menu.get() LOGGER.write('Deleting repository {}'.format(target)) pyautogit.commands.remove_repo_tree(target) self.refresh_status()
def open_autogit_window(self): """Function that opens the repository control window. """ LOGGER.write('Opening repo control window') target = self.repo_select_manager.repo_menu.get() self.repo_select_manager.clear_elements() self.repo_control_manager.set_initial_values() self.root.apply_widget_set(self.repo_control_widget_set) if self.current_state == 'workspace': os.chdir(target) self.current_state = 'repo' self.root.set_title('pyautogit v{} - {}'.format(__version__, target)) self.repo_control_manager.refresh_status()
def show_repo_status(self): """Function that shows the current repository status """ current_repo = self.repo_menu.get_selected_item_index() repo_name = self.repo_menu.get() LOGGER.write('Displaying repo status for {}'.format(repo_name)) self.git_status_box.clear() out, err = pyautogit.commands.git_status(repo_name) if err != 0: self.manager.root.show_error_popup('Unable to get git status!', out) self.git_status_box.title = 'Git Repo Status - {}'.format(repo_name) self.git_status_box.set_text('\n{}'.format(out)) self.refresh_status() self.repo_menu.selected_item = current_repo
def update_password(self, passwd): """Function called once password is entered. If necessary, fires the post_input_callback function Parameters ---------- passwd : str The user's password """ self.credentials.append(passwd) self.repo_select_manager.refresh_status() LOGGER.write('User credentials entered') if self.post_input_callback is not None: self.post_input_callback() self.post_input_callback = None
def open_repo_select_window(self): """Opens the repo select window. Fired when the backspace key is pressed in the repo control window """ LOGGER.write('Opening repo select window') self.repo_control_manager.clear_elements() self.settings_manager.clear_elements() self.repo_select_manager.set_initial_values() self.root.apply_widget_set(self.repo_select_widget_set) if self.current_state == 'repo': os.chdir('..') self.current_state = 'workspace' self.root.set_title('pyautogit v{} - {}'.format( __version__, os.path.basename(os.getcwd()))) self.repo_select_manager.refresh_status() self.root.move_focus(self.repo_select_manager.repo_menu)
def update_default_editor(self): """Function that sets the default editor Parameters ---------- editor : str command line call to open the editor """ LOGGER.write('Updating the default editor to {}'.format( self.user_message)) self.default_editor = self.user_message self.editor_type = 'External' self.root.show_message_popup( 'Default Editor Changed', '{} editor will be used to open directories'.format( self.user_message)) self.repo_select_manager.refresh_status()
def write_metadata(self): """Writes metadata file with cached settings """ settings_dir = os.path.join(self.manager.workspace_path, '.pyautogit') settings_file = os.path.join(settings_dir, 'pyautogit_settings.json') if not os.path.exists(settings_dir): os.mkdir(settings_dir) if os.path.exists(settings_file): os.remove(settings_file) metadata = {} metadata['EDITOR'] = self.manager.default_editor metadata['VERSION'] = pyautogit.__version__ metadata['LOG_ENABLE'] = LOGGER._LOG_ENABLED LOGGER.write('Writing metadata: {}'.format(metadata)) fp = open(settings_file, 'w') json.dump(metadata, fp) fp.close()
def refresh_status(self): """Function that refreshes the repositories in the selection screen """ LOGGER.write('Refreshing repo select status') self.manager.repos = pyautogit.find_repos_in_path(self.manager.workspace_path) self.repo_menu.clear() self.repo_menu.add_item_list(self.manager.repos) status_message = 'Current directory:\n{}\n\n'.format(self.manager.workspace_path) status_message = status_message + '# of Repos: {}\n\n'.format(len(self.manager.repos)) if len(self.manager.credentials) == 0: status_message = status_message + 'Credentials Not Entered\n' else: status_message = status_message + 'Credentials Entered\n' if self.manager.default_editor is not None: status_message = status_message + '\nEditor: {}'.format(self.manager.default_editor) else: status_message = status_message + '\nNo Editor Specified.' self.current_status_box.set_text(status_message)
def perform_long_operation(self, title, long_operation_function, post_loading_callback): """Function that wraps an operation around a loading icon popup. Parameters ---------- title : str title for loading icon long_operation_function : function operation to perform in the background post_loading_callback : function Function fired once long operation is finished. """ LOGGER.write('Executing long operation {}'.format(title)) self.root.show_loading_icon_popup('Please Wait', title, callback=post_loading_callback) self.operation_thread = threading.Thread( target=long_operation_function) self.operation_thread.start()
def main(): """Entry point for pyautogit. Parses arguments, and initializes the CUI """ target, credentials, args = parse_args() save_metadata = not args['nosavemetadata'] debug_logging = args['debug'] target_abs = os.path.abspath(target) input_type = 'repo' if not is_git_repo(target): input_type = 'workspace' # Make sure we have write permissions if not os.access(target, os.W_OK): print('ERROR - Permission error for target {}'.format(target_abs)) exit(-1) if input_type == 'repo' and not os.access(os.path.dirname(target_abs), os.W_OK): print( 'ERROR - Permission denied for parent workspace {} of repository {}' .format(os.path.dirname(target_abs), target_abs)) exit(-1) if debug_logging: if input_type == 'repo': LOGGER.set_log_file_path('../.pyautogit/{}.log'.format( str(datetime.datetime.today()).split(' ')[0])) else: LOGGER.set_log_file_path('.pyautogit/{}.log'.format( str(datetime.datetime.today()).split(' ')[0])) LOGGER.toggle_logging() LOGGER.write('Initialized debug logging') root = py_cui.PyCUI(5, 4) if debug_logging: root.enable_logging(log_file_path='.pyautogit/py_cui_root.log') # Use feature added in py_cui 0.0.3 to add unicode widget borders root.toggle_unicode_borders() _ = PyAutogitManager(root, target, input_type, save_metadata, credentials) LOGGER.write('Parsed args. Target location - {}'.format(target_abs)) LOGGER.write('Initial state - {}'.format(input_type)) LOGGER.write('Initialized manager object, starting CUI...') root.start()
def read_metadata(self): """Converts metadata json file to python dict Returns ------- metadata : dict metadata dictionary """ settings_dir = os.path.join(self.manager.workspace_path, '.pyautogit') settings_file = os.path.join(settings_dir, 'pyautogit_settings.json') if os.path.exists(settings_file): try: fp = open(settings_file, 'r') metadata = json.load(fp) fp.close() LOGGER.write('Read metadata:{}'.format(metadata)) return metadata except json.decoder.JSONDecodeError: shutil.rmtree(settings_dir) self.first_time = True else: self.first_time = True
def find_repos_in_path(path): """Helper function that finds repositories in the path Parameters ---------- path : str Target path Returns ------- repos : list of str list of git repositories within target """ repos = [] for dir in os.listdir(path): new_dir = os.path.join(path, dir) if os.path.isdir(new_dir) and is_git_repo(new_dir): repos.append(os.path.basename(new_dir)) LOGGER.write('Found repos in path: {}'.format(repos)) return repos
def handle_basic_command(command, name, remove_quotes=True): """Function that executes any git command given, and returns program output. Parameters ---------- command : str The command string to run name : str The name of the command being run remove_quotes : bool Since subprocess takes an array of strings, we split on spaces, however in some cases we want quotes to remain together (ex. commit message) Returns ------- out : str Output string from stdout if success, stderr if failure err : int Error code if failure, 0 otherwise. """ out = None err = 0 run_command = parse_string_into_executable_command(command, remove_quotes) try: LOGGER.write('Executing command: {}'.format(str(run_command))) proc = Popen(run_command, stdout=PIPE, stderr=PIPE) output, error = proc.communicate() if proc.returncode != 0: out = error.decode() err = proc.returncode else: out = output.decode() except: out = "Unknown error processing function: {}".format(name) err = -1 return out, err
def __init__(self, root, target_path, current_state, save_metadata, credentials): """Constructor for PyAutogitManager """ self.root = root self.repo_select_manager = SELECT.RepoSelectManager(self) self.repo_control_manager = CONTROL.RepoControlManager(self) self.settings_manager = SETTINGS.SettingsScreen(self) self.editor_manager = EDITOR.EditorScreenManager(self, target_path) LOGGER.write('Initialized subscreen managers.') self.save_metadata = save_metadata # Make sure to convert to absolute path. If we opened a repository, the top path will be one level higher self.current_path = os.path.abspath(target_path) self.workspace_path = self.current_path if current_state == 'repo': self.workspace_path = os.path.dirname(self.current_path) # Setup some helper objects and default information/variables self.current_state = current_state self.default_editor = None self.editor_type = 'Internal' self.metadata_manager = METADATA.PyAutogitMetadataManager(self) self.loaded_metadata = self.metadata_manager.read_metadata() LOGGER.write('Loaded metadata') LOGGER.write(self.loaded_metadata) self.metadata_manager.apply_metadata(self.loaded_metadata) LOGGER.write('Applied metadata') # Stores currently entered credentials self.credentials = credentials # Temp variable fired on callback after inout self.post_input_callback = None # Add a run on exit callback to save metadata and close log file self.root.run_on_exit(self.close_cleanup) # Utility variable used to store user input for callbacks self.user_message = None # Thread used to perform longer operations self.operation_thread = None # Repository select screen widgets, key commands. self.repos = find_repos_in_path(self.workspace_path) # Initialize CUI elements for each sub-screen self.repo_select_widget_set = self.repo_select_manager.initialize_screen_elements( ) self.repo_control_widget_set = self.repo_control_manager.initialize_screen_elements( ) self.settings_widget_set = self.settings_manager.initialize_screen_elements( ) self.editor_widget_set = self.editor_manager.initialize_screen_elements( ) LOGGER.write('Initialized CUI elements') # Open repo select screen in workspace view if self.current_state == 'workspace': self.open_repo_select_window() # Open repo control screen in repo view elif self.current_state == 'repo': self.open_autogit_window()