Source code for pdiffcopy.cli
# Command line interface for pdiffcopy.
#
# Author: Peter Odding <peter@peterodding.com>
# Last Change: March 6, 2020
# URL: https://pdiffcopy.readthedocs.io
"""
Usage: pdiffcopy [OPTIONS] [SOURCE, TARGET]
Synchronize large binary data files between Linux servers at blazing speeds
by performing delta transfers and spreading the work over many CPU cores.
One of the SOURCE and TARGET arguments is expected to be the pathname of a
local file and the other argument is expected to be a URL that provides the
location of a remote pdiffcopy server and a remote filename. File data will be
read from SOURCE and written to TARGET.
If no positional arguments are given the server is started.
Supported options:
-b, --block-size=BYTES
Customize the block size of the delta transfer. Can be a plain
integer number (bytes) or an expression like 5K, 1MiB, etc.
-m, --hash-method=NAME
Customize the hash method of the delta transfer (defaults to 'sha1'
but supports all hash methods provided by the Python hashlib module).
-W, --whole-file
Disable the delta transfer algorithm (skips computing
of hashing and downloads all blocks unconditionally).
-c, --concurrency=COUNT
Change the number of parallel block hash / copy operations.
-n, --dry-run
Scan for differences between the source and target file and report the
similarity index, but don't write any changed blocks to the target.
-B, --benchmark=COUNT
Evaluate the effectiveness of delta transfer by mutating the TARGET
file (which must be a local file) and resynchronizing its contents.
This process is repeated COUNT times, with varying similarity.
At the end an overview is printed.
-l, --listen=ADDRESS
Listen on the specified IP:PORT or PORT.
-v, --verbose
Increase logging verbosity (can be repeated).
-q, --quiet
Decrease logging verbosity (can be repeated).
-h, --help
Show this message and exit.
"""
# Standard library modules.
import getopt
import logging
import sys
# External dependencies.
import coloredlogs
from humanfriendly import parse_size
from humanfriendly.terminal import warning, usage
# Modules included in our package.
from pdiffcopy.exceptions import DependencyError
# Initialize a logger for this module.
logger = logging.getLogger(__name__)
[docs]def main():
"""The command line interface."""
# Initialize logging to the terminal and system log.
coloredlogs.install(syslog=True)
# Parse the command line options.
try:
options, arguments = getopt.gnu_getopt(
sys.argv[1:],
"b:m:Wc:B:l:nvqh",
[
"block-size=",
"hash-method=",
"whole-file",
"concurrency=",
"benchmark=",
"listen=",
"dry-run",
"verbose",
"quiet",
"help",
],
)
except Exception as e:
warning("Error: %s", e)
sys.exit(1)
# Command line option defaults.
client_opts = {}
server_opts = {}
# Map parsed options to variables.
for option, value in options:
if option in ("-b", "--block-size"):
client_opts["block_size"] = parse_size(value)
elif option in ("-m", "--hash-method"):
client_opts["hash_method"] = value
elif option in ("-W", "--whole-file"):
client_opts["delta_transfer"] = False
elif option in ("-c", "--concurrency"):
client_opts["concurrency"] = int(value)
server_opts["concurrency"] = int(value)
elif option in ("-B", "--benchmark"):
client_opts["benchmark"] = int(value)
elif option in ("-l", "--listen"):
server_opts["address"] = value
elif option in ("-n", "--dry-run"):
client_opts["dry_run"] = True
elif option in ("-v", "--verbose"):
coloredlogs.increase_verbosity()
elif option in ("-q", "--quiet"):
coloredlogs.decrease_verbosity()
elif option in ("-h", "--help"):
usage(__doc__)
sys.exit(0)
# Execute the requested action.
try:
if arguments:
if len(arguments) != 2:
warning("Error: Two positional arguments expected!")
sys.exit(1)
client_opts['source'] = arguments[0]
client_opts['target'] = arguments[1]
run_client(**client_opts)
else:
run_server(**server_opts)
except Exception:
logger.exception("Program terminating due to exception!")
sys.exit(1)
[docs]def run_client(**options):
"""Run the client program."""
try:
from pdiffcopy.client import Client
Client(**options).synchronize()
except ImportError:
raise DependencyError(
"""
Installation requirements seem to be missing! You can
install them using 'pip install pdiffcopy[client]'.
"""
)
[docs]def run_server(**options):
"""Run the server program."""
try:
from pdiffcopy.server import start_server
return start_server(**options)
except ImportError:
raise DependencyError(
"""
Installation requirements seem to be missing! You can
install them using 'pip install pdiffcopy[server]'.
"""
)