Exemple #1
0
    def run(self, path_arg=""):

        single_lib = path_arg
        found = False

        for lib in self.config.lib_configs:
            if not single_lib or single_lib == lib.name:
                print_info("Cleaning {}".format(lib.name))
                found = True

                if os.path.exists(lib.build_dir):
                    try:
                        shutil.rmtree(lib.build_dir)
                    except Exception:
                        cls, value, traceback = sys.exc_info()
                        if cls == OSError and 'No such file or directory' in str(
                                value
                        ):  # TODO see if there is a proper way to do this
                            pass  # Nothing to do here, the directory didn't exist
                        else:
                            print_warning(
                                'Failed to clean the build directory: {}: {}'.
                                format(type, value))
                else:
                    print_info(
                        'Nothing to clean. Path does not exist: {}'.format(
                            lib.build_dir))

        if single_lib and not found:
            raise ValueError(
                'Cannot clean unknown library {}. You may add it to the clickable.json'
                .format(single_lib))
Exemple #2
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))
Exemple #3
0
    def run(self, path_arg=''):
        if not requests_available:
            raise Exception('Unable to publish app, python requests module is not installed')

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

        click = self.config.get_click_filename()
        click_path = os.path.join(self.config.build_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.config.find_package_name())
        channel = 'xenial' if self.config.is_xenial else 'vivid'
        files = {'file': open(click_path, 'rb')}
        data = {
            'channel': channel,
            'changelog': path_arg,
        }
        params = {'apikey': self.config.apikey}

        print_info('Uploading version {} of {} for {} to the OpenStore'.format(self.config.find_version(), self.config.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':
                raise Exception('Failed to upload click: Unauthorized')
            else:
                raise Exception('Failed to upload click: {}'.format(response.json()['message']))
Exemple #4
0
    def run_docker_command(self, docker_config, verbose_mode):
        command = docker_config.render_command()
        if verbose_mode:
            print_info(command)

        subprocess.check_call(shlex.split(command),
                              cwd=docker_config.working_directory)
Exemple #5
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']))
Exemple #6
0
    def check_lxd(self):
        name = 'clickable-{}'.format(self.config.build_arch)

        status = ''
        try:
            status = run_subprocess_check_output(shlex.split('usdk-target status {}'.format(name)), stderr=subprocess.STDOUT)
            status = json.loads(status)['status']
        except subprocess.CalledProcessError as e:
            if e.output.strip() == 'error: Could not connect to the LXD server.' or 'Can\'t establish a working socket connection' in e.output.strip():
                started = self.start_lxd()
                if started:
                    status = 'Running'  # Pretend it's started, but we will call this function again to check if it's actually ok

                    time.sleep(3)  # Give it a sec to boot up
                    self.check_lxd()
                else:
                    raise Exception('LXD is not running, please start it')
            elif e.output.strip() == 'error: Could not query container status. error: not found':
                raise Exception('No lxd container exists to build in, please run `clickable setup-lxd`')
            else:
                print(e.output)
                raise e

        if status != 'Running':
            print_info('Going to start lxd container "{}"'.format(name))
            subprocess.check_call(shlex.split('lxc start {}'.format(name)))
Exemple #7
0
    def detect_template(self):
        if not self.template:
            template = None

            try:
                manifest = get_manifest(os.getcwd())
            except ValueError:
                manifest = None
            except ManifestNotFoundException:
                manifest = None

            directory = os.listdir(os.getcwd())
            if not template and 'CMakeLists.txt' in directory:
                template = Config.CMAKE

                if manifest and manifest.get('architecture', None) == 'all':
                    template = Config.PURE_QML_CMAKE

            pro_files = [f for f in directory if f.endswith('.pro')]

            if pro_files:
                template = Config.QMAKE

                if manifest and manifest.get('architecture', None) == 'all':
                    template = Config.PURE_QML_QMAKE

            if not template and 'config.xml' in directory:
                template = Config.CORDOVA

            if not template:
                template = Config.PURE

            self.template = template
            print_info('Auto detected template to be "{}"'.format(template))
Exemple #8
0
    def check_lxd(self):
        name = 'clickable-{}'.format(self.config.build_arch)

        status = ''
        try:
            status = run_subprocess_check_output(shlex.split(
                'usdk-target status {}'.format(name)),
                                                 stderr=subprocess.STDOUT)
            status = json.loads(status)['status']
        except subprocess.CalledProcessError as e:
            if e.output.strip(
            ) == 'error: Could not connect to the LXD server.' or 'Can\'t establish a working socket connection' in e.output.strip(
            ):
                started = self.start_lxd()
                if started:
                    status = 'Running'  # Pretend it's started, but we will call this function again to check if it's actually ok

                    time.sleep(3)  # Give it a sec to boot up
                    self.check_lxd()
                else:
                    raise Exception('LXD is not running, please start it')
            elif e.output.strip(
            ) == 'error: Could not query container status. error: not found':
                raise Exception(
                    'No lxd container exists to build in, please run `clickable setup-lxd`'
                )
            else:
                print(e.output)
                raise e

        if status != 'Running':
            print_info('Going to start lxd container "{}"'.format(name))
            subprocess.check_call(shlex.split('lxc start {}'.format(name)))
Exemple #9
0
    def run(self, path_arg=None):
        devices = self.device.detect_attached()

        if len(devices) == 0:
            print_warning('No attached devices')
        else:
            for device in devices:
                print_info(device)
Exemple #10
0
    def devices(self):
        devices = self.detect_devices()

        if len(devices) == 0:
            print_warning('No attached devices')
        else:
            for device in devices:
                print_info(device)
Exemple #11
0
    def run(self, path_arg=None):
        '''
        Inspired by http://bazaar.launchpad.net/~phablet-team/phablet-tools/trunk/view/head:/phablet-shell
        '''

        if self.config.ssh:
            subprocess.check_call(shlex.split('ssh phablet@{}'.format(self.config.ssh)))
        else:
            self.device.check_any_attached()

            adb_args = ''
            if self.config.device_serial_number:
                adb_args = '-s {}'.format(self.config.device_serial_number)
            else:
                self.device.check_multiple_attached()

            output = run_subprocess_check_output(shlex.split('adb {} shell pgrep sshd'.format(adb_args))).split()
            if not output:
                self.toggle_ssh(on=True)

            # Use the usb cable rather than worrying about going over wifi
            port = 0
            for p in range(2222, 2299):
                error_code = run_subprocess_call(shlex.split('adb {} forward tcp:{} tcp:22'.format(adb_args, p)), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                if error_code == 0:
                    port = p
                    break

            if port == 0:
                raise Exception('Failed to open a port to the device')

            # Purge the device host key so that SSH doesn't print a scary warning about it
            # (it changes every time the device is reflashed and this is expected)
            known_hosts = os.path.expanduser('~/.ssh/known_hosts')
            subprocess.check_call(shlex.split('touch {}'.format(known_hosts)))
            subprocess.check_call(shlex.split('ssh-keygen -f {} -R [localhost]:{}'.format(known_hosts, port)))

            id_pub = os.path.expanduser('~/.ssh/id_rsa.pub')
            if not os.path.isfile(id_pub):
                raise Exception('Could not find a ssh public key at "{}", please generate one and try again'.format(id_pub))

            with open(id_pub, 'r') as f:
                public_key = f.read().strip()

            self.device.run_command('[ -d ~/.ssh ] || mkdir ~/.ssh', cwd=self.config.cwd)
            self.device.run_command('touch  ~/.ssh/authorized_keys', cwd=self.config.cwd)

            output = run_subprocess_check_output('adb {} shell "grep \\"{}\\" ~/.ssh/authorized_keys"'.format(adb_args, public_key), shell=True).strip()
            if not output or 'No such file or directory' in output:
                print_info('Inserting ssh public key on the connected device')
                self.device.run_command('echo \"{}\" >>~/.ssh/authorized_keys'.format(public_key), cwd=self.config.cwd)
                self.device.run_command('chmod 700 ~/.ssh', cwd=self.config.cwd)
                self.device.run_command('chmod 600 ~/.ssh/authorized_keys', cwd=self.config.cwd)

            subprocess.check_call(shlex.split('ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p {} phablet@localhost'.format(port)))
            self.toggle_ssh(on=False)
Exemple #12
0
    def start_lxd(self):
        started = False
        error_code = run_subprocess_call(shlex.split('which systemctl'), stdout=subprocess.PIPE, stderr=subprocess.PIPE)

        if error_code == 0:
            print_info('Asking for root to start lxd')
            error_code = run_subprocess_call(shlex.split('sudo systemctl start lxd'))

            started = (error_code == 0)

        return started
Exemple #13
0
    def setup_docker(self):
        self.check_command('docker')
        self.start_docker()

        group_exists = False
        with open('/etc/group', 'r') as f:
            lines = f.readlines()
            for line in lines:
                if line.startswith('docker:'):
                    group_exists = True

        if not group_exists:
            print_info('Asking for root to create docker group')
            subprocess.check_call(shlex.split('sudo groupadd docker'))

        output = run_subprocess_check_output(
            shlex.split('groups {}'.format(getpass.getuser()))).strip()
        # Test for exactly docker in the group list
        if ' docker ' in output or output.endswith(
                ' docker') or output.startswith(
                    'docker ') or output == 'docker':
            print_info('Setup has already been completed')
        else:
            print_info(
                'Asking for root to add the current user to the docker group')
            subprocess.check_call(
                shlex.split('sudo usermod -aG docker {}'.format(
                    getpass.getuser())))

            print_info('Log out or restart to apply changes')
Exemple #14
0
    def start_lxd(self):
        started = False
        error_code = run_subprocess_call(shlex.split('which systemctl'),
                                         stdout=subprocess.PIPE,
                                         stderr=subprocess.PIPE)

        if error_code == 0:
            print_info('Asking for root to start lxd')
            error_code = run_subprocess_call(
                shlex.split('sudo systemctl start lxd'))

            started = (error_code == 0)

        return started
Exemple #15
0
    def run(self, path_arg=None):
        command = 'click build {} --no-validate'.format(os.path.dirname(self.config.find_manifest()))

        self.container.run_command(command)

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

            if not os.path.exists(self.config.click_output):
                os.makedirs(self.config.click_output)

            print_info('Click outputted to {}'.format(output_file))
            shutil.copyfile(click_path, output_file)
Exemple #16
0
    def run(self, path_arg=None):
        command = 'click build {} --no-validate'.format(os.path.dirname(self.config.find_manifest()))

        self.container.run_command(command)

        if self.config.click_output:
            click = self.config.get_click_filename()
            click_path = os.path.join(self.config.build_dir, click)
            output_file = os.path.join(self.config.click_output, click)

            if not os.path.exists(self.config.click_output):
                os.makedirs(self.config.click_output)

            print_info('Click outputted to {}'.format(output_file))
            shutil.copyfile(click_path, output_file)
Exemple #17
0
    def run(self, path_arg=None):
        if not cookiecutter_available:
            raise Exception('Cookiecutter is not available on your computer, more information can be found here: https://cookiecutter.readthedocs.io/en/latest/installation.html#install-cookiecutter')

        app_template = None
        if path_arg:
            for template in APP_TEMPLATES:
                if template['name'] == path_arg:
                    app_template = template

        if not app_template:
            print_info('Available app templates:')
            for (index, template) in enumerate(APP_TEMPLATES):
                print('[{}] {} - {}'.format(index + 1, template['name'], template['display']))

            choice = input('Choose an app template [1]: ').strip()
            if not choice:
                choice = '1'

            try:
                choice = int(choice)
            except ValueError:
                raise Exception('Invalid choice')

            if choice > len(APP_TEMPLATES) or choice < 1:
                raise Exception('Invalid choice')

            app_template = APP_TEMPLATES[choice - 1]

        print_info('Generating new app from template: {}'.format(app_template['display']))
        cookiecutter(app_template['url'])

        print_info('Your new app has been generated, go to the app\'s directory and run clickable to get started')
Exemple #18
0
    def click_build(self):
        command = 'click build {} --no-validate'.format(
            os.path.dirname(self.find_manifest()))

        if self.config.chroot:
            subprocess.check_call(shlex.split(command), cwd=self.config.dir)
        else:
            # Run this in the container so the host doesn't need to have click installed
            self.run_container_command(command)

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

            if not os.path.exists(self.config.click_output):
                os.makedirs(self.config.click_output)

            print_info('Click outputted to {}'.format(output_file))
            shutil.copyfile(click_path, output_file)
Exemple #19
0
    def run(self, path_arg=''):
        if not requests_available:
            raise Exception(
                'Unable to publish app, python requests module is not installed'
            )

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

        click = self.config.get_click_filename()
        click_path = os.path.join(self.config.build_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.config.find_package_name())
        channel = 'xenial' if self.config.is_xenial else 'vivid'
        files = {'file': open(click_path, 'rb')}
        data = {
            'channel': channel,
            'changelog': path_arg,
        }
        params = {'apikey': self.config.apikey}

        print_info('Uploading version {} of {} for {} to the OpenStore'.format(
            self.config.find_version(), self.config.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':
                raise Exception('Failed to upload click: Unauthorized')
            else:
                raise Exception('Failed to upload click: {}'.format(
                    response.json()['message']))
Exemple #20
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

                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])))

                container = Container(lib)
                container.setup_dependencies()

                if lib.prebuild:
                    run_subprocess_check_call(lib.prebuild, cwd=self.config.cwd, shell=True)

                self.build(lib, container)

                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))
