ewan@6766: #!/usr/bin/env python ewan@6766: ewan@6766: # pythfilter.py v1.5.5, written by Matthias Baas (baas@ira.uka.de) ewan@6766: ewan@6766: # Doxygen filter which can be used to document Python source code. ewan@6766: # Classes (incl. methods) and functions can be documented. ewan@6766: # Every comment that begins with ## is literally turned into an ewan@6766: # Doxygen comment. Consecutive comment lines are turned into ewan@6766: # comment blocks (-> /** ... */). ewan@6766: # All the stuff is put inside a namespace with the same name as ewan@6766: # the source file. ewan@6766: ewan@6766: # Conversions: ewan@6766: # ============ ewan@6766: # ##-blocks -> /** ... */ ewan@6766: # "class name(base): ..." -> "class name : public base {...}" ewan@6766: # "def name(params): ..." -> "name(params) {...}" ewan@6766: ewan@6766: # Changelog: ewan@6766: # 21.01.2003: Raw (r"") or unicode (u"") doc string will now be properly ewan@6766: # handled. (thanks to Richard Laager for the patch) ewan@6766: # 22.12.2003: Fixed a bug where no function names would be output for "def" ewan@6766: # blocks that were not in a class. ewan@6766: # (thanks to Richard Laager for the patch) ewan@6766: # 12.12.2003: Implemented code to handle static and class methods with ewan@6766: # this logic: Methods with "self" as the first argument are ewan@6766: # non-static. Methods with "cls" are Python class methods, ewan@6766: # which translate into static methods for Doxygen. Other ewan@6766: # methods are assumed to be static methods. As should be ewan@6766: # obvious, this logic doesn't take into account if the method ewan@6766: # is actually setup as a classmethod() or a staticmethod(), ewan@6766: # just if it follows the normal conventions. ewan@6766: # (thanks to Richard Laager for the patch) ewan@6766: # 11.12.2003: Corrected #includes to use os.path.sep instead of ".". Corrected ewan@6766: # namespace code to use "::" instead of ".". ewan@6766: # (thanks to Richard Laager for the patch) ewan@6766: # 11.12.2003: Methods beginning with two underscores that end with ewan@6766: # something other than two underscores are considered private ewan@6766: # and are handled accordingly. ewan@6766: # (thanks to Richard Laager for the patch) ewan@6766: # 03.12.2003: The first parameter of class methods (self) is removed from ewan@6766: # the documentation. ewan@6766: # 03.11.2003: The module docstring will be used as namespace documentation ewan@6766: # (thanks to Joe Bronkema for the patch) ewan@6766: # 08.07.2003: Namespaces get a default documentation so that the namespace ewan@6766: # and its contents will show up in the generated documentation. ewan@6766: # 05.02.2003: Directories will be delted during synchronization. ewan@6766: # 31.01.2003: -f option & filtering entire directory trees. ewan@6766: # 10.08.2002: In base classes the '.' will be replaced by '::' ewan@6766: # 18.07.2002: * and ** will be translated into arguments ewan@6766: # 18.07.2002: Argument lists may contain default values using constructors. ewan@6766: # 18.06.2002: Support for ## public: ewan@6766: # 21.01.2002: from ... import will be translated to "using namespace ...;" ewan@6766: # TODO: "from ... import *" vs "from ... import names" ewan@6766: # TODO: Using normal imports: name.name -> name::name ewan@6766: # 20.01.2002: #includes will be placed in front of the namespace ewan@6766: ewan@6766: ###################################################################### ewan@6766: ewan@6766: # The program is written as a state machine with the following states: ewan@6766: # ewan@6766: # - OUTSIDE The current position is outside any comment, ewan@6766: # class definition or function. ewan@6766: # ewan@6766: # - BUILD_COMMENT Begins with first "##". ewan@6766: # Ends with the first token that is no "##" ewan@6766: # at the same column as before. ewan@6766: # ewan@6766: # - BUILD_CLASS_DECL Begins with "class". ewan@6766: # Ends with ":" ewan@6766: # - BUILD_CLASS_BODY Begins just after BUILD_CLASS_DECL. ewan@6766: # The first following token (which is no comment) ewan@6766: # determines indentation depth. ewan@6766: # Ends with a token that has a smaller indendation. ewan@6766: # ewan@6766: # - BUILD_DEF_DECL Begins with "def". ewan@6766: # Ends with ":". ewan@6766: # - BUILD_DEF_BODY Begins just after BUILD_DEF_DECL. ewan@6766: # The first following token (which is no comment) ewan@6766: # determines indentation depth. ewan@6766: # Ends with a token that has a smaller indendation. ewan@6766: ewan@6766: import getopt ewan@6766: import glob ewan@6766: import os.path ewan@6766: import re ewan@6766: import shutil ewan@6766: import string ewan@6766: import sys ewan@6766: import token ewan@6766: import tokenize ewan@6766: ewan@6766: from stat import * ewan@6766: ewan@6766: OUTSIDE = 0 ewan@6766: BUILD_COMMENT = 1 ewan@6766: BUILD_CLASS_DECL = 2 ewan@6766: BUILD_CLASS_BODY = 3 ewan@6766: BUILD_DEF_DECL = 4 ewan@6766: BUILD_DEF_BODY = 5 ewan@6766: IMPORT = 6 ewan@6766: IMPORT_OP = 7 ewan@6766: IMPORT_APPEND = 8 ewan@6766: ewan@6766: # Output file stream ewan@6766: outfile = sys.stdout ewan@6766: ewan@6766: # Output buffer ewan@6766: outbuffer = [] ewan@6766: ewan@6766: out_row = 1 ewan@6766: out_col = 0 ewan@6766: ewan@6766: # Variables used by rec_name_n_param() ewan@6766: name = "" ewan@6766: param = "" ewan@6766: doc_string = "" ewan@6766: record_state = 0 ewan@6766: bracket_counter = 0 ewan@6766: ewan@6766: # Tuple: (row,column) ewan@6766: class_spos = (0,0) ewan@6766: def_spos = (0,0) ewan@6766: import_spos = (0,0) ewan@6766: ewan@6766: # Which import was used? ("import" or "from") ewan@6766: import_token = "" ewan@6766: ewan@6766: # Comment block buffer ewan@6766: comment_block = [] ewan@6766: comment_finished = 0 ewan@6766: ewan@6766: # Imported modules ewan@6766: modules = [] ewan@6766: ewan@6766: # Program state ewan@6766: stateStack = [OUTSIDE] ewan@6766: ewan@6766: # Keep track of whether module has a docstring ewan@6766: module_has_docstring = False ewan@6766: ewan@6766: # Keep track of member protection ewan@6766: protection_level = "public" ewan@6766: private_member = False ewan@6766: ewan@6766: # Keep track of the module namespace ewan@6766: namespace = "" ewan@6766: ewan@6766: ###################################################################### ewan@6766: # Output string s. '\n' may only be at the end of the string (not ewan@6766: # somewhere in the middle). ewan@6766: # ewan@6766: # In: s - String ewan@6766: # spos - Startpos ewan@6766: ###################################################################### ewan@6766: def output(s,spos, immediate=0): ewan@6766: global outbuffer, out_row, out_col, outfile ewan@6766: ewan@6766: os = string.rjust(s,spos[1]-out_col+len(s)) ewan@6766: ewan@6766: if immediate: ewan@6766: outfile.write(os) ewan@6766: else: ewan@6766: outbuffer.append(os) ewan@6766: ewan@6766: assert -1 == string.find(s[0:-2], "\n"), s ewan@6766: ewan@6766: if (s[-1:]=="\n"): ewan@6766: out_row = out_row+1 ewan@6766: out_col = 0 ewan@6766: else: ewan@6766: out_col = spos[1]+len(s) ewan@6766: ewan@6766: ewan@6766: ###################################################################### ewan@6766: # Records a name and parameters. The name is either a class name or ewan@6766: # a function name. Then the parameter is either the base class or ewan@6766: # the function parameters. ewan@6766: # The name is stored in the global variable "name", the parameters ewan@6766: # in "param". ewan@6766: # The variable "record_state" holds the current state of this internal ewan@6766: # state machine. ewan@6766: # The recording is started by calling start_recording(). ewan@6766: # ewan@6766: # In: type, tok ewan@6766: ###################################################################### ewan@6766: def rec_name_n_param(type, tok): ewan@6766: global record_state,name,param,doc_string,bracket_counter ewan@6766: s = record_state ewan@6766: # State 0: Do nothing. ewan@6766: if (s==0): ewan@6766: return ewan@6766: # State 1: Remember name. ewan@6766: elif (s==1): ewan@6766: name = tok ewan@6766: record_state = 2 ewan@6766: # State 2: Wait for opening bracket or colon ewan@6766: elif (s==2): ewan@6766: if (tok=='('): ewan@6766: bracket_counter = 1 ewan@6766: record_state=3 ewan@6766: if (tok==':'): record_state=4 ewan@6766: # State 3: Store parameter (or base class) and wait for an ending bracket ewan@6766: elif (s==3): ewan@6766: if (tok=='*' or tok=='**'): ewan@6766: tok='' ewan@6766: if (tok=='('): ewan@6766: bracket_counter = bracket_counter+1 ewan@6766: if (tok==')'): ewan@6766: bracket_counter = bracket_counter-1 ewan@6766: if bracket_counter==0: ewan@6766: record_state=4 ewan@6766: else: ewan@6766: param=param+tok ewan@6766: # State 4: Look for doc string ewan@6766: elif (s==4): ewan@6766: if (type==token.NEWLINE or type==token.INDENT or type==token.SLASHEQUAL): ewan@6766: return ewan@6766: elif (tok==":"): ewan@6766: return ewan@6766: elif (type==token.STRING): ewan@6766: while tok[:1]=='r' or tok[:1]=='u': ewan@6766: tok=tok[1:] ewan@6766: while tok[:1]=='"': ewan@6766: tok=tok[1:] ewan@6766: while tok[-1:]=='"': ewan@6766: tok=tok[:-1] ewan@6766: doc_string=tok ewan@6766: record_state=0 ewan@6766: ewan@6766: ###################################################################### ewan@6766: # Starts the recording of a name & param part. ewan@6766: # The function rec_name_n_param() has to be fed with tokens. After ewan@6766: # the necessary tokens are fed the name and parameters can be found ewan@6766: # in the global variables "name" und "param". ewan@6766: ###################################################################### ewan@6766: def start_recording(): ewan@6766: global record_state,param,name, doc_string ewan@6766: record_state=1 ewan@6766: name="" ewan@6766: param="" ewan@6766: doc_string="" ewan@6766: ewan@6766: ###################################################################### ewan@6766: # Test if recording is finished ewan@6766: ###################################################################### ewan@6766: def is_recording_finished(): ewan@6766: global record_state ewan@6766: return record_state==0 ewan@6766: ewan@6766: ###################################################################### ewan@6766: ## Gather comment block ewan@6766: ###################################################################### ewan@6766: def gather_comment(type,tok,spos): ewan@6766: global comment_block,comment_finished ewan@6766: if (type!=tokenize.COMMENT): ewan@6766: comment_finished = 1 ewan@6766: else: ewan@6766: # Output old comment block if a new one is started. ewan@6766: if (comment_finished): ewan@6766: print_comment(spos) ewan@6766: comment_finished=0 ewan@6766: if (tok[0:2]=="##" and tok[0:3]!="###"): ewan@6766: append_comment_lines(tok[2:]) ewan@6766: ewan@6766: ###################################################################### ewan@6766: ## Output comment block and empty buffer. ewan@6766: ###################################################################### ewan@6766: def print_comment(spos): ewan@6766: global comment_block,comment_finished ewan@6766: if (comment_block!=[]): ewan@6766: output("/** ",spos) ewan@6766: for c in comment_block: ewan@6766: output(c,spos) ewan@6766: output("*/\n",spos) ewan@6766: comment_block = [] ewan@6766: comment_finished = 0 ewan@6766: ewan@6766: ###################################################################### ewan@6766: def set_state(s): ewan@6766: global stateStack ewan@6766: stateStack[len(stateStack)-1]=s ewan@6766: ewan@6766: ###################################################################### ewan@6766: def get_state(): ewan@6766: global stateStack ewan@6766: return stateStack[len(stateStack)-1] ewan@6766: ewan@6766: ###################################################################### ewan@6766: def push_state(s): ewan@6766: global stateStack ewan@6766: stateStack.append(s) ewan@6766: ewan@6766: ###################################################################### ewan@6766: def pop_state(): ewan@6766: global stateStack ewan@6766: stateStack.pop() ewan@6766: ewan@6766: ewan@6766: ###################################################################### ewan@6766: def tok_eater(type, tok, spos, epos, line): ewan@6766: global stateStack,name,param,class_spos,def_spos,import_spos ewan@6766: global doc_string, modules, import_token, module_has_docstring ewan@6766: global protection_level, private_member ewan@6766: global out_row ewan@6766: ewan@6766: while out_row + 1 < spos[0]: ewan@6766: output("\n", (0, 0)) ewan@6766: ewan@6766: rec_name_n_param(type,tok) ewan@6766: if (string.replace(string.strip(tok)," ","")=="##private:"): ewan@6766: protection_level = "private" ewan@6766: output("private:\n",spos) ewan@6766: elif (string.replace(string.strip(tok)," ","")=="##protected:"): ewan@6766: protection_level = "protected" ewan@6766: output("protected:\n",spos) ewan@6766: elif (string.replace(string.strip(tok)," ","")=="##public:"): ewan@6766: protection_level = "public" ewan@6766: output("public:\n",spos) ewan@6766: else: ewan@6766: gather_comment(type,tok,spos) ewan@6766: ewan@6766: state = get_state() ewan@6766: ewan@6766: # sys.stderr.write("%d: %s\n"%(state, tok)) ewan@6766: ewan@6766: # OUTSIDE ewan@6766: if (state==OUTSIDE): ewan@6766: if (tok=="class"): ewan@6766: start_recording() ewan@6766: class_spos = spos ewan@6766: push_state(BUILD_CLASS_DECL) ewan@6766: elif (tok=="def"): ewan@6766: start_recording() ewan@6766: def_spos = spos ewan@6766: push_state(BUILD_DEF_DECL) ewan@6766: elif (tok=="import") or (tok=="from"): ewan@6766: import_token = tok ewan@6766: import_spos = spos ewan@6766: modules = [] ewan@6766: push_state(IMPORT) ewan@6766: elif (spos[1] == 0 and tok[:3] == '"""'): ewan@6766: # Capture module docstring as namespace documentation ewan@6766: module_has_docstring = True ewan@6766: append_comment_lines("\\namespace %s\n" % namespace) ewan@6766: append_comment_lines(tok[3:-3]) ewan@6766: print_comment(spos) ewan@6766: ewan@6766: # IMPORT ewan@6766: elif (state==IMPORT): ewan@6766: if (type==token.NAME): ewan@6766: modules.append(tok) ewan@6766: set_state(IMPORT_OP) ewan@6766: # IMPORT_OP ewan@6766: elif (state==IMPORT_OP): ewan@6766: if (tok=="."): ewan@6766: set_state(IMPORT_APPEND) ewan@6766: elif (tok==","): ewan@6766: set_state(IMPORT) ewan@6766: else: ewan@6766: for m in modules: ewan@6766: output('#include "'+m.replace('.',os.path.sep)+'.py"\n', import_spos, immediate=1) ewan@6766: if import_token=="from": ewan@6766: output('using namespace '+m.replace('.', '::')+';\n', import_spos) ewan@6766: pop_state() ewan@6766: # IMPORT_APPEND ewan@6766: elif (state==IMPORT_APPEND): ewan@6766: if (type==token.NAME): ewan@6766: modules[len(modules)-1]+="."+tok ewan@6766: set_state(IMPORT_OP) ewan@6766: # BUILD_CLASS_DECL ewan@6766: elif (state==BUILD_CLASS_DECL): ewan@6766: if (is_recording_finished()): ewan@6766: s = "class "+name ewan@6766: if (param!=""): s = s+" : public "+param.replace('.','::') ewan@6766: if (doc_string!=""): ewan@6766: append_comment_lines(doc_string) ewan@6766: print_comment(class_spos) ewan@6766: output(s+"\n",class_spos) ewan@6766: output("{\n",(class_spos[0]+1,class_spos[1])) ewan@6766: protection_level = "public" ewan@6766: output(" public:\n",(class_spos[0]+2,class_spos[1])) ewan@6766: set_state(BUILD_CLASS_BODY) ewan@6766: # BUILD_CLASS_BODY ewan@6766: elif (state==BUILD_CLASS_BODY): ewan@6766: if (type!=token.INDENT and type!=token.NEWLINE and type!=40 and ewan@6766: type!=tokenize.NL and type!=tokenize.COMMENT and ewan@6766: (spos[1]<=class_spos[1])): ewan@6766: output("}; // end of class\n",(out_row+1,class_spos[1])) ewan@6766: pop_state() ewan@6766: elif (tok=="def"): ewan@6766: start_recording() ewan@6766: def_spos = spos ewan@6766: push_state(BUILD_DEF_DECL) ewan@6766: # BUILD_DEF_DECL ewan@6766: elif (state==BUILD_DEF_DECL): ewan@6766: if (is_recording_finished()): ewan@6766: param = param.replace("\n", " ") ewan@6766: param = param.replace("=", " = ") ewan@6766: params = param.split(",") ewan@6766: if BUILD_CLASS_BODY in stateStack: ewan@6766: if len(name) > 1 \ ewan@6766: and name[0:2] == '__' \ ewan@6766: and name[len(name)-2:len(name)] != '__' \ ewan@6766: and protection_level != 'private': ewan@6766: private_member = True ewan@6766: output(" private:\n",(def_spos[0]+2,def_spos[1])) ewan@6766: ewan@6766: if (doc_string != ""): ewan@6766: append_comment_lines(doc_string) ewan@6766: ewan@6766: print_comment(def_spos) ewan@6766: ewan@6766: output_function_decl(name, params) ewan@6766: # output("{\n",(def_spos[0]+1,def_spos[1])) ewan@6766: set_state(BUILD_DEF_BODY) ewan@6766: # BUILD_DEF_BODY ewan@6766: elif (state==BUILD_DEF_BODY): ewan@6766: if (type!=token.INDENT and type!=token.NEWLINE \ ewan@6766: and type!=40 and type!=tokenize.NL \ ewan@6766: and (spos[1]<=def_spos[1])): ewan@6766: # output("} // end of method/function\n",(out_row+1,def_spos[1])) ewan@6766: if private_member and protection_level != 'private': ewan@6766: private_member = False ewan@6766: output(" " + protection_level + ":\n",(def_spos[0]+2,def_spos[1])) ewan@6766: pop_state() ewan@6766: # else: ewan@6766: # output(tok,spos) ewan@6766: ewan@6766: ewan@6766: def output_function_decl(name, params): ewan@6766: global def_spos ewan@6766: ewan@6766: # Do we document a class method? then remove the 'self' parameter ewan@6766: if params[0] == 'self': ewan@6766: preamble = '' ewan@6766: params = params[1:] ewan@6766: else: ewan@6766: preamble = 'static ' ewan@6766: if params[0] == 'cls': ewan@6766: params = params[1:] ewan@6766: ewan@6766: param_string = string.join(params, ", Type ") ewan@6766: ewan@6766: if param_string == '': ewan@6766: param_string = '(' + param_string + ');\n' ewan@6766: else: ewan@6766: param_string = '(Type ' + param_string + ');\n' ewan@6766: ewan@6766: output(preamble, def_spos) ewan@6766: output(name, def_spos) ewan@6766: output(param_string, def_spos) ewan@6766: ewan@6766: ewan@6766: def append_comment_lines(lines): ewan@6766: map(append_comment_line, doc_string.split('\n')) ewan@6766: ewan@6766: paramRE = re.compile(r'(@param \w+):') ewan@6766: ewan@6766: def append_comment_line(line): ewan@6766: global paramRE ewan@6766: ewan@6766: comment_block.append(paramRE.sub(r'\1', line) + '\n') ewan@6766: ewan@6766: def dump(filename): ewan@6766: f = open(filename) ewan@6766: r = f.readlines() ewan@6766: for s in r: ewan@6766: sys.stdout.write(s) ewan@6766: ewan@6766: def filter(filename): ewan@6768: global name, module_has_docstring, source_root ewan@6766: ewan@6766: path,name = os.path.split(filename) ewan@6766: root,ext = os.path.splitext(name) ewan@6766: ewan@6768: if source_root and path.find(source_root) == 0: ewan@6768: path = path[len(source_root):] ewan@6768: ewan@6768: if path[0] == os.sep: ewan@6768: path = path[1:] ewan@6768: ewan@6768: ns = path.split(os.sep) ewan@6768: else: ewan@6768: ns = [] ewan@6768: ewan@6768: ns.append(root) ewan@6768: ewan@6768: for n in ns: ewan@6768: output("namespace " + n + " {\n",(0,0)) ewan@6766: ewan@6766: # set module name for tok_eater to use if there's a module doc string ewan@6766: name = root ewan@6766: ewan@6766: # sys.stderr.write('Filtering "'+filename+'"...') ewan@6766: f = open(filename) ewan@6766: tokenize.tokenize(f.readline, tok_eater) ewan@6766: f.close() ewan@6766: print_comment((0,0)) ewan@6766: ewan@6766: output("\n",(0,0)) ewan@6768: ewan@6768: for n in ns: ewan@6768: output("} // end of namespace\n",(0,0)) ewan@6766: ewan@6766: if not module_has_docstring: ewan@6766: # Put in default namespace documentation ewan@6766: output('/** \\namespace '+root+' \n',(0,0)) ewan@6766: output(' \\brief Module "%s" */\n'%(root),(0,0)) ewan@6766: ewan@6766: for s in outbuffer: ewan@6766: outfile.write(s) ewan@6766: ewan@6766: ewan@6766: def filterFile(filename, out=sys.stdout): ewan@6766: global outfile ewan@6766: ewan@6766: outfile = out ewan@6766: ewan@6766: try: ewan@6766: root,ext = os.path.splitext(filename) ewan@6766: ewan@6766: if ext==".py": ewan@6766: filter(filename) ewan@6766: else: ewan@6766: dump(filename) ewan@6766: ewan@6766: # sys.stderr.write("OK\n") ewan@6766: except IOError,e: ewan@6766: sys.stderr.write(e[1]+"\n") ewan@6766: ewan@6766: ewan@6766: ###################################################################### ewan@6766: ewan@6766: # preparePath ewan@6766: def preparePath(path): ewan@6766: """Prepare a path. ewan@6766: ewan@6766: Checks if the path exists and creates it if it does not exist. ewan@6766: """ ewan@6766: if not os.path.exists(path): ewan@6766: parent = os.path.dirname(path) ewan@6766: if parent!="": ewan@6766: preparePath(parent) ewan@6766: os.mkdir(path) ewan@6766: ewan@6766: # isNewer ewan@6766: def isNewer(file1,file2): ewan@6766: """Check if file1 is newer than file2. ewan@6766: ewan@6766: file1 must be an existing file. ewan@6766: """ ewan@6766: if not os.path.exists(file2): ewan@6766: return True ewan@6766: return os.stat(file1)[ST_MTIME]>os.stat(file2)[ST_MTIME] ewan@6766: ewan@6766: # convert ewan@6766: def convert(srcpath, destpath): ewan@6766: """Convert a Python source tree into a C+ stub tree. ewan@6766: ewan@6766: All *.py files in srcpath (including sub-directories) are filtered ewan@6766: and written to destpath. If destpath exists, only the files ewan@6766: that have been modified are filtered again. Files that were deleted ewan@6766: from srcpath are also deleted in destpath if they are still present. ewan@6766: The function returns the number of processed *.py files. ewan@6766: """ ewan@6766: count=0 ewan@6766: sp = os.path.join(srcpath,"*") ewan@6766: sfiles = glob.glob(sp) ewan@6766: dp = os.path.join(destpath,"*") ewan@6766: dfiles = glob.glob(dp) ewan@6766: leftovers={} ewan@6766: for df in dfiles: ewan@6766: leftovers[os.path.basename(df)]=1 ewan@6766: ewan@6766: for srcfile in sfiles: ewan@6766: basename = os.path.basename(srcfile) ewan@6766: if basename in leftovers: ewan@6766: del leftovers[basename] ewan@6766: ewan@6766: # Is it a subdirectory? ewan@6766: if os.path.isdir(srcfile): ewan@6766: sdir = os.path.join(srcpath,basename) ewan@6766: ddir = os.path.join(destpath,basename) ewan@6766: count+=convert(sdir, ddir) ewan@6766: continue ewan@6766: # Check the extension (only *.py will be converted) ewan@6766: root, ext = os.path.splitext(srcfile) ewan@6766: if ext.lower()!=".py": ewan@6766: continue ewan@6766: ewan@6766: destfile = os.path.join(destpath,basename) ewan@6766: if destfile==srcfile: ewan@6766: print "WARNING: Input and output names are identical!" ewan@6766: sys.exit(1) ewan@6766: ewan@6766: count+=1 ewan@6766: # sys.stdout.write("%s\015"%(srcfile)) ewan@6766: ewan@6766: if isNewer(srcfile, destfile): ewan@6766: preparePath(os.path.dirname(destfile)) ewan@6766: # out=open(destfile,"w") ewan@6766: # filterFile(srcfile, out) ewan@6766: # out.close() ewan@6766: os.system("python %s -f %s>%s"%(sys.argv[0],srcfile,destfile)) ewan@6766: ewan@6766: # Delete obsolete files in destpath ewan@6766: for df in leftovers: ewan@6766: dname=os.path.join(destpath,df) ewan@6766: if os.path.isdir(dname): ewan@6766: try: ewan@6766: shutil.rmtree(dname) ewan@6766: except: ewan@6766: print "Can't remove obsolete directory '%s'"%dname ewan@6766: else: ewan@6766: try: ewan@6766: os.remove(dname) ewan@6766: except: ewan@6766: print "Can't remove obsolete file '%s'"%dname ewan@6766: ewan@6766: return count ewan@6766: ewan@6766: ewan@6766: ###################################################################### ewan@6766: ###################################################################### ewan@6766: ###################################################################### ewan@6766: ewan@6766: filter_file = False ewan@6768: source_root = None ewan@6766: ewan@6766: try: ewan@6768: opts, args = getopt.getopt(sys.argv[1:], "hfr:", ["help"]) ewan@6766: except getopt.GetoptError,e: ewan@6766: print e ewan@6766: sys.exit(1) ewan@6766: ewan@6766: for o,a in opts: ewan@6766: if o=="-f": ewan@6766: filter_file = True ewan@6766: ewan@6768: if o=="-r": ewan@6768: source_root = os.path.abspath(a) ewan@6768: ewan@6766: if filter_file: ewan@6766: # Filter the specified file and print the result to stdout ewan@6766: filename = string.join(args) ewan@6768: filterFile(os.path.abspath(filename)) ewan@6766: else: ewan@6766: ewan@6766: if len(args)!=2: ewan@6766: sys.stderr.write("%s options input output\n"%(os.path.basename(sys.argv[0]))) ewan@6766: sys.exit(1) ewan@6766: ewan@6766: # Filter an entire Python source tree ewan@6766: print '"%s" -> "%s"\n'%(args[0],args[1]) ewan@6766: c=convert(args[0],args[1]) ewan@6766: print "%d files"%(c) ewan@6766: