Example #1
0
def create_snap_packaging(project_config: _config.Config) -> str:
    """Create snap.yaml and related assets in meta.

    Create the meta directory and provision it with snap.yaml in the snap dir
    using information from config_data. Also copy in the local 'snap'
    directory, and generate wrappers for hooks coming from parts.

    :param dict config_data: project values defined in snapcraft.yaml.
    :return: meta_dir.
    """

    # Update config_data using metadata extracted from the project
    _update_yaml_with_extracted_metadata(project_config.data,
                                         project_config.parts)

    # Now that we've updated config_data with random stuff extracted from
    # parts, re-validate it to ensure the it still conforms with the schema.
    validator = project_loader.Validator(project_config.data)
    validator.validate(source="properties")

    # Update default values
    _update_yaml_with_defaults(project_config.data,
                               project_config.validator.schema)

    # Ensure the YAML contains all required keywords before continuing to
    # use it to generate the snap.yaml.
    _ensure_required_keywords(project_config.data)

    packaging = _SnapPackaging(project_config)
    packaging.write_snap_yaml()
    packaging.setup_assets()
    packaging.generate_hook_wrappers()
    packaging.write_snap_directory()

    return packaging.meta_dir
Example #2
0
    def make_snapcraft_yaml(self, n=1, create=True):
        parts = '\n'.join([self.yaml_part.format(i) for i in range(n)])
        super().make_snapcraft_yaml(self.yaml_template.format(parts=parts))
        open('icon.png', 'w').close()

        parts = []
        validator = project_loader.Validator()
        for i in range(n):
            part_name = 'clean{}'.format(i)
            handler = pluginhandler.load_plugin(
                part_name, plugin_name='nil',
                part_properties={'plugin': 'nil'},
                part_schema=validator.part_schema,
                definitions_schema=validator.definitions_schema)
            parts.append({
                'part_dir': handler.code.partdir,
            })

            if create:
                handler.makedirs()
                open(os.path.join(
                    handler.code.installdir, part_name), 'w').close()

                handler.mark_done('pull')
                handler.mark_done('build')

                handler.stage()
                handler.prime()

        return parts
Example #3
0
    def test_license_version_without_license_raises_exception(self):
        self.data['license-version'] = '1.1'

        with self.assertRaises(SnapcraftSchemaError) as raised:
            project_loader.Validator(self.data).validate()

        expected_message = "'license' is a dependency of 'license-version'"
        self.assertEqual(raised.exception.message, expected_message,
                         msg=self.data)
Example #4
0
    def test_summary_too_long(self):
        self.data['summary'] = 'a' * 80
        with self.assertRaises(SnapcraftSchemaError) as raised:
            project_loader.Validator(self.data).validate()

        expected_message = (
            "The 'summary' property does not match the required schema: "
            "'{}' is too long").format(self.data['summary'])
        self.assertEqual(raised.exception.message, expected_message,
                         msg=self.data)
Example #5
0
    def test_invalid_part_name_plugin_raises_exception(self):
        self.data['parts']['plugins'] = {'type': 'go'}

        with self.assertRaises(SnapcraftSchemaError) as raised:
            project_loader.Validator(self.data).validate()

        expected_message = ("The 'parts' property does not match the "
                            "required schema: Additional properties are not "
                            "allowed ('plugins' was unexpected)")
        self.assertEqual(raised.exception.message, expected_message,
                         msg=self.data)
Example #6
0
    def test_valid_types(self):
        valid_types = [
            'app',
            'kernel',
            'os',
        ]

        for t in valid_types:
            data = self.data.copy()
            with self.subTest(key=t):
                project_loader.Validator(data).validate()
Example #7
0
    def setUp(self):
        super().setUp()
        dirs.setup_dirs()

        patcher = unittest.mock.patch(
            'snapcraft.internal.project_loader._get_snapcraft_yaml')
        self.mock_get_yaml = patcher.start()
        self.mock_get_yaml.return_value = 'snapcraft.yaml'
        self.addCleanup(patcher.stop)
        self.part_schema = project_loader.Validator().part_schema
        self.deb_arch = snapcraft.ProjectOptions().deb_arch
Example #8
0
    def test_apps_required_properties(self):
        self.data['apps'] = {'service1': {}}

        with self.assertRaises(SnapcraftSchemaError) as raised:
            project_loader.Validator(self.data).validate()

        expected_message = ("The 'service1' property does not match the "
                            "required schema: 'command' is a required "
                            "property")
        self.assertEqual(raised.exception.message, expected_message,
                         msg=self.data)
Example #9
0
    def test_required_properties(self):
        for key in self.data:
            data = self.data.copy()
            with self.subTest(key=key):
                del data[key]

                with self.assertRaises(SnapcraftSchemaError) as raised:
                    project_loader.Validator(data).validate()

                expected_message = '\'{}\' is a required property'.format(key)
                self.assertEqual(raised.exception.message, expected_message,
                                 msg=data)
Example #10
0
    def test_schema_file_not_found(self):
        mock_the_open = unittest.mock.mock_open()
        mock_the_open.side_effect = FileNotFoundError()

        with unittest.mock.patch('snapcraft._schema.open',
                                 mock_the_open, create=True):
            with self.assertRaises(SnapcraftSchemaError) as raised:
                project_loader.Validator(self.data).validate()

        expected_message = ('snapcraft validation file is missing from '
                            'installation path')
        self.assertEqual(raised.exception.message, expected_message)
