#!/usr/bin/python

import sys,getopt,debian_bundle.deb822,scriptutil,os,tempfile,copy

def usage():
   print "Usage: jh_manifest [options] [<jar> ...]"
   print "Options:"
   print "\t-h --help: show this text"
   print "\t-v --verbose: show more information while running"
   print "\t-V --version: print the version"
   print "\t-n --no-act: don't actually do anything, just print the results"
   print "When reading manifest files for packages:"
   print "\t-i --indep: run for all Arch: all packages"
   print "\t-a --arch: run for all Arch-specific packages"
   print "\t-p<package> --package=<package>: package to act on (default=all)"  
   print "\t-P<packagedir> --tmpdir=<package>: package directory (default=\$CWD/debian/package)"  
   print "When acting on a jar from the command line:"
   print "\t-c<classpath> --classpath=<classpath>: The classpath to set (space separated)"
   print "\t-j</path/to/java/home> --java-home=</path/to/java/home>: The path to the JRE to use to execute the jar"
   print "\t-m<class> --main=<class>: The class to run when executing the jar"
   print "\t-o<options> --javaopts=<options>: Options passed to java when executing the jar"

opts="vnihVap:P:c:j:m:o:"
longopts=["version","help","verbose","no-act","indep","arch","package=","tmpdir=","classpath=","main=","javaopts=","with="]

sys.argv.remove(sys.argv[0]);
(parsed, notparsed) = getopt.getopt(sys.argv,opts,longopts);

args={}

def version():
   print "javahelper version: ??"

def findpackages(args):
   packages = []
   f = file("debian/control")
   for pkg in debian_bundle.deb822.Deb822.iter_paragraphs(f):
      if "Package" in pkg:
         if "--package" in args:
            if pkg["Package"] == args["--package"]:
               packages.append(pkg["Package"])
         elif "-p" in args:
            if pkg["Package"] == args["-p"]:
               packages.append(pkg["Package"])
         elif "--arch" in args or "-a" in args:
            if pkg["Architecture"] != "all":
               packages.append(pkg["Package"])
         elif "--indep" in args or "-i" in args:
            if pkg["Architecture"] == "all":
               packages.append(pkg["Package"])
         else:
             packages.append(pkg["Package"])

   f.close()
   return packages

def updatejar(jar, manifest, args):

   jar = os.path.realpath(jar)
   if not os.path.exists(jar):
      print "Warning: "+jar+" does not exist"
      return

   if "--verbose" in args or "-v" in args:
      print "Updating manifest in "+jar

   tempdir = tempfile.mkdtemp()

   if os.path.exists(tempdir + "/META-INF/MANIFEST.MF"):
      os.unlink(tempdir + "/META-INF/MANIFEST.MF")

   os.system("cd '"+tempdir+"' ; fastjar -x -f '"+jar+"'")

   manifest_override = 0
   if {"top":{}} != manifest:
     manifest_override = 1

   manifest = parseManifest(tempdir + "/META-INF/MANIFEST.MF", None, manifest)

   if not "Class-Path" in manifest["top"] and "CLASSPATH" in os.environ:
      manifest["top"]["Class-Path"] = os.environ["CLASSPATH"].replace(":", " ")
      manifest_override = 1

   # No need to rewrite manifest if there are no overrides !
   if manifest_override:
     writeManifest(tempdir + "/MANIFEST.MF", manifest)

   if "--no-act" in args or "-n" in args:
      print jar+":"
      print str(manifest)
   elif manifest_override:
   # No need to rewrite manifest if there are no overrides !
      os.system("rm -f '"+jar+"' ")
      os.system("cd '"+tempdir+"' ; ls -1 | egrep -v '^(META-INF|MANIFEST.MF)' | fastjar -c -f '"+jar+"' -m MANIFEST.MF -@")

   os.system("rm -rf '"+tempdir+"' ")

def findjars(path):
   return scriptutil.ffind(path, shellglobs=['*.jar'])

