#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# 
# Hay que guardar una copia de este fichero en el svn en
# org.gvsig.desktop/org.gvsig.desktop.installer/src/main/packaging
#
import sys
import os
import os.path
import fnmatch
import shutil
import zipfile
import stat
import getopt
from os.path import dirname
import shutil
from os import system
import ConfigParser
import StringIO
import re
import urllib2
import time

DEBUG = False
VERBOSE = False
SEARCH_VERSIONS = list()

class Platform:
  def __init__(self,os,arch,exe,onlinefamily=None, portableSufix=""):
    self.osfamily = None
    self.osname = None
    self.osversion = None
    self.os = os
    self.arch = arch
    self.exe_extension = exe
    self.portableSufix = portableSufix
    if "_" in self.os:
      ss=self.os.split("_")
      self.osfamily = ss[0]
      if len(ss)>1:
        self.osname = ss[1]
        if len(ss)>2:
          self.osversion= ss[2]
    else:
      self.osfamily = self.os
    if onlinefamily == None:
      self.onlinefamily = self.osfamily
    else:
      self.onlinefamily = onlinefamily

  def getOS(self):
    return self.os

  def getOSFamily(self):
    return self.osfamily

  def getOSFamilyForOnlineInstaller(self):
    return self.onlinefamily

  def getOSName(self):
    return self.osname

  def getOSVersion(self):
    return self.osversion

  def getArch(self):
    return self.arch

  def getExeExtension(self):
    return self.exe_extension

  def getPortableSufix(self):
    return self.portableSufix

platforms = (
  Platform("lin","x86_64",".run"),
  Platform("win","x86_64",".exe"),
  #Platform("darwin_macos_10.11","x86_64",".run",onlinefamily="lin", portableSufix=".app"),
  #Platform("lin","x86",".run"),
  #Platform("win","x86",".exe"),
  #Platform("lin_ubuntu_14.04","x86_64",".run",onlinefamily="lin"),
  #Platform("lin_ubuntu_14.04","x86",".run",onlinefamily="lin")
)


def log(msg):
  f=open("/tmp/gvspkg.log","a")
  f.write(time.ctime())
  f.write(": ")
  f.write(msg)
  f.write("\n")
  f.close()

def message(msg):
    if VERBOSE:
        print msg
        sys.stdout.flush()
    log(msg)

def msgerror(msg, err=None):
    print "ERROR: ", msg
    log("ERROR: "+msg)
    if err!=None :
      print "ERROR: ", str(err)
      sys.stdout.flush()
      log("ERROR: "+ str(err))


def msgwarn(msg):
    print "WARNING: ", msg
    sys.stdout.flush()
    log("WARNING: "+ msg)

def debug(msg):
    if DEBUG:
        print "DEBUG: ", msg
        sys.stdout.flush()
        log("DEBUG: "+ msg)

def acquire_file(name):
  files = list()
  folder = os.getcwd()
  while folder not in ( None, "", "/"):
    pathname = os.path.join(folder,name)
    if os.path.exists(pathname):
      files.append(pathname)
    folder = os.path.dirname(folder)
  return files

def get_gvspkg_bin_folder():
    files = list()
    if os.environ.get("HOME") != None :
        files.append(os.path.join(os.environ['HOME'],".gvspkg.bin"))
    files.extend( acquire_file(".gvspkg.bin") )
    files.extend( acquire_file("gvspkg.bin") )
    if len(files)<1 :
      return None
    debug( "gvspkg.bin = %s" % files[-1])
    return files[-1]

def search_GVSPKG_ROOT():
  f = get_gvspkg_bin_folder()
  if f==None:
    return None
  return os.path.dirname(f)

RWALL = stat.S_IWOTH | stat.S_IROTH | stat.S_IWUSR | stat.S_IRUSR | stat.S_IWGRP | stat.S_IRGRP
RWXALL = RWALL | stat.S_IXUSR | stat.S_IXOTH | stat.S_IXGRP

VERSION = os.path.basename(os.getcwd())
GVSPKG_ROOT = search_GVSPKG_ROOT()

def getVersion():
    return VERSION

def getSearchVersions():
    vers = list();
    vers.extend(SEARCH_VERSIONS)
    vers.append(VERSION)
    return vers

def getPackagesRoot():
    return GVSPKG_ROOT

def getPool():
    return getPackagesRoot() + "/pool"

def getWeb():
    return getPackagesRoot() + "/web"

def getDist():
    return getPackagesRoot() + "/dists/" +getVersion()

def findfiles(root,filename):
    result=list()
    for wroot, dirs, files in os.walk(root):
        for f in files :
            if fnmatch.fnmatch(f,filename):
                result.append(wroot+"/"+f)
    result.sort()
    return result

def getpackageUrl(path):
  return re.sub(".*/downloads/","http://downloads.gvsig.org/download/",path)

def mychmod(filename, perms):
    try:
        os.chmod(filename,perms)
    except Exception, ex:
        msgwarn("Can't change permissions of file '%s', error %s" % (filename, str(ex)))

def makedirs(path):
    if not os.path.isdir(path) :
      os.makedirs(path)

class Command:

    def __init__(self, args):
        self.args = args
        self.defaultoptions = None

    def load_options(self,filename):
        debug("loading option from %s" % filename)
        if not os.path.isfile(filename):
            debug("filename %s not found" % filename)
            return
        f=file(filename,"r")
        for line in f.readlines():
            line = line.strip()
            if line=="" or line.startswith("#"):
                continue
            if line[-1] == "\n":
                line = line[:-1]
            n = line.find("=")
            if n<0 :
                continue
            cmd = line[:n]
            args = line[n+1:].strip()

            if args != "":
              self.defaultoptions[cmd] = self.defaultoptions.get(cmd,[]) +  args.split(" ")
            debug("add options: %s=%r" % (cmd, args.split(" ")))

        f.close()

    def load_default_options(self):
        if self.defaultoptions != None:
            return
        self.defaultoptions = dict()
        options = list();
        if GVSPKG_ROOT != None:
          rootoptions = os.path.join(GVSPKG_ROOT,"gvspkg.bin/options")
        else:
          rootoptions = None
        if rootoptions != None and os.path.isfile(rootoptions):
            options.append(rootoptions)
        else:
            options.append("~/.gvspkg.bin/options")
        options.extend(acquire_file(".gvspkg.options"))
        options.extend(acquire_file("gvspkg.options"))
        for optionfile in options:
          self.load_options(optionfile)

    def getArgs(self,name):
        self.load_default_options()
        l = list()
        cmd = self.defaultoptions.get(name,None)
        if cmd != None:
          l.extend(cmd)
        l.extend(self.args[1:])
        return l

def isDigit(s):
    if len(s)>1:
        s=s[0]
    return s in ("0","1","2","3","4","5","6","7","8","9")



