1#!/usr/bin/env python 2 3# Copyright 2012-2013 Daniel James 4# Distributed under the Boost Software License, Version 1.0. 5# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) 6 7import sys, os, subprocess, tempfile, re 8 9def main(args, directory): 10 if len(args) != 1: 11 print "Usage: output-deps.py quickbook-command" 12 exit(1) 13 quickbook_command = args[0] 14 15 failures = 0 16 17 # Dependency tests 18 19 failures += run_quickbook(quickbook_command, 'svg_missing.qbk', 20 deps_gold = 'svg_missing_deps.txt') 21 failures += run_quickbook(quickbook_command, 'svg_missing.qbk', 22 locations_gold = 'svg_missing_locs.txt') 23 failures += run_quickbook(quickbook_command, 'missing_relative.qbk', 24 deps_gold = 'missing_relative_deps.txt', 25 locations_gold = 'missing_relative_locs.txt') 26 failures += run_quickbook(quickbook_command, 'include_path.qbk', 27 deps_gold = 'include_path_deps.txt', 28 locations_gold = 'include_path_locs.txt', 29 input_path = ['sub1', 'sub2']) 30 failures += run_quickbook(quickbook_command, 'include_glob.qbk', 31 deps_gold = 'include_glob_deps.txt', 32 locations_gold = 'include_glob_locs.txt', 33 input_path = ['sub1', 'sub2']) 34 35 # Try building a simple document with various flags. 36 37 failures += run_quickbook(quickbook_command, 'simple.qbk', 38 output_gold = 'simple.xml') 39 failures += run_quickbook(quickbook_command, 'simple.qbk', 40 extra_flags = ['--no-self-linked-headers'], 41 output_gold = 'simple_no_self_linked.xml') 42 failures += run_quickbook(quickbook_command, 'simple.qbk', 43 extra_flags = ['--no-pretty-print'], 44 output_gold = 'simple_no_pretty_print.xml') 45 failures += run_quickbook(quickbook_command, 'simple.qbk', 46 extra_flags = ['--indent','4','--linewidth','60'], 47 output_gold = 'simple_custom_pretty_print.xml') 48 49 if failures == 0: 50 print "Success" 51 else: 52 print "Failures:",failures 53 exit(failures) 54 55def run_quickbook(quickbook_command, filename, output_gold = None, 56 deps_gold = None, locations_gold = None, input_path = [], 57 extra_flags = None): 58 failures = 0 59 60 command = [quickbook_command, '--debug', filename] 61 62 output_filename = None 63 if output_gold: 64 output_filename = temp_filename('.qbk') 65 command.extend(['--output-file', output_filename]) 66 67 deps_filename = None 68 if deps_gold: 69 deps_filename = temp_filename('.txt') 70 command.extend(['--output-deps', deps_filename]) 71 72 locations_filename = None 73 if locations_gold: 74 locations_filename = temp_filename('.txt') 75 command.extend(['--output-checked-locations', locations_filename]) 76 77 for path in input_path: 78 command.extend(['-I', path]) 79 80 if extra_flags: 81 command.extend(extra_flags) 82 83 try: 84 print 'Running: ' + ' '.join(command) 85 print 86 exit_code = subprocess.call(command) 87 print 88 success = not exit_code 89 90 if output_filename: 91 output = load_file(output_filename) 92 else: 93 output = None 94 95 if deps_filename: 96 deps = load_dependencies(deps_filename) 97 else: 98 deps = None 99 100 if locations_filename: 101 locations = load_locations(locations_filename) 102 else: 103 locations = None 104 finally: 105 if output_filename: os.unlink(output_filename) 106 if deps_filename: os.unlink(deps_filename) 107 108 if deps_gold: 109 gold = load_dependencies(deps_gold) 110 if deps != gold: 111 failures = failures + 1 112 print "Dependencies don't match:" 113 print "Gold:", gold 114 print "Result:", deps 115 print 116 117 if locations_gold: 118 gold = load_locations(locations_gold) 119 if locations != gold: 120 failures = failures + 1 121 print "Dependencies don't match:" 122 print "Gold:", gold 123 print "Result:", locations 124 print 125 126 if output_gold: 127 gold = load_file(output_gold) 128 if gold != output: 129 failures = failures + 1 130 print "Output doesn't match:" 131 print 132 print gold 133 print 134 print output 135 print 136 137 return failures 138 139def load_dependencies(filename): 140 dependencies = set() 141 f = open(filename, 'r') 142 for path in f: 143 if path[0] == '#': continue 144 if path in dependencies: 145 raise Exception("Duplicate path (%1s) in %2s" % (path, filename)) 146 dependencies.add(path) 147 return dependencies 148 149def load_locations(filename): 150 line_matcher = re.compile("^([+-g]) (.*)$") 151 dependencies = {} 152 f = open(filename, 'r') 153 glob = None 154 globs = {} 155 for line in f: 156 if line[0] == '#': continue 157 m = line_matcher.match(line) 158 159 path = m.group(2) 160 161 if not m: 162 raise Exception("Invalid dependency file: %1s" % filename) 163 if m.group(1) == 'g': 164 globs[path] = [] 165 glob = path 166 elif glob: 167 if m.group(1) != '+': 168 raise Exception("Negative match in glob.") 169 globs[glob].append(path) 170 else: 171 found = m.group(1) == '+' 172 if path in dependencies: 173 raise Exception("Duplicate path (%1s) in %2s" % (path, filename)) 174 dependencies[path] = found 175 return { 'dependencies': dependencies, 'globs': globs } 176 177def temp_filename(extension): 178 file = tempfile.mkstemp(suffix = extension) 179 os.close(file[0]) 180 return file[1] 181 182def load_file(filename): 183 f = open(filename, 'r') 184 try: 185 return f.read() 186 finally: 187 f.close() 188 189 return None 190 191main(sys.argv[1:], os.path.dirname(sys.argv[0])) 192