def splitWrite(f, line):
   words = line.split()
   i = 0
   first = True
   for w in words:
      if i+len(w) > 71:
         f.write("\n ")
         i = 0
      if len(w) > 71:
         k = 0
         while k < len(w):
            if k % 72 == 71:
               f.write("\n ")
            f.write(w[k])
            k = k + 1
         i = i + (k % 72) + 1
      else:
         if first:
            first = False
         else:
            f.write(" ")
         f.write(w)
         i = i + len(w) + 1
   f.write("\n")

def writeManifest(filename, manifest):
   f = file(filename, 'w')
   kvs = manifest["top"].items()
   kvs.reverse()
   for (k, v) in kvs:
      splitWrite(f, k+": "+v)
   splitWrite(f, "")
   for (l, m) in manifest.items():
      if l != "top":
         if "Name" in m:
            splitWrite(f, "Name: "+m["Name"])
         for (k, v) in m.items():
            if "Name" != k:
               splitWrite(f, k+": "+v)
         splitWrite(f, "")

   f.flush()
   f.close()

def parseManifest(filename, jar, manifest):

   if not os.path.exists(filename):
      return manifest

   f = file(filename)
   if None == jar:
      section = "top"
      secno = 0
      for sec in debian_bundle.deb822.Deb822.iter_paragraphs(f):
         if "" == section:
            if "Name" in sec:
               section = sec["Name"]
            else:
                section = "anon"+str(secno)
         if section not in manifest:
            manifest[section] = {}
         for i in sec:
            if not i.strip() in manifest[section]:
               manifest[section][i.strip()] = sec[i].strip().replace('\n ','')
         section = ""
   else:
      lines = f.readlines()

      section="top"
      sec = 0
      injar = True
      for l in lines:
         l = l.rstrip()
         if None != jar:
            if "" != l and (jar+":").endswith(l):
               section = "top"
               injar = True
               continue
            if not injar: continue
            if "" != l and not l.startswith(" "): 
               section = "top"
               injar = False
               continue
         l = l.lstrip()
         if "" == l:
            section=""
            continue
         elif "" == section:
            (k, v) = l.split(":", 1)
            if "Name" == k: 
               section = v.strip()
            else:
               section = "anon"+str(sec)
               sec = sec + 1
            if not section in manifest:
               manifest[section] = {}
         else:
            (k, v) = l.split(":", 1)

         if not k.strip() in manifest[section]:
            manifest[section][k.strip()] = v.strip()

   f.close()

   return manifest

for i in parsed:
   (k, v) = i
   args[k] = v

if "--help" in args or "-h" in args:
   usage()
   sys.exit(0)
if "--version" in args or "-V" in args:
   version()
   sys.exit(0)

manifest = {"top":{}}
if "--classpath" in args:
   manifest["top"]["Class-Path"] = args["--classpath"]
if "-c" in args:
   manifest["top"]["Class-Path"] = args["-c"]
if "--main" in args:
   manifest["top"]["Main-Class"] = args["--main"]
if "-m" in args:
   manifest["top"]["Main-Class"] = args["-m"]
if "--java-home" in args:
   manifest["top"]["Debian-Java-Home"] = args["--java-home"]
if "-j" in args:
   manifest["top"]["Debian-Java-Home"] = args["-j"]
if "--javaopts" in args:
   manifest["top"]["Debian-Java-Parameters"] = args["--javaopts"]
if "-o" in args:
   manifest["top"]["Debian-Java-Parameters"] = args["-o"]

if len(notparsed) > 0:
   
   for i in notparsed:
      updatejar(i, manifest, args)

else:

   if not os.path.exists("debian/changelog"):
      print "No debian/changelog, aborting"
      sys.exit(1)

   for p in findpackages(args):
      tmpdir="debian/"+p
      if "-P" in args:
         tmpdir = args["-P"]
      if "--tmpdir" in args:
         tmpdir = args["--tmpdir"]
   
      for j in findjars(tmpdir):

         tempmanifest = copy.deepcopy(manifest)
         if os.path.exists("debian/"+p+".manifest"):
            manifestfile = "debian/"+p+".manifest"
            tempmanifest = parseManifest(manifestfile, j, tempmanifest)
         if os.path.exists("debian/manifest"):
            manifestfile = "debian/manifest"
            tempmanifest = parseManifest(manifestfile, j, tempmanifest)

         updatejar(j, tempmanifest, args)