class PackageInfo(str):
    def __init__(self, filename):
        self._ini = None
        self.filename = filename[:-7]
        self.type = filename[-6:]
        s = os.path.basename(self.filename)
        s = s.split("-")
        #print "## PackageInfo ", repr(s)
        self.gvsig = s[0] + "-" + s[1]
        self.gvsig_version = s[2]
        self.code = s[3]
        try:
  # gvSIG-desktop-1.12.0-com.iver.cit.gvsig.cad-1.12.0-opencadtools-1418-final-all-all-j1_6.gvspkg
  #    0 -  1    -  2   -          3           -  4   - 5          -  6 - 7   - 8 - 9 - 10
  # gvSIG-desktop-1.12.0-com.iver.cit.gvsig.cad-1.12.0-1418-final-all-all-j1_6.gvspkg
  #    0 -  1    -  2   -          3           -  4   - 5  -  6  - 7 - 8 - 9

            if isDigit(s[5]) :
                self.version = s[4]
                self.build = s[5]
                self.status = s[6]
                self.os = s[7]
                self.arch = s[8]
            else:
                self.version = s[4] + "-" + s[5]
                self.build = s[6]
                self.status = s[7]
                self.os = s[8]
                self.arch = s[9]

        except Exception:
            self.build = "0"
            self.status = "unknow"
            self.os = "all"
            self.arch = "all"
        try:
            self.build = int(self.build)
        except:
            pass

    def getCode(self):
        return self.code

    def getOS(self):
        return self.os

    def getArch(self):
        return self.arch

    def getKey(self):
        return self.code+"-"+self.os+"-"+self.arch

    def getFullName(self):
        return os.path.basename(self.filename)

    def getFullVersion(self):
        try:
          r = re.compile("([0-9]+)[.]([0-9]+)[.]([0-9]+)-([a-zA-Z0-9]+)$")
          m = r.match(self.version)
          if m == None:
            clasificador="ZZZZZZZZ"
            r = re.compile("([0-9]+)[.]([0-9]+)[.]([0-9]+)$")
            m = r.match(self.version)
          else:
            clasificador=m.group(4)
          v1=int(m.group(1))
          v2=int(m.group(2))
          v3=int(m.group(3))
          return "%06d.%06d.%06d-%s-%06d" % (v1,v2,v3,clasificador,self.build)
        except:
          if "-" in self.version :
            return "%s-%06d" %(self.version,self.build)
          else:
            return "%s-ZZZZZZZZ-%06d" %(self.version,self.build)

    def getFilename(self):
        return self.filename + "." + self.type

    def isPki(self):
        return self.type.lower() == "gvspki"

    def isPkg(self):
        return self.type.lower() != "gvspki"

    def hasPki(self):
        return os.path.isfile( self.getPkiFilename() )

    def getPkiFilename(self):
        return self.filename + ".gvspki"

    def hasPkg(self):
        return os.path.isfile( self.getPkgFilename() )

    def getPkgFilename(self):
        return self.filename + ".gvspkg"

    def getIniOption(self, name, default=None):
      section = "general"
      ini = self.getIni()
      if ini.has_option(section, name):
        x = ini.get(section, name)
        x = x.replace("\\:", ":")
        return x
      return default

    def getDescription(self):
      return self.getIniOption("description")

    def getCategories(self):
      return self.getIniOption("categories")

    def getName(self):
      return self.getIniOption("name")

    def getOwner(self):
      ini = self.getIni()
      if ini.has_option("general","owner"):
        return ini.get("general","owner")
      return None

    def getUrl(self):
      ini = self.getIni()
      if ini.has_option("general","download-url"):
        return ini.get("general","download-url")
      return None

    def getSourceUrl(self):
      ini = self.getIni()
      if ini.has_option("general","source-url"):
        return ini.get("general","source-url")
      return None

    def getDependencies(self):
      ini = self.getIni()
      if ini.has_option("general","dependencies"):
        return ini.get("general","dependencies")
      return None

    def getType(self):
      ini = self.getIni()
      if ini.has_option("general","type"):
        return ini.get("general","type")
      return None

    def getOfficial(self):
      ini = self.getIni()
      if ini.has_option("general","official"):
        return ini.get("general","official")
      return None

    def getIni(self):
        if self._ini != None:
          return self._ini
        index_path = self.getPkiFilename()
        outputfolder="/tmp/gvspkg.%s" % os.getpid()
        os.mkdir(outputfolder)
        os.system('unzip -q %s -d %s' % (index_path,outputfolder))

        files = findfiles(outputfolder, "package.info")
        if len(files) != 1:
            msgerror("Can't locate package.info in pool '%s'." % (index_path))
            return None

        package_info = files[0]
        self._ini = ConfigParser.ConfigParser()
        f = file(package_info,"r")
        ss = f.read()
        self._ini.readfp(StringIO.StringIO("[general]\n"+ss))
        f.close()
        shutil.rmtree(outputfolder)
        return self._ini

    def match(self, names):
      for name in names:
        if self.getCode() == name:
          return True
        if self.getFullName() == name:
          return True
        if fnmatch.fnmatch(self.getFullName(),name):
          return True
      return False
        
    def __str__(self):
        return self.filename

    def __repr__(self):
        return "filename=%r:gvsig=%r:gvsig_version=%r:code=%r:version=%r:build=%r:status=%r" % (
                self.filename, self.gvsig, self.gvsig_version, self.code, self.version, self.build, self.status )

class IndexList(list):

    def load(self, fname):
        message( "Loading index list from '%s'." % fname)
        f=file(fname,"r")
        lines=f.readlines()
        f.close()
        for line in lines:
          if line[-1] == "\n":
            line = line[:-1]

          info = PackageInfo(line)
          self.append(info)

    def save(self,fname):
        message( "Saving index list from '%s'." % fname)
        f=file(fname,"w")
        for index in self:
          f.write("%s\n" % index.getFilename())
        f.close()
        mychmod(fname,RWALL)

    def build(self, pool, versions):
        message( "Creating index list for version '%s' from '%s'" % (versions, pool) )
        packages=dict()
        for root, dirs, files in os.walk(pool):
            for f in files :
                if f[-7:].lower()  in (".gvspki", ".gvspkg") :
                    fullpath = root+"/"+f
                    info = PackageInfo(fullpath)
                    if info.gvsig == "gvSIG-desktop" and info.gvsig_version in versions :
                        if packages.get(info.getKey()) == None:
                            debug( "build: add    " + repr(info))
                            packages[info.getKey()]=info
                        else:
                            oldinfo = packages[info.getKey()]
                            debug("build: %s %s %s" % ( info.getKey(), oldinfo.getFullVersion(),info.getFullVersion()))
                            if oldinfo.getFullVersion()<info.getFullVersion()  :
                                debug( "build: update "+ repr(oldinfo))
                                packages[info.getKey()]=info
                    else:
                        debug( "build: skip   "+ repr(info))
        self.extend(packages.values())
        self.sort()

def lsi(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("lsi"), "l", ["long-format"])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    long_format=False
    for opt, arg in opts:
        if opt in ("-l", "--long-format"):
            long_format = True
        else:
            assert False, "unhandled option"

    indexes = IndexList()
    indexes.build(getPool(), getSearchVersions())

    for info in indexes:
        if info.hasPki():
            if long_format:
                print "["+os.path.basename(info.getPkiFilename())+"]"
                print "# ", info.getPkiFilename()
                show(["show", os.path.basename(info.getPkiFilename())])
            else:
                print info.getPkiFilename()


def installer_add(cmd,arg1,arg2):
    installer_add_use_zip(cmd,arg1,arg2)

def installer_add_use_zip(cmd,arg1,arg2):
    if cmd == "addjrelin":
      return

    if cmd == "addjrewin":
      return

    if cmd == "addpks":
       zip = zipfile.ZipFile(arg1,"a",zipfile.ZIP_STORED)
       zip.write(arg2,"package.gvspks")
       zip.close()

def installer_add_use_installkit(cmd,arg1,arg2):
    folder = "%s/gvspkg.bin" % GVSPKG_ROOT

    cmd = "%s/installkit %s/main.tcl %s %s %s" % (
        "/mnt/data0/public-files/gvsig-desktop/gvspkg.bin",
        folder,
        cmd,
        arg1,
        arg2
    )
    system(cmd)

