Example #1
0
    def __init__(self, project: project.Project) -> None:
        self.build_snaps: Set[str] = set()
        self.project = project

        # raw_snapcraft_yaml is read only, create a new copy
        snapcraft_yaml = apply_extensions(project.info.get_raw_snapcraft())

        self.validator = Validator(snapcraft_yaml)
        self.validator.validate()

        snapcraft_yaml = self._expand_filesets(snapcraft_yaml)

        self.data = self._expand_env(snapcraft_yaml)

        self.data["architectures"] = _process_architectures(
            self.data.get("architectures"), project.deb_arch)

        self._ensure_no_duplicate_app_aliases()

        self._global_grammar_processor = grammar_processing.GlobalGrammarProcessor(
            properties=self.data, project=project)

        # XXX: Resetting snap_meta due to above mangling of data.
        # Convergence to operating on snap_meta will remove this requirement...
        project._snap_meta = Snap.from_dict(self.data)

        self.parts = PartsConfig(parts=self.data,
                                 project=project,
                                 validator=self.validator)
Example #2
0
    def __init__(self, project: project.Project) -> None:
        self.build_snaps: Set[str] = set()
        self.project = project

        # raw_snapcraft_yaml is read only, create a new copy
        snapcraft_yaml = apply_extensions(project.info.get_raw_snapcraft())

        self.validator = Validator(snapcraft_yaml)
        self.validator.validate()

        snapcraft_yaml = self._expand_filesets(snapcraft_yaml)

        self.data = self._expand_env(snapcraft_yaml)

        self.data["architectures"] = _process_architectures(
            self.data.get("architectures"), project.deb_arch)

        self._ensure_no_duplicate_app_aliases()

        grammar_processor = grammar_processing.GlobalGrammarProcessor(
            properties=self.data, project=project)

        self.build_tools = grammar_processor.get_build_packages()
        self.build_tools |= set(project.additional_build_packages)

        # If version: git is used we want to add "git" to build-packages
        if self.data.get("version") == "git":
            self.build_tools.add("git")

        # XXX: Resetting snap_meta due to above mangling of data.
        # Convergence to operating on snap_meta will remove this requirement...
        project._snap_meta = Snap.from_dict(self.data)

        # Always add the base for building for non os and base snaps
        if project.info.base is None and project.info.type in ("app",
                                                               "gadget"):
            raise SnapcraftEnvironmentError(
                "A base is required for snaps of type {!r}.".format(
                    project.info.type))
        if project.info.base is not None:
            # If the base is already installed by other means, skip its installation.
            # But, we should always add it when in a docker environment so
            # the creator of said docker image is aware that it is required.
            if common.is_process_container(
            ) or not repo.snaps.SnapPackage.is_snap_installed(
                    project.info.base):
                self.build_snaps.add(project.info.base)

        self.parts = PartsConfig(
            parts=self.data,
            project=project,
            validator=self.validator,
            build_snaps=self.build_snaps,
            build_tools=self.build_tools,
        )
Example #3
0
    def __init__(self, project: project.Project) -> None:
        self.build_snaps = set()  # type: Set[str]
        self.project = project

        # raw_snapcraft_yaml is read only, create a new copy
        snapcraft_yaml = apply_extensions(project.info.get_raw_snapcraft())

        self.validator = Validator(snapcraft_yaml)
        self.validator.validate()

        snapcraft_yaml = self._expand_filesets(snapcraft_yaml)

        self.data = self._expand_env(snapcraft_yaml)
        self._ensure_no_duplicate_app_aliases()

        grammar_processor = grammar_processing.GlobalGrammarProcessor(
            properties=self.data, project=project)

        self.build_tools = grammar_processor.get_build_packages()
        self.build_tools |= set(project.additional_build_packages)

        # If version: git is used we want to add "git" to build-packages
        if self.data.get("version") == "git":
            self.build_tools.add("git")

        # Always add the base for building for non os and base snaps
        if project.info.base is not None and project.info.type not in ("base",
                                                                       "os"):
            # If the base is already installed by other means, skip its installation.
            # But, we should always add it when in a docker environment so
            # the creator of said docker image is aware that it is required.
            if common.is_docker_instance(
            ) or not repo.snaps.SnapPackage.is_snap_installed(
                    project.info.base):
                self.build_snaps.add(project.info.base)
        elif project.info.type not in ("base", "os"):
            # This exception is here to help with porting issues with bases. In normal
            # executions, when no base is set, the legacy snapcraft will be executed.
            raise RuntimeError("A base is required for {!r} snaps.".format(
                project.info.type))

        self.parts = PartsConfig(
            parts=self.data,
            project=project,
            validator=self.validator,
            build_snaps=self.build_snaps,
            build_tools=self.build_tools,
        )

        self.data["architectures"] = _process_architectures(
            self.data.get("architectures"), project.deb_arch)

        conduct_environment_sanity_check(self.project, self.data,
                                         self.validator.schema)
