diff options
author | Aleksey Filippov <alekseyf@google.com> | 2018-09-25 18:07:09 +0100 |
---|---|---|
committer | Jussi Pakkanen <jpakkane@gmail.com> | 2018-11-22 23:38:40 +0200 |
commit | 1c8c888854e2c3ad2fbfeb3229520b8a6d3c1799 (patch) | |
tree | 88c66bd2555170e03bbcdb96af7985ac361cbb09 | |
parent | 9f675cc55a04545886e6de4fb1721acc6536f40c (diff) | |
download | meson-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.py | 36 | ||||
-rwxr-xr-x | run_unittests.py | 22 |
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() |