util.py 3.6 KB

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