Add 'meson subprojects foreach' command

Sometimes it is convenient to run an arbitrary command (e.g. 'git diff')
on all subprojects.

Add a 'meson subprojects foreach' command to take care of that.

For this command the common argument 'subprojects' does not make sense,
so only add '--sourcedir' and cover the case of a missing
options.subprojects in run().
pull/5176/head
Antonio Ospite 6 years ago
parent 5905533fcd
commit e680dbe065
  1. 9
      docs/markdown/Subprojects.md
  2. 7
      docs/markdown/snippets/subproject-foreach.md
  3. 37
      mesonbuild/msubprojects.py

@ -241,6 +241,15 @@ changes.
To come back to the revision set in wrap file (i.e. master), just run
`meson subprojects checkout` with no branch name.
## Execute a command on all subprojects
*Since 0.51.0*
The command-line `meson subprojects foreach <command> [...]` will
execute a command in each subproject directory. For example this can be useful
to check the status of subprojects (e.g. with `git status` or `git diff`) before
performing other actions on them.
## Why must all subprojects be inside a single directory?
There are several reasons.

@ -0,0 +1,7 @@
## Add new `meson subprojects foreach` command
`meson subprojects` has learned a new `foreach` command which accepts a command
with arguments and executes it in each subproject directory.
For example this can be useful to check the status of subprojects (e.g. with
`git status` or `git diff`) before performing other actions on them.

@ -1,4 +1,5 @@
import os, subprocess
import argparse
from . import mlog
from .mesonlib import Popen_safe
@ -167,6 +168,18 @@ def download(wrap, repo_dir, options):
except WrapException as e:
mlog.log(' ->', mlog.red(str(e)))
def foreach(wrap, repo_dir, options):
mlog.log('Executing command in %s' % repo_dir)
if not os.path.isdir(repo_dir):
mlog.log(' -> Not downloaded yet')
return
try:
subprocess.check_call([options.command] + options.args, cwd=repo_dir)
mlog.log('')
except subprocess.CalledProcessError as e:
out = e.output.decode().strip()
mlog.log(' -> ', mlog.red(out))
def add_common_arguments(p):
p.add_argument('--sourcedir', default='.',
help='Path to source directory')
@ -197,6 +210,15 @@ def add_arguments(parser):
add_common_arguments(p)
p.set_defaults(subprojects_func=download)
p = subparsers.add_parser('foreach', help='Execute a command in each subproject directory.')
p.add_argument('command', metavar='command ...',
help='Command to execute in each subproject directory')
p.add_argument('args', nargs=argparse.REMAINDER,
help=argparse.SUPPRESS)
p.add_argument('--sourcedir', default='.',
help='Path to source directory')
p.set_defaults(subprojects_func=foreach)
def run(options):
src_dir = os.path.relpath(os.path.realpath(options.sourcedir))
if not os.path.isfile(os.path.join(src_dir, 'meson.build')):
@ -207,13 +229,14 @@ def run(options):
mlog.log('Directory', mlog.bold(src_dir), 'does not seem to have subprojects.')
return 0
files = []
for name in options.subprojects:
f = os.path.join(subprojects_dir, name + '.wrap')
if not os.path.isfile(f):
mlog.error('Subproject', mlog.bold(name), 'not found.')
return 1
else:
files.append(f)
if hasattr(options, 'subprojects'):
for name in options.subprojects:
f = os.path.join(subprojects_dir, name + '.wrap')
if not os.path.isfile(f):
mlog.error('Subproject', mlog.bold(name), 'not found.')
return 1
else:
files.append(f)
if not files:
for f in os.listdir(subprojects_dir):
if f.endswith('.wrap'):

Loading…
Cancel
Save