def mkinstall(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("mkinstall"), "N:lL:wW:", ["addjrewin", "addjrelin", "jrelin=", "jrewin=", "distribution-name="])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    #print "opts = ",opts
    #print "args = ",args
    addjrelin=False
    addjrewin=False
    jrelin=None
    jrewin=None
    distribution_name = "custom"
    for opt, arg in opts:
        if opt in ("-L", "--jrelin"):
            jrelin = arg
        elif opt in ("-W", "--jrewin"):
            jrewin = arg
        elif opt in ("-l", "--addjrelin"):
            addjrelin = True
        elif opt in ("-w", "--addjrewin"):
            addjrewin = True
        elif opt in ("-N", "--distrinution-name"):
            distribution_name = arg
        else:
            assert False, "unhandled option"


    if len(args) != 2 :
        shorthelp(args)
        sys.exit(4)

    bin_name = args[0]
    gvspks_name = args[1]
    custom_name = bin_name.replace("online", distribution_name)

    if not "online" in bin_name :
        print "gvspkg mkinstall: binary file name must contain 'online'"
        sys.exit(3)

    if addjrelin and addjrewin :
        print "gvspkg mkinstall: only one of addjrelin or addjrewin is allowed."
        sys.exit(4)

    message("Creating %s..." % custom_name)
    shutil.copyfile(bin_name, custom_name)
    mychmod(custom_name,RWALL)
    message("Adding %s..." % gvspks_name)
    installer_add("addpks", custom_name, gvspks_name)

    """
    if addjrelin:
        withjre_name = bin_name.replace("online", distribution_name+"-withjre")
        message("Creating %s..." % withjre_name)
        shutil.copyfile(custom_name, withjre_name)
        mychmod(withjre_name,RWALL)
        message("Adding %s..." % jrelin)
        installer_add("addjrelin", withjre_name, jrelin)


    if addjrewin:
        withjre_name = bin_name.replace("online", distribution_name+"-withjre")
        message("Creating %s..." % withjre_name)
        shutil.copyfile(custom_name, withjre_name)
        mychmod(withjre_name,RWALL)
        message("Adding %s..." % jrewin)
        installer_add("addjrewin", withjre_name, jrewin)
    """

def mks(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("mks"), "ixscI:", ["index-only","include-default-selection", "clear-list", "exclude=", "excludepki=", "excludepkg=", "include="])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    excludes_pkg_by_os = dict()
    for platform in platforms:
      excludes_pkg_by_os[platform.getOS()] = list()
      
    default_selection = None
    index_only = False
    clear_list=False
    includes=list()
    excludes_pki=list()
    excludes_pkg=list()
    for opt, arg in opts:
        if opt in ("-c", "--clear-list"):
            clear_list = True
        elif opt in ("-s", "--include-default-selection"):
            default_selection = "defaultPackages"
        elif opt in ("-x", "--exclude"):
            excludes_pki.append(arg)
            excludes_pkg.append(arg)
        elif opt in ( "--excludepki"):
            excludes_pki.append(arg)
        elif opt in ( "--excludepkg"):
            if ":" in arg:
              osid, arg = arg.split(":")
              excludes_pkg_by_os[osid] = arg
            else:
              excludes_pkg.append(arg)
        elif opt in ( "--include", "-I"):
            if not os.path.isabs(arg) :
              arg = os.path.join(getPool(), arg)
            if arg.endswith(".*"):
              includes.append(PackageInfo(arg[:-2]+".gvspkg"))
              includes.append(PackageInfo(arg[:-2]+".gvspki"))
            else:
              includes.append(PackageInfo(arg))
        elif opt in ("-i", "--index-only"):
            index_only = True
        else:
            assert False, "unhandled option %r" % opt

    if default_selection!=None and  not os.path.isfile(default_selection) :
        msgwarn("No se ha encontrado el fichero %r. la opcion -s/--include-default-selection sera ignorada." % default_selection)
        default_selection = None


    indexes = IndexList()

    packages_txt = getDist() +"/packages.txt"
    packages_gvspki = getDist() +"/packages.gvspki"

    message( "Creating 'packages.gvspki' for version '%s'" % getVersion() + "...")
    if not os.path.exists(getDist()):
        msgerror("Can't locate version folder '%s'." % getDist())
        sys.exit(3)

    if os.path.exists(packages_txt) and not clear_list:
        indexes.load(packages_txt)
    else:
        indexes.build(getPool(), getSearchVersions())
        indexes.save(packages_txt)

    for pkg in includes:
      indexes.append(pkg)

    # El indice de paquetes lleva los paquetes para todas las plataformas y sistemas
    # ya que al conectarnos a el desde el administrador de complementos ya
    # se encarga la aplicacion de seleccionar los correspondientes a la plataforma
    # sobre la que esta rodando gvSIG.
    message( "Writing 'packages.gvspki' to '%s'" % packages_gvspki )
    set = zipfile.ZipFile(packages_gvspki,"w",zipfile.ZIP_STORED)
    for info in indexes:
        if not info.match(excludes_pki):
            debug("Add package '%s'" % info.getPkiFilename())
            try:
                if info.hasPki() :
                    set.write(info.getPkiFilename(), os.path.basename(info.getPkiFilename()))
            except Exception, ex:
                msgerror("Can't add index '%s', error %s" % (info, str(ex)))
        else:
            debug("Exclude package '%s'" % info.getFullName())
    if default_selection != None :
        set.write(default_selection,default_selection)
    set.write("packages.properties","packages.properties")
    set.close()
    mychmod(packages_gvspki,RWALL)

    md5sum(packages_gvspki,packages_gvspki+".md5")
    mychmod(packages_gvspki+".md5",RWALL)

    if not index_only :
      for platform in platforms:
        packages_gvspks = getDist() +"/packages-"+platform.getOS()+"-"+platform.getArch()+".gvspks"
        message( "Writing 'packages-"+platform.getOS()+"-"+platform.getArch()+".gvspks' to '%s'" % packages_gvspks )
        set = zipfile.ZipFile(packages_gvspks,"w",zipfile.ZIP_STORED)
        for info in indexes:
            if not info.match(excludes_pkg) and not info.match(excludes_pkg_by_os[platform.getOS()]):
                try:
                    if info.hasPkg():
                      if info.getOS() in ("all", platform.getOS()) :
                        if info.getArch() in ("all", platform.getArch()) :
                          set.write(info.getPkgFilename(), os.path.basename(info.getPkgFilename()))
                except Exception, ex:
                    msgerror("Can't add package '%s', error %s" % (info, str(ex)))
            else:
                debug("Exclude package '%s'" % info.getFullName())
        if default_selection != None :
            set.write(default_selection,default_selection)
        set.write("packages.properties","packages.properties")
        set.close()
        mychmod(packages_gvspks,RWALL)

        md5sum(packages_gvspks,packages_gvspks+".md5")
        mychmod(packages_gvspks+".md5",RWALL)

    message( "Createds package indexes.\n")

def mkmirror(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("mkmirrot"), "b:", [ "build="])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    build = None
    for opt, arg in opts:
        if opt in ("-b", "--build"):
            build = arg
        else:
            assert False, "unhandled option %r" % opt

    if build == None:
        msgerror("Build number required.")
        sys.exit(3)
    domkmirror( getPackagesRoot(),getVersion(),build)

def linkfile(src,dst):
  if os.path.lexists(dst):
    os.remove(dst)
  os.symlink(src,dst)
  if os.path.lexists(src+".md5") :
    if os.path.lexists(dst+".md5"):
      os.remove(dst+".md5")
    os.symlink(src+".md5",dst+".md5")