Example #4
0
def test_required_properties(data, key):
    del data[key]

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    assert f"{key!r} is a required property" in str(error.value)
Example #5
0
def test_type_base_and_base(data):
    data["type"] = "base"

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    assert _BASE_TYPE_MSG in str(error.value)
Example #6
0
    def test_invalid(self, data, packages, message_contains):
        data["package-repositories"] = packages

        with pytest.raises(errors.YamlValidationError) as error:
            Validator(data).validate()

        assert message_contains in str(error.value)
Example #7
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",
            },
            "service5": {"command": "binary5", "daemon": "notify"},
            "service6": {
                "command": "binary6",
                "post-stop-command": "binary6 --post-stop",
                "daemon": "simple",
            },
            "service7": {
                "command": "binary7",
                "reload-command": "binary7 --reload",
                "daemon": "simple",
            },
        }

        Validator(self.data).validate()
Example #8
0
def test_invalid_title(data, title, error_template):
    data["title"] = title

    with pytest.raises(snapcraft.yaml_utils.errors.YamlValidationError) as error:
        Validator(data).validate()

    assert _EXPECTED_ERROR_TEMPLATE[error_template].format(title) in str(error.value)
Example #9
0
    def test(self, data, architectures, message):
        data["architectures"] = architectures

        with pytest.raises(errors.YamlValidationError) as error:
            Validator(data).validate()

        assert message in str(error.value)
Example #10
0
def test_invalid_adapter(data, adapter):
    data["apps"] = {"foo": {"command": "foo", "adapter": adapter}}

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = "The 'apps/foo/adapter' property does not match"
    assert expected_message in str(error.value)
