#!/usr/bin/python -u
#
# Copyright (c) 2008--2013 Red Hat, Inc.
# Copyright (c) 2011 SUSE LLC
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
#

LOCK = None

import shutil
import sys
import os
import socket
from optparse import OptionParser


def systemExit(code, msg=None):
    "Exit with a code and optional message(s). Saved a few lines of code."
    sys.stderr.write(str(msg)+'\n')
    sys.exit(code)

try:
    from rhn import rhnLockfile
    from spacewalk.common.rhnConfig import CFG, initCFG
    from spacewalk.common.rhnTB import fetchTraceback
    from spacewalk.satellite_tools import reposync
except KeyboardInterrupt:
    systemExit(0, "\nUser interrupted process.")
except ImportError:
    systemExit(1, "Unable to find code tree.\n"
               "Path not correct? " + ', '.join(sys.path))

def releaseLOCK():
    global LOCK
    if LOCK:
        LOCK.release()
        LOCK = None

def clear_interrupted_downloads():
    initCFG('server.satellite')
    pkgdir = os.path.join(CFG.MOUNT_POINT, CFG.PREPENDED_DIR, '1', 'stage')
    if os.path.exists(pkgdir):
        shutil.rmtree(pkgdir)

def main():

    # quick check to see if you are a super-user.
    if os.getuid() != 0:
        systemExit(8, 'ERROR: must be root to execute.')

    global LOCK
    try:
        LOCK = rhnLockfile.Lockfile('/var/run/spacewalk-repo-sync.pid')
    except rhnLockfile.LockfileLockedException:
        systemExit(1, "ERROR: attempting to run more than one instance of "
                      "spacewalk-repo-sync Exiting.")

    parser = OptionParser()
    parser.add_option('-u', '--url', action='store', dest='url',
                      help='The url to sync')
    parser.add_option('-c', '--channel', action='store',
                      dest='channel_label',
                      help='The label of the channel to sync packages to')
    parser.add_option('-t', '--type', action='store', dest='repo_type',
                      help='The type of repo, currently only "yum" is supported',
                      default='yum')
    parser.add_option('-f', '--fail', action='store_true', dest='fail',
                      default=False,
                      help="If a package import fails, fail the entire operation")
    parser.add_option('-q', '--quiet', action='store_true', dest='quiet',
                      default=False, help="Print no output, still logs output")
    parser.add_option('-n', '--non-interactive', action='store_true',
                      dest='noninteractive', default=False,
                      help="Do not ask anything, use default answers")
    parser.add_option('-i', '--include', action='callback',
                      callback=reposync.set_filter_opt, type='str', nargs=1,
                      dest='filters', default=[],
                      help="List of included packages")
    parser.add_option('-e', '--exclude', action='callback',
                      callback=reposync.set_filter_opt,
                      type='str', nargs=1, dest='filters', default=[],
                      help="List of excluded packages")
    parser.add_option('', '--no-errata', action='store_true', dest='no_errata',
                      default=False, help="Do not sync errata")
    parser.add_option('', '--sync-kickstart', action='store_true', dest='sync_kickstart',
                      default=False, help="Sync kickstartable tree")
    parser.add_option('-Y', '--deep-verify', action='store_true',
                      dest='deep_verify', default=False,
                      help='Do not use cached package checksums')

    (options, args) = parser.parse_args()

    if not options.channel_label:
        systemExit(1, "--channel must be specified")

    # Automatically remove all the remains inside of /var/spacewalk/packages/1/stage
    # Yum does not seem to handle download resumes properly. This can lead to
    # errors like:
    #
    # > Repo Sync Errors: (50, u'checksums did not match 326a904c2fbd7a0e20033c87fc84ebba6b24d937 vs
    # > afd8c60d7908b2b0e2d95ad0b333920aea9892eb', 'Invalid information uploaded to the server')
    clear_interrupted_downloads()

    sync = reposync.RepoSync(channel_label=options.channel_label,
                      repo_type=options.repo_type,
                      url=options.url,
                      fail=options.fail,
                      quiet=options.quiet,
                      noninteractive=options.noninteractive,
                      filters=options.filters,
                      deep_verify=options.deep_verify,
                      no_errata=options.no_errata,
                      sync_kickstart=options.sync_kickstart)
    sync.sync()
    releaseLOCK()
    return 0


if __name__ == '__main__':
    try:
        sys.exit(abs(main() or 0))
    except KeyboardInterrupt:
        systemExit(0, "\nUser interrupted process.")
    except SystemExit, e:
        releaseLOCK()
        sys.exit(e.code)
    except Exception, e:
        releaseLOCK()
        raise