Exemple #21
0
    def run(self, path_arg=""):

        single_lib = path_arg
        found = False

        for lib in self.config.lib_configs:
            if not single_lib or single_lib == lib.name:
                print_info("Cleaning {}".format(lib.name))
                found = True

                if os.path.exists(lib.build_dir):
                    try:
                        shutil.rmtree(lib.build_dir)
                    except Exception:
                        cls, value, traceback = sys.exc_info()
                        if cls == OSError and 'No such file or directory' in str(value):  # TODO see if there is a proper way to do this
                            pass  # Nothing to do here, the directory didn't exist
                        else:
                            print_warning('Failed to clean the build directory: {}: {}'.format(type, value))
                else:
                    print_info('Nothing to clean. Path does not exist: {}'.format(lib.build_dir))

        if single_lib and not found:
            raise ValueError('Cannot clean unknown library {}. You may add it to the clickable.json'.format(single_lib))
Exemple #22
0
    def setup_docker(self):
        print_info('Setting up docker')

        check_command('docker')
        self.start_docker()

        if not self.docker_group_exists():
            print_info('Asking for root to create docker group')
            subprocess.check_call(shlex.split('sudo groupadd docker'))

        if self.user_part_of_docker_group():
            print_info('Setup has already been completed')
        else:
            print_info('Asking for root to add the current user to the docker group')
            subprocess.check_call(shlex.split('sudo usermod -aG docker {}'.format(getpass.getuser())))

            raise Exception('Log out or restart to apply changes')
