Example #1
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.platform_dir = os.path.join(self.config.cwd, 'platforms/ubuntu/')
        self.sdk = 'ubuntu-sdk-16.04' if self.config.is_xenial else 'ubuntu-sdk-15.04'

        self._dirs = {
            'build': '{}/{}/{}/build/' .format(self.platform_dir, self.sdk, self.config.build_arch),
            'prefix': '{}/{}/{}/prefix/'.format(self.platform_dir, self.sdk, self.config.build_arch),
            'make': '{}/build'.format(self.platform_dir)
        }

        self.config.temp = self._dirs['build']
        self.config.build_dir = self._dirs['prefix']

        if not os.path.isdir(self.platform_dir):
            # fail when not using docker, need it anyways
            if self.config.container_mode or self.config.lxd:
                print_error('Docker is required to intialize cordova directories. Enable docker or run "cordova platform add ubuntu" manually to remove this message')
                sys.exit(1)

            command = 'cordova platform add ubuntu'

            # Can't use self.container.run_command because need to set -e HOME=/tmp
            wrapped_command = 'docker run -v {cwd}:{cwd} -w {cwd} -u {uid}:{uid} -e HOME=/tmp --rm -i {img} {cmd}'.format(
                cwd=self.config.cwd,
                uid=os.getuid(),
                img=self.config.docker_image,
                cmd=command
            )

            subprocess.check_call(shlex.split(wrapped_command))
Example #2
0
    def __init__(self, *args, **kwargs):
        super(CMakeClickable, self).__init__(*args, **kwargs)

        self.platform_dir = os.path.join(self.cwd, 'platforms/ubuntu/')

        self._dirs = {
            'build': '{}/{}/{}/build/' .format(self.platform_dir, self.config.sdk, self.build_arch),
            'prefix': '{}/{}/{}/prefix/'.format(self.platform_dir, self.config.sdk, self.build_arch),
            'make': '{}/build'.format(self.platform_dir)
        }

        self.temp = self._dirs['build']

        if not os.path.isdir(self.platform_dir):
            # fail when not using docker, need it anyways
            if self.config.container_mode or self.config.lxd or self.config.chroot:
                print_error('Docker is required to intialize cordova directories. Enable docker or run "cordova platform add ubuntu" manually to remove this message')
                sys.exit(1)

            cordova_docker_image = "beevelop/cordova:v7.0.0"  # TODO add cordova to the clickable image
            command = "cordova platform add ubuntu"

            # Can't use self.run_container_command because need to set -e HOME=/tmp
            wrapped_command = 'docker run -v {cwd}:{cwd} -w {cwd} -u {uid}:{uid} -e HOME=/tmp --rm -i {img} {cmd}'.format(
                cwd=self.cwd,
                uid=os.getuid(),
                img=cordova_docker_image,
                cmd=command
            )

            subprocess.check_call(shlex.split(wrapped_command))

        self.config.dir = self._dirs['prefix']
Example #3
0
    def __init__(self, *args, **kwargs):
        super(CMakeClickable, self).__init__(*args, **kwargs)

        self.platform_dir = os.path.join(self.cwd, 'platforms/ubuntu/')

        self._dirs = {
            'build':
            '{}/{}/{}/build/'.format(self.platform_dir,
                                     'ubuntu-sdk-{}'.format(self.config.sdk),
                                     self.build_arch),
            'prefix':
            '{}/{}/{}/prefix/'.format(self.platform_dir,
                                      'ubuntu-sdk-{}'.format(self.config.sdk),
                                      self.build_arch),
            'make':
            '{}/build'.format(self.platform_dir)
        }

        self.temp = self._dirs['build']

        if not os.path.isdir(self.platform_dir):
            if (self.config.container_mode or self.config.lxd
                    or self.config.chroot) and not shutil.which("cordova"):
                print_error(
                    'Docker is required to intialize cordova directories. Enable docker or run "cordova platform add ubuntu" manually to remove this message'
                )
                sys.exit(1)

            cordova_docker_image = "beevelop/cordova:v7.0.0"  # TODO add cordova to the clickable image
            command = "cordova platform add ubuntu"

            old_docker_image = (hasattr(self, "docker_image"),
                                getattr(self, "docker_image", None))
            self.docker_image = cordova_docker_image
            self.run_container_command(command, use_dir=False)
            if old_docker_image[0]:
                self.docker_image = old_docker_image[1]
            else:
                del self.docker_image

            os.makedirs(self._dirs["build"], exist_ok=True)

        self.config.dir = self._dirs['prefix']
