p4.py 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. #
  2. # Copyright (c) Contributors to the Open 3D Engine Project.
  3. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. #
  5. # SPDX-License-Identifier: Apache-2.0 OR MIT
  6. #
  7. #
  8. import marshal
  9. from subprocess import Popen, PIPE, check_output
  10. from typing import List
  11. def run_p4_command(command: str, client: str = None, raw_output: bool = False) -> List[dict]:
  12. """Executes a Perforce command by calling p4 in a subprocess
  13. :param command: The command to run (not including p4, e.g., not ['p4', 'opened'] but ['opened'])
  14. :param client: The Perforce client to use when running the command
  15. :param raw_output: if True, return the raw output from p4 instead of using the python dict.
  16. :return: The list of results from the command where each result is a dict (refer to p4's global -G option)
  17. if 'raw_output' is true, return will be verbatim string from p4.
  18. """
  19. results = []
  20. base_command = ['p4']
  21. if not raw_output:
  22. base_command.append('-G')
  23. if client is not None:
  24. base_command += ['-c', client]
  25. if raw_output:
  26. return check_output(base_command + command.split()).decode('utf8')
  27. pipe = Popen(base_command + command.split(), stdout=PIPE).stdout
  28. try:
  29. while True:
  30. result = marshal.load(pipe)
  31. results.append(result)
  32. except EOFError:
  33. pass
  34. finally:
  35. pipe.close()
  36. decoded_results = [{k.decode(): v.decode() if isinstance(v, bytes) else str(v) for k, v in r.items()} for r in results]
  37. if decoded_results and decoded_results[0]['code'] == 'error':
  38. command_was = ' '.join(base_command + command.split())
  39. error_was = decoded_results[0]['data']
  40. raise RuntimeError(f'P4 Command failed: "{command_was}"\nERROR FROM P4: {error_was}\n')
  41. return decoded_results