1#!/usr/bin/env python 2# Protocol Buffers - Google's data interchange format 3# Copyright 2008 Google Inc. All rights reserved. 4# 5# Use of this source code is governed by a BSD-style 6# license that can be found in the LICENSE file or at 7# https://developers.google.com/open-source/licenses/bsd 8 9"""Script to update a failure list file to add/remove failures. 10 11When adding, will attempt to place them in their correct lexicographical 12position relative to other test names. This requires that the failure list is 13already sorted. This does not guarantee that the tests will appear neatly one 14after the other, as there may be comments in between. If the failure list 15is not sorted, sorted blocks may be produced, but the list as a whole will not. 16Lastly, be wary of lists that have tests stripped from OSS; if you catch that 17a test was added inside a stripped block, you may need to move it out. 18 19This is sort of like comm(1), except it recognizes comments and ignores them. 20""" 21 22import argparse 23 24parser = argparse.ArgumentParser( 25 description='Adds/removes failures from the failure list.') 26parser.add_argument('filename', type=str, help='failure list file to update') 27parser.add_argument('--add', dest='add_list', action='append') 28parser.add_argument('--remove', dest='remove_list', action='append') 29 30DEFAULT_ALIGNMENT = 114 31args = parser.parse_args() 32 33add_set = set() 34remove_set = set() 35 36# Adds test + failure message 37for add_file in (args.add_list or []): 38 with open(add_file) as f: 39 for line in f: 40 add_set.add(line) 41 42# We only remove by name 43for remove_file in (args.remove_list or []): 44 with open(remove_file) as f: 45 for line in f: 46 if line in add_set: 47 raise Exception("Asked to both add and remove test: " + line) 48 remove_set.add(line.split('#')[0].strip()) 49 50add_list = sorted(add_set, reverse=True) 51 52with open(args.filename) as in_file: 53 existing_list = in_file.read() 54 55with open(args.filename, 'w') as f: 56 split_lines = existing_list.splitlines(True) 57 # Make sure that we have one newline for potential tests that have to be 58 # added at the end. 59 split_lines[-1] = split_lines[-1].rstrip() + '\n' 60 for line in split_lines: 61 test = line.split('#')[0].strip() 62 # As long as the tests we are adding appear lexicographically before our 63 # read test, put them first followed by our read test. 64 while add_list and test > add_list[-1]: 65 f.write(add_list.pop()) 66 if test not in remove_set: 67 f.write(line) 68 # Any remaining tests are added at the end 69 while add_list: 70 f.write(add_list.pop()) 71 72# Update our read of the existing file 73with open(args.filename, 'r') as f: 74 existing_list = f.read() 75 76# Actual alignment of failure messages to 'DEFAULT_ALIGNMENT' 77# If test name exceeds DEFAULT_ALIGNMENT, it cannot and will not be aligned. 78with open(args.filename, 'w') as f: 79 for line in existing_list.splitlines(True): 80 split = line.split('#', 1) 81 test = split[0].strip() 82 if len(split) > 1 and test: 83 message = split[1].lstrip() 84 spaces = ' ' * (DEFAULT_ALIGNMENT - len(test)) 85 line = test + spaces + ' # ' + message 86 f.write(line) 87 else: # ignore blank lines/lines that do not have '#'/comments 88 f.write(line) 89