Exemple #23
0
    def setup_docker(self):
        print_info('Setting up docker')

        check_command('docker')
        self.start_docker()

        if not self.docker_group_exists():
            print_info('Asking for root to create docker group')
            subprocess.check_call(shlex.split('sudo groupadd docker'))

        if self.user_part_of_docker_group():
            print_info('Setup has already been completed')
        else:
            print_info(
                'Asking for root to add the current user to the docker group')
            subprocess.check_call(
                shlex.split('sudo usermod -aG docker {}'.format(
                    getpass.getuser())))

            raise Exception('Log out or restart to apply changes')
Exemple #24
0
    def restore_cached_container(self):
        with open(self.docker_name_file, 'r') as f:
            cached_container = f.read().strip()

            if not image_exists(cached_container):
                print_info("Cached container does not exist anymore")
                return

            command_base = 'docker images -q {}'.format(self.base_docker_image)
            command_cached = 'docker history -q {}'.format(cached_container)

            hash_base = run_subprocess_check_output(command_base).strip()
            history_cached = run_subprocess_check_output(
                command_cached).strip()

            if hash_base in history_cached:
                print_info("Found cached container")
                self.docker_image = cached_container
            else:
                print_info("Found outdated container")
Exemple #25
0
    def run(self, path_arg=None):
        if not cookiecutter_available:
            raise Exception(
                'Cookiecutter is not available on your computer, more information can be found here: https://cookiecutter.readthedocs.io/en/latest/installation.html#install-cookiecutter'
            )

        app_template = None
        if path_arg:
            for template in APP_TEMPLATES:
                if template['name'] == path_arg:
                    app_template = template

        if not app_template:
            print_info('Available app templates:')
            for (index, template) in enumerate(APP_TEMPLATES):
                print('[{}] {} - {}'.format(index + 1, template['name'],
                                            template['display']))

            choice = input('Choose an app template [1]: ').strip()
            if not choice:
                choice = '1'

            try:
                choice = int(choice)
            except ValueError:
                raise Exception('Invalid choice')

            if choice > len(APP_TEMPLATES) or choice < 1:
                raise Exception('Invalid choice')

            app_template = APP_TEMPLATES[choice - 1]

        print_info('Generating new app from template: {}'.format(
            app_template['display']))
        cookiecutter(app_template['url'])

        print_info(
            'Your new app has been generated, go to the app\'s directory and run clickable to get started'
        )
