#!/usr/bin/python -t
#
# mic-image-convertor : Converts raw/kvm or vmdk image to live image
#
# Copyright 2009, Intel Inc.
#
# 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; version 2 of the License.
#
# 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 Library 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

import os
import os.path
import sys
import time
import optparse
import logging
import shutil
import subprocess
import string
import glob
import rpm
import re

import mic.appcreate as appcreate
import mic.imgcreate as imgcreate
import mic.imgconvert as imgconvert

import signal
def sig_interrupt(signum=None, frame=None):
    raise imgcreate.CreatorError('Canceled by ^C.')
signal.signal(signal.SIGINT, sig_interrupt)

try:
    import mic.__version__
    version = mic.__version__.version
except:
    version = 'unknown'

class Usage(Exception):
    def __init__(self, msg = None, no_error = False):
        Exception.__init__(self, msg, no_error)

def parse_options(args):
    parser = optparse.OptionParser(version = version)

    commonopt = optparse.OptionGroup(parser, "General options",
                                  "These options define the source and destination images.")
    commonopt.add_option("-F", "--source-format", type="string", dest="srcformat",
                    help="Source image format, possible values are: raw, vmdk or vdi (default: automatically detect image type).")
    commonopt.add_option("-I", "--source-image", type="string", dest="srcimg",
                    help="Source image which was created by mic-image-creator or an image file system.")
    commonopt.add_option("-T", "--target-format", type="string", dest="dstformat",
                    help="Target image format, possible values are: livecd and liveusb")

    parser.add_option_group(commonopt)

    # options related to the config of your system
    sysopt = optparse.OptionGroup(parser, "System directory options",
                                  "These options define directories used on your system for creating the live image")
    sysopt.add_option("-t", "--tmpdir", type="string",
                      dest="tmpdir", default="/var/tmp",
                      help="Temporary directory to use (default: /var/tmp)")
    sysopt.add_option("-o", "--outdir", type="string",
                      dest="outdir", default=None,
                      help="Output directory to use (default: current work dir)")
    sysopt.add_option("-P", "--prefix", type="string",
                      dest="prefix", default=None,
                      help="Image name prefix (default: meego)")
    sysopt.add_option("-S", "--suffix", type="string",
                      dest="suffix", default=None,
                      help="Image name suffix (default: date stamp)")
    parser.add_option_group(sysopt)

    # options related to live USB
    liveusbopt = optparse.OptionGroup(parser, "Live USB options",
                                  "These options are for creating the live USB image")
    liveusbopt.add_option("-i", "--interactive", action="store_true",
                      dest="interactive", default=False,
                      help="Directly write into a USB disk.")
    liveusbopt.add_option("", "--fstype", type="string",
                      dest="fstype", default="vfat",
                      help="File system type for live USB image, ext3 or vfat, the default is vfat.")
    liveusbopt.add_option("", "--overlay-size-mb", type="int",
                      dest="overlaysizemb", default=64,
                      help="Overlay size in MB as unit, it means how size changes you can save in your live USB disk.")
    parser.add_option_group(liveusbopt)

    # Don't compress the image.
    sysopt.add_option("-s", "--skip-compression", action="store_true", dest="skip_compression",
                      default=False, help=optparse.SUPPRESS_HELP)
    parser.add_option("", "--skip-minimize", action="store_true", dest="skip_minimize",
                      default=False, help=optparse.SUPPRESS_HELP)

    # Start a shell in the chroot for post-configuration.
    parser.add_option("-l", "--shell", action="store_true", dest="give_shell",
                      help=optparse.SUPPRESS_HELP)

    imgcreate.setup_logging(parser)

    (options, args) = parser.parse_args()

    if not options.srcimg or not os.path.exists(options.srcimg):
        raise Usage("Source image file path must be provided.")

    if not options.srcformat:
        options.srcformat = imgcreate.get_image_type(options.srcimg)
    if options.srcformat not in ("raw", "vmdk", "vdi", "livecd", "liveusb", "fs", "ext3fsimg"):
        raise Usage("Source image format '%s' not supported " % options.srcformat)

    if options.dstformat not in (None, "livecd", "liveusb"):
        raise Usage("Target image format '%s' not supported " % options.dstformat)

    return options

