Skip to content

Commit

Permalink
TypedDict for dub JSON definitions
Browse files Browse the repository at this point in the history
  • Loading branch information
rtbo committed May 19, 2023
1 parent 2f6b1de commit 9f34852
Showing 1 changed file with 78 additions and 24 deletions.
102 changes: 78 additions & 24 deletions mesonbuild/dependencies/dub.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,62 @@
if T.TYPE_CHECKING:
from ..environment import Environment

JsonDict = T.Dict[str, T.Union[str, T.List[str]]]

# Definition of what `dub describe` returns (only the fields used by Meson)
class DubDescription(T.TypedDict):
platform: T.List[str]
architecture: T.List[str]
buildType: str
packages: T.List[DubPackDesc]
targets: T.List[DubTargetDesc]

class DubPackDesc(T.TypedDict):
name: str
version: str
active: bool
configuration: str
path: str
targetType: str
targetFileName: str

class DubTargetDesc(T.TypedDict):
rootPackage: str
linkDependencies: T.List[str]
buildSettings: DubBuildSettings

class DubBuildSettings(T.TypedDict):
importPaths: T.List[str]
stringImportPaths: T.List[str]
versions: T.List[str]
mainSourceFile: str
sourceFiles: T.List[str]
dflags: T.List[str]
libs: T.List[str]
lflags: T.List[str]

class DubCacheDbEntry(T.TypedDict):
package: str
version: str
configuration: str
platform: T.List[str]
architecture: T.List[str]
buildType: str
compiler: str
compilerBinary: str
compilerVersion: str
buildId: str
targetBinaryPath: str

class FindTargetSpec(T.TypedDict):
name: str
version: str
configuration: str
build_type: str
target_file_name: str
package_path: str
platform: T.List[str]
architecture: T.List[str]
compiler: str
compiler_version: T.List[str]

class DubDependency(ExternalDependency):
# dub program and version
Expand Down Expand Up @@ -125,14 +179,14 @@ def dub_build_deep_command() -> str:
return join_args(cmd)

dub_comp_id = self.compiler.get_id().replace('llvm', 'ldc').replace('gcc', 'gdc')
description = json.loads(res)
description: DubDescription = json.loads(res)

self.compile_args = []
self.link_args = self.raw_link_args = []

show_buildtype_warning = False

def find_package_target(pkg: JsonDict) -> bool:
def find_package_target(pkg: DubPackDesc) -> bool:
nonlocal show_buildtype_warning
# try to find a static library in a DUB folder corresponding to
# version, configuration, compiler, arch and build-type
Expand All @@ -152,10 +206,10 @@ def find_package_target(pkg: JsonDict) -> bool:
mlog.error(mlog.bold(pack_id), 'found but not compiled for', mlog.bold(dub_arch))
elif 'platform' not in compatibilities:
mlog.error(mlog.bold(pack_id), 'found but not compiled for',
mlog.bold(description['platform'].join('.')))
mlog.bold('.'.join(description['platform'])))
elif 'configuration' not in compatibilities:
mlog.error(mlog.bold(pack_id), 'found but not compiled for the',
mlog.bold(str(pkg['configuration'])), 'configuration')
mlog.bold(pkg['configuration']), 'configuration')
else:
mlog.error(mlog.bold(pack_id), 'not found')

Expand All @@ -180,7 +234,7 @@ def find_package_target(pkg: JsonDict) -> bool:

# 1
self.is_found = False
packages = {}
packages: T.Dict[str, DubPackDesc] = {}
for pkg in description['packages']:
packages[pkg['name']] = pkg

Expand Down Expand Up @@ -310,18 +364,18 @@ def find_package_target(pkg: JsonDict) -> bool:
# compiler, architecture, configuration...
# It returns (target|None, {compatibilities})
# If None is returned for target, compatibilities will list what other targets were found without full compatibility
def _find_target_in_cache(self, jdesc: JsonDict, jpack: JsonDict, dub_comp_id: str) -> T.Tuple[str, T.Set[str]]:
def _find_target_in_cache(self, jdesc: DubDescription, jpack: DubPackDesc, dub_comp_id: str) -> T.Tuple[str, T.Set[str]]:

