aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.com>2018-10-18 11:18:35 -0400
committerXavier Claessens <xavier.claessens@collabora.com>2018-10-18 11:42:17 -0400
commit3f98ad8eed598d5502157d06334e5c3857ab0f8b (patch)
tree9e50aba4e155ed24d45dcba1c339cc7d4d651d51
parent1889e3338918b3bef22838d6de92d6b748ee01aa (diff)
downloadmeson-3f98ad8eed598d5502157d06334e5c3857ab0f8b.zip
meson-3f98ad8eed598d5502157d06334e5c3857ab0f8b.tar.gz
meson-3f98ad8eed598d5502157d06334e5c3857ab0f8b.tar.bz2
wrap: Improve error handling and logging
-rw-r--r--mesonbuild/interpreter.py49
-rw-r--r--mesonbuild/wrap/wrap.py68
2 files changed, 62 insertions, 55 deletions
diff --git a/mesonbuild/interpreter.py b/mesonbuild/interpreter.py
index 9b3fdc7..98424ec 100644
--- a/mesonbuild/interpreter.py
+++ b/mesonbuild/interpreter.py
@@ -2261,19 +2261,21 @@ external dependencies (including libraries) must go to "dependencies".''')
r = wrap.Resolver(subproject_dir_abs, self.coredata.get_builtin_option('wrap_mode'))
try:
resolved = r.resolve(dirname)
- except RuntimeError as e:
- # if the reason subproject execution failed was because
- # the directory doesn't exist, try to give some helpful
- # advice if it's a nested subproject that needs
- # promotion...
- self.print_nested_info(dirname)
-
- if required:
- msg = 'Subproject directory {!r} does not exist and cannot be downloaded:\n{}'
- raise InterpreterException(msg.format(os.path.join(self.subproject_dir, dirname), e))
-
- mlog.log('\nSubproject ', mlog.bold(dirname), 'is buildable:', mlog.red('NO'), '(disabling)\n')
- return self.disabled_subproject(dirname)
+ except wrap.WrapException as e:
+ subprojdir = os.path.join(self.subproject_dir, r.directory)
+ if not required:
+ mlog.log('\nSubproject ', mlog.bold(subprojdir), 'is buildable:', mlog.red('NO'), '(disabling)\n')
+ return self.disabled_subproject(dirname)
+
+ if isinstance(e, wrap.WrapNotFoundException):
+ # if the reason subproject execution failed was because
+ # the directory doesn't exist, try to give some helpful
+ # advice if it's a nested subproject that needs
+ # promotion...
+ self.print_nested_info(dirname)
+
+ msg = 'Failed to initialize {!r}:\n{}'
+ raise InterpreterException(msg.format(subprojdir, e))
subdir = os.path.join(self.subproject_dir, resolved)
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
@@ -2979,26 +2981,21 @@ external dependencies (including libraries) must go to "dependencies".''')
return Disabler()
def print_nested_info(self, dependency_name):
- message_templ = '''\nDependency %s not found but it is available in a sub-subproject.
-To use it in the current project, promote it by going in the project source
-root and issuing %s.
-
-'''
+ message = ['Dependency', mlog.bold(dependency_name), 'not found but it is available in a sub-subproject.\n' +
+ 'To use it in the current project, promote it by going in the project source\n'
+ 'root and issuing']
sprojs = mesonlib.detect_subprojects('subprojects', self.source_root)
if dependency_name not in sprojs:
return
found = sprojs[dependency_name]
if len(found) > 1:
- suffix = 'one of the following commands'
+ message.append('one of the following commands:')
else:
- suffix = 'the following command'
- message = message_templ % (dependency_name, suffix)
- cmds = []
- command_templ = 'meson wrap promote '
+ message.append('the following command:')
+ command_templ = '\nmeson wrap promote {}'
for l in found:
- cmds.append(command_templ + l[len(self.source_root) + 1:])
- final_message = message + '\n'.join(cmds)
- print(final_message)
+ message.append(mlog.bold(command_templ.format(l[len(self.source_root) + 1:])))
+ mlog.warning(*message)
def get_subproject_infos(self, kwargs):
fbinfo = kwargs['fallback']
diff --git a/mesonbuild/wrap/wrap.py b/mesonbuild/wrap/wrap.py
index 0171429..67da23c 100644
--- a/mesonbuild/wrap/wrap.py
+++ b/mesonbuild/wrap/wrap.py
@@ -18,8 +18,8 @@ import urllib.request, os, hashlib, shutil, tempfile, stat
import subprocess
import sys
import configparser
-from pathlib import Path
from . import WrapMode
+from ..mesonlib import MesonException
try:
import ssl
@@ -67,19 +67,35 @@ def open_wrapdburl(urlstring):
urlstring = 'http' + urlstring[5:]
return urllib.request.urlopen(urlstring, timeout=req_timeout)
+class WrapException(MesonException):
+ pass
+
+class WrapNotFoundException(WrapException):
+ pass
class PackageDefinition:
def __init__(self, fname):
- self.config = configparser.ConfigParser()
- self.config.read(fname)
+ self.basename = os.path.basename(fname)
+ try:
+ self.config = configparser.ConfigParser()
+ self.config.read(fname)
+ except:
+ raise WrapException('Failed to parse {}'.format(self.basename))
+ if len(self.config.sections()) < 1:
+ raise WrapException('Missing sections in {}'.format(self.basename))
self.wrap_section = self.config.sections()[0]
if not self.wrap_section.startswith('wrap-'):
- raise RuntimeError('Invalid format of package file')
+ m = '{!r} is not a valid first section in {}'
+ raise WrapException(m.format(self.wrap_section, self.basename))
self.type = self.wrap_section[5:]
self.values = dict(self.config[self.wrap_section])
def get(self, key):
- return self.values[key]
+ try:
+ return self.values[key]
+ except KeyError:
+ m = 'Missing key {!r} in {}'
+ raise WrapException(m.format(key, self.basename))
def has_patch(self):
return 'patch_url' in self.values
@@ -92,32 +108,30 @@ class Resolver:
def resolve(self, packagename):
self.packagename = packagename
+ self.directory = packagename
# We always have to load the wrap file, if it exists, because it could
# override the default directory name.
p = self.load_wrap()
- directory = packagename
if p and 'directory' in p.values:
- directory = p.get('directory')
- dirname = os.path.join(self.subdir_root, directory)
- subprojdir = os.path.join(*Path(dirname).parts[-2:])
+ self.directory = p.get('directory')
+ dirname = os.path.join(self.subdir_root, self.directory)
meson_file = os.path.join(dirname, 'meson.build')
# The directory is there and has meson.build? Great, use it.
if os.path.exists(meson_file):
- return directory
+ return self.directory
# Check if the subproject is a git submodule
self.resolve_git_submodule(dirname)
if os.path.exists(dirname):
if not os.path.isdir(dirname):
- m = '{!r} already exists and is not a dir; cannot use as subproject'
- raise RuntimeError(m.format(subprojdir))
+ raise WrapException('Path already exists but is not a directory')
else:
# A wrap file is required to download
if not p:
- m = 'No {}.wrap found for {!r}'
- raise RuntimeError(m.format(packagename, subprojdir))
+ m = 'Subproject directory not found and {}.wrap file not found'
+ raise WrapNotFoundException(m.format(self.packagename))
if p.type == 'file':
self.get_file(p)
@@ -130,14 +144,13 @@ class Resolver:
elif p.type == "svn":
self.get_svn(p)
else:
- raise AssertionError('Unreachable code.')
+ raise WrapException('Unknown wrap type {!r}'.format(p.type))
# A meson.build file is required in the directory
if not os.path.exists(meson_file):
- m = '{!r} is not empty and has no meson.build files'
- raise RuntimeError(m.format(subprojdir))
+ raise WrapException('Subproject exists but has no meson.build file')
- return directory
+ return self.directory
def load_wrap(self):
fname = os.path.join(self.subdir_root, self.packagename + '.wrap')
@@ -150,7 +163,7 @@ class Resolver:
# Git submodules are ok (see above)!
if self.wrap_mode is WrapMode.nodownload:
m = 'Automatic wrap-based subproject downloading is disabled'
- raise RuntimeError(m)
+ raise WrapException(m)
def resolve_git_submodule(self, dirname):
# Are we in a git repository?
@@ -163,15 +176,15 @@ class Resolver:
return False
# Submodule has not been added, add it
if out.startswith(b'+'):
- mlog.warning('git submodule {} might be out of date'.format(dirname))
+ mlog.warning('git submodule might be out of date')
return True
elif out.startswith(b'U'):
- raise RuntimeError('submodule {} has merge conflicts'.format(dirname))
+ raise WrapException('git submodule has merge conflicts')
# Submodule exists, but is deinitialized or wasn't initialized
elif out.startswith(b'-'):
if subprocess.call(['git', '-C', self.subdir_root, 'submodule', 'update', '--init', dirname]) == 0:
return True
- raise RuntimeError('Failed to git submodule init {!r}'.format(dirname))
+ raise WrapException('git submodule failed to init')
# Submodule looks fine, but maybe it wasn't populated properly. Do a checkout.
elif out.startswith(b' '):
subprocess.call(['git', 'checkout', '.'], cwd=dirname)
@@ -182,7 +195,7 @@ class Resolver:
# It is not a submodule, just a folder that exists in the main repository.
return False
m = 'Unknown git submodule output: {!r}'
- raise RuntimeError(m.format(out))
+ raise WrapException(m.format(out))
def get_file(self, p):
path = self.get_file_internal(p, 'source')
@@ -190,12 +203,9 @@ class Resolver:
extract_dir = self.subdir_root
# Some upstreams ship packages that do not have a leading directory.
# Create one for them.
- try:
- p.get('lead_directory_missing')
+ if 'lead_directory_missing' in p.values:
os.mkdir(target_dir)
extract_dir = target_dir
- except KeyError:
- pass
shutil.unpack_archive(path, extract_dir)
if p.has_patch():
self.apply_patch(p)
@@ -285,7 +295,7 @@ class Resolver:
h.update(f.read())
dhash = h.hexdigest()
if dhash != expected:
- raise RuntimeError('Incorrect hash for %s:\n %s expected\n %s actual.' % (what, expected, dhash))
+ raise WrapException('Incorrect hash for %s:\n %s expected\n %s actual.' % (what, expected, dhash))
def download(self, p, what, ofname):
self.check_can_download()
@@ -295,7 +305,7 @@ class Resolver:
expected = p.get(what + '_hash')
if dhash != expected:
os.remove(tmpfile)
- raise RuntimeError('Incorrect hash for %s:\n %s expected\n %s actual.' % (what, expected, dhash))
+ raise WrapException('Incorrect hash for %s:\n %s expected\n %s actual.' % (what, expected, dhash))
os.rename(tmpfile, ofname)
def get_file_internal(self, p, what):