zodbcommit, zodbrestore: Robustify copy handling
When zodbdump input says to copy an object, we first load that object. However if object does not exist loadBefore raises POSKeyError, and when object at copied-from revision was deleted loadBefore returns None.
-> Handle that explicitly to provide failure details to the user, so that instead of cryptic
=== RUN TestLoad/δstart=0285cbac75555580
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 133, in <module>
main()
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main
return command_module.main(argv)
File "<decorator-gen-6>", line 2, in main
File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 103, in _
return f(*argv, **kw)
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 94, in main
zodbrestore(stor, asbinstream(sys.stdin), _)
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 43, in zodbrestore
zodbcommit(stor, at, txn)
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 122, in zodbcommit
_()
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 91, in _
data, _, _ = stor.loadBefore(obj.oid, p64(u64(obj.copy_from)+1))
TypeError: 'NoneType' object is not iterable
xtesting.go:483: /tmp/demo009767458/δ0285cbac75555580/δ.fs: zpyrestore: exit status 1
it fails with something more understandable:
=== RUN TestLoad/δstart=0285cbac75555580
Traceback (most recent call last):
File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
"__main__", fname, loader, pkg_name)
File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 133, in <module>
main()
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodb.py", line 129, in main
return command_module.main(argv)
File "<decorator-gen-6>", line 2, in main
File "/home/kirr/src/tools/go/pygolang/golang/__init__.py", line 103, in _
return f(*argv, **kw)
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 94, in main
zodbrestore(stor, asbinstream(sys.stdin), _)
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbrestore.py", line 43, in zodbrestore
zodbcommit(stor, at, txn)
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 129, in zodbcommit
_()
File "/home/kirr/src/wendelin/z/zodbtools/zodbtools/zodbcommit.py", line 97, in _
(stor.__name__, ashex(obj.oid), ashex(obj.copy_from)))
ValueError: /tmp/demo358030847/δ0285cbac75555580/δ.fs: object 0000000000000003: copy from @0285cbac70a3d733: no data
xtesting.go:483: /tmp/demo358030847/δ0285cbac75555580/δ.fs: zpyrestore: exit status 1
For the implementation it would be easier to use loadAt (https://github.com/zopefoundation/ZODB/pull/323), but we don't have that yet.
/cc @jerome