Example #11
0
def test_invalid_yaml_invalid_username(data):
    data["system-usernames"] = {"snap_user": "******"}
    with pytest.raises(
            snapcraft.yaml_utils.errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = "The 'system-usernames' property does not match the required schema: 'snap_user' is not a valid system-username."
    assert expected_message in str(error.value)
Example #12
0
def test_invalid_yaml_invalid_long_scope(data):
    data["system-usernames"] = {"snap_daemon": {"scope": "invalid-scope"}}
    with pytest.raises(
            snapcraft.yaml_utils.errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = "The 'system-usernames/snap_daemon' property does not match the required schema: {'scope': 'invalid-scope'} is not valid under any of the given schemas"
    assert expected_message in str(error.value)
Example #13
0
    def test_required_properties(self):
        data = self.data.copy()
        del data[self.key]

        raised = self.assertRaises(errors.YamlValidationError, Validator(data).validate)

        expected_message = "'{}' is a required property".format(self.key)
        self.assertThat(raised.message, Equals(expected_message), message=data)
Example #14
0
def test_invalid_command_chain(data, command_chain):
    data["apps"] = {"foo": {"command": "foo", "command-chain": command_chain}}

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = "The 'apps/foo/command-chain"
    assert expected_message in str(error.value)
Example #15
0
 def test_valid_modes(self):
     self.data["apps"] = {
         "service1": {
             "command": "binary1",
             "daemon": "simple",
             "stop-mode": self.mode,
         }
     }
     Validator(self.data).validate()
Example #16
0
 def test_valid_restart_conditions(self):
     self.data["apps"] = {
         "service1": {
             "command": "binary1",
             "daemon": "simple"
         }
     }
     self.data["apps"]["service1"]["restart-condition"] = self.condition
     Validator(self.data).validate()
Example #17
0
def test_invalid_grade(data, grade):
    data["grade"] = grade

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = ("The 'grade' property does not match the required "
                        f"schema: {grade!r} is not one of ['stable', 'devel']")
    assert expected_message in str(error.value)
Example #18
0
def test_valid_modes(data, mode):
    data["apps"] = {
        "service1": {
            "command": "binary1",
            "daemon": "simple",
            "stop-mode": mode
        }
    }
    Validator(data).validate()
Example #19
0
    def test(self, data, name, err):
        data["name"] = name

        with pytest.raises(errors.YamlValidationError) as error:
            Validator(data).validate()

        assert str(error.value).endswith(
            f"The 'name' property does not match the required schema: {name!r} is {err}"
        )
Example #20
0
def test_daemon_dependency(data, option, value):
    data["apps"] = {"service1": {"command": "binary1", option: value}}

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    assert str(error.value).endswith(
        "The 'apps/service1' property does not match the required schema: "
        f"'daemon' is a dependency of {option!r}")
Example #21
0
def test_invalid_compression(data, compression):
    data["compression"] = compression

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = (
        "The 'compression' property does not match the required "
        f"schema: {compression!r} is not one of ['lzo', 'xz']")
    assert expected_message in str(error.value)
Example #22
0
def test_invalid_metadata_links(data, contact, donation, issues, source_code,
                                website):
    data["contact"] = contact
    data["donation"] = donation
    data["issues"] = issues
    data["source-code"] = source_code
    data["website"] = website

    with pytest.raises(snapcraft.yaml_utils.errors.YamlValidationError):
        Validator(data).validate()
Example #23
0
    def test_invalid_names(self):
        data = self.data.copy()
        data["name"] = self.name

        raised = self.assertRaises(errors.YamlValidationError, Validator(data).validate)

        expected_message = (
            "The 'name' property does not match the required schema: {!r} is {}"
        ).format(self.name, self.err)
        self.assertThat(raised.message, Equals(expected_message), message=data)
Example #24
0
    def test_daemon_missing_errors(self):
        self.data["apps"] = {
            "service1": {
                "command": "binary1",
                "stop-mode": self.mode
            }
        }

        self.assertRaises(errors.YamlValidationError,
                          Validator(self.data).validate)
Example #25
0
def test_invalid_description(data, desc):
    data["description"] = desc

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = (
        "The 'description' property does not match the required "
        f"schema: {desc!r} is not a valid description string")
    assert expected_message in str(error.value)
Example #26
0
def test_invalid_license(data):
    data["license"] = 1234

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = (
        "The 'license' property does not match the required schema: "
        "1234 is not of type 'string'")
    assert expected_message in str(error.value)
Example #27
0
def test_invalid_epoch(data, epoch):
    data["epoch"] = epoch

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = (
        f"{epoch!r} is not a 'epoch' (epochs are positive integers "
        "followed by an optional asterisk)")
    assert expected_message in str(error.value)
Example #28
0
    def test_summary_too_long(self):
        self.data["summary"] = "a" * 80
        raised = self.assertRaises(
            errors.YamlValidationError, Validator(self.data).validate
        )

        expected_message = (
            "The 'summary' property does not match the required schema: "
            "'{}' is too long (maximum length is 78)"
        ).format(self.data["summary"])
        self.assertThat(raised.message, Equals(expected_message), message=self.data)
Example #29
0
def test_invalid_version_length(data):
    data["version"] = "this.is.a.really.too.long.version"

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = (
        "The 'version' property does not match the required "
        "schema: 'this.is.a.really.too.long.version' is too long "
        "(maximum length is 32)")
    assert expected_message in str(error.value)
Example #30
0
def test_invalid_confinement(data, confinement):
    data["confinement"] = confinement

    with pytest.raises(errors.YamlValidationError) as error:
        Validator(data).validate()

    expected_message = (
        "The 'confinement' property does not match the required "
        f"schema: {confinement!r} is not one of ['classic', 'devmode', "
        "'strict']")
    assert expected_message in str(error.value)