예제 #1
0
    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))
예제 #2
0
    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'])
예제 #3
0
    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)
예제 #4
0
 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)
예제 #5
0
    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))
예제 #6
0
    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)
예제 #7
0
    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')
예제 #8
0
 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
예제 #9
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = PublishCommand(self.config)
예제 #10
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = InstallCommand(self.config)
예제 #11
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = LaunchCommand(self.config)
예제 #12
0
 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)
예제 #13
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = CleanCommand(self.config)
예제 #14
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = UpdateCommand(self.config)
예제 #15
0
 def setUp(self):
     self.config = ConfigMock({})
     self.container = Container(self.config)
     self.device = Device(self.config)
     self.command = CordovaBuilder(self.config, self.command)
예제 #16
0
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)
예제 #17
0
파일: base.py 프로젝트: jonnius/clickable
 def __init__(self, config):
     self.config = config
     self.container = Container(config)
     self.device = Device(config)
예제 #18
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = WritableImageCommand(self.config)
예제 #19
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = ClickBuildCommand(self.config)
예제 #20
0
 def setUp(self):
     self.config = ConfigMock()
     self.config.container = Container(self.config)
     self.command = DevicesCommand(self.config)
예제 #21
0
    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)