66'''West project commands'''
77
88import argparse
9+ import asyncio
910from functools import partial
1011import logging
1112import os
@@ -1670,16 +1671,15 @@ def do_add_parser(self, parser_adder):
16701671 parser .add_argument ('projects' , metavar = 'PROJECT' , nargs = '*' ,
16711672 help = '''projects (by name or path) to operate on;
16721673 defaults to active cloned projects''' )
1674+ parser .add_argument ('-j' , '--jobs' , nargs = '?' , const = - 1 ,
1675+ default = 1 , type = int , action = 'store' ,
1676+ help = '''Use multiple jobs to parallelize commands.
1677+ Pass no number or -1 to run commands on all cores.''' )
16731678 return parser
16741679
1675- def do_run (self , args , user_args ):
1676- failed = []
1677- group_set = set (args .groups )
1678- env = os .environ .copy ()
1679- for project in self ._cloned_projects (args , only_active = not args .all ):
1680- if group_set and not group_set .intersection (set (project .groups )):
1681- continue
1682-
1680+ async def run_for_project (self , project , args , sem ):
1681+ async with sem :
1682+ env = os .environ .copy ()
16831683 env ["WEST_PROJECT_NAME" ] = project .name
16841684 env ["WEST_PROJECT_PATH" ] = project .path
16851685 env ["WEST_PROJECT_ABSPATH" ] = project .abspath if project .abspath else ''
@@ -1689,12 +1689,24 @@ def do_run(self, args, user_args):
16891689
16901690 cwd = args .cwd if args .cwd else project .abspath
16911691
1692- self .banner (
1693- f'running "{ args .subcommand } " in { project .name_and_path } :' )
1694- rc = subprocess .Popen (args .subcommand , shell = True , env = env ,
1695- cwd = cwd ).wait ()
1696- if rc :
1697- failed .append (project )
1692+ self .banner (f'running "{ args .subcommand } " in { project .name_and_path } :' )
1693+ proc = await asyncio .create_subprocess_shell (args .subcommand ,
1694+ cwd = cwd , env = env , shell = True )
1695+ return await proc .wait ()
1696+
1697+ def do_run (self , args , unknown ):
1698+ group_set = set (args .groups )
1699+ projects = [p for p in self ._cloned_projects (args , only_active = not args .all )
1700+ if not group_set or group_set .intersection (set (p .groups ))]
1701+
1702+ asyncio .run (self .do_run_async (args , projects ))
1703+
1704+ async def do_run_async (self , args , projects ):
1705+ sem = asyncio .Semaphore (args .jobs if args .jobs > 0 else os .cpu_count () or sys .maxsize )
1706+
1707+ rcs = await asyncio .gather (* [self .run_for_project (p , args , sem ) for p in projects ])
1708+
1709+ failed = [p for (p , rc ) in zip (projects , rcs ) if rc ]
16981710 self ._handle_failed (args , failed )
16991711
17001712GREP_EPILOG = '''
0 commit comments