Exemple #26
0
    def setup_dependencies(self, force_build=False):
        if self.config.dependencies_build or self.config.dependencies_target:
            print_info('Checking dependencies')

            dependencies = self.config.dependencies_build
            for dep in self.config.dependencies_target:
                if ':' in dep:
                    dependencies.append(dep)
                else:
                    dependencies.append('{}:{}'.format(dep, self.config.arch))

            if self.config.lxd or self.config.container_mode:
                self.run_command('apt-get update', sudo=True, use_dir=False)

                command = 'apt-get install -y --force-yes'
                run = False
                for dep in dependencies:
                    exists = ''
                    try:
                        exists = self.run_command(
                            'dpkg -s {} | grep Status'.format(dep),
                            get_output=True,
                            use_dir=False)
                    except subprocess.CalledProcessError:
                        exists = ''

                    if exists.strip() != 'Status: install ok installed':
                        run = True
                        command = '{} {}'.format(command, dep)

                if run:
                    self.run_command(command, sudo=True, use_dir=False)
                else:
                    print_info('Dependencies already installed')
            else:  # Docker
                self.check_docker()

                if self.config.custom_docker_image:
                    print_info(
                        'Skipping dependency check, using a custom docker image'
                    )
                else:
                    command_ppa = ''
                    if self.config.dependencies_ppa:
                        command_ppa = 'RUN add-apt-repository {}'.format(
                            ' '.join(self.config.dependencies_ppa))
                    dockerfile = '''
FROM {}
RUN echo set debconf/frontend Noninteractive | debconf-communicate && echo set debconf/priority critical | debconf-communicate
{}
RUN apt-get update && apt-get install -y --force-yes --no-install-recommends {} && apt-get clean
                    '''.format(self.base_docker_image, command_ppa,
                               ' '.join(dependencies)).strip()

                    build = force_build

                    if not os.path.exists(self.clickable_dir):
                        os.makedirs(self.clickable_dir)

                    if self.docker_image != self.base_docker_image and os.path.exists(
                            self.docker_file):
                        with open(self.docker_file, 'r') as f:
                            if dockerfile.strip() != f.read().strip():
                                build = True
                    else:
                        build = True

                    if not build:
                        command = 'docker images -q {}'.format(
                            self.docker_image)
                        image_exists = run_subprocess_check_output(
                            command).strip()
                        build = not image_exists

                    if build:
                        with open(self.docker_file, 'w') as f:
                            f.write(dockerfile)

                        self.docker_image = '{}-{}'.format(
                            self.base_docker_image, uuid.uuid4())
                        with open(self.docker_name_file, 'w') as f:
                            f.write(self.docker_image)

                        print_info('Generating new docker image')
                        try:
                            subprocess.check_call(shlex.split(
                                'docker build -t {} .'.format(
                                    self.docker_image)),
                                                  cwd=self.clickable_dir)
                        except subprocess.CalledProcessError:
                            self.clean_clickable()
                            raise
                    else:
                        print_info('Dependencies already setup')