def domkmirror(root_src, version, build):
  join = os.path.join

  build = str(build)
  root_target = join(root_src,"mirrors",version+"-"+build,"gvsig-desktop")
  build_src = join(root_src,"dists",version,"builds",build)
  build_target = join(root_target,"dists",version,"builds",build)
  pool_src = join(root_src,"pool")
  pool_target = join(root_target,"pool")

  makedirs(root_target)
  makedirs(build_target)
  makedirs(pool_target)
  files = os.listdir(build_src)
  linkfile(join(build_src,"packages.gvspki"), join(root_target,"dists",version,"packages.gvspki"))
  for f in files:
    f_src = join(build_src,f)
    f_target = join(build_target,f)
    if os.path.isfile(f_src):
      linkfile(f_src,f_target)

  z = zipfile.ZipFile(join(build_src,"packages.gvspki"))
  pkgs = z.namelist()
  for pkgname in pkgs:
    if pkgname!='defaultPackages':
      pkg = PackageInfo(pkgname)
      makedirs(join(root_target,"pool",pkg.getCode()))
      src = join(root_src,"pool",pkg.getCode(),pkg.getPkgFilename())
      target = join(root_target,"pool",pkg.getCode(),pkg.getPkgFilename())
      linkfile(src,target)
  cmd = "cd %s ; find . ! -type d >%s/files.lst" % (root_target, build_target)
  os.system(cmd)

def mkhtml(args):
    def getCode(info):
      return info.code


    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("mkhtml"), "xsc", ["clear-list", "exclude=", "excludepki=", "excludepkg=", "include="])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    index_only = False
    clear_list=False
    includes=list()
    excludes_pki=list()
    excludes_pkg=list()
    for opt, arg in opts:
        if opt in ("-c", "--clear-list"):
            clear_list = True
        elif opt in ("-x", "--exclude"):
            excludes_pki.append(arg)
            excludes_pkg.append(arg)
        elif opt in ( "--excludepki"):
            excludes_pki.append(arg)
        elif opt in ( "--excludepkg"):
            excludes_pkg.append(arg)
        elif opt in ( "--include", "-I"):
            includes.append(PackageInfo(arg))
        else:
            assert False, "unhandled option %r" % opt

    message("Creating html pages...")
    indexes = IndexList()

    packages_txt = getDist() +"/packages.txt"

    if os.path.exists(packages_txt) and not clear_list:
        indexes.load(packages_txt)
    else:
        indexes.build(getPool(), getSearchVersions())
        indexes.save(packages_txt)

    for pkg in includes:
      indexes.append(pkg)

    allpackages = list()
    basepath = getWeb()
    for info in indexes:
        if not ( info.code in excludes_pki or info.getFullName() in excludes_pki ):
            try:
                if info.hasPki() :
                    mkpkihtml(basepath, info)
                    allpackages.append(info)
            except Exception, ex:
                msgerror("Can't create html '%s', error %s" % (info, str(ex)))

    html = '''
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content= "text/html; charset=us-ascii" />
      <title>"%s" package list</title>'''% getVersion() # Title

    html += '''
<!-- estilos para las tablas -->
  <style type="text/css" title="currentStyle">
    @import "css/demo_table.css";
    @import "css/thickbox.css";
    #pkglist{
        width:100%;
        clear:both;
        font-family:Arial,Helvetica,sans-serif;
    }
    #pkgdetails{
        width:600px !important;
        clear:both;
    }
    #pkgdetails table th{
        text-algin:right;
    }
  </style>
</head>'''

    html += '''
<body>
  <h1>%s package list</h1>
  <table id="pkglist" summary="%s package list" width="100%%" >
    <thead>
    <tr>
      <td>Package name</td>
      <td>Version</td>
      <td>O.S.</td>
      <td>Official</td>
      <td>Type</td>
      <td>Owner</td>
    </tr>
    </thead>
    <tbody>'''%(getVersion(),getVersion())

    # sort allpackages
    for item in sorted(allpackages, key=getCode):
      html += '''\n    <tr>
      <td><a class="thickbox" href="%s">%s</a></td>
      <td>%s</td>
      <td>%s</td>
      <td>%s</td>
      <td>%s</td>
      <td>%s</td>
    </tr>\n'''%(
  "../../../web/" + item.getFullName() + ".html?height=400&width=600",
        item.getName(),
  item.version,
  item.os,
  item.getOfficial(),
  item.getType(),
  item.getOwner()
      )
    html += """ </tbody>\n </table>
<!--javascript para la visualizacion de la tabla y carga dinamica del contenido del enlace -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js" type="text/javascript"></script>
<script src="http://datatables.net/release-datatables/media/js/jquery.dataTables.js" type="text/javascript"></script>
<script type="text/javascript" src="js/thickbox-compressed.js"></script>

<!-- inicializacion de la tabla con cosas chachis -->
<script type="text/javascript">
  $(document).ready(function() {
      $('#pkglist').dataTable( {
      "bPaginate": false,
      "bLengthChange": true,
      "bFilter": true,
      "bSort": true,
      "bInfo": true,
      "bAutoWidth": true
    });
 } );
</script>
</body>
</html>"""

    # generate index.html
    try:
      f=file(getDist()+"/web/index.html","w")
      f.write(html)
      f.close()
    except Exception, ex:
      raise ex

    message("html pages createds.\n")


def mkpkihtml(basepath, info):
  html='''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
  <title>%s</title>
  <!-- estilos para las tablas -->
  <style type="text/css" title="currentStyle">
    @import "../dists/%s/web/css/demo_table.css";
    #pkgdetails{
      width:600px;
      clear:both;
    }
    #pkgdetails table th{
        text-algin:right;
    }
  </style>
</head>
<body>\n'''%(info.getIniOption("name"), getVersion())
  html += '  <table id="pkgdetails" summary=%s >\n'%info.getIniOption("name")
  html += '    <thead>\n  <tr>\n  <th>%s </th>\n  <td>%s</td>\n  </tr>\n  </thead>\n'%("Name", info.getIniOption("name"))
  html += '    <tbody><tr><th>%s </th><td>%s</td></tr>\n'%("Code", info.code)
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Version", info.version)
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("State", info.getIniOption("state"))
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Build", info.build)
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Owner", info.getOwner())

  #url = info.getUrl()
  url = info.getIniOption("download-url")
  if url != None:
    html += '    <tr><th valing="top">Downloads</th><td><a href ="%s">Binaries</a></td></tr>\n'%(url)
  else:
    html += '    <tr><th valing="top">Downloads</th><td>Binaries</td></tr>\n'

  sourceUrl = info.getSourceUrl()

  if sourceUrl != None:
    html += '    <tr><td></td><td><a href ="%s">Sources</a></td></tr>\n'%(sourceUrl)
  else:
    html += "    <tr><td></td><td>Sources</td></tr>\n"

  if info.getDependencies() == None:
    html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Dependencies", "")
  else:
    html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Dependencies", info.getDependencies().replace("\:",":"))
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Type", info.getType())
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Official", info.getOfficial())
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("O.S.", info.getOS())
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Architecture", info.getArch())
  html += '    <tr><th valing="top">%s </th><td>%s</td></tr>\n'%("Categories", info.getCategories())

  description = info.getDescription()
  if description == None:
    description = ""
  description = description.replace("\\n", "<br>")
  description = description.replace("\:",":")
  html += '    <tr valing="top"><th valing="top">%s </th><td>%s</td></tr>\n'%("Description", description)
  html += """  </tbody>\n</table>\n"""
  html += """
  <!-- javascript para la visualizacion de la tabla -->
  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
  <script src="http://datatables.net/release-datatables/media/js/jquery.dataTables.js" type="text/javascript"></script>
  <!-- inicializacion de la tabla con cosas chachis -->
  <script type="text/javascript">
    $(document).ready(function() {
      $('#pkgdetails').dataTable( {
        "bPaginate": false,
        "bLengthChange": true,
        "bFilter": false,
        "bSort": false,
        "bInfo": false,
        "bAutoWidth": true
      });
    });
  </script>
  </body>\n</html>"""


  try:
    f = file(getWeb() + "/" + info.getFullName() + ".html","w")
    f.write(html)
    f.close()
  except Exception, ex:
    raise ex

def extract_make_portable(zfile, targetfolder):
  print "Extracting 'make-portable' from %r to %r" % (zfile,targetfolder)
  zf = zipfile.ZipFile(zfile)
  data = zf.read("tools/make-portable")
  f = open(os.path.join(targetfolder,"make-portable"),"wb")
  f.write(data)
  f.close()
  zf.close()


