#!/usr/bin/python
# Copyright (C) 2013 HashBackup, LLC.
#
# Example implementation of a shell destination that behaves like the
# built-in Dir destination.
#
# Shell destinations are used to connect to external storage not
# supported with a native destination, where sending, getting, and
# removing files can be done using a Unix command.
#
# Shell destinations report success or failure with their exit code.  If
# a non-zero exit code is returned (failure), the command is retried
# with exponential backoff like all other destinations.
#
# Example dest.conf for this shell destination:
#
#   destname mydest
#   type shell
#   run python ~jim/hbdev/exdirshell.py --dir ~jim/hbdev/hb2 --command
#
# To make parsing easier, a --command option has been added to the
# end.  The command line is processed by the shell, so things like
# $PASSWORD, shell functions, and quoting work fine.
#
# A command and arguments will be added to the run command line by HB:
#
#   noop
#
#      exit 0; this is used once per worker during startup ensure the
#      command is runnable
#      
#   send pathname filename
#
#      send the local file indicated by pathname to the remote
#      destination and store it as filename.  Note that filename may
#      already exist on the remote, and HB expects send to overwrite
#      the existing file.  This happens when archives are packed, with
#      recrypt, and when sending dest.db.
#
#      Some remote protocols, like rsync, automatically prevent
#      partial files on the remote by copying first into a temp file,
#      then renaming the temp file to the real filename.  If your
#      remote protocol doesn't do this automatically (ftp doesn't for
#      example), it's a good idea, when possible, to send the file as
#      filename.tmp, then rename filename.tmp to filename, overwriting
#      filename if it already exists.  If the remote cannot rename
#      over an existing file, you can send as filename.tmp, delete
#      filename, then rename filename.tmp to filename.  This runs the
#      slight risk of a failure after the delete, which would have to
#      be corrected manually by renaming filename.tmp on the remote.
#      It will be corrected automatically on the next backup by
#      resending the file.
#
#   get pathname filename
#
#      fetch the remote file indicated by filename and store it in the
#      local file pathname
#
#   rm filename
#
#      remove the remote file indicated by filename.  If the file
#      doesn't exist, no error should occur.

from argparse import ArgumentParser
import os
import sys

def main(argv):

    parser = ArgumentParser()
    parser.add_argument('--debug', action="store_true", default=False)
    parser.add_argument('--dir', action='store', required=True)
    parser.add_argument('--command', action='store', required=True)
    parser.add_argument('arg', action='store', nargs='*')
    opt = parser.parse_args(argv)

    if opt.debug:
        print 'HB command:', opt.command, opt.arg

    if opt.command == 'noop':
        return 0

    if opt.command == 'rm':
        rempath = os.path.join(opt.dir, opt.arg[0])
        return os.system('rm -f %s' % rempath)

    rempath = os.path.join(opt.dir, opt.arg[1])
    locpath = opt.arg[0]

    if opt.command == 'send':
        return os.system('cp %s %s.tmp && mv %s.tmp %s' % (locpath, rempath, rempath, rempath))

    if opt.command == 'get':
        return os.system('cp %s %s.tmp && mv %s.tmp %s' % (rempath, locpath, locpath, locpath))

if __name__ == '__main__':
    rc = main(sys.argv[1:])
    sys.exit(rc)