Exemple #27
0
 def build(self):
     if os.path.isdir(self.config.install_dir):
         raise ValueError('Build directory already exists. Please run "clickable clean" before building again!')
     shutil.copytree(self.config.cwd, self.config.install_dir, ignore=self._ignore)
     print_info('Copied files to install directory for click building')
Exemple #28
0
    def run_command(self,
                    command,
                    force_lxd=False,
                    sudo=False,
                    get_output=False,
                    use_dir=True,
                    cwd=None):
        wrapped_command = command
        cwd = cwd if cwd else self.config.cwd

        if self.config.container_mode:
            wrapped_command = 'bash -c "{}"'.format(command)
        elif force_lxd or self.config.lxd:
            self.check_lxd()

            target_command = 'exec'
            if sudo:
                target_command = 'maint'

            if use_dir:
                command = 'cd {}; {}'.format(self.config.dir, command)

            wrapped_command = 'usdk-target {} clickable-{} -- bash -c "{}"'.format(
                target_command, self.config.build_arch, command)
        else:  # Docker
            self.check_docker()

            if ' ' in cwd or ' ' in self.config.dir:
                raise Exception(
                    'There are spaces in the current path, this will cause errors in the build process'
                )

            if self.config.first_docker_info:
                print_info('Using docker container "{}"'.format(
                    self.docker_image))
                self.config.first_docker_info = False

            go_config = ''
            if self.config.gopath:
                go_config = '-v {}:/gopath -e GOPATH=/gopath'.format(
                    self.config.gopath)

            wrapped_command = 'docker run -v {}:{} {} -w {} -u {} -e HOME=/tmp --rm -i {} bash -c "{}"'.format(
                cwd,
                cwd,
                go_config,
                self.config.dir if use_dir else cwd,
                os.getuid(),
                self.docker_image,
                command,
            )

        kwargs = {}
        if use_dir:
            kwargs['cwd'] = self.config.dir

        if get_output:
            return run_subprocess_check_output(shlex.split(wrapped_command),
                                               **kwargs)
        else:
            subprocess.check_call(shlex.split(wrapped_command), **kwargs)
Exemple #29
0
    def setup_dependencies(self):
        if len(self.config.dependencies) > 0:
            print_info('Checking dependencies')

            if self.config.lxd or self.config.container_mode:
                command = 'apt-get install -y --force-yes'
                run = False
                for dep in self.config.dependencies:
                    if self.config.arch == 'armhf' and 'armhf' not in dep and not self.config.specificDependencies:
                        dep = '{}:{}'.format(dep, self.config.arch)

                    exists = ''
                    try:
                        exists = self.run_command(
                            'dpkg -s {} | grep Status'.format(dep),
                            get_output=True,
                            use_dir=False)
                    except subprocess.CalledProcessError:
                        exists = ''

                    if exists.strip() != 'Status: install ok installed':
                        run = True
                        command = '{} {}'.format(command, dep)

                if run:
                    self.run_command(command, sudo=True, use_dir=False)
                else:
                    print_info('Dependencies already installed')
            else:  # Docker
                self.check_docker()

                # TODO make the path to the dockerfile arch dependent

                if self.config.custom_docker_image:
                    print_info(
                        'Skipping dependency check, using a custom docker image'
                    )
                else:
                    dependencies = ''
                    for dep in self.config.dependencies:
                        if self.config.arch == 'armhf' and 'armhf' not in dep and not self.config.specificDependencies:
                            dependencies = '{} {}:{}'.format(
                                dependencies, dep, self.config.arch)
                        else:
                            dependencies = '{} {}'.format(dependencies, dep)

                    dockerfile = '''
FROM {}
RUN echo set debconf/frontend Noninteractive | debconf-communicate && echo set debconf/priority critical | debconf-communicate
RUN apt-get update && apt-get install -y --force-yes --no-install-recommends {} && apt-get clean
                    '''.format(self.base_docker_image, dependencies).strip()

                    build = False

                    if not os.path.exists('.clickable'):
                        os.makedirs('.clickable')

                    if os.path.exists('.clickable/Dockerfile'):
                        with open('.clickable/Dockerfile', 'r') as f:
                            if dockerfile.strip() != f.read().strip():
                                build = True
                    else:
                        build = True

                    if not build:
                        command = 'docker images -q {}'.format(
                            self.docker_image)
                        image_exists = run_subprocess_check_output(
                            command).strip()
                        build = not image_exists

                    if build:
                        with open('.clickable/Dockerfile', 'w') as f:
                            f.write(dockerfile)

                        self.docker_image = '{}-{}'.format(
                            self.base_docker_image, uuid.uuid4())
                        with open('.clickable/name.txt', 'w') as f:
                            f.write(self.docker_image)

                        print_info('Generating new docker image')
                        try:
                            subprocess.check_call(shlex.split(
                                'docker build -t {} .'.format(
                                    self.docker_image)),
                                                  cwd='.clickable')
                        except subprocess.CalledProcessError:
                            self.clean_clickable()
                            raise
                    else:
                        print_info('Dependencies already setup')
