Kiln » TortoiseHg » TortoiseHg
Clone URL:  
Pushed to one repository · View In Graph Contained in 0.8, 0.8.1, and 0.8.2

visdiff: further work on internal visual diff

still not done, but getting close

Changeset f03027a6f8ce

Parent 2bac8fd9d844

by Steve Borho

Changes to 2 files · Browse files at f03027a6f8ce Showing diff from parent 2bac8fd9d844 Diff from another changeset...

Change 1 of 7 Show Entire File hggtk/​visdiff.py Stacked
 
7
8
9
 
10
11
12
13
14
 
15
16
17
 
19
20
21
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
24
 
 
 
 
 
 
 
 
25
26
27
 
45
46
47
48
49
50
51
 
72
73
74
 
75
76
77
 
82
83
84
85
86
87
88
 
103
104
105
106
 
107
108
109
 
121
122
123
124
 
125
126
127
 
7
8
9
10
11
12
13
14
15
16
17
18
19
 
21
22
23
 
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
 
95
96
97
98
99
100
101
102
103
104
105
 
123
124
125
 
126
127
128
 
149
150
151
152
153
154
155
 
160
161
162
 
163
164
165
 
180
181
182
 
183
184
185
186
 
198
199
200
 
201
202
203
204
@@ -7,11 +7,13 @@
 # This software may be used and distributed according to the terms  # of the GNU General Public License, incorporated herein by reference.   +import gtk  from mercurial.i18n import _  from mercurial.node import short  from mercurial import cmdutil, util, commands  from gdialog import Prompt  import os, shlex, subprocess, shutil, tempfile +import shlib    try:   import win32con @@ -19,9 +21,85 @@
 except ImportError:   openflags = 0   -def showfiles(repo, modified, removed, added, dir1, dir2): +diffpath, diffopts = None, None + +class FileSelectionDialog(gtk.Dialog): + 'Dialog for selecting visual diff candidates' + def __init__(self, modified, added, removed, dir1, dir2, dir2root, tmproot): + 'Initialize the Dialog' + gtk.Dialog.__init__(self) + shlib.set_tortoise_icon(self, 'menushowchanged.ico') + self.set_title('Visual Diffs') + self.diffs = (dir1, dir2, dir2root, tmproot) + self.set_default_size(400, 150) + + scroller = gtk.ScrolledWindow() + scroller.set_shadow_type(gtk.SHADOW_IN) + scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + model = gtk.ListStore(str, str) + treeview = gtk.TreeView(model) + treeview.get_selection().set_mode(gtk.SELECTION_SINGLE) + scroller.add(treeview) + self.vbox.pack_start(scroller, True, True) + + treeview.connect('row-activated', self.rowactivated) + treeview.set_headers_visible(False) + treeview.set_property('enable-grid-lines', True) + treeview.set_enable_search(False) + + cell = gtk.CellRendererText() + stcol = gtk.TreeViewColumn('Status', cell) + stcol.set_resizable(True) + stcol.add_attribute(cell, 'text', 0) + treeview.append_column(stcol) + + cell = gtk.CellRendererText() + fcol = gtk.TreeViewColumn('Filename', cell) + fcol.set_resizable(True) + fcol.add_attribute(cell, 'text', 1) + treeview.append_column(fcol) + + for m in modified: + treeview.get_model().append(['M', m]) + for a in added: + treeview.get_model().append(['A', a]) + for r in removed: + treeview.get_model().append(['R', r]) + + def rowactivated(self, tree, path, column): + global diffpath, diffopts + selection = tree.get_selection() + if selection.count_selected_rows() != 1: + return False + model, paths = selection.get_selected_rows() + st, fname = model[paths[0]] + dir1, dir2, dir2root, tmproot = self.diffs + if st == 'M': + dir1 = os.path.join(dir1, util.localpath(fname)) + dir2 = os.path.join(dir2root, dir2, util.localpath(fname)) + elif st == 'R': + dir1 = os.path.join(dir1, util.localpath(fname)) + dir2 = os.devnull + else: + dir1 = os.devnull + dir2 = os.path.join(dir2root, dir2, util.localpath(fname)) + cmdline = [diffpath] + diffopts + [dir1, dir2] + subprocess.Popen(cmdline, shell=False, cwd=tmproot, + creationflags=openflags, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE).wait() + +def showfiles(modified, removed, added, dir1, dir2, dir2root, tmproot):   '''open a treeview dialog to allow user to select files''' - print 'showfiles', modified, removed, added + dialog = FileSelectionDialog(modified, added, removed, + dir1, dir2, dir2root, tmproot) + dialog.show_all() + dialog.connect('destroy', gtk.main_quit) + gtk.gdk.threads_init() + gtk.gdk.threads_enter() + gtk.main() + gtk.gdk.threads_leave()    def snapshot_node(repo, files, node, tmproot):   '''snapshot files as of some revision''' @@ -45,7 +123,6 @@
  open(dest, 'wb').write(data)   return dirname   -diffpath, diffopts = None, None  def visualdiff(repo, pats, opts):   global diffpath, diffopts   if diffpath is None: @@ -72,6 +149,7 @@
    tmproot = tempfile.mkdtemp(prefix='extdiff.')   dir2root = '' + dir2 = ''   try:   # Always make a copy of node1   dir1 = snapshot_node(repo, modified + removed, node1, tmproot) @@ -82,7 +160,6 @@
  dir2 = snapshot_node(repo, modified + added, node2, tmproot)   elif changes == 1:   # This lets the diff tool open the changed file directly - dir2 = ''   dir2root = repo.root     # If only one change, diff the files instead of the directories @@ -103,7 +180,7 @@
  stdout=subprocess.PIPE,   stdin=subprocess.PIPE).wait()   else: - showfiles(repo, modified, removed, added, dir1, dir2) + showfiles(modified, removed, added, dir1, dir2, dir2root, tmproot)   finally:   shutil.rmtree(tmproot)   @@ -121,7 +198,7 @@
  diffopts = ui.config('extdiff', 'opts.' + cmd, '')   diffopts = diffopts and [diffopts] or []   return path, diffopts - elif cmd == usercmd: + elif cmd == vdiff:   # command = path opts   if path:   diffopts = shlex.split(path)
