util.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  2. """
  3. This module keeps commonly used components.
  4. """
  5. try:
  6. from builtins import object
  7. except ImportError:
  8. from __builtin__ import object
  9. import os
  10. import subprocess
  11. import sys
  12. import time
  13. class ColorString:
  14. """Generate colorful strings on terminal"""
  15. HEADER = "\033[95m"
  16. BLUE = "\033[94m"
  17. GREEN = "\033[92m"
  18. WARNING = "\033[93m"
  19. FAIL = "\033[91m"
  20. ENDC = "\033[0m"
  21. @staticmethod
  22. def _make_color_str(text, color):
  23. # In Python2, default encoding for unicode string is ASCII
  24. if sys.version_info.major <= 2:
  25. return "".join([color, text.encode("utf-8"), ColorString.ENDC])
  26. # From Python3, default encoding for unicode string is UTF-8
  27. return "".join([color, text, ColorString.ENDC])
  28. @staticmethod
  29. def ok(text):
  30. if ColorString.is_disabled:
  31. return text
  32. return ColorString._make_color_str(text, ColorString.GREEN)
  33. @staticmethod
  34. def info(text):
  35. if ColorString.is_disabled:
  36. return text
  37. return ColorString._make_color_str(text, ColorString.BLUE)
  38. @staticmethod
  39. def header(text):
  40. if ColorString.is_disabled:
  41. return text
  42. return ColorString._make_color_str(text, ColorString.HEADER)
  43. @staticmethod
  44. def error(text):
  45. if ColorString.is_disabled:
  46. return text
  47. return ColorString._make_color_str(text, ColorString.FAIL)
  48. @staticmethod
  49. def warning(text):
  50. if ColorString.is_disabled:
  51. return text
  52. return ColorString._make_color_str(text, ColorString.WARNING)
  53. is_disabled = False
  54. def run_shell_command(shell_cmd, cmd_dir=None):
  55. """Run a single shell command.
  56. @returns a tuple of shell command return code, stdout, stderr"""
  57. if cmd_dir is not None and not os.path.exists(cmd_dir):
  58. run_shell_command("mkdir -p %s" % cmd_dir)
  59. start = time.time()
  60. print("\t>>> Running: " + shell_cmd)
  61. p = subprocess.Popen( # noqa
  62. shell_cmd,
  63. shell=True,
  64. stdout=subprocess.PIPE,
  65. stderr=subprocess.PIPE,
  66. cwd=cmd_dir,
  67. )
  68. stdout, stderr = p.communicate()
  69. end = time.time()
  70. # Report time if we spent more than 5 minutes executing a command
  71. execution_time = end - start
  72. if execution_time > (60 * 5):
  73. mins = execution_time / 60
  74. secs = execution_time % 60
  75. print("\t>time spent: %d minutes %d seconds" % (mins, secs))
  76. return p.returncode, stdout, stderr
  77. def run_shell_commands(shell_cmds, cmd_dir=None, verbose=False):
  78. """Execute a sequence of shell commands, which is equivalent to
  79. running `cmd1 && cmd2 && cmd3`
  80. @returns boolean indication if all commands succeeds.
  81. """
  82. if cmd_dir:
  83. print("\t=== Set current working directory => %s" % cmd_dir)
  84. for shell_cmd in shell_cmds:
  85. ret_code, stdout, stderr = run_shell_command(shell_cmd, cmd_dir)
  86. if stdout:
  87. if verbose or ret_code != 0:
  88. print(ColorString.info("stdout: \n"), stdout)
  89. if stderr:
  90. # contents in stderr is not necessarily to be error messages.
  91. if verbose or ret_code != 0:
  92. print(ColorString.error("stderr: \n"), stderr)
  93. if ret_code != 0:
  94. return False
  95. return True