Qinusty pushed to branch Qinusty/597-backport-ValueError-fix at BuildStream / buildstream
Commits:
-
76a66abf
by Jürg Billeter at 2018-08-28T13:29:47Z
-
1a96b537
by Valentin David at 2018-08-28T13:29:48Z
-
765dd3d9
by Jürg Billeter at 2018-08-28T13:29:48Z
-
0de2f87b
by Tristan Van Berkom at 2018-08-28T13:39:18Z
-
7da1c309
by Jürg Billeter at 2018-08-28T16:32:34Z
-
291763b0
by Chandan Singh at 2018-08-29T12:23:21Z
-
557fb81a
by Tristan Van Berkom at 2018-08-29T12:44:25Z
-
582e0c05
by Josh Smith at 2018-08-29T13:02:04Z
5 changed files:
- buildstream/element.py
- buildstream/source.py
- buildstream/utils.py
- setup.py
- tests/frontend/workspace.py
Changes:
... | ... | @@ -1085,9 +1085,12 @@ class Element(Plugin): |
1085 | 1085 |
# until the full cache query below.
|
1086 | 1086 |
cached = self.__artifacts.contains(self, self.__weak_cache_key)
|
1087 | 1087 |
if (not self.__assemble_scheduled and not self.__assemble_done and
|
1088 |
- not cached and not self._pull_pending() and self._is_required()):
|
|
1089 |
- self._schedule_assemble()
|
|
1090 |
- return
|
|
1088 |
+ not cached and not self._pull_pending()):
|
|
1089 |
+ # For uncached workspaced elements, assemble is required
|
|
1090 |
+ # even if we only need the cache key
|
|
1091 |
+ if self._is_required() or self._get_workspace():
|
|
1092 |
+ self._schedule_assemble()
|
|
1093 |
+ return
|
|
1091 | 1094 |
|
1092 | 1095 |
if self.__strict_cache_key is None:
|
1093 | 1096 |
dependencies = [
|
... | ... | @@ -1107,13 +1110,17 @@ class Element(Plugin): |
1107 | 1110 |
self.__strong_cached = self.__artifacts.contains(self, self.__strict_cache_key)
|
1108 | 1111 |
|
1109 | 1112 |
if (not self.__assemble_scheduled and not self.__assemble_done and
|
1110 |
- not self.__cached and not self._pull_pending() and self._is_required()):
|
|
1113 |
+ not self.__cached and not self._pull_pending()):
|
|
1111 | 1114 |
# Workspaced sources are considered unstable if a build is pending
|
1112 | 1115 |
# as the build will modify the contents of the workspace.
|
1113 | 1116 |
# Determine as early as possible if a build is pending to discard
|
1114 | 1117 |
# unstable cache keys.
|
1115 |
- self._schedule_assemble()
|
|
1116 |
- return
|
|
1118 |
+ |
|
1119 |
+ # For uncached workspaced elements, assemble is required
|
|
1120 |
+ # even if we only need the cache key
|
|
1121 |
+ if self._is_required() or self._get_workspace():
|
|
1122 |
+ self._schedule_assemble()
|
|
1123 |
+ return
|
|
1117 | 1124 |
|
1118 | 1125 |
if self.__cache_key is None:
|
1119 | 1126 |
# Calculate strong cache key
|
... | ... | @@ -1382,7 +1389,6 @@ class Element(Plugin): |
1382 | 1389 |
# in a subprocess.
|
1383 | 1390 |
#
|
1384 | 1391 |
def _schedule_assemble(self):
|
1385 |
- assert self._is_required()
|
|
1386 | 1392 |
assert not self.__assemble_scheduled
|
1387 | 1393 |
self.__assemble_scheduled = True
|
1388 | 1394 |
|
... | ... | @@ -1390,6 +1396,8 @@ class Element(Plugin): |
1390 | 1396 |
for dep in self.dependencies(Scope.BUILD, recurse=False):
|
1391 | 1397 |
dep._set_required()
|
1392 | 1398 |
|
1399 |
+ self._set_required()
|
|
1400 |
+ |
|
1393 | 1401 |
# Invalidate workspace key as the build modifies the workspace directory
|
1394 | 1402 |
workspace = self._get_workspace()
|
1395 | 1403 |
if workspace:
|
... | ... | @@ -1579,6 +1587,10 @@ class Element(Plugin): |
1579 | 1587 |
# (bool): Whether a pull operation is pending
|
1580 | 1588 |
#
|
1581 | 1589 |
def _pull_pending(self):
|
1590 |
+ if self._get_workspace():
|
|
1591 |
+ # Workspace builds are never pushed to artifact servers
|
|
1592 |
+ return False
|
|
1593 |
+ |
|
1582 | 1594 |
if self.__strong_cached:
|
1583 | 1595 |
# Artifact already in local cache
|
1584 | 1596 |
return False
|
... | ... | @@ -184,10 +184,7 @@ class SourceFetcher(): |
184 | 184 |
Args:
|
185 | 185 |
url (str): The url used to download.
|
186 | 186 |
"""
|
187 |
- # Not guaranteed to be a valid alias yet.
|
|
188 |
- # Ensuring it's a valid alias currently happens in Project.get_alias_uris
|
|
189 |
- alias, _ = url.split(utils._ALIAS_SEPARATOR, 1)
|
|
190 |
- self.__alias = alias
|
|
187 |
+ self.__alias = _extract_alias(url)
|
|
191 | 188 |
|
192 | 189 |
#############################################################
|
193 | 190 |
# Private Methods used in BuildStream #
|
... | ... | @@ -386,8 +383,7 @@ class Source(Plugin): |
386 | 383 |
|
387 | 384 |
*Since: 1.2*
|
388 | 385 |
"""
|
389 |
- alias, _ = url.split(utils._ALIAS_SEPARATOR, 1)
|
|
390 |
- self.__expected_alias = alias
|
|
386 |
+ self.__expected_alias = _extract_alias(url)
|
|
391 | 387 |
|
392 | 388 |
def get_source_fetchers(self):
|
393 | 389 |
"""Get the objects that are used for fetching
|
... | ... | @@ -452,8 +448,7 @@ class Source(Plugin): |
452 | 448 |
else:
|
453 | 449 |
# Sneakily store the alias if it hasn't already been stored
|
454 | 450 |
if not self.__expected_alias and url and utils._ALIAS_SEPARATOR in url:
|
455 |
- url_alias, _ = url.split(utils._ALIAS_SEPARATOR, 1)
|
|
456 |
- self.__expected_alias = url_alias
|
|
451 |
+ self.mark_download_url(url)
|
|
457 | 452 |
|
458 | 453 |
project = self._get_project()
|
459 | 454 |
return project.translate_url(url, first_pass=self.__first_pass)
|
... | ... | @@ -804,12 +799,12 @@ class Source(Plugin): |
804 | 799 |
# Tries to call track for every mirror, stopping once it succeeds
|
805 | 800 |
def __do_track(self):
|
806 | 801 |
project = self._get_project()
|
807 |
- # If there are no mirrors, or no aliases to replace, there's nothing to do here.
|
|
808 | 802 |
alias = self._get_alias()
|
809 | 803 |
if self.__first_pass:
|
810 | 804 |
mirrors = project.first_pass_config.mirrors
|
811 | 805 |
else:
|
812 | 806 |
mirrors = project.config.mirrors
|
807 |
+ # If there are no mirrors, or no aliases to replace, there's nothing to do here.
|
|
813 | 808 |
if not mirrors or not alias:
|
814 | 809 |
return self.track()
|
815 | 810 |
|
... | ... | @@ -867,3 +862,11 @@ class Source(Plugin): |
867 | 862 |
_yaml.node_final_assertions(config)
|
868 | 863 |
|
869 | 864 |
return config
|
865 |
+ |
|
866 |
+ |
|
867 |
+def _extract_alias(url):
|
|
868 |
+ parts = url.split(utils._ALIAS_SEPARATOR, 1)
|
|
869 |
+ if len(parts) > 1 and not parts[0].lower() in utils._URI_SCHEMES:
|
|
870 |
+ return parts[0]
|
|
871 |
+ else:
|
|
872 |
+ return ""
|
... | ... | @@ -44,6 +44,7 @@ from ._exceptions import BstError, ErrorDomain |
44 | 44 |
|
45 | 45 |
# The separator we use for user specified aliases
|
46 | 46 |
_ALIAS_SEPARATOR = ':'
|
47 |
+_URI_SCHEMES = ["http", "https", "ftp", "file", "git", "sftp", "ssh"]
|
|
47 | 48 |
|
48 | 49 |
|
49 | 50 |
class UtilError(BstError):
|
... | ... | @@ -25,7 +25,14 @@ import subprocess |
25 | 25 |
import sys
|
26 | 26 |
import versioneer
|
27 | 27 |
|
28 |
-if sys.version_info[0] != 3 or sys.version_info[1] < 5:
|
|
28 |
+ |
|
29 |
+##################################################################
|
|
30 |
+# Python requirements
|
|
31 |
+##################################################################
|
|
32 |
+REQUIRED_PYTHON_MAJOR = 3
|
|
33 |
+REQUIRED_PYTHON_MINOR = 5
|
|
34 |
+ |
|
35 |
+if sys.version_info[0] != REQUIRED_PYTHON_MAJOR or sys.version_info[1] < REQUIRED_PYTHON_MINOR:
|
|
29 | 36 |
print("BuildStream requires Python >= 3.5")
|
30 | 37 |
sys.exit(1)
|
31 | 38 |
|
... | ... | @@ -242,11 +249,28 @@ setup(name='BuildStream', |
242 | 249 |
|
243 | 250 |
author='BuildStream Developers',
|
244 | 251 |
author_email='buildstream-list gnome org',
|
252 |
+ classifiers=[
|
|
253 |
+ 'Environment :: Console',
|
|
254 |
+ 'Intended Audience :: Developers',
|
|
255 |
+ 'License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)',
|
|
256 |
+ 'Operating System :: POSIX',
|
|
257 |
+ 'Programming Language :: Python :: 3',
|
|
258 |
+ 'Programming Language :: Python :: 3.5',
|
|
259 |
+ 'Programming Language :: Python :: 3.6',
|
|
260 |
+ 'Programming Language :: Python :: 3.7',
|
|
261 |
+ 'Topic :: Software Development :: Build Tools'
|
|
262 |
+ ],
|
|
245 | 263 |
description='A framework for modelling build pipelines in YAML',
|
246 | 264 |
license='LGPL',
|
247 | 265 |
long_description=long_description,
|
248 | 266 |
long_description_content_type='text/x-rst; charset=UTF-8',
|
249 | 267 |
url='https://gitlab.com/BuildStream/buildstream',
|
268 |
+ project_urls={
|
|
269 |
+ 'Documentation': 'https://buildstream.gitlab.io/buildstream/',
|
|
270 |
+ 'Tracker': 'https://gitlab.com/BuildStream/buildstream/issues',
|
|
271 |
+ 'Mailing List': 'https://mail.gnome.org/mailman/listinfo/buildstream-list'
|
|
272 |
+ },
|
|
273 |
+ python_requires='~={}.{}'.format(REQUIRED_PYTHON_MAJOR, REQUIRED_PYTHON_MINOR),
|
|
250 | 274 |
packages=find_packages(exclude=('tests', 'tests.*')),
|
251 | 275 |
package_data={'buildstream': ['plugins/*/*.py', 'plugins/*/*.yaml',
|
252 | 276 |
'data/*.yaml', 'data/*.sh.in']},
|
... | ... | @@ -712,3 +712,73 @@ def test_inconsitent_pipeline_message(cli, tmpdir, datafiles, kind): |
712 | 712 |
'build', element_name
|
713 | 713 |
])
|
714 | 714 |
result.assert_main_error(ErrorDomain.PIPELINE, "inconsistent-pipeline-workspaced")
|
715 |
+ |
|
716 |
+ |
|
717 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
718 |
+@pytest.mark.parametrize("strict", [("strict"), ("non-strict")])
|
|
719 |
+def test_cache_key_workspace_in_dependencies(cli, tmpdir, datafiles, strict):
|
|
720 |
+ checkout = os.path.join(str(tmpdir), 'checkout')
|
|
721 |
+ element_name, project, workspace = open_workspace(cli, os.path.join(str(tmpdir), 'repo-a'),
|
|
722 |
+ datafiles, 'git', False)
|
|
723 |
+ |
|
724 |
+ element_path = os.path.join(project, 'elements')
|
|
725 |
+ back_dep_element_name = 'workspace-test-back-dep.bst'
|
|
726 |
+ |
|
727 |
+ # Write out our test target
|
|
728 |
+ element = {
|
|
729 |
+ 'kind': 'compose',
|
|
730 |
+ 'depends': [
|
|
731 |
+ {
|
|
732 |
+ 'filename': element_name,
|
|
733 |
+ 'type': 'build'
|
|
734 |
+ }
|
|
735 |
+ ]
|
|
736 |
+ }
|
|
737 |
+ _yaml.dump(element,
|
|
738 |
+ os.path.join(element_path,
|
|
739 |
+ back_dep_element_name))
|
|
740 |
+ |
|
741 |
+ # Modify workspace
|
|
742 |
+ shutil.rmtree(os.path.join(workspace, 'usr', 'bin'))
|
|
743 |
+ os.makedirs(os.path.join(workspace, 'etc'))
|
|
744 |
+ with open(os.path.join(workspace, 'etc', 'pony.conf'), 'w') as f:
|
|
745 |
+ f.write("PONY='pink'")
|
|
746 |
+ |
|
747 |
+ # Configure strict mode
|
|
748 |
+ strict_mode = True
|
|
749 |
+ if strict != 'strict':
|
|
750 |
+ strict_mode = False
|
|
751 |
+ cli.configure({
|
|
752 |
+ 'projects': {
|
|
753 |
+ 'test': {
|
|
754 |
+ 'strict': strict_mode
|
|
755 |
+ }
|
|
756 |
+ }
|
|
757 |
+ })
|
|
758 |
+ |
|
759 |
+ # Build artifact with dependency's modified workspace
|
|
760 |
+ assert cli.get_element_state(project, element_name) == 'buildable'
|
|
761 |
+ assert cli.get_element_key(project, element_name) == "{:?<64}".format('')
|
|
762 |
+ assert cli.get_element_state(project, back_dep_element_name) == 'waiting'
|
|
763 |
+ assert cli.get_element_key(project, back_dep_element_name) == "{:?<64}".format('')
|
|
764 |
+ result = cli.run(project=project, args=['build', back_dep_element_name])
|
|
765 |
+ result.assert_success()
|
|
766 |
+ assert cli.get_element_state(project, element_name) == 'cached'
|
|
767 |
+ assert cli.get_element_key(project, element_name) != "{:?<64}".format('')
|
|
768 |
+ assert cli.get_element_state(project, back_dep_element_name) == 'cached'
|
|
769 |
+ assert cli.get_element_key(project, back_dep_element_name) != "{:?<64}".format('')
|
|
770 |
+ result = cli.run(project=project, args=['build', back_dep_element_name])
|
|
771 |
+ result.assert_success()
|
|
772 |
+ |
|
773 |
+ # Checkout the result
|
|
774 |
+ result = cli.run(project=project, args=[
|
|
775 |
+ 'checkout', back_dep_element_name, checkout
|
|
776 |
+ ])
|
|
777 |
+ result.assert_success()
|
|
778 |
+ |
|
779 |
+ # Check that the pony.conf from the modified workspace exists
|
|
780 |
+ filename = os.path.join(checkout, 'etc', 'pony.conf')
|
|
781 |
+ assert os.path.exists(filename)
|
|
782 |
+ |
|
783 |
+ # Check that the original /usr/bin/hello is not in the checkout
|
|
784 |
+ assert not os.path.exists(os.path.join(checkout, 'usr', 'bin', 'hello'))
|