Example #4
0
    def publish(self):
        # TODO allow publishing app for the first time

        if not self.config.apikey:
            print_error(
                'No api key specified, use OPENSTORE_API_KEY or --apikey')
            return

        click = '{}_{}_{}.click'.format(self.find_package_name(),
                                        self.find_version(), self.config.arch)
        click_path = os.path.join(self.config.dir, click)

        url = OPENSTORE_API
        if 'OPENSTORE_API' in os.environ and os.environ['OPENSTORE_API']:
            url = os.environ['OPENSTORE_API']

        url = url + OPENSTORE_API_PATH.format(self.find_package_name())
        channel = 'xenial' if self.config.isXenial else 'vivid'
        files = {'file': open(click_path, 'rb')}
        data = {'channel': channel}
        params = {'apikey': self.config.apikey}

        print_info('Uploading version {} of {} for {} to the OpenStore'.format(
            self.find_version(), self.find_package_name(), channel))
        response = requests.post(url, files=files, data=data, params=params)
        if response.status_code == requests.codes.ok:
            print_success('Upload successful')
        else:
            if response.text == 'Unauthorized':
                print_error('Failed to upload click: Unauthorized')
            else:
                print_error('Failed to upload click: {}'.format(
                    response.json()['message']))
Example #5
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.platform_dir = os.path.join(self.config.cwd, 'platforms/ubuntu/')
        self.sdk = 'ubuntu-sdk-16.04' if self.config.is_xenial else 'ubuntu-sdk-15.04'

        self._dirs = {
            'build':
            '{}/{}/{}/build/'.format(self.platform_dir, self.sdk,
                                     self.config.build_arch),
            'prefix':
            '{}/{}/{}/prefix/'.format(self.platform_dir, self.sdk,
                                      self.config.build_arch),
            'make':
            '{}/build'.format(self.platform_dir)
        }

        self.config.temp = self._dirs['build']
        self.config.dir = self._dirs['prefix']

        if not os.path.isdir(self.platform_dir):
            # fail when not using docker, need it anyways
            if self.config.container_mode or self.config.lxd:
                print_error(
                    'Docker is required to intialize cordova directories. Enable docker or run "cordova platform add ubuntu" manually to remove this message'
                )
                sys.exit(1)

            command = 'cordova platform add ubuntu'

            # Can't use self.container.run_command because need to set -e HOME=/tmp
            wrapped_command = 'docker run -v {cwd}:{cwd} -w {cwd} -u {uid}:{uid} -e HOME=/tmp --rm -i {img} {cmd}'.format(
                cwd=self.config.cwd,
                uid=os.getuid(),
                img=self.base_docker_image,
                cmd=command)

            subprocess.check_call(shlex.split(wrapped_command))
Example #6
0
 def or_exit(self):
     if not self.query.is_met():
         self.print_instructions()
         print_error('System requirement not met')
         exit(1)
Example #7
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)
Example #8
0
 def setup_lxd(self):
     print_error(
         'Setting up lxd is no longer supported, use docker instead')