Exemple #30
0
    def run(self, path_arg=None):
        '''
        Inspired by http://bazaar.launchpad.net/~phablet-team/phablet-tools/trunk/view/head:/phablet-shell
        '''

        if self.config.ssh:
            subprocess.check_call(
                shlex.split('ssh phablet@{}'.format(self.config.ssh)))
        else:
            self.device.check_any_attached()

            adb_args = ''
            if self.config.device_serial_number:
                adb_args = '-s {}'.format(self.config.device_serial_number)
            else:
                self.device.check_multiple_attached()

            output = run_subprocess_check_output(
                shlex.split(
                    'adb {} shell pgrep sshd'.format(adb_args))).split()
            if not output:
                self.toggle_ssh(on=True)

            # Use the usb cable rather than worrying about going over wifi
            port = 0
            for p in range(2222, 2299):
                error_code = run_subprocess_call(shlex.split(
                    'adb {} forward tcp:{} tcp:22'.format(adb_args, p)),
                                                 stdout=subprocess.PIPE,
                                                 stderr=subprocess.PIPE)
                if error_code == 0:
                    port = p
                    break

            if port == 0:
                raise Exception('Failed to open a port to the device')

            # Purge the device host key so that SSH doesn't print a scary warning about it
            # (it changes every time the device is reflashed and this is expected)
            known_hosts = os.path.expanduser('~/.ssh/known_hosts')
            subprocess.check_call(shlex.split('touch {}'.format(known_hosts)))
            subprocess.check_call(
                shlex.split('ssh-keygen -f {} -R [localhost]:{}'.format(
                    known_hosts, port)))

            id_pub = os.path.expanduser('~/.ssh/id_rsa.pub')
            if not os.path.isfile(id_pub):
                raise Exception(
                    'Could not find a ssh public key at "{}", please generate one and try again'
                    .format(id_pub))

            with open(id_pub, 'r') as f:
                public_key = f.read().strip()

            self.device.run_command('[ -d ~/.ssh ] || mkdir ~/.ssh',
                                    cwd=self.config.cwd)
            self.device.run_command('touch  ~/.ssh/authorized_keys',
                                    cwd=self.config.cwd)

            output = run_subprocess_check_output(
                'adb {} shell "grep \\"{}\\" ~/.ssh/authorized_keys"'.format(
                    adb_args, public_key),
                shell=True).strip()
            if not output or 'No such file or directory' in output:
                print_info('Inserting ssh public key on the connected device')
                self.device.run_command(
                    'echo \"{}\" >>~/.ssh/authorized_keys'.format(public_key),
                    cwd=self.config.cwd)
                self.device.run_command('chmod 700 ~/.ssh',
                                        cwd=self.config.cwd)
                self.device.run_command('chmod 600 ~/.ssh/authorized_keys',
                                        cwd=self.config.cwd)

            subprocess.check_call(
                shlex.split(
                    'ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p {} phablet@localhost'
                    .format(port)))
            self.toggle_ssh(on=False)
Exemple #31
0
    def run_command(self,
                    command,
                    force_lxd=False,
                    sudo=False,
                    get_output=False,
                    use_dir=True,
                    cwd=None):
        wrapped_command = command
        cwd = cwd if cwd else os.path.abspath(self.config.root_dir)

        if self.config.container_mode:
            wrapped_command = 'bash -c "{}"'.format(command)
        elif force_lxd or self.config.lxd:
            self.check_lxd()

            target_command = 'exec'
            if sudo:
                target_command = 'maint'

            if use_dir:
                command = 'cd {}; {}'.format(self.config.build_dir, command)

            wrapped_command = 'usdk-target {} clickable-{} -- bash -c "{}"'.format(
                target_command, self.config.build_arch, command)
        else:  # Docker
            self.check_docker()

            if ' ' in cwd or ' ' in self.config.build_dir:
                raise Exception(
                    'There are spaces in the current path, this will cause errors in the build process'
                )

            if self.config.first_docker_info:
                print_info('Using docker container "{}"'.format(
                    self.docker_image))
                self.config.first_docker_info = False

            go_config = ''
            if self.config.gopath:
                gopaths = self.config.gopath.split(':')

                docker_gopaths = []
                go_configs = []
                for (index, path) in enumerate(gopaths):
                    go_configs.append('-v {}:/gopath/path{}:Z'.format(
                        path, index))
                    docker_gopaths.append('/gopath/path{}'.format(index))

                go_config = '{} -e GOPATH={}'.format(
                    ' '.join(go_configs),
                    ':'.join(docker_gopaths),
                )

            rust_config = ''

            if self.config.config[
                    'template'] == Config.RUST and self.config.cargo_home:
                cargo_registry = os.path.join(self.config.cargo_home,
                                              'registry')
                cargo_git = os.path.join(self.config.cargo_home, 'git')
                cargo_package_cache_lock = os.path.join(
                    self.config.cargo_home, '.package-cache')

                os.makedirs(cargo_registry, exist_ok=True)
                os.makedirs(cargo_git, exist_ok=True)

                # create .package-cache if it doesn't exist
                with open(cargo_package_cache_lock, "a"):
                    pass

                rust_config = '-v {}:/opt/rust/cargo/registry:Z -v {}:/opt/rust/cargo/git:Z -v {}:/opt/rust/cargo/.package-cache'.format(
                    cargo_registry,
                    cargo_git,
                    cargo_package_cache_lock,
                )

            wrapped_command = 'docker run -v {}:{}:Z {} {} -w {} -u {} -e HOME=/tmp --rm -i {} bash -c "{}"'.format(
                cwd,
                cwd,
                go_config,
                rust_config,
                self.config.build_dir if use_dir else cwd,
                os.getuid(),
                self.docker_image,
                command,
            )

        kwargs = {}
        if use_dir:
            kwargs['cwd'] = self.config.build_dir

        if get_output:
            return run_subprocess_check_output(shlex.split(wrapped_command),
                                               **kwargs)
        else:
            subprocess.check_call(shlex.split(wrapped_command), **kwargs)