def extract_mkexec(zfile, targetfolder):
  print "extract_mkexec: zfile=%s, target=%s" % (zfile, os.path.join(targetfolder,"mkexec"))
  zf = zipfile.ZipFile(zfile)
  data = zf.read("tools/mkexec")
  f = open(os.path.join(targetfolder,"mkexec"),"wb")
  f.write(data)
  f.close()
  zf.close()


def prepare_portable(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("prepare-portable"), "b:s:", [ "build=", "state=" ])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    build=None
    state=None
    for opt, arg in opts:
        if opt in ("-b", "--build"):
            build=arg
        elif opt in ("-s", "--state"):
            state=arg
        else:
            assert False, "unhandled option %r" % opt

    if build == None:
      print "Requiered option --build not found."
      shorthelp(args)
      sys.exit(2)

    if state == None:
      print "Requiered option --state not found."
      shorthelp(args)
      sys.exit(2)

    join = os.path.join
    build_folder = join(getPackagesRoot(),"dists",getVersion(),"builds",build)
    if not os.path.isdir(build_folder):
      print "Can't access the build folder "+build_folder+"."
      sys.exit(2)

    do_prepare_portable(build,state)

def do_prepare_portable(build,state):
    join = os.path.join
    build_folder = join(getPackagesRoot(),"dists",getVersion(),"builds",build)
    portable_folder = join(build_folder,"misc","portable")
    makedirs(portable_folder)
    makedirs(join(portable_folder,"packages","custom"))
    makedirs(join(portable_folder,"standard"))
    makedirs(join(portable_folder,"patchs"))
    shutil.copy(
        join(getPackagesRoot(),"dists",getVersion(),"excludes.portable"),
        join(portable_folder,"packages","excludes")
    )
    for platform in platforms :
      fname_base = "gvSIG-desktop-%s-%s-%s-%s-%s" % (
        getVersion(),build,state,platform.getOS(),platform.getArch()
      )
      fname_base_onlinefamily = "gvSIG-desktop-%s-%s-%s-%s-%s" % (
        getVersion(),build,state,platform.getOSFamilyForOnlineInstaller(),platform.getArch()
      )
      linkfile(
        join(build_folder,fname_base_onlinefamily + "-online.zip"),
        join(portable_folder,"standard",fname_base_onlinefamily + "-online.zip")
      )
      linkfile(
        join(build_folder,fname_base + ".gvspks"),
        join(portable_folder,"standard",fname_base + ".gvspks")
      )
    extract_make_portable(
      join(build_folder,fname_base_onlinefamily + "-online.zip"),
      join(portable_folder)
    )
    mychmod(join(portable_folder,"make-portable"),RWXALL)

def zipfolder(source,target):
  def zipdir(path, zip):
      for root, dirs, files in os.walk(path):
          for file in files:
              zip.write(os.path.join(root, file))
  zipf = zipfile.ZipFile(target, 'w')
  zipdir(source, zipf)
  zipf.close()

def removefile(filename):
  if os.path.exists(filename):
    os.remove(filename)

def mkportable(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("mkportable"), "b:s:", [ "build=", "state=" ])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    build=None
    state=None
    for opt, arg in opts:
        if opt in ("-b", "--build"):
            build=arg
        elif opt in ("-s", "--state"):
            state=arg
        else:
            assert False, "unhandled option %r" % opt

    if build == None:
      print "Requiered option --build not found."
      shorthelp(args)
      sys.exit(2)

    if state == None:
      print "Requiered option --state not found."
      shorthelp(args)
      sys.exit(2)

    join = os.path.join
    build_folder = join(getPackagesRoot(),"dists",getVersion(),"builds",build)
    portable_folder = join(build_folder,"misc","portable")
    target_folder = join(portable_folder,"target")

    if not os.path.isdir(build_folder):
      print "Can't access the build folder "+build_folder+"."
      sys.exit(2)

    if not os.path.isdir(portable_folder) :
      do_prepare_portable(build,state)
    os.system('cd %s ; ./make-portable' % (portable_folder))

    message("Moving portable zip files to build folder")
    for platform in platforms :
      fname = "gvSIG-desktop-%s-%s-%s-%s-%s%s.zip" %  (
        getVersion(),build,state,platform.getOS(),platform.getArch(), platform.getPortableSufix()
      )
      if os.path.exists(join(target_folder,fname)) :
        message("    Removing previos %s" % fname)
        removefile(join(build_folder,fname))
        message("    Moving zip %s" % fname)
        shutil.move(join(target_folder,fname), build_folder)
      else:
        message("    Skip zip %s" % fname)

    message("Remove temporary folders")
    shutil.rmtree(target_folder)

def mkexec(version, build, state, distribution_name, folder):
  fname = "gvSIG-desktop-%s-%s-%s-lin-x86_64-online.zip" % (version,build,state)
  extract_mkexec(os.path.join(folder,fname), folder)
  mychmod(os.path.join(folder,"mkexec"),RWXALL)
  cmd = 'cd %s ; ./mkexec "%s" "%s" "%s" "%s" "%s"' % (folder,version, build, state, distribution_name, folder)
  print "mkexec: cmd=", cmd
  os.system(cmd)
  os.remove(os.path.join(folder,"mkexec"))

def mkdist(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("mkdist"), "b:s:", [ "build=", "state=", "distribution_name=" ])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    build=None
    state=None
    distribution_name = "standard"

    for opt, arg in opts:
        if opt in ("-b", "--build"):
            build=arg
        elif opt in ("-s", "--state"):
            state=arg
        elif opt in ("-N", "--distrinution-name"):
            distribution_name = arg
        else:
            assert False, "unhandled option %r" % opt

    if build == None:
      print "Requiered option --build not found."
      shorthelp(args)
      sys.exit(2)

    if state == None:
      print "Requiered option --state not found."
      shorthelp(args)
      sys.exit(2)

    if not os.path.isdir("builds/"+build):
      print "Can't access the build folder builds/"+build+"."
      sys.exit(2)

    message( "Generating distribution for build "+ build + "...")
    message("Recreating index of packages...")
    executeCommand("mks", "-s", "-c")

    #executeCommand("mkhtml" )

    gvspki_filename = "builds/"+build+"/packages.gvspki"
    message( "Coping packages.gvspki to "+ gvspki_filename + "\n")
    shutil.copyfile("packages.gvspki", gvspki_filename)
    shutil.copyfile("packages.gvspki.md5", gvspki_filename +".md5")

    can_make_exec = False
    for platform in platforms:
        message( "Creating package set for platform "+platform.getOS()+"/"+platform.getArch()+"...")
        gvspks_filename = "builds/"+build+"/gvSIG-desktop-" + VERSION + "-" + build+ "-" + state + "-"+platform.getOS()+"-"+platform.getArch()+".gvspks"

        message( "Coping packages-"+platform.getOS()+"-"+platform.getArch()+".gvspks to "+ gvspks_filename)
        shutil.copyfile("packages-"+platform.getOS()+"-"+platform.getArch()+".gvspks", gvspks_filename)
        shutil.copyfile("packages-"+platform.getOS()+"-"+platform.getArch()+".gvspks.md5", gvspks_filename +".md5")

        message( "Creating installers for platform "+platform.getOS()+"/"+platform.getArch()+"...")
        online_filename = "builds/"+build+"/gvSIG-desktop-" + VERSION + "-" + build+ "-" + state + "-"+platform.getOS()+"-"+platform.getArch() + "-online.jar"

        if not os.path.isfile(online_filename):
          osfamily=platform.getOSFamilyForOnlineInstaller()
          online_family_filename="builds/"+build+"/gvSIG-desktop-" + VERSION + "-" + build+ "-" + state + "-"+osfamily+"-"+platform.getArch() + "-online.jar"
          if os.path.isfile(online_family_filename):
            message("Coping standard online installer from os family (%s) to %s." % (osfamily, online_filename))
            shutil.copyfile(
              online_family_filename,
              online_filename
            )
  
        if not os.path.isfile(online_filename):
          msgwarn("Can't access the online installer for "+platform.getOS()+"/"+platform.getArch() + " ("+online_filename+").")
          continue

        can_make_exec = True
        message( "Add execution permissions to online installers....")
        mychmod(online_filename,RWXALL)

        md5sum(online_filename,online_filename+".md5")
        mychmod(online_filename+".md5",RWALL)

        executeCommand("mkinstall" , online_filename, gvspks_filename)

        message( "Renaming files from custom to standard...")
        target_filename = "builds/"+build+"/gvSIG-desktop-" + VERSION + "-" + build+ "-" + state + "-"+platform.getOS()+"-"+platform.getArch()+"-"+distribution_name + ".jar"
        shutil.move(
            "builds/"+build+"/gvSIG-desktop-" + VERSION + "-" + build+ "-" + state + "-"+platform.getOS()+"-"+platform.getArch() + "-custom.jar",
            target_filename
        )
        mychmod(target_filename,RWXALL)

        md5sum(target_filename,target_filename+".md5")
        mychmod(target_filename+".md5",RWALL)

        message( "Createds installers for platform "+platform.getOS()+"/"+platform.getArch()+"\n")

    if can_make_exec:
      mkexec(VERSION, build, state, distribution_name, os.path.join(os.getcwd(), "builds", build))

    #message( "Coping html index to browse paqueges of the distro.")
    #shutil.rmtree("builds/"+build+"/web", ignore_errors=True)
    #shutil.copytree("web", "builds/"+build+"/web")
    #f = file("builds/"+build+"/web/index.html","r")
    #contents = f.read()
    #f.close()
    #contents = contents.replace("href=\"../../../web/gvSIG-desktop-", "href=\"../../../../../web/gvSIG-desktop-")
    #f = file("builds/"+build+"/web/index.html","w")
    #f.write(contents)
    #f.close()

    message( "\nCreation of distribution completed.\n")


