aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Carson <danielcarson271@gmail.com>2022-06-27 16:04:48 -0400
committerEli Schwartz <eschwartz93@gmail.com>2022-09-18 22:48:50 -0400
commit004575874ffdb77ee997f9c19e0a041d144994d6 (patch)
tree939353cff137c4718bbf19d7756f0c040c9bc5a9
parent97f248db24fe88495dbe35bbae6eafd643c0c94b (diff)
downloadmeson-004575874ffdb77ee997f9c19e0a041d144994d6.zip
meson-004575874ffdb77ee997f9c19e0a041d144994d6.tar.gz
meson-004575874ffdb77ee997f9c19e0a041d144994d6.tar.bz2
Warn if wrap file changes
Save off the hash of the wrap file when first configuring a subproject. When reconfiguring a subproject, check the hash of the wrap file against the stored hash. If they don't match then warn the user.
-rwxr-xr-xmesonbuild/msubprojects.py13
-rw-r--r--mesonbuild/wrap/wrap.py38
-rw-r--r--unittests/allplatformstests.py18
3 files changed, 62 insertions, 7 deletions
diff --git a/mesonbuild/msubprojects.py b/mesonbuild/msubprojects.py
index 21f0853..f8c0b92 100755
--- a/mesonbuild/msubprojects.py
+++ b/mesonbuild/msubprojects.py
@@ -394,19 +394,22 @@ class Runner:
def update(self) -> bool:
self.log(f'Updating {self.wrap.name}...')
+ success = False
if self.wrap.type == 'file':
- return self.update_file()
+ success = self.update_file()
elif self.wrap.type == 'git':
- return self.update_git()
+ success = self.update_git()
elif self.wrap.type == 'hg':
- return self.update_hg()
+ success = self.update_hg()
elif self.wrap.type == 'svn':
- return self.update_svn()
+ success = self.update_svn()
elif self.wrap.type is None:
self.log(' -> Cannot update subproject with no wrap file')
else:
self.log(' -> Cannot update', self.wrap.type, 'subproject')
- return True
+ if success:
+ self.wrap.update_hash_cache(self.wrap_resolver.dirname)
+ return success
def checkout(self) -> bool:
options = T.cast('CheckoutArguments', self.options)
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index 34249d5..25e96e6 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -132,7 +132,9 @@ class PackageDefinition:
self.redirected = False
if self.has_wrap:
self.parse_wrap()
- self.directory = self.values.get('directory', self.name)
+ self.directory = self.values.get('directory', self.name)
+ with open(fname, 'r', encoding='utf-8') as file:
+ self.wrapfile_hash = hashlib.sha256(file.read().encode('utf-8')).hexdigest()
if os.path.dirname(self.directory):
raise WrapException('Directory key must be a name and not a path')
if self.type and self.type not in ALL_TYPES:
@@ -221,6 +223,14 @@ class PackageDefinition:
except KeyError:
raise WrapException(f'Missing key {key!r} in {self.basename}')
+ def get_hashfile(self, subproject_directory: str) -> str:
+ return os.path.join(subproject_directory, '.meson-subproject-wrap-hash.txt')
+
+ def update_hash_cache(self, subproject_directory: str) -> None:
+ if self.has_wrap:
+ with open(self.get_hashfile(subproject_directory), 'w', encoding='utf-8') as file:
+ file.write(self.wrapfile_hash + '\n')
+
def get_directory(subdir_root: str, packagename: str) -> str:
fname = os.path.join(subdir_root, packagename + '.wrap')
if os.path.isfile(fname):
@@ -367,6 +377,7 @@ class Resolver:
# The directory is there and has meson.build? Great, use it.
if method == 'meson' and os.path.exists(meson_file):
+ self.validate()
return rel_path
if method == 'cmake' and os.path.exists(cmake_file):
return rel_path
@@ -403,6 +414,11 @@ class Resolver:
if method == 'cmake' and not os.path.exists(cmake_file):
raise WrapException('Subproject exists but has no CMakeLists.txt file')
+ # At this point, the subproject has been successfully resolved for the
+ # first time so save off the hash of the entire wrap file for future
+ # reference.
+ self.wrap.update_hash_cache(self.dirname)
+
return rel_path
def check_can_download(self) -> None:
@@ -504,6 +520,26 @@ class Resolver:
if push_url:
verbose_git(['remote', 'set-url', '--push', 'origin', push_url], self.dirname, check=True)
+ def validate(self) -> None:
+ # This check is only for subprojects with wraps.
+ if not self.wrap.has_wrap:
+ return
+
+ # Retrieve original hash, if it exists.
+ hashfile = self.wrap.get_hashfile(self.dirname)
+ if os.path.isfile(hashfile):
+ with open(hashfile, 'r', encoding='utf-8') as file:
+ expected_hash = file.read().strip()
+ else:
+ # If stored hash doesn't exist then don't warn.
+ return
+
+ actual_hash = self.wrap.wrapfile_hash
+
+ # Compare hashes and warn the user if they don't match.
+ if expected_hash != actual_hash:
+ mlog.warning(f'Subproject {self.wrap.name}\'s revision may be out of date; its wrap file has changed since it was first configured')
+
def is_git_full_commit_id(self, revno: str) -> bool:
result = False
if len(revno) in (40, 64): # 40 for sha1, 64 for upcoming sha256
diff --git a/unittests/allplatformstests.py b/unittests/allplatformstests.py
index 8e0f934..7f0dd44 100644
--- a/unittests/allplatformstests.py
+++ b/unittests/allplatformstests.py
@@ -3733,10 +3733,26 @@ class AllPlatformTests(BasePlatformTests):
patch_directory = wrap_git_builddef
revision = master
'''.format(upstream_uri)))
- self.init(srcdir)
+ out = self.init(srcdir)
self.build()
self.run_tests()
+ # Make sure the warning does not occur on the first init.
+ out_of_date_warning = 'revision may be out of date'
+ self.assertNotIn(out_of_date_warning, out)
+
+ # Change the wrap's revisions, reconfigure, and make sure it does
+ # warn on the reconfigure.
+ with open(os.path.join(srcdir, 'subprojects', 'wrap_git.wrap'), 'w', encoding='utf-8') as f:
+ f.write(textwrap.dedent('''
+ [wrap-git]
+ url = {}
+ patch_directory = wrap_git_builddef
+ revision = not-master
+ '''.format(upstream_uri)))
+ out = self.init(srcdir, extra_args='--reconfigure')
+ self.assertIn(out_of_date_warning, out)
+
def test_extract_objects_custom_target_no_warning(self):
testdir = os.path.join(self.common_test_dir, '22 object extraction')