##// END OF EJS Templates
Merge with crew
Bryan O'Sullivan -
r5676:9ed65758 merge default
parent child Browse files
Show More
@@ -0,0 +1,108 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "mq=" >> $HGRCPATH
5 echo "[diff]" >> $HGRCPATH
6 echo "nodates=true" >> $HGRCPATH
7
8
9 catlog() {
10 cat .hg/patches/$1.patch | sed -e "s/^diff \-r [0-9a-f]* /diff -r ... /"
11 hg log --template "{rev}: {desc} - {author}\n"
12 }
13
14
15 echo ==== init
16 hg init a
17 cd a
18 hg qinit
19
20
21 echo ==== qnew -U
22 hg qnew -U 1.patch
23 catlog 1
24
25 echo ==== qref
26 echo "1" >1
27 hg add
28 hg qref
29 catlog 1
30
31 echo ==== qref -u
32 hg qref -u mary
33 catlog 1
34
35 echo ==== qnew
36 hg qnew 2.patch
37 echo "2" >2
38 hg add
39 hg qref
40 catlog 2
41
42 echo ==== qref -u
43 hg qref -u jane
44 catlog 2
45
46
47 echo ==== qnew -U -m
48 hg qnew -U -m "Three" 3.patch
49 catlog 3
50
51 echo ==== qref
52 echo "3" >3
53 hg add
54 hg qref
55 catlog 3
56
57 echo ==== qref -m
58 hg qref -m "Drei"
59 catlog 3
60
61 echo ==== qref -u
62 hg qref -u mary
63 catlog 3
64
65 echo ==== qref -u -m
66 hg qref -u maria -m "Three (again)"
67 catlog 3
68
69 echo ==== qnew -m
70 hg qnew -m "Four" 4.patch
71 echo "4" >4
72 hg add
73 hg qref
74 catlog 4
75
76 echo ==== qref -u
77 hg qref -u jane
78 catlog 4
79
80
81 echo ==== qnew with HG header
82 hg qnew 5.patch
83 hg qpop
84 echo "# HG changeset patch" >>.hg/patches/5.patch
85 echo "# User johndoe" >>.hg/patches/5.patch
86 # Drop patch specific error line
87 hg qpush 2>&1 | grep -v garbage
88 catlog 5
89
90 echo ==== hg qref
91 echo "5" >5
92 hg add
93 hg qref
94 catlog 5
95
96 echo ==== hg qref -U
97 hg qref -U
98 catlog 5
99
100 echo ==== hg qref -u
101 hg qref -u johndeere
102 catlog 5
103
104
105 echo ==== "qpop -a / qpush -a"
106 hg qpop -a
107 hg qpush -a
108 hg log --template "{rev}: {desc} - {author}\n"
@@ -0,0 +1,200 b''
1 ==== init
2 ==== qnew -U
3 From: test
4
5 0: [mq]: 1.patch - test
6 ==== qref
7 adding 1
8 From: test
9
10 diff -r ... 1
11 --- /dev/null
12 +++ b/1
13 @@ -0,0 +1,1 @@
14 +1
15 0: [mq]: 1.patch - test
16 ==== qref -u
17 From: mary
18
19 diff -r ... 1
20 --- /dev/null
21 +++ b/1
22 @@ -0,0 +1,1 @@
23 +1
24 0: [mq]: 1.patch - mary
25 ==== qnew
26 adding 2
27 diff -r ... 2
28 --- /dev/null
29 +++ b/2
30 @@ -0,0 +1,1 @@
31 +2
32 1: [mq]: 2.patch - test
33 0: [mq]: 1.patch - mary
34 ==== qref -u
35 From: jane
36
37
38 diff -r ... 2
39 --- /dev/null
40 +++ b/2
41 @@ -0,0 +1,1 @@
42 +2
43 1: [mq]: 2.patch - jane
44 0: [mq]: 1.patch - mary
45 ==== qnew -U -m
46 From: test
47
48 Three
49 2: Three - test
50 1: [mq]: 2.patch - jane
51 0: [mq]: 1.patch - mary
52 ==== qref
53 adding 3
54 From: test
55
56 Three
57
58 diff -r ... 3
59 --- /dev/null
60 +++ b/3
61 @@ -0,0 +1,1 @@
62 +3
63 2: Three - test
64 1: [mq]: 2.patch - jane
65 0: [mq]: 1.patch - mary
66 ==== qref -m
67 From: test
68
69 Drei
70
71 diff -r ... 3
72 --- /dev/null
73 +++ b/3
74 @@ -0,0 +1,1 @@
75 +3
76 2: Drei - test
77 1: [mq]: 2.patch - jane
78 0: [mq]: 1.patch - mary
79 ==== qref -u
80 From: mary
81
82 Drei
83
84 diff -r ... 3
85 --- /dev/null
86 +++ b/3
87 @@ -0,0 +1,1 @@
88 +3
89 2: Drei - mary
90 1: [mq]: 2.patch - jane
91 0: [mq]: 1.patch - mary
92 ==== qref -u -m
93 From: maria
94
95 Three (again)
96
97 diff -r ... 3
98 --- /dev/null
99 +++ b/3
100 @@ -0,0 +1,1 @@
101 +3
102 2: Three (again) - maria
103 1: [mq]: 2.patch - jane
104 0: [mq]: 1.patch - mary
105 ==== qnew -m
106 adding 4
107 Four
108
109 diff -r ... 4
110 --- /dev/null
111 +++ b/4
112 @@ -0,0 +1,1 @@
113 +4
114 3: Four - test
115 2: Three (again) - maria
116 1: [mq]: 2.patch - jane
117 0: [mq]: 1.patch - mary
118 ==== qref -u
119 From: jane
120
121 Four
122
123 diff -r ... 4
124 --- /dev/null
125 +++ b/4
126 @@ -0,0 +1,1 @@
127 +4
128 3: Four - jane
129 2: Three (again) - maria
130 1: [mq]: 2.patch - jane
131 0: [mq]: 1.patch - mary
132 ==== qnew with HG header
133 Now at: 4.patch
134 applying 5.patch
135 patch failed, unable to continue (try -v)
136 patch 5.patch is empty
137 Now at: 5.patch
138 # HG changeset patch
139 # User johndoe
140 4: imported patch 5.patch - johndoe
141 3: Four - jane
142 2: Three (again) - maria
143 1: [mq]: 2.patch - jane
144 0: [mq]: 1.patch - mary
145 ==== hg qref
146 adding 5
147 # HG changeset patch
148 # User johndoe
149
150 diff -r ... 5
151 --- /dev/null
152 +++ b/5
153 @@ -0,0 +1,1 @@
154 +5
155 4: [mq]: 5.patch - johndoe
156 3: Four - jane
157 2: Three (again) - maria
158 1: [mq]: 2.patch - jane
159 0: [mq]: 1.patch - mary
160 ==== hg qref -U
161 # HG changeset patch
162 # User test
163
164 diff -r ... 5
165 --- /dev/null
166 +++ b/5
167 @@ -0,0 +1,1 @@
168 +5
169 4: [mq]: 5.patch - test
170 3: Four - jane
171 2: Three (again) - maria
172 1: [mq]: 2.patch - jane
173 0: [mq]: 1.patch - mary
174 ==== hg qref -u
175 # HG changeset patch
176 # User johndeere
177
178 diff -r ... 5
179 --- /dev/null
180 +++ b/5
181 @@ -0,0 +1,1 @@
182 +5
183 4: [mq]: 5.patch - johndeere
184 3: Four - jane
185 2: Three (again) - maria
186 1: [mq]: 2.patch - jane
187 0: [mq]: 1.patch - mary
188 ==== qpop -a / qpush -a
189 Patch queue now empty
190 applying 1.patch
191 applying 2.patch
192 applying 3.patch
193 applying 4.patch
194 applying 5.patch
195 Now at: 5.patch
196 4: imported patch 5.patch - johndeere
197 3: Four - jane
198 2: Three (again) - maria
199 1: imported patch 2.patch - jane
200 0: imported patch 1.patch - mary
@@ -281,7 +281,7 b' hooks::'
281 commit to proceed. Non-zero status will cause the commit to fail.
281 commit to proceed. Non-zero status will cause the commit to fail.
282 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
282 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
283 preoutgoing;;
283 preoutgoing;;
284 Run before computing changes to send from the local repository to
284 Run before collecting changes to send from the local repository to
285 another. Non-zero status will cause failure. This lets you
285 another. Non-zero status will cause failure. This lets you
286 prevent pull over http or ssh. Also prevents against local pull,
286 prevent pull over http or ssh. Also prevents against local pull,
287 push (outbound) or bundle commands, but not effective, since you
287 push (outbound) or bundle commands, but not effective, since you
@@ -603,6 +603,7 b' class queue:'
603 def new(self, repo, patch, *pats, **opts):
603 def new(self, repo, patch, *pats, **opts):
604 msg = opts.get('msg')
604 msg = opts.get('msg')
605 force = opts.get('force')
605 force = opts.get('force')
606 user = opts.get('user')
606 if os.path.exists(self.join(patch)):
607 if os.path.exists(self.join(patch)):
607 raise util.Abort(_('patch "%s" already exists') % patch)
608 raise util.Abort(_('patch "%s" already exists') % patch)
608 if opts.get('include') or opts.get('exclude') or pats:
609 if opts.get('include') or opts.get('exclude') or pats:
@@ -617,7 +618,7 b' class queue:'
617 try:
618 try:
618 insert = self.full_series_end()
619 insert = self.full_series_end()
619 commitmsg = msg and msg or ("[mq]: %s" % patch)
620 commitmsg = msg and msg or ("[mq]: %s" % patch)
620 n = repo.commit(commitfiles, commitmsg, match=match, force=True)
621 n = repo.commit(commitfiles, commitmsg, user, match=match, force=True)
621 if n == None:
622 if n == None:
622 raise util.Abort(_("repo commit failed"))
623 raise util.Abort(_("repo commit failed"))
623 self.full_series[insert:insert] = [patch]
624 self.full_series[insert:insert] = [patch]
@@ -626,6 +627,8 b' class queue:'
626 self.series_dirty = 1
627 self.series_dirty = 1
627 self.applied_dirty = 1
628 self.applied_dirty = 1
628 p = self.opener(patch, "w")
629 p = self.opener(patch, "w")
630 if user:
631 p.write("From: " + user + "\n\n")
629 if msg:
632 if msg:
630 msg = msg + "\n"
633 msg = msg + "\n"
631 p.write(msg)
634 p.write(msg)
@@ -945,6 +948,22 b' class queue:'
945 while message[mi] != comments[ci]:
948 while message[mi] != comments[ci]:
946 ci += 1
949 ci += 1
947 del comments[ci]
950 del comments[ci]
951
952 newuser = opts.get('user')
953 if newuser:
954 # Update all references to a user in the patch header.
955 # If none found, add "From: " header.
956 needfrom = True
957 for prefix in ['# User ', 'From: ']:
958 for i in xrange(len(comments)):
959 if comments[i].startswith(prefix):
960 comments[i] = prefix + newuser
961 needfrom = False
962 break
963 if needfrom:
964 comments = ['From: ' + newuser, ''] + comments
965 user = newuser
966
948 if msg:
967 if msg:
949 comments.append(msg)
968 comments.append(msg)
950
969
@@ -1070,9 +1089,12 b' class queue:'
1070 else:
1089 else:
1071 message = msg
1090 message = msg
1072
1091
1092 if not user:
1093 user = changes[1]
1094
1073 self.strip(repo, top, update=False,
1095 self.strip(repo, top, update=False,
1074 backup='strip')
1096 backup='strip')
1075 n = repo.commit(filelist, message, changes[1], match=matchfn,
1097 n = repo.commit(filelist, message, user, match=matchfn,
1076 force=1)
1098 force=1)
1077 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1099 self.applied[-1] = statusentry(revlog.hex(n), patchfn)
1078 self.applied_dirty = 1
1100 self.applied_dirty = 1
@@ -1605,6 +1627,12 b' def prev(ui, repo, **opts):'
1605 return q.qseries(repo, start=l-2, length=1, status='A',
1627 return q.qseries(repo, start=l-2, length=1, status='A',
1606 summary=opts.get('summary'))
1628 summary=opts.get('summary'))
1607
1629
1630 def setupheaderopts(ui, opts):
1631 def do(opt,val):
1632 if not opts[opt] and opts['current' + opt]:
1633 opts[opt] = val
1634 do('user', ui.username())
1635
1608 def new(ui, repo, patch, *args, **opts):
1636 def new(ui, repo, patch, *args, **opts):
1609 """create a new patch
1637 """create a new patch
1610
1638
@@ -1623,6 +1651,7 b' def new(ui, repo, patch, *args, **opts):'
1623 if opts['edit']:
1651 if opts['edit']:
1624 message = ui.edit(message, ui.username())
1652 message = ui.edit(message, ui.username())
1625 opts['msg'] = message
1653 opts['msg'] = message
1654 setupheaderopts(ui, opts)
1626 q.new(repo, patch, *args, **opts)
1655 q.new(repo, patch, *args, **opts)
1627 q.save_dirty()
1656 q.save_dirty()
1628 return 0
1657 return 0
@@ -1648,6 +1677,7 b' def refresh(ui, repo, *pats, **opts):'
1648 patch = q.applied[-1].name
1677 patch = q.applied[-1].name
1649 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1678 (message, comment, user, date, hasdiff) = q.readheaders(patch)
1650 message = ui.edit('\n'.join(message), user or ui.username())
1679 message = ui.edit('\n'.join(message), user or ui.username())
1680 setupheaderopts(ui, opts)
1651 ret = q.refresh(repo, pats, msg=message, **opts)
1681 ret = q.refresh(repo, pats, msg=message, **opts)
1652 q.save_dirty()
1682 q.save_dirty()
1653 return ret
1683 return ret
@@ -2138,6 +2168,10 b' def reposetup(ui, repo):'
2138
2168
2139 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2169 seriesopts = [('s', 'summary', None, _('print first line of patch header'))]
2140
2170
2171 headeropts = [
2172 ('U', 'currentuser', None, _('add "From: <current user>" to patch')),
2173 ('u', 'user', '', _('add "From: <given user>" to patch'))]
2174
2141 cmdtable = {
2175 cmdtable = {
2142 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2176 "qapplied": (applied, [] + seriesopts, _('hg qapplied [-s] [PATCH]')),
2143 "qclone":
2177 "qclone":
@@ -2196,7 +2230,7 b' cmdtable = {'
2196 [('e', 'edit', None, _('edit commit message')),
2230 [('e', 'edit', None, _('edit commit message')),
2197 ('f', 'force', None, _('import uncommitted changes into patch')),
2231 ('f', 'force', None, _('import uncommitted changes into patch')),
2198 ('g', 'git', None, _('use git extended diff format')),
2232 ('g', 'git', None, _('use git extended diff format')),
2199 ] + commands.walkopts + commands.commitopts,
2233 ] + commands.walkopts + commands.commitopts + headeropts,
2200 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2234 _('hg qnew [-e] [-m TEXT] [-l FILE] [-f] PATCH [FILE]...')),
2201 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2235 "qnext": (next, [] + seriesopts, _('hg qnext [-s]')),
2202 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
2236 "qprev": (prev, [] + seriesopts, _('hg qprev [-s]')),
@@ -2219,7 +2253,7 b' cmdtable = {'
2219 [('e', 'edit', None, _('edit commit message')),
2253 [('e', 'edit', None, _('edit commit message')),
2220 ('g', 'git', None, _('use git extended diff format')),
2254 ('g', 'git', None, _('use git extended diff format')),
2221 ('s', 'short', None, _('refresh only files already in the patch')),
2255 ('s', 'short', None, _('refresh only files already in the patch')),
2222 ] + commands.walkopts + commands.commitopts,
2256 ] + commands.walkopts + commands.commitopts + headeropts,
2223 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2257 _('hg qrefresh [-I] [-X] [-e] [-m TEXT] [-l FILE] [-s] [FILE]...')),
2224 'qrename|qmv':
2258 'qrename|qmv':
2225 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
2259 (rename, [], _('hg qrename PATCH1 [PATCH2]')),
@@ -2029,6 +2029,7 b' def remove(ui, repo, *pats, **opts):'
2029 forget.append(abs)
2029 forget.append(abs)
2030 continue
2030 continue
2031 reason = _('has been marked for add (use -f to force removal)')
2031 reason = _('has been marked for add (use -f to force removal)')
2032 exact = 1 # force the message
2032 elif abs not in repo.dirstate:
2033 elif abs not in repo.dirstate:
2033 reason = _('is not managed')
2034 reason = _('is not managed')
2034 elif opts['after'] and not exact and abs not in deleted:
2035 elif opts['after'] and not exact and abs not in deleted:
@@ -67,7 +67,7 b' class _demandmod(object):'
67 return "<proxied module '%s'>" % self._data[0]
67 return "<proxied module '%s'>" % self._data[0]
68 return "<unloaded module '%s'>" % self._data[0]
68 return "<unloaded module '%s'>" % self._data[0]
69 def __call__(self, *args, **kwargs):
69 def __call__(self, *args, **kwargs):
70 raise TypeError("'unloaded module' object is not callable")
70 raise TypeError("%s object is not callable" % repr(self))
71 def __getattribute__(self, attr):
71 def __getattribute__(self, attr):
72 if attr in ('_data', '_extend', '_load', '_module'):
72 if attr in ('_data', '_extend', '_load', '_module'):
73 return object.__getattribute__(self, attr)
73 return object.__getattribute__(self, attr)
@@ -133,6 +133,8 b' def _runcatch(ui, args):'
133
133
134 except util.Abort, inst:
134 except util.Abort, inst:
135 ui.warn(_("abort: %s\n") % inst)
135 ui.warn(_("abort: %s\n") % inst)
136 except MemoryError:
137 ui.warn(_("abort: out of memory\n"))
136 except SystemExit, inst:
138 except SystemExit, inst:
137 # Commands shouldn't sys.exit directly, but give a return code.
139 # Commands shouldn't sys.exit directly, but give a return code.
138 # Just in case catch this and and pass exit code to caller.
140 # Just in case catch this and and pass exit code to caller.
@@ -1,35 +1,74 b''
1 import getopt
1 import getopt
2
2
3 def fancyopts(args, options, state):
3 def fancyopts(args, options, state):
4 long = []
4 """
5 short = ''
5 read args, parse options, and store options in state
6 map = {}
6
7 dt = {}
7 each option is a tuple of:
8
9 short option or ''
10 long option
11 default value
12 description
13
14 option types include:
15
16 boolean or none - option sets variable in state to true
17 string - parameter string is stored in state
18 list - parameter string is added to a list
19 integer - parameter strings is stored as int
20 function - call function with parameter
8
21
9 for s, l, d, c in options:
22 non-option args are returned
10 pl = l.replace('-', '_')
23 """
11 map['-'+s] = map['--'+l] = pl
24 namelist = []
12 if isinstance(d, list):
25 shortlist = ''
13 state[pl] = d[:]
26 argmap = {}
27 defmap = {}
28
29 for short, name, default, comment in options:
30 # convert opts to getopt format
31 oname = name
32 name = name.replace('-', '_')
33
34 argmap['-' + short] = argmap['--' + oname] = name
35 defmap[name] = default
36
37 # copy defaults to state
38 if isinstance(default, list):
39 state[name] = default[:]
40 elif callable(default):
41 print "whoa", name, default
42 state[name] = None
14 else:
43 else:
15 state[pl] = d
44 state[name] = default
16 dt[pl] = type(d)
17 if (d is not None and d is not True and d is not False and
18 not callable(d)):
19 if s: s += ':'
20 if l: l += '='
21 if s: short = short + s
22 if l: long.append(l)
23
45
24 opts, args = getopt.getopt(args, short, long)
46 # does it take a parameter?
47 if not (default is None or default is True or default is False):
48 if short: short += ':'
49 if oname: oname += '='
50 if short:
51 shortlist += short
52 if name:
53 namelist.append(oname)
54
55 # parse arguments
56 opts, args = getopt.getopt(args, shortlist, namelist)
25
57
26 for opt, arg in opts:
58 # transfer result to state
27 if dt[map[opt]] is type(fancyopts): state[map[opt]](state, map[opt], arg)
59 for opt, val in opts:
28 elif dt[map[opt]] is type(1): state[map[opt]] = int(arg)
60 name = argmap[opt]
29 elif dt[map[opt]] is type(''): state[map[opt]] = arg
61 t = type(defmap[name])
30 elif dt[map[opt]] is type([]): state[map[opt]].append(arg)
62 if t is type(fancyopts):
31 elif dt[map[opt]] is type(None): state[map[opt]] = True
63 state[name] = defmap[name](val)
32 elif dt[map[opt]] is type(False): state[map[opt]] = True
64 elif t is type(1):
65 state[name] = int(val)
66 elif t is type(''):
67 state[name] = val
68 elif t is type([]):
69 state[name].append(val)
70 elif t is type(None) or t is type(False):
71 state[name] = True
33
72
73 # return unparsed args
34 return args
74 return args
35
@@ -280,13 +280,13 b' def update(repo, node):'
280 # len(pl)==1, otherwise _merge.update() would have raised util.Abort:
280 # len(pl)==1, otherwise _merge.update() would have raised util.Abort:
281 repo.ui.status(_(" hg update %s\n hg update %s\n")
281 repo.ui.status(_(" hg update %s\n hg update %s\n")
282 % (pl[0].rev(), repo.changectx(node).rev()))
282 % (pl[0].rev(), repo.changectx(node).rev()))
283 return stats[3]
283 return stats[3] > 0
284
284
285 def clean(repo, node, show_stats=True):
285 def clean(repo, node, show_stats=True):
286 """forcibly switch the working directory to node, clobbering changes"""
286 """forcibly switch the working directory to node, clobbering changes"""
287 stats = _merge.update(repo, node, False, True, None)
287 stats = _merge.update(repo, node, False, True, None)
288 if show_stats: _showstats(repo, stats)
288 if show_stats: _showstats(repo, stats)
289 return stats[3]
289 return stats[3] > 0
290
290
291 def merge(repo, node, force=None, remind=True):
291 def merge(repo, node, force=None, remind=True):
292 """branch merge with node, resolving changes"""
292 """branch merge with node, resolving changes"""
@@ -301,11 +301,11 b' def merge(repo, node, force=None, remind'
301 % (pl[0].rev(), pl[1].rev()))
301 % (pl[0].rev(), pl[1].rev()))
302 elif remind:
302 elif remind:
303 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
303 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
304 return stats[3]
304 return stats[3] > 0
305
305
306 def revert(repo, node, choose):
306 def revert(repo, node, choose):
307 """revert changes to revision in node without updating dirstate"""
307 """revert changes to revision in node without updating dirstate"""
308 return _merge.update(repo, node, False, True, choose)[3]
308 return _merge.update(repo, node, False, True, choose)[3] > 0
309
309
310 def verify(repo):
310 def verify(repo):
311 """verify the consistency of a repository"""
311 """verify the consistency of a repository"""
@@ -6,18 +6,21 b''
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 from i18n import _
8 from i18n import _
9 import util
9 import util, re
10
11 _commentre = None
10
12
11 def _parselines(fp):
13 def _parselines(fp):
12 for line in fp:
14 for line in fp:
13 if not line.endswith('\n'):
15 if "#" in line:
14 line += '\n'
16 global _commentre
15 escape = False
17 if not _commentre:
16 for i in xrange(len(line)):
18 _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
17 if escape: escape = False
19 # remove comments prefixed by an even number of escapes
18 elif line[i] == '\\': escape = True
20 line = _commentre.sub(r'\1', line)
19 elif line[i] == '#': break
21 # fixup properly escaped comments that survived the above
20 line = line[:i].rstrip()
22 line = line.replace("\\#", "#")
23 line = line.rstrip()
21 if line:
24 if line:
22 yield line
25 yield line
23
26
@@ -661,6 +661,7 b' class localrepository(repo.repository):'
661 match=util.always, force=False, force_editor=False,
661 match=util.always, force=False, force_editor=False,
662 p1=None, p2=None, extra={}, empty_ok=False):
662 p1=None, p2=None, extra={}, empty_ok=False):
663 wlock = lock = tr = None
663 wlock = lock = tr = None
664 valid = 0 # don't save the dirstate if this isn't set
664 try:
665 try:
665 commit = []
666 commit = []
666 remove = []
667 remove = []
@@ -747,6 +748,9 b' class localrepository(repo.repository):'
747 if old_exec != new_exec or old_link != new_link:
748 if old_exec != new_exec or old_link != new_link:
748 changed.append(f)
749 changed.append(f)
749 m1.set(f, new_exec, new_link)
750 m1.set(f, new_exec, new_link)
751 if use_dirstate:
752 self.dirstate.normal(f)
753
750 except (OSError, IOError):
754 except (OSError, IOError):
751 if use_dirstate:
755 if use_dirstate:
752 self.ui.warn(_("trouble committing %s!\n") % f)
756 self.ui.warn(_("trouble committing %s!\n") % f)
@@ -817,14 +821,15 b' class localrepository(repo.repository):'
817 if use_dirstate or update_dirstate:
821 if use_dirstate or update_dirstate:
818 self.dirstate.setparents(n)
822 self.dirstate.setparents(n)
819 if use_dirstate:
823 if use_dirstate:
820 for f in new:
821 self.dirstate.normal(f)
822 for f in removed:
824 for f in removed:
823 self.dirstate.forget(f)
825 self.dirstate.forget(f)
826 valid = 1 # our dirstate updates are complete
824
827
825 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
828 self.hook("commit", node=hex(n), parent1=xp1, parent2=xp2)
826 return n
829 return n
827 finally:
830 finally:
831 if not valid: # don't save our updated dirstate
832 self.dirstate.invalidate()
828 del tr, lock, wlock
833 del tr, lock, wlock
829
834
830 def walk(self, node=None, files=[], match=util.always, badmatch=None):
835 def walk(self, node=None, files=[], match=util.always, badmatch=None):
@@ -302,24 +302,26 b" unidesc = re.compile('@@ -(\\d+)(,(\\d+))?"
302 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
302 contextdesc = re.compile('(---|\*\*\*) (\d+)(,(\d+))? (---|\*\*\*)')
303
303
304 class patchfile:
304 class patchfile:
305 def __init__(self, ui, fname):
305 def __init__(self, ui, fname, missing=False):
306 self.fname = fname
306 self.fname = fname
307 self.ui = ui
307 self.ui = ui
308 try:
308 self.lines = []
309 fp = file(fname, 'rb')
309 self.exists = False
310 self.lines = fp.readlines()
310 self.missing = missing
311 self.exists = True
311 if not missing:
312 except IOError:
312 try:
313 fp = file(fname, 'rb')
314 self.lines = fp.readlines()
315 self.exists = True
316 except IOError:
317 pass
318 else:
319 self.ui.warn(_("unable to find '%s' for patching\n") % self.fname)
320
321 if not self.exists:
313 dirname = os.path.dirname(fname)
322 dirname = os.path.dirname(fname)
314 if dirname and not os.path.isdir(dirname):
323 if dirname and not os.path.isdir(dirname):
315 dirs = dirname.split(os.path.sep)
324 os.makedirs(dirname)
316 d = ""
317 for x in dirs:
318 d = os.path.join(d, x)
319 if not os.path.isdir(d):
320 os.mkdir(d)
321 self.lines = []
322 self.exists = False
323
325
324 self.hash = {}
326 self.hash = {}
325 self.dirty = 0
327 self.dirty = 0
@@ -427,6 +429,10 b' class patchfile:'
427 if reverse:
429 if reverse:
428 h.reverse()
430 h.reverse()
429
431
432 if self.missing:
433 self.rej.append(h)
434 return -1
435
430 if self.exists and h.createfile():
436 if self.exists and h.createfile():
431 self.ui.warn(_("file %s already exists\n") % self.fname)
437 self.ui.warn(_("file %s already exists\n") % self.fname)
432 self.rej.append(h)
438 self.rej.append(h)
@@ -796,31 +802,32 b' def selectfile(afile_orig, bfile_orig, h'
796 nulla = afile_orig == "/dev/null"
802 nulla = afile_orig == "/dev/null"
797 nullb = bfile_orig == "/dev/null"
803 nullb = bfile_orig == "/dev/null"
798 afile = pathstrip(afile_orig, strip)
804 afile = pathstrip(afile_orig, strip)
799 gooda = os.path.exists(afile) and not nulla
805 gooda = not nulla and os.path.exists(afile)
800 bfile = pathstrip(bfile_orig, strip)
806 bfile = pathstrip(bfile_orig, strip)
801 if afile == bfile:
807 if afile == bfile:
802 goodb = gooda
808 goodb = gooda
803 else:
809 else:
804 goodb = os.path.exists(bfile) and not nullb
810 goodb = not nullb and os.path.exists(bfile)
805 createfunc = hunk.createfile
811 createfunc = hunk.createfile
806 if reverse:
812 if reverse:
807 createfunc = hunk.rmfile
813 createfunc = hunk.rmfile
808 if not goodb and not gooda and not createfunc():
814 missing = not goodb and not gooda and not createfunc()
809 raise PatchError(_("unable to find %s or %s for patching") %
815 fname = None
810 (afile, bfile))
816 if not missing:
811 if gooda and goodb:
817 if gooda and goodb:
812 fname = bfile
818 fname = (afile in bfile) and afile or bfile
813 if afile in bfile:
819 elif gooda:
814 fname = afile
820 fname = afile
815 elif gooda:
821
816 fname = afile
822 if not fname:
817 elif not nullb:
823 if not nullb:
818 fname = bfile
824 fname = (afile in bfile) and afile or bfile
819 if afile in bfile:
825 elif not nulla:
820 fname = afile
826 fname = afile
821 elif not nulla:
827 else:
822 fname = afile
828 raise PatchError(_("undefined source and destination files"))
823 return fname
829
830 return fname, missing
824
831
825 class linereader:
832 class linereader:
826 # simple class to allow pushing lines back into the input stream
833 # simple class to allow pushing lines back into the input stream
@@ -838,14 +845,16 b' class linereader:'
838 return l
845 return l
839 return self.fp.readline()
846 return self.fp.readline()
840
847
841 def applydiff(ui, fp, changed, strip=1, sourcefile=None, reverse=False,
848 def iterhunks(ui, fp, sourcefile=None):
842 rejmerge=None, updatedir=None):
849 """Read a patch and yield the following events:
843 """reads a patch from fp and tries to apply it. The dict 'changed' is
850 - ("file", afile, bfile, firsthunk): select a new target file.
844 filled in with all of the filenames changed by the patch. Returns 0
851 - ("hunk", hunk): a new hunk is ready to be applied, follows a
845 for a clean patch, -1 if any rejects were found and 1 if there was
852 "file" event.
846 any fuzz."""
853 - ("git", gitchanges): current diff is in git format, gitchanges
854 maps filenames to gitpatch records. Unique event.
855 """
847
856
848 def scangitpatch(fp, firstline, cwd=None):
857 def scangitpatch(fp, firstline):
849 '''git patches can modify a file, then copy that file to
858 '''git patches can modify a file, then copy that file to
850 a new file, but expect the source to be the unmodified form.
859 a new file, but expect the source to be the unmodified form.
851 So we scan the patch looking for that case so we can do
860 So we scan the patch looking for that case so we can do
@@ -858,46 +867,28 b' def applydiff(ui, fp, changed, strip=1, '
858 fp = cStringIO.StringIO(fp.read())
867 fp = cStringIO.StringIO(fp.read())
859
868
860 (dopatch, gitpatches) = readgitpatch(fp, firstline)
869 (dopatch, gitpatches) = readgitpatch(fp, firstline)
861 for gp in gitpatches:
862 if gp.op in ('COPY', 'RENAME'):
863 copyfile(gp.oldpath, gp.path, basedir=cwd)
864
865 fp.seek(pos)
870 fp.seek(pos)
866
871
867 return fp, dopatch, gitpatches
872 return fp, dopatch, gitpatches
868
873
874 changed = {}
869 current_hunk = None
875 current_hunk = None
870 current_file = None
871 afile = ""
876 afile = ""
872 bfile = ""
877 bfile = ""
873 state = None
878 state = None
874 hunknum = 0
879 hunknum = 0
875 rejects = 0
880 emitfile = False
876
881
877 git = False
882 git = False
878 gitre = re.compile('diff --git (a/.*) (b/.*)')
883 gitre = re.compile('diff --git (a/.*) (b/.*)')
879
884
880 # our states
885 # our states
881 BFILE = 1
886 BFILE = 1
882 err = 0
883 context = None
887 context = None
884 lr = linereader(fp)
888 lr = linereader(fp)
885 dopatch = True
889 dopatch = True
886 gitworkdone = False
890 gitworkdone = False
887
891
888 def getpatchfile(afile, bfile, hunk):
889 try:
890 if sourcefile:
891 targetfile = patchfile(ui, sourcefile)
892 else:
893 targetfile = selectfile(afile, bfile, hunk,
894 strip, reverse)
895 targetfile = patchfile(ui, targetfile)
896 return targetfile
897 except PatchError, err:
898 ui.warn(str(err) + '\n')
899 return None
900
901 while True:
892 while True:
902 newfile = False
893 newfile = False
903 x = lr.readline()
894 x = lr.readline()
@@ -906,11 +897,7 b' def applydiff(ui, fp, changed, strip=1, '
906 if current_hunk:
897 if current_hunk:
907 if x.startswith('\ '):
898 if x.startswith('\ '):
908 current_hunk.fix_newline()
899 current_hunk.fix_newline()
909 ret = current_file.apply(current_hunk, reverse)
900 yield 'hunk', current_hunk
910 if ret >= 0:
911 changed.setdefault(current_file.fname, (None, None))
912 if ret > 0:
913 err = 1
914 current_hunk = None
901 current_hunk = None
915 gitworkdone = False
902 gitworkdone = False
916 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
903 if ((sourcefile or state == BFILE) and ((not context and x[0] == '@') or
@@ -924,21 +911,15 b' def applydiff(ui, fp, changed, strip=1, '
924 current_hunk = None
911 current_hunk = None
925 continue
912 continue
926 hunknum += 1
913 hunknum += 1
927 if not current_file:
914 if emitfile:
928 current_file = getpatchfile(afile, bfile, current_hunk)
915 emitfile = False
929 if not current_file:
916 yield 'file', (afile, bfile, current_hunk)
930 current_file, current_hunk = None, None
931 rejects += 1
932 continue
933 elif state == BFILE and x.startswith('GIT binary patch'):
917 elif state == BFILE and x.startswith('GIT binary patch'):
934 current_hunk = binhunk(changed[bfile[2:]][1])
918 current_hunk = binhunk(changed[bfile[2:]][1])
935 hunknum += 1
919 hunknum += 1
936 if not current_file:
920 if emitfile:
937 current_file = getpatchfile(afile, bfile, current_hunk)
921 emitfile = False
938 if not current_file:
922 yield 'file', (afile, bfile, current_hunk)
939 current_file, current_hunk = None, None
940 rejects += 1
941 continue
942 current_hunk.extract(fp)
923 current_hunk.extract(fp)
943 elif x.startswith('diff --git'):
924 elif x.startswith('diff --git'):
944 # check for git diff, scanning the whole patch file if needed
925 # check for git diff, scanning the whole patch file if needed
@@ -948,6 +929,7 b' def applydiff(ui, fp, changed, strip=1, '
948 if not git:
929 if not git:
949 git = True
930 git = True
950 fp, dopatch, gitpatches = scangitpatch(fp, x)
931 fp, dopatch, gitpatches = scangitpatch(fp, x)
932 yield 'git', gitpatches
951 for gp in gitpatches:
933 for gp in gitpatches:
952 changed[gp.path] = (gp.op, gp)
934 changed[gp.path] = (gp.op, gp)
953 # else error?
935 # else error?
@@ -984,36 +966,79 b' def applydiff(ui, fp, changed, strip=1, '
984 bfile = parsefilename(l2)
966 bfile = parsefilename(l2)
985
967
986 if newfile:
968 if newfile:
987 if current_file:
969 emitfile = True
988 current_file.close()
989 if rejmerge:
990 rejmerge(current_file)
991 rejects += len(current_file.rej)
992 state = BFILE
970 state = BFILE
993 current_file = None
994 hunknum = 0
971 hunknum = 0
995 if current_hunk:
972 if current_hunk:
996 if current_hunk.complete():
973 if current_hunk.complete():
974 yield 'hunk', current_hunk
975 else:
976 raise PatchError(_("malformed patch %s %s") % (afile,
977 current_hunk.desc))
978
979 if hunknum == 0 and dopatch and not gitworkdone:
980 raise NoHunks
981
982 def applydiff(ui, fp, changed, strip=1, sourcefile=None, reverse=False,
983 rejmerge=None, updatedir=None):
984 """reads a patch from fp and tries to apply it. The dict 'changed' is
985 filled in with all of the filenames changed by the patch. Returns 0
986 for a clean patch, -1 if any rejects were found and 1 if there was
987 any fuzz."""
988
989 rejects = 0
990 err = 0
991 current_file = None
992 gitpatches = None
993
994 def closefile():
995 if not current_file:
996 return 0
997 current_file.close()
998 if rejmerge:
999 rejmerge(current_file)
1000 return len(current_file.rej)
1001
1002 for state, values in iterhunks(ui, fp, sourcefile):
1003 if state == 'hunk':
1004 if not current_file:
1005 continue
1006 current_hunk = values
997 ret = current_file.apply(current_hunk, reverse)
1007 ret = current_file.apply(current_hunk, reverse)
998 if ret >= 0:
1008 if ret >= 0:
999 changed.setdefault(current_file.fname, (None, None))
1009 changed.setdefault(current_file.fname, (None, None))
1000 if ret > 0:
1010 if ret > 0:
1001 err = 1
1011 err = 1
1012 elif state == 'file':
1013 rejects += closefile()
1014 afile, bfile, first_hunk = values
1015 try:
1016 if sourcefile:
1017 current_file = patchfile(ui, sourcefile)
1018 else:
1019 current_file, missing = selectfile(afile, bfile, first_hunk,
1020 strip, reverse)
1021 current_file = patchfile(ui, current_file, missing)
1022 except PatchError, err:
1023 ui.warn(str(err) + '\n')
1024 current_file, current_hunk = None, None
1025 rejects += 1
1026 continue
1027 elif state == 'git':
1028 gitpatches = values
1029 for gp in gitpatches:
1030 if gp.op in ('COPY', 'RENAME'):
1031 copyfile(gp.oldpath, gp.path)
1032 changed[gp.path] = (gp.op, gp)
1002 else:
1033 else:
1003 fname = current_file and current_file.fname or None
1034 raise util.Abort(_('unsupported parser state: %s') % state)
1004 raise PatchError(_("malformed patch %s %s") % (fname,
1035
1005 current_hunk.desc))
1036 rejects += closefile()
1006 if current_file:
1037
1007 current_file.close()
1038 if updatedir and gitpatches:
1008 if rejmerge:
1009 rejmerge(current_file)
1010 rejects += len(current_file.rej)
1011 if updatedir and git:
1012 updatedir(gitpatches)
1039 updatedir(gitpatches)
1013 if rejects:
1040 if rejects:
1014 return -1
1041 return -1
1015 if hunknum == 0 and dopatch and not gitworkdone:
1016 raise NoHunks
1017 return err
1042 return err
1018
1043
1019 def diffopts(ui, opts={}, untrusted=False):
1044 def diffopts(ui, opts={}, untrusted=False):
@@ -919,7 +919,15 b" if os.name == 'nt':"
919
919
920 def write(self, s):
920 def write(self, s):
921 try:
921 try:
922 return self.fp.write(s)
922 # This is workaround for "Not enough space" error on
923 # writing large size of data to console.
924 limit = 16000
925 l = len(s)
926 start = 0
927 while start < l:
928 end = start + limit
929 self.fp.write(s[start:end])
930 start = end
923 except IOError, inst:
931 except IOError, inst:
924 if inst.errno != 0: raise
932 if inst.errno != 0: raise
925 self.close()
933 self.close()
@@ -41,6 +41,8 b' hg qpush'
41 echo % display added files
41 echo % display added files
42 cat a
42 cat a
43 cat c
43 cat c
44 echo % display rejections
45 cat b.rej
44 cd ..
46 cd ..
45
47
46
48
@@ -65,5 +67,7 b' hg st'
65 echo % display added files
67 echo % display added files
66 cat a
68 cat a
67 cat c
69 cat c
70 echo % display rejections
71 cat b.rej
68 cd ..
72 cd ..
69
73
@@ -2,24 +2,48 b' adding b'
2 Patch queue now empty
2 Patch queue now empty
3 % push patch with missing target
3 % push patch with missing target
4 applying changeb
4 applying changeb
5 unable to find b or b for patching
5 unable to find 'b' for patching
6 unable to find b or b for patching
6 2 out of 2 hunks FAILED -- saving rejects to file b.rej
7 patch failed, unable to continue (try -v)
7 patch failed, unable to continue (try -v)
8 patch failed, rejects left in working dir
8 patch failed, rejects left in working dir
9 Errors during apply, please fix and refresh changeb
9 Errors during apply, please fix and refresh changeb
10 % display added files
10 % display added files
11 a
11 a
12 c
12 c
13 % display rejections
14 --- b
15 +++ b
16 @@ -1,3 +1,5 @@ a
17 +b
18 +b
19 a
20 a
21 a
22 @@ -8,3 +10,5 @@ a
23 a
24 a
25 a
26 +c
27 +c
13 adding b
28 adding b
14 Patch queue now empty
29 Patch queue now empty
15 % push git patch with missing target
30 % push git patch with missing target
16 applying changeb
31 applying changeb
17 unable to find b or b for patching
32 unable to find 'b' for patching
33 1 out of 1 hunk FAILED -- saving rejects to file b.rej
18 patch failed, unable to continue (try -v)
34 patch failed, unable to continue (try -v)
19 b: No such file or directory
35 b: No such file or directory
20 b not tracked!
36 b not tracked!
21 patch failed, rejects left in working dir
37 patch failed, rejects left in working dir
22 Errors during apply, please fix and refresh changeb
38 Errors during apply, please fix and refresh changeb
39 ? b.rej
23 % display added files
40 % display added files
24 a
41 a
25 c
42 c
43 % display rejections
44 --- b
45 +++ b
46 GIT binary patch
47 literal 2
48 Jc${No0000400IC2
49
General Comments 0
You need to be logged in to leave comments. Login now