Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
zodbtools
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Jérome Perrin
zodbtools
Commits
347ea21d
Commit
347ea21d
authored
Jan 30, 2019
by
Jérome Perrin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
util: add type annotations and fix bytes vs str
parent
72011755
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
117 additions
and
64 deletions
+117
-64
mypy.ini
mypy.ini
+3
-0
zodbtools/help.py
zodbtools/help.py
+6
-1
zodbtools/test/test_commit.py
zodbtools/test/test_commit.py
+3
-3
zodbtools/test/test_dump.py
zodbtools/test/test_dump.py
+15
-15
zodbtools/test/test_zodb.py
zodbtools/test/test_zodb.py
+3
-1
zodbtools/util.py
zodbtools/util.py
+34
-11
zodbtools/zodbanalyze.py
zodbtools/zodbanalyze.py
+1
-1
zodbtools/zodbdump.py
zodbtools/zodbdump.py
+52
-32
No files found.
mypy.ini
0 → 100644
View file @
347ea21d
[mypy]
# XXX according to mypy doc, this is a bad idea.
ignore_missing_imports
=
True
zodbtools/help.py
View file @
347ea21d
...
@@ -19,10 +19,15 @@
...
@@ -19,10 +19,15 @@
# See COPYING file for full licensing terms.
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
# See https://www.nexedi.com/licensing for rationale and options.
try
:
from
typing
import
Tuple
except
ImportError
:
pass
from
collections
import
OrderedDict
from
collections
import
OrderedDict
# topic_name -> (topic_summary, topic_help)
# topic_name -> (topic_summary, topic_help)
topic_dict
=
OrderedDict
()
topic_dict
=
OrderedDict
()
# type: OrderedDict[str, Tuple[str, str]]
help_zurl
=
"""
\
help_zurl
=
"""
\
Almost every zodb command works with a database.
Almost every zodb command works with a database.
...
...
zodbtools/test/test_commit.py
View file @
347ea21d
...
@@ -41,8 +41,8 @@ def test_zodbcommit(zext):
...
@@ -41,8 +41,8 @@ def test_zodbcommit(zext):
# commit some transactions via zodbcommit and verify if storage dump gives
# commit some transactions via zodbcommit and verify if storage dump gives
# what is expected.
# what is expected.
t1
=
Transaction
(
z64
,
' '
,
b'user name'
,
b'description ...'
,
zext
(
dumps
({
'a'
:
'b'
},
_protocol
)),
[
t1
=
Transaction
(
z64
,
' '
,
b'user name'
,
b'description ...'
,
zext
(
dumps
({
'a'
:
'b'
},
_protocol
)),
[
ObjectData
(
p64
(
1
),
b'data1'
,
'sha1'
,
sha1
(
'data1'
)),
ObjectData
(
p64
(
1
),
b'data1'
,
'sha1'
,
sha1
(
b
'data1'
)),
ObjectData
(
p64
(
2
),
b'data2'
,
'sha1'
,
sha1
(
'data2'
))])
ObjectData
(
p64
(
2
),
b'data2'
,
'sha1'
,
sha1
(
b
'data2'
))])
t1
.
tid
=
zodbcommit
(
stor
,
head
,
t1
)
t1
.
tid
=
zodbcommit
(
stor
,
head
,
t1
)
...
@@ -56,7 +56,7 @@ def test_zodbcommit(zext):
...
@@ -56,7 +56,7 @@ def test_zodbcommit(zext):
zodbdump
(
stor
,
p64
(
u64
(
head
)
+
1
),
None
,
out
=
buf
)
zodbdump
(
stor
,
p64
(
u64
(
head
)
+
1
),
None
,
out
=
buf
)
dumped
=
buf
.
getvalue
()
dumped
=
buf
.
getvalue
()
assert
dumped
==
''
.
join
([
_
.
zdump
()
for
_
in
(
t1
,
t2
)])
assert
dumped
==
b
''
.
join
([
_
.
zdump
()
for
_
in
(
t1
,
t2
)])
# ObjectCopy. XXX zodbcommit handled ObjectCopy by actually copying data,
# ObjectCopy. XXX zodbcommit handled ObjectCopy by actually copying data,
# not referencing previous transaction via backpointer.
# not referencing previous transaction via backpointer.
...
...
zodbtools/test/test_dump.py
View file @
347ea21d
...
@@ -21,14 +21,14 @@ from zodbtools.zodbdump import (
...
@@ -21,14 +21,14 @@ from zodbtools.zodbdump import (
zodbdump
,
DumpReader
,
Transaction
,
ObjectDelete
,
ObjectCopy
,
zodbdump
,
DumpReader
,
Transaction
,
ObjectDelete
,
ObjectCopy
,
ObjectData
,
HashOnly
ObjectData
,
HashOnly
)
)
from
zodbtools.util
import
fromhex
from
ZODB.FileStorage
import
FileStorage
from
ZODB.FileStorage
import
FileStorage
from
ZODB.utils
import
p64
from
ZODB.utils
import
p64
from
cStringIO
import
String
IO
from
io
import
Bytes
IO
from
os.path
import
dirname
from
os.path
import
dirname
from
zodbtools.test.testutil
import
zext_supported
from
pytest
import
raises
from
pytest
import
raises
,
xfail
# verify zodbdump output against golden
# verify zodbdump output against golden
def
test_zodbdump
(
zext
):
def
test_zodbdump
(
zext
):
...
@@ -39,7 +39,7 @@ def test_zodbdump(zext):
...
@@ -39,7 +39,7 @@ def test_zodbdump(zext):
with
open
(
'%s/testdata/1%s.zdump.ok'
%
(
tdir
,
zkind
))
as
f
:
with
open
(
'%s/testdata/1%s.zdump.ok'
%
(
tdir
,
zkind
))
as
f
:
dumpok
=
f
.
read
()
dumpok
=
f
.
read
()
out
=
String
IO
()
out
=
Bytes
IO
()
zodbdump
(
stor
,
None
,
None
,
out
=
out
)
zodbdump
(
stor
,
None
,
None
,
out
=
out
)
assert
out
.
getvalue
()
==
dumpok
assert
out
.
getvalue
()
==
dumpok
...
@@ -69,10 +69,10 @@ extension "qqq"
...
@@ -69,10 +69,10 @@ extension "qqq"
"""
"""
r
=
DumpReader
(
String
IO
(
in_
))
r
=
DumpReader
(
Bytes
IO
(
in_
))
t1
=
r
.
readtxn
()
t1
=
r
.
readtxn
()
assert
isinstance
(
t1
,
Transaction
)
assert
isinstance
(
t1
,
Transaction
)
assert
t1
.
tid
==
'0123456789abcdef'
.
decode
(
'hex
'
)
assert
t1
.
tid
==
fromhex
(
'0123456789abcdef
'
)
assert
t1
.
user
==
b'my name'
assert
t1
.
user
==
b'my name'
assert
t1
.
description
==
b'o la-la...'
assert
t1
.
description
==
b'o la-la...'
assert
t1
.
extension_bytes
==
b'zzz123 def'
assert
t1
.
extension_bytes
==
b'zzz123 def'
...
@@ -83,29 +83,29 @@ extension "qqq"
...
@@ -83,29 +83,29 @@ extension "qqq"
_
=
t1
.
objv
[
1
]
_
=
t1
.
objv
[
1
]
assert
isinstance
(
_
,
ObjectCopy
)
assert
isinstance
(
_
,
ObjectCopy
)
assert
_
.
oid
==
p64
(
2
)
assert
_
.
oid
==
p64
(
2
)
assert
_
.
copy_from
==
'0123456789abcdee'
.
decode
(
'hex
'
)
assert
_
.
copy_from
==
fromhex
(
'0123456789abcdee
'
)
_
=
t1
.
objv
[
2
]
_
=
t1
.
objv
[
2
]
assert
isinstance
(
_
,
ObjectData
)
assert
isinstance
(
_
,
ObjectData
)
assert
_
.
oid
==
p64
(
3
)
assert
_
.
oid
==
p64
(
3
)
assert
_
.
data
==
HashOnly
(
54
)
assert
_
.
data
==
HashOnly
(
54
)
assert
_
.
hashfunc
==
'adler32'
assert
_
.
hashfunc
==
'adler32'
assert
_
.
hash_
==
'01234567'
.
decode
(
'hex
'
)
assert
_
.
hash_
==
fromhex
(
'01234567
'
)
_
=
t1
.
objv
[
3
]
_
=
t1
.
objv
[
3
]
assert
isinstance
(
_
,
ObjectData
)
assert
isinstance
(
_
,
ObjectData
)
assert
_
.
oid
==
p64
(
4
)
assert
_
.
oid
==
p64
(
4
)
assert
_
.
data
==
b'ZZZZ'
assert
_
.
data
==
b'ZZZZ'
assert
_
.
hashfunc
==
'sha1'
assert
_
.
hashfunc
==
'sha1'
assert
_
.
hash_
==
'9865d483bc5a94f2e30056fc256ed3066af54d04'
.
decode
(
'hex
'
)
assert
_
.
hash_
==
fromhex
(
'9865d483bc5a94f2e30056fc256ed3066af54d04
'
)
_
=
t1
.
objv
[
4
]
_
=
t1
.
objv
[
4
]
assert
isinstance
(
_
,
ObjectData
)
assert
isinstance
(
_
,
ObjectData
)
assert
_
.
oid
==
p64
(
5
)
assert
_
.
oid
==
p64
(
5
)
assert
_
.
data
==
b'ABC
\
n
\
n
DEF!'
assert
_
.
data
==
b'ABC
\
n
\
n
DEF!'
assert
_
.
hashfunc
==
'crc32'
assert
_
.
hashfunc
==
'crc32'
assert
_
.
hash_
==
'52fdeac5'
.
decode
(
'hex
'
)
assert
_
.
hash_
==
fromhex
(
'52fdeac5
'
)
t2
=
r
.
readtxn
()
t2
=
r
.
readtxn
()
assert
isinstance
(
t2
,
Transaction
)
assert
isinstance
(
t2
,
Transaction
)
assert
t2
.
tid
==
'0123456789abcdf0'
.
decode
(
'hex
'
)
assert
t2
.
tid
==
fromhex
(
'0123456789abcdf0
'
)
assert
t2
.
user
==
b'author2'
assert
t2
.
user
==
b'author2'
assert
t2
.
description
==
b'zzz'
assert
t2
.
description
==
b'zzz'
assert
t2
.
extension_bytes
==
b'qqq'
assert
t2
.
extension_bytes
==
b'qqq'
...
@@ -113,11 +113,11 @@ extension "qqq"
...
@@ -113,11 +113,11 @@ extension "qqq"
assert
r
.
readtxn
()
==
None
assert
r
.
readtxn
()
==
None
z
=
''
.
join
([
_
.
zdump
()
for
_
in
(
t1
,
t2
)])
z
=
b
''
.
join
([
_
.
zdump
()
for
_
in
(
t1
,
t2
)])
assert
z
==
in_
assert
z
==
in_
# unknown hash function
# unknown hash function
r
=
DumpReader
(
StringIO
(
"""
\
r
=
DumpReader
(
BytesIO
(
b
"""
\
txn 0000000000000000 " "
txn 0000000000000000 " "
user ""
user ""
description ""
description ""
...
@@ -130,7 +130,7 @@ obj 0000000000000001 1 xyz:0123 -
...
@@ -130,7 +130,7 @@ obj 0000000000000001 1 xyz:0123 -
assert
exc
.
value
.
args
==
(
"""+5: invalid line: unknown hash function "xyz" ('obj 0000000000000001 1 xyz:0123 -')"""
,)
assert
exc
.
value
.
args
==
(
"""+5: invalid line: unknown hash function "xyz" ('obj 0000000000000001 1 xyz:0123 -')"""
,)
# data integrity error
# data integrity error
r
=
DumpReader
(
StringIO
(
"""
\
r
=
DumpReader
(
BytesIO
(
b
"""
\
txn 0000000000000000 " "
txn 0000000000000000 " "
user ""
user ""
description ""
description ""
...
@@ -141,4 +141,4 @@ hello
...
@@ -141,4 +141,4 @@ hello
"""
))
"""
))
with
raises
(
RuntimeError
)
as
exc
:
with
raises
(
RuntimeError
)
as
exc
:
r
.
readtxn
()
r
.
readtxn
()
assert
exc
.
value
.
args
==
(
"""+6: data corrupt: crc32 = 3610a686, expected 01234567"""
,)
assert
exc
.
value
.
args
==
(
"""+6: data corrupt: crc32 = 3610a686, expected 01234567"""
,)
\ No newline at end of file
zodbtools/test/test_zodb.py
View file @
347ea21d
...
@@ -22,7 +22,9 @@ try:
...
@@ -22,7 +22,9 @@ try:
from
unittest
import
mock
from
unittest
import
mock
except
ImportError
:
except
ImportError
:
# BBB python2
# BBB python2
import
mock
import
mock
# type: ignore
# mypy complains: error: Name 'mock' already defined (by an import)
# https://github.com/python/mypy/issues/1153#issuecomment-253842414
import
pytest
import
pytest
...
...
zodbtools/util.py
View file @
347ea21d
...
@@ -18,20 +18,32 @@
...
@@ -18,20 +18,32 @@
# See COPYING file for full licensing terms.
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
# See https://www.nexedi.com/licensing for rationale and options.
try
:
from
typing
import
Tuple
,
Optional
,
Union
,
Iterable
,
Any
,
Mapping
,
Callable
except
ImportError
:
pass
import
hashlib
,
struct
,
codecs
import
hashlib
,
struct
,
codecs
import
zodburi
import
zodburi
# type: ignore
from
six.moves.urllib_parse
import
urlsplit
,
urlunsplit
from
six.moves.urllib_parse
import
urlsplit
,
urlunsplit
from
zlib
import
crc32
,
adler32
from
zlib
import
crc32
,
adler32
from
ZODB.TimeStamp
import
TimeStamp
from
ZODB.TimeStamp
import
TimeStamp
import
dateparser
import
dateparser
# XXX note that for ashex and fromhex I run mypy with a typeshed patch
# https://github.com/python/typeshed/issues/300#issuecomment-459151016
def
ashex
(
s
):
def
ashex
(
s
):
return
s
.
encode
(
'hex'
)
# type: (bytes) -> str
return
codecs
.
encode
(
s
,
'hex'
).
decode
()
def
fromhex
(
s
):
def
fromhex
(
s
):
# type: (Union[str,bytes]) -> bytes
return
codecs
.
decode
(
s
,
'hex'
)
return
codecs
.
decode
(
s
,
'hex'
)
def
sha1
(
data
):
def
sha1
(
data
):
# type: (bytes) -> bytes
m
=
hashlib
.
sha1
()
m
=
hashlib
.
sha1
()
m
.
update
(
data
)
m
.
update
(
data
)
return
m
.
digest
()
return
m
.
digest
()
...
@@ -53,6 +65,8 @@ def nextitem(it):
...
@@ -53,6 +65,8 @@ def nextitem(it):
# objects of a IStorageTransactionInformation
# objects of a IStorageTransactionInformation
def
txnobjv
(
txn
):
def
txnobjv
(
txn
):
# type: (Any) -> Iterable[Any]
# XXX type ?
objv
=
[]
objv
=
[]
for
obj
in
txn
:
for
obj
in
txn
:
assert
obj
.
tid
==
txn
.
tid
assert
obj
.
tid
==
txn
.
tid
...
@@ -72,6 +86,7 @@ class TidRangeInvalid(ValueError):
...
@@ -72,6 +86,7 @@ class TidRangeInvalid(ValueError):
def
parse_tid
(
tid_string
,
raw_only
=
False
):
def
parse_tid
(
tid_string
,
raw_only
=
False
):
# type: (str, bool) -> bytes
"""Try to parse `tid_string` as a time and returns the
"""Try to parse `tid_string` as a time and returns the
corresponding raw TID.
corresponding raw TID.
If `tid_string` cannot be parsed as a time, assume it was
If `tid_string` cannot be parsed as a time, assume it was
...
@@ -121,19 +136,16 @@ def parse_tid(tid_string, raw_only=False):
...
@@ -121,19 +136,16 @@ def parse_tid(tid_string, raw_only=False):
#
#
# see `zodb help tidrange` for accepted tidrange syntax.
# see `zodb help tidrange` for accepted tidrange syntax.
def
parse_tidrange
(
tidrange
):
def
parse_tidrange
(
tidrange
):
# type: (str) -> Tuple[Optional[bytes], Optional[bytes]]
try
:
try
:
tidmin
,
tidmax
=
tidrange
.
split
(
".."
)
tidmin
,
tidmax
=
tidrange
.
split
(
".."
)
except
ValueError
:
# not exactly 2 parts in between ".."
except
ValueError
:
# not exactly 2 parts in between ".."
raise
TidRangeInvalid
(
tidrange
)
raise
TidRangeInvalid
(
tidrange
)
if
tidmin
:
tidmin
=
parse_tid
(
tidmin
)
if
tidmax
:
tidmax
=
parse_tid
(
tidmax
)
# empty tid means -inf / +inf respectively
# empty tid means -inf / +inf respectively
# ( which is None in IStorage.iterator() )
# ( which is None in IStorage.iterator() )
return
(
tidmin
or
None
,
tidmax
or
None
)
return
(
parse_tid
(
tidmin
)
if
tidmin
else
None
,
parse_tid
(
tidmax
)
if
tidmax
else
None
)
# storageFromURL opens a ZODB-storage specified by url
# storageFromURL opens a ZODB-storage specified by url
...
@@ -169,12 +181,15 @@ class NullHasher:
...
@@ -169,12 +181,15 @@ class NullHasher:
digest_size
=
1
digest_size
=
1
def
update
(
self
,
data
):
def
update
(
self
,
data
):
# type: (bytes) -> None
pass
pass
def
digest
(
self
):
def
digest
(
self
):
# type: () -> bytes
return
b'
\
0
'
return
b'
\
0
'
def
hexdigest
(
self
):
def
hexdigest
(
self
):
# type: () -> str
return
"00"
return
"00"
# adler32 in hashlib interface
# adler32 in hashlib interface
...
@@ -183,15 +198,19 @@ class Adler32Hasher:
...
@@ -183,15 +198,19 @@ class Adler32Hasher:
digest_size
=
4
digest_size
=
4
def
__init__
(
self
):
def
__init__
(
self
):
self
.
_h
=
adler32
(
''
)
# type: () -> None
self
.
_h
=
adler32
(
b''
)
def
update
(
self
,
data
):
def
update
(
self
,
data
):
# type: (bytes) -> None
self
.
_h
=
adler32
(
data
,
self
.
_h
)
self
.
_h
=
adler32
(
data
,
self
.
_h
)
def
digest
(
self
):
def
digest
(
self
):
# type: () -> bytes
return
struct
.
pack
(
'>I'
,
self
.
_h
&
0xffffffff
)
return
struct
.
pack
(
'>I'
,
self
.
_h
&
0xffffffff
)
def
hexdigest
(
self
):
def
hexdigest
(
self
):
# type: () -> str
return
'%08x'
%
(
self
.
_h
&
0xffffffff
)
return
'%08x'
%
(
self
.
_h
&
0xffffffff
)
# crc32 in hashlib interface
# crc32 in hashlib interface
...
@@ -200,15 +219,19 @@ class CRC32Hasher:
...
@@ -200,15 +219,19 @@ class CRC32Hasher:
digest_size
=
4
digest_size
=
4
def
__init__
(
self
):
def
__init__
(
self
):
self
.
_h
=
crc32
(
''
)
# type: () -> None
self
.
_h
=
crc32
(
b''
)
def
update
(
self
,
data
):
def
update
(
self
,
data
):
# type: (bytes) -> None
self
.
_h
=
crc32
(
data
,
self
.
_h
)
self
.
_h
=
crc32
(
data
,
self
.
_h
)
def
digest
(
self
):
def
digest
(
self
):
# type: () -> bytes
return
struct
.
pack
(
'>I'
,
self
.
_h
&
0xffffffff
)
return
struct
.
pack
(
'>I'
,
self
.
_h
&
0xffffffff
)
def
hexdigest
(
self
):
def
hexdigest
(
self
):
# type: () -> str
return
'%08x'
%
(
self
.
_h
&
0xffffffff
)
return
'%08x'
%
(
self
.
_h
&
0xffffffff
)
# {} name -> hasher
# {} name -> hasher
...
@@ -219,4 +242,4 @@ hashRegistry = {
...
@@ -219,4 +242,4 @@ hashRegistry = {
"sha1"
:
hashlib
.
sha1
,
"sha1"
:
hashlib
.
sha1
,
"sha256"
:
hashlib
.
sha256
,
"sha256"
:
hashlib
.
sha256
,
"sha512"
:
hashlib
.
sha512
,
"sha512"
:
hashlib
.
sha512
,
}
}
# type: Mapping[str, Callable] # XXX "Callable" is a bit too wide typing
zodbtools/zodbanalyze.py
View file @
347ea21d
...
@@ -9,7 +9,7 @@ from __future__ import print_function
...
@@ -9,7 +9,7 @@ from __future__ import print_function
import
sys
import
sys
import
os
import
os
import
getopt
import
getopt
from
six.moves
import
dbm_gnu
as
dbm
from
six.moves
import
dbm_gnu
as
dbm
# type: ignore
import
tempfile
import
tempfile
import
shutil
import
shutil
from
ZODB.FileStorage
import
FileIterator
,
packed_version
from
ZODB.FileStorage
import
FileIterator
,
packed_version
...
...
zodbtools/zodbdump.py
View file @
347ea21d
...
@@ -53,6 +53,10 @@ TODO also protect txn record by hash.
...
@@ -53,6 +53,10 @@ TODO also protect txn record by hash.
"""
"""
from
__future__
import
print_function
from
__future__
import
print_function
try
:
from
typing
import
Any
,
Set
,
Optional
,
BinaryIO
,
NoReturn
,
Union
except
ImportError
:
pass
from
zodbtools.util
import
ashex
,
fromhex
,
sha1
,
txnobjv
,
parse_tidrange
,
TidRangeInvalid
,
\
from
zodbtools.util
import
ashex
,
fromhex
,
sha1
,
txnobjv
,
parse_tidrange
,
TidRangeInvalid
,
\
storageFromURL
,
hashRegistry
storageFromURL
,
hashRegistry
from
ZODB._compat
import
loads
,
_protocol
,
BytesIO
from
ZODB._compat
import
loads
,
_protocol
,
BytesIO
...
@@ -61,6 +65,7 @@ from zodbpickle.slowpickle import Pickler as pyPickler
...
@@ -61,6 +65,7 @@ from zodbpickle.slowpickle import Pickler as pyPickler
from
ZODB.interfaces
import
IStorageTransactionInformation
from
ZODB.interfaces
import
IStorageTransactionInformation
from
zope.interface
import
implementer
from
zope.interface
import
implementer
import
six
import
sys
import
sys
import
logging
import
logging
import
re
import
re
...
@@ -92,50 +97,53 @@ def txn_raw_extension(stor, txn):
...
@@ -92,50 +97,53 @@ def txn_raw_extension(stor, txn):
return
serializeext
(
txn
.
extension
)
return
serializeext
(
txn
.
extension
)
# set of storage names already warned for not providing IStorageTransactionInformationRaw
# set of storage names already warned for not providing IStorageTransactionInformationRaw
_already_warned_notxnraw
=
set
()
_already_warned_notxnraw
=
set
()
# type: Set[str]
# zodbdump dumps content of a ZODB storage to a file.
# zodbdump dumps content of a ZODB storage to a file.
# please see module doc-string for dump format and details
# please see module doc-string for dump format and details
def
zodbdump
(
stor
,
tidmin
,
tidmax
,
hashonly
=
False
,
out
=
sys
.
stdout
):
def
zodbdump
(
stor
,
tidmin
,
tidmax
,
hashonly
=
False
,
out
=
sys
.
stdout
.
buffer
):
# type: (Any, Optional[bytes], Optional[bytes], bool, BinaryIO) -> None
for
txn
in
stor
.
iterator
(
tidmin
,
tidmax
):
for
txn
in
stor
.
iterator
(
tidmin
,
tidmax
):
# XXX .status not covered by IStorageTransactionInformation
# XXX .status not covered by IStorageTransactionInformation
# XXX but covered by BaseStorage.TransactionRecord
# XXX but covered by BaseStorage.TransactionRecord
out
.
write
(
"txn %s %s
\
n
user %s
\
n
description %s
\
n
extension %s
\
n
"
%
(
out
.
write
(
(
"txn %s %s
\
n
user %s
\
n
description %s
\
n
extension %s
\
n
"
%
(
ashex
(
txn
.
tid
),
qq
(
txn
.
status
),
ashex
(
txn
.
tid
),
qq
(
txn
.
status
),
qq
(
txn
.
user
),
qq
(
txn
.
user
),
qq
(
txn
.
description
),
qq
(
txn
.
description
),
qq
(
txn_raw_extension
(
stor
,
txn
))
))
qq
(
txn_raw_extension
(
stor
,
txn
))
))
.
encode
())
objv
=
txnobjv
(
txn
)
objv
=
txnobjv
(
txn
)
for
obj
in
objv
:
for
obj
in
objv
:
entry
=
"obj %s "
%
ashex
(
obj
.
oid
)
entry
=
b"obj %s "
%
ashex
(
obj
.
oid
).
encode
(
)
write_data
=
False
write_data
=
False
if
obj
.
data
is
None
:
if
obj
.
data
is
None
:
entry
+=
"delete"
entry
+=
b
"delete"
# was undo and data taken from obj.data_txn
# was undo and data taken from obj.data_txn
elif
obj
.
data_txn
is
not
None
:
elif
obj
.
data_txn
is
not
None
:
entry
+=
"from %s"
%
ashex
(
obj
.
data_txn
)
entry
+=
b
"from %s"
%
ashex
(
obj
.
data_txn
)
else
:
else
:
# XXX sha1 is hardcoded for now. Dump format allows other hashes.
# XXX sha1 is hardcoded for now. Dump format allows other hashes.
entry
+=
"%i sha1:%s"
%
(
len
(
obj
.
data
),
ashex
(
sha1
(
obj
.
data
)
))
entry
+=
b"%i sha1:%s"
%
(
len
(
obj
.
data
),
ashex
(
sha1
(
obj
.
data
)).
encode
(
))
write_data
=
True
write_data
=
True
if
six
.
PY2
:
entry
=
entry
.
encode
(
'utf-8'
)
out
.
write
(
entry
)
out
.
write
(
entry
)
if
write_data
:
if
write_data
:
if
hashonly
:
if
hashonly
:
out
.
write
(
" -"
)
out
.
write
(
b
" -"
)
else
:
else
:
out
.
write
(
"
\
n
"
)
out
.
write
(
b
"
\
n
"
)
out
.
write
(
obj
.
data
)
out
.
write
(
obj
.
data
or
b""
)
out
.
write
(
"
\
n
"
)
out
.
write
(
b
"
\
n
"
)
out
.
write
(
"
\
n
"
)
out
.
write
(
b
"
\
n
"
)
# ----------------------------------------
# ----------------------------------------
# XPickler is Pickler that tries to save objects stably
# XPickler is Pickler that tries to save objects stably
...
@@ -309,13 +317,15 @@ class DumpReader(object):
...
@@ -309,13 +317,15 @@ class DumpReader(object):
# .lineno - line number position in read stream
# .lineno - line number position in read stream
def
__init__
(
self
,
r
):
def
__init__
(
self
,
r
):
self
.
_r
=
r
# type (BinaryIO) -> None
self
.
_r
=
r
# type: BinaryIO
self
.
_line
=
None
# last read line
self
.
_line
=
None
# last read line
self
.
lineno
=
0
self
.
lineno
=
0
def
_readline
(
self
):
def
_readline
(
self
):
# type: () -> Optional[bytes]
l
=
self
.
_r
.
readline
()
l
=
self
.
_r
.
readline
()
if
l
==
''
:
if
l
==
b
''
:
self
.
_line
=
None
self
.
_line
=
None
return
None
# EOF
return
None
# EOF
...
@@ -326,11 +336,17 @@ class DumpReader(object):
...
@@ -326,11 +336,17 @@ class DumpReader(object):
# report a problem found around currently-read line
# report a problem found around currently-read line
def
_badline
(
self
,
msg
):
def
_badline
(
self
,
msg
):
raise
RuntimeError
(
"%s+%d: invalid line: %s (%r)"
%
(
_ioname
(
self
.
_r
),
self
.
lineno
,
msg
,
self
.
_line
))
# type: (str) -> NoReturn
raise
RuntimeError
(
"%s+%d: invalid line: %s (%r)"
%
(
_ioname
(
self
.
_r
),
self
.
lineno
,
msg
,
# BBB produce same output in python 2 and 3
self
.
_line
.
decode
()
if
six
.
PY3
else
self
.
_line
.
encode
()))
# readtxn reads one transaction record from input stream and returns
# readtxn reads one transaction record from input stream and returns
# Transaction instance or None at EOF.
# Transaction instance or None at EOF.
def
readtxn
(
self
):
def
readtxn
(
self
):
# type: () -> Optional[Transaction]
# header
# header
l
=
self
.
_readline
()
l
=
self
.
_readline
()
if
l
is
None
:
if
l
is
None
:
...
@@ -356,7 +372,7 @@ class DumpReader(object):
...
@@ -356,7 +372,7 @@ class DumpReader(object):
objv
=
[]
objv
=
[]
while
1
:
while
1
:
l
=
self
.
_readline
()
l
=
self
.
_readline
()
if
l
==
''
:
if
l
==
b
''
:
break
# empty line - end of transaction
break
# empty line - end of transaction
if
l
is
None
or
not
l
.
startswith
(
b'obj '
):
if
l
is
None
or
not
l
.
startswith
(
b'obj '
):
...
@@ -366,7 +382,7 @@ class DumpReader(object):
...
@@ -366,7 +382,7 @@ class DumpReader(object):
if
m
is
None
:
if
m
is
None
:
self
.
_badline
(
'invalid obj entry'
)
self
.
_badline
(
'invalid obj entry'
)
obj
=
None
#
will be Object*
obj
=
None
#
type: Optional[Union[ObjectDelete, ObjectCopy, ObjectData]]
oid
=
fromhex
(
m
.
group
(
'oid'
))
oid
=
fromhex
(
m
.
group
(
'oid'
))
from_
=
m
.
group
(
'from'
)
from_
=
m
.
group
(
'from'
)
...
@@ -380,10 +396,10 @@ class DumpReader(object):
...
@@ -380,10 +396,10 @@ class DumpReader(object):
else
:
else
:
size
=
int
(
m
.
group
(
'size'
))
size
=
int
(
m
.
group
(
'size'
))
hashfunc
=
m
.
group
(
'hashfunc'
)
hashfunc
=
m
.
group
(
'hashfunc'
)
.
decode
()
hashok
=
fromhex
(
m
.
group
(
'hash'
))
hashok
=
fromhex
(
m
.
group
(
'hash'
))
hashonly
=
m
.
group
(
'hashonly'
)
is
not
None
hashonly
=
m
.
group
(
'hashonly'
)
is
not
None
data
=
None
# see vvv
data
=
None
#
type: Optional[Union[HashOnly, bytes]] #
see vvv
hcls
=
hashRegistry
.
get
(
hashfunc
)
hcls
=
hashRegistry
.
get
(
hashfunc
)
if
hcls
is
None
:
if
hcls
is
None
:
...
@@ -399,7 +415,7 @@ class DumpReader(object):
...
@@ -399,7 +415,7 @@ class DumpReader(object):
chunk
=
self
.
_r
.
read
(
n
)
chunk
=
self
.
_r
.
read
(
n
)
data
+=
chunk
data
+=
chunk
n
-=
len
(
chunk
)
n
-=
len
(
chunk
)
self
.
lineno
+=
data
.
count
(
'
\
n
'
)
self
.
lineno
+=
data
.
count
(
b
'
\
n
'
)
self
.
_line
=
None
self
.
_line
=
None
if
data
[
-
1
:]
!=
b'
\
n
'
:
if
data
[
-
1
:]
!=
b'
\
n
'
:
raise
RuntimeError
(
'%s+%d: no LF after obj data'
%
(
_ioname
(
self
.
_r
),
self
.
lineno
))
raise
RuntimeError
(
'%s+%d: no LF after obj data'
%
(
_ioname
(
self
.
_r
),
self
.
lineno
))
...
@@ -460,13 +476,14 @@ class Transaction(object):
...
@@ -460,13 +476,14 @@ class Transaction(object):
# zdump returns text representation of a record in zodbdump format.
# zdump returns text representation of a record in zodbdump format.
def
zdump
(
self
):
def
zdump
(
self
):
z
=
'txn %s %s
\
n
'
%
(
ashex
(
self
.
tid
),
qq
(
self
.
status
))
# type: () -> bytes
z
+=
'user %s
\
n
'
%
qq
(
self
.
user
)
z
=
b'txn %s %s
\
n
'
%
(
ashex
(
self
.
tid
).
encode
(),
qq
(
self
.
status
).
encode
())
z
+=
'description %s
\
n
'
%
qq
(
self
.
description
)
z
+=
b'user %s
\
n
'
%
qq
(
self
.
user
).
encode
()
z
+=
'extension %s
\
n
'
%
qq
(
self
.
extension_bytes
)
z
+=
b'description %s
\
n
'
%
qq
(
self
.
description
).
encode
()
z
+=
b'extension %s
\
n
'
%
qq
(
self
.
extension_bytes
).
encode
()
for
obj
in
self
.
objv
:
for
obj
in
self
.
objv
:
z
+=
obj
.
zdump
()
z
+=
obj
.
zdump
()
z
+=
'
\
n
'
z
+=
b
'
\
n
'
return
z
return
z
...
@@ -483,7 +500,8 @@ class ObjectDelete(Object):
...
@@ -483,7 +500,8 @@ class ObjectDelete(Object):
super
(
ObjectDelete
,
self
).
__init__
(
oid
)
super
(
ObjectDelete
,
self
).
__init__
(
oid
)
def
zdump
(
self
):
def
zdump
(
self
):
return
'obj %s delete
\
n
'
%
(
ashex
(
self
.
oid
))
# type: () -> bytes
return
b'obj %s delete
\
n
'
%
(
ashex
(
self
.
oid
).
encode
())
# ObjectCopy represents object data copy.
# ObjectCopy represents object data copy.
class
ObjectCopy
(
Object
):
class
ObjectCopy
(
Object
):
...
@@ -493,7 +511,8 @@ class ObjectCopy(Object):
...
@@ -493,7 +511,8 @@ class ObjectCopy(Object):
self
.
copy_from
=
copy_from
self
.
copy_from
=
copy_from
def
zdump
(
self
):
def
zdump
(
self
):
return
'obj %s from %s
\
n
'
%
(
ashex
(
self
.
oid
),
ashex
(
self
.
copy_from
))
# type: () -> bytes
return
b'obj %s from %s
\
n
'
%
(
ashex
(
self
.
oid
).
encode
(),
ashex
(
self
.
copy_from
).
encode
())
# ObjectData represents record with object data.
# ObjectData represents record with object data.
class
ObjectData
(
Object
):
class
ObjectData
(
Object
):
...
@@ -507,19 +526,20 @@ class ObjectData(Object):
...
@@ -507,19 +526,20 @@ class ObjectData(Object):
self
.
hash_
=
hash_
self
.
hash_
=
hash_
def
zdump
(
self
):
def
zdump
(
self
):
# type: () -> bytes
data
=
self
.
data
data
=
self
.
data
hashonly
=
isinstance
(
data
,
HashOnly
)
hashonly
=
isinstance
(
data
,
HashOnly
)
if
hashonly
:
if
hashonly
:
size
=
data
.
size
size
=
data
.
size
else
:
else
:
size
=
len
(
data
)
size
=
len
(
data
)
z
=
'obj %s %d %s:%s'
%
(
ashex
(
self
.
oid
),
size
,
self
.
hashfunc
,
ashex
(
self
.
hash_
))
z
=
b'obj %s %d %s:%s'
%
(
ashex
(
self
.
oid
).
encode
(),
size
,
self
.
hashfunc
.
encode
(),
ashex
(
self
.
hash_
).
encode
(
))
if
hashonly
:
if
hashonly
:
z
+=
' -'
z
+=
b
' -'
else
:
else
:
z
+=
'
\
n
'
z
+=
b
'
\
n
'
z
+=
data
z
+=
data
z
+=
'
\
n
'
z
+=
b
'
\
n
'
return
z
return
z
# HashOnly indicated that this ObjectData record contains only hash and does not contain object data.
# HashOnly indicated that this ObjectData record contains only hash and does not contain object data.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment