wdiff.py :  » Mobile » Python-for-PalmOS » Python-1.5.2+reduced-1.0 » Demo » stdwin » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Mobile » Python for PalmOS 
Python for PalmOS » Python 1.5.2 reduced 1.0 » Demo » stdwin » wdiff.py
#! /usr/bin/env python

# A window-oriented recursive diff utility.
# NB: This uses undocumented window classing modules.

# TO DO:
#  - faster update after moving/copying one file
#  - diff flags (-b, etc.) should be global or maintained per window
#  - use a few fixed windows instead of creating new ones all the time
#  - ways to specify patterns to skip
#    (best by pointing at a file and clicking a special menu entry!)
#  - add rcsdiff menu commands
#  - add a way to view status of selected files without opening them
#  - add a way to diff two files with different names
#  - add a way to rename files
#  - keep backups of overwritten/deleted files
#  - a way to mark specified files as uninteresting for dircmp

import sys
import os
import rand
import commands
import dircache
import statcache
import cmp
import cmpcache
import stdwin
import gwin
import textwin
import filewin
import tablewin
import anywin

mkarg = commands.mkarg
mk2arg = commands.mk2arg

# List of names to ignore in dircmp()
#
skiplist = ['RCS', 'CVS', '.Amake', 'tags', 'TAGS', '.', '..']

# Function to determine whether a name should be ignored in dircmp().
#
def skipthis(file):
  return file[-1:] == '~' or file in skiplist


def anydiff(a, b, flags): # Display differences between any two objects
  print 'diff', flags, a, b
  if os.path.isdir(a) and os.path.isdir(b):
    w = dirdiff(a, b, flags)
  else:
    w = filediff(a, b, flags)
  addstatmenu(w, [a, b])
  w.original_close = w.close
  w.close = close_dirwin
  return w

def close_dirwin(w):
  close_subwindows(w, (), 0)
  w.original_close(w)

def filediff(a, b, flags): # Display differences between two text files
  diffcmd = 'diff'
  if flags: diffcmd = diffcmd + mkarg(flags)
  diffcmd = diffcmd + mkarg(a) + mkarg(b)
  difftext = commands.getoutput(diffcmd)
  return textwin.open_readonly(mktitle(a, b), difftext)

def dirdiff(a, b, flags): # Display differences between two directories
  data = diffdata(a, b, flags)
  w = tablewin.open(mktitle(a, b), data)
  w.flags = flags
  w.a = a
  w.b = b
  addviewmenu(w)
  addactionmenu(w)
  return w

def diffdata(a, b, flags): # Compute directory differences.
  #
  a_only = [('A only:', header_action), ('', header_action)]
  b_only = [('B only:', header_action), ('', header_action)]
  ab_diff = [('A <> B:', header_action), ('', header_action)]
  ab_same = [('A == B:', header_action), ('', header_action)]
  data = [a_only, b_only, ab_diff, ab_same]
  #
  a_list = dircache.listdir(a)[:]
  b_list = dircache.listdir(b)[:]
  dircache.annotate(a, a_list)
  dircache.annotate(b, b_list)
  a_list.sort()
  b_list.sort()
  #
  for x in a_list:
    if x in ['./', '../']:
      pass
    elif x not in b_list:
      a_only.append((x, a_only_action))
    else:
      ax = os.path.join(a, x)
      bx = os.path.join(b, x)
      if os.path.isdir(ax) and os.path.isdir(bx):
        if flags == '-r':
          same = dircmp(ax, bx)
        else:
          same = 0
      else:
        try:
          same = cmp.cmp(ax, bx)
        except (RuntimeError, os.error):
          same = 0
      if same:
        ab_same.append((x, ab_same_action))
      else:
        ab_diff.append((x, ab_diff_action))
  #
  for x in b_list:
    if x in ['./', '../']:
      pass
    elif x not in a_list:
      b_only.append((x, b_only_action))
  #
  return data

# Re-read the directory.
# Attempt to find the selected item back.

def update(w):
  setbusy(w)
  icol, irow = w.selection
  if 0 <= icol < len(w.data) and 2 <= irow < len(w.data[icol]):
    selname = w.data[icol][irow][0]
  else:
    selname = ''
  statcache.forget_dir(w.a)
  statcache.forget_dir(w.b)
  tablewin.select(w, (-1, -1))
  tablewin.update(w, diffdata(w.a, w.b, w.flags))
  if selname:
    for icol in range(len(w.data)):
      for irow in range(2, len(w.data[icol])):
        if w.data[icol][irow][0] == selname:
          tablewin.select(w, (icol, irow))
          break

# Action functions for table items in directory diff windows

def header_action(w, string, (icol, irow), (pos, clicks, button, mask)):
  tablewin.select(w, (-1, -1))

