def run(self, path_arg=""): if not self.config.lib_configs: print_warning('No libraries defined.') single_lib = path_arg found = False for lib in self.config.lib_configs: if not single_lib or single_lib == lib.name: print_info("Building {}".format(lib.name)) found = True lib.container_mode = self.config.container_mode lib.docker_image = self.config.docker_image lib.build_arch = self.config.build_arch lib.container = Container(lib, lib.name) lib.container.setup_dependencies() try: os.makedirs(lib.build_dir) except FileExistsError: pass except Exception: print_warning('Failed to create the build directory: {}'.format(str(sys.exc_info()[0]))) if lib.prebuild: run_subprocess_check_call(lib.prebuild, cwd=self.config.cwd, shell=True) self.build(lib) if lib.postbuild: run_subprocess_check_call(lib.postbuild, cwd=lib.build_dir, shell=True) if single_lib and not found: raise ValueError('Cannot build unknown library {}. You may add it to the clickable.json'.format(single_lib))
def create_and_run(self, template): config = ConfigMock() config.container = Container(config) command = CreateCommand(config) command.run(path_arg=template, no_input=True) os.chdir(self.app_path) self.clickable.run(['clean', 'build'])
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 setUp(self): self.custom_cmd = 'echo "Building lib"' self.config = ConfigMock() self.config.lib_configs = [ LibConfigMock({ 'template': 'custom', 'build': self.custom_cmd, }) ] self.config.container = Container(self.config) self.command = LibBuildCommand(self.config)
def run(self, path_arg=""): if not self.config.lib_configs: logger.warning('No libraries defined.') single_lib = path_arg found = False for lib in self.config.lib_configs: if not single_lib or single_lib == lib.name: logger.info("Building {}".format(lib.name)) found = True lib.container_mode = self.config.container_mode lib.docker_image = self.config.docker_image lib.build_arch = self.config.build_arch lib.container = Container(lib, lib.name) lib.container.setup() # This is a workaround for lib env vars being overwritten by # project env vars, especially affecting Container Mode. lib.set_env_vars() try: os.makedirs(lib.build_dir, exist_ok=True) except Exception: logger.warning( 'Failed to create the build directory: {}'.format( str(sys.exc_info()[0]))) try: os.makedirs(lib.build_home, exist_ok=True) except Exception: logger.warning( 'Failed to create the build home directory: {}'.format( str(sys.exc_info()[0]))) if lib.prebuild: run_subprocess_check_call(lib.prebuild, cwd=self.config.cwd, shell=True) self.build(lib) if lib.postbuild: run_subprocess_check_call(lib.postbuild, cwd=lib.build_dir, shell=True) if single_lib and not found: raise ClickableException( 'Cannot build unknown library {}, which is not in your clickable.json' .format(single_lib))
def run_test(self, lib): if not os.path.exists(lib.build_dir): logger.warning( "Library {} has not yet been built for host architecture.". format(lib.name)) else: lib.container_mode = self.config.container_mode lib.docker_image = self.config.docker_image lib.build_arch = self.config.build_arch lib.container = Container(lib, lib.name) lib.container.setup() # This is a workaround for lib env vars being overwritten by # project env vars, especially affecting Container Mode. lib.set_env_vars() command = 'xvfb-startup {}'.format(lib.test) lib.container.run_command(command, use_build_dir=True)
def test_rust(self): # TODO see if the rust template can support automatically changing the arch in the manifest config = ConfigMock() config.container = Container(config) command = CreateCommand(config) command.run(path_arg='Rust', no_input=True) manifest_path = os.path.join(self.app_path, 'manifest.json') with open(manifest_path, 'r') as manifest_reader: manifest = json.load(manifest_reader) manifest['architecture'] = 'amd64' with open(manifest_path, 'w') as manifest_writer: json.dump(manifest, manifest_writer, indent=4) os.chdir(self.app_path) self.clickable.run(['clean', 'build']) self.assertClickExists('amd64')
def setUpConfig(self, expect_exception=False, mock_config_json={}, mock_config_env={}, *args, **kwargs): self.config = None try: self.config = ConfigMock(mock_config_json=mock_config_json, mock_config_env=mock_config_env, mock_install_files=True, *args, **kwargs) self.config.container = Container(self.config) self.config.interactive = False if expect_exception: raise ClickableException( "A ClickableException was expected, but was not raised") except ClickableException as e: if not expect_exception: raise e
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = PublishCommand(self.config)
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = InstallCommand(self.config)
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = LaunchCommand(self.config)
def setUp(self): self.config = ConfigMock({}) self.container = Container(self.config) self.device = Device(self.config) self.command = PureQMLMakeBuilder(self.config, self.container, self.command)
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = CleanCommand(self.config)
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = UpdateCommand(self.config)
def setUp(self): self.config = ConfigMock({}) self.container = Container(self.config) self.device = Device(self.config) self.command = CordovaBuilder(self.config, self.command)
def main(): config = None command_classes = {} command_names = [] command_aliases = {} command_help = {} command_dir = dirname(__file__) modules = glob.glob(join(command_dir, 'commands/*.py')) command_modules = [ basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py') ] for name in command_modules: command_submodule = __import__('clickable.commands.{}'.format(name), globals(), locals(), [name]) for name, cls in inspect.getmembers(command_submodule): if inspect.isclass(cls) and issubclass( cls, Command ) and cls != Command and cls.name not in command_classes: command_classes[cls.name] = cls command_names.append(cls.name) if cls.help: command_help[cls.name] = cls.help for alias in cls.aliases: command_aliases[alias] = cls.name # TODO show the help text def show_valid_commands(): n = ['Valid commands:', ', '.join(sorted(command_names))] if config and hasattr(config, 'scripts') and config.scripts: n += [ 'Project-specific custom commands:', ', '.join(sorted(config.scripts.keys())) ] return '\n'.join(n) def print_valid_commands(): print(show_valid_commands()) parser = argparse.ArgumentParser(description='clickable') parser.add_argument('--version', '-v', action='version', version='%(prog)s ' + __version__) parser.add_argument('commands', nargs='*', help=show_valid_commands()) parser.add_argument( '--serial-number', '-s', help= 'Directs command to the device or emulator with the given serial number or qualifier (using adb)', default=None) parser.add_argument( '--config', '-c', help= 'Use specified config file instead of looking for the optional "clickable.json" in the current directory', default=None) parser.add_argument( '--ssh', help= 'Directs command to the device with the given IP address (using ssh)', default=None) parser.add_argument( '--arch', '-a', help= 'Use the specified arch when building (ignores the setting in clickable.json)' ) parser.add_argument( '--debug', action='store_true', help='Runs clickable in debug mode', default=False, ) parser.add_argument( '--lxd', action='store_true', help='Run build commands in a lxd container', default=False, ) parser.add_argument( '--output', help='Where to output the compiled click package', ) parser.add_argument( '--container-mode', action='store_true', help= 'Run all build commands on the current machine and not a container', default=False, ) parser.add_argument( '--nvidia', action='store_true', help='Use docker with --runtime=nvidia and *-nvidia docker image', default=False, ) parser.add_argument( '--apikey', help='Api key for the OpenStore', ) parser.add_argument( '--vivid', action='store_true', help='Use the old vivid build container', default=False, ) parser.add_argument('--docker-image', help='Use a specific docker image to build with') parser.add_argument( '--dirty', action='store_true', help='Do not clean build directory', default=False, ) parser.add_argument( '--debug-build', action='store_true', help='Perform a debug build', default=False, ) parser.add_argument( '--gdbserver', help= 'Start gdbserver at the given port to debug the app remotely (only desktop mode)', ) parser.add_argument( '--gdb', action='store_true', help='Start gdb to debug the app (only desktop mode)', default=False, ) args = parser.parse_args() try: config = Config( args=args, clickable_version=__version__, desktop=('desktop' in args.commands or 'test' in args.commands), ) config.container = Container(config) VALID_COMMANDS = command_names + list(config.scripts.keys()) commands = args.commands if len(args.commands) == 0: commands = 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 = [ command_aliases[command] if command in command_aliases else command for command in commands ] for command in commands: if command in command_names: cmd = command_classes[command](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 config.scripts: subprocess.check_call(config.scripts[command], cwd=config.cwd, shell=True) elif command in command_names: cmd = command_classes[command](config) cmd.run(command_arg) elif command == 'help': parser.print_help() else: print_error( 'There is no builtin or custom command named "{}"'.format( command)) print_valid_commands() sys.exit(1) except Exception: if args.debug: raise else: print_error(str(sys.exc_info()[1])) sys.exit(1)
def __init__(self, config): self.config = config self.container = Container(config) self.device = Device(config)
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = WritableImageCommand(self.config)
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = ClickBuildCommand(self.config)
def setUp(self): self.config = ConfigMock() self.config.container = Container(self.config) self.command = DevicesCommand(self.config)
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)