f | #!/usr/bin/env python | f | #!/usr/bin/env python |
| # | | # |
| # Homepage: http://code.google.com/p/coderev | | # Homepage: http://code.google.com/p/coderev |
| # License: GPLv2, see "COPYING" | | # License: GPLv2, see "COPYING" |
| # | | # |
n | # $Id: codediff.py 3 2008-08-19 04:06:17Z mattwyl $ | n | # $Id: codediff.py 9 2008-08-21 14:08:53Z mattwyl $ |
| | | |
| '''Diff two files/directories and produce HTML pages.''' | | '''Diff two files/directories and produce HTML pages.''' |
| | | |
| import sys, os, stat, errno, time, re, difflib, filecmp | | import sys, os, stat, errno, time, re, difflib, filecmp |
| | | |
| _myname = os.path.basename(sys.argv[0]) | | _myname = os.path.basename(sys.argv[0]) |
n | _revision = '$Revision: 3 $'.split()[1] | n | _revision = '$Revision: 9 $'.split()[1] |
| | | |
| | | |
| ########## globals & templates begin ########## | | ########## globals & templates begin ########## |
| # index page layout: | | # index page layout: |
| # | | # |
| # h1: dir1 vs dir2 | | # h1: dir1 vs dir2 |
| # summary_info: Files changed/added/deleted: xx/yy/zz | | # summary_info: Files changed/added/deleted: xx/yy/zz |
| # | | # |
| # Filename C/D/A Summary Diffs Sources | | # Filename C/D/A Summary Diffs Sources |
| # Pathname x/y/z Cdiffs Udiffs Sdiffs Fdiffs Old New | | # Pathname x/y/z Cdiffs Udiffs Sdiffs Fdiffs Old New |
| # Pathname x/y/z Cdiffs Udiffs Sdiffs Fdiffs Old New | | # Pathname x/y/z Cdiffs Udiffs Sdiffs Fdiffs Old New |
| # Pathname x/y/z - - - - - New | | # Pathname x/y/z - - - - - New |
| # Pathname x/y/z - - - - Old - | | # Pathname x/y/z - - - - Old - |
| # | | # |
| # Legends: | | # Legends: |
| # Changed Deleted Added | | # Changed Deleted Added |
| # <hr> | | # <hr> |
| # footer_info | | # footer_info |
| # | | # |
| | | |
| _file_template = """ | | _file_template = """ |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | | "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html> | | <html> |
| | | |
| <head> | | <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> | | <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" /> |
| <title> | | <title> |
| %(title)s | | %(title)s |
| </title> | | </title> |
| <style type="text/css"> | | <style type="text/css"> |
| %(styles)s | | %(styles)s |
| </style> | | </style> |
| </head> | | </head> |
| | | |
| <body> | | <body> |
| %(header_info)s | | %(header_info)s |
| %(summary_info)s | | %(summary_info)s |
| %(data_rows)s | | %(data_rows)s |
| %(legend)s | | %(legend)s |
| <hr> | | <hr> |
| %(footer_info)s | | %(footer_info)s |
| </body> | | </body> |
| | | |
| </html>""" | | </html>""" |
| | | |
| _styles = """ | | _styles = """ |
| body {font-family: monospace; font-size: 9pt;} | | body {font-family: monospace; font-size: 9pt;} |
| #summary_info {font-style: italic;} | | #summary_info {font-style: italic;} |
| #summary_table { | | #summary_table { |
| text-align:left;font-family:monospace; | | text-align:left;font-family:monospace; |
| border: 1px solid #ccc; border-collapse: collapse | | border: 1px solid #ccc; border-collapse: collapse |
| } | | } |
| td {padding-left:5px;padding-right:5px;} | | td {padding-left:5px;padding-right:5px;} |
| #legend {border:medium;text-align:center;} | | #legend {border:medium;text-align:center;} |
| #footer_info {color:#333; font-size:8pt;} | | #footer_info {color:#333; font-size:8pt;} |
| .diff {background-color:#ffd;} | | .diff {background-color:#ffd;} |
| .added {background-color:#afa;} | | .added {background-color:#afa;} |
| .deleted {background-color:#faa;} | | .deleted {background-color:#faa;} |
| .table_header th { | | .table_header th { |
| text-align:center; | | text-align:center; |
| background-color:#f0f0f0; | | background-color:#f0f0f0; |
| border-bottom: 1px solid #aaa; | | border-bottom: 1px solid #aaa; |
| padding: 4px 4px 4px 4px; | | padding: 4px 4px 4px 4px; |
| } | | } |
| """ | | """ |
| | | |
| _header_info_template = """ | | _header_info_template = """ |
| <h1>%(dir1)s vs %(dir2)s</h1>""" | | <h1>%(dir1)s vs %(dir2)s</h1>""" |
| | | |
| _summary_info_template = """ | | _summary_info_template = """ |
| <p id="summary_info"> | | <p id="summary_info"> |
| Files Changed/Deleted/Added: %(changed)d/%(deleted)d/%(added)d | | Files Changed/Deleted/Added: %(changed)d/%(deleted)d/%(added)d |
| </p>""" | | </p>""" |
| | | |
| _data_rows_template = """ | | _data_rows_template = """ |
| <table id="summary_table" cellspacing="1" border="1" nowrap="nowrap"> | | <table id="summary_table" cellspacing="1" border="1" nowrap="nowrap"> |
| <tr class="table_header"> | | <tr class="table_header"> |
| <th>Filename</th> | | <th>Filename</th> |
| <th><abbr title="Changed/Deleted/Added">C/D/A</abbr> Summary</th> | | <th><abbr title="Changed/Deleted/Added">C/D/A</abbr> Summary</th> |
| <th colspan="4">Diffs</th> | | <th colspan="4">Diffs</th> |
| <th colspan="2">Sources</th> | | <th colspan="2">Sources</th> |
| </tr> | | </tr> |
| %(data_rows)s | | %(data_rows)s |
| </table>""" | | </table>""" |
| | | |
| _diff_data_row_template = """ | | _diff_data_row_template = """ |
| <tr class="diff"> | | <tr class="diff"> |
| <td>%(pathname)s</td> | | <td>%(pathname)s</td> |
| <td><abbr title="Changed/Deleted/Added">%(changed)s/%(deleted)s/%(added)s</abbr></td> | | <td><abbr title="Changed/Deleted/Added">%(changed)s/%(deleted)s/%(added)s</abbr></td> |
| <td><a href=%(pathname)s.cdiff.html title="context diffs">Cdiffs</a></td> | | <td><a href=%(pathname)s.cdiff.html title="context diffs">Cdiffs</a></td> |
| <td><a href=%(pathname)s.udiff.html title="unified diffs">Udiffs</a></td> | | <td><a href=%(pathname)s.udiff.html title="unified diffs">Udiffs</a></td> |
| <td><a href=%(pathname)s.sdiff.html title="side-by-side context diffs">Sdiffs</a></td> | | <td><a href=%(pathname)s.sdiff.html title="side-by-side context diffs">Sdiffs</a></td> |
| <td><a href=%(pathname)s.fdiff.html title="side-by-side full diffs">Fdiffs</a></td> | | <td><a href=%(pathname)s.fdiff.html title="side-by-side full diffs">Fdiffs</a></td> |
| <td><a href=%(pathname)s-.html title="old file">Old</a></td> | | <td><a href=%(pathname)s-.html title="old file">Old</a></td> |
| <td><a href=%(pathname)s.html title="new file">New</a></td> | | <td><a href=%(pathname)s.html title="new file">New</a></td> |
| </tr>""" | | </tr>""" |
| | | |
| _deleted_data_row_template = """ | | _deleted_data_row_template = """ |
| <tr class="deleted"> | | <tr class="deleted"> |
| <td>%(pathname)s</td> | | <td>%(pathname)s</td> |
| <td>-/-/-</td> | | <td>-/-/-</td> |
| <td>-</td> | | <td>-</td> |
| <td>-</td> | | <td>-</td> |
| <td>-</td> | | <td>-</td> |
| <td>-</td> | | <td>-</td> |
| <td><a href=%(pathname)s-.html title="old file">Old</a></td> | | <td><a href=%(pathname)s-.html title="old file">Old</a></td> |
| <td>-</td> | | <td>-</td> |
| </tr>""" | | </tr>""" |
| | | |
| _added_data_row_template = """ | | _added_data_row_template = """ |
| <tr class="added"> | | <tr class="added"> |
| <td>%(pathname)s</td> | | <td>%(pathname)s</td> |
| <td>-/-/-</td> | | <td>-/-/-</td> |
| <td>-</td> | | <td>-</td> |
| <td>-</td> | | <td>-</td> |
| <td>-</td> | | <td>-</td> |
| <td>-</td> | | <td>-</td> |
| <td>-</td> | | <td>-</td> |
| <td><a href=%(pathname)s.html title="new file">New</a></td> | | <td><a href=%(pathname)s.html title="new file">New</a></td> |
| </tr>""" | | </tr>""" |
| | | |
| _legend = """ | | _legend = """ |
| <br><em>Legends:</em> | | <br><em>Legends:</em> |
| <table id="legend"> | | <table id="legend"> |
| <tr> | | <tr> |
| <td width="20%%" class="diff">Changed</td> | | <td width="20%%" class="diff">Changed</td> |
| <td width="20%%" class="deleted">Deleted</td> | | <td width="20%%" class="deleted">Deleted</td> |
| <td width="20%%" class="added">Added</td> | | <td width="20%%" class="added">Added</td> |
| </tr> | | </tr> |
| </table>""" | | </table>""" |
| | | |
| _footer_info_template = """ | | _footer_info_template = """ |
| <i id="footer_info"> | | <i id="footer_info"> |
| Generated by %(myname)s r%(revision)s at %(time)s | | Generated by %(myname)s r%(revision)s at %(time)s |
| </i>""" | | </i>""" |
| | | |
n | _global_dir_ignore_list = [ | n | _global_dir_ignore_list = ( |
| '\bCVS$', | | r'^CVS$', |
| '\bSCCS$', | | r'^SCCS$', |
| '\b\\.svn$', | | r'^\.svn$', |
| ] | | ) |
| | | |
n | _global_file_ignore_list = [ | n | _global_file_ignore_list = ( |
| '.*\\.o$', | | r'.*\.o$', |
| '.*\\.swp$', | | r'.*\.swp$', |
| '.*\\.bak$', | | r'.*\.bak$', |
| '.*\\.old$', | | r'.*\.old$', |
| '.*\\~$', | | r'.*~$', |
| '\\.cvsignore$', | | r'^\.cvsignore$', |
| ] | | ) |
| ########## globals & templates end ########## | | ########## globals & templates end ########## |
| | | |
| | | |
| def makeTitle(pathname, width): | | def makeTitle(pathname, width): |
| 'Wrap long pathname to abbreviate name to fit the text width' | | 'Wrap long pathname to abbreviate name to fit the text width' |
| if not pathname: | | if not pathname: |
| return 'None' | | return 'None' |
| | | |
| if not width or width <= 0: | | if not width or width <= 0: |
| title = pathname | | title = pathname |
| elif len(pathname) > width: | | elif len(pathname) > width: |
| if width > 3: | | if width > 3: |
| title = '...' + pathname[-(width-3):] | | title = '...' + pathname[-(width-3):] |
| else: | | else: |
| title = pathname[-width:] | | title = pathname[-width:] |
| else: | | else: |
| title = pathname | | title = pathname |
| return title | | return title |
| | | |
| | | |
| def getLines(file): | | def getLines(file): |
| '''Return content of file (a list, each is a line)''' | | '''Return content of file (a list, each is a line)''' |
| if not file: | | if not file: |
| return [] | | return [] |
| try: | | try: |
| fp = open(file, 'r') | | fp = open(file, 'r') |
| lines = fp.readlines() | | lines = fp.readlines() |
| fp.close() | | fp.close() |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| return lines | | return lines |
| | | |
| | | |
| def sdiffLines(fomeLines, toLines, outFile, fromTitle, toTitle, | | def sdiffLines(fomeLines, toLines, outFile, fromTitle, toTitle, |
| context, wrapnum, lines): | | context, wrapnum, lines): |
| '''diff two texts and return side-by-side html page, write to outFile. | | '''diff two texts and return side-by-side html page, write to outFile. |
| Return code indicating whether there are differences''' | | Return code indicating whether there are differences''' |
| d = difflib.HtmlDiff(wrapcolumn=wrapnum) | | d = difflib.HtmlDiff(wrapcolumn=wrapnum) |
| d._styles += ''' | | d._styles += ''' |
| /* customized style */ | | /* customized style */ |
| body { font-family:monospace; font-size: 9pt; } | | body { font-family:monospace; font-size: 9pt; } |
| table.diff {font-family:monospace; border:medium;}''' | | table.diff {font-family:monospace; border:medium;}''' |
| html = d.make_file(fomeLines, toLines, fromTitle, toTitle, context, lines) | | html = d.make_file(fomeLines, toLines, fromTitle, toTitle, context, lines) |
| | | |
| try: | | try: |
| fp = open(outFile, 'w') | | fp = open(outFile, 'w') |
| fp.write(html) | | fp.write(html) |
| fp.close() | | fp.close() |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| | | |
| | | |
| def cdiffLines(fomeLines, toLines, outFile, fromName, toName, | | def cdiffLines(fomeLines, toLines, outFile, fromName, toName, |
| fromDate, toDate, context): | | fromDate, toDate, context): |
| '''cdiff two texts and return summary info, write to outFile. | | '''cdiff two texts and return summary info, write to outFile. |
| Return code indicating whether there are differences''' | | Return code indicating whether there are differences''' |
| d = difflib.context_diff(fomeLines, toLines, fromName, toName, | | d = difflib.context_diff(fomeLines, toLines, fromName, toName, |
| fromDate, toDate, n=context) | | fromDate, toDate, n=context) |
| title = 'Cdiffs of %s and %s' % (fromName, toName) | | title = 'Cdiffs of %s and %s' % (fromName, toName) |
| summary, html = cdiffToHtml(d, title) | | summary, html = cdiffToHtml(d, title) |
| | | |
| try: | | try: |
| fp = open(outFile, 'w') | | fp = open(outFile, 'w') |
| fp.write(html) | | fp.write(html) |
| fp.close() | | fp.close() |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| | | |
| return summary | | return summary |
| | | |
| | | |
| def udiffLines(fomeLines, toLines, outFile, fromName, toName, | | def udiffLines(fomeLines, toLines, outFile, fromName, toName, |
| fromDate, toDate, n): | | fromDate, toDate, n): |
| '''udiff two texts and return html page, write to outFile. | | '''udiff two texts and return html page, write to outFile. |
| Return code indicating whether there are differences''' | | Return code indicating whether there are differences''' |
| d = difflib.unified_diff(fomeLines, toLines, fromName, toName, | | d = difflib.unified_diff(fomeLines, toLines, fromName, toName, |
| fromDate, toDate, n) | | fromDate, toDate, n) |
| title = 'Udiffs of %s and %s' % (fromName, toName) | | title = 'Udiffs of %s and %s' % (fromName, toName) |
| html = udiffToHtml(d, title) | | html = udiffToHtml(d, title) |
| | | |
| try: | | try: |
| fp = open(outFile, 'w') | | fp = open(outFile, 'w') |
| fp.write(html) | | fp.write(html) |
| fp.close() | | fp.close() |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| | | |
| | | |
| # This is only called when diff two files specified from command line | | # This is only called when diff two files specified from command line |
| def diffFile(file1, file2, outFile, context=False, wrapnum=None, lines=3): | | def diffFile(file1, file2, outFile, context=False, wrapnum=None, lines=3): |
| '''diff two files and return html page, write to outFile. | | '''diff two files and return html page, write to outFile. |
| Return code indicating whether there are differences''' | | Return code indicating whether there are differences''' |
| #print 'call diffFile(%s, %s, %s, ...)' % (file1, file2, outFile) | | #print 'call diffFile(%s, %s, %s, ...)' % (file1, file2, outFile) |
| #print '-' * 32 | | #print '-' * 32 |
| | | |
| fomeLines = getLines(file1) | | fomeLines = getLines(file1) |
| toLines = getLines(file2) | | toLines = getLines(file2) |
| fromTitle = makeTitle(file1, wrapnum) | | fromTitle = makeTitle(file1, wrapnum) |
| toTitle = makeTitle(file2, wrapnum) | | toTitle = makeTitle(file2, wrapnum) |
| sdiffLines(fomeLines, toLines, outFile, fromTitle, toTitle, context, | | sdiffLines(fomeLines, toLines, outFile, fromTitle, toTitle, context, |
| wrapnum, lines) | | wrapnum, lines) |
| | | |
| | | |
| def inIgnoreList(name, ignorelist): | | def inIgnoreList(name, ignorelist): |
| for pat in ignorelist: | | for pat in ignorelist: |
| if re.match(pat, name): | | if re.match(pat, name): |
| return True | | return True |
| return False | | return False |
| | | |
| | | |
| def grabDir(dir): | | def grabDir(dir): |
| 'Get file list of dir, and remove unwanted file from the list' | | 'Get file list of dir, and remove unwanted file from the list' |
| flist = [] | | flist = [] |
| while dir[-1] == '/': # remove unwanted trailling slash | | while dir[-1] == '/': # remove unwanted trailling slash |
| dir = dir[:-1] | | dir = dir[:-1] |
| prefix = dir + '/' # os.path.sep | | prefix = dir + '/' # os.path.sep |
| plen = len(prefix) | | plen = len(prefix) |
| | | |
| for root, dirs, files in os.walk(dir): | | for root, dirs, files in os.walk(dir): |
t | for d in dirs: | t | for d in [k for k in dirs]: |
| if inIgnoreList(d, _global_dir_ignore_list): | | if inIgnoreList(d, _global_dir_ignore_list): |
| dirs.remove(d) | | dirs.remove(d) |
| for f in files: | | for f in files: |
| if not inIgnoreList(f, _global_file_ignore_list): | | if not inIgnoreList(f, _global_file_ignore_list): |
| name = os.path.join(root, f) | | name = os.path.join(root, f) |
| flist.append(name[plen:]) | | flist.append(name[plen:]) |
| return flist | | return flist |
| | | |
| | | |
| def mergeList(list1, list2): | | def mergeList(list1, list2): |
| # important: should make a new list! don't refer to list1 | | # important: should make a new list! don't refer to list1 |
| list = [ i for i in list1 ] # XXX: list = list1 | | list = [ i for i in list1 ] # XXX: list = list1 |
| for i in list2: | | for i in list2: |
| if i not in list1: list.append(i) | | if i not in list1: list.append(i) |
| return list | | return list |
| | | |
| | | |
| def sourceToHtml(src, outfile): | | def sourceToHtml(src, outfile): |
| """Read file `src' and convert to html, write to file `outfile'""" | | """Read file `src' and convert to html, write to file `outfile'""" |
| #print 'call sourceToHtml(src=%s, outfile=%s)' % (src, outfile) | | #print 'call sourceToHtml(src=%s, outfile=%s)' % (src, outfile) |
| #print '-' * 32 | | #print '-' * 32 |
| try: | | try: |
| infp = open(src, 'r') | | infp = open(src, 'r') |
| body = infp.read() | | body = infp.read() |
| infp.close() | | infp.close() |
| body = body.replace("&","&").replace(">",">").replace("<","<") | | body = body.replace("&","&").replace(">",">").replace("<","<") |
| | | |
| outfp = open(outfile, 'w') | | outfp = open(outfile, 'w') |
| # TODO: convert to syntax highlighted html | | # TODO: convert to syntax highlighted html |
| outfp.write('''<html><head><title>%s</title></head><body> | | outfp.write('''<html><head><title>%s</title></head><body> |
| <pre style="font-family:monospace; font-size:9pt;">%s</pre> | | <pre style="font-family:monospace; font-size:9pt;">%s</pre> |
| </body></html>''' % (src, body)) | | </body></html>''' % (src, body)) |
| outfp.close() | | outfp.close() |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| | | |
| | | |
| def diffDir(dir1, dir2, outdir, wrapnum=None, lines=3): | | def diffDir(dir1, dir2, outdir, wrapnum=None, lines=3): |
| '''diff two directories and generate an index page. Return code | | '''diff two directories and generate an index page. Return code |
| indicating whether there are differences and the summary info''' | | indicating whether there are differences and the summary info''' |
| | | |
| #print 'call diffDir(%s, %s, %s, ...)' % (dir1, dir2, outdir) | | #print 'call diffDir(%s, %s, %s, ...)' % (dir1, dir2, outdir) |
| #print '_global_dirseq:', _global_dirseq | | #print '_global_dirseq:', _global_dirseq |
| #print '=' * 72 | | #print '=' * 72 |
| | | |
| flist1 = grabDir(dir1) # already filtered | | flist1 = grabDir(dir1) # already filtered |
| flist2 = grabDir(dir2) | | flist2 = grabDir(dir2) |
| flist = mergeList(flist1, flist2) | | flist = mergeList(flist1, flist2) |
| return diffDirByList(dir1, dir2, outdir, flist, wrapnum, lines) | | return diffDirByList(dir1, dir2, outdir, flist, wrapnum, lines) |
| | | |
| | | |
| def lstatFile(obj): | | def lstatFile(obj): |
| 'return None in case ENOENT, else a lstat info' | | 'return None in case ENOENT, else a lstat info' |
| try: | | try: |
| statinfo = os.lstat(obj) | | statinfo = os.lstat(obj) |
| except OSError, dig: | | except OSError, dig: |
| if dig.errno == errno.ENOENT: | | if dig.errno == errno.ENOENT: |
| statinfo = None | | statinfo = None |
| else: | | else: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| return statinfo | | return statinfo |
| | | |
| | | |
| def diffDirByList(dir1, dir2, outdir, flist, wrapnum=None, lines=3): | | def diffDirByList(dir1, dir2, outdir, flist, wrapnum=None, lines=3): |
| '''diff two directories and generate an index page. Return code | | '''diff two directories and generate an index page. Return code |
| indicating whether there are differences and the summary info''' | | indicating whether there are differences and the summary info''' |
| | | |
| data_rows = '' | | data_rows = '' |
| data_row = '' | | data_row = '' |
| summary = { 'changed': 0, 'added': 0, 'deleted': 0 } | | summary = { 'changed': 0, 'added': 0, 'deleted': 0 } |
| file_summary = { 'changed': 0, 'added': 0, 'deleted': 0 } | | file_summary = { 'changed': 0, 'added': 0, 'deleted': 0 } |
| has_diff = False | | has_diff = False |
| | | |
| flist.sort() | | flist.sort() |
| | | |
| for f in flist: | | for f in flist: |
| # set default values | | # set default values |
| fromLines = '' | | fromLines = '' |
| toLines = '' | | toLines = '' |
| fromDate = '' | | fromDate = '' |
| toDate = '' | | toDate = '' |
| | | |
| target = os.path.join(outdir, f) | | target = os.path.join(outdir, f) |
| obj1 = os.path.join(dir1, f) | | obj1 = os.path.join(dir1, f) |
| obj2 = os.path.join(dir2, f) | | obj2 = os.path.join(dir2, f) |
| | | |
| # make output dir and sub dir | | # make output dir and sub dir |
| try: | | try: |
| os.makedirs(os.path.join(outdir, os.path.dirname(f))) | | os.makedirs(os.path.join(outdir, os.path.dirname(f))) |
| except OSError, dig: | | except OSError, dig: |
| if dig.errno != errno.EEXIST: | | if dig.errno != errno.EEXIST: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| | | |
| stat1 = lstatFile(obj1) | | stat1 = lstatFile(obj1) |
| stat2 = lstatFile(obj2) | | stat2 = lstatFile(obj2) |
| | | |
| if stat1 and not stat2: # deleted | | if stat1 and not stat2: # deleted |
| print '%-40s |' % f, | | print '%-40s |' % f, |
| print 'File removed', | | print 'File removed', |
| #st_mtime = time.localtime(stat1[8]) | | #st_mtime = time.localtime(stat1[8]) |
| if not stat.S_ISREG(stat1[0]) or isBinaryFile(obj1): | | if not stat.S_ISREG(stat1[0]) or isBinaryFile(obj1): |
| print '(skipped dir/special/binary)' | | print '(skipped dir/special/binary)' |
| continue | | continue |
| print | | print |
| old = sourceToHtml(obj1, target + '-.html') | | old = sourceToHtml(obj1, target + '-.html') |
| data_row = _deleted_data_row_template % {'pathname': f} | | data_row = _deleted_data_row_template % {'pathname': f} |
| summary['deleted'] += 1 | | summary['deleted'] += 1 |
| has_diff = True | | has_diff = True |
| | | |
| elif not stat1 and stat2: # added | | elif not stat1 and stat2: # added |
| print '%-40s |' % f, | | print '%-40s |' % f, |
| print 'New file', | | print 'New file', |
| if not stat.S_ISREG(stat2[0]) or isBinaryFile(obj2): | | if not stat.S_ISREG(stat2[0]) or isBinaryFile(obj2): |
| print '(skipped special/binary)' | | print '(skipped special/binary)' |
| continue | | continue |
| print | | print |
| new = sourceToHtml(obj2, target + '.html') | | new = sourceToHtml(obj2, target + '.html') |
| data_row = _added_data_row_template % {'pathname': f} | | data_row = _added_data_row_template % {'pathname': f} |
| summary['added'] += 1 | | summary['added'] += 1 |
| has_diff = True | | has_diff = True |
| | | |
| elif stat1 and stat2: # same or diff | | elif stat1 and stat2: # same or diff |
| # do not compare special or binary file | | # do not compare special or binary file |
| if not stat.S_ISREG(stat1[0]) or isBinaryFile(obj1): | | if not stat.S_ISREG(stat1[0]) or isBinaryFile(obj1): |
| print '%-40s |' % f, | | print '%-40s |' % f, |
| print '(skipped, former file is special)' | | print '(skipped, former file is special)' |
| continue | | continue |
| if not stat.S_ISREG(stat2[0]) or isBinaryFile(obj2): | | if not stat.S_ISREG(stat2[0]) or isBinaryFile(obj2): |
| print '%-40s |' % f, | | print '%-40s |' % f, |
| print '(skipped, latter file is binary)' | | print '(skipped, latter file is binary)' |
| continue | | continue |
| if filecmp.cmp(obj1, obj2): | | if filecmp.cmp(obj1, obj2): |
| continue | | continue |
| | | |
| has_diff = True | | has_diff = True |
| fromDate = time.ctime(stat1[8]) | | fromDate = time.ctime(stat1[8]) |
| toDate = time.ctime(stat2[8]) | | toDate = time.ctime(stat2[8]) |
| fromLines = getLines(obj1) | | fromLines = getLines(obj1) |
| toLines = getLines(obj2) | | toLines = getLines(obj2) |
| | | |
| # Cdiffs | | # Cdiffs |
| file_summary = cdiffLines(fromLines, toLines, | | file_summary = cdiffLines(fromLines, toLines, |
| target+'.cdiff.html', obj1, obj2, fromDate, toDate, lines) | | target+'.cdiff.html', obj1, obj2, fromDate, toDate, lines) |
| | | |
| # Udiffs | | # Udiffs |
| udiffLines(fromLines, toLines, target+'.udiff.html', obj1, obj2, | | udiffLines(fromLines, toLines, target+'.udiff.html', obj1, obj2, |
| fromDate, toDate, lines) | | fromDate, toDate, lines) |
| | | |
| # Sdiffs | | # Sdiffs |
| sdiffLines(fromLines, toLines, target+'.sdiff.html', obj1, obj2, | | sdiffLines(fromLines, toLines, target+'.sdiff.html', obj1, obj2, |
| True, wrapnum, lines) | | True, wrapnum, lines) |
| | | |
| # Fdiffs | | # Fdiffs |
| sdiffLines(fromLines, toLines, target+'.fdiff.html', obj1, obj2, | | sdiffLines(fromLines, toLines, target+'.fdiff.html', obj1, obj2, |
| False, wrapnum, lines) | | False, wrapnum, lines) |
| | | |
| print '%-40s |' % f, | | print '%-40s |' % f, |
| print 'Changed/Deleted/Added: %d/%d/%d' % (\ | | print 'Changed/Deleted/Added: %d/%d/%d' % (\ |
| file_summary['changed'], | | file_summary['changed'], |
| file_summary['deleted'], | | file_summary['deleted'], |
| file_summary['added']) | | file_summary['added']) |
| | | |
| old = sourceToHtml(obj1, target + '-.html') | | old = sourceToHtml(obj1, target + '-.html') |
| new = sourceToHtml(obj2, target + '.html') | | new = sourceToHtml(obj2, target + '.html') |
| data_row = _diff_data_row_template % dict( | | data_row = _diff_data_row_template % dict( |
| pathname = f, | | pathname = f, |
| changed = file_summary['changed'], | | changed = file_summary['changed'], |
| deleted = file_summary['deleted'], | | deleted = file_summary['deleted'], |
| added = file_summary['added'], | | added = file_summary['added'], |
| ) | | ) |
| summary['changed'] += 1 | | summary['changed'] += 1 |
| else: # this case occured when controlled by master file list | | else: # this case occured when controlled by master file list |
| print '%-40s |' % f, | | print '%-40s |' % f, |
| print 'Not found' | | print 'Not found' |
| data_row = '' | | data_row = '' |
| | | |
| data_rows += data_row | | data_rows += data_row |
| | | |
| if not has_diff: | | if not has_diff: |
| return False | | return False |
| | | |
| # Generate footer info | | # Generate footer info |
| footer_info = _footer_info_template % dict( | | footer_info = _footer_info_template % dict( |
| time = time.strftime('%a %b %d %X %Z %Y', time.localtime()), | | time = time.strftime('%a %b %d %X %Z %Y', time.localtime()), |
| myname = _myname, | | myname = _myname, |
| revision = _revision | | revision = _revision |
| ) | | ) |
| | | |
| # now wirte index page | | # now wirte index page |
| try: | | try: |
| index = open(os.path.join(outdir, 'index.html'), 'w') | | index = open(os.path.join(outdir, 'index.html'), 'w') |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| index.write(_file_template % dict( | | index.write(_file_template % dict( |
| title = '%s vs %s' % (dir1, dir2), | | title = '%s vs %s' % (dir1, dir2), |
| styles = _styles, | | styles = _styles, |
| header_info = _header_info_template % dict(dir1=dir1, dir2=dir2), | | header_info = _header_info_template % dict(dir1=dir1, dir2=dir2), |
| summary_info = _summary_info_template % summary, | | summary_info = _summary_info_template % summary, |
| data_rows = _data_rows_template % {'data_rows': data_rows}, | | data_rows = _data_rows_template % {'data_rows': data_rows}, |
| legend = _legend, | | legend = _legend, |
| footer_info = footer_info, | | footer_info = footer_info, |
| )) | | )) |
| index.close() | | index.close() |
| return True | | return True |
| | | |
| | | |
| def warnOverwrite(pathname): | | def warnOverwrite(pathname): |
| 'Warnning for overwriting, return True if answered yes, False if no' | | 'Warnning for overwriting, return True if answered yes, False if no' |
| msg = "`%s' exists, are you sure you want to overwrite it (yes/no)? " | | msg = "`%s' exists, are you sure you want to overwrite it (yes/no)? " |
| while True: | | while True: |
| sys.stderr.write(msg % pathname) | | sys.stderr.write(msg % pathname) |
| answer = raw_input('') | | answer = raw_input('') |
| if answer == 'yes': | | if answer == 'yes': |
| return True | | return True |
| elif answer == 'no': | | elif answer == 'no': |
| return False | | return False |
| # else: prompt again | | # else: prompt again |
| | | |
| | | |
| def isBinaryFile(file): | | def isBinaryFile(file): |
| '''I determine a binary file by reading the first 1024 bytes of the file | | '''I determine a binary file by reading the first 1024 bytes of the file |
| and counting the non-text characters, if the number is great than 8, then | | and counting the non-text characters, if the number is great than 8, then |
| the file is considered as binary file. This is not very reliable but is | | the file is considered as binary file. This is not very reliable but is |
| effective''' | | effective''' |
| if not file: | | if not file: |
| return False | | return False |
| | | |
| non_text = 0 | | non_text = 0 |
| target_count = 8 | | target_count = 8 |
| try: | | try: |
| fp = open(file, 'rb') | | fp = open(file, 'rb') |
| data = fp.read(1024) | | data = fp.read(1024) |
| for c in data: | | for c in data: |
| a = ord(c) | | a = ord(c) |
| if a < 8 or (a > 13 and a < 32): # not printable | | if a < 8 or (a > 13 and a < 32): # not printable |
| non_text += 1 | | non_text += 1 |
| if non_text >= target_count: break | | if non_text >= target_count: break |
| fp.close() | | fp.close() |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| return non_text >= target_count | | return non_text >= target_count |
| | | |
| | | |
| def cdiffToHtml(cdiff, title): | | def cdiffToHtml(cdiff, title): |
| '''cdiff is context diff (a list) that generated by difflib.context_diff, | | '''cdiff is context diff (a list) that generated by difflib.context_diff, |
| return summary and html page''' | | return summary and html page''' |
| summary = { 'changed': 0, 'added': 0, 'deleted': 0 } | | summary = { 'changed': 0, 'added': 0, 'deleted': 0 } |
| line_pattern = '<span class="%s">%s</span>' | | line_pattern = '<span class="%s">%s</span>' |
| | | |
| body = '' | | body = '' |
| old_group = False | | old_group = False |
| for line in cdiff: | | for line in cdiff: |
| n = len(line) | | n = len(line) |
| line = line.replace("&","&").replace(">",">").replace("<","<") | | line = line.replace("&","&").replace(">",">").replace("<","<") |
| if n >= 4 and line[0:4] == '*** ': | | if n >= 4 and line[0:4] == '*** ': |
| old_group = True | | old_group = True |
| body += line_pattern % ('fromtitle', line) | | body += line_pattern % ('fromtitle', line) |
| elif n >= 4 and line[0:4] == '--- ': | | elif n >= 4 and line[0:4] == '--- ': |
| old_group = False | | old_group = False |
| body += line_pattern % ('totitle', line) | | body += line_pattern % ('totitle', line) |
| elif n >= 2 and line[0:2] == ' ': | | elif n >= 2 and line[0:2] == ' ': |
| body += line_pattern % ('same', line) | | body += line_pattern % ('same', line) |
| elif n >= 2 and line[0:2] == '! ': | | elif n >= 2 and line[0:2] == '! ': |
| body += line_pattern % ('change', line) | | body += line_pattern % ('change', line) |
| if old_group: | | if old_group: |
| summary['changed'] += 1 | | summary['changed'] += 1 |
| elif n >= 2 and line[0:2] == '- ': | | elif n >= 2 and line[0:2] == '- ': |
| body += line_pattern % ('delete', line) | | body += line_pattern % ('delete', line) |
| summary['deleted'] += 1 | | summary['deleted'] += 1 |
| elif n >= 2 and line[0:2] == '+ ': | | elif n >= 2 and line[0:2] == '+ ': |
| body += line_pattern % ('insert', line) | | body += line_pattern % ('insert', line) |
| summary['added'] += 1 | | summary['added'] += 1 |
| elif n >= 15 and line[0:15] == '*' * 15: | | elif n >= 15 and line[0:15] == '*' * 15: |
| body += '<hr>' | | body += '<hr>' |
| else: # shouldn't happen | | else: # shouldn't happen |
| body += line | | body += line |
| | | |
| html = '''<html><head> | | html = '''<html><head> |
| <title>%s</title> | | <title>%s</title> |
| <style type="text/css"> | | <style type="text/css"> |
| .fromtitle {color:brown; font:bold 11pt;} | | .fromtitle {color:brown; font:bold 11pt;} |
| .totitle {color:green; font:bold 11pt;} | | .totitle {color:green; font:bold 11pt;} |
| .same {color:black; font:9pt;} | | .same {color:black; font:9pt;} |
| .change {color:blue; font:9pt;} | | .change {color:blue; font:9pt;} |
| .delete {color:brown; font:9pt;} | | .delete {color:brown; font:9pt;} |
| .insert {color:green; font:9pt;} | | .insert {color:green; font:9pt;} |
| </style> | | </style> |
| <body> | | <body> |
| <pre>%s</pre> | | <pre>%s</pre> |
| </body> | | </body> |
| </head></html>''' % (title, body) | | </head></html>''' % (title, body) |
| return summary, html | | return summary, html |
| | | |
| | | |
| def udiffToHtml(udiff, title): | | def udiffToHtml(udiff, title): |
| '''udiff is uniform diff (a list) that generated by difflib.uniform_diff, | | '''udiff is uniform diff (a list) that generated by difflib.uniform_diff, |
| return html page''' | | return html page''' |
| | | |
| line_pattern = '<span class="%s">%s</span>' | | line_pattern = '<span class="%s">%s</span>' |
| body = '' | | body = '' |
| for line in udiff: | | for line in udiff: |
| n = len(line) | | n = len(line) |
| line = line.replace("&","&").replace(">",">").replace("<","<") | | line = line.replace("&","&").replace(">",">").replace("<","<") |
| if n >= 4 and line[0:4] == '--- ': | | if n >= 4 and line[0:4] == '--- ': |
| body += line_pattern % ('fromtitle', line) | | body += line_pattern % ('fromtitle', line) |
| elif n >= 4 and line[0:4] == '+++ ': | | elif n >= 4 and line[0:4] == '+++ ': |
| body += line_pattern % ('totitle', line) | | body += line_pattern % ('totitle', line) |
| elif n >= 1 and line[0] == ' ': | | elif n >= 1 and line[0] == ' ': |
| body += line_pattern % ('same', line) | | body += line_pattern % ('same', line) |
| elif n >= 1 and line[0] == '-': | | elif n >= 1 and line[0] == '-': |
| body += line_pattern % ('old', line) | | body += line_pattern % ('old', line) |
| elif n >= 1 and line[0] == '+': | | elif n >= 1 and line[0] == '+': |
| body += line_pattern % ('new', line) | | body += line_pattern % ('new', line) |
| elif n >= 4 and line[0:4] == '@@ -': | | elif n >= 4 and line[0:4] == '@@ -': |
| body += '<hr>' | | body += '<hr>' |
| body += line_pattern % ('head', line) | | body += line_pattern % ('head', line) |
| else: # shouldn't happen | | else: # shouldn't happen |
| body += line | | body += line |
| | | |
| html = '''<html><head> | | html = '''<html><head> |
| <title>%s</title> | | <title>%s</title> |
| <style type="text/css"> | | <style type="text/css"> |
| .fromtitle {color:brown; font:bold 11pt;} | | .fromtitle {color:brown; font:bold 11pt;} |
| .totitle {color:green; font:bold 11pt;} | | .totitle {color:green; font:bold 11pt;} |
| .head {color:blue; font:bold 9pt;} | | .head {color:blue; font:bold 9pt;} |
| .same {color:black; font:9pt;} | | .same {color:black; font:9pt;} |
| .old {color:brown; font:9pt;} | | .old {color:brown; font:9pt;} |
| .new {color:green; font:9pt;} | | .new {color:green; font:9pt;} |
| </style> | | </style> |
| <body> | | <body> |
| <pre>%s</pre> | | <pre>%s</pre> |
| </body> | | </body> |
| </head></html>''' % (title, body) | | </head></html>''' % (title, body) |
| return html | | return html |
| | | |
| | | |
| def stripPrefix(name, p=0): | | def stripPrefix(name, p=0): |
| '''strip NUM slashes, like patch(1) -pNUM | | '''strip NUM slashes, like patch(1) -pNUM |
| eg1: /foo/bar/a/b/x.c | | eg1: /foo/bar/a/b/x.c |
| -p0 gives orignal name (no change) | | -p0 gives orignal name (no change) |
| -p1 gives foo/bar/a/b/x.c | | -p1 gives foo/bar/a/b/x.c |
| -p2 gives bar/a/b/x.c | | -p2 gives bar/a/b/x.c |
| -p9 gives x.c | | -p9 gives x.c |
| | | |
| eg2: foo/bar/a/b/x.c | | eg2: foo/bar/a/b/x.c |
| -p0 gives orignal name (no change) | | -p0 gives orignal name (no change) |
| -p1 gives bar/a/b/x.c | | -p1 gives bar/a/b/x.c |
| -p2 gives a/b/x.c | | -p2 gives a/b/x.c |
| -p9 gives x.c | | -p9 gives x.c |
| | | |
| eg3: ./foo/bar/a/b/x.c | | eg3: ./foo/bar/a/b/x.c |
| -p0 gives orignal name (no change) | | -p0 gives orignal name (no change) |
| -p1 gives foo/bar/a/b/x.c | | -p1 gives foo/bar/a/b/x.c |
| -p2 gives bar/a/b/x.c | | -p2 gives bar/a/b/x.c |
| -p9 gives x.c | | -p9 gives x.c |
| ''' | | ''' |
| cur = 0 | | cur = 0 |
| tail = len(name) - 1 | | tail = len(name) - 1 |
| while p > 0: | | while p > 0: |
| index = name.find('/', cur) | | index = name.find('/', cur) |
| #print 'p:', p, 'cur:', cur, 'index:', index | | #print 'p:', p, 'cur:', cur, 'index:', index |
| if index == -1: break | | if index == -1: break |
| while index <= tail and name[index] == '/': | | while index <= tail and name[index] == '/': |
| index += 1 | | index += 1 |
| cur = index | | cur = index |
| p -= 1 | | p -= 1 |
| return name[cur:] | | return name[cur:] |
| | | |
| | | |
| def readFileList(file, p=0): | | def readFileList(file, p=0): |
| '''Return content of filelist (a file, each line is a filename)''' | | '''Return content of filelist (a file, each line is a filename)''' |
| flist = [] | | flist = [] |
| if not file: | | if not file: |
| return [] | | return [] |
| if file == '-': # read from stdin | | if file == '-': # read from stdin |
| flist = sys.stdin.readlines() | | flist = sys.stdin.readlines() |
| else: | | else: |
| try: | | try: |
| fp = open(file, 'r') | | fp = open(file, 'r') |
| flist = fp.readlines() | | flist = fp.readlines() |
| fp.close() | | fp.close() |
| except IOError, dig: | | except IOError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| | | |
| outlist = [] | | outlist = [] |
| for i in flist: | | for i in flist: |
| outlist.append(stripPrefix(i, p).rstrip()) | | outlist.append(stripPrefix(i, p).rstrip()) |
| #print outlist | | #print outlist |
| return outlist | | return outlist |
| | | |
| | | |
| if __name__ == '__main__': | | if __name__ == '__main__': |
| import optparse | | import optparse |
| | | |
| usage = ''' | | usage = ''' |
| %(name)s [options] OLD NEW | | %(name)s [options] OLD NEW |
| %(name)s OLD NEW [options] | | %(name)s OLD NEW [options] |
| | | |
| Diff two files/directories and produce HTML pages.''' % \ | | Diff two files/directories and produce HTML pages.''' % \ |
| {'name': os.path.basename(sys.argv[0])} | | {'name': os.path.basename(sys.argv[0])} |
| | | |
| parser = optparse.OptionParser(usage) | | parser = optparse.OptionParser(usage) |
| parser.add_option('-o', '--outupt', dest='output', | | parser.add_option('-o', '--outupt', dest='output', |
| help='specify output file or directory name') | | help='specify output file or directory name') |
| parser.add_option('-c', '--context', action='store_true', | | parser.add_option('-c', '--context', action='store_true', |
| dest='context', default=False, | | dest='context', default=False, |
| help='generate context diff (default is full diff),' + \ | | help='generate context diff (default is full diff),' + \ |
| ' only take effect when diffing two files') | | ' only take effect when diffing two files') |
| parser.add_option('-f', '--filelist', dest='filelist', metavar='FILE', | | parser.add_option('-f', '--filelist', dest='filelist', metavar='FILE', |
| help='specify a file list to read from, filelist can ' + \ | | help='specify a file list to read from, filelist can ' + \ |
| 'be generated by find -type f, specify - to read' + \ | | 'be generated by find -type f, specify - to read' + \ |
| ' from stdin') | | ' from stdin') |
| parser.add_option('-p', '--striplevel', dest='striplevel', | | parser.add_option('-p', '--striplevel', dest='striplevel', |
| type='int', metavar='NUM', | | type='int', metavar='NUM', |
| help='for all pathnames in the filelist, delete NUM ' + \ | | help='for all pathnames in the filelist, delete NUM ' + \ |
| 'path name components from the beginning of each' + \ | | 'path name components from the beginning of each' + \ |
| ' path name, it is similar to patch(1) -p') | | ' path name, it is similar to patch(1) -p') |
| parser.add_option('-n', '--lines', dest='lines', | | parser.add_option('-n', '--lines', dest='lines', |
| type='int', metavar='NUM', default=3, | | type='int', metavar='NUM', default=3, |
| help='specify context line count when generating ' + \ | | help='specify context line count when generating ' + \ |
| 'context diffs or unified diffs, default is 3') | | 'context diffs or unified diffs, default is 3') |
| parser.add_option('-w', '--wrap', dest='wrapnum', | | parser.add_option('-w', '--wrap', dest='wrapnum', |
| type='int', metavar='WIDTH', | | type='int', metavar='WIDTH', |
| help='specify column number where lines are broken ' + \ | | help='specify column number where lines are broken ' + \ |
| 'and wrapped for sdiff, default is no line wrapping') | | 'and wrapped for sdiff, default is no line wrapping') |
| parser.add_option('-y', '--yes', action='store_true', | | parser.add_option('-y', '--yes', action='store_true', |
| dest='overwrite', default=False, | | dest='overwrite', default=False, |
| help='do not prompt for overwriting') | | help='do not prompt for overwriting') |
| | | |
| opts, args = parser.parse_args() | | opts, args = parser.parse_args() |
| | | |
| if len(args) != 2: | | if len(args) != 2: |
| sys.stderr.write("Sorry, you must specify two file/directory names\n" \ | | sys.stderr.write("Sorry, you must specify two file/directory names\n" \ |
| + "type `%s -h' for help\n" % _myname) | | + "type `%s -h' for help\n" % _myname) |
| sys.exit(1) | | sys.exit(1) |
| | | |
| if not opts.output: | | if not opts.output: |
| sys.stderr.write("Sorry, you must specify output name (use `-o')\n") | | sys.stderr.write("Sorry, you must specify output name (use `-o')\n") |
| sys.exit(2) | | sys.exit(2) |
| | | |
| try: | | try: |
| # Note: use stat instead lstat to permit symbolic links | | # Note: use stat instead lstat to permit symbolic links |
| stat1 = os.stat(args[0])[0] | | stat1 = os.stat(args[0])[0] |
| stat2 = os.stat(args[1])[0] | | stat2 = os.stat(args[1])[0] |
| except OSError, dig: | | except OSError, dig: |
| sys.stderr.write(str(dig) + '\n') | | sys.stderr.write(str(dig) + '\n') |
| sys.exit(2) | | sys.exit(2) |
| | | |
| # Compare two files | | # Compare two files |
| # | | # |
| if stat.S_ISREG(stat1) and stat.S_ISREG(stat2): | | if stat.S_ISREG(stat1) and stat.S_ISREG(stat2): |
| if not opts.overwrite and os.path.exists(opts.output): | | if not opts.overwrite and os.path.exists(opts.output): |
| if not warnOverwrite(opts.output): sys.exit(1) | | if not warnOverwrite(opts.output): sys.exit(1) |
| url = 'file://%s\n' % os.path.realpath(opts.output) | | url = 'file://%s\n' % os.path.realpath(opts.output) |
| | | |
| if filecmp.cmp(args[0], arg2[1]): | | if filecmp.cmp(args[0], arg2[1]): |
| print 'No difference found.' | | print 'No difference found.' |
| else: | | else: |
| diffFile(args[0], args[1], opts.output, opts.context, | | diffFile(args[0], args[1], opts.output, opts.context, |
| opts.wrapnum, opts.lines) | | opts.wrapnum, opts.lines) |
| print '\nURL:\n%s' % url | | print '\nURL:\n%s' % url |
| | | |
| # Compare two dirs | | # Compare two dirs |
| # | | # |
| elif stat.S_ISDIR(stat1) and stat.S_ISDIR(stat2): | | elif stat.S_ISDIR(stat1) and stat.S_ISDIR(stat2): |
| if not opts.overwrite and os.path.exists(opts.output): | | if not opts.overwrite and os.path.exists(opts.output): |
| if opts.filelist == '-': | | if opts.filelist == '-': |
| # stdin redirected, so we cannot read answer from stdin | | # stdin redirected, so we cannot read answer from stdin |
| print "`%s' exists, please select another output directory, " \ | | print "`%s' exists, please select another output directory, " \ |
| "or specify '-y' to force overwriting." % opts.output | | "or specify '-y' to force overwriting." % opts.output |
| sys.exit(1) | | sys.exit(1) |
| else: | | else: |
| if not warnOverwrite(opts.output): | | if not warnOverwrite(opts.output): |
| sys.exit(1) | | sys.exit(1) |
| url = 'file://%s/index.html\n' % os.path.realpath(opts.output) | | url = 'file://%s/index.html\n' % os.path.realpath(opts.output) |
| | | |
| if opts.filelist: | | if opts.filelist: |
| # filelist mode, contolled by master file list | | # filelist mode, contolled by master file list |
| # read file list, ignore lines with first char is '/' | | # read file list, ignore lines with first char is '/' |
| # if see 'foo/bar/abc', makedirs foo/bar/, then put abc.diffs to it | | # if see 'foo/bar/abc', makedirs foo/bar/, then put abc.diffs to it |
| flist = readFileList(opts.filelist, opts.striplevel) | | flist = readFileList(opts.filelist, opts.striplevel) |
| if diffDirByList(args[0], args[1], opts.output, | | if diffDirByList(args[0], args[1], opts.output, |
| flist, opts.wrapnum, opts.lines): | | flist, opts.wrapnum, opts.lines): |
| print '\nURL:\n%s' % url | | print '\nURL:\n%s' % url |
| else: | | else: |
| print 'No difference found.' | | print 'No difference found.' |
| else: | | else: |
| if diffDir(args[0], args[1], opts.output, opts.wrapnum, | | if diffDir(args[0], args[1], opts.output, opts.wrapnum, |
| opts.lines): | | opts.lines): |
| print '\nURL:\n%s' % url | | print '\nURL:\n%s' % url |
| else: | | else: |
| print 'No difference found.' | | print 'No difference found.' |
| | | |
| else: | | else: |
| sys.stderr.write("Sorry, I don't know how to compare `%s' and `%s'\n" \ | | sys.stderr.write("Sorry, I don't know how to compare `%s' and `%s'\n" \ |
| % (args[0], args[1])) | | % (args[0], args[1])) |
| sys.exit(2) | | sys.exit(2) |
| | | |
| # vim:set et sts=4 sw=4: | | # vim:set et sts=4 sw=4: |