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
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
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)
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)
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)
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()
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
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)
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)
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)
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()
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))
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)
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
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)
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()
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)
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)
def test_license_with_license_version(self): self.data['license'] = 'LICENSE' self.data['license-version'] = '1.0' project_loader.Validator(self.data).validate()
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()
def test_license_hook(self): self.data['license'] = 'LICENSE' project_loader.Validator(self.data).validate()
def test_icon_missing_is_valid_yaml(self): self.mock_path_exists.return_value = False project_loader.Validator(self.data).validate()