1 # Copyright 2011 Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
|
2 # Logilab SA <contact@logilab.fr> |
|
3 # |
|
4 # This software may be used and distributed according to the terms of the |
|
5 # GNU General Public License version 2 or any later version. |
|
6 """Deprecated extension that formerly introduced "Changeset Obsolescence". |
|
7 |
|
8 This concept is now partially in Mercurial core (starting with Mercurial 2.3). |
|
9 The remaining logic has been grouped with the evolve extension. |
|
10 |
|
11 Some code remains in this extensions to detect and convert prehistoric format |
|
12 of obsolete marker than early user may have create. Keep it enabled if you |
|
13 were such user. |
|
14 """ |
|
15 |
|
16 from mercurial import error |
|
17 |
|
18 try: |
|
19 from mercurial import obsolete |
|
20 except ImportError: |
|
21 raise error.Abort('Obsolete extension requires Mercurial 2.3 (or later)') |
|
22 |
|
23 import sys |
|
24 import json |
|
25 |
|
26 from mercurial import cmdutil |
|
27 from mercurial.i18n import _ |
|
28 from mercurial.node import bin, nullid |
|
29 from mercurial import util |
|
30 |
|
31 |
|
32 ##################################################################### |
|
33 ### Older format management ### |
|
34 ##################################################################### |
|
35 |
|
36 # Code related to detection and management of older legacy format never |
|
37 # handled by core |
|
38 |
|
39 |
|
40 def reposetup(ui, repo): |
|
41 """Detect that a repo still contains some old obsolete format |
|
42 """ |
|
43 if not repo.local(): |
|
44 return |
|
45 evolveopts = ui.configlist('experimental', 'evolution') |
|
46 if not evolveopts: |
|
47 evolveopts = 'all' |
|
48 ui.setconfig('experimental', 'evolution', evolveopts) |
|
49 for arg in sys.argv: |
|
50 if 'debugc' in arg: |
|
51 break |
|
52 else: |
|
53 data = repo.opener.tryread('obsolete-relations') |
|
54 if not data: |
|
55 data = repo.svfs.tryread('obsoletemarkers') |
|
56 if data: |
|
57 raise error.Abort('old format of obsolete marker detected!\n' |
|
58 'run `hg debugconvertobsolete` once.') |
|
59 |
|
60 def _obsdeserialize(flike): |
|
61 """read a file like object serialized with _obsserialize |
|
62 |
|
63 this deserialize into a {subject -> objects} mapping |
|
64 |
|
65 this was the very first format ever.""" |
|
66 rels = {} |
|
67 for line in flike: |
|
68 subhex, objhex = line.split() |
|
69 subnode = bin(subhex) |
|
70 if subnode == nullid: |
|
71 subnode = None |
|
72 rels.setdefault(subnode, set()).add(bin(objhex)) |
|
73 return rels |
|
74 |
|
75 cmdtable = {} |
|
76 command = cmdutil.command(cmdtable) |
|
77 @command('debugconvertobsolete', [], '') |
|
78 def cmddebugconvertobsolete(ui, repo): |
|
79 """import markers from an .hg/obsolete-relations file""" |
|
80 cnt = 0 |
|
81 err = 0 |
|
82 l = repo.lock() |
|
83 some = False |
|
84 try: |
|
85 unlink = [] |
|
86 tr = repo.transaction('convert-obsolete') |
|
87 try: |
|
88 repo._importoldobsolete = True |
|
89 store = repo.obsstore |
|
90 ### very first format |
|
91 try: |
|
92 f = repo.opener('obsolete-relations') |
|
93 try: |
|
94 some = True |
|
95 for line in f: |
|
96 subhex, objhex = line.split() |
|
97 suc = bin(subhex) |
|
98 prec = bin(objhex) |
|
99 sucs = (suc==nullid) and [] or [suc] |
|
100 meta = { |
|
101 'date': '%i %i' % util.makedate(), |
|
102 'user': ui.username(), |
|
103 } |
|
104 try: |
|
105 store.create(tr, prec, sucs, 0, metadata=meta) |
|
106 cnt += 1 |
|
107 except ValueError: |
|
108 repo.ui.write_err("invalid old marker line: %s" |
|
109 % (line)) |
|
110 err += 1 |
|
111 finally: |
|
112 f.close() |
|
113 unlink.append(repo.join('obsolete-relations')) |
|
114 except IOError: |
|
115 pass |
|
116 ### second (json) format |
|
117 data = repo.svfs.tryread('obsoletemarkers') |
|
118 if data: |
|
119 some = True |
|
120 for oldmark in json.loads(data): |
|
121 del oldmark['id'] # dropped for now |
|
122 del oldmark['reason'] # unused until then |
|
123 oldobject = str(oldmark.pop('object')) |
|
124 oldsubjects = [str(s) for s in oldmark.pop('subjects', [])] |
|
125 LOOKUP_ERRORS = (error.RepoLookupError, error.LookupError) |
|
126 if len(oldobject) != 40: |
|
127 try: |
|
128 oldobject = repo[oldobject].node() |
|
129 except LOOKUP_ERRORS: |
|
130 pass |
|
131 if any(len(s) != 40 for s in oldsubjects): |
|
132 try: |
|
133 oldsubjects = [repo[s].node() for s in oldsubjects] |
|
134 except LOOKUP_ERRORS: |
|
135 pass |
|
136 |
|
137 oldmark['date'] = '%i %i' % tuple(oldmark['date']) |
|
138 meta = dict((k.encode('utf-8'), v.encode('utf-8')) |
|
139 for k, v in oldmark.iteritems()) |
|
140 try: |
|
141 succs = [bin(n) for n in oldsubjects] |
|
142 succs = [n for n in succs if n != nullid] |
|
143 store.create(tr, bin(oldobject), succs, |
|
144 0, metadata=meta) |
|
145 cnt += 1 |
|
146 except ValueError: |
|
147 repo.ui.write_err("invalid marker %s -> %s\n" |
|
148 % (oldobject, oldsubjects)) |
|
149 err += 1 |
|
150 unlink.append(repo.sjoin('obsoletemarkers')) |
|
151 tr.close() |
|
152 for path in unlink: |
|
153 util.unlink(path) |
|
154 finally: |
|
155 tr.release() |
|
156 finally: |
|
157 del repo._importoldobsolete |
|
158 l.release() |
|
159 if not some: |
|
160 ui.warn(_('nothing to do\n')) |
|
161 ui.status('%i obsolete marker converted\n' % cnt) |
|
162 if err: |
|
163 ui.write_err('%i conversion failed. check you graph!\n' % err) |
|