Source code for efrotools.pcommands2

# Released under the MIT License. See LICENSE for details.
#
"""Standard snippets that can be pulled into project pcommand scripts.

A snippet is a mini-program that directly takes input from stdin and does
some focused task. This module is a repository of common snippets that can
be imported into projects' pcommand script for easy reuse.
"""
from __future__ import annotations

import sys
from typing import TYPE_CHECKING

from efrotools import pcommand

if TYPE_CHECKING:
    pass


[docs] def with_build_lock() -> None: """Run a shell command wrapped in a build-lock.""" from efro.error import CleanError from efrotools.buildlock import BuildLock import subprocess pcommand.disallow_in_batch() args = sys.argv[2:] if len(args) < 2: raise CleanError( 'Expected one lock-name arg and at least one command arg' ) with BuildLock(args[0], projroot=str(pcommand.PROJROOT)): subprocess.run(' '.join(args[1:]), check=True, shell=True)
[docs] def sortlines() -> None: """Sort provided lines. For tidying import lists, etc.""" from efro.error import CleanError pcommand.disallow_in_batch() if len(sys.argv) != 3: raise CleanError('Expected 1 arg.') val = sys.argv[2] lines = val.splitlines() print('\n'.join(sorted(lines, key=lambda l: l.lower())))
[docs] def openal_build_android() -> None: """Build openalsoft for android.""" from efro.error import CleanError from efrotools.openalbuild import build_openal pcommand.disallow_in_batch() args = sys.argv[2:] if len(args) != 2: raise CleanError( 'Expected one <ARCH> arg: arm, arm64, x86, x86_64' ' and one <MODE> arg: debug, release' ) build_openal(args[0], args[1])
[docs] def openal_gather() -> None: """Gather built opealsoft libs into src.""" from efro.error import CleanError from efrotools.openalbuild import gather pcommand.disallow_in_batch() args = sys.argv[2:] if args: raise CleanError('No args expected.') gather()
[docs] def pyright() -> None: """Run Pyright checks on project Python code.""" import subprocess from efro.terminal import Clr from efro.error import CleanError pcommand.disallow_in_batch() print(f'{Clr.BLU}Running Pyright (experimental)...{Clr.RST}') try: subprocess.run( ['pyright', '--project', '.pyrightconfig.json'], check=True ) except Exception as exc: raise CleanError('Pyright failed.') from exc
[docs] def build_pcommandbatch() -> None: """Build a version of pcommand geared for large batches of commands.""" from efro.error import CleanError from efro.terminal import Clr import efrotools.pcommandbatch as pcb pcommand.disallow_in_batch() args = pcommand.get_args() if len(args) < 2: raise CleanError('Expected at least 2 args.') inpaths = args[:-1] outpath = args[-1] print(f'Creating batch executable: {Clr.BLD}{outpath}{Clr.RST}') pcb.build_pcommandbatch(inpaths, outpath)
[docs] def batchserver() -> None: """Run a server for handling pcommands.""" from efro.error import CleanError from efro.util import extract_arg import efrotools.pcommandbatch as pcb pcommand.disallow_in_batch() args = pcommand.get_args() idle_timeout_secs = int(extract_arg(args, '--timeout', required=True)) project_dir = extract_arg(args, '--project-dir', required=True) instance = extract_arg(args, '--instance', required=True) if args: raise CleanError(f'Unexpected args: {args}.') pcb.batchserver( idle_timeout_secs=idle_timeout_secs, project_dir=project_dir, instance=instance, )
[docs] def pcommandbatch_speed_test() -> None: """Test batch mode speeds.""" # pylint: disable=too-many-locals import time import subprocess import threading from multiprocessing import cpu_count from concurrent.futures import ThreadPoolExecutor from efro.error import CleanError from efro.terminal import Clr args = pcommand.get_args() if len(args) != 1: raise CleanError('Expected one arg.') batch_binary_path = args[0] thread_count = cpu_count() class _Test: def __init__(self) -> None: self.in_flight = 0 self.lock = threading.Lock() self.total_runs = 0 def run_standalone(self) -> None: """Run an instance of the test in standalone mode.""" subprocess.run(['tools/pcommand', 'null'], check=True) self._finish_run() def run_batch(self) -> None: """Run an instance of the test in batch mode.""" subprocess.run([batch_binary_path, 'null'], check=True) self._finish_run() def _finish_run(self) -> None: with self.lock: self.in_flight -= 1 assert self.in_flight >= 0 self.total_runs += 1 test_duration = 5.0 for name, batch in [('regular pcommand', False), ('pcommandbatch', True)]: print(f'{Clr.BLU}Testing {name} speed...{Clr.RST}') start_time = time.monotonic() test = _Test() total_runs_at_timeout = 0 with ThreadPoolExecutor(max_workers=thread_count) as executor: # Convert the generator to a list to trigger any # exceptions that occurred. while True: # Try to keep all worker threads busy. while test.in_flight < thread_count * 2: with test.lock: test.in_flight += 1 executor.submit( test.run_batch if batch else test.run_standalone ) if time.monotonic() - start_time > test_duration: total_runs_at_timeout = test.total_runs break time.sleep(0.0001) print( f'Total runs in {test_duration:.0f} seconds:' f' {Clr.SMAG}{Clr.BLD}{total_runs_at_timeout}{Clr.RST}.' )
[docs] def null() -> None: """Do nothing. Useful for speed tests and whatnot."""