def main(): clickable = Clickable() args = clickable.parse_args() if args.verbose: console_handler.setLevel(logging.DEBUG) logger.debug('Clickable v' + __version__) try: clickable.run(args.commands, args) except ClickableException as e: logger.error(str(e)) sys.exit(1) except subprocess.CalledProcessError as e: logger.debug('Command exited with an error:' + str(e.cmd), exc_info=e) logger.critical( 'Command exited with non-zero exit status {}, see above for details. This is most likely not a problem with Clickable.' .format(e.returncode, )) sys.exit(2) except Exception as e: logger.debug('Encountered an unknown error', exc_info=e) if not args.verbose: logger.critical('Encountered an unknown error: ' + str(e)) logger.critical( 'If you believe this is a bug, please file a report at https://gitlab.com/clickable/clickable/issues with the log file located at ' + log_file) sys.exit(3)
def run(self, commands=[], args=None): self.config = Config( args=args, clickable_version=__version__, desktop=('desktop' in commands or 'test' in commands), ) self.config.container = Container(self.config) VALID_COMMANDS = self.command_names + list(self.config.scripts.keys()) if len(commands) == 0: commands = self.config.default.split(' ') ''' Detect senarios when an argument is passed to a command. For example: `clickable install /path/to/click`. Since clickable allows commands to be strung together it makes detecting this harder. This check has been limited to just the case when we have 2 values in args.commands as stringing together multiple commands and a command with an argument is unlikely to occur. TODO determine if there is a better way to do this. ''' command_arg = '' if len(commands) == 2 and commands[1] not in VALID_COMMANDS: command_arg = commands[1] commands = commands[:1] commands = [ self.command_aliases[command] if command in self.command_aliases else command for command in commands ] for command in commands: if command in self.command_names: cmd = self.command_classes[command](self.config) cmd.preprocess(command_arg) # TODO consider removing the ability to string together multiple commands # This should help clean up the arguments & command_arg for command in commands: if command in self.config.scripts: logger.debug('Running the "{}" script'.format(command)) subprocess.check_call(self.config.scripts[command], cwd=self.config.cwd, shell=True) elif command in self.command_names: logger.debug('Running the "{}" command'.format(command)) cmd = self.command_classes[command](self.config) cmd.run(command_arg) else: logger.error( 'There is no builtin or custom command named "{}"'.format( command)) self.print_valid_commands() sys.exit(1)
def validate_clickable_json(config, schema): try: from jsonschema import validate, ValidationError try: validate(instance=config, schema=schema) except ValidationError as e: logger.error("The clickable.json configuration file is invalid!") error_message = e.message # Lets add the key to the invalid value if e.path: if len(e.path) > 1 and isinstance(e.path[-1], int): error_message = "{} (in '{}')".format( error_message, e.path[-2]) else: error_message = "{} (in '{}')".format( error_message, e.path[-1]) raise ClickableException(error_message) except ImportError: logger.warning( "Dependency 'jsonschema' not found. Could not validate clickable.json." ) pass
def main(): clickable = Clickable() args = clickable.parse_args() if args.verbose: console_handler.setLevel(logging.DEBUG) logger.debug('Clickable v' + __version__) clickable.check_version(quiet=True) try: clickable.run(args.commands, args) except ClickableException as e: logger.error(str(e)) sys.exit(1) except subprocess.CalledProcessError as e: logger.debug('Command exited with an error:' + str(e.cmd), exc_info=e) logger.critical( 'Command exited with non-zero exit status {}, see above for details. This is most likely not a problem with Clickable.' .format(e.returncode, )) sys.exit(2) except KeyboardInterrupt as e: logger.info( '') # Print an empty space at then end so the cli prompt is nicer sys.exit(0) except Exception as e: if isinstance(e, OSError) and '28' in str(e): logger.critical('No space left on device') sys.exit(2) return logger.debug('Encountered an unknown error', exc_info=e) if not args.verbose: logger.critical('Encountered an unknown error: ' + str(e)) logger.critical( 'If you believe this is a bug, please file a report at https://gitlab.com/clickable/clickable/issues with the log file located at ' + log_file) sys.exit(3)
def run(self, arg_commands=[], args=None): self.config = self.setup_config(args, arg_commands) self.config.container = Container( self.config, minimum_version=__container_minimum_required__) commands = self.config.commands VALID_COMMANDS = self.command_names + list(self.config.scripts.keys()) is_default = not arg_commands ''' Detect senarios when an argument is passed to a command. For example: `clickable install /path/to/click`. Since clickable allows commands to be strung together it makes detecting this harder. This check has been limited to just the case when we have 2 values in args.commands as stringing together multiple commands and a command with an argument is unlikely to occur. TODO remove chaining and clean this up ''' command_arg = '' if len(commands) == 2 and commands[1] not in VALID_COMMANDS: command_arg = commands[1] commands = commands[:1] commands = [ self.command_aliases[command] if command in self.command_aliases else command for command in commands ] if len(commands) > 1 and not is_default: logger.warning( 'Chaining multiple commands is deprecated and will be rejected in a future version of Clickable.' ) for command in commands: if command in self.command_names: cmd = self.command_classes[command](self.config) cmd.preprocess(command_arg) for command in commands: if command == 'bash-completion': cli_args = [ '--serial-number', '--config', '--ssh', '--arch', '--verbose', '--container-mode', '--apikey', '--docker-image', '--dirty', '--debug', ] print(' '.join(sorted(VALID_COMMANDS + cli_args))) elif command == 'bash-completion-desktop': cli_args = [ '--nvidia', '--no-nvidia' '--gdbserver', '--gdb', '--dark-mode', '--lang', '--skip-build', '--dirty', '--verbose', '--config', ] print(' '.join(sorted(cli_args))) elif command in self.config.scripts: logger.debug('Running the "{}" script'.format(command)) subprocess.check_call(self.config.scripts[command], cwd=self.config.cwd, shell=True) elif command in self.command_names: logger.debug('Running the "{}" command'.format(command)) cmd = self.command_classes[command](self.config) cmd.run(command_arg) else: logger.error( 'There is no builtin or custom command named "{}"'.format( command)) self.print_valid_commands() sys.exit(1)
def or_exit(self): if not self.query.is_met(): self.print_instructions() logger.error('System requirement not met') exit(1)