Change 1 of 1 Show Changes Only setup.py Stacked
1
2
3
4
5
6
7
8
 
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
 # setup.py  # A distutils setup script to install TortoiseHg in Windows and Posix  # environments.  #  # On Windows, this script is mostly used to build a stand-alone  # TortoiseHg package. See installer\build.txt for details. The other  # use is to report the current version of the TortoiseHg source.   +  import time  import sys  import os  from distutils.core import setup    def setup_windows():   # Specific definitios for Windows NT-alike installations   _scripts = []   _data_files = []   _packages = ['hggtk', 'hggtk.vis', 'hggtk.iniparse', 'tortoise']   extra = {}   hgextmods = []     # ModuleFinder can't handle runtime changes to __path__,   # but win32com uses them     try:   # if this doesn't work, try import modulefinder   import py2exe.mf as modulefinder   import win32com   for p in win32com.__path__[1:]:   modulefinder.AddPackagePath("win32com", p)   for e in ["win32com.shell"]: #,"win32com.mapi"   __import__(e)   m = sys.modules[e]   for p in m.__path__[1:]:   modulefinder.AddPackagePath(e, p)   except ImportError:   # no build path setup, no worries.   pass     try: import py2exe   except ImportError:   if '--version' not in sys.argv:   raise     if 'py2exe' in sys.argv:   # FIXME: quick hack to include installed hg extensions in py2exe binary   import hgext   hgextdir = os.path.dirname(hgext.__file__)   hgextmods = set(["hgext." + os.path.splitext(f)[0]   for f in os.listdir(hgextdir)])   _data_files = [(root, [os.path.join(root, file_) for file_ in files])   for root, dirs, files in os.walk('icons')]   extra['windows'] = [   {"script":"contrib/tracelog.py",   "icon_resources": [(1, "icons/tortoise/python.ico")]}   ]   extra['com_server'] = ["tortoisehg"]   extra['console'] = ["contrib/hg", "hgtk"]     # add library files to support PyGtk-based dialogs/windows   includes = ['dbhash', 'pango', 'atk', 'pangocairo', 'cairo', 'gobject']     # Manually include other modules py2exe can't find by itself.   if 'hgext.highlight' in hgextmods:   includes += ['pygments.*', 'pygments.lexers.*', 'pygments.formatters.*',   'pygments.filters.*', 'pygments.styles.*']   if 'hgext.patchbomb' in hgextmods:   includes += ['email.*', 'email.mime.*']     extra['options'] = {   "py2exe" : {   # This is one way to ensure that hgtk can find its icons when   # running in a py2exe environment. It also makes debugging easier.   "skip_archive" : 1,     # Don't pull in all this MFC stuff used by the makepy UI.   "excludes" : "pywin,pywin.dialogs,pywin.dialogs.list",     # add library files to support PyGtk-based dialogs/windows   # Note:   # after py2exe build, copy GTK's etc and lib directories into   # the dist directory created by py2exe.   # also needed is the GTK's share/themes (as dist/share/themes),   # for dialogs to display in MS-Windows XP theme.   "includes" : includes + list(hgextmods),   "optimize" : 1,   }   }     return _scripts, _packages, _data_files, extra      def setup_posix():   # Specific definitios for Posix installations   _extra = {}   _scripts = ['hgtk']   _packages = ['hggtk', 'hggtk.vis', 'hggtk.iniparse', 'tortoise']   _data_files = [(os.path.join('share/pixmaps/tortoisehg', root),   [os.path.join(root, file_) for file_ in files])   for root, dirs, files in os.walk('icons')]   _data_files += [('lib/nautilus/extensions-2.0/python',   ['contrib/nautilus-thg.py'])]     return _scripts, _packages, _data_files, _extra      if os.name == "nt":   (scripts, packages, data_files, extra) = setup_windows()   desc='Windows shell extension for Mercurial VCS'  else:   (scripts, packages, data_files, extra) = setup_posix()   desc='TortoiseHg dialogs for Mercurial VCS'    try:   l = os.popen('hg id -it').read().split()   while len(l) > 1 and l[-1][0].isalpha(): # remove non-numbered tags   l.pop()   version = l and l[-1] or 'unknown' # latest tag or revision number   if version.endswith('+'):   version += time.strftime('%Y%m%d')  except OSError:   version = "unknown"    f = file(os.path.join("hggtk", "__version__.py"), "w")  f.write('# this file is autogenerated by setup.py\n')  f.write('version = "%s"\n' % version)  f.close()    setup(name="tortoisehg",   version=version,   author='TK Soh',   author_email='teekaysoh@gmail.com',   url='http://bitbucket.org/tortoisehg/stable/',   description=desc,   license='GNU GPL2',   scripts=scripts,   packages=packages,   data_files=data_files,   **extra   )