def show(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("show"), "S", [ "verify"])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    eerify = False
    for opt, arg in opts:
        if opt in ("-V", "--verify"):
            verify = True
        else:
            assert False, "unhandled option %r" % opt

    index_name=args[0]
    message( "Show package.info from '%s'" % index_name)
    files = findfiles(getPool(), index_name)
    if len(files) != 1:
        msgerror("Can't locate package '%s' in pool '%s'." % (index_name, getPool()))
        return
    index_path = files[0]
    outputfolder="/tmp/gvspkg.%s" % os.getpid()
    os.mkdir(outputfolder)
    os.system('unzip -q %s -d %s' % (index_path,outputfolder))

    files = findfiles(outputfolder, "package.info")
    if len(files) != 1:
        msgerror("Can't locate package.info in pool '%s'." % (index_name))
        return

    package_info = files[0]
    f = file(package_info,"r")
    s = f.read()
    f.close()
    print s
    if verify:
      verify_sign(package_info)
    shutil.rmtree(outputfolder)

def editall(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("editall"), "Scx:I:r:", ["clear-list", "exclude=", "excludepki=", "excludepkg=", "include=", "replace=", "sign"])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    index_only = False
    clear_list=False
    includes=list()
    excludes_pki=list()
    replaces = list()
    excludes_pkg=list()
    sign = False
    interactive = True
    for opt, arg in opts:
        if opt in ("-c", "--clear-list"):
            clear_list = True
        elif opt in ("-x", "--exclude"):
            excludes_pki.append(arg)
            excludes_pkg.append(arg)
        elif opt in ( "--excludepki"):
            excludes_pki.append(arg)
        elif opt in ( "--excludepkg"):
            excludes_pkg.append(arg)
        elif opt in ( "--include", "-I"):
            includes.append(PackageInfo(arg))
        elif opt in ("-r", "--replace"):
            interactive = False
            replaces.append(arg)
        elif opt in ("-S", "--sign"):
            sign = True
        else:
            assert False, "unhandled option %r" % opt

    indexes = IndexList()

    packages_txt = getDist() +"/packages.txt"
    if os.path.exists(packages_txt) and not clear_list:
        indexes.load(packages_txt)
    else:
        indexes.build(getPool(), getSearchVersions())
        indexes.save(packages_txt)

    for pkg in includes:
      indexes.append(pkg)

    allpackages = list()
    for info in indexes:
        if not ( info.code in excludes_pki or info.getFullName() in excludes_pki ):
            try:
                if info.hasPki() :
                  print info.getPkiFilename()
                  if interactive :
                    edit_pkginfo_of_package(info.getPkiFilename(), edit_ui)
                  elif len(replaces) < 1:
                    edit_pkginfo_of_package(info.getPkiFilename(), edit_replace, replaces)

                  if sign:
                    edit_pkginfo_of_package(info.getPkiFilename(), edit_sign)

            except Exception, ex:
                msgerror("Can't add index '%s', error %s" % (info, str(ex)))

def edit(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("edit"), "Sr:", [ "replace=", "onlysign", "sign" ])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    replaces = list()
    interactive = True
    sign = False
    for opt, arg in opts:
        if opt in ("-r", "--replace"):
            interactive = False
            replaces.append(arg)
        elif opt in ("--onlysign"):
            interactive = False
            sign = True
        elif opt in ("-S", "--sign"):
            sign = True
        else:
            assert False, "unhandled option %r" % opt

    index_name=args[0]
    message( "Show package.info from '%s'" % index_name)
    files = findfiles(getPool(), index_name)
    if len(files) != 1:
        msgerror("Can't locate package '%s' in pool '%s'." % (index_name, getPool()))
        return
    index_path = files[0]
    if interactive:
      edit_pkginfo_of_package(index_path, edit_ui)
    elif len(replaces) < 1:
      edit_pkginfo_of_package(index_path, edit_replace, replaces)

    if sign:
      edit_pkginfo_of_package(index_path, edit_sign)

def edit_ui(filename, args):
      os.system('vi "%s"' % filename)

def edit_replace(filename, args):
      replaces = args[0]
      f = open(filename)
      s = f.read()
      f.close()
      for replace in replaces:
        x = replace.split(replace[0])
        if len(x)==4:
          s=re.sub(x[1],x[2],s)
      f = open(filename,"w")
      f.write(s)
      f.close()

def edit_sign(filename, args):
      os.system('java -cp "%s/commons-codec-1.6.jar:%s/org.gvsig.installer.lib.impl-1.0.1-SNAPSHOT.jar" org.gvsig.installer.lib.impl.utils.SignUtil sign %s' %  (
        get_gvspkg_bin_folder(),
        get_gvspkg_bin_folder(),
        filename)
      )

def verify_sign(filename):
      os.system('java -cp "%s/commons-codec-1.6.jar:%s/org.gvsig.installer.lib.impl-1.0.1-SNAPSHOT.jar" org.gvsig.installer.lib.impl.utils.SignUtil verify %s' % (
        get_gvspkg_bin_folder(),
        get_gvspkg_bin_folder(),
        filename)
      )

def edit_pkginfo_of_package(pkg_path, operation, *args):
    outputfolder="/tmp/gvspkg.%s" % os.getpid()
    os.mkdir(outputfolder)
    os.system('unzip -q %s -d %s' % (pkg_path,outputfolder))

    files = findfiles(outputfolder, "package.info")
    if len(files) != 1:
        msgerror("Can't locate package.info in pool '%s'." % (pkg_path))
        return

    package_info = files[0]
    code = package_info.split("/")[-2]
    operation(package_info, args)

    # zip -Dr kk.zip org.gvsig.wfs
    temp_index_name = "/tmp/packages.gvspki.%s" % os.getpid()
    temp_index = zipfile.ZipFile(temp_index_name,"w",zipfile.ZIP_STORED)
    temp_index.write(package_info, "%s/package.info" % (code))
    temp_index.close()
    shutil.rmtree(outputfolder)
    os.remove(pkg_path)
    shutil.move(temp_index_name,pkg_path)