Exemple #32
0
 def _build(self):
     shutil.copytree(self.cwd, self.temp, ignore=self._ignore)
     print_info('Copied files to temp directory for click building')
Exemple #33
0
    def setup_dependencies(self):
        if self.config.dependencies_build or self.config.dependencies_target:
            print_info('Checking dependencies')

            dependencies = self.config.dependencies_build
            for dep in self.config.dependencies_target:
                if ':' in dep:
                    dependencies.append(dep)
                else:
                    dependencies.append('{}:{}'.format(dep, self.config.arch))

            if self.config.lxd or self.config.container_mode:
                self.run_command('apt-get update', sudo=True, use_dir=False)

                command = 'apt-get install -y --force-yes'
                run = False
                for dep in dependencies:
                    exists = ''
                    try:
                        exists = self.run_command('dpkg -s {} | grep Status'.format(dep), get_output=True, use_dir=False)
                    except subprocess.CalledProcessError:
                        exists = ''

                    if exists.strip() != 'Status: install ok installed':
                        run = True
                        command = '{} {}'.format(command, dep)

                if run:
                    self.run_command(command, sudo=True, use_dir=False)
                else:
                    print_info('Dependencies already installed')
            else:  # Docker
                self.check_docker()

                if self.config.custom_docker_image:
                    print_info('Skipping dependency check, using a custom docker image')
                else:
                    command_ppa = ''
                    if self.config.dependencies_ppa:
                        command_ppa = 'RUN add-apt-repository {}'.format(' '.join(self.config.dependencies_ppa))
                    dockerfile = '''
FROM {}
RUN echo set debconf/frontend Noninteractive | debconf-communicate && echo set debconf/priority critical | debconf-communicate
{}
RUN apt-get update && apt-get install -y --force-yes --no-install-recommends {} && apt-get clean
                    '''.format(
                        self.base_docker_image,
                        command_ppa,
                        ' '.join(dependencies)
                    ).strip()

                    build = False

                    if not os.path.exists(self.clickableDir):
                        os.makedirs(self.clickableDir)

                    if os.path.exists(self.dockerFile):
                        with open(self.dockerFile, 'r') as f:
                            if dockerfile.strip() != f.read().strip():
                                build = True
                    else:
                        build = True

                    if not build:
                        command = 'docker images -q {}'.format(self.docker_image)
                        image_exists = run_subprocess_check_output(command).strip()
                        build = not image_exists

                    if build:
                        with open(self.dockerFile, 'w') as f:
                            f.write(dockerfile)

                        self.docker_image = '{}-{}'.format(self.base_docker_image, uuid.uuid4())
                        with open(self.dockerNameFile, 'w') as f:
                            f.write(self.docker_image)

                        print_info('Generating new docker image')
                        try:
                            subprocess.check_call(shlex.split('docker build -t {} .'.format(self.docker_image)), cwd=self.clickableDir)
                        except subprocess.CalledProcessError:
                            self.clean_clickable()
                            raise
                    else:
                        print_info('Dependencies already setup')
Exemple #34
0
 def writable_image(self):
     command = 'dbus-send --system --print-reply --dest=com.canonical.PropertyService /com/canonical/PropertyService com.canonical.PropertyService.SetProperty string:writable boolean:true'
     self.run_device_command(command, cwd=self.cwd)
     print_info('Rebooting for writable image')
