devenv: Source bash completion scripts

pull/10047/head
Xavier Claessens 3 years ago committed by Xavier Claessens
parent 79c6075b56
commit 6fafeb13b3
  1. 3
      docs/markdown/Commands.md
  2. 5
      docs/markdown/snippets/devenv.md
  3. 34
      mesonbuild/mdevenv.py
  4. 20
      mesonbuild/minstall.py

@ -321,4 +321,7 @@ These variables are set in environment in addition to those set using `meson.add
layout must match the installed tree layout otherwise `import subdir.mod`
cannot work.
Since *Since 0.62.0* if bash-completion scripts are being installed and the
shell is bash, they will be automatically sourced.
{{ devenv_arguments.inc }}

@ -3,3 +3,8 @@
`PYTHONPATH` now includes every directory where a python module is being
installed using [`python.install_sources()`](Python-module.md#install_sources)
and [`python.extension_module()`](Python-module.md#extension_module).
## Bash completion scripts sourced in `meson devenv`
If bash-completion scripts are being installed and the shell is bash, they will
be automatically sourced.

@ -3,10 +3,12 @@ import argparse
import tempfile
from pathlib import Path
from . import build
from .mesonlib import MesonException, RealPathAction, is_windows, setup_vsenv
from . import build, minstall, dependencies
from .mesonlib import MesonException, RealPathAction, is_windows, setup_vsenv, OptionKey
import typing as T
if T.TYPE_CHECKING:
from .backends import InstallData
def add_arguments(parser: argparse.ArgumentParser) -> None:
parser.add_argument('-C', dest='wd', action=RealPathAction,
@ -36,11 +38,30 @@ def get_env(b: build.Build, build_dir: str) -> T.Dict[str, str]:
return extra_env.get_env(env)
def bash_completion_files(b: build.Build, install_data: 'InstallData') -> T.List[str]:
result = []
dep = dependencies.PkgConfigDependency('bash-completion', b.environment,
{'silent': True, 'version': '>=2.10'})
if dep.found():
prefix = b.environment.coredata.get_option(OptionKey('prefix'))
assert isinstance(prefix, str), 'for mypy'
datadir = b.environment.coredata.get_option(OptionKey('datadir'))
assert isinstance(datadir, str), 'for mypy'
datadir_abs = os.path.join(prefix, datadir)
completionsdir = dep.get_variable(pkgconfig='completionsdir', pkgconfig_define=['datadir', datadir_abs])
assert isinstance(completionsdir, str), 'for mypy'
completionsdir_path = Path(completionsdir)
for f in install_data.data:
if completionsdir_path in Path(f.install_path).parents:
result.append(f.path)
return result
def run(options: argparse.Namespace) -> int:
buildfile = Path(options.wd) / 'meson-private' / 'build.dat'
if not buildfile.is_file():
raise MesonException(f'Directory {options.wd!r} does not seem to be a Meson build directory.')
b = build.load(options.wd)
install_data = minstall.load_install_data(str(buildfile.parent / 'install.dat'))
setup_vsenv(b.need_vsenv)
devenv = get_env(b, options.wd)
@ -64,12 +85,15 @@ def run(options: argparse.Namespace) -> int:
args += ['/k', f'prompt {prompt_prefix} $P$G']
else:
args = [os.environ.get("SHELL", os.path.realpath("/bin/sh"))]
if "bash" in args[0] and not os.environ.get("MESON_DISABLE_PS1_OVERRIDE"):
if "bash" in args[0]:
# Let the GC remove the tmp file
tmprc = tempfile.NamedTemporaryFile(mode='w')
tmprc.write('[ -e ~/.bashrc ] && . ~/.bashrc\n')
tmprc.write(f'export PS1="{prompt_prefix} $PS1"')
if not os.environ.get("MESON_DISABLE_PS1_OVERRIDE"):
tmprc.write(f'export PS1="{prompt_prefix} $PS1"\n')
for f in bash_completion_files(b, install_data):
tmprc.write(f'. "{f}"\n')
tmprc.flush()
# Let the GC remove the tmp file
args.append("--rcfile")
args.append(tmprc.name)

@ -127,6 +127,15 @@ class DirMaker:
append_to_log(self.lf, d)
def load_install_data(fname: str) -> InstallData:
with open(fname, 'rb') as ifile:
obj = pickle.load(ifile)
if not isinstance(obj, InstallData) or not hasattr(obj, 'version'):
raise MesonVersionMismatchException('<unknown>', coredata_version)
if major_versions_differ(obj.version, coredata_version):
raise MesonVersionMismatchException(obj.version, coredata_version)
return obj
def is_executable(path: str, follow_symlinks: bool = False) -> bool:
'''Checks whether any of the "x" bits are set in the source file mode.'''
return bool(os.stat(path, follow_symlinks=follow_symlinks).st_mode & 0o111)
@ -510,17 +519,8 @@ class Installer:
self.do_copyfile(abs_src, abs_dst)
self.set_mode(abs_dst, install_mode, data.install_umask)
@staticmethod
def check_installdata(obj: InstallData) -> InstallData:
if not isinstance(obj, InstallData) or not hasattr(obj, 'version'):
raise MesonVersionMismatchException('<unknown>', coredata_version)
if major_versions_differ(obj.version, coredata_version):
raise MesonVersionMismatchException(obj.version, coredata_version)
return obj
def do_install(self, datafilename: str) -> None:
with open(datafilename, 'rb') as ifile:
d = self.check_installdata(pickle.load(ifile))
d = load_install_data(datafilename)
destdir = self.options.destdir
if destdir is None:

Loading…
Cancel
Save