summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Filippov <alekseyf@google.com>2018-09-25 18:07:09 +0100
committerJussi Pakkanen <jpakkane@gmail.com>2018-11-22 23:38:40 +0200
commit1c8c888854e2c3ad2fbfeb3229520b8a6d3c1799 (patch)
tree88c66bd2555170e03bbcdb96af7985ac361cbb09
parent9f675cc55a04545886e6de4fb1721acc6536f40c (diff)
downloadmeson-1c8c888854e2c3ad2fbfeb3229520b8a6d3c1799.tar.gz
Use first 7 letters of sha256 for subdirectory part of target id
Fixed-size hash makes paths shorter and prevents doubling of path length because of subdir usage in target id: "subdir/id" would generate "subdir/{subdir-without-slashes}@@id" target otherwise. Export construct_id_from_path() to aid tests. Add a separate unit test for this function to make sure it is not broken unexpectedly. Closes #4226.
-rw-r--r--mesonbuild/build.py36
-rwxr-xr-xrun_unittests.py22
2 files changed, 47 insertions, 11 deletions
diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index c0f4564fa..e47bd6f58 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -15,6 +15,7 @@
import copy, os, re
from collections import OrderedDict
import itertools, pathlib
+import hashlib
import pickle
from functools import lru_cache
@@ -363,19 +364,38 @@ a hard error in the future.''' % name)
def get_subdir(self):
return self.subdir
- def get_id(self):
+ @staticmethod
+ def _get_id_hash(target_id):
+ # We don't really need cryptographic security here.
+ # Small-digest hash function with unlikely collision is good enough.
+ h = hashlib.sha256()
+ h.update(target_id.encode(encoding='utf-8', errors='replace'))
+ # This ID should be case-insensitive and should work in Visual Studio,
+ # e.g. it should not start with leading '-'.
+ return h.hexdigest()[:7]
+
+ @staticmethod
+ def construct_id_from_path(subdir, name, type_suffix):
+ """Construct target ID from subdir, name and type suffix.
+
+ This helper function is made public mostly for tests."""
# This ID must also be a valid file name on all OSs.
# It should also avoid shell metacharacters for obvious
# reasons. '@' is not used as often as '_' in source code names.
# In case of collisions consider using checksums.
# FIXME replace with assert when slash in names is prohibited
- name_part = self.name.replace('/', '@').replace('\\', '@')
- assert not has_path_sep(self.type_suffix())
- myid = name_part + self.type_suffix()
- if self.subdir:
- subdir_part = self.subdir.replace('/', '@').replace('\\', '@')
- myid = subdir_part + '@@' + myid
- return myid
+ name_part = name.replace('/', '@').replace('\\', '@')
+ assert not has_path_sep(type_suffix)
+ my_id = name_part + type_suffix
+ if subdir:
+ subdir_part = Target._get_id_hash(subdir)
+ # preserve myid for better debuggability
+ return subdir_part + '@@' + my_id
+ return my_id
+
+ def get_id(self):
+ return self.construct_id_from_path(
+ self.subdir, self.name, self.type_suffix())
def process_kwargs(self, kwargs):
if 'build_by_default' in kwargs:
diff --git a/run_unittests.py b/run_unittests.py
index ecd6b6e1a..a8371ad71 100755
--- a/run_unittests.py
+++ b/run_unittests.py
@@ -48,6 +48,7 @@ from mesonbuild.mesonlib import (
from mesonbuild.environment import detect_ninja
from mesonbuild.mesonlib import MesonException, EnvironmentException
from mesonbuild.dependencies import PkgConfigDependency, ExternalProgram
+from mesonbuild.build import Target
import mesonbuild.modules.pkgconfig
from run_tests import exe_suffix, get_fake_env, get_meson_script
@@ -1633,7 +1634,8 @@ class AllPlatformTests(BasePlatformTests):
incs = [a for a in shlex.split(execmd) if a.startswith("-I")]
self.assertEqual(len(incs), 9)
# target private dir
- self.assertPathEqual(incs[0], "-Isub4/sub4@@someexe@exe")
+ someexe_id = Target.construct_id_from_path("sub4", "someexe", "@exe")
+ self.assertPathEqual(incs[0], "-I" + os.path.join("sub4", someexe_id))
# target build subdir
self.assertPathEqual(incs[1], "-Isub4")
# target source subdir
@@ -2897,6 +2899,18 @@ recommended as it is not supported on some platforms''')
self.build()
self.run_tests()
+ def test_target_construct_id_from_path(self):
+ # This id is stable but not guessable.
+ # The test is supposed to prevent unintentional
+ # changes of target ID generation.
+ target_id = Target.construct_id_from_path('some/obscure/subdir',
+ 'target-id', '@suffix')
+ self.assertEqual('5e002d3@@target-id@suffix', target_id)
+ target_id = Target.construct_id_from_path('subproject/foo/subdir/bar',
+ 'target2-id', '@other')
+ self.assertEqual('81d46d1@@target2-id@other', target_id)
+
+
class FailureTests(BasePlatformTests):
'''
Tests that test failure conditions. Build files here should be dynamically
@@ -3709,8 +3723,10 @@ class LinuxlikeTests(BasePlatformTests):
def test_unity_subproj(self):
testdir = os.path.join(self.common_test_dir, '46 subproject')
self.init(testdir, extra_args='--unity=subprojects')
- self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/subprojects@sublib@@simpletest@exe/simpletest-unity.c'))
- self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib/subprojects@sublib@@sublib@sha/sublib-unity.c'))
+ simpletest_id = Target.construct_id_from_path('subprojects/sublib', 'simpletest', '@exe')
+ self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', simpletest_id, 'simpletest-unity.c'))
+ sublib_id = Target.construct_id_from_path('subprojects/sublib', 'sublib', '@sha')
+ self.assertPathExists(os.path.join(self.builddir, 'subprojects/sublib', sublib_id, 'sublib-unity.c'))
self.assertPathDoesNotExist(os.path.join(self.builddir, 'user@exe/user-unity.c'))
self.build()