Example #11
0
    def test_valid_restart_conditions(self):
        self.data['apps'] = {
            'service1': {
                'command': 'binary1',
                'daemon': 'simple',
            }
        }
        valid_conditions = ['always', 'on-success', 'on-failure',
                            'on-abnormal', 'on-abort', 'never']

        for condition in valid_conditions:
            with self.subTest(key=condition):
                self.data['apps']['service1']['restart-condition'] = condition
                project_loader.Validator(self.data).validate()
Example #12
0
    def test_invalid_restart_condition(self):
        self.data['apps'] = {
            'service1': {
                'command': 'binary1',
                'daemon': 'simple',
                'restart-condition': 'on-watchdog',
            }
        }

        with self.assertRaises(SnapcraftSchemaError) as raised:
            project_loader.Validator(self.data).validate()

        self.assertEqual(
            "The 'restart-condition' property does not match the required "
            "schema: 'on-watchdog' is not one of ['on-success', "
            "'on-failure', 'on-abnormal', 'on-abort', 'always', 'never']",
            str(raised.exception))
Example #13
0
def loadplugin(part_name,
               plugin_name=None,
               part_properties=None,
               project_options=None):
    if not plugin_name:
        plugin_name = 'nil'
    properties = {'plugin': plugin_name}
    if part_properties:
        properties.update(part_properties)
    if not project_options:
        project_options = snapcraft.ProjectOptions()

    schema = project_loader.Validator().part_schema
    return pluginhandler.load_plugin(part_name=part_name,
                                     plugin_name=plugin_name,
                                     part_properties=properties,
                                     project_options=project_options,
                                     part_schema=schema)
Example #14
0
    def setUp(self):
        super().setUp()
        dirs.setup_dirs()

        patcher = unittest.mock.patch(
            'snapcraft.internal.project_loader.get_snapcraft_yaml')
        self.mock_get_yaml = patcher.start()
        self.mock_get_yaml.return_value = os.path.join('snap',
                                                       'snapcraft.yaml')
        self.addCleanup(patcher.stop)

        patcher = unittest.mock.patch(
            'snapcraft.internal.project_loader._parts_config.PartsConfig'
            '.load_part')
        self.mock_plugin_loader = patcher.start()
        self.addCleanup(patcher.stop)

        self.part_schema = project_loader.Validator().part_schema
        self.deb_arch = snapcraft.ProjectOptions().deb_arch
Example #15
0
    def test_invalid_names(self):
        invalid_names = [
            'package@awesome',
            'something.another',
            '_hideme',
        ]

        for name in invalid_names:
            data = self.data.copy()
            with self.subTest(key=name):
                data['name'] = name

                with self.assertRaises(SnapcraftSchemaError) as raised:
                    project_loader.Validator(data).validate()

                expected_message = ("The 'name' property does not match the "
                                    "required schema: '{}' does not match "
                                    "'^[a-z0-9][a-z0-9+-]*$'").format(name)
                self.assertEqual(raised.exception.message, expected_message,
                                 msg=data)
Example #16
0
    def test_valid_app_daemons(self):
        self.data['apps'] = {
            'service1': {'command': 'binary1 start', 'daemon': 'simple'},
            'service2': {
                'command': 'binary2',
                'stop-command': 'binary2 --stop',
                'daemon': 'simple'
            },
            'service3': {
                'command': 'binary3',
                'daemon': 'forking',
            },
            'service4': {
                'command': 'binary4',
                'daemon': 'simple',
                'restart-condition': 'always',
            }
        }

        project_loader.Validator(self.data).validate()
Example #17
0
    def test_invalid_types(self):
        invalid_types = [
            'apps',
            'framework',
            'platform',
            'oem',
        ]

        for t in invalid_types:
            data = self.data.copy()
            with self.subTest(key=t):
                data['type'] = t

                with self.assertRaises(SnapcraftSchemaError) as raised:
                    project_loader.Validator(data).validate()

                expected_message = (
                    "The 'type' property does not match the required "
                    "schema: '{}' is not one of "
                    "['app', 'kernel', 'os']").format(t)
                self.assertEqual(raised.exception.message, expected_message,
                                 msg=data)
Example #18
0
    def test_invalid_app_names(self):
        invalid_names = {
            'qwe#rty': {'command': '1'},
            'qwe_rty': {'command': '1'},
            'que rty': {'command': '1'},
            'que  rty': {'command': '1'},
        }

        for t in invalid_names:
            data = self.data.copy()
            with self.subTest(key=t):
                data['apps'] = {t: invalid_names[t]}

                with self.assertRaises(SnapcraftSchemaError) as raised:
                    project_loader.Validator(data).validate()

                expected_message = (
                    "The 'apps' property does not match the required "
                    "schema: Additional properties are not allowed ('{}' "
                    "was unexpected)").format(t)
                self.assertEqual(raised.exception.message, expected_message,
                                 msg=data)
Example #19
0
    def test_license_with_license_version(self):
        self.data['license'] = 'LICENSE'
        self.data['license-version'] = '1.0'

        project_loader.Validator(self.data).validate()
Example #20
0
    def test_full_license_use(self):
        self.data['license'] = 'LICENSE'
        self.data['license-agreement'] = 'explicit'
        self.data['license-version'] = '1.0'

        project_loader.Validator(self.data).validate()
Example #21
0
    def test_license_hook(self):
        self.data['license'] = 'LICENSE'

        project_loader.Validator(self.data).validate()
Example #22
0
    def test_icon_missing_is_valid_yaml(self):
        self.mock_path_exists.return_value = False

        project_loader.Validator(self.data).validate()