source_index.py revision 5821806d5e7f356e8fa4b058a389a808ea183019
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/env python 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2011 The Chromium Authors. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Usage: <win-path-to-pdb.pdb> 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)This tool will take a PDB on the command line, extract the source files that 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)were used in building the PDB, query SVN for which repository and revision 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)these files are at, and then finally write this information back into the PDB 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)in a format that the debugging tools understand. This allows for automatic 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)source debugging, as all of the information is contained in the PDB, and the 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)debugger can go out and fetch the source files via SVN. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)You most likely want to run these immediately after a build, since the source 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)input files need to match the generated PDB, and we want the correct SVN 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)revision information for the exact files that were used for the build. 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The following files from a windbg + source server installation are expected 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to reside in the same directory as this python script: 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dbghelp.dll 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pdbstr.exe 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srctool.exe 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)NOTE: Expected to run under a native win32 python, NOT cygwin. All paths are 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)dealt with as win32 paths, since we have to interact with the Microsoft tools. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import sys 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import time 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import tempfile 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This serves two purposes. First, it acts as a whitelist, and only files 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# from repositories listed here will be source indexed. Second, it allows us 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# to map from one SVN URL to another, so we can map to external SVN servers. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)REPO_MAP = { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "svn://chrome-svn/chrome": "http://src.chromium.org/svn", 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "svn://chrome-svn.corp.google.com/chrome": "http://src.chromium.org/svn", 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http://v8.googlecode.com/svn": None, 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http://google-breakpad.googlecode.com/svn": None, 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http://googletest.googlecode.com/svn": None, 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http://open-vcdiff.googlecode.com/svn": None, 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) "http://google-url.googlecode.com/svn": None, 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FindFile(filename): 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Return the full windows path to a file in the same dir as this code.""" 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) thisdir = os.path.dirname(os.path.join(os.path.curdir, __file__)) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return os.path.abspath(os.path.join(thisdir, filename)) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractSourceFiles(pdb_filename): 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Extract a list of local paths of the source files from a PDB.""" 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srctool = subprocess.Popen([FindFile('srctool.exe'), '-r', pdb_filename], 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout=subprocess.PIPE, stderr=subprocess.PIPE) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filelist = srctool.stdout.read() 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res = srctool.wait() 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if res != 0 or filelist.startswith("srctool: "): 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise "srctool failed: " + filelist 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [x for x in filelist.split('\r\n') if len(x) != 0] 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ReadSourceStream(pdb_filename): 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Read the contents of the source information stream from a PDB.""" 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srctool = subprocess.Popen([FindFile('pdbstr.exe'), 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '-r', '-s:srcsrv', 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '-p:%s' % pdb_filename], 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout=subprocess.PIPE, stderr=subprocess.PIPE) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = srctool.stdout.read() 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res = srctool.wait() 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (res != 0 and res != -1) or data.startswith("pdbstr: "): 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise "pdbstr failed: " + data 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return data 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def WriteSourceStream(pdb_filename, data): 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Write the contents of the source information stream to a PDB.""" 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Write out the data to a temporary filename that we can pass to pdbstr. 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (f, fname) = tempfile.mkstemp() 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f = os.fdopen(f, "wb") 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.write(data) 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) f.close() 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srctool = subprocess.Popen([FindFile('pdbstr.exe'), 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '-w', '-s:srcsrv', 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '-i:%s' % fname, 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) '-p:%s' % pdb_filename], 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout=subprocess.PIPE, stderr=subprocess.PIPE) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) data = srctool.stdout.read() 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res = srctool.wait() 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (res != 0 and res != -1) or data.startswith("pdbstr: "): 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise "pdbstr failed: " + data 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) os.unlink(fname) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# TODO for performance, we should probably work in directories instead of 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# files. I'm scared of DEPS and generated files, so for now we query each 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# individual file, and don't make assumptions that all files in the same 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# directory are part of the same repository or at the same revision number. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ExtractSvnInfo(local_filename): 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Calls svn info to extract the repository, path, and revision.""" 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # We call svn.bat to make sure and get the depot tools SVN and not cygwin. 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) srctool = subprocess.Popen(['svn.bat', 'info', local_filename], 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stdout=subprocess.PIPE, stderr=subprocess.PIPE) 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info = srctool.stdout.read() 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) res = srctool.wait() 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if res != 0: 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return None 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Hack up into a dictionary of the fields printed by svn info. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vals = dict((y.split(': ', 2) for y in info.split('\r\n') if y)) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root = vals['Repository Root'] 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not vals['URL'].startswith(root): 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise "URL is not inside of the repository root?!?" 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = vals['URL'][len(root):] 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rev = int(vals['Revision']) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return [root, path, rev] 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def UpdatePDB(pdb_filename, verbose=False): 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Update a pdb file with source information.""" 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir_blacklist = { } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # TODO(deanm) look into "compressing" our output, by making use of vars 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # and other things, so we don't need to duplicate the repo path and revs. 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines = [ 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SRCSRV: ini ------------------------------------------------', 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'VERSION=1', 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'INDEXVERSION=2', 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'VERCTRL=Subversion', 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'DATETIME=%s' % time.asctime(), 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SRCSRV: variables ------------------------------------------', 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SVN_EXTRACT_TARGET=%targ%\%fnbksl%(%var3%)\%var4%\%fnfile%(%var1%)', 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SVN_EXTRACT_CMD=cmd /c svn cat "%var2%%var3%@%var4%" --non-interactive > "%svn_extract_target%"', 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SRCSRVTRG=%SVN_extract_target%', 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SRCSRVCMD=%SVN_extract_cmd%', 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'SRCSRV: source files ---------------------------------------', 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ] 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ReadSourceStream(pdb_filename): 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise "PDB already has source indexing information!" 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filelist = ExtractSourceFiles(pdb_filename) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for filename in filelist: 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filedir = os.path.dirname(filename) 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if verbose: 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "Processing: %s" % filename 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This directory is blacklisted, either because it's not part of the SVN 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # repository, or from one we're not interested in indexing. 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if dir_blacklist.get(filedir, False): 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if verbose: 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print " skipping, directory is blacklisted." 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) info = ExtractSvnInfo(filename) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Skip the file if it's not under an svn repository. To avoid constantly 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # querying SVN for files outside of SVN control (for example, the CRT 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # sources), check if the directory is outside of SVN and blacklist it. 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not info: 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not ExtractSvnInfo(filedir): 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir_blacklist[filedir] = True 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if verbose: 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print " skipping, file is not in an SVN repository" 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root = info[0] 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = info[1] 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rev = info[2] 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check if file was from a svn repository we don't know about, or don't 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # want to index. Blacklist the entire directory. 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not REPO_MAP.has_key(info[0]): 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if verbose: 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print " skipping, file is from an unknown SVN repository %s" % root 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) dir_blacklist[filedir] = True 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # We might want to map an internal repository URL to an external repository. 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if REPO_MAP[root]: 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) root = REPO_MAP[root] 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines.append('%s*%s*%s*%s' % (filename, root, path, rev)) 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if verbose: 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print " indexed file." 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines.append('SRCSRV: end ------------------------------------------------') 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WriteSourceStream(pdb_filename, '\r\n'.join(lines)) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def main(): 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(sys.argv) < 2 or len(sys.argv) > 3: 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) print "usage: file.pdb [-v]" 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verbose = False 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if len(sys.argv) == 3: 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verbose = (sys.argv[2] == '-v') 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdatePDB(sys.argv[1], verbose=verbose) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)if __name__ == '__main__': 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sys.exit(main()) 213