1# Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights 2# reserved. Use of this source code is governed by a BSD-style license that 3# can be found in the LICENSE file. 4 5from __future__ import absolute_import 6from glob import iglob 7from io import open 8import os 9import fnmatch 10import shutil 11import sys 12import time 13 14 15def read_file(name, normalize=True): 16 """ Read a file. """ 17 try: 18 with open(name, 'r', encoding='utf-8') as f: 19 # read the data 20 data = f.read() 21 if normalize: 22 # normalize line endings 23 data = data.replace("\r\n", "\n") 24 return data 25 except IOError as e: 26 (errno, strerror) = e.args 27 sys.stderr.write('Failed to read file ' + name + ': ' + strerror) 28 raise 29 30 31def write_file(name, data): 32 """ Write a file. """ 33 try: 34 with open(name, 'w', encoding='utf-8') as f: 35 # write the data 36 if sys.version_info.major == 2: 37 f.write(data.decode('utf-8')) 38 else: 39 f.write(data) 40 except IOError as e: 41 (errno, strerror) = e.args 42 sys.stderr.write('Failed to write file ' + name + ': ' + strerror) 43 raise 44 45 46def path_exists(name): 47 """ Returns true if the path currently exists. """ 48 return os.path.exists(name) 49 50 51def write_file_if_changed(name, data): 52 """ Write a file if the contents have changed. Returns True if the file was written. """ 53 if path_exists(name): 54 old_contents = read_file(name) 55 else: 56 old_contents = '' 57 58 if (data != old_contents): 59 write_file(name, data) 60 return True 61 return False 62 63 64def backup_file(name): 65 """ Rename the file to a name that includes the current time stamp. """ 66 move_file(name, name + '.' + time.strftime('%Y-%m-%d-%H-%M-%S')) 67 68 69def copy_file(src, dst, quiet=True): 70 """ Copy a file. """ 71 try: 72 shutil.copy2(src, dst) 73 if not quiet: 74 sys.stdout.write('Transferring ' + src + ' file.\n') 75 except IOError as e: 76 (errno, strerror) = e.args 77 sys.stderr.write('Failed to copy file from ' + src + ' to ' + dst + ': ' + 78 strerror) 79 raise 80 81 82def move_file(src, dst, quiet=True): 83 """ Move a file. """ 84 try: 85 shutil.move(src, dst) 86 if not quiet: 87 sys.stdout.write('Moving ' + src + ' file.\n') 88 except IOError as e: 89 (errno, strerror) = e.args 90 sys.stderr.write('Failed to move file from ' + src + ' to ' + dst + ': ' + 91 strerror) 92 raise 93 94 95def copy_files(src_glob, dst_folder, quiet=True): 96 """ Copy multiple files. """ 97 for fname in iglob(src_glob): 98 dst = os.path.join(dst_folder, os.path.basename(fname)) 99 if os.path.isdir(fname): 100 copy_dir(fname, dst, quiet) 101 else: 102 copy_file(fname, dst, quiet) 103 104 105def remove_file(name, quiet=True): 106 """ Remove the specified file. """ 107 try: 108 if path_exists(name): 109 os.remove(name) 110 if not quiet: 111 sys.stdout.write('Removing ' + name + ' file.\n') 112 except IOError as e: 113 (errno, strerror) = e.args 114 sys.stderr.write('Failed to remove file ' + name + ': ' + strerror) 115 raise 116 117 118def copy_dir(src, dst, quiet=True): 119 """ Copy a directory tree. """ 120 try: 121 remove_dir(dst, quiet) 122 shutil.copytree(src, dst) 123 if not quiet: 124 sys.stdout.write('Transferring ' + src + ' directory.\n') 125 except IOError as e: 126 (errno, strerror) = e.args 127 sys.stderr.write('Failed to copy directory from ' + src + ' to ' + dst + 128 ': ' + strerror) 129 raise 130 131 132def remove_dir(name, quiet=True): 133 """ Remove the specified directory. """ 134 try: 135 if path_exists(name): 136 shutil.rmtree(name) 137 if not quiet: 138 sys.stdout.write('Removing ' + name + ' directory.\n') 139 except IOError as e: 140 (errno, strerror) = e.args 141 sys.stderr.write('Failed to remove directory ' + name + ': ' + strerror) 142 raise 143 144 145def make_dir(name, quiet=True): 146 """ Create the specified directory. """ 147 try: 148 if not path_exists(name): 149 if not quiet: 150 sys.stdout.write('Creating ' + name + ' directory.\n') 151 os.makedirs(name) 152 except IOError as e: 153 (errno, strerror) = e.args 154 sys.stderr.write('Failed to create directory ' + name + ': ' + strerror) 155 raise 156 157 158def get_files(search_glob): 159 """ Returns all files matching |search_glob|. """ 160 recursive_glob = '**' + os.path.sep 161 if recursive_glob in search_glob: 162 if sys.version_info >= (3, 5): 163 result = iglob(search_glob, recursive=True) 164 else: 165 # Polyfill for recursive glob pattern matching added in Python 3.5. 166 result = get_files_recursive(*search_glob.split(recursive_glob)) 167 else: 168 result = iglob(search_glob) 169 170 # Sort the result for consistency across platforms. 171 return sorted(result) 172 173 174def get_files_recursive(directory, pattern): 175 """ Returns all files in |directory| matching |pattern| recursively. """ 176 for root, dirs, files in os.walk(directory): 177 for basename in files: 178 if fnmatch.fnmatch(basename, pattern): 179 filename = os.path.join(root, basename) 180 yield filename 181 182 183def read_version_file(file, args): 184 """ Read and parse a version file (key=value pairs, one per line). """ 185 lines = read_file(file).split("\n") 186 for line in lines: 187 parts = line.split('=', 1) 188 if len(parts) == 2: 189 args[parts[0]] = parts[1] 190 191 192def eval_file(src): 193 """ Loads and evaluates the contents of the specified file. """ 194 return eval(read_file(src), {'__builtins__': None}, None) 195 196 197def normalize_path(path): 198 """ Normalizes the path separator to match the Unix standard. """ 199 if sys.platform == 'win32': 200 return path.replace('\\', '/') 201 return path 202