##// END OF EJS Templates
Merge with mpm
Brendan Cully -
r4712:f49fcbb3 merge default
parent child Browse files
Show More
@@ -0,0 +1,127 b''
1 # repair.py - functions for repository repair for mercurial
2 #
3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 # Copyright 2007 Matt Mackall
5 #
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
8
9 import changegroup, revlog, os, commands
10
11 def strip(ui, repo, rev, backup="all"):
12 def limitheads(chlog, stop):
13 """return the list of all nodes that have no children"""
14 p = {}
15 h = []
16 stoprev = 0
17 if stop in chlog.nodemap:
18 stoprev = chlog.rev(stop)
19
20 for r in xrange(chlog.count() - 1, -1, -1):
21 n = chlog.node(r)
22 if n not in p:
23 h.append(n)
24 if n == stop:
25 break
26 if r < stoprev:
27 break
28 for pn in chlog.parents(n):
29 p[pn] = 1
30 return h
31
32 def bundle(repo, bases, heads, rev, suffix):
33 cg = repo.changegroupsubset(bases, heads, 'strip')
34 backupdir = repo.join("strip-backup")
35 if not os.path.isdir(backupdir):
36 os.mkdir(backupdir)
37 name = os.path.join(backupdir, "%s-%s" % (revlog.short(rev), suffix))
38 ui.warn("saving bundle to %s\n" % name)
39 return changegroup.writebundle(cg, name, "HG10BZ")
40
41 def stripall(revnum):
42 mm = repo.changectx(rev).manifest()
43 seen = {}
44
45 for x in xrange(revnum, repo.changelog.count()):
46 for f in repo.changectx(x).files():
47 if f in seen:
48 continue
49 seen[f] = 1
50 if f in mm:
51 filerev = mm[f]
52 else:
53 filerev = 0
54 seen[f] = filerev
55 # we go in two steps here so the strip loop happens in a
56 # sensible order. When stripping many files, this helps keep
57 # our disk access patterns under control.
58 seen_list = seen.keys()
59 seen_list.sort()
60 for f in seen_list:
61 ff = repo.file(f)
62 filerev = seen[f]
63 if filerev != 0:
64 if filerev in ff.nodemap:
65 filerev = ff.rev(filerev)
66 else:
67 filerev = 0
68 ff.strip(filerev, revnum)
69
70 chlog = repo.changelog
71 # TODO delete the undo files, and handle undo of merge sets
72 pp = chlog.parents(rev)
73 revnum = chlog.rev(rev)
74
75 # save is a list of all the branches we are truncating away
76 # that we actually want to keep. changegroup will be used
77 # to preserve them and add them back after the truncate
78 saveheads = []
79 savebases = {}
80
81 heads = limitheads(chlog, rev)
82 seen = {}
83
84 # search through all the heads, finding those where the revision
85 # we want to strip away is an ancestor. Also look for merges
86 # that might be turned into new heads by the strip.
87 while heads:
88 h = heads.pop()
89 n = h
90 while True:
91 seen[n] = 1
92 pp = chlog.parents(n)
93 if pp[1] != revlog.nullid:
94 for p in pp:
95 if chlog.rev(p) > revnum and p not in seen:
96 heads.append(p)
97 if pp[0] == revlog.nullid:
98 break
99 if chlog.rev(pp[0]) < revnum:
100 break
101 n = pp[0]
102 if n == rev:
103 break
104 r = chlog.reachable(h, rev)
105 if rev not in r:
106 saveheads.append(h)
107 for x in r:
108 if chlog.rev(x) > revnum:
109 savebases[x] = 1
110
111 # create a changegroup for all the branches we need to keep
112 if backup == "all":
113 bundle(repo, [rev], chlog.heads(), rev, 'backup')
114 if saveheads:
115 chgrpfile = bundle(repo, savebases.keys(), saveheads, rev, 'temp')
116
117 stripall(revnum)
118
119 change = chlog.read(rev)
120 chlog.strip(revnum, revnum)
121 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
122 if saveheads:
123 ui.status("adding branch\n")
124 commands.unbundle(ui, repo, "file:%s" % chgrpfile, update=False)
125 if backup != "strip":
126 os.unlink(chgrpfile)
127
@@ -7,7 +7,7 b' help:'
7 @echo ' all - build program and documentation'
7 @echo ' all - build program and documentation'
8 @echo ' install - install program and man pages to PREFIX ($(PREFIX))'
8 @echo ' install - install program and man pages to PREFIX ($(PREFIX))'
9 @echo ' install-home - install with setup.py install --home=HOME ($(HOME))'
9 @echo ' install-home - install with setup.py install --home=HOME ($(HOME))'
10 @echo ' local - build C extensions for inplace usage'
10 @echo ' local - build for inplace usage'
11 @echo ' tests - run all tests in the automatic test suite'
11 @echo ' tests - run all tests in the automatic test suite'
12 @echo ' test-foo - run only specified tests (e.g. test-merge1)'
12 @echo ' test-foo - run only specified tests (e.g. test-merge1)'
13 @echo ' dist - run all tests and create a source tarball in dist/'
13 @echo ' dist - run all tests and create a source tarball in dist/'
@@ -24,6 +24,8 b' all: build doc'
24
24
25 local:
25 local:
26 $(PYTHON) setup.py build_ext -i
26 $(PYTHON) setup.py build_ext -i
27 $(PYTHON) setup.py build_py -c -d .
28 $(PYTHON) hg version
27
29
28 build:
30 build:
29 $(PYTHON) setup.py build
31 $(PYTHON) setup.py build
@@ -33,7 +35,7 b' doc:'
33
35
34 clean:
36 clean:
35 -$(PYTHON) setup.py clean --all # ignore errors of this command
37 -$(PYTHON) setup.py clean --all # ignore errors of this command
36 find . -name '*.py[co]' -exec rm -f '{}' ';'
38 find . -name '*.py[cdo]' -exec rm -f '{}' ';'
37 rm -f MANIFEST mercurial/__version__.py mercurial/*.so tests/*.err
39 rm -f MANIFEST mercurial/__version__.py mercurial/*.so tests/*.err
38 $(MAKE) -C doc clean
40 $(MAKE) -C doc clean
39
41
@@ -525,6 +525,8 b' web::'
525 Default is "unknown".
525 Default is "unknown".
526 errorlog;;
526 errorlog;;
527 Where to output the error log. Default is stderr.
527 Where to output the error log. Default is stderr.
528 hidden;;
529 Whether to hide the repository in the hgwebdir index. Default is false.
528 ipv6;;
530 ipv6;;
529 Whether to use IPv6. Default is false.
531 Whether to use IPv6. Default is false.
530 name;;
532 name;;
@@ -30,7 +30,8 b' refresh contents of top applied patch '
30 '''
30 '''
31
31
32 from mercurial.i18n import _
32 from mercurial.i18n import _
33 from mercurial import commands, cmdutil, hg, patch, revlog, util, changegroup
33 from mercurial import commands, cmdutil, hg, patch, revlog, util
34 from mercurial import repair
34 import os, sys, re, errno
35 import os, sys, re, errno
35
36
36 commands.norepo += " qclone qversion"
37 commands.norepo += " qclone qversion"
@@ -629,71 +630,9 b' class queue:'
629 self.removeundo(repo)
630 self.removeundo(repo)
630
631
631 def strip(self, repo, rev, update=True, backup="all", wlock=None):
632 def strip(self, repo, rev, update=True, backup="all", wlock=None):
632 def limitheads(chlog, stop):
633 """return the list of all nodes that have no children"""
634 p = {}
635 h = []
636 stoprev = 0
637 if stop in chlog.nodemap:
638 stoprev = chlog.rev(stop)
639
640 for r in xrange(chlog.count() - 1, -1, -1):
641 n = chlog.node(r)
642 if n not in p:
643 h.append(n)
644 if n == stop:
645 break
646 if r < stoprev:
647 break
648 for pn in chlog.parents(n):
649 p[pn] = 1
650 return h
651
652 def bundle(cg):
653 backupdir = repo.join("strip-backup")
654 if not os.path.isdir(backupdir):
655 os.mkdir(backupdir)
656 name = os.path.join(backupdir, "%s" % revlog.short(rev))
657 name = savename(name)
658 self.ui.warn("saving bundle to %s\n" % name)
659 return changegroup.writebundle(cg, name, "HG10BZ")
660
661 def stripall(revnum):
662 mm = repo.changectx(rev).manifest()
663 seen = {}
664
665 for x in xrange(revnum, repo.changelog.count()):
666 for f in repo.changectx(x).files():
667 if f in seen:
668 continue
669 seen[f] = 1
670 if f in mm:
671 filerev = mm[f]
672 else:
673 filerev = 0
674 seen[f] = filerev
675 # we go in two steps here so the strip loop happens in a
676 # sensible order. When stripping many files, this helps keep
677 # our disk access patterns under control.
678 seen_list = seen.keys()
679 seen_list.sort()
680 for f in seen_list:
681 ff = repo.file(f)
682 filerev = seen[f]
683 if filerev != 0:
684 if filerev in ff.nodemap:
685 filerev = ff.rev(filerev)
686 else:
687 filerev = 0
688 ff.strip(filerev, revnum)
689
690 if not wlock:
633 if not wlock:
691 wlock = repo.wlock()
634 wlock = repo.wlock()
692 lock = repo.lock()
635 lock = repo.lock()
693 chlog = repo.changelog
694 # TODO delete the undo files, and handle undo of merge sets
695 pp = chlog.parents(rev)
696 revnum = chlog.rev(rev)
697
636
698 if update:
637 if update:
699 self.check_localchanges(repo, refresh=False)
638 self.check_localchanges(repo, refresh=False)
@@ -701,62 +640,8 b' class queue:'
701 hg.clean(repo, urev, wlock=wlock)
640 hg.clean(repo, urev, wlock=wlock)
702 repo.dirstate.write()
641 repo.dirstate.write()
703
642
704 # save is a list of all the branches we are truncating away
705 # that we actually want to keep. changegroup will be used
706 # to preserve them and add them back after the truncate
707 saveheads = []
708 savebases = {}
709
710 heads = limitheads(chlog, rev)
711 seen = {}
712
713 # search through all the heads, finding those where the revision
714 # we want to strip away is an ancestor. Also look for merges
715 # that might be turned into new heads by the strip.
716 while heads:
717 h = heads.pop()
718 n = h
719 while True:
720 seen[n] = 1
721 pp = chlog.parents(n)
722 if pp[1] != revlog.nullid:
723 for p in pp:
724 if chlog.rev(p) > revnum and p not in seen:
725 heads.append(p)
726 if pp[0] == revlog.nullid:
727 break
728 if chlog.rev(pp[0]) < revnum:
729 break
730 n = pp[0]
731 if n == rev:
732 break
733 r = chlog.reachable(h, rev)
734 if rev not in r:
735 saveheads.append(h)
736 for x in r:
737 if chlog.rev(x) > revnum:
738 savebases[x] = 1
739
740 # create a changegroup for all the branches we need to keep
741 if backup == "all":
742 backupch = repo.changegroupsubset([rev], chlog.heads(), 'strip')
743 bundle(backupch)
744 if saveheads:
745 backupch = repo.changegroupsubset(savebases.keys(), saveheads, 'strip')
746 chgrpfile = bundle(backupch)
747
748 stripall(revnum)
749
750 change = chlog.read(rev)
751 chlog.strip(revnum, revnum)
752 repo.manifest.strip(repo.manifest.rev(change[0]), revnum)
753 self.removeundo(repo)
643 self.removeundo(repo)
754 if saveheads:
644 repair.strip(self.ui, repo, rev, backup)
755 self.ui.status("adding branch\n")
756 commands.unbundle(self.ui, repo, "file:%s" % chgrpfile,
757 update=False)
758 if backup != "strip":
759 os.unlink(chgrpfile)
760
645
761 def isapplied(self, patch):
646 def isapplied(self, patch):
762 """returns (index, rev, patch)"""
647 """returns (index, rev, patch)"""
@@ -142,6 +142,9 b' class hgwebdir(object):'
142 def get(section, name, default=None):
142 def get(section, name, default=None):
143 return u.config(section, name, default, untrusted=True)
143 return u.config(section, name, default, untrusted=True)
144
144
145 if u.configbool("web", "hidden", untrusted=True):
146 continue
147
145 url = ('/'.join([req.env["REQUEST_URI"].split('?')[0], name])
148 url = ('/'.join([req.env["REQUEST_URI"].split('?')[0], name])
146 .replace("//", "/")) + '/'
149 .replace("//", "/")) + '/'
147
150
@@ -105,6 +105,7 b' defaultdateformats = ('
105 '%m/%d/%Y',
105 '%m/%d/%Y',
106 '%a %b %d %H:%M:%S %Y',
106 '%a %b %d %H:%M:%S %Y',
107 '%a %b %d %I:%M:%S%p %Y',
107 '%a %b %d %I:%M:%S%p %Y',
108 '%a, %d %b %Y %H:%M:%S', # GNU coreutils "/bin/date --rfc-2822"
108 '%b %d %H:%M:%S %Y',
109 '%b %d %H:%M:%S %Y',
109 '%b %d %I:%M:%S%p %Y',
110 '%b %d %I:%M:%S%p %Y',
110 '%b %d %H:%M:%S',
111 '%b %d %H:%M:%S',
@@ -48,7 +48,7 b' filelogchild = \'<tr><td align="right">ch'
48 shortlog = shortlog.tmpl
48 shortlog = shortlog.tmpl
49 tagtag = '<span class="tagtag" title="{name}">{name}</span> '
49 tagtag = '<span class="tagtag" title="{name}">{name}</span> '
50 branchtag = '<span class="branchtag" title="{name}">{name}</span> '
50 branchtag = '<span class="branchtag" title="{name}">{name}</span> '
51 shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b> <span class="logtags">{branches%branchtag}{tags%tagtag}</span></a></td><td class="link" nowrap><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
51 shortlogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><i>#author|person#</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b> <span class="logtags">{branches%branchtag}{tags%tagtag}</span></a></td><td class="link" nowrap><a href="{url}rev/#node|short#{sessionvars%urlparameter}">changeset</a> | <a href="{url}file/#node|short#{sessionvars%urlparameter}">manifest</a></td></tr>'
52 filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url}diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url}annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> #rename%filelogrename#</td></tr>'
52 filelogentry = '<tr class="parity#parity#"><td class="age"><i>#date|age# ago</i></td><td><a class="list" href="{url}rev/#node|short#{sessionvars%urlparameter}"><b>#desc|strip|firstline|escape#</b></a></td><td class="link"><a href="{url}file/#node|short#/#file|urlescape#{sessionvars%urlparameter}">file</a>&nbsp;|&nbsp;<a href="{url}diff/#node|short#/#file|urlescape#{sessionvars%urlparameter}">diff</a>&nbsp;|&nbsp;<a href="{url}annotate/#node|short#/#file|urlescape#{sessionvars%urlparameter}">annotate</a> #rename%filelogrename#</td></tr>'
53 archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
53 archiveentry = ' | <a href="{url}archive/{node|short}{extension}">#type|escape#</a> '
54 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#{sessionvars%urlparameter}"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
54 indexentry = '<tr class="parity#parity#"><td><a class="list" href="#url#{sessionvars%urlparameter}"><b>#name|escape#</b></a></td><td>#description#</td><td>#contact|obfuscate#</td><td class="age">#lastchange|age# ago</td><td class="indexlinks"><a class="rss_logo" href="#url#rss-log">RSS</a> #archives%archiveentry#</td></tr>'
@@ -32,10 +32,10 b' summary |'
32 <tr><td>last change</td><td>#lastchange|rfc822date#</td></tr>
32 <tr><td>last change</td><td>#lastchange|rfc822date#</td></tr>
33 </table>
33 </table>
34
34
35 <div><a class="title" href="{url}log{sessionvars%urlparameter}">changes</a></div>
35 <div><a class="title" href="{url}shortlog{sessionvars%urlparameter}">changes</a></div>
36 <table cellspacing="0">
36 <table cellspacing="0">
37 #shortlog#
37 #shortlog#
38 <tr class="light"><td colspan="4"><a class="list" href="{url}log{sessionvars%urlparameter}">...</a></td></tr>
38 <tr class="light"><td colspan="4"><a class="list" href="{url}shortlog{sessionvars%urlparameter}">...</a></td></tr>
39 </table>
39 </table>
40
40
41 <div><a class="title" href="{url}tags{sessionvars%urlparameter}">tags</a></div>
41 <div><a class="title" href="{url}tags{sessionvars%urlparameter}">tags</a></div>
@@ -1,4 +1,4 b''
1 default = 'changelog'
1 default = 'shortlog'
2 header = header.tmpl
2 header = header.tmpl
3 footer = footer.tmpl
3 footer = footer.tmpl
4 search = search.tmpl
4 search = search.tmpl
@@ -1,7 +1,7 b''
1 <table class="slogEntry parity#parity#">
1 <table class="slogEntry parity#parity#">
2 <tr>
2 <tr>
3 <td class="age">#date|age#</td>
3 <td class="age">#date|age#</td>
4 <td class="author">#author|obfuscate#</td>
4 <td class="author">#author|person#</td>
5 <td class="node"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#desc|strip|firstline|escape#</a></td>
5 <td class="node"><a href="#url#rev/#node|short#{sessionvars%urlparameter}">#desc|strip|firstline|escape#</a></td>
6 </tr>
6 </tr>
7 </table>
7 </table>
@@ -58,10 +58,10 b' pre { margin: 0; }'
58 .logEntry th.firstline { text-align: left; width: inherit; }
58 .logEntry th.firstline { text-align: left; width: inherit; }
59
59
60 /* Shortlog entries */
60 /* Shortlog entries */
61 .slogEntry { width: 100%; font-size: smaller; }
61 .slogEntry { width: 100%; }
62 .slogEntry .age { width: 7%; }
62 .slogEntry .age { width: 8em; }
63 .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
63 .slogEntry td { font-weight: normal; text-align: left; vertical-align: top; }
64 .slogEntry td.author { width: 35%; }
64 .slogEntry td.author { width: 15em; }
65
65
66 /* Tag entries */
66 /* Tag entries */
67 #tagEntries { list-style: none; margin: 0; padding: 0; }
67 #tagEntries { list-style: none; margin: 0; padding: 0; }
General Comments 0
You need to be logged in to leave comments. Login now