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
6 years ago
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
This diff is collapsed.
Click to expand it.
zodbtools/help.py
View file @
347ea21d
...
...
@@ -19,10 +19,15 @@
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
try
:
from
typing
import
Tuple
except
ImportError
:
pass
from
collections
import
OrderedDict
# topic_name -> (topic_summary, topic_help)
topic_dict
=
OrderedDict
()
topic_dict
=
OrderedDict
()
# type: OrderedDict[str, Tuple[str, str]]
help_zurl
=
"""
\
Almost every zodb command works with a database.
...
...
This diff is collapsed.
Click to expand it.
zodbtools/test/test_commit.py
View file @
347ea21d
...
...
@@ -41,8 +41,8 @@ def test_zodbcommit(zext):
# commit some transactions via zodbcommit and verify if storage dump gives
# what is expected.
t1
=
Transaction
(
z64
,
' '
,
b'user name'
,
b'description ...'
,
zext
(
dumps
({
'a'
:
'b'
},
_protocol
)),
[
ObjectData
(
p64
(
1
),
b'data1'
,
'sha1'
,
sha1
(
'data1'
)),
ObjectData
(
p64
(
2
),
b'data2'
,
'sha1'
,
sha1
(
'data2'
))])
ObjectData
(
p64
(
1
),
b'data1'
,
'sha1'
,
sha1
(
b
'data1'
)),
ObjectData
(
p64
(
2
),
b'data2'
,
'sha1'
,
sha1
(
b
'data2'
))])
t1
.
tid
=
zodbcommit
(
stor
,
head
,
t1
)
...
...
@@ -56,7 +56,7 @@ def test_zodbcommit(zext):
zodbdump
(
stor
,
p64
(
u64
(
head
)
+
1
),
None
,
out
=
buf
)
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,
# not referencing previous transaction via backpointer.
...
...
This diff is collapsed.
Click to expand it.
zodbtools/test/test_dump.py
View file @
347ea21d
...
...
@@ -21,14 +21,14 @@ from zodbtools.zodbdump import (
zodbdump
,
DumpReader
,
Transaction
,
ObjectDelete
,
ObjectCopy
,
ObjectData
,
HashOnly
)
from
zodbtools.util
import
fromhex
from
ZODB.FileStorage
import
FileStorage
from
ZODB.utils
import
p64
from
cStringIO
import
String
IO
from
io
import
Bytes
IO
from
os.path
import
dirname
from
zodbtools.test.testutil
import
zext_supported
from
pytest
import
raises
,
xfail
from
pytest
import
raises
# verify zodbdump output against golden
def
test_zodbdump
(
zext
):
...
...
@@ -39,7 +39,7 @@ def test_zodbdump(zext):
with
open
(
'%s/testdata/1%s.zdump.ok'
%
(
tdir
,
zkind
))
as
f
:
dumpok
=
f
.
read
()
out
=
String
IO
()
out
=
Bytes
IO
()
zodbdump
(
stor
,
None
,
None
,
out
=
out
)
assert
out
.
getvalue
()
==
dumpok
...
...
@@ -69,10 +69,10 @@ extension "qqq"
"""
r
=
DumpReader
(
String
IO
(
in_
))
r
=
DumpReader
(
Bytes
IO
(
in_
))
t1
=
r
.
readtxn
()
assert
isinstance
(
t1
,
Transaction
)
assert
t1
.
tid
==
'0123456789abcdef'
.
decode
(
'hex
'
)
assert
t1
.
tid
==
fromhex
(
'0123456789abcdef
'
)
assert
t1
.
user
==
b'my name'
assert
t1
.
description
==
b'o la-la...'
assert
t1
.
extension_bytes
==
b'zzz123 def'
...
...
@@ -83,29 +83,29 @@ extension "qqq"
_
=
t1
.
objv
[
1
]
assert
isinstance
(
_
,
ObjectCopy
)
assert
_
.
oid
==
p64
(
2
)
assert
_
.
copy_from
==
'0123456789abcdee'
.
decode
(
'hex
'
)
assert
_
.
copy_from
==
fromhex
(
'0123456789abcdee
'
)
_
=
t1
.
objv
[
2
]
assert
isinstance
(
_
,
ObjectData
)
assert
_
.
oid
==
p64
(
3
)
assert
_
.
data
==
HashOnly
(
54
)
assert
_
.
hashfunc
==
'adler32'
assert
_
.
hash_
==
'01234567'
.
decode
(
'hex
'
)
assert
_
.
hash_
==
fromhex
(
'01234567
'
)
_
=
t1
.
objv
[
3
]
assert
isinstance
(
_
,
ObjectData
)
assert
_
.
oid
==
p64
(
4
)
assert
_
.
data
==
b'ZZZZ'
assert
_
.
hashfunc
==
'sha1'
assert
_
.
hash_
==
'9865d483bc5a94f2e30056fc256ed3066af54d04'
.
decode
(
'hex
'
)
assert
_
.
hash_
==
fromhex
(
'9865d483bc5a94f2e30056fc256ed3066af54d04
'
)
_
=
t1
.
objv
[
4
]
assert
isinstance
(
_
,
ObjectData
)
assert
_
.
oid
==
p64
(
5
)
assert
_
.
data
==
b'ABC
\
n
\
n
DEF!'
assert
_
.
hashfunc
==
'crc32'
assert
_
.
hash_
==
'52fdeac5'
.
decode
(
'hex
'
)
assert
_
.
hash_
==
fromhex
(
'52fdeac5
'
)
t2
=
r
.
readtxn
()
assert
isinstance
(
t2
,
Transaction
)
assert
t2
.
tid
==
'0123456789abcdf0'
.
decode
(
'hex
'
)
assert
t2
.
tid
==
fromhex
(
'0123456789abcdf0
'
)
assert
t2
.
user
==
b'author2'
assert
t2
.
description
==
b'zzz'
assert
t2
.
extension_bytes
==
b'qqq'
...
...
@@ -113,11 +113,11 @@ extension "qqq"
assert
r
.
readtxn
()
==
None
z
=
''
.
join
([
_
.
zdump
()
for
_
in
(
t1
,
t2
)])
z
=
b
''
.
join
([
_
.
zdump
()
for
_
in
(
t1
,
t2
)])
assert
z
==
in_
# unknown hash function
r
=
DumpReader
(
StringIO
(
"""
\
r
=
DumpReader
(
BytesIO
(
b
"""
\
txn 0000000000000000 " "
user ""
description ""
...
...
@@ -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 -')"""
,)
# data integrity error
r
=
DumpReader
(
StringIO
(
"""
\
r
=
DumpReader
(
BytesIO
(
b
"""
\
txn 0000000000000000 " "
user ""
description ""
...
...
@@ -141,4 +141,4 @@ hello
"""
))
with
raises
(
RuntimeError
)
as
exc
:
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
This diff is collapsed.
Click to expand it.
zodbtools/test/test_zodb.py
View file @
347ea21d
...
...
@@ -22,7 +22,9 @@ try:
from
unittest
import
mock
except
ImportError
:
# 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
...
...
This diff is collapsed.
Click to expand it.
zodbtools/util.py
View file @
347ea21d
...
...
@@ -18,20 +18,32 @@
# See COPYING file for full licensing terms.
# 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
zodburi
import
zodburi
# type: ignore
from
six.moves.urllib_parse
import
urlsplit
,
urlunsplit
from
zlib
import
crc32
,
adler32
from
ZODB.TimeStamp
import
TimeStamp
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
):
return
s
.
encode
(
'hex'
)
# type: (bytes) -> str
return
codecs
.
encode
(
s
,
'hex'
).
decode
()
def
fromhex
(
s
):
# type: (Union[str,bytes]) -> bytes
return
codecs
.
decode
(
s
,
'hex'
)
def
sha1
(
data
):
# type: (bytes) -> bytes
m
=
hashlib
.
sha1
()
m
.
update
(
data
)
return
m
.
digest
()
...
...
@@ -53,6 +65,8 @@ def nextitem(it):
# objects of a IStorageTransactionInformation
def
txnobjv
(
txn
):
# type: (Any) -> Iterable[Any]
# XXX type ?
objv
=
[]
for
obj
in
txn
:
assert
obj
.
tid
==
txn
.
tid
...
...
@@ -72,6 +86,7 @@ class TidRangeInvalid(ValueError):
def
parse_tid
(
tid_string
,
raw_only
=
False
):
# type: (str, bool) -> bytes
"""Try to parse `tid_string` as a time and returns the
corresponding raw TID.
If `tid_string` cannot be parsed as a time, assume it was
...
...
@@ -121,19 +136,16 @@ def parse_tid(tid_string, raw_only=False):
#
# see `zodb help tidrange` for accepted tidrange syntax.
def
parse_tidrange
(
tidrange
):
# type: (str) -> Tuple[Optional[bytes], Optional[bytes]]
try
:
tidmin
,
tidmax
=
tidrange
.
split
(
".."
)
except
ValueError
:
# not exactly 2 parts in between ".."
raise
TidRangeInvalid
(
tidrange
)
if
tidmin
:
tidmin
=
parse_tid
(
tidmin
)
if
tidmax
:
tidmax
=
parse_tid
(
tidmax
)
# empty tid means -inf / +inf respectively
# ( 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
...
...
@@ -169,12 +181,15 @@ class NullHasher:
digest_size
=
1
def
update
(
self
,
data
):
# type: (bytes) -> None
pass
def
digest
(
self
):
# type: () -> bytes
return
b'
\
0
'
def
hexdigest
(
self
):
# type: () -> str
return
"00"
# adler32 in hashlib interface
...
...
@@ -183,15 +198,19 @@ class Adler32Hasher:
digest_size
=
4
def
__init__
(
self
):
self
.
_h
=
adler32
(
''
)
# type: () -> None
self
.
_h
=
adler32
(
b''
)
def
update
(
self
,
data
):
# type: (bytes) -> None
self
.
_h
=
adler32
(
data
,
self
.
_h
)
def
digest
(
self
):
# type: () -> bytes
return
struct
.
pack
(
'>I'
,
self
.
_h
&
0xffffffff
)
def
hexdigest
(
self
):
# type: () -> str
return
'%08x'
%
(
self
.
_h
&
0xffffffff
)
# crc32 in hashlib interface
...
...
@@ -200,15 +219,19 @@ class CRC32Hasher:
digest_size
=
4
def
__init__
(
self
):
self
.
_h
=
crc32
(
''
)
# type: () -> None
self
.
_h
=
crc32
(
b''
)
def
update
(
self
,
data
):
# type: (bytes) -> None
self
.
_h
=
crc32
(
data
,
self
.
_h
)
def
digest
(
self
):
# type: () -> bytes
return
struct
.
pack
(
'>I'
,
self
.
_h
&
0xffffffff
)
def
hexdigest
(
self
):
# type: () -> str
return
'%08x'
%
(
self
.
_h
&
0xffffffff
)
# {} name -> hasher
...
...
@@ -219,4 +242,4 @@ hashRegistry = {
"sha1"
:
hashlib
.
sha1
,
"sha256"
:
hashlib
.
sha256
,
"sha512"
:
hashlib
.
sha512
,
}
}
# type: Mapping[str, Callable] # XXX "Callable" is a bit too wide typing
This diff is collapsed.
Click to expand it.
zodbtools/zodbanalyze.py
View file @
347ea21d
...
...
@@ -9,7 +9,7 @@ from __future__ import print_function
import
sys
import
os
import
getopt
from
six.moves
import
dbm_gnu
as
dbm
from
six.moves
import
dbm_gnu
as
dbm
# type: ignore
import
tempfile
import
shutil
from
ZODB.FileStorage
import
FileIterator
,
packed_version
...
...
This diff is collapsed.
Click to expand it.
zodbtools/zodbdump.py
View file @
347ea21d
...
...
@@ -53,6 +53,10 @@ TODO also protect txn record by hash.
"""
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
,
\
storageFromURL
,
hashRegistry
from
ZODB._compat
import
loads
,
_protocol
,
BytesIO
...
...
@@ -61,6 +65,7 @@ from zodbpickle.slowpickle import Pickler as pyPickler
from
ZODB.interfaces
import
IStorageTransactionInformation
from
zope.interface
import
implementer
import
six
import
sys
import
logging
import
re
...
...
@@ -92,50 +97,53 @@ def txn_raw_extension(stor, txn):
return
serializeext
(
txn
.
extension
)
# 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.
# 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
):
# XXX .status not covered by IStorageTransactionInformation
# 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
),
qq
(
txn
.
user
),
qq
(
txn
.
description
),
qq
(
txn_raw_extension
(
stor
,
txn
))
))
qq
(
txn_raw_extension
(
stor
,
txn
))
))
.
encode
())
objv
=
txnobjv
(
txn
)
for
obj
in
objv
:
entry
=
"obj %s "
%
ashex
(
obj
.
oid
)
entry
=
b"obj %s "
%
ashex
(
obj
.
oid
).
encode
(
)
write_data
=
False
if
obj
.
data
is
None
:
entry
+=
"delete"
entry
+=
b
"delete"
# was undo and data taken from obj.data_txn
elif
obj
.
data_txn
is
not
None
:
entry
+=
"from %s"
%
ashex
(
obj
.
data_txn
)
entry
+=
b
"from %s"
%
ashex
(
obj
.
data_txn
)
else
:
# 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
if
six
.
PY2
:
entry
=
entry
.
encode
(
'utf-8'
)
out
.
write
(
entry
)
if
write_data
:
if
hashonly
:
out
.
write
(
" -"
)
out
.
write
(
b
" -"
)
else
:
out
.
write
(
"
\
n
"
)
out
.
write
(
obj
.
data
)
out
.
write
(
b
"
\
n
"
)
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
...
...
@@ -309,13 +317,15 @@ class DumpReader(object):
# .lineno - line number position in read stream
def
__init__
(
self
,
r
):
self
.
_r
=
r
# type (BinaryIO) -> None
self
.
_r
=
r
# type: BinaryIO
self
.
_line
=
None
# last read line
self
.
lineno
=
0
def
_readline
(
self
):
# type: () -> Optional[bytes]
l
=
self
.
_r
.
readline
()
if
l
==
''
:
if
l
==
b
''
:
self
.
_line
=
None
return
None
# EOF
...
...
@@ -326,11 +336,17 @@ class DumpReader(object):
# report a problem found around currently-read line
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
# Transaction instance or None at EOF.
def
readtxn
(
self
):
# type: () -> Optional[Transaction]
# header
l
=
self
.
_readline
()
if
l
is
None
:
...
...
@@ -356,7 +372,7 @@ class DumpReader(object):
objv
=
[]
while
1
:
l
=
self
.
_readline
()
if
l
==
''
:
if
l
==
b
''
:
break
# empty line - end of transaction
if
l
is
None
or
not
l
.
startswith
(
b'obj '
):
...
...
@@ -366,7 +382,7 @@ class DumpReader(object):
if
m
is
None
:
self
.
_badline
(
'invalid obj entry'
)
obj
=
None
#
will be Object*
obj
=
None
#
type: Optional[Union[ObjectDelete, ObjectCopy, ObjectData]]
oid
=
fromhex
(
m
.
group
(
'oid'
))
from_
=
m
.
group
(
'from'
)
...
...
@@ -380,10 +396,10 @@ class DumpReader(object):
else
:
size
=
int
(
m
.
group
(
'size'
))
hashfunc
=
m
.
group
(
'hashfunc'
)
hashfunc
=
m
.
group
(
'hashfunc'
)
.
decode
()
hashok
=
fromhex
(
m
.
group
(
'hash'
))
hashonly
=
m
.
group
(
'hashonly'
)
is
not
None
data
=
None
# see vvv
data
=
None
#
type: Optional[Union[HashOnly, bytes]] #
see vvv
hcls
=
hashRegistry
.
get
(
hashfunc
)
if
hcls
is
None
:
...
...
@@ -399,7 +415,7 @@ class DumpReader(object):
chunk
=
self
.
_r
.
read
(
n
)
data
+=
chunk
n
-=
len
(
chunk
)
self
.
lineno
+=
data
.
count
(
'
\
n
'
)
self
.
lineno
+=
data
.
count
(
b
'
\
n
'
)
self
.
_line
=
None
if
data
[
-
1
:]
!=
b'
\
n
'
:
raise
RuntimeError
(
'%s+%d: no LF after obj data'
%
(
_ioname
(
self
.
_r
),
self
.
lineno
))
...
...
@@ -460,13 +476,14 @@ class Transaction(object):
# zdump returns text representation of a record in zodbdump format.
def
zdump
(
self
):
z
=
'txn %s %s
\
n
'
%
(
ashex
(
self
.
tid
),
qq
(
self
.
status
))
z
+=
'user %s
\
n
'
%
qq
(
self
.
user
)
z
+=
'description %s
\
n
'
%
qq
(
self
.
description
)
z
+=
'extension %s
\
n
'
%
qq
(
self
.
extension_bytes
)
# type: () -> bytes
z
=
b'txn %s %s
\
n
'
%
(
ashex
(
self
.
tid
).
encode
(),
qq
(
self
.
status
).
encode
())
z
+=
b'user %s
\
n
'
%
qq
(
self
.
user
).
encode
()
z
+=
b'description %s
\
n
'
%
qq
(
self
.
description
).
encode
()
z
+=
b'extension %s
\
n
'
%
qq
(
self
.
extension_bytes
).
encode
()
for
obj
in
self
.
objv
:
z
+=
obj
.
zdump
()
z
+=
'
\
n
'
z
+=
b
'
\
n
'
return
z
...
...
@@ -483,7 +500,8 @@ class ObjectDelete(Object):
super
(
ObjectDelete
,
self
).
__init__
(
oid
)
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.
class
ObjectCopy
(
Object
):
...
...
@@ -493,7 +511,8 @@ class ObjectCopy(Object):
self
.
copy_from
=
copy_from
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.
class
ObjectData
(
Object
):
...
...
@@ -507,19 +526,20 @@ class ObjectData(Object):
self
.
hash_
=
hash_
def
zdump
(
self
):
# type: () -> bytes
data
=
self
.
data
hashonly
=
isinstance
(
data
,
HashOnly
)
if
hashonly
:
size
=
data
.
size
else
:
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
:
z
+=
' -'
z
+=
b
' -'
else
:
z
+=
'
\
n
'
z
+=
b
'
\
n
'
z
+=
data
z
+=
'
\
n
'
z
+=
b
'
\
n
'
return
z
# HashOnly indicated that this ObjectData record contains only hash and does not contain object data.
...
...
This diff is collapsed.
Click to expand it.
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