Exemple #35
0
    def init_app(self, name=None):
        if not cookiecutter_available:
            raise Exception(
                'Cookiecutter is not available on your computer, more information can be found here: https://cookiecutter.readthedocs.io/en/latest/installation.html#install-cookiecutter'
            )

        app_templates = [{
            'name':
            'pure-qml-cmake',
            'display':
            'Pure QML App (built using CMake)',
            'url':
            'https://github.com/bhdouglass/ut-app-pure-qml-cmake-template',
        }, {
            'name':
            'cmake',
            'display':
            'C++/QML App (built using CMake)',
            'url':
            'https://github.com/bhdouglass/ut-app-cmake-template',
        }, {
            'name':
            'python-cmake',
            'display':
            'Python/QML App (built using CMake)',
            'url':
            'https://github.com/bhdouglass/ut-app-python-cmake-template',
        }, {
            'name':
            'html',
            'display':
            'HTML App',
            'url':
            'https://github.com/bhdouglass/ut-app-html-template',
        }, {
            'name':
            'webapp',
            'display':
            'Simple Webapp',
            'url':
            'https://github.com/bhdouglass/ut-app-webapp-template',
        }, {
            'name':
            'go',
            'display':
            'Go/QML App',
            'url':
            'https://github.com/bhdouglass/ut-app-go-template',
        }]

        app_template = None
        if name:
            for template in app_templates:
                if template['name'] == name:
                    app_template = template

        if not app_template:
            print_info('Available app templates:')
            for (index, template) in enumerate(app_templates):
                print('[{}] {} - {}'.format(index + 1, template['name'],
                                            template['display']))

            choice = input('Choose an app template [1]: ').strip()
            if not choice:
                choice = '1'

            try:
                choice = int(choice)
            except ValueError:
                raise Exception('Invalid choice')

            if choice > len(app_templates) or choice < 1:
                raise Exception('Invalid choice')

            app_template = app_templates[choice - 1]

        print_info('Generating new app from template: {}'.format(
            app_template['display']))
        cookiecutter(app_template['url'])

        print_info(
            'Your new app has been generated, go to the app\'s directory and run clickable to get started'
        )
Exemple #36
0
 def build(self):
     shutil.copytree(self.config.cwd, self.config.temp, ignore=self._ignore)
     print_info('Copied files to temp directory for click building')
Exemple #37
0
    def run_command(self, command, force_lxd=False, sudo=False, get_output=False, use_dir=True, cwd=None):
        wrapped_command = command
        cwd = cwd if cwd else os.path.abspath(self.config.root_dir)

        if self.config.container_mode:
            wrapped_command = 'bash -c "{}"'.format(command)
        elif force_lxd or self.config.lxd:
            self.check_lxd()

            target_command = 'exec'
            if sudo:
                target_command = 'maint'

            if use_dir:
                command = 'cd {}; {}'.format(self.config.build_dir, command)

            wrapped_command = 'usdk-target {} clickable-{} -- bash -c "{}"'.format(target_command, self.config.build_arch, command)
        else:  # Docker
            self.check_docker()

            if ' ' in cwd or ' ' in self.config.build_dir:
                raise Exception('There are spaces in the current path, this will cause errors in the build process')

            if self.config.first_docker_info:
                print_info('Using docker container "{}"'.format(self.docker_image))
                self.config.first_docker_info = False

            go_config = ''
            if self.config.gopath:
                gopaths = self.config.gopath.split(':')

                docker_gopaths = []
                go_configs = []
                for (index, path) in enumerate(gopaths):
                    go_configs.append('-v {}:/gopath/path{}:Z'.format(path, index))
                    docker_gopaths.append('/gopath/path{}'.format(index))

                go_config = '{} -e GOPATH={}'.format(
                    ' '.join(go_configs),
                    ':'.join(docker_gopaths),
                )

            rust_config = ''

            if self.config.config['template'] == Config.RUST and self.config.cargo_home:
                cargo_registry = os.path.join(self.config.cargo_home, 'registry')
                cargo_git = os.path.join(self.config.cargo_home, 'git')

                os.makedirs(cargo_registry, exist_ok=True)
                os.makedirs(cargo_git, exist_ok=True)

                rust_config = '-v {}:/opt/rust/cargo/registry:Z -v {}:/opt/rust/cargo/git:Z'.format(
                    cargo_registry,
                    cargo_git,
                )

            wrapped_command = 'docker run -v {}:{}:Z {} {} -w {} -u {} -e HOME=/tmp --rm -i {} bash -c "{}"'.format(
                cwd,
                cwd,
                go_config,
                rust_config,
                self.config.build_dir if use_dir else cwd,
                os.getuid(),
                self.docker_image,
                command,
            )

        kwargs = {}
        if use_dir:
            kwargs['cwd'] = self.config.build_dir

        if get_output:
            return run_subprocess_check_output(shlex.split(wrapped_command), **kwargs)
        else:
            subprocess.check_call(shlex.split(wrapped_command), **kwargs)
Exemple #38
0
 def no_lock(self):
     print_info('Turning off device activity timeout')
     command = 'gsettings set com.ubuntu.touch.system activity-timeout 0'
     self.run_device_command(command, cwd=self.cwd)
Exemple #39
0
 def run(self, path_arg=None):
     print_info('Turning off device activity timeout')
     command = 'gsettings set com.ubuntu.touch.system activity-timeout 0'
     self.device.run_command(command, cwd=self.config.cwd)
Exemple #40
0
 def run(self, path_arg=None):
     command = 'dbus-send --system --print-reply --dest=com.canonical.PropertyService /com/canonical/PropertyService com.canonical.PropertyService.SetProperty string:writable boolean:true'
     self.device.run_command(command, cwd=self.config.cwd)
     print_info('Rebooting device for writable image')