def a_only_action(w, string, (icol, irow), (pos, clicks, button, mask)):
  tablewin.select(w, (icol, irow))
  if clicks == 2:
    w2 = anyopen(os.path.join(w.a, string))
    if w2:
      w2.parent = w

def b_only_action(w, string, (icol, irow), (pos, clicks, button, mask)):
  tablewin.select(w, (icol, irow))
  if clicks == 2:
    w2 = anyopen(os.path.join(w.b, string))
    if w2:
      w2.parent = w

def ab_diff_action(w, string, (icol, irow), (pos, clicks, button, mask)):
  tablewin.select(w, (icol, irow))
  if clicks == 2:
    w2 = anydiff(os.path.join(w.a, string), os.path.join(w.b, string),'')
    w2.parent = w

def ab_same_action(w, string, sel, detail):
  ax = os.path.join(w.a, string)
  if os.path.isdir(ax):
    ab_diff_action(w, string, sel, detail)
  else:
    a_only_action(w, string, sel, detail)

def anyopen(name): # Open any kind of document, ignore errors
  try:
    w = anywin.open(name)
  except (RuntimeError, os.error):
    stdwin.message('Can\'t open ' + name)
    return 0
  addstatmenu(w, [name])
  return w

def dircmp(a, b): # Compare whether two directories are the same
  # To make this as fast as possible, it uses the statcache
  print '  dircmp', a, b
  a_list = dircache.listdir(a)
  b_list = dircache.listdir(b)
  for x in a_list:
    if skipthis(x):
      pass
    elif x not in b_list:
      return 0
    else:
      ax = os.path.join(a, x)
      bx = os.path.join(b, x)
      if statcache.isdir(ax) and statcache.isdir(bx):
        if not dircmp(ax, bx): return 0
      else:
        try:
          if not cmpcache.cmp(ax, bx): return 0
        except (RuntimeError, os.error):
          return 0
  for x in b_list:
    if skipthis(x):
      pass
    elif x not in a_list:
      return 0
  return 1


# View menu (for dir diff windows only)

def addviewmenu(w):
  w.viewmenu = m = w.menucreate('View')
  m.action = []
  add(m, 'diff -r A B', diffr_ab)
  add(m, 'diff A B', diff_ab)
  add(m, 'diff -b A B', diffb_ab)
  add(m, 'diff -c A B', diffc_ab)
  add(m, 'gdiff A B', gdiff_ab)
  add(m, ('Open A   ', 'A'), open_a)
  add(m, ('Open B   ', 'B'), open_b)
  add(m, 'Rescan', rescan)
  add(m, 'Rescan -r', rescan_r)

# Action menu (for dir diff windows only)

def addactionmenu(w):
  w.actionmenu = m = w.menucreate('Action')
  m.action = []
  add(m, 'cp A B', cp_ab)
  add(m, 'rm B', rm_b)
  add(m, '', nop)
  add(m, 'cp B A', cp_ba)
  add(m, 'rm A', rm_a)

# Main menu (global):

def mainmenu():
  m = stdwin.menucreate('Wdiff')
  m.action = []
  add(m, ('Quit wdiff', 'Q'), quit_wdiff)
  add(m, 'Close subwindows', close_subwindows)
  return m

def add(m, text, action):
  m.additem(text)
  m.action.append(action)

def quit_wdiff(w, m, item):
  if askyesno('Really quit wdiff altogether?', 1):
    sys.exit(0)

def close_subwindows(w, m, item):
  while 1:
    for w2 in gwin.windows:
      if w2.parent == w:
        close_subwindows(w2, m, item)
        w2.close(w2)
        break # inner loop, continue outer loop
    else:
      break # outer loop

def diffr_ab(w, m, item):
  dodiff(w, '-r')

def diff_ab(w, m, item):
  dodiff(w, '')

def diffb_ab(w, m, item):
  dodiff(w, '-b')

def diffc_ab(w, m, item):
  dodiff(w, '-c')

def gdiff_ab(w, m, item): # Call SGI's gdiff utility
  x = getselection(w)
  if x:
    a, b = os.path.join(w.a, x), os.path.join(w.b, x)
    if os.path.isdir(a) or os.path.isdir(b):
      stdwin.fleep() # This is for files only
    else:
      diffcmd = 'gdiff'
      diffcmd = diffcmd + mkarg(a) + mkarg(b) + ' &'
      print diffcmd
      sts = os.system(diffcmd)
      if sts: print 'Exit status', sts

def dodiff(w, flags):
  x = getselection(w)
  if x:
    w2 = anydiff(os.path.join(w.a, x), os.path.join(w.b, x), flags)
    w2.parent = w

def open_a(w, m, item):
  x = getselection(w)
  if x:
    w2 = anyopen(os.path.join(w.a, x))
    if w2:
      w2.parent = w

def open_b(w, m, item):
  x = getselection(w)
  if x:
    w2 = anyopen(os.path.join(w.b, x))
    if w2:
      w2.parent = w