def main():
    try:
        options = parse_options(sys.argv[1:])
    except Usage, (msg, no_error):
        if no_error:
            out = sys.stdout
            ret = 0
        else:
            out = sys.stderr
            ret = 2
        if msg:
            print >> out, msg
        return ret

    if os.geteuid () != 0:
        print >> sys.stderr, "You must run mic-image-convertor as root"
        return 1

    imgname_pattern = "converted-from-%s" % options.srcformat

    if not options.prefix:
        options.prefix = "meego"
    if not options.suffix:
        options.suffix = time.strftime("%Y%m%d%H%M")
    name = imgcreate.build_name(imgname_pattern, "%s-" % options.prefix, suffix=options.suffix)

    destdir = "."
    if options.outdir:
        destdir=options.outdir

    if options.srcformat not in ("raw", "vmdk", "vdi", "livecd", "liveusb", "fs", "ext3fsimg"):
        print "You have to specify image format as raw, vmdk, vdi, livecd or liveusb"
        return 1

    fs_label = imgcreate.build_name(imgname_pattern,
                                    "%s-" % options.prefix,
                                    maxlen = imgcreate.FSLABEL_MAXLEN,
                                    suffix = "%s-%s" %(os.uname()[4], time.strftime("%Y%m%d%H%M")))

    logging.info("Using label '%s' and name '%s'" % (fs_label, name))
    try:
        if options.dstformat == "liveusb" and not options.interactive:
            convertor = imgconvert.LiveUSBImageConvertor(None, name, fs_label)
            convertor.fstype = options.fstype
            if convertor.fstype != "vfat" and convertor.fstype != "ext3":
                print >> sys.stderr, "Error: file system type for live USB image  must be vfat or ext3"
                return 2
        else:
            convertor = imgconvert.LiveImageConvertor(None, name, fs_label)
        convertor.overlaysizemb = options.overlaysizemb
        if options.dstformat == "liveusb":
            if convertor.overlaysizemb < 0:
                print >> sys.stderr, "Error: Overlay size must be greater than 0"
                return 2
    except imgcreate.CreatorError, e:
        logging.error("Error creating image : %s" % e)
        return 1

    convertor.skip_compression = options.skip_compression
    convertor.skip_minimize = options.skip_minimize
    convertor.setup_temp_dirs(options.tmpdir)
    convertor.set_source_image(options.srcimg, options.srcformat)
    base_on = None
    if options.srcformat in ("livecd", "liveusb", "ext3fsimg"):
        base_on = options.srcimg

    try:
        convertor.mount(base_on, None)
        convertor.install()
        convertor.configure()
        convertor.launch_shell(options.give_shell)
        convertor.unmount()
        convertor.package(destdir)
    except imgcreate.CreatorError, e:
        logging.error("Error creating Live CD : %s" % e)
        return 1
    finally:
        convertor.print_outimage_info()
        outimage = convertor.outimage
        convertor.cleanup()
        if options.dstformat == "liveusb" and options.interactive:
                mypath = os.path.abspath(sys.argv[0])
                mypath = os.path.dirname(mypath)
                isotodisk = mypath + "/mic-livecd-iso-to-disk"
                if not os.path.isfile(isotodisk):
                    logging.error("Error mic-livecd-iso-to-disk doesn't exist")
                    return 1
                args = [isotodisk, "--reset-mbr", "--overlay-size-mb", "%d" % options.overlaysizemb, outimage[0]]
                ret = subprocess.call(args)
                if ret != 0:
                    logging.error("Unable to create Live USB : '%s' exited with error (%d)" % (string.join(args, " "), ret))
                    return 1

    return 0

if __name__ == "__main__":
    sys.exit(main())
