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 directory\n') % |
|
69 (len(files))) |
|
70 wopener = util.opener(base) |
|
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 ? |
68 continue |
77 continue |
69 ui.note(' %s\n' % wfn) |
78 ui.note(' %s\n' % wfn) |
70 dest = os.path.join(base, wfn) |
79 dest = os.path.join(base, wfn) |
71 destdir = os.path.dirname(dest) |
80 fctx = ctx[wfn] |
72 if not os.path.isdir(destdir): |
81 data = repo.wwritedata(wfn, fctx.data()) |
73 os.makedirs(destdir) |
82 if 'l' in fctx.flags(): |
74 data = repo.wwritedata(wfn, ctx[wfn].data()) |
83 wopener.symlink(data, wfn) |
75 open(dest, 'wb').write(data) |
84 else: |
76 return dirname |
85 wopener(wfn, 'w').write(data) |
77 |
86 if 'x' in fctx.flags(): |
78 |
87 util.set_flags(dest, False, True) |
79 def snapshot_wdir(ui, repo, files, tmproot): |
88 if node is None: |
80 '''snapshot files from working directory. |
89 fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest))) |
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 directory\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 |
90 return dirname, fns_and_mtime |
110 |
|
111 |
91 |
112 def dodiff(ui, repo, diffcmd, diffopts, pats, opts): |
92 def dodiff(ui, repo, diffcmd, diffopts, pats, opts): |
113 '''Do the actuall diff: |
93 '''Do the actuall diff: |
114 |
94 |
115 - copy to a temp structure if diffing 2 internal revisions |
95 - copy to a temp structure if diffing 2 internal revisions |
137 |
117 |
138 tmproot = tempfile.mkdtemp(prefix='extdiff.') |
118 tmproot = tempfile.mkdtemp(prefix='extdiff.') |
139 dir2root = '' |
119 dir2root = '' |
140 try: |
120 try: |
141 # Always make a copy of node1 |
121 # Always make a copy of node1 |
142 dir1 = snapshot_node(ui, repo, modified + removed, node1, tmproot) |
122 dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] |
143 changes = len(modified) + len(removed) + len(added) |
123 changes = len(modified) + len(removed) + len(added) |
144 |
124 |
145 fns_and_mtime = [] |
|
146 |
|
147 # If node2 in not the wc or there is >1 change, copy it |
125 # If node2 in not the wc or there is >1 change, copy it |
148 if node2: |
126 if node2 or changes > 1: |
149 dir2 = snapshot_node(ui, repo, modified + added, node2, tmproot) |
127 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: |
128 else: |
157 # This lets the diff tool open the changed file directly |
129 # This lets the diff tool open the changed file directly |
158 dir2 = '' |
130 dir2 = '' |
159 dir2root = repo.root |
131 dir2root = repo.root |
|
132 fns_and_mtime = [] |
160 |
133 |
161 # If only one change, diff the files instead of the directories |
134 # If only one change, diff the files instead of the directories |
162 if changes == 1 : |
135 if changes == 1 : |
163 if len(modified): |
136 if len(modified): |
164 dir1 = os.path.join(dir1, util.localpath(modified[0])) |
137 dir1 = os.path.join(dir1, util.localpath(modified[0])) |