def rescan(w, m, item):
  w.flags = ''
  update(w)

def rescan_r(w, m, item):
  w.flags = '-r'
  update(w)

def rm_a(w, m, item):
  x = getselection(w)
  if x:
    if x[-1:] == '/': x = x[:-1]
    x = os.path.join(w.a, x)
    if os.path.isdir(x):
      if askyesno('Recursively remove A directory ' + x, 1):
        runcmd('rm -rf' + mkarg(x))
    else:
      runcmd('rm -f' + mkarg(x))
    update(w)

def rm_b(w, m, item):
  x = getselection(w)
  if x:
    if x[-1:] == '/': x = x[:-1]
    x = os.path.join(w.b, x)
    if os.path.isdir(x):
      if askyesno('Recursively remove B directory ' + x, 1):
        runcmd('rm -rf' + mkarg(x))
    else:
      runcmd('rm -f' + mkarg(x))
    update(w)

def cp_ab(w, m, item):
  x = getselection(w)
  if x:
    if x[-1:] == '/': x = x[:-1]
    ax = os.path.join(w.a, x)
    bx = os.path.join(w.b, x)
    if os.path.isdir(ax):
      if os.path.exists(bx):
        m = 'Can\'t copy directory to existing target'
        stdwin.message(m)
        return
      runcmd('cp -r' + mkarg(ax) + mkarg(w.b))
    else:
      runcmd('cp' + mkarg(ax) + mk2arg(w.b, x))
    update(w)

def cp_ba(w, m, item):
  x = getselection(w)
  if x:
    if x[-1:] == '/': x = x[:-1]
    ax = os.path.join(w.a, x)
    bx = os.path.join(w.b, x)
    if os.path.isdir(bx):
      if os.path.exists(ax):
        m = 'Can\'t copy directory to existing target'
        stdwin.message(m)
        return
      runcmd('cp -r' + mkarg(bx) + mkarg(w.a))
    else:
      runcmd('cp' + mk2arg(w.b, x) + mkarg(ax))
    update(w)

def nop(args):
  pass

def getselection(w):
  icol, irow = w.selection
  if 0 <= icol < len(w.data):
    if 0 <= irow < len(w.data[icol]):
      return w.data[icol][irow][0]
  stdwin.message('no selection')
  return ''

def runcmd(cmd):
  print cmd
  sts, output = commands.getstatusoutput(cmd)
  if sts or output:
    if not output:
      output = 'Exit status ' + `sts`
    stdwin.message(output)


# Status menu (for all kinds of windows)

def addstatmenu(w, files):
  w.statmenu = m = w.menucreate('Stat')
  m.files = files
  m.action = []
  for file in files:
    m.additem(commands.getstatus(file))
    m.action.append(stataction)

def stataction(w, m, item): # Menu item action for stat menu
  file = m.files[item]
  try:
    m.setitem(item, commands.getstatus(file))
  except os.error:
    stdwin.message('Can\'t get status for ' + file)


# Compute a suitable window title from two paths

def mktitle(a, b):
  if a == b: return a
  i = 1
  while a[-i:] == b[-i:]: i = i+1
  i = i-1
  if not i:
    return a + '  ' + b
  else:
    return '{' + a[:-i] + ',' + b[:-i] + '}' + a[-i:]


# Ask a confirmation question

def askyesno(prompt, default):
  try:
    return stdwin.askync(prompt, default)
  except KeyboardInterrupt:
    return 0


# Display a message "busy" in a window, and mark it for updating

def setbusy(w):
  left, top = w.getorigin()
  width, height = w.getwinsize()
  right, bottom = left + width, top + height
  d = w.begindrawing()
  d.erase((0, 0), (10000, 10000))
  text = 'Busy...'
  textwidth = d.textwidth(text)
  textheight = d.lineheight()
  h, v = left + (width-textwidth)/2, top + (height-textheight)/2
  d.text((h, v), text)
  del d
  w.change((0, 0), (10000, 10000))


# Main function

def main():
  print 'wdiff: warning: this program does NOT make backups'
  argv = sys.argv
  flags = ''
  if len(argv) >= 2 and argv[1][:1] == '-':
    flags = argv[1]
    del argv[1]
  stdwin.setdefscrollbars(0, 1)
  m = mainmenu() # Create menu earlier than windows
  if len(argv) == 2: # 1 argument
    w = anyopen(argv[1])
    if not w: return
  elif len(argv) == 3: # 2 arguments
    w = anydiff(argv[1], argv[2], flags)
    w.parent = ()
  else:
    sys.stdout = sys.stderr
    print 'usage:', argv[0], '[diff-flags] dir-1 [dir-2]'
    sys.exit(2)
  del w # It's preserved in gwin.windows
  while 1:
    try:
      gwin.mainloop()
      break
    except KeyboardInterrupt:
      pass  # Just continue...

# Start the main function (this is a script)
main()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.