def crearpki(path_pkg, url_pkg):
  z = zipfile.ZipFile(path_pkg,"r")
  zi = z.infolist()
  filename = None
  contents = None
  for info in zi :
    if info.filename.endswith("/package.info"):
      filename = info.filename
      contents = z.read(filename)
      if contents[-1:]!= "\n":
        contents += "\n"
      contents += "download-url=%s\n" % url_pkg.replace(":","\\:")
      break

  z.close()
  
  if filename == None:
    return
  
  fname = path_pkg[:-7]+".gvspki"
  z = zipfile.ZipFile(fname,"w")
  z.writestr(filename,contents)
  z.close()
  
  return fname
  
def install(args):
    cmd = Command(args)
    try:
        opts, args = getopt.getopt(cmd.getArgs("install"), "fS", [ "force","nohttps" ])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(args)
        sys.exit(2)

    force = False
    nohttps = False
    for opt, arg in opts:
        if opt in ("-f", "--force"):
            force = True
        if opt in ("-S", "--nohttps"):
            nohttps = True
        else:
            assert False, "unhandled option %r" % opt

    url_pki = args[0]
    if url_pki.endswith(".gvspki") and url_pki.startswith("https:") and nohttps :
       url_pki = "http:" + url_pki[6:]

    message( "Download package index '%s'" % url_pki)
    temppath_pki= os.path.join("/tmp",os.path.basename(url_pki))
    if not downloadFile(url_pki,temppath_pki):
      msgerror("Can't download index.")
      msgerror("Can't install '%s'." % url_pki)
      print # force a newline
      return 1
    if temppath_pki.endswith(".gvspki"):
      pkg = PackageInfo(temppath_pki)
      url_pkg = pkg.getUrl().replace("\\","")
      if url_pkg[-7:] == ".gvspki" :
        msgwarn("Suspicious download-url value. Ends with gvspki, expected gvspkg.")
        msgwarn("download-url ='%s'." % url_pkg)

      if url_pkg.startswith("https:") and nohttps :
         url_pkg = "http:" + url_pkg[6:]

      message( "Download package '%s'" % url_pkg)
      temppath_pkg= os.path.join("/tmp",os.path.basename(url_pkg))
      if not downloadFile(url_pkg,temppath_pkg):
        msgerror("Can't download package from download-url ('%s')." % url_pkg)
        msgerror("Can't install '%s'," % url_pki)
        print # force a newline
        return 1

    elif temppath_pki.endswith(".gvspkg"):
      temppath_pkg = temppath_pki
      pkg = PackageInfo(temppath_pki)
      url = getpackageUrl(getPool()+"/"+pkg.getCode()+"/"+os.path.basename(temppath_pkg))
      temppath_pki = crearpki(temppath_pkg,url)

    else:
      msgerror("Can't install '%s', extension is not a gvspki or gvspkg.\n" % url_pki)
      return 1

    folder = os.path.join(getPool(),pkg.getCode())
    makedirs(folder)
    pathname_pki = os.path.join(folder,os.path.basename(temppath_pki))
    if not force and os.path.isfile(pathname_pki) :
        msgwarn("The package index alreade exist in the pool. Use -f to forrce install.")
        print # force a newline
        return 1
    pathname_pkg = os.path.join(folder,os.path.basename(temppath_pkg))
    if  not force and os.path.isfile(pathname_pki) :
        msgwarn("The package downloaded from download-url alredy exists in the pool. Use -f to force install.")
        print # force a newline
        return 1
    message( "installing package '%s'" % os.path.basename(pathname_pki))
    shutil.copyfile(temppath_pki, pathname_pki)
    message( "installing package '%s'" % os.path.basename(pathname_pkg))
    shutil.copyfile(temppath_pkg, pathname_pkg)

    md5sum(pathname_pki, pathname_pki+".md5")
    md5sum(pathname_pkg, pathname_pkg+".md5")
    
def md5sum(fin, fout):
    message( "Calculating md5sum of %s..." % fin )
    system("md5sum -b %s >%s" % (fin, fout) )

def downloadFile(url,path):
  try:
    fsrc = urllib2.urlopen(url)
  except urllib2.HTTPError,e:
    msgerror("Error abriendo url '%s'." % url, e)
    return False
  fdst = file(path,"wb")
  shutil.copyfileobj(fsrc,fdst)
  fdst.close()
  fsrc.close()
  return True

def shorthelp(args):
    print """
usage: gvspkg [OPTIONS] COMMANDS
OPTIONS:

-h,--help       Muestra esta ayuda
-v,--verbose    Activa el modo verbose
-d,--debug      Activa el modo debug.
--version ver   Fija la version con la que van a trabajar.
-r,--package-root root    Fija la carpeta del raiz del sistema de paquetes

COMMANDS:

mkinstall [OPTIONS] install-file packages-file
    -L, --jrelin=path
    -W, --jrewin=path
    -l, --addjrelin
    -w, --addjrewin
    -N, --distribution-name=name

lsi [OPTIONS]
    -l, --long-format

mks [OPTIONS]
     -c, --clear-list
     --excludepkg pkgcode
     --excludepki pkgcode
     --exclude pkgcode
     -s, --include-default-selection
     -i, --index-only
     -I full-path-to-package, --include full-path-to-package

mkdist [OPTIONS]
     -s STATE, --state=STATE
     -b BUILD, --build=BUILD
     -N, --distribution-name=name

mkmirror [OPTIONS]
     -b, --build buildnumber

mkhtml [OPTIONS]
     -c, --clear-list
     --excludepkg pkgcode
     --excludepki pkgcode
     --exclude pkgcode

show OPTIONS package-index
    --verify, -V

edit [OPTIONS] package-index
     --replace=@search@replace@
     --onlysign
     --sign, -S

editall [OPTIONS]
     -c, --clear-list
     --excludepkg pkgcode
     --excludepki pkgcode
     --exclude pkgcode
     --replace=@search@replace@
     --sign, -S

install [OPTIONS] url-to-pki
     -f, --force

prepare-portable [OPTIONS]
     -b, --build
     -s, --state

mkportable [OPTIONS]
     -b, --build
     -s, --state

La version actual a utilizar es:
  %s

El directorio root de la estructura de packetes actual es:
  %s
    """ % (VERSION, GVSPKG_ROOT)


