Merge pull request #1490 from jjardon/jjardon/grpcio_1.34_master

requirements/requirements.in: It depends on grpc >= 1.34
diff --git a/src/buildstream/_context.py b/src/buildstream/_context.py
index 540f376..feec102 100644
--- a/src/buildstream/_context.py
+++ b/src/buildstream/_context.py
@@ -17,7 +17,7 @@
 #  Authors:
 #        Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
 
-from typing import TYPE_CHECKING, List, Dict, Set, Tuple, Optional, Iterable
+from typing import TYPE_CHECKING, List, Dict, Set, Optional, Iterable
 
 import os
 import shutil
diff --git a/src/buildstream/source.py b/src/buildstream/source.py
index 3268d3a..01bc270 100644
--- a/src/buildstream/source.py
+++ b/src/buildstream/source.py
@@ -164,7 +164,7 @@
 from . import _yaml, utils
 from .node import MappingNode
 from .plugin import Plugin
-from .types import SourceRef, Union
+from .types import SourceRef, Union, CoreWarnings
 from ._exceptions import BstError, ImplError, PluginError
 from .exceptions import ErrorDomain
 from ._loader.metasource import MetaSource
@@ -654,6 +654,25 @@
                 url
             ), "URL was not seen at configure time: {}".format(url)
 
+        alias = _extract_alias(url)
+
+        # Issue a (fatal-able) warning if the source used a URL without specifying an alias
+        if not alias:
+            self.warn(
+                "{}: Use of unaliased source download URL: {}".format(self, url),
+                warning_token=CoreWarnings.UNALIASED_URL,
+            )
+
+        # If there is an alias in use, ensure that it exists in the project
+        if alias:
+            project = self._get_project()
+            alias_uri = project.get_alias_uri(alias, first_pass=self.__first_pass)
+            if alias_uri is None:
+                raise SourceError(
+                    "{}: Invalid alias '{}' specified in URL: {}".format(self, alias, url),
+                    reason="invalid-source-alias",
+                )
+
     def get_project_directory(self) -> str:
         """Fetch the project base directory
 
diff --git a/src/buildstream/types.py b/src/buildstream/types.py
index 4d9effc..34914df 100644
--- a/src/buildstream/types.py
+++ b/src/buildstream/types.py
@@ -125,6 +125,12 @@
     characters in its name.
     """
 
+    UNALIASED_URL = "unaliased-url"
+    """
+    A URL used for fetching a sources was specified without specifying any
+    :ref:`alias <project_source_aliases>`
+    """
+
 
 class OverlapAction(FastEnum):
     """OverlapAction()
diff --git a/tests/cachekey/project/project.conf b/tests/cachekey/project/project.conf
index fb06907..d77c089 100644
--- a/tests/cachekey/project/project.conf
+++ b/tests/cachekey/project/project.conf
@@ -1,3 +1,6 @@
 # Project config for cache key test
 name: cachekey
 min-version: 2.0
+
+aliases:
+  upstream: https://up.stream.org
diff --git a/tests/frontend/project/elements/invalid-alias.bst b/tests/frontend/project/elements/invalid-alias.bst
new file mode 100644
index 0000000..a35e9ed
--- /dev/null
+++ b/tests/frontend/project/elements/invalid-alias.bst
@@ -0,0 +1,5 @@
+kind: import
+
+sources:
+- kind: tar
+  url: zebry:tarball.tar
diff --git a/tests/frontend/project/elements/unaliased-tar.bst b/tests/frontend/project/elements/unaliased-tar.bst
new file mode 100644
index 0000000..8cd2bbd
--- /dev/null
+++ b/tests/frontend/project/elements/unaliased-tar.bst
@@ -0,0 +1,5 @@
+kind: import
+
+sources:
+- kind: tar
+  url: https://unaliased-url.org/tarball.tar
diff --git a/tests/frontend/show.py b/tests/frontend/show.py
index 81e1e62..7f4d9ff 100644
--- a/tests/frontend/show.py
+++ b/tests/frontend/show.py
@@ -9,6 +9,7 @@
 from buildstream.testing import cli  # pylint: disable=unused-import
 from buildstream import _yaml
 from buildstream.exceptions import ErrorDomain, LoadErrorReason
+from buildstream.types import CoreWarnings
 
 from tests.testutils import generate_junction
 
@@ -550,3 +551,27 @@
     states = cli.get_element_states(project, ["base.bst", target])
     assert states["base.bst"] == "buildable"
     assert states[target] == expected_state
+
+
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "project"))
+@pytest.mark.parametrize("fatal", [True, False], ids=["fatal", "non-fatal"])
+def test_unaliased_url(cli, tmpdir, datafiles, fatal):
+    project = str(datafiles)
+    if fatal:
+        configure_project(project, {"fatal-warnings": [CoreWarnings.UNALIASED_URL]})
+
+    result = cli.run(project=project, silent=True, args=["show", "unaliased-tar.bst"])
+
+    if fatal:
+        result.assert_main_error(ErrorDomain.PLUGIN, CoreWarnings.UNALIASED_URL)
+    else:
+        result.assert_success()
+        assert "WARNING [unaliased-url]" in result.stderr
+
+
+@pytest.mark.datafiles(os.path.join(DATA_DIR, "project"))
+def test_invalid_alias(cli, tmpdir, datafiles):
+    project = str(datafiles)
+    configure_project(project, {"aliases": {"pony": "https://pony.org/tarballs", "horsy": "http://horsy.tv/shows"}})
+    result = cli.run(project=project, silent=True, args=["show", "invalid-alias.bst"])
+    result.assert_main_error(ErrorDomain.SOURCE, "invalid-source-alias")