diff --git a/apt-vim b/apt-vim index a4c0bdc..2779835 100755 --- a/apt-vim +++ b/apt-vim @@ -1,5 +1,5 @@ #!/usr/bin/env python -import json, sys, os, re, shutil, shlex, getopt, platform, stat, ast +import json, sys, os, re, shutil, shlex, getopt, platform, stat, ast, signal from distutils.util import strtobool from subprocess import call, check_output, CalledProcessError @@ -23,6 +23,27 @@ HOST_OS = platform.system().lower() CWD = os.getcwd() PKG_IDENTIFIER = '@vimpkg' +def sigint_handler(signal, frame): + sys.exit(1) + +# Thanks to stackoverflow.com/questions/377017/test-if-executable-exists-in-python +def exists_in_path(program): + def is_exe(fpath): + return os.path.isfile(fpath) and os.access(fpath, os.X_OK) + + fpath, fname = os.path.split(program) + if fpath: + if is_exe(program): + return True + else: + for path in os.environ["PATH"].split(os.pathsep): + path = path.strip('"') + exe_file = os.path.join(path, program) + if is_exe(exe_file): + return True + + return False + def report_fail(fail_msg=None, confirm_msg=None, confirm_continue=True, ASSUME_YES=False): if fail_msg is None: fail_msg = 'Something went wrong...\n' @@ -195,14 +216,21 @@ class aptvim(object): def install_pkg(self, vimpkg, skip_clone=False): self.status_update(vimpkg.name) # Install dependencies of package - self.install_dependencies(vimpkg) + if self.install_dependencies(vimpkg) is None: + return # Clone the plugin and run any post-install commands if not skip_clone: self.clone_pkg(vimpkg.pkg_url, vimpkg.name) os.chdir(self.INSTALL_TARGET) os.chdir(vimpkg.name) - if not self.exe_shell_commands(vimpkg.get_recipe(ASSUME_YES=self.ASSUME_YES)): - report_fail('Failed to intall ' + vimpkg.name, + commands = vimpkg.get_recipe(ASSUME_YES=self.ASSUME_YES) + if len(commands) > 0: + print('Attempting to install `' + vimpkg.name + '`') + install_result = self.exe_shell_commands(commands, vimpkg.name) + if install_result is None: + self.remove_pkg(vimpkg) + elif install_result == False: + report_fail('Failed to install ' + vimpkg.name, ASSUME_YES=self.ASSUME_YES) # Change back to the DIR containing this script os.chdir(SCRIPT_ROOT_DIR) @@ -280,25 +308,30 @@ class aptvim(object): def install_dependencies(self, vimpkg): pkg_name = vimpkg.name dependencies = vimpkg.depends_on - if dependencies: + if dependencies and len(dependencies) > 0: # Change to directory with dependency source os.chdir(SRC_DIR) if not os.path.exists(pkg_name): os.makedirs(pkg_name) os.chdir(pkg_name) - for dep in dependencies: - if not self.check_requirements([dep.name]): - commands = dep.get_recipe(ASSUME_YES=self.ASSUME_YES) - if not self.exe_shell_commands(commands): - report_fail('Failed to intall ' + pkg_name, ASSUME_YES=self.ASSUME_YES) + for dep in dependencies: + if not self.check_requirements([dep.name]): + commands = dep.get_recipe(ASSUME_YES=self.ASSUME_YES) + install_result = self.exe_shell_commands(commands, dep.name) + if install_result is None: + return None + if not self.exe_shell_commands(commands, dep.name): + report_fail('Failed to intall ' + pkg_name, ASSUME_YES=self.ASSUME_YES) + return False + else: + exe = self.find_executable(SRC_DIR, dep.name) + if exe: + dst = os.path.join(BIN_DIR, dep.name) + shutil.copyfile(exe, dst) else: - exe = self.find_executable(SRC_DIR, dep.name) - if exe: - dst = os.path.join(BIN_DIR, dep.name) - shutil.copyfile(exe, dst) - else: - print('`' + dep.name + '` already in PATH') + print('`' + dep.name + '` already in PATH') + return True def find_executable(self, path, filename): executable = stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH @@ -467,12 +500,13 @@ class aptvim(object): return False return True - def usage(self): - pass - - def exe_shell_commands(self, commands=None): + def exe_shell_commands(self, commands=None, command_requester='Unknown'): if commands is None: commands = [] + if len(commands) > 0 and \ + not self.confirm_install_ok(command_requester, commands): + print('Skipping commands by user request.') + return None for com in commands: com = com.replace('~', HOME) try: @@ -567,7 +601,7 @@ class aptvim(object): os.chmod(SCRIPT_EXE_PATH, 0o744) os.environ['PATH'] += os.pathsep + BIN_DIR - missing_dependencies = self.init() + missing_dependencies = self.dep_check() if missing_dependencies: report_fail('Cannot proceed. Missing the following dependencies that could' \ + ' not be automatically insatlled:\n' \ @@ -585,26 +619,35 @@ class aptvim(object): report_fail(msg, confirm_continue=False, ASSUME_YES=self.ASSUME_YES) def confirm_install_ok(self, install_requester, commands): - confirm_string = 'Package `' + install_requester + '` wants to run the following commands:\n' + if self.ASSUME_YES: + return True + prompt_command_string = 'command' + if len(commands) > 1: + prompt_command_string += 's' + + confirm_string = 'Package `' + install_requester + \ + '` wants to run the following ' + prompt_command_string + \ + ' from the directory "' + os.getcwd() + '"\n' command_string = '' for command in commands: - command_string += command + '\n' + command_string += ' ' + command + '\n' confirm_string += command_string + 'Is this ok?' - if self.ASSUME_YES or user_confirm(confirm_string, ASSUME_YES=self.ASSUME_YES): + if user_confirm(confirm_string, ASSUME_YES=self.ASSUME_YES): return True return False - def init(self): + def dep_check(self): self.verify_bin_in_path() missing_deps = [] deps = self.VIM_CONFIG[GBL][DPND] for dep in deps: dep = Dependency.dict_to_dep(dep, ASSUME_YES=self.ASSUME_YES) - if not self.check_requirements([dep.name]) and \ - (len(dep.get_recipe(ASSUME_YES=self.ASSUME_YES)) > 0 and self.confirm_install_ok(dep.name, dep.get_recipe(ASSUME_YES=self.ASSUME_YES))): - print('Attempting to install `' + dep.name + '`') - if not self.exe_shell_commands(dep.get_recipe(ASSUME_YES=self.ASSUME_YES)): + if not exists_in_path(dep.name): + commands = dep.get_recipe(ASSUME_YES=self.ASSUME_YES) + if len(commands) > 0: + print('Attempting to install `' + dep.name + '`') + if not self.exe_shell_commands(commands, dep.name): missing_deps.append(dep.name) return missing_deps @@ -719,8 +762,10 @@ class aptvim(object): return self.__handle_remove(argv, options, pkg_ids, delete=True) def handle_update(self, argv, options, pkg_ids): - if not pkg_ids: # If no urls provided, assume updating all packages in vim_config - pkg_ids = [ p[PKG_URL] for p in self.VIM_CONFIG[PKGS] ] + if not pkg_ids: # If no urls provided, assume updating all INSTALLED packages in vim_config + installed_packages = self.get_installed_pkgs() + pkg_ids = [ p[PKG_URL] for p in self.VIM_CONFIG[PKGS] if \ + p[NAME] in installed_packages ] if not pkg_ids: report_fail('No package URL specified. Exiting', confirm_continue=False, ASSUME_YES=self.ASSUME_YES) @@ -758,7 +803,7 @@ class aptvim(object): self.MODES[mode]() return - missing_dependencies = self.init() + missing_dependencies = self.dep_check() if mode == 'list': self.MODES[mode]() sys.exit(0) @@ -778,12 +823,16 @@ class aptvim(object): self.MODES[mode](argv[1:], options, remainder) def usage(self): - print('Valid modes: ', str(sorted(list(self.MODES.keys()), key=lambda s: s.lower())), '\n') + print('Valid modes: ' + str(sorted(list(self.MODES.keys()), key=lambda s: s.lower())) + '\n') sys.exit(1) def main(self): self.process_cmd_args() - print('Completed successfully!') + print('Completed successfully.') + + + +signal.signal(signal.SIGINT, sigint_handler) if __name__ != '__main__': # We're calling from an import/shell script