# platform, arch and compiler_version are arrays
spec: JsonDict = {
spec: FindTargetSpec = {
'name': jpack['name'],
'version': jpack['version'],
'path': jpack['path'],
'package_path': jpack['path'],
'target_file_name': jpack['targetFileName'],
'configuration': jpack['configuration'],
'build_type': jdesc['buildType'],
'platform': jdesc['platform'],
'arch': jdesc['architecture'],
'architecture': jdesc['architecture'],
'compiler': dub_comp_id,
'compiler_version': self._get_comp_versions_to_find(dub_comp_id),
}
Expand All @@ -343,7 +397,7 @@ def _find_target_in_cache(self, jdesc: JsonDict, jpack: JsonDict, dub_comp_id: s

return result

def _find_in_cache_db(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[str, T.Set[str]]:
def _find_in_cache_db(self, spec: FindTargetSpec, check_list: T.Set[str]) -> T.Tuple[str, T.Set[str]]:
# The cache database is a JSON file written by newer versions of Dub to help to locate builds
# artifact in the cache.
# The JSON file path is ~/.dub/cache/pkg/version/[+subpkg/]db.json
Expand All @@ -352,11 +406,11 @@ def _find_in_cache_db(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[s
DubDependency.class_cache_dir = self._find_cache_dir()
cache_dir = DubDependency.class_cache_dir

pkg = str(spec['name'])
pkg = spec['name']
subpkg = None
if ':' in pkg:
[pkg, subpkg] = pkg.split(':')
pkg_cache_dir = os.path.join(cache_dir, pkg, str(spec['version']))
pkg_cache_dir = os.path.join(cache_dir, pkg, spec['version'])
if subpkg is not None:
pkg_cache_dir = os.path.join(pkg_cache_dir, f'+{subpkg}')
db_file = os.path.join(pkg_cache_dir, 'db.json')
Expand All @@ -369,7 +423,7 @@ def _find_in_cache_db(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[s
compatibilities: T.Set[str] = set()

with open(db_file, encoding='utf-8') as f:
db = json.load(f)
db: T.List[DubCacheDbEntry] = json.load(f)
for entry in db:
target = entry['targetBinaryPath']
if not os.path.exists(target):
Expand All @@ -386,13 +440,13 @@ def _find_in_cache_db(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[s
if all(platform in entry['platform'] for platform in spec['platform']):
comps.add('platform')

if all(arch in entry['architecture'] for arch in spec['arch']):
if all(arch in entry['architecture'] for arch in spec['architecture']):
comps.add('arch')

if spec['compiler'] == entry['compiler']:
comps.add('compiler')

if not spec['compiler_version'] or any(cv == entry['compiler_version'] for cv in spec['compiler_version']):
if not spec['compiler_version'] or any(cv == entry['compilerVersion'] for cv in spec['compiler_version']):
comps.add('compiler_version')

if all(key in comps for key in check_list):
Expand All @@ -402,9 +456,9 @@ def _find_in_cache_db(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[s

return (None, compatibilities)

def _find_in_old_cache(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[str, T.Set[str]]:
def _find_in_old_cache(self, spec: FindTargetSpec, check_list: T.Set[str]) -> T.Tuple[str, T.Set[str]]:
# the "old" cache is the `.dub` directory in every package of ~/.dub/packages
dub_build_path = os.path.join(str(spec['path']), '.dub', 'build')
dub_build_path = os.path.join(spec['package_path'], '.dub', 'build')

if not os.path.exists(dub_build_path):
return (None, None)
Expand All @@ -424,7 +478,7 @@ def _find_in_old_cache(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[

for entry in os.listdir(dub_build_path):

target = os.path.join(dub_build_path, entry, str(spec['target_file_name']))
target = os.path.join(dub_build_path, entry, spec['target_file_name'])
if not os.path.exists(target):
# unless Dub and Meson are racing, the target file should be present
# when the directory is present
Expand All @@ -436,19 +490,19 @@ def _find_in_old_cache(self, spec: JsonDict, check_list: T.Set[str]) -> T.Tuple[
# otherwise we could miss the WARNING about build_type
comps = set()

if str(spec['configuration']) in entry:
if spec['configuration'] in entry:
comps.add('configuration')

if str(spec['build_type']) in entry:
if spec['build_type'] in entry:
comps.add('build_type')

if all(platform in entry for platform in spec['platform']):
comps.add('platform')

if all(arch in entry for arch in spec['arch']):
if all(arch in entry for arch in spec['architecture']):
comps.add('arch')

if str(spec['compiler']) in entry:
if spec['compiler'] in entry:
comps.add('compiler')

if not spec['compiler_version'] or any(cv in entry for cv in spec['compiler_version']):
Expand Down

0 comments on commit 9f34852

Please sign in to comment.