#!/usr/bin/python -Es
# Copyright (C) 2014-2015 Red Hat
# AUTHOR: Dan Walsh <dwalsh@redhat.com>
# see file 'COPYING' for use and warranty information
#
# atomic is a tool for managing Atomic Systems and Containers
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License as
#    published by the Free Software Foundation; either version 2 of
#    the License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#    02110-1301 USA.
#
#
import sys, os
import argparse
import gettext
import docker
import subprocess
import Atomic

PROGNAME="atomic"
gettext.bindtextdomain(PROGNAME, "/usr/share/locale")
gettext.textdomain(PROGNAME)
try:
    gettext.install(PROGNAME,
                    unicode=True,
                    codeset = 'utf-8')
except TypeError:
    # Failover to python3 install
    gettext.install(PROGNAME,
                    codeset = 'utf-8')
except IOError:
    import builtins
    builtins.__dict__['_'] = str

class HelpByDefaultArgumentParser(argparse.ArgumentParser):
    def error(self, message):
        self.print_help()
        sys.stderr.write('\nerror: %s\n' % message)
        sys.exit(2)

if __name__ == '__main__':
    atomic=Atomic.Atomic()
    parser = HelpByDefaultArgumentParser(description=atomic.help())
    subparser = parser.add_subparsers(help=_("commands"))

    if os.path.exists("/usr/bin/rpm-ostree"):
        hostp = subparser.add_parser("host",help=_("execute Atomic host commands"))
        host_subparser = hostp.add_subparsers(help=_("host commands"))
        rollbackp = host_subparser.add_parser("rollback", help=_("switch to alternate tree at boot"))
        rollbackp.set_defaults(func=atomic.host_rollback)
        rollbackp.add_argument("-r", "--reboot", dest="reboot",
                               action="store_true",
                               help=_("initiate a reboot after rollback is prepared"))

        statusp = host_subparser.add_parser("status", help=_("list information about all deployments"))
        statusp.set_defaults(func=atomic.host_status)
        upgradep = host_subparser.add_parser("upgrade", help=_("upgrade to the latest Atomic tree if one is available"))
        upgradep.set_defaults(func=atomic.host_upgrade)
        upgradep.add_argument("-r", "--reboot", dest="reboot",
                              action="store_true",
                              help=_("if an upgrade is available, reboot after deployment is complete"))

    infop = subparser.add_parser("info",
                                 help=_("display label information about an image"),
                                 epilog="atomic info attempts to read and display the LABEL information about an image")
    infop.set_defaults(func=atomic.info)
    infop.add_argument("image", help=_("container image"))

    installp = subparser.add_parser("install",
                                    help=_("execute container image install method"),
                                    epilog="atomic install attempts to read the LABEL INSTALL field in the image, if it does not exist atomic will just pull the image on to your machine.  You could add a LABEL INSTALL command to your Dockerfile like: 'LABEL INSTALL %s'" % atomic.print_install() )

    installp.set_defaults(func=atomic.install)
    installp.add_argument("-n", "--name", dest="name",
                      default=None,
                      help=_("name of container"))
    installp.add_argument("image", help=_("container image"))
    installp.add_argument("args", nargs=argparse.REMAINDER,
                          help=_("Additional arguments appended to the image uninstall method"))

    mountp = subparser.add_parser("mount",
                                  help=_("mount container image to a specified "
                                    "directory"),
                                  epilog="atomic mount attempts to mount a "
                                    "container image to a specified directory so "
                                    "that its contents may be inspected.")
    mountp.set_defaults(func=atomic.mount)
    mountp.add_argument("-o", "--options", dest="options",
                      default="",
                      help=_("comma-separated list of mount options, "
                          "defaults are 'ro,nodev,nosuid'"),)
    mountp.add_argument("image", help=_("image/container id"))
    mountp.add_argument("mountpoint", help=_("filesystem location to mount the image/container"))

    stopp = subparser.add_parser("stop",
                                help=_("execute container image stop method"),
                                 epilog="atomic will just stop the container if it is running, if image does not specify LABEL STOP\n")
    stopp.set_defaults(func=atomic.stop)
    stopp.add_argument("-n", "--name", dest="name",
                      default=None,
                      help=_("name of container"))
    stopp.add_argument("image", help=_("container image"))

    runp = subparser.add_parser("run",
                                help=_("execute container image run method"),
                                epilog="atomic run defaults to the following command, if image does not specify LABEL run\n'%s'" % atomic.print_run() )
    runp.set_defaults(func=atomic.run)
    runp.add_argument("-n", "--name", dest="name",
                      default=None,
                      help=_("name of container"))
    runp.add_argument("--spc",
                      default=False,
                      action="store_true",
                      help=_("use super privileged container mode: '%s'") % atomic.print_spc() )
    runp.add_argument("image", help=_("container image"))
    runp.add_argument("command", nargs=argparse.REMAINDER,
                      help=_("command to execute within the container"))

    uninstallp = subparser.add_parser("uninstall",
                                      help=_("execute container image uninstall method"),
                                                                          epilog="atomic uninstall attempts to read the LABEL UNINSTALL field in the image, if it does not exist atomic will remove the image from your machine.  You could add a LABEL UNINSTALL command to your Dockerfile like: 'LABEL UNINSTALL %s'" % atomic.print_uninstall() )

    uninstallp.set_defaults(func=atomic.uninstall)
    uninstallp.add_argument("-n", "--name", dest="name",
                            default=None,
                            help=_("name of container"))
    uninstallp.add_argument("-f", "--force",
                            default=False,
                            dest="force",
                            action="store_true",
                            help=_("remove all containers based on this image"))
    uninstallp.add_argument("image", help=_("container image"))
    uninstallp.add_argument("args", nargs=argparse.REMAINDER,
                          help=_("Additional arguments appended to the image install method"))

    unmountp = subparser.add_parser("unmount",
                                   help=_("unmount container image"),
                                   epilog="atomic unmount will unmount a "
                                   "container image previously mounted with "
                                   "atomic mount")
    unmountp.set_defaults(func=atomic.unmount)
    unmountp.add_argument("mountpoint", help=_("filesystem location of image/container to be unmounted"))

    updatep = subparser.add_parser("update",help=_("pull latest container image from repository"), epilog="atomic update downloads the latest container image. If a previously container based on this image exists, the container will continue to use the old image.  Use --force to remove the container.")

    updatep.set_defaults(func=atomic.update)
    updatep.add_argument("-f", "--force",
                         default=False,
                         dest="force",
                         action="store_true",
                         help=_("remove all containers based on this image"))
    updatep.add_argument("image", help=_("container image"))

    uploadp = subparser.add_parser("upload",help=_("upload latest image to repository"), epilog="atomic upload uploads the latest specified image.")

    uploadp.set_defaults(func=atomic.upload)
    uploadp.add_argument("--pulp",
                         default=False,
                         action="store_true",
                         help=_("upload image using pulp"))
    config = Atomic.PulpConfig().config()
    uploadp.add_argument("--verify_ssl",
                         default=config["verify_ssl"],
                         action="store_true",
                         help=_("verify ssl of registry"))
    uploadp.add_argument("-U", "--url",
                         dest="url",
                         default=config["url"],
                         help=_("Url for remote registry"))
    uploadp.add_argument("-u", "--username",
                         default=config["username"],
                         dest="username",
                         help=_("Username for remote registry"))
    uploadp.add_argument("-p", "--password",
                         default=config["password"],
                         dest="password",
                         help=_("Password for remote registry"))
    uploadp.add_argument("image", help=_("container image"))

    versionp = subparser.add_parser("version",
                                    help=_("display image 'Name Version Release' label"),
                                    epilog="atomic version displays the image version information, if it is provided")
    versionp.add_argument("-r", "--recurse",
                         default=False,
                         dest="recurse",
                         action="store_true",
                         help=_("recurse through all layers"))
    versionp.set_defaults(func=atomic.print_version)
    versionp.add_argument("image", help=_("container image"))

    verifyp = subparser.add_parser("verify",
                                    help=_("verify image is fully updated"),
                                    epilog="atomic verify checks whether there is a newer image available and scans through all layers to see if any of the sublayers have a new version available")
    verifyp.set_defaults(func=atomic.print_verify)
    verifyp.add_argument("image", help=_("container image"))

    try:
        args = parser.parse_args()
        atomic.set_args(args)
        sys.exit(args.func())
    except ValueError as e:
        sys.stderr.write("%s\n" % str(e))
        sys.exit(1)
    except IOError as e:
        sys.stderr.write("%s\n" % str(e))
        sys.exit(1)
    except KeyboardInterrupt:
        sys.exit(0)
    except subprocess.CalledProcessError as e:
        sys.stderr.write("\n")
        sys.exit(e.returncode)
    except docker.errors.DockerException as e:
        sys.stderr.write("%s\n" % str(e))
        sys.exit(1)
