##// END OF EJS Templates
merge.
Vadim Gelfer -
r2871:ffa2be02 merge default
parent child Browse files
Show More
@@ -0,0 +1,251 b''
1 # patch.py - patch file parsing routines
2 #
3 # Copyright 2006 Brendan Cully <brendan@kublai.com>
4 #
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7
8 from demandload import demandload
9 from i18n import gettext as _
10 demandload(globals(), "util")
11 demandload(globals(), "cStringIO email.Parser os re shutil tempfile")
12
13 def extract(ui, fileobj):
14 '''extract patch from data read from fileobj.
15
16 patch can be normal patch or contained in email message.
17
18 return tuple (filename, message, user, date). any item in returned
19 tuple can be None. if filename is None, fileobj did not contain
20 patch. caller must unlink filename when done.'''
21
22 # attempt to detect the start of a patch
23 # (this heuristic is borrowed from quilt)
24 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
25 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
26 '(---|\*\*\*)[ \t])', re.MULTILINE)
27
28 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
29 tmpfp = os.fdopen(fd, 'w')
30 try:
31 hgpatch = False
32
33 msg = email.Parser.Parser().parse(fileobj)
34
35 message = msg['Subject']
36 user = msg['From']
37 # should try to parse msg['Date']
38 date = None
39
40 if message:
41 message = message.replace('\n\t', ' ')
42 ui.debug('Subject: %s\n' % message)
43 if user:
44 ui.debug('From: %s\n' % user)
45 diffs_seen = 0
46 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
47
48 for part in msg.walk():
49 content_type = part.get_content_type()
50 ui.debug('Content-Type: %s\n' % content_type)
51 if content_type not in ok_types:
52 continue
53 payload = part.get_payload(decode=True)
54 m = diffre.search(payload)
55 if m:
56 ui.debug(_('found patch at byte %d\n') % m.start(0))
57 diffs_seen += 1
58 cfp = cStringIO.StringIO()
59 if message:
60 cfp.write(message)
61 cfp.write('\n')
62 for line in payload[:m.start(0)].splitlines():
63 if line.startswith('# HG changeset patch'):
64 ui.debug(_('patch generated by hg export\n'))
65 hgpatch = True
66 # drop earlier commit message content
67 cfp.seek(0)
68 cfp.truncate()
69 elif hgpatch:
70 if line.startswith('# User '):
71 user = line[7:]
72 ui.debug('From: %s\n' % user)
73 elif line.startswith("# Date "):
74 date = line[7:]
75 if not line.startswith('# '):
76 cfp.write(line)
77 cfp.write('\n')
78 message = cfp.getvalue()
79 if tmpfp:
80 tmpfp.write(payload)
81 if not payload.endswith('\n'):
82 tmpfp.write('\n')
83 elif not diffs_seen and message and content_type == 'text/plain':
84 message += '\n' + payload
85 except:
86 tmpfp.close()
87 os.unlink(tmpname)
88 raise
89
90 tmpfp.close()
91 if not diffs_seen:
92 os.unlink(tmpname)
93 return None, message, user, date
94 return tmpname, message, user, date
95
96 def readgitpatch(patchname):
97 """extract git-style metadata about patches from <patchname>"""
98 class gitpatch:
99 "op is one of ADD, DELETE, RENAME, MODIFY or COPY"
100 def __init__(self, path):
101 self.path = path
102 self.oldpath = None
103 self.mode = None
104 self.op = 'MODIFY'
105 self.copymod = False
106 self.lineno = 0
107
108 # Filter patch for git information
109 gitre = re.compile('diff --git a/(.*) b/(.*)')
110 pf = file(patchname)
111 gp = None
112 gitpatches = []
113 # Can have a git patch with only metadata, causing patch to complain
114 dopatch = False
115
116 lineno = 0
117 for line in pf:
118 lineno += 1
119 if line.startswith('diff --git'):
120 m = gitre.match(line)
121 if m:
122 if gp:
123 gitpatches.append(gp)
124 src, dst = m.group(1,2)
125 gp = gitpatch(dst)
126 gp.lineno = lineno
127 elif gp:
128 if line.startswith('--- '):
129 if gp.op in ('COPY', 'RENAME'):
130 gp.copymod = True
131 dopatch = 'filter'
132 gitpatches.append(gp)
133 gp = None
134 if not dopatch:
135 dopatch = True
136 continue
137 if line.startswith('rename from '):
138 gp.op = 'RENAME'
139 gp.oldpath = line[12:].rstrip()
140 elif line.startswith('rename to '):
141 gp.path = line[10:].rstrip()
142 elif line.startswith('copy from '):
143 gp.op = 'COPY'
144 gp.oldpath = line[10:].rstrip()
145 elif line.startswith('copy to '):
146 gp.path = line[8:].rstrip()
147 elif line.startswith('deleted file'):
148 gp.op = 'DELETE'
149 elif line.startswith('new file mode '):
150 gp.op = 'ADD'
151 gp.mode = int(line.rstrip()[-3:], 8)
152 elif line.startswith('new mode '):
153 gp.mode = int(line.rstrip()[-3:], 8)
154 if gp:
155 gitpatches.append(gp)
156
157 if not gitpatches:
158 dopatch = True
159
160 return (dopatch, gitpatches)
161
162 def dogitpatch(patchname, gitpatches):
163 """Preprocess git patch so that vanilla patch can handle it"""
164 pf = file(patchname)
165 pfline = 1
166
167 fd, patchname = tempfile.mkstemp(prefix='hg-patch-')
168 tmpfp = os.fdopen(fd, 'w')
169
170 try:
171 for i in range(len(gitpatches)):
172 p = gitpatches[i]
173 if not p.copymod:
174 continue
175
176 if os.path.exists(p.path):
177 raise util.Abort(_("cannot create %s: destination already exists") %
178 p.path)
179
180 (src, dst) = [os.path.join(os.getcwd(), n)
181 for n in (p.oldpath, p.path)]
182
183 targetdir = os.path.dirname(dst)
184 if not os.path.isdir(targetdir):
185 os.makedirs(targetdir)
186 try:
187 shutil.copyfile(src, dst)
188 shutil.copymode(src, dst)
189 except shutil.Error, inst:
190 raise util.Abort(str(inst))
191
192 # rewrite patch hunk
193 while pfline < p.lineno:
194 tmpfp.write(pf.readline())
195 pfline += 1
196 tmpfp.write('diff --git a/%s b/%s\n' % (p.path, p.path))
197 line = pf.readline()
198 pfline += 1
199 while not line.startswith('--- a/'):
200 tmpfp.write(line)
201 line = pf.readline()
202 pfline += 1
203 tmpfp.write('--- a/%s\n' % p.path)
204
205 line = pf.readline()
206 while line:
207 tmpfp.write(line)
208 line = pf.readline()
209 except:
210 tmpfp.close()
211 os.unlink(patchname)
212 raise
213
214 tmpfp.close()
215 return patchname
216
217 def patch(strip, patchname, ui, cwd=None):
218 """apply the patch <patchname> to the working directory.
219 a list of patched files is returned"""
220
221 (dopatch, gitpatches) = readgitpatch(patchname)
222
223 files = {}
224 if dopatch:
225 if dopatch == 'filter':
226 patchname = dogitpatch(patchname, gitpatches)
227 patcher = util.find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
228 args = []
229 if cwd:
230 args.append('-d %s' % util.shellquote(cwd))
231 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
232 util.shellquote(patchname)))
233
234 if dopatch == 'filter':
235 False and os.unlink(patchname)
236
237 for line in fp:
238 line = line.rstrip()
239 ui.status("%s\n" % line)
240 if line.startswith('patching file '):
241 pf = util.parse_patch_output(line)
242 files.setdefault(pf, (None, None))
243 code = fp.close()
244 if code:
245 raise util.Abort(_("patch command failed: %s") %
246 util.explain_exit(code)[0])
247
248 for gp in gitpatches:
249 files[gp.path] = (gp.op, gp)
250
251 return files
@@ -0,0 +1,122 b''
1 #!/bin/sh
2
3 hg init a
4 cd a
5
6 echo % new file
7 hg import -mnew - <<EOF
8 diff --git a/new b/new
9 new file mode 100644
10 index 0000000..7898192
11 --- /dev/null
12 +++ b/new
13 @@ -0,0 +1 @@
14 +a
15 EOF
16
17 echo % chmod +x
18 hg import -msetx - <<EOF
19 diff --git a/new b/new
20 old mode 100644
21 new mode 100755
22 EOF
23
24 test -x new || echo failed
25
26 echo % copy
27 hg import -mcopy - <<EOF
28 diff --git a/new b/copy
29 old mode 100755
30 new mode 100644
31 similarity index 100%
32 copy from new
33 copy to copy
34 diff --git a/new b/copyx
35 similarity index 100%
36 copy from new
37 copy to copyx
38 EOF
39
40 test -f copy -a ! -x copy || echo failed
41 test -x copyx || echo failed
42 cat copy
43 hg cat copy
44
45 echo % rename
46 hg import -mrename - <<EOF
47 diff --git a/copy b/rename
48 similarity index 100%
49 rename from copy
50 rename to rename
51 EOF
52
53 hg locate
54
55 echo % delete
56 hg import -mdelete - <<EOF
57 diff --git a/copyx b/copyx
58 deleted file mode 100755
59 index 7898192..0000000
60 --- a/copyx
61 +++ /dev/null
62 @@ -1 +0,0 @@
63 -a
64 EOF
65
66 hg locate
67 test -f copyx && echo failed || true
68
69 echo % regular diff
70 hg import -mregular - <<EOF
71 diff --git a/rename b/rename
72 index 7898192..72e1fe3 100644
73 --- a/rename
74 +++ b/rename
75 @@ -1 +1,5 @@
76 a
77 +a
78 +a
79 +a
80 +a
81 EOF
82
83 echo % copy and modify
84 hg import -mcopymod - <<EOF
85 diff --git a/rename b/copy2
86 similarity index 80%
87 copy from rename
88 copy to copy2
89 index 72e1fe3..b53c148 100644
90 --- a/rename
91 +++ b/copy2
92 @@ -1,5 +1,5 @@
93 a
94 a
95 -a
96 +b
97 a
98 a
99 EOF
100
101 hg cat copy2
102
103 echo % rename and modify
104 hg import -mrenamemod - <<EOF
105 diff --git a/copy2 b/rename2
106 similarity index 80%
107 rename from copy2
108 rename to rename2
109 index b53c148..8f81e29 100644
110 --- a/copy2
111 +++ b/rename2
112 @@ -1,5 +1,5 @@
113 a
114 a
115 b
116 -a
117 +c
118 a
119 EOF
120
121 hg locate copy2
122 hg cat rename2
@@ -0,0 +1,39 b''
1 % new file
2 applying patch from stdin
3 patching file new
4 % chmod +x
5 applying patch from stdin
6 % copy
7 applying patch from stdin
8 a
9 a
10 % rename
11 applying patch from stdin
12 copyx
13 new
14 rename
15 % delete
16 applying patch from stdin
17 patching file copyx
18 new
19 rename
20 % regular diff
21 applying patch from stdin
22 patching file rename
23 % copy and modify
24 applying patch from stdin
25 patching file copy2
26 a
27 a
28 b
29 a
30 a
31 % rename and modify
32 applying patch from stdin
33 patching file rename2
34 copy2: No such file or directory
35 a
36 a
37 b
38 c
39 a
@@ -216,6 +216,6 b' http://selenic.com/mailman/listinfo/merc'
216
216
217 COPYING
217 COPYING
218 -------
218 -------
219 Copyright \(C) 2005 Matt Mackall.
219 Copyright \(C) 2005, 2006 Matt Mackall.
220 Free use of this software is granted under the terms of the GNU General
220 Free use of this software is granted under the terms of the GNU General
221 Public License (GPL).
221 Public License (GPL).
@@ -30,6 +30,6 b' hg(1) - the command line interface to Me'
30
30
31 COPYING
31 COPYING
32 -------
32 -------
33 Copyright \(C) 2005 Matt Mackall.
33 Copyright \(C) 2005, 2006 Matt Mackall.
34 Free use of this software is granted under the terms of the GNU General
34 Free use of this software is granted under the terms of the GNU General
35 Public License (GPL).
35 Public License (GPL).
@@ -862,6 +862,6 b' http://selenic.com/mailman/listinfo/mercurial[\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xaa\xe3\x83\xb3\xe3\x82\xb0\xe3\x83\xaa\xe3\x82\xb9\xe3\x83\x88]'
862
862
863 著作権情報
863 著作権情報
864 -----
864 -----
865 Copyright (C) 2005 Matt Mackall.
865 Copyright (C) 2005, 2006 Matt Mackall.
866 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
866 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
867 認められます。
867 認められます。
@@ -32,6 +32,6 b' hg(1) - Mercurial \xe3\x82\xb7\xe3\x82\xb9\xe3\x83\x86\xe3\x83\xa0\xe3\x81\xb8\xe3\x81\xae\xe3\x82\xb3\xe3\x83\x9e\xe3\x83\xb3\xe3\x83\x89\xe3\x83\xa9\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xa4\xe3\x83\xb3\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\x95\xe3\x82\xa7\xe3\x82\xa4\xe3\x82\xb9'
32
32
33 著作権情報
33 著作権情報
34 ----
34 ----
35 Copyright (C) 2005 Matt Mackall.
35 Copyright (C) 2005, 2006 Matt Mackall.
36 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
36 このソフトウェアの自由な使用は GNU 一般公有使用許諾 (GPL) のもとで
37 認められます。
37 認められます。
@@ -1,6 +1,6 b''
1 # Minimal support for git commands on an hg repository
1 # Minimal support for git commands on an hg repository
2 #
2 #
3 # Copyright 2005 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,6 b''
1
2 # queue.py - patch queues for mercurial
1 # queue.py - patch queues for mercurial
3 #
2 #
4 # Copyright 2005 Chris Mason <mason@suse.com>
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
5 #
4 #
6 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -31,9 +30,9 b' refresh contents of top applied patch '
31 '''
30 '''
32
31
33 from mercurial.demandload import *
32 from mercurial.demandload import *
33 from mercurial.i18n import gettext as _
34 demandload(globals(), "os sys re struct traceback errno bz2")
34 demandload(globals(), "os sys re struct traceback errno bz2")
35 from mercurial.i18n import gettext as _
35 demandload(globals(), "mercurial:commands,hg,revlog,ui,util")
36 from mercurial import ui, hg, revlog, commands, util
37
36
38 commands.norepo += " qclone qversion"
37 commands.norepo += " qclone qversion"
39
38
@@ -561,7 +560,7 b' class queue:'
561 r = self.qrepo()
560 r = self.qrepo()
562 if r: r.add([patch])
561 if r: r.add([patch])
563 if commitfiles:
562 if commitfiles:
564 self.refresh(repo, msg=None, short=True)
563 self.refresh(repo, short=True)
565
564
566 def strip(self, repo, rev, update=True, backup="all", wlock=None):
565 def strip(self, repo, rev, update=True, backup="all", wlock=None):
567 def limitheads(chlog, stop):
566 def limitheads(chlog, stop):
@@ -888,7 +887,6 b' class queue:'
888 top = self.check_toppatch(repo)
887 top = self.check_toppatch(repo)
889 qp = self.qparents(repo, rev)
888 qp = self.qparents(repo, rev)
890 changes = repo.changelog.read(qp)
889 changes = repo.changelog.read(qp)
891 mf1 = repo.manifest.readflags(changes[0])
892 mmap = repo.manifest.read(changes[0])
890 mmap = repo.manifest.read(changes[0])
893 (c, a, r, d, u) = repo.changes(qp, top)
891 (c, a, r, d, u) = repo.changes(qp, top)
894 if d:
892 if d:
@@ -897,7 +895,7 b' class queue:'
897 getfile(f, mmap[f])
895 getfile(f, mmap[f])
898 for f in r:
896 for f in r:
899 getfile(f, mmap[f])
897 getfile(f, mmap[f])
900 util.set_exec(repo.wjoin(f), mf1[f])
898 util.set_exec(repo.wjoin(f), mmap.execf[f])
901 repo.dirstate.update(c + r, 'n')
899 repo.dirstate.update(c + r, 'n')
902 for f in a:
900 for f in a:
903 try: os.unlink(repo.wjoin(f))
901 try: os.unlink(repo.wjoin(f))
@@ -922,7 +920,7 b' class queue:'
922 qp = self.qparents(repo, top)
920 qp = self.qparents(repo, top)
923 commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
921 commands.dodiff(sys.stdout, self.ui, repo, qp, None, files)
924
922
925 def refresh(self, repo, msg=None, short=False):
923 def refresh(self, repo, msg='', short=False):
926 if len(self.applied) == 0:
924 if len(self.applied) == 0:
927 self.ui.write("No patches applied\n")
925 self.ui.write("No patches applied\n")
928 return
926 return
@@ -1988,4 +1986,3 b' cmdtable = {'
1988 "qtop": (top, [], 'hg qtop'),
1986 "qtop": (top, [], 'hg qtop'),
1989 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1987 "qunapplied": (unapplied, [], 'hg qunapplied [PATCH]'),
1990 }
1988 }
1991
@@ -163,12 +163,12 b' def archive(repo, dest, node, kind, deco'
163 change = repo.changelog.read(node)
163 change = repo.changelog.read(node)
164 mn = change[0]
164 mn = change[0]
165 archiver = archivers[kind](dest, prefix, mtime or change[2][0])
165 archiver = archivers[kind](dest, prefix, mtime or change[2][0])
166 mf = repo.manifest.read(mn).items()
166 m = repo.manifest.read(mn)
167 mff = repo.manifest.readflags(mn)
167 items = m.items()
168 mf.sort()
168 items.sort()
169 write('.hg_archival.txt', 0644,
169 write('.hg_archival.txt', 0644,
170 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
170 'repo: %s\nnode: %s\n' % (hex(repo.changelog.node(0)), hex(node)))
171 for filename, filenode in mf:
171 for filename, filenode in items:
172 write(filename, mff[filename] and 0755 or 0644,
172 write(filename, m.execf(filename) and 0755 or 0644,
173 repo.file(filename).read(filenode))
173 repo.file(filename).read(filenode))
174 archiver.done()
174 archiver.done()
@@ -1,7 +1,7 b''
1 /*
1 /*
2 bdiff.c - efficient binary diff extension for Mercurial
2 bdiff.c - efficient binary diff extension for Mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # changelog.py - changelog class for mercurial
1 # changelog.py - changelog class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -10,9 +10,9 b' from node import *'
10 from i18n import gettext as _
10 from i18n import gettext as _
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
11 demandload(globals(), "os re sys signal shutil imp urllib pdb")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
12 demandload(globals(), "fancyopts ui hg util lock revlog templater bundlerepo")
13 demandload(globals(), "fnmatch mdiff difflib random signal tempfile time")
13 demandload(globals(), "fnmatch mdiff difflib patch random signal tempfile time")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
14 demandload(globals(), "traceback errno socket version struct atexit sets bz2")
15 demandload(globals(), "archival cStringIO changegroup email.Parser")
15 demandload(globals(), "archival cStringIO changegroup")
16 demandload(globals(), "hgweb.server sshserver")
16 demandload(globals(), "hgweb.server sshserver")
17
17
18 class UnknownCommand(Exception):
18 class UnknownCommand(Exception):
@@ -633,7 +633,7 b' def show_version(ui):'
633 ui.write(_("Mercurial Distributed SCM (version %s)\n")
633 ui.write(_("Mercurial Distributed SCM (version %s)\n")
634 % version.get_version())
634 % version.get_version())
635 ui.status(_(
635 ui.status(_(
636 "\nCopyright (C) 2005 Matt Mackall <mpm@selenic.com>\n"
636 "\nCopyright (C) 2005, 2006 Matt Mackall <mpm@selenic.com>\n"
637 "This is free software; see the source for copying conditions. "
637 "This is free software; see the source for copying conditions. "
638 "There is NO\nwarranty; "
638 "There is NO\nwarranty; "
639 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
639 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
@@ -1333,9 +1333,9 b' def debugrebuildstate(ui, repo, rev=None'
1333 rev = repo.lookup(rev)
1333 rev = repo.lookup(rev)
1334 change = repo.changelog.read(rev)
1334 change = repo.changelog.read(rev)
1335 n = change[0]
1335 n = change[0]
1336 files = repo.manifest.readflags(n)
1336 files = repo.manifest.read(n)
1337 wlock = repo.wlock()
1337 wlock = repo.wlock()
1338 repo.dirstate.rebuild(rev, files.iteritems())
1338 repo.dirstate.rebuild(rev, files)
1339
1339
1340 def debugcheckstate(ui, repo):
1340 def debugcheckstate(ui, repo):
1341 """validate the correctness of the current dirstate"""
1341 """validate the correctness of the current dirstate"""
@@ -1843,84 +1843,23 b' def import_(ui, repo, patch1, *patches, '
1843 d = opts["base"]
1843 d = opts["base"]
1844 strip = opts["strip"]
1844 strip = opts["strip"]
1845
1845
1846 mailre = re.compile(r'(?:From |[\w-]+:)')
1847
1848 # attempt to detect the start of a patch
1849 # (this heuristic is borrowed from quilt)
1850 diffre = re.compile(r'^(?:Index:[ \t]|diff[ \t]|RCS file: |' +
1851 'retrieving revision [0-9]+(\.[0-9]+)*$|' +
1852 '(---|\*\*\*)[ \t])', re.MULTILINE)
1853
1854 wlock = repo.wlock()
1846 wlock = repo.wlock()
1855 lock = repo.lock()
1847 lock = repo.lock()
1856
1848
1857 for patch in patches:
1849 for p in patches:
1858 pf = os.path.join(d, patch)
1850 pf = os.path.join(d, p)
1859
1851
1860 message = None
1861 user = None
1862 date = None
1863 hgpatch = False
1864
1865 p = email.Parser.Parser()
1866 if pf == '-':
1852 if pf == '-':
1867 msg = p.parse(sys.stdin)
1868 ui.status(_("applying patch from stdin\n"))
1853 ui.status(_("applying patch from stdin\n"))
1854 tmpname, message, user, date = patch.extract(ui, sys.stdin)
1869 else:
1855 else:
1870 msg = p.parse(file(pf))
1856 ui.status(_("applying %s\n") % p)
1871 ui.status(_("applying %s\n") % patch)
1857 tmpname, message, user, date = patch.extract(ui, file(pf))
1872
1858
1873 fd, tmpname = tempfile.mkstemp(prefix='hg-patch-')
1859 if tmpname is None:
1874 tmpfp = os.fdopen(fd, 'w')
1860 raise util.Abort(_('no diffs found'))
1861
1875 try:
1862 try:
1876 message = msg['Subject']
1877 if message:
1878 message = message.replace('\n\t', ' ')
1879 ui.debug('Subject: %s\n' % message)
1880 user = msg['From']
1881 if user:
1882 ui.debug('From: %s\n' % user)
1883 diffs_seen = 0
1884 ok_types = ('text/plain', 'text/x-diff', 'text/x-patch')
1885 for part in msg.walk():
1886 content_type = part.get_content_type()
1887 ui.debug('Content-Type: %s\n' % content_type)
1888 if content_type not in ok_types:
1889 continue
1890 payload = part.get_payload(decode=True)
1891 m = diffre.search(payload)
1892 if m:
1893 ui.debug(_('found patch at byte %d\n') % m.start(0))
1894 diffs_seen += 1
1895 hgpatch = False
1896 fp = cStringIO.StringIO()
1897 if message:
1898 fp.write(message)
1899 fp.write('\n')
1900 for line in payload[:m.start(0)].splitlines():
1901 if line.startswith('# HG changeset patch'):
1902 ui.debug(_('patch generated by hg export\n'))
1903 hgpatch = True
1904 # drop earlier commit message content
1905 fp.seek(0)
1906 fp.truncate()
1907 elif hgpatch:
1908 if line.startswith('# User '):
1909 user = line[7:]
1910 ui.debug('From: %s\n' % user)
1911 elif line.startswith("# Date "):
1912 date = line[7:]
1913 if not line.startswith('# '):
1914 fp.write(line)
1915 fp.write('\n')
1916 message = fp.getvalue()
1917 if tmpfp:
1918 tmpfp.write(payload)
1919 if not payload.endswith('\n'):
1920 tmpfp.write('\n')
1921 elif not diffs_seen and message and content_type == 'text/plain':
1922 message += '\n' + payload
1923
1924 if opts['message']:
1863 if opts['message']:
1925 # pickup the cmdline msg
1864 # pickup the cmdline msg
1926 message = opts['message']
1865 message = opts['message']
@@ -1932,17 +1871,45 b' def import_(ui, repo, patch1, *patches, '
1932 message = None
1871 message = None
1933 ui.debug(_('message:\n%s\n') % message)
1872 ui.debug(_('message:\n%s\n') % message)
1934
1873
1935 tmpfp.close()
1874 files = patch.patch(strip, tmpname, ui, cwd=repo.root)
1936 if not diffs_seen:
1875 removes = []
1937 raise util.Abort(_('no diffs found'))
1938
1939 files = util.patch(strip, tmpname, ui, cwd=repo.root)
1940 if len(files) > 0:
1876 if len(files) > 0:
1941 cfiles = files
1877 cfiles = files.keys()
1878 copies = []
1879 copts = {'after': False, 'force': False}
1942 cwd = repo.getcwd()
1880 cwd = repo.getcwd()
1943 if cwd:
1881 if cwd:
1944 cfiles = [util.pathto(cwd, f) for f in files]
1882 cfiles = [util.pathto(cwd, f) for f in files.keys()]
1883 for f in files:
1884 ctype, gp = files[f]
1885 if ctype == 'RENAME':
1886 copies.append((gp.oldpath, gp.path, gp.copymod))
1887 removes.append(gp.oldpath)
1888 elif ctype == 'COPY':
1889 copies.append((gp.oldpath, gp.path, gp.copymod))
1890 elif ctype == 'DELETE':
1891 removes.append(gp.path)
1892 for src, dst, after in copies:
1893 absdst = os.path.join(repo.root, dst)
1894 if not after and os.path.exists(absdst):
1895 raise util.Abort(_('patch creates existing file %s') % dst)
1896 if cwd:
1897 src, dst = [util.pathto(cwd, f) for f in (src, dst)]
1898 copts['after'] = after
1899 errs, copied = docopy(ui, repo, (src, dst), copts, wlock=wlock)
1900 if errs:
1901 raise util.Abort(errs)
1902 if removes:
1903 repo.remove(removes, True, wlock=wlock)
1904 for f in files:
1905 ctype, gp = files[f]
1906 if gp and gp.mode:
1907 x = gp.mode & 0100 != 0
1908 dst = os.path.join(repo.root, gp.path)
1909 util.set_exec(dst, x)
1945 addremove_lock(ui, repo, cfiles, {}, wlock=wlock)
1910 addremove_lock(ui, repo, cfiles, {}, wlock=wlock)
1911 files = files.keys()
1912 files.extend([r for r in removes if r not in files])
1946 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1913 repo.commit(files, message, user, date, wlock=wlock, lock=lock)
1947 finally:
1914 finally:
1948 os.unlink(tmpname)
1915 os.unlink(tmpname)
@@ -2178,12 +2145,12 b' def manifest(ui, repo, rev=None):'
2178 else:
2145 else:
2179 n = repo.manifest.tip()
2146 n = repo.manifest.tip()
2180 m = repo.manifest.read(n)
2147 m = repo.manifest.read(n)
2181 mf = repo.manifest.readflags(n)
2182 files = m.keys()
2148 files = m.keys()
2183 files.sort()
2149 files.sort()
2184
2150
2185 for f in files:
2151 for f in files:
2186 ui.write("%40s %3s %s\n" % (hex(m[f]), mf[f] and "755" or "644", f))
2152 ui.write("%40s %3s %s\n" % (hex(m[f]),
2153 m.execf(f) and "755" or "644", f))
2187
2154
2188 def merge(ui, repo, node=None, force=None, branch=None):
2155 def merge(ui, repo, node=None, force=None, branch=None):
2189 """Merge working directory with another revision
2156 """Merge working directory with another revision
@@ -1,6 +1,6 b''
1 # context.py - changeset and file context objects for mercurial
1 # context.py - changeset and file context objects for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 """
1 """
2 dirstate.py - working directory tracking for mercurial
2 dirstate.py - working directory tracking for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
@@ -238,8 +238,8 b' class dirstate(object):'
238 self.clear()
238 self.clear()
239 umask = os.umask(0)
239 umask = os.umask(0)
240 os.umask(umask)
240 os.umask(umask)
241 for f, mode in files:
241 for f in files:
242 if mode:
242 if files.execf(f):
243 self.map[f] = ('n', ~umask, -1, 0)
243 self.map[f] = ('n', ~umask, -1, 0)
244 else:
244 else:
245 self.map[f] = ('n', ~umask & 0666, -1, 0)
245 self.map[f] = ('n', ~umask & 0666, -1, 0)
@@ -1,6 +1,6 b''
1 # filelog.py - file history class for mercurial
1 # filelog.py - file history class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,7 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
1 # hgweb/common.py - Utility functions needed by hgweb_mod and hgwebdir_mod
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 # hgweb/hgweb_mod.py - Web interface for a repository.
1 # hgweb/hgweb_mod.py - Web interface for a repository.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -398,7 +398,7 b' class hgweb(object):'
398 parent=self.siblings(fl.parents(n), fl.rev, file=f),
398 parent=self.siblings(fl.parents(n), fl.rev, file=f),
399 child=self.siblings(fl.children(n), fl.rev, file=f),
399 child=self.siblings(fl.children(n), fl.rev, file=f),
400 rename=self.renamelink(fl, n),
400 rename=self.renamelink(fl, n),
401 permissions=self.repo.manifest.readflags(mfn)[f])
401 permissions=self.repo.manifest.read(mfn).execf(f))
402
402
403 def fileannotate(self, f, node):
403 def fileannotate(self, f, node):
404 bcache = {}
404 bcache = {}
@@ -452,7 +452,7 b' class hgweb(object):'
452 rename=self.renamelink(fl, n),
452 rename=self.renamelink(fl, n),
453 parent=self.siblings(fl.parents(n), fl.rev, file=f),
453 parent=self.siblings(fl.parents(n), fl.rev, file=f),
454 child=self.siblings(fl.children(n), fl.rev, file=f),
454 child=self.siblings(fl.children(n), fl.rev, file=f),
455 permissions=self.repo.manifest.readflags(mfn)[f])
455 permissions=self.repo.manifest.read(mfn).execf(f))
456
456
457 def manifest(self, mnode, path):
457 def manifest(self, mnode, path):
458 man = self.repo.manifest
458 man = self.repo.manifest
@@ -462,7 +462,6 b' class hgweb(object):'
462 rev = man.rev(mn)
462 rev = man.rev(mn)
463 changerev = man.linkrev(mn)
463 changerev = man.linkrev(mn)
464 node = self.repo.changelog.node(changerev)
464 node = self.repo.changelog.node(changerev)
465 mff = man.readflags(mn)
466
465
467 files = {}
466 files = {}
468
467
@@ -496,7 +495,7 b' class hgweb(object):'
496 "filenode": hex(fnode),
495 "filenode": hex(fnode),
497 "parity": self.stripes(parity),
496 "parity": self.stripes(parity),
498 "basename": f,
497 "basename": f,
499 "permissions": mff[full]}
498 "permissions": mf.execf(full)}
500 parity += 1
499 parity += 1
501
500
502 def dirlist(**map):
501 def dirlist(**map):
@@ -1,7 +1,7 b''
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 # hgweb/request.py - An http request from either CGI or the standalone server.
1 # hgweb/request.py - An http request from either CGI or the standalone server.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 # hgweb/server.py - The standalone hg web server.
1 # hgweb/server.py - The standalone hg web server.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # httprangereader.py - just what it says
1 # httprangereader.py - just what it says
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,7 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httprepo.py - HTTP repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 """
1 """
2 i18n.py - internationalization support for mercurial
2 i18n.py - internationalization support for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # localrepo.py - read/write repository class for mercurial
1 # localrepo.py - read/write repository class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -470,8 +470,7 b' class localrepository(repo.repository):'
470 p2 = p2 or self.dirstate.parents()[1] or nullid
470 p2 = p2 or self.dirstate.parents()[1] or nullid
471 c1 = self.changelog.read(p1)
471 c1 = self.changelog.read(p1)
472 c2 = self.changelog.read(p2)
472 c2 = self.changelog.read(p2)
473 m1 = self.manifest.read(c1[0])
473 m1 = self.manifest.read(c1[0]).copy()
474 mf1 = self.manifest.readflags(c1[0])
475 m2 = self.manifest.read(c2[0])
474 m2 = self.manifest.read(c2[0])
476 changed = []
475 changed = []
477
476
@@ -484,36 +483,32 b' class localrepository(repo.repository):'
484 wlock = self.wlock()
483 wlock = self.wlock()
485 l = self.lock()
484 l = self.lock()
486 tr = self.transaction()
485 tr = self.transaction()
487 mm = m1.copy()
488 mfm = mf1.copy()
489 linkrev = self.changelog.count()
486 linkrev = self.changelog.count()
490 for f in files:
487 for f in files:
491 try:
488 try:
492 t = self.wread(f)
489 t = self.wread(f)
493 tm = util.is_exec(self.wjoin(f), mfm.get(f, False))
490 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
494 r = self.file(f)
491 r = self.file(f)
495 mfm[f] = tm
496
492
497 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
493 (entry, fp1, fp2) = self.checkfilemerge(f, t, r, m1, m2)
498 if entry:
494 if entry:
499 mm[f] = entry
495 m1[f] = entry
500 continue
496 continue
501
497
502 mm[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
498 m1[f] = r.add(t, {}, tr, linkrev, fp1, fp2)
503 changed.append(f)
499 changed.append(f)
504 if update_dirstate:
500 if update_dirstate:
505 self.dirstate.update([f], "n")
501 self.dirstate.update([f], "n")
506 except IOError:
502 except IOError:
507 try:
503 try:
508 del mm[f]
504 del m1[f]
509 del mfm[f]
510 if update_dirstate:
505 if update_dirstate:
511 self.dirstate.forget([f])
506 self.dirstate.forget([f])
512 except:
507 except:
513 # deleted from p2?
508 # deleted from p2?
514 pass
509 pass
515
510
516 mnode = self.manifest.add(mm, mfm, tr, linkrev, c1[0], c2[0])
511 mnode = self.manifest.add(m1, tr, linkrev, c1[0], c2[0])
517 user = user or self.ui.username()
512 user = user or self.ui.username()
518 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
513 n = self.changelog.add(mnode, changed, text, tr, p1, p2, user, date)
519 tr.close()
514 tr.close()
@@ -544,8 +539,7 b' class localrepository(repo.repository):'
544 p1, p2 = self.dirstate.parents()
539 p1, p2 = self.dirstate.parents()
545 c1 = self.changelog.read(p1)
540 c1 = self.changelog.read(p1)
546 c2 = self.changelog.read(p2)
541 c2 = self.changelog.read(p2)
547 m1 = self.manifest.read(c1[0])
542 m1 = self.manifest.read(c1[0]).copy()
548 mf1 = self.manifest.readflags(c1[0])
549 m2 = self.manifest.read(c2[0])
543 m2 = self.manifest.read(c2[0])
550
544
551 if not commit and not remove and not force and p2 == nullid:
545 if not commit and not remove and not force and p2 == nullid:
@@ -571,7 +565,7 b' class localrepository(repo.repository):'
571 for f in commit:
565 for f in commit:
572 self.ui.note(f + "\n")
566 self.ui.note(f + "\n")
573 try:
567 try:
574 mf1[f] = util.is_exec(self.wjoin(f), mf1.get(f, False))
568 m1.set(f, util.is_exec(self.wjoin(f), m1.execf(f)))
575 t = self.wread(f)
569 t = self.wread(f)
576 except IOError:
570 except IOError:
577 self.ui.warn(_("trouble committing %s!\n") % f)
571 self.ui.warn(_("trouble committing %s!\n") % f)
@@ -598,12 +592,11 b' class localrepository(repo.repository):'
598 changed.append(f)
592 changed.append(f)
599
593
600 # update manifest
594 # update manifest
601 m1 = m1.copy()
602 m1.update(new)
595 m1.update(new)
603 for f in remove:
596 for f in remove:
604 if f in m1:
597 if f in m1:
605 del m1[f]
598 del m1[f]
606 mn = self.manifest.add(m1, mf1, tr, linkrev, c1[0], c2[0],
599 mn = self.manifest.add(m1, tr, linkrev, c1[0], c2[0],
607 (new, remove))
600 (new, remove))
608
601
609 # add changeset
602 # add changeset
@@ -816,7 +809,6 b' class localrepository(repo.repository):'
816 def undelete(self, list, wlock=None):
809 def undelete(self, list, wlock=None):
817 p = self.dirstate.parents()[0]
810 p = self.dirstate.parents()[0]
818 mn = self.changelog.read(p)[0]
811 mn = self.changelog.read(p)[0]
819 mf = self.manifest.readflags(mn)
820 m = self.manifest.read(mn)
812 m = self.manifest.read(mn)
821 if not wlock:
813 if not wlock:
822 wlock = self.wlock()
814 wlock = self.wlock()
@@ -826,7 +818,7 b' class localrepository(repo.repository):'
826 else:
818 else:
827 t = self.file(f).read(m[f])
819 t = self.file(f).read(m[f])
828 self.wwrite(f, t)
820 self.wwrite(f, t)
829 util.set_exec(self.wjoin(f), mf[f])
821 util.set_exec(self.wjoin(f), m.execf(f))
830 self.dirstate.update([f], "n")
822 self.dirstate.update([f], "n")
831
823
832 def copy(self, source, dest, wlock=None):
824 def copy(self, source, dest, wlock=None):
@@ -1,6 +1,6 b''
1 # lock.py - simple locking scheme for mercurial
1 # lock.py - simple locking scheme for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # manifest.py - manifest revision class for mercurial
1 # manifest.py - manifest revision class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -10,6 +10,31 b' from i18n import gettext as _'
10 from demandload import *
10 from demandload import *
11 demandload(globals(), "array bisect struct")
11 demandload(globals(), "array bisect struct")
12
12
13 class manifestdict(dict):
14 def __init__(self, mapping=None, flags=None):
15 if mapping is None: mapping = {}
16 if flags is None: flags = {}
17 dict.__init__(self, mapping)
18 self._flags = flags
19 def flags(self, f):
20 return self._flags.get(f, "")
21 def execf(self, f):
22 "test for executable in manifest flags"
23 return "x" in self.flags(f)
24 def linkf(self, f):
25 "test for symlink in manifest flags"
26 return "l" in self.flags(f)
27 def rawset(self, f, entry):
28 self[f] = bin(entry[:40])
29 fl = entry[40:-1]
30 if fl: self._flags[f] = fl
31 def set(self, f, execf=False, linkf=False):
32 if linkf: self._flags[f] = "l"
33 elif execf: self._flags[f] = "x"
34 else: self._flags[f] = ""
35 def copy(self):
36 return manifestdict(dict.copy(self), dict.copy(self._flags))
37
13 class manifest(revlog):
38 class manifest(revlog):
14 def __init__(self, opener, defversion=REVLOGV0):
39 def __init__(self, opener, defversion=REVLOGV0):
15 self.mapcache = None
40 self.mapcache = None
@@ -18,26 +43,18 b' class manifest(revlog):'
18 defversion)
43 defversion)
19
44
20 def read(self, node):
45 def read(self, node):
21 if node == nullid: return {} # don't upset local cache
46 if node == nullid: return manifestdict() # don't upset local cache
22 if self.mapcache and self.mapcache[0] == node:
47 if self.mapcache and self.mapcache[0] == node:
23 return self.mapcache[1]
48 return self.mapcache[1]
24 text = self.revision(node)
49 text = self.revision(node)
25 map = {}
26 flag = {}
27 self.listcache = array.array('c', text)
50 self.listcache = array.array('c', text)
28 lines = text.splitlines(1)
51 lines = text.splitlines(1)
52 mapping = manifestdict()
29 for l in lines:
53 for l in lines:
30 (f, n) = l.split('\0')
54 (f, n) = l.split('\0')
31 map[f] = bin(n[:40])
55 mapping.rawset(f, n)
32 flag[f] = (n[40:-1] == "x")
56 self.mapcache = (node, mapping)
33 self.mapcache = (node, map, flag)
57 return mapping
34 return map
35
36 def readflags(self, node):
37 if node == nullid: return {} # don't upset local cache
38 if not self.mapcache or self.mapcache[0] != node:
39 self.read(node)
40 return self.mapcache[2]
41
58
42 def diff(self, a, b):
59 def diff(self, a, b):
43 return mdiff.textdiff(str(a), str(b))
60 return mdiff.textdiff(str(a), str(b))
@@ -86,7 +103,7 b' class manifest(revlog):'
86 '''look up entry for a single file efficiently.
103 '''look up entry for a single file efficiently.
87 return (node, flag) pair if found, (None, None) if not.'''
104 return (node, flag) pair if found, (None, None) if not.'''
88 if self.mapcache and node == self.mapcache[0]:
105 if self.mapcache and node == self.mapcache[0]:
89 return self.mapcache[1].get(f), self.mapcache[2].get(f)
106 return self.mapcache[1].get(f), self.mapcache[1].flags(f)
90 text = self.revision(node)
107 text = self.revision(node)
91 start, end = self._search(text, f)
108 start, end = self._search(text, f)
92 if start == end:
109 if start == end:
@@ -95,7 +112,7 b' class manifest(revlog):'
95 f, n = l.split('\0')
112 f, n = l.split('\0')
96 return bin(n[:40]), n[40:-1] == 'x'
113 return bin(n[:40]), n[40:-1] == 'x'
97
114
98 def add(self, map, flags, transaction, link, p1=None, p2=None,
115 def add(self, map, transaction, link, p1=None, p2=None,
99 changed=None):
116 changed=None):
100 # apply the changes collected during the bisect loop to our addlist
117 # apply the changes collected during the bisect loop to our addlist
101 # return a delta suitable for addrevision
118 # return a delta suitable for addrevision
@@ -123,9 +140,7 b' class manifest(revlog):'
123
140
124 # if this is changed to support newlines in filenames,
141 # if this is changed to support newlines in filenames,
125 # be sure to check the templates/ dir again (especially *-raw.tmpl)
142 # be sure to check the templates/ dir again (especially *-raw.tmpl)
126 text = ["%s\000%s%s\n" %
143 text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f)) for f in files]
127 (f, hex(map[f]), flags[f] and "x" or '')
128 for f in files]
129 self.listcache = array.array('c', "".join(text))
144 self.listcache = array.array('c', "".join(text))
130 cachedelta = None
145 cachedelta = None
131 else:
146 else:
@@ -151,8 +166,7 b' class manifest(revlog):'
151 # bs will either be the index of the item or the insert point
166 # bs will either be the index of the item or the insert point
152 start, end = self._search(addbuf, f, start)
167 start, end = self._search(addbuf, f, start)
153 if w[1] == 0:
168 if w[1] == 0:
154 l = "%s\000%s%s\n" % (f, hex(map[f]),
169 l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f))
155 flags[f] and "x" or '')
156 else:
170 else:
157 l = ""
171 l = ""
158 if start == end and w[1] == 1:
172 if start == end and w[1] == 1:
@@ -183,6 +197,6 b' class manifest(revlog):'
183
197
184 n = self.addrevision(buffer(self.listcache), transaction, link, p1, \
198 n = self.addrevision(buffer(self.listcache), transaction, link, p1, \
185 p2, cachedelta)
199 p2, cachedelta)
186 self.mapcache = (n, map, flags)
200 self.mapcache = (n, map)
187
201
188 return n
202 return n
@@ -1,6 +1,6 b''
1 # mdiff.py - diff and patch routines for mercurial
1 # mdiff.py - diff and patch routines for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -84,11 +84,8 b' def update(repo, node, branchmerge=False'
84 m2n = repo.changelog.read(p2)[0]
84 m2n = repo.changelog.read(p2)[0]
85 man = repo.manifest.ancestor(m1n, m2n)
85 man = repo.manifest.ancestor(m1n, m2n)
86 m1 = repo.manifest.read(m1n)
86 m1 = repo.manifest.read(m1n)
87 mf1 = repo.manifest.readflags(m1n)
88 m2 = repo.manifest.read(m2n).copy()
87 m2 = repo.manifest.read(m2n).copy()
89 mf2 = repo.manifest.readflags(m2n)
90 ma = repo.manifest.read(man)
88 ma = repo.manifest.read(man)
91 mfa = repo.manifest.readflags(man)
92
89
93 if not forcemerge and not overwrite:
90 if not forcemerge and not overwrite:
94 for f in unknown:
91 for f in unknown:
@@ -113,12 +110,11 b' def update(repo, node, branchmerge=False'
113
110
114 # construct a working dir manifest
111 # construct a working dir manifest
115 mw = m1.copy()
112 mw = m1.copy()
116 mfw = mf1.copy()
117 umap = dict.fromkeys(unknown)
113 umap = dict.fromkeys(unknown)
118
114
119 for f in added + modified + unknown:
115 for f in added + modified + unknown:
120 mw[f] = ""
116 mw[f] = ""
121 mfw[f] = util.is_exec(repo.wjoin(f), mfw.get(f, False))
117 mw.set(f, util.is_exec(repo.wjoin(f), mw.execf(f)))
122
118
123 for f in deleted + removed:
119 for f in deleted + removed:
124 if f in mw:
120 if f in mw:
@@ -155,28 +151,28 b' def update(repo, node, branchmerge=False'
155 repo.ui.debug(_(" %s versions differ, resolve\n") % f)
151 repo.ui.debug(_(" %s versions differ, resolve\n") % f)
156 # merge executable bits
152 # merge executable bits
157 # "if we changed or they changed, change in merge"
153 # "if we changed or they changed, change in merge"
158 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
154 a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
159 mode = ((a^b) | (a^c)) ^ a
155 mode = ((a^b) | (a^c)) ^ a
160 merge[f] = (m1.get(f, nullid), m2[f], mode)
156 merge[f] = (mode, m1.get(f, nullid), m2[f])
161 s = 1
157 s = 1
162 # are we clobbering?
158 # are we clobbering?
163 # is remote's version newer?
159 # is remote's version newer?
164 # or are we going back in time?
160 # or are we going back in time?
165 elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
161 elif overwrite or m2[f] != a or (p2 == pa and mw[f] == m1[f]):
166 repo.ui.debug(_(" remote %s is newer, get\n") % f)
162 repo.ui.debug(_(" remote %s is newer, get\n") % f)
167 get[f] = m2[f]
163 get[f] = (m2.execf(f), m2[f])
168 s = 1
164 s = 1
169 elif f in umap or f in added:
165 elif f in umap or f in added:
170 # this unknown file is the same as the checkout
166 # this unknown file is the same as the checkout
171 # we need to reset the dirstate if the file was added
167 # we need to reset the dirstate if the file was added
172 get[f] = m2[f]
168 get[f] = (m2.execf(f), m2[f])
173
169
174 if not s and mfw[f] != mf2[f]:
170 if not s and mw.execf(f) != m2.execf(f):
175 if overwrite:
171 if overwrite:
176 repo.ui.debug(_(" updating permissions for %s\n") % f)
172 repo.ui.debug(_(" updating permissions for %s\n") % f)
177 util.set_exec(repo.wjoin(f), mf2[f])
173 util.set_exec(repo.wjoin(f), m2.execf(f))
178 else:
174 else:
179 a, b, c = mfa.get(f, 0), mfw[f], mf2[f]
175 a, b, c = ma.execf(f), mw.execf(f), m2.execf(f)
180 mode = ((a^b) | (a^c)) ^ a
176 mode = ((a^b) | (a^c)) ^ a
181 if mode != b:
177 if mode != b:
182 repo.ui.debug(_(" updating permissions for %s\n")
178 repo.ui.debug(_(" updating permissions for %s\n")
@@ -221,14 +217,14 b' def update(repo, node, branchmerge=False'
221 (_("remote changed %s which local deleted\n") % f) +
217 (_("remote changed %s which local deleted\n") % f) +
222 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
218 _("(k)eep or (d)elete?"), _("[kd]"), _("k"))
223 if r == _("k"):
219 if r == _("k"):
224 get[f] = n
220 get[f] = (m2.execf(f), n)
225 elif f not in ma:
221 elif f not in ma:
226 repo.ui.debug(_("remote created %s\n") % f)
222 repo.ui.debug(_("remote created %s\n") % f)
227 get[f] = n
223 get[f] = (m2.execf(f), n)
228 else:
224 else:
229 if overwrite or p2 == pa: # going backwards?
225 if overwrite or p2 == pa: # going backwards?
230 repo.ui.debug(_("local deleted %s, recreating\n") % f)
226 repo.ui.debug(_("local deleted %s, recreating\n") % f)
231 get[f] = n
227 get[f] = (m2.execf(f), n)
232 else:
228 else:
233 repo.ui.debug(_("local deleted %s\n") % f)
229 repo.ui.debug(_("local deleted %s\n") % f)
234
230
@@ -236,7 +232,7 b' def update(repo, node, branchmerge=False'
236
232
237 if overwrite:
233 if overwrite:
238 for f in merge:
234 for f in merge:
239 get[f] = merge[f][1]
235 get[f] = merge[f][:2]
240 merge = {}
236 merge = {}
241
237
242 if linear_path or overwrite:
238 if linear_path or overwrite:
@@ -254,12 +250,13 b' def update(repo, node, branchmerge=False'
254 files = get.keys()
250 files = get.keys()
255 files.sort()
251 files.sort()
256 for f in files:
252 for f in files:
253 flag, node = get[f]
257 if f[0] == "/":
254 if f[0] == "/":
258 continue
255 continue
259 repo.ui.note(_("getting %s\n") % f)
256 repo.ui.note(_("getting %s\n") % f)
260 t = repo.file(f).read(get[f])
257 t = repo.file(f).read(node)
261 repo.wwrite(f, t)
258 repo.wwrite(f, t)
262 util.set_exec(repo.wjoin(f), mf2[f])
259 util.set_exec(repo.wjoin(f), flag)
263 if not partial:
260 if not partial:
264 if branchmerge:
261 if branchmerge:
265 repo.dirstate.update([f], 'n', st_mtime=-1)
262 repo.dirstate.update([f], 'n', st_mtime=-1)
@@ -272,7 +269,7 b' def update(repo, node, branchmerge=False'
272 files.sort()
269 files.sort()
273 for f in files:
270 for f in files:
274 repo.ui.status(_("merging %s\n") % f)
271 repo.ui.status(_("merging %s\n") % f)
275 my, other, flag = merge[f]
272 flag, my, other = merge[f]
276 ret = merge3(repo, f, my, other, xp1, xp2)
273 ret = merge3(repo, f, my, other, xp1, xp2)
277 if ret:
274 if ret:
278 unresolved.append(f)
275 unresolved.append(f)
@@ -14,7 +14,7 b''
14 allocation of intermediate Python objects. Working memory is about 2x
14 allocation of intermediate Python objects. Working memory is about 2x
15 the total number of hunks.
15 the total number of hunks.
16
16
17 Copyright 2005 Matt Mackall <mpm@selenic.com>
17 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
18
18
19 This software may be used and distributed according to the terms
19 This software may be used and distributed according to the terms
20 of the GNU General Public License, incorporated herein by reference.
20 of the GNU General Public License, incorporated herein by reference.
@@ -1,7 +1,7 b''
1 """
1 """
2 node.py - basic nodeid manipulation for mercurial
2 node.py - basic nodeid manipulation for mercurial
3
3
4 Copyright 2005 Matt Mackall <mpm@selenic.com>
4 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5
5
6 This software may be used and distributed according to the terms
6 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
7 of the GNU General Public License, incorporated herein by reference.
@@ -2,7 +2,7 b''
2 # Used for the py2exe distutil.
2 # Used for the py2exe distutil.
3 # This module must be the first mercurial module imported in setup.py
3 # This module must be the first mercurial module imported in setup.py
4 #
4 #
5 # Copyright 2005 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
5 # Copyright 2005, 2006 Volker Kleinfeld <Volker.Kleinfeld@gmx.de>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # remoterepo - remote repositort proxy classes for mercurial
1 # remoterepo - remote repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,7 b''
1 # repo.py - repository base classes for mercurial
1 # repo.py - repository base classes for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -4,7 +4,7 b' revlog.py - storage back-end for mercuri'
4 This provides efficient delta storage with O(1) retrieve and append
4 This provides efficient delta storage with O(1) retrieve and append
5 and O(changes) merge between branches
5 and O(changes) merge between branches
6
6
7 Copyright 2005 Matt Mackall <mpm@selenic.com>
7 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
8
8
9 This software may be used and distributed according to the terms
9 This software may be used and distributed according to the terms
10 of the GNU General Public License, incorporated herein by reference.
10 of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # sshrepo.py - ssh repository proxy class for mercurial
1 # sshrepo.py - ssh repository proxy class for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,7 b''
1 # sshserver.py - ssh protocol server support for mercurial
1 # sshserver.py - ssh protocol server support for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 #
5 #
5 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
@@ -2,7 +2,7 b''
2 #
2 #
3 # This provides read-only repo access to repositories exported via static http
3 # This provides read-only repo access to repositories exported via static http
4 #
4 #
5 # Copyright 2005 Matt Mackall <mpm@selenic.com>
5 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
8 # of the GNU General Public License, incorporated herein by reference.
@@ -6,7 +6,7 b''
6 # effectively log-structured, this should amount to simply truncating
6 # effectively log-structured, this should amount to simply truncating
7 # anything that isn't referenced in the changelog.
7 # anything that isn't referenced in the changelog.
8 #
8 #
9 # Copyright 2005 Matt Mackall <mpm@selenic.com>
9 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
10 #
10 #
11 # This software may be used and distributed according to the terms
11 # This software may be used and distributed according to the terms
12 # of the GNU General Public License, incorporated herein by reference.
12 # of the GNU General Public License, incorporated herein by reference.
@@ -1,6 +1,6 b''
1 # ui.py - user interface bits for mercurial
1 # ui.py - user interface bits for mercurial
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
@@ -2,6 +2,8 b''
2 util.py - Mercurial utility functions and platform specfic implementations
2 util.py - Mercurial utility functions and platform specfic implementations
3
3
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
4 Copyright 2005 K. Thananchayan <thananck@yahoo.com>
5 Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
6 Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5
7
6 This software may be used and distributed according to the terms
8 This software may be used and distributed according to the terms
7 of the GNU General Public License, incorporated herein by reference.
9 of the GNU General Public License, incorporated herein by reference.
@@ -93,27 +95,6 b' def find_in_path(name, path, default=Non'
93 return p_name
95 return p_name
94 return default
96 return default
95
97
96 def patch(strip, patchname, ui, cwd=None):
97 """apply the patch <patchname> to the working directory.
98 a list of patched files is returned"""
99 patcher = find_in_path('gpatch', os.environ.get('PATH', ''), 'patch')
100 args = []
101 if cwd:
102 args.append('-d %s' % shellquote(cwd))
103 fp = os.popen('%s %s -p%d < %s' % (patcher, ' '.join(args), strip,
104 shellquote(patchname)))
105 files = {}
106 for line in fp:
107 line = line.rstrip()
108 ui.status("%s\n" % line)
109 if line.startswith('patching file '):
110 pf = parse_patch_output(line)
111 files.setdefault(pf, 1)
112 code = fp.close()
113 if code:
114 raise Abort(_("patch command failed: %s") % explain_exit(code)[0])
115 return files.keys()
116
117 def binary(s):
98 def binary(s):
118 """return true if a string is binary data using diff's heuristic"""
99 """return true if a string is binary data using diff's heuristic"""
119 if s and '\0' in s[:4096]:
100 if s and '\0' in s[:4096]:
@@ -1,4 +1,4 b''
1 # Copyright (C) 2005 by Intevation GmbH
1 # Copyright (C) 2005, 2006 by Intevation GmbH
2 # Author(s):
2 # Author(s):
3 # Thomas Arendsen Hein <thomas@intevation.de>
3 # Thomas Arendsen Hein <thomas@intevation.de>
4 #
4 #
General Comments 0
You need to be logged in to leave comments. Login now