def help(args):
    print """
usage: gvspkg [OPTIONS] COMMANDS

OPTIONS:

-h|--help
    Muestra esta ayuda

-v|--verbose
    Activa el modo verbose

-d|--debug
    Activa el modo debug. Se muestran mensajes que pueden ser
    utilies de cara a depuracion.

--version version
    Fija la version con la que van a trabajar los comandos indicados.

-r|--package-root package-root
    Fija la carpeta en la que va a buscar el raiz del sistema de paquetes
    con el que trabajar

COMMANDS:

mkinstall [OPTIONS] install-file packages-file

    OPTIONS:

    -L | --jrelin=path

    -W | --jrewin=path

    -l | --addjrelin

    -w | --addjrewin

    -N | --distribution-name=name
      Nombre usado como sufijo del nuevo binario a generar. Por defecto si no se
      indica valdra "custom".


lsi [OPTIONS]
    Lista los indices disponibles de la version

    OPTIONS:

    -l | --long-format
        Muestra para cada paquete la informacion del package.info

mks [OPTIONS]
     Crea el fichero packages.gvspki con los indices de la
     version y packages.gvspkg con los paquetes.

     OPTIONS:

     -c | --clear-list
        Elimina la lista de paquetes a utilizar recreandola a partir
        de los paquetes del pool tomando el ultimo build de cada paquete.

     --excludepkg pkgcode
        No incluye el paquete indicado en el fichero gvspkg a generar

     --excludepki pkgcode
        No incluye el paquete indicado en el fichero gvspki a generar

     --exclude pkgcode
        No incluye el paquete indicado en los ficheros gvspkg y gvspki a generar

     -s | --include-default-selection
        Incluye el fichero "defaultPackages", que se debe encontrar en el
        directorio corriente, con los nombres de paquetes a seleccionar
        por defecto.

     -i | --index-only
        No crea el fichero gvspks, solo crea el gvspki

     -I full-path-to-package | --include full-path-to-package
        Agrega el paquete indicado a la lista de paquetes aunque no coincida para
        la version de gvSIG con la que se esta trabajando.

mkdist [OPTIONS]
     Crea los ficheros de la distribucion standard para el buil dindicado a partir de
     la distribucion online y los paquetes que hayan en el pool para esta version.
     Ejecuta un "mks" y un "mkhtml" automaticamente para preparar el conjunto de paquetes
     a incluir en la distribucion, y una vez preparados ejecuta un "mkinsrall" por
     S.O. (win y lin), renombrando los ficheros generados segun corresponda.

     OPTIONS:
     -s STATE | --state=STATE
        Indica el estado de la distribucion a generar, devel, alpha, ..., debe estar
        deacuerdo con lo que diga el cihero online a usar como base.

     -b BUILD | --build=BUILD
        Indica el numero de build de la destribucion a generar. Es usado para localizar
        los ficheros en la carpeta builds de la distribucion y para saber donde debe
        dejar los ficheros generados.

     -N | --distribution-name=name
        Nombre usado como sufijo del nuevo binario a generar. Por defecto si no se
        indica valdra "standard".


mkmirror [OPTIONS]

  Prepara una carpeta para hacer un mirror de un build en concreto.

     OPTIONS:

     -b | --build buildnumber
       Indica el numero de build del que se quiere hacer un mirror.

mkhtml [OPTIONS]
     ????

     OPTIONS:

     -c | --clear-list
        Elimina la lista de paquetes a utilizar recreandola a partir
        de los paquetes del pool tomando el ultimo build de cada paquete.

     --excludepkg pkgcode
        No incluye el paquete indicado en el fichero gvspkg a generar

     --excludepki pkgcode
        No incluye el paquete indicado en el fichero gvspki a generar

     --exclude pkgcode
        No incluye el paquete indicado en los ficheros gvspkg y gvspki a generar

show OPTIONS package-index
    Muestra el package.info del indice indicado como parametro.

    OPTIONS

    --verify | -V
      Comprueba la forma del packete.

edit [OPTIONS] package-index
    Edita el package.info del indice indicado como parametro.

     OPTIONS:

     --replace=@search@replace@
       Reemplaza en el package.info de cada paquete la cadena "search" por "replace"
       todas las veces que aparezca. "@" puede ser cualquier caracter que no aparezca
       en "search" y "replace".
       Esta opcion puede indicarse tatas veces como reemplazos se deseen efectuar.

     --onlysign
       firma el package.info sin editarlo de forma interactiva (no invoca al editor antes
       de firmarlo).

     --sign | -S
       Firma el package.info tras terminar la edicion (bach o interactiva)

editall [OPTIONS]
    Edita todos los package.info

     OPTIONS:

     -c | --clear-list
        Elimina la lista de paquetes a utilizar recreandola a partir
        de los paquetes del pool tomando el ultimo build de cada paquete.

     --excludepkg pkgcode
        No incluye el paquete indicado en el fichero gvspkg a generar

     --excludepki pkgcode
        No incluye el paquete indicado en el fichero gvspki a generar

     --exclude pkgcode
        No incluye el paquete indicado en los ficheros gvspkg y gvspki a generar

     --replace=@search@replace@
       Reemplaza en el package.info de cada paquete la cadena "search" por "replace"
       todas las veces que aparezca. "@" puede ser cualquier caracter que no aparezca
       en "search" y "replace".
       Esta opcion puede indicarse tatas veces como reemplazos se deseen efectuar.

      --sign | -S
        Firma todos los paquetes que sean oficiales

install [OPTIONS] url-to-pki
    descarga de la url indicada un fichero gvspki e instala este junto con su correspondiente
    pkg en el pool local.

     OPTIONS:

     -f | --force
       fuerza la sobreescritura de los ficheros en caso de que estos ya existan.

Si en la carpeta corriente encuentra un fichero gvspkg.options cargara los
flags indicados ahi como flags por defecto para cada comando. El formato del
fichero es:
  main=OPCION-POR-DEFECTO
  mks=OPCOPNES-POR-DEFECTO
Donde main indica las opciones por defecto generales, independientes del comando
a ejecutar. "mks" indica las opciones por defecto a usar en el comando "mks", y
asi sucesivamente, indicando el nombre del comando seguido de un "=" y las opciones
por defecto para ese comando.

Por defecto la version la obtiene del nombre de la carpeta
corriente (%s). Las opciones indicadas en el fichero gvspkg.options tienen prioridad
sobre este valor.

El directorio root de la estructura de packetes lo buscara en el
sitio indicado por la variable de entorno GVPKG_ROOT, y si esta no
esta establecida usara "%s". Las opciones indicadas en el fichero gvspkg.options
tienen prioridad sobre este valor.

    """ % (VERSION, GVSPKG_ROOT)

def executeCommand(*args):
    command = "shorthelp"
    if len(args)>0:
        command=args[0]

    r=1
    if command=="lsi" :
        r=lsi(args)
    elif command == "mks":
        r=mks(args)
    elif command == "edit":
        r=edit(args)
    elif command == "editall":
        r=editall(args)
    elif command == "show":
        r=show(args)
    elif command == "mkhtml":
        r=mkhtml(args)
    elif command == "mkinstall":
        r=mkinstall(args)
    elif command == "install":
        r=install(args)
    elif command == "mkdist":
        r=mkdist(args)
    elif command == "mkmirror":
        r=mkmirror(args)
    elif command == "mkportable":
        r=mkportable(args)
    elif command == "prepare-portable":
        r=prepare_portable(args)
    elif command == "help":
        r=help(args)
    else:
        r=shorthelp(args)
    return r

def main():
    global DEBUG
    global VERSION
    global VERBOSE
    global GVSPKG_ROOT
    global SEARCH_VERSIONS

    cmd = Command(sys.argv)
    try:
        opts, args = getopt.getopt(cmd.getArgs("main"), "dhvr:", ["debug", "verbose", "version=", "package-root=","help","search_versions="])
    except getopt.GetoptError, err:
        # print help information and exit:
        print str(err) # will print something like "option -a not recognized"
        shorthelp(None)
        sys.exit(2)

    for opt, arg in opts:
        if opt in ("-h", "--help"):
            shorthelp(args)
            sys.exit()
        elif opt in ("-d", "--debug"):
            DEBUG = True
        elif opt in ("-v", "--verbose"):
            VERBOSE = True
        elif opt in ("--version"):
            VERSION = arg
        elif opt in ("--search_versions"):
            SEARCH_VERSIONS.append(arg)
        elif opt in ("-r", "--package-root"):
            GVSPKG_ROOT = arg
        else:
            assert False, "unhandled option"
    #
    debug("DEBUG=%s" % DEBUG)
    debug("VERSION=%s" % VERSION)
    debug("GVSPKG_ROOT=%s" % GVSPKG_ROOT)
    if GVSPKG_ROOT == None:
      shorthelp(None)
    else:
      r=executeCommand(*args)
      sys.exit(r)

main()




