48 from mercurial.i18n import _ |
48 from mercurial.i18n import _ |
49 from mercurial.node import short |
49 from mercurial.node import short |
50 from mercurial import cmdutil, util, commands |
50 from mercurial import cmdutil, util, commands |
51 import os, shlex, shutil, tempfile |
51 import os, shlex, shutil, tempfile |
52 |
52 |
53 def snapshot_node(ui, repo, files, node, tmproot): |
53 def snapshot(ui, repo, files, node, tmproot): |
54 '''snapshot files as of some revision''' |
54 '''snapshot files as of some revision |
|
55 if not using snapshot, -I/-X does not work and recursive diff |
|
56 in tools like kdiff3 and meld displays too many files.''' |
55 dirname = os.path.basename(repo.root) |
57 dirname = os.path.basename(repo.root) |
56 if dirname == "": |
58 if dirname == "": |
57 dirname = "root" |
59 dirname = "root" |
58 dirname = '%s.%s' % (dirname, short(node)) |
60 if node is not None: |
|
61 dirname = '%s.%s' % (dirname, short(node)) |
59 base = os.path.join(tmproot, dirname) |
62 base = os.path.join(tmproot, dirname) |
60 os.mkdir(base) |
63 os.mkdir(base) |
61 ui.note(_('making snapshot of %d files from rev %s\n') % |
64 if node is not None: |
62 (len(files), short(node))) |
65 ui.note(_('making snapshot of %d files from rev %s\n') % |
|
66 (len(files), short(node))) |
|
67 else: |
|
68 ui.note(_('making snapshot of %d files from working dir\n') % |
|
69 (len(files))) |
|
70 |
|
71 fns_and_mtime = [] |
63 ctx = repo[node] |
72 ctx = repo[node] |
64 for fn in files: |
73 for fn in files: |
65 wfn = util.pconvert(fn) |
74 wfn = util.pconvert(fn) |
66 if not wfn in ctx: |
75 if not wfn in ctx: |
67 # skipping new file after a merge ? |
76 # skipping new file after a merge ? |
71 destdir = os.path.dirname(dest) |
80 destdir = os.path.dirname(dest) |
72 if not os.path.isdir(destdir): |
81 if not os.path.isdir(destdir): |
73 os.makedirs(destdir) |
82 os.makedirs(destdir) |
74 data = repo.wwritedata(wfn, ctx[wfn].data()) |
83 data = repo.wwritedata(wfn, ctx[wfn].data()) |
75 open(dest, 'wb').write(data) |
84 open(dest, 'wb').write(data) |
76 return dirname |
85 if node is None: |
77 |
86 fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest))) |
78 |
|
79 def snapshot_wdir(ui, repo, files, tmproot): |
|
80 '''snapshot files from working directory. |
|
81 if not using snapshot, -I/-X does not work and recursive diff |
|
82 in tools like kdiff3 and meld displays too many files.''' |
|
83 dirname = os.path.basename(repo.root) |
|
84 if dirname == "": |
|
85 dirname = "root" |
|
86 base = os.path.join(tmproot, dirname) |
|
87 os.mkdir(base) |
|
88 ui.note(_('making snapshot of %d files from working dir\n') % |
|
89 (len(files))) |
|
90 |
|
91 fns_and_mtime = [] |
|
92 |
|
93 for fn in files: |
|
94 wfn = util.pconvert(fn) |
|
95 ui.note(' %s\n' % wfn) |
|
96 dest = os.path.join(base, wfn) |
|
97 destdir = os.path.dirname(dest) |
|
98 if not os.path.isdir(destdir): |
|
99 os.makedirs(destdir) |
|
100 |
|
101 fp = open(dest, 'wb') |
|
102 for chunk in util.filechunkiter(repo.wopener(wfn)): |
|
103 fp.write(chunk) |
|
104 fp.close() |
|
105 |
|
106 fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest))) |
|
107 |
|
108 |
|
109 return dirname, fns_and_mtime |
87 return dirname, fns_and_mtime |
110 |
|
111 |
88 |
112 def dodiff(ui, repo, diffcmd, diffopts, pats, opts): |
89 def dodiff(ui, repo, diffcmd, diffopts, pats, opts): |
113 '''Do the actuall diff: |
90 '''Do the actuall diff: |
114 |
91 |
115 - copy to a temp structure if diffing 2 internal revisions |
92 - copy to a temp structure if diffing 2 internal revisions |
137 |
114 |
138 tmproot = tempfile.mkdtemp(prefix='extdiff.') |
115 tmproot = tempfile.mkdtemp(prefix='extdiff.') |
139 dir2root = '' |
116 dir2root = '' |
140 try: |
117 try: |
141 # Always make a copy of node1 |
118 # Always make a copy of node1 |
142 dir1 = snapshot_node(ui, repo, modified + removed, node1, tmproot) |
119 dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] |
143 changes = len(modified) + len(removed) + len(added) |
120 changes = len(modified) + len(removed) + len(added) |
144 |
121 |
145 fns_and_mtime = [] |
|
146 |
|
147 # If node2 in not the wc or there is >1 change, copy it |
122 # If node2 in not the wc or there is >1 change, copy it |
148 if node2: |
123 if node2 or changes > 1: |
149 dir2 = snapshot_node(ui, repo, modified + added, node2, tmproot) |
124 dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) |
150 elif changes > 1: |
|
151 #we only actually need to get the files to copy back to the working |
|
152 #dir in this case (because the other cases are: diffing 2 revisions |
|
153 #or single file -- in which case the file is already directly passed |
|
154 #to the diff tool). |
|
155 dir2, fns_and_mtime = snapshot_wdir(ui, repo, modified + added, tmproot) |
|
156 else: |
125 else: |
157 # This lets the diff tool open the changed file directly |
126 # This lets the diff tool open the changed file directly |
158 dir2 = '' |
127 dir2 = '' |
159 dir2root = repo.root |
128 dir2root = repo.root |
|
129 fns_and_mtime = [] |
160 |
130 |
161 # If only one change, diff the files instead of the directories |
131 # If only one change, diff the files instead of the directories |
162 if changes == 1 : |
132 if changes == 1 : |
163 if len(modified): |
133 if len(modified): |
164 dir1 = os.path.join(dir1, util.localpath(modified[0])) |
134 dir1 = os.path.join(dir1, util.localpath(modified[0])) |