Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 3 | import sys, os, re, difflib, unicodedata, errno |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 4 | |
| 5 | class Colors: |
| 6 | class Null: |
| 7 | red = '' |
| 8 | green = '' |
| 9 | end = '' |
| 10 | class ANSI: |
| 11 | red = '\033[41;37;1m' |
| 12 | green = '\033[42;37;1m' |
| 13 | end = '\033[m' |
| 14 | class HTML: |
| 15 | red = '<span style="color:red">' |
| 16 | green = '<span style="color:green">' |
| 17 | end = '</span>' |
| 18 | |
| 19 | @staticmethod |
| 20 | def Auto (argv = [], out = sys.stdout): |
| 21 | if "--color" in argv or os.isatty (out.fileno ()): |
| 22 | if "--color" in sys.argv[1:]: |
| 23 | argv.remove ("--color") |
Behdad Esfahbod | f22089a | 2012-01-20 21:21:47 -0500 | [diff] [blame] | 24 | return Colors.ANSI, argv |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 25 | else: |
Behdad Esfahbod | f22089a | 2012-01-20 21:21:47 -0500 | [diff] [blame] | 26 | return Colors.Null, argv |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 27 | |
Behdad Esfahbod | ad34e39 | 2012-01-20 18:39:27 -0500 | [diff] [blame] | 28 | @staticmethod |
| 29 | def Default (argv = []): |
| 30 | return Colors.ANSI |
| 31 | |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 32 | |
| 33 | class FancyDiffer: |
| 34 | |
| 35 | diff_regex = re.compile ('([a-za-z0-9_]*)([^a-za-z0-9_]?)') |
| 36 | |
| 37 | @staticmethod |
| 38 | def diff_lines (l1, l2, colors=Colors.Null): |
| 39 | |
| 40 | ss = [FancyDiffer.diff_regex.sub (r'\1\n\2\n', l).splitlines (True) for l in (l1, l2)] |
| 41 | oo = ["",""] |
| 42 | st = [False, False] |
| 43 | for l in difflib.Differ().compare (*ss): |
| 44 | if l[0] == '?': |
| 45 | continue |
| 46 | if l[0] == ' ': |
| 47 | for i in range(2): |
| 48 | if st[i]: |
| 49 | oo[i] += colors.end |
| 50 | st[i] = False |
| 51 | oo = [o + l[2:] for o in oo] |
| 52 | continue |
| 53 | if l[0] == '-': |
| 54 | if not st[0]: |
| 55 | oo[0] += colors.red |
| 56 | st[0] = True |
| 57 | oo[0] += l[2:] |
| 58 | continue |
| 59 | if l[0] == '+': |
| 60 | if not st[1]: |
| 61 | oo[1] += colors.green |
| 62 | st[1] = True |
| 63 | oo[1] += l[2:] |
| 64 | for i in range(2): |
| 65 | if st[i]: |
| 66 | oo[i] += colors.end |
| 67 | st[i] = 0 |
| 68 | oo = [o.replace ('\n', '') for o in oo] |
| 69 | if oo[0] == oo[1]: |
| 70 | return [' ', oo[0], '\n'] |
| 71 | return ['-', oo[0], '\n', '+', oo[1], '\n'] |
| 72 | |
| 73 | @staticmethod |
| 74 | def diff_files (f1, f2, colors=Colors.Null): |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 75 | try: |
| 76 | for (l1,l2) in zip (f1, f2): |
| 77 | if l1 == l2: |
| 78 | sys.stdout.writelines ([" ", l1]) |
| 79 | continue |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 80 | |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 81 | sys.stdout.writelines (FancyDiffer.diff_lines (l1, l2, colors)) |
| 82 | # print out residues |
| 83 | for l in f1: |
| 84 | sys.stdout.writelines (["-", colors.red, l1, colors.end]) |
| 85 | for l in f1: |
| 86 | sys.stdout.writelines (["-", colors.green, l1, colors.end]) |
| 87 | except IOError as e: |
| 88 | if e.errno != errno.EPIPE: |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 89 | print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror) |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 90 | sys.exit (1) |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 91 | |
Behdad Esfahbod | ad34e39 | 2012-01-20 18:39:27 -0500 | [diff] [blame] | 92 | |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 93 | class DiffFilters: |
| 94 | |
| 95 | @staticmethod |
| 96 | def filter_failures (f): |
| 97 | for l in f: |
| 98 | if l[0] in '-+': |
| 99 | sys.stdout.writelines (l) |
| 100 | |
| 101 | |
Behdad Esfahbod | ad34e39 | 2012-01-20 18:39:27 -0500 | [diff] [blame] | 102 | class ShapeFilters: |
| 103 | |
| 104 | @staticmethod |
| 105 | def filter_failures (f): |
| 106 | for l in f: |
| 107 | if l[0] in '-+': |
| 108 | sys.stdout.writelines (l) |
| 109 | |
| 110 | |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 111 | class UtilMains: |
| 112 | |
| 113 | @staticmethod |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 114 | def process_multiple_files (callback, mnemonic = "FILE"): |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 115 | |
| 116 | if len (sys.argv) == 1: |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 117 | print "Usage: %s %s..." % (sys.argv[0], mnemonic) |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 118 | sys.exit (1) |
| 119 | |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 120 | try: |
| 121 | for s in sys.argv[1:]: |
| 122 | callback (FileHelpers.open_file_or_stdin (s)) |
| 123 | except IOError as e: |
| 124 | if e.errno != errno.EPIPE: |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 125 | print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror) |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 126 | sys.exit (1) |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 127 | |
| 128 | @staticmethod |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 129 | def process_multiple_args (callback, mnemonic): |
| 130 | |
| 131 | if len (sys.argv) == 1: |
| 132 | print "Usage: %s %s..." % (sys.argv[0], mnemonic) |
| 133 | sys.exit (1) |
| 134 | |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 135 | try: |
| 136 | for s in sys.argv[1:]: |
| 137 | callback (s) |
| 138 | except IOError as e: |
| 139 | if e.errno != errno.EPIPE: |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 140 | print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror) |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 141 | sys.exit (1) |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 142 | |
| 143 | @staticmethod |
| 144 | def filter_multiple_strings_or_stdin (callback, mnemonic, \ |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 145 | separator = " ", \ |
| 146 | concat_separator = False): |
| 147 | |
| 148 | if len (sys.argv) == 1 or ('--stdin' in sys.argv and len (sys.argv) != 2): |
| 149 | print "Usage:\n %s %s...\nor:\n %s --stdin" \ |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 150 | % (sys.argv[0], mnemonic, sys.argv[0]) |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 151 | sys.exit (1) |
| 152 | |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 153 | try: |
| 154 | if '--stdin' in sys.argv: |
| 155 | sys.argv.remove ('--stdin') |
| 156 | while (1): |
| 157 | line = sys.stdin.readline () |
| 158 | if not len (line): |
| 159 | break |
| 160 | print callback (line) |
| 161 | else: |
| 162 | args = sys.argv[1:] |
| 163 | if concat_separator != False: |
| 164 | args = [concat_separator.join (args)] |
| 165 | print separator.join (callback (x) for x in (args)) |
| 166 | except IOError as e: |
| 167 | if e.errno != errno.EPIPE: |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 168 | print >> sys.stderr, "%s: %s: %s" % (sys.argv[0], e.filename, e.strerror) |
Behdad Esfahbod | 3a34e9e | 2012-01-21 19:15:41 -0500 | [diff] [blame] | 169 | sys.exit (1) |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 170 | |
| 171 | |
| 172 | class Unicode: |
| 173 | |
| 174 | @staticmethod |
| 175 | def decode (s): |
Behdad Esfahbod | 46ac456 | 2012-01-20 19:32:17 -0500 | [diff] [blame] | 176 | return '<' + u','.join ("U+%04X" % ord (u) for u in unicode (s, 'utf-8')).encode ('utf-8') + '>' |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 177 | |
| 178 | @staticmethod |
| 179 | def encode (s): |
Behdad Esfahbod | 46ac456 | 2012-01-20 19:32:17 -0500 | [diff] [blame] | 180 | s = re.sub (r"[<+>,\\uU\n ]", " ", s) |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 181 | s = re.sub (r"0[xX]", " ", s) |
Behdad Esfahbod | 46ac456 | 2012-01-20 19:32:17 -0500 | [diff] [blame] | 182 | return u''.join (unichr (int (x, 16)) for x in s.split (' ') if len (x)).encode ('utf-8') |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 183 | |
| 184 | shorthands = { |
| 185 | "ZERO WIDTH NON-JOINER": "ZWNJ", |
| 186 | "ZERO WIDTH JOINER": "ZWJ", |
| 187 | "NARROW NO-BREAK SPACE": "NNBSP", |
| 188 | "COMBINING GRAPHEME JOINER": "CGJ", |
| 189 | "LEFT-TO-RIGHT MARK": "LRM", |
| 190 | "RIGHT-TO-LEFT MARK": "RLM", |
| 191 | "LEFT-TO-RIGHT EMBEDDING": "LRE", |
| 192 | "RIGHT-TO-LEFT EMBEDDING": "RLE", |
| 193 | "POP DIRECTIONAL FORMATTING": "PDF", |
| 194 | "LEFT-TO-RIGHT OVERRIDE": "LRO", |
| 195 | "RIGHT-TO-LEFT OVERRIDE": "RLO", |
| 196 | } |
| 197 | |
| 198 | @staticmethod |
| 199 | def pretty_name (u): |
| 200 | try: |
| 201 | s = unicodedata.name (u) |
| 202 | except ValueError: |
| 203 | return "XXX" |
| 204 | s = re.sub (".* LETTER ", "", s) |
| 205 | s = re.sub (".* VOWEL SIGN (.*)", r"\1-MATRA", s) |
| 206 | s = re.sub (".* SIGN ", "", s) |
| 207 | s = re.sub (".* COMBINING ", "", s) |
| 208 | if re.match (".* VIRAMA", s): |
| 209 | s = "HALANT" |
| 210 | if s in Unicode.shorthands: |
| 211 | s = Unicode.shorthands[s] |
| 212 | return s |
| 213 | |
| 214 | @staticmethod |
| 215 | def pretty_names (s): |
| 216 | s = re.sub (r"[<+>\\uU]", " ", s) |
| 217 | s = re.sub (r"0[xX]", " ", s) |
| 218 | s = [unichr (int (x, 16)) for x in re.split ('[, \n]', s) if len (x)] |
Behdad Esfahbod | 46ac456 | 2012-01-20 19:32:17 -0500 | [diff] [blame] | 219 | return u' + '.join (Unicode.pretty_name (x) for x in s).encode ('utf-8') |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 220 | |
Behdad Esfahbod | ad34e39 | 2012-01-20 18:39:27 -0500 | [diff] [blame] | 221 | |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 222 | class FileHelpers: |
Behdad Esfahbod | ad34e39 | 2012-01-20 18:39:27 -0500 | [diff] [blame] | 223 | |
| 224 | @staticmethod |
| 225 | def open_file_or_stdin (f): |
| 226 | if f == '-': |
| 227 | return sys.stdin |
| 228 | return file (f) |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 229 | |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 230 | |
| 231 | class Manifest: |
| 232 | |
| 233 | @staticmethod |
| 234 | def print_to_stdout (s, strict = True): |
| 235 | if not os.path.exists (s): |
| 236 | if strict: |
| 237 | print >> sys.stderr, "%s: %s does not exist" (sys.argv[0], s) |
| 238 | sys.exit (1) |
| 239 | return |
| 240 | |
| 241 | if os.path.isdir (s): |
| 242 | |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 243 | if s[-1] in '/\\': |
| 244 | s = s[:-1] |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 245 | |
| 246 | try: |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 247 | m = file (os.path.join (s, "MANIFEST")) |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 248 | items = [x.strip () for x in m.readlines ()] |
| 249 | for f in items: |
| 250 | Manifest.print_to_stdout (s + f) |
| 251 | except IOError: |
| 252 | if strict: |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 253 | print >> sys.stderr, "%s: %s does not exist" (sys.argv[0], os.path.join (s, "MANIFEST")) |
Behdad Esfahbod | 96968bf | 2012-01-20 21:16:34 -0500 | [diff] [blame] | 254 | sys.exit (1) |
| 255 | return |
| 256 | else: |
| 257 | print s |
| 258 | |
Behdad Esfahbod | 956d552 | 2012-01-21 19:31:51 -0500 | [diff] [blame^] | 259 | @staticmethod |
| 260 | def update_recursive (s): |
| 261 | |
| 262 | for dirpath, dirnames, filenames in os.walk (s, followlinks=True): |
| 263 | |
| 264 | for f in ["MANIFEST", "README", "LICENSE", "COPYING", "AUTHORS", "SOURCES"]: |
| 265 | if f in dirnames: |
| 266 | dirnames.remove (f) |
| 267 | if f in filenames: |
| 268 | filenames.remove (f) |
| 269 | dirnames.sort () |
| 270 | filenames.sort () |
| 271 | ms = os.path.join (dirpath, "MANIFEST") |
| 272 | print " GEN %s" % ms |
| 273 | m = open (ms, "w") |
| 274 | for f in filenames: |
| 275 | print >> m, f |
| 276 | for f in dirnames: |
| 277 | print >> m, f |
| 278 | for f in dirnames: |
| 279 | Manifest.update_recursive (os.path.join (dirpath, f)) |
| 280 | |
Behdad Esfahbod | 91540a7 | 2012-01-20 18:27:52 -0500 | [diff] [blame] | 281 | if __name__ == '__main__': |
| 282 | pass |