Commit 984cfe22 authored by Kirill Smelkov's avatar Kirill Smelkov

zodb - Tool to drive them all

We already have 3 commands in zodbtools suite (zodbanalyze, zodbdump &
zodbcmp) and this is going to grow. And it was already noted some time
ago with TODO (in 66946b8d) that we need only one command driver to
invoke everything.

So do it: introduce `zodb` command which can invoke other subcommands
and show general help or help for subcommand or a topic.

The structure is modelled after `git` and `go` commands. Help topics
are for now empty but we'll add one help topic in the next patch.
parent 9e4305b8
...@@ -8,6 +8,6 @@ scripts anymore. So we are here: ...@@ -8,6 +8,6 @@ scripts anymore. So we are here:
__ https://github.com/zopefoundation/ZODB/pull/128#issuecomment-260970932 __ https://github.com/zopefoundation/ZODB/pull/128#issuecomment-260970932
- `zodbanalyze` - analyze FileStorage or repozo deltafs usage. - `zodb analyze` - analyze FileStorage or repozo deltafs usage.
- `zodbcmp` - compare content of two ZODB databases bit-to-bit. - `zodb cmp` - compare content of two ZODB databases bit-to-bit.
- `zodbdump` - dump content of a ZODB database. - `zodb dump` - dump content of a ZODB database.
...@@ -21,15 +21,7 @@ setup( ...@@ -21,15 +21,7 @@ setup(
packages = find_packages(), packages = find_packages(),
install_requires = ['ZODB'], install_requires = ['ZODB'],
# TODO have only one console program "zodb" and then it is entry_points= {'console_scripts': ['zodb = zodbtools.zodb:main']},
# zodb cmd ...
# zodb dump ...
entry_points= {'console_scripts': [
'zodbanalyze = zodbtools.zodbanalyze:main',
'zodbcmp = zodbtools.zodbcmp:main',
'zodbdump = zodbtools.zodbdump:main',
]
},
classifiers = [_.strip() for _ in """\ classifiers = [_.strip() for _ in """\
Development Status :: 3 - Alpha Development Status :: 3 - Alpha
......
# zodbtools - help topics
# Copyright (C) 2017 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Open Source Initiative approved licenses and Convey
# the resulting work. Corresponding source of such a combination shall include
# the source code for all other software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
from collections import OrderedDict
# topic_name -> (topic_summary, topic_help)
topic_dict = OrderedDict()
#!/usr/bin/env python
# Copyright (C) 2017 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Open Source Initiative approved licenses and Convey
# the resulting work. Corresponding source of such a combination shall include
# the source code for all other software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
"""Zodb is a driver program for invoking zodbtools subcommands"""
from __future__ import print_function
from zodbtools import help as help_module
import getopt
import importlib
import sys
# command_name -> command_module
command_dict = {}
def register_command(cmdname):
command_module = importlib.import_module('zodbtools.zodb' + cmdname)
command_dict[cmdname] = command_module
for _ in ('analyze', 'cmp', 'dump'):
register_command(_)
def usage(out):
print("""\
Zodb is a tool for managing ZODB databases.
Usage:
zodb command [arguments]
The commands are:
""", file=out)
cmdv = command_dict.keys()
cmdv.sort()
for cmd in cmdv:
cmd_module = command_dict[cmd]
print(" %-11s %s" % (cmd, cmd_module.summary), file=out)
print("""\
Use "zodb help [command]" for more information about a command.
Additional help topics:
""", file=out)
# NOTE no sorting here - topic_dict is pre-ordered
for topic, (topic_summary, _) in help_module.topic_dict.items():
print(" %-11s %s" % (topic, topic_summary), file=out)
print("""\
Use "zodb help [topic]" for more information about that topic.
""", file=out)
# help shows general help or help for a command/topic
def help(argv):
if len(argv) < 2: # help topic ...
usage(sys.stderr)
sys.exit(2)
topic = argv[1]
# topic can either be a command name or a help topic
if topic in command_dict:
command = command_dict[topic]
command.usage(sys.stdout)
sys.exit(0)
if topic in help_module.topic_dict:
_, topic_help = help_module.topic_dict[topic]
print(topic_help)
sys.exit(0)
print("Unknown help topic `%s`. Run 'zodb help'." % topic, file=sys.stderr)
sys.exit(2)
def main():
try:
optv, argv = getopt.getopt(sys.argv[1:], "h", ["help"])
except getopt.GetoptError as e:
print(e, file=sys.stderr)
usage(sys.stderr)
sys.exit(2)
for opt, _ in optv:
if opt in ("-h", "--help"):
usage(sys.stdout)
sys.exit(0)
if len(argv) < 1:
usage(sys.stderr)
sys.exit(2)
command = argv[0]
# help on a topic
if command=="help":
return help(argv)
# run subcommand
command_module = command_dict.get(command)
if command_module is None:
print('zodb: unknown subcommand "%s"' % command, file=sys.stderr)
print("Run 'zodb help' for usage.", file=sys.stderr)
sys.exit(2)
return command_module.main(argv)
if __name__ == '__main__':
main()
#!/usr/bin/env python
# Copyright (C) 2002-2017 Zope Foundation + Nexedi + Contributors # Copyright (C) 2002-2017 Zope Foundation + Nexedi + Contributors
# See LICENSE-ZPL.txt for full licensing terms. # See LICENSE-ZPL.txt for full licensing terms.
...@@ -237,17 +236,18 @@ Note: ...@@ -237,17 +236,18 @@ Note:
Input deltafs file should be uncompressed. Input deltafs file should be uncompressed.
""" """
summary = "analyze FileStorage or repozo deltafs usage"
def usage(stream, msg=None): def usage(stream, msg=None):
if msg: if msg:
print >>stream, msg print >>stream, msg
print >>stream print >>stream
program = os.path.basename(sys.argv[0]) print >>stream, __doc__ % {"program": "zodb analyze"}
print >>stream, __doc__ % {"program": program}
def main(): def main(argv):
try: try:
opts, args = getopt.getopt(sys.argv[1:], opts, args = getopt.getopt(argv[1:],
'hcd', ['help', 'csv', 'dbm']) 'hcd', ['help', 'csv', 'dbm'])
path = args[0] path = args[0]
except (getopt.GetoptError, IndexError), msg: except (getopt.GetoptError, IndexError), msg:
...@@ -275,6 +275,3 @@ def main(): ...@@ -275,6 +275,3 @@ def main():
return h return h
FileStorageFormatter._read_data_header = _read_data_header FileStorageFormatter._read_data_header = _read_data_header
report(analyze(path, use_dbm, delta_fs), csv) report(analyze(path, use_dbm, delta_fs), csv)
if __name__ == "__main__":
main()
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Copyright (C) 2016-2017 Nexedi SA and Contributors. # Copyright (C) 2016-2017 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com> # Kirill Smelkov <kirr@nexedi.com>
...@@ -111,9 +110,11 @@ import ZODB.config ...@@ -111,9 +110,11 @@ import ZODB.config
import sys, getopt import sys, getopt
import traceback import traceback
summary = "compare two ZODB databases"
def usage(out): def usage(out):
print("""\ print("""\
Usage: zodbcmp [OPTIONS] <storage1> <storage2> [tidmin..tidmax] Usage: zodb cmp [OPTIONS] <storage1> <storage2> [tidmin..tidmax]
Compare two ZODB databases. Compare two ZODB databases.
<storageX> is a file with ZConfig-based storage definition, e.g. <storageX> is a file with ZConfig-based storage definition, e.g.
...@@ -130,11 +131,11 @@ Options: ...@@ -130,11 +131,11 @@ Options:
-h --help show this help -h --help show this help
""", file=out) """, file=out)
def main2(): def main2(argv):
verbose = False verbose = False
try: try:
optv, argv = getopt.getopt(sys.argv[1:], "hv", ["help", "verbose"]) optv, argv = getopt.getopt(argv[1:], "hv", ["help", "verbose"])
except getopt.GetoptError as e: except getopt.GetoptError as e:
print(e, file=sys.stderr) print(e, file=sys.stderr)
usage(sys.stderr) usage(sys.stderr)
...@@ -168,14 +169,11 @@ def main2(): ...@@ -168,14 +169,11 @@ def main2():
zcmp = storcmp(stor1, stor2, tidmin, tidmax, verbose) zcmp = storcmp(stor1, stor2, tidmin, tidmax, verbose)
sys.exit(1 if zcmp else 0) sys.exit(1 if zcmp else 0)
def main(): def main(argv):
try: try:
main2() main2(argv)
except SystemExit: except SystemExit:
raise # this was sys.exit() call, not an error raise # this was sys.exit() call, not an error
except: except:
traceback.print_exc() traceback.print_exc()
sys.exit(2) sys.exit(2)
if __name__ == '__main__':
main()
#!/usr/bin/env python
# Copyright (C) 2016-2017 Nexedi SA and Contributors. # Copyright (C) 2016-2017 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com> # Kirill Smelkov <kirr@nexedi.com>
# #
...@@ -71,9 +70,11 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False): ...@@ -71,9 +70,11 @@ def zodbdump(stor, tidmin, tidmax, hashonly=False):
import ZODB.config import ZODB.config
import sys, getopt import sys, getopt
summary = "dump content of a ZODB database"
def usage(out): def usage(out):
print("""\ print("""\
Usage: zodbdump [OPTIONS] <storage> [tidmin..tidmax] Usage: zodb dump [OPTIONS] <storage> [tidmin..tidmax]
Dump content of a ZODB database. Dump content of a ZODB database.
<storage> is a file with ZConfig-based storage definition, e.g. <storage> is a file with ZConfig-based storage definition, e.g.
...@@ -90,11 +91,11 @@ Options: ...@@ -90,11 +91,11 @@ Options:
-h --help show this help -h --help show this help
""", file=out) """, file=out)
def main(): def main(argv):
hashonly = False hashonly = False
try: try:
optv, argv = getopt.getopt(sys.argv[1:], "h", ["help", "hashonly"]) optv, argv = getopt.getopt(argv[1:], "h", ["help", "hashonly"])
except getopt.GetoptError as e: except getopt.GetoptError as e:
print(e, file=sys.stderr) print(e, file=sys.stderr)
usage(sys.stderr) usage(sys.stderr)
...@@ -125,6 +126,3 @@ def main(): ...@@ -125,6 +126,3 @@ def main():
stor = ZODB.config.storageFromFile(open(storconf, 'r')) stor = ZODB.config.storageFromFile(open(storconf, 'r'))
zodbdump(stor, tidmin, tidmax, hashonly) zodbdump(stor, tidmin, tidmax, hashonly)
if __name__ == '__main__':
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment