3 # This is a pretty-printer for subversion BDB repository databases.
6 import sys
, os
, re
, codecs
, textwrap
10 if len(sys
.argv
) == 2:
11 dbhome
= os
.path
.join(sys
.argv
[1], 'db')
12 if not os
.path
.exists(dbhome
):
13 sys
.stderr
.write("%s: '%s' is not a valid svn repository\n" %
14 (sys
.argv
[0], dbhome
))
17 sys
.stderr
.write("Usage: %s <svn-repository>\n" % sys
.argv
[0])
21 class RepositoryProblem(Exception):
25 def ok(bool, comment
):
27 raise RepositoryProblem(text
)
42 ok(db
.keys() == [1], 'uuid Table Structure')
43 ok(re
.match(r
'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$',
44 db
[1]), 'UUID format')
45 print "Repos UUID: %s" % db
[1]
47 def am_revisions(ctx
):
49 cur
= ctx
.revs_db
.cursor()
52 ctx
.txn2rev
= txn2rev
= {}
55 rev
= skel
.Rev(rec
[1])
57 print "r%d: txn %s%s" % (revnum
, rev
.txn
,
58 (not ctx
.txns_db
.has_key(rev
.txn
)) and "*** MISSING TXN ***" or "")
59 ok(not txn2rev
.has_key(rev
.txn
), 'Multiple revs bound to same txn')
60 txn2rev
[rev
.txn
] = revnum
67 cur
= ctx
.changes_db
.cursor()
71 while current_txnid_len
<= maximum_txnid_len
:
72 current_txnid_len
+= 1
76 if len(rec
[0]) != current_txnid_len
:
79 ch
= skel
.Change(rec
[1])
80 lead
= "txn %s:" % rec
[0]
82 lead
= " " * len(lead
)
83 print "%s %s %s %s %s %s%s" % (lead
, opmap
[ch
.kind
], ch
.path
, ch
.node
,
84 ch
.textmod
and "T" or "-", ch
.propmod
and "P" or "-",
85 (not ctx
.nodes_db
.has_key(ch
.node
)) \
86 and "*** MISSING NODE ***" or "")
88 if len(rec
[0]) > maximum_txnid_len
:
89 maximum_txnid_len
= len(rec
[0])
96 cur
= ctx
.copies_db
.cursor()
98 print "next-key: %s" % ctx
.copies_db
['next-key']
101 if rec
[0] != 'next-key':
102 cp
= skel
.Copy(rec
[1])
103 destnode
= ctx
.nodes_db
.get(cp
.destnode
)
105 destpath
= "*** MISSING NODE ***"
107 destpath
= skel
.Node(destnode
).createpath
108 print "cpy %s: %s %s @txn %s to %s (%s)" % (rec
[0],
109 {'copy':'C','soft-copy':'S'}[cp
.kind
], cp
.srcpath
or "-",
110 cp
.srctxn
or "-", cp
.destnode
, destpath
)
117 cur
= ctx
.txns_db
.cursor()
119 print "next-key: %s" % ctx
.txns_db
['next-key']
126 if rec
[0] != 'next-key' and len(rec
[0]) == length
:
128 txn
= skel
.Txn(rec
[1])
129 if txn
.kind
== "committed":
130 label
= "r%s" % txn
.rev
131 ok(ctx
.txn2rev
[rec
[0]] == int(txn
.rev
), 'Txn->rev not <-txn')
133 label
= "%s based-on %s" % (txn
.kind
, txn
.basenode
)
134 print "txn %s: %s root-node %s props %d copies %s" % (rec
[0],
135 label
, txn
.rootnode
, len(txn
.proplist
) / 2, ",".join(txn
.copies
))
143 cur
= ctx
.nodes_db
.cursor()
145 print "next-key: %s" % ctx
.txns_db
['next-key']
149 if rec
[0] == 'next-key':
152 nd
= skel
.Node(rec
[1])
153 nid
,cid
,tid
= rec
[0].split(".")
154 data
[tid
.rjust(20)+nd
.createpath
] = (rec
[0], nd
)
158 reptype
= {"fulltext":"F", "delta":"D"}
161 prkind
= drkind
= " "
164 rep
= skel
.Rep(ctx
.reps_db
[nd
.proprep
])
165 prkind
= reptype
[rep
.kind
]
166 if ctx
.bad_reps
.has_key(nd
.proprep
):
167 prkind
+= " *** BAD ***"
169 prkind
= "*** MISSING ***"
172 rep
= skel
.Rep(ctx
.reps_db
[nd
.datarep
])
173 drkind
= reptype
[rep
.kind
]
174 if ctx
.bad_reps
.has_key(nd
.datarep
):
175 drkind
+= " *** BAD ***"
177 drkind
= "*** MISSING ***"
178 stringdata
= "%s: %s %s pred %s count %s prop %s %s data %s %s edit %s" \
179 % ( data
[i
][0], {"file":"F", "dir":"D"}[nd
.kind
], nd
.createpath
,
180 nd
.prednode
or "-", nd
.predcount
, prkind
, nd
.proprep
or "-",
181 drkind
, nd
.datarep
or "-", nd
.editrep
or "-")
182 if nd
.createpath
== "/":
188 def get_string(ctx
, id):
190 return ctx
.get_whole_string(id)
191 except DbNotFoundError
:
192 return "*** MISSING STRING ***"
197 cur
= ctx
.reps_db
.cursor()
199 print "next-key: %s" % ctx
.txns_db
['next-key']
202 if rec
[0] != 'next-key':
203 rep
= skel
.Rep(rec
[1])
204 lead
= "rep %s: txn %s: %s %s " % (rec
[0], rep
.txn
, rep
.cksumtype
,
205 codecs
.getencoder('hex_codec')(rep
.cksum
)[0])
206 if rep
.kind
== "fulltext":
208 if not ctx
.strings_db
.has_key(rep
.str):
210 ctx
.bad_reps
[rec
[0]] = None
211 print lead
+("fulltext str %s%s" % (rep
.str, note
))
213 print textwrap
.fill(get_string(ctx
, rep
.str), initial_indent
=" ",
214 subsequent_indent
=" ", width
=78)
215 elif rep
.kind
== "delta":
216 print lead
+("delta of %s window%s" % (len(rep
.windows
),
217 len(rep
.windows
) != 1 and "s" or ""))
218 for window
in rep
.windows
:
219 noterep
= notestr
= ""
220 if not ctx
.reps_db
.has_key(window
.vs_rep
):
222 ctx
.bad_reps
[rec
[0]] = None
223 if not ctx
.strings_db
.has_key(window
.str):
225 ctx
.bad_reps
[rec
[0]] = None
226 print "\toff %s len %s vs-rep %s%s str %s%s" % (window
.offset
,
227 window
.size
, window
.vs_rep
, noterep
, window
.str, notestr
)
229 print lead
+"*** UNKNOWN REPRESENTATION TYPE ***"
235 def am_stringsize(ctx
):
239 cur
= ctx
.strings_db
.cursor()
244 size
= size
+ len(rec
[1] or "")
246 print size
, size
/1024.0, size
/1024.0/1024.0
258 # Takes too long: am_stringsize,
262 print "Repository View for '%s'" % dbhome
264 ctx
= svnfs
.Ctx(dbhome
, readonly
=1)
265 # Stash process state in a library data structure. Yuck!
269 print "MODULE: %s" % am
.__doc
__
275 if __name__
== '__main__':