Example #9
0
def main():
    config = None
    COMMAND_ALIASES = {
        'click_build': 'click_build',
        'build_click': 'click_build',
        'build-click': 'click_build',
        'writeable-image': 'writable_image',
    }

    COMMAND_HANDLERS = {
        'kill': 'kill',
        'clean': 'clean',
        'build': 'build',
        'click-build': 'click_build',
        'install': 'install',
        'launch': 'launch',
        'logs': 'logs',
        'setup-lxd': 'setup_lxd',
        'display-on': 'display_on',
        'no-lock': 'no_lock',
        'setup-docker': 'setup_docker',
        'update-docker': 'update_docker',
        'shell': 'shell',
        'devices': 'devices',
        'init': 'init_app',
        'run': 'run',
        'review': 'click_review',
        'writable-image': 'writable_image',
        'publish': 'publish',
    }

    def show_valid_commands():
        n = [
            'Valid commands:',
            ', '.join(sorted(COMMAND_HANDLERS.keys()))
        ]
        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(
        '--device',
        '-d',
        action='store_true',
        help='Whether or not to run the custom command on the device',
        default=False,
    )
    parser.add_argument(
        '--device-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(
        '--ip',
        '-i',
        help='Directs command to the device with the given IP address (using ssh)'
    )
    parser.add_argument(
        '--arch',
        '-a',
        help='Use the specified arch when building (ignores the setting in clickable.json)'
    )
    parser.add_argument(
        '--template',
        '-t',
        help='Use the specified template when building (ignores the setting in clickable.json)'
    )

    # TODO depricate
    parser.add_argument(
        '--click',
        '-c',
        help='Installs the specified click (use with the "install" command)'
    )

    # TODO depricate
    parser.add_argument(
        '--app',
        '-p',
        help='Launches the specified app (use with the "launch" command)'
    )
    parser.add_argument(
        '--debug',
        action='store_true',
        help='Runs 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(
        '--name',
        '-n',
        help='Specify an app template name to use when running "clickable init"'
    )
    parser.add_argument(
        '--desktop',
        '-e',
        action='store_true',
        help='Run the app on the current machine for testing',
        default=False,
    )
    parser.add_argument(
        '--sdk',
        '-k',
        help='Use a specific version of the ubuntu sdk to compile against',
    )
    parser.add_argument(
        '--nvidia',
        action='store_true',
        help='Use nvidia-docker rather than docker',
        default=False,
    )
    parser.add_argument(
        '--apikey',
        help='Api key for the OpenStore',
    )
    parser.add_argument(
        '--xenial',
        action='store_true',
        help='Shortcut for --sdk=16.04',
        default=False,
    )

    args = parser.parse_args()

    skip_detection = False
    if args.click:
        skip_detection = True

    if len(args.commands) == 1:
        skip_commands = [
            'setup-lxd',
            'setup-docker',
            'shell',
            'no-lock',
            'display-on',
            'devices',
            'init',
        ]

        if args.commands[0] in skip_commands:
            skip_detection = True

    try:
        # TODO clean this up
        config = Config(
            ip=args.ip,
            arch=args.arch,
            template=args.template,
            skip_detection=skip_detection,
            lxd=args.lxd,
            click_output=args.output,
            container_mode=args.container_mode,
            desktop=args.desktop,
            sdk='16.04' if args.xenial else args.sdk,
            use_nvidia=args.nvidia,
            apikey=args.apikey,
        )

        VALID_COMMANDS = list(COMMAND_HANDLERS.keys()) + list(config.scripts.keys())

        clickable = None
        if config.template == config.PURE_QML_QMAKE:
            clickable = PureQMLQMakeClickable(config, args.device_serial_number)
        elif config.template == config.QMAKE:
            clickable = QMakeClickable(config, args.device_serial_number)
        elif config.template == config.PURE_QML_CMAKE:
            clickable = PureQMLCMakeClickable(config, args.device_serial_number)
        elif config.template == config.CMAKE:
            clickable = CMakeClickable(config, args.device_serial_number)
        elif config.template == config.CUSTOM:
            clickable = CustomClickable(config, args.device_serial_number)
        elif config.template == config.CORDOVA:
            clickable = CordovaClickable(config, args.device_serial_number)
        elif config.template == config.PURE:
            clickable = PureClickable(config, args.device_serial_number)
        elif config.template == config.PYTHON:
            clickable = PythonClickable(config, args.device_serial_number)
        elif config.template == config.GO:
            clickable = GoClickable(config, args.device_serial_number)

        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]

        # TODO consider removing the ability to string together multiple commands
        # This should help clean up the arguments & new command_arg
        for command in commands:
            if command in config.scripts:
                clickable.script(command, args.device)
            elif command == 'install':
                clickable.install(args.click if args.click else command_arg)
            elif command == 'review':
                clickable.click_review(args.click if args.click else command_arg)
            elif command == 'launch':
                clickable.launch(args.app if args.app else command_arg)
            elif command == 'init':
                clickable.init_app(args.name)
            elif command == 'run':
                if not command_arg:
                    raise ValueError('No command supplied for `clickable run`')

                clickable.run(command_arg)
            elif command in COMMAND_HANDLERS:
                getattr(clickable, COMMAND_HANDLERS[command])()
            elif command in COMMAND_ALIASES:
                getattr(clickable, COMMAND_ALIASES[command])()
            elif command == 'help':
                parser.print_help()
            else:
                print_error('There is no builtin or custom command named "{}"'.format(command))
                print_valid_commands()
    except Exception:
        if args.debug:
            raise
        else:
            print_error(str(sys.exc_info()[1]))
            sys.exit(1)
Example #10
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 nvidia-docker rather than docker',
        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,
    )

    args = parser.parse_args()

    try:
        config = Config(
            args=args,
            clickable_version=__version__,
            desktop=('desktop' in args.commands),
        )

        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)