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