SDK: fix script creating platform source archive.

It turns out that the way I use Python to create ZIP
archives is plain wrong. Some files simply don't have the
right size and we get EOFException when unzipping with
Java's ZipFile.

This change adds a flag to instead simply copy all the
files we want and then run the 'zip' system command.
The python zip facility is left there intact in case
I want to go back and fix it later (I'm going to assume
it's my usage that's wrong before really blaming python).

Change-Id: Iea178a49be0bf23c91c01a2e036ae7a76def2b55
diff --git a/build/tools/mk_sources_zip.py b/build/tools/mk_sources_zip.py
index 3d4c582..4aaa714 100755
--- a/build/tools/mk_sources_zip.py
+++ b/build/tools/mk_sources_zip.py
@@ -19,6 +19,8 @@
 import os
 import sys
 import getopt
+import shutil
+import subprocess
 import zipfile
 
 VERBOSE = False
@@ -28,6 +30,7 @@
 # Holds cmd-line arguments and context information
 class Params(object):
     def __init__(self):
+        self.EXEC_ZIP = False
         self.DRY = False
         self.PROPS = None
         self.SRC = None
@@ -36,6 +39,7 @@
         self.CNT_NOPKG = 0
         # DIR is the list of directories to scan in TOPDIR.
         self.DIR = "frameworks libcore"
+        self.IGNORE_DIR = [ "hosttests" ]
         # IGNORE is a list of namespaces to ignore. Must be java
         # package definitions (e.g. "com.blah.foo.")
         self.IGNORE = [ "sun.", "libcore.", "dalvik.",
@@ -62,12 +66,13 @@
    by the SDK Manager.
 
  Usage:
-   %s [-n|-v] <source.properties> <sources.zip> <topdir>
+   %s [-n|-v|-z] <source.properties> <sources.zip> <topdir>
 
  The source.properties file must exist and will be injected in the Zip file.
  The source directory must already exist.
  Use -v for verbose output (lists each file being picked up or ignored).
  Use -n for a dry-run (doesn't write the zip file).
+ Use -z to use the system 'zip' command instead of the Python Zip module.
 
 """ % sys.argv[0]
 
@@ -84,19 +89,25 @@
 
     try:
         opts, args = getopt.getopt(argv[1:],
-                                   "vns:",
-                                   [ "--verbose", "--dry", "--sourcedir=" ])
+                         "zvns:",
+                         [ "exec-zip", "verbose", "dry", "sourcedir=" ])
     except getopt.GetoptError, e:
         error = str(e)
 
     if error is None:
         for o, a in opts:
             if o in [ "-n", "--dry" ]:
+                # Dry mode: don't copy/zip, print what would be done.
                 p.DRY = True
             if o in [ "-v", "--verbose" ]:
+                # Verbose mode. Display everything that's going on.
                 VERBOSE = True
             elif o in [ "-s", "--sourcedir" ]:
+                # The source directories to process (space separated list)
                 p.DIR = a
+            elif o in [ "-z", "--exec-zip" ]:
+                # Don't use Python zip, instead call the 'zip' system exec.
+                p.EXEC_ZIP = True
 
         if len(args) != 3:
             error = "Missing arguments: <source> <dest>"
@@ -131,8 +142,11 @@
                 verbose("No package found in %s", filepath)
             if pkg:
                 # Should we ignore this package?
+                pkg2 = pkg
+                if not "." in pkg2:
+                    pkg2 += "."
                 for ignore in p.IGNORE:
-                    if pkg.startswith(ignore):
+                    if pkg2.startswith(ignore):
                         verbose("Ignore package %s [%s]", pkg, filepath)
                         pkg = None
                         break
@@ -144,7 +158,8 @@
             else:
                 p.CNT_NOPKG += 1
         elif os.path.isdir(filepath):
-            parseSrcDir(p, filepath)
+            if not filename in p.IGNORE_DIR:
+                parseSrcDir(p, filepath)
 
 
 # Check a java file to find its package declaration, if any
@@ -165,14 +180,41 @@
     return None
 
 
+USED_ARC_PATH = {}
+
 # Copy the given file (given its absolute filepath) to
 # the relative desk_pkg directory in the zip file.
 def copy(p, filepath, dest_pkg):
     arc_path = os.path.join(TOP_FOLDER, dest_pkg, os.path.basename(filepath))
+    if arc_path in USED_ARC_PATH:
+        verbose("Ignore duplicate archive path %s", arc_path)
+    USED_ARC_PATH[arc_path] = 1
     if p.DRY:
         print >>sys.stderr, "zip %s [%s]" % (arc_path, filepath)
     elif p.zipfile is not None:
-        p.zipfile.write(filepath, arc_path)
+        if p.EXEC_ZIP:
+            # zipfile is a path. Copy to it.
+            dest_path = os.path.join(p.zipfile, arc_path)
+            dest_dir = os.path.dirname(dest_path)
+            if not os.path.isdir(dest_dir):
+                os.makedirs(dest_dir)
+            shutil.copyfile(filepath, dest_path)
+        else:
+            # zipfile is a ZipFile object. Compress with it.
+            p.zipfile.write(filepath, arc_path)
+
+
+def shellExec(*cmd):
+  """
+  Executes the given system command.
+
+  The command must be split into a list (c.f. shext.split().)
+
+  This raises an exception if the command fails.
+  Stdin/out/err are not being redirected.
+  """
+  verbose("exec: %s", repr(cmd))
+  subprocess.check_call(cmd)
 
 
 def main():
@@ -180,11 +222,28 @@
     z = None
     try:
         if not p.DRY:
-            p.zipfile = z = zipfile.ZipFile(p.DST, "w", zipfile.ZIP_DEFLATED)
-            z.write(p.PROPS, TOP_FOLDER + "/source.properties")
+            if p.EXEC_ZIP:
+                p.zipfile = p.DST + "_temp_dir"
+                if os.path.exists(p.zipfile):
+                    shutil.rmtree(p.zipfile)
+                props_dest = os.path.join(p.zipfile, TOP_FOLDER + "/source.properties")
+                os.makedirs(os.path.dirname(props_dest))
+                shutil.copyfile(p.PROPS, props_dest)
+            else:
+                p.zipfile = z = zipfile.ZipFile(p.DST, "w", zipfile.ZIP_DEFLATED)
+                z.write(p.PROPS, TOP_FOLDER + "/source.properties")
         for d in p.DIR.split():
             if d:
                 parseSrcDir(p, os.path.join(p.SRC, d))
+        if p.EXEC_ZIP and not p.DRY:
+            curr_dir = os.getcwd()
+            os.chdir(p.zipfile)
+            if os.path.exists("_temp.zip"):
+                os.unlink("_temp.zip");
+            shellExec("zip", "-9r", "_temp.zip", TOP_FOLDER)
+            os.chdir(curr_dir)
+            shutil.move(os.path.join(p.zipfile, "_temp.zip"), p.DST)
+            shutil.rmtree(p.zipfile)
     finally:
         if z is not None:
             z.close()
diff --git a/build/tools/sdk_repo.mk b/build/tools/sdk_repo.mk
index de48e57..cc0d1be 100644
--- a/build/tools/sdk_repo.mk
+++ b/build/tools/sdk_repo.mk
@@ -90,7 +90,7 @@
 define mk-sdk-repo-sources
 $(call sdk-repo-pkg-zip,$(1),$(2),$(3)): $(2) $(TOPDIR)development/sdk/source_source.properties
 	@echo "Building SDK sources package"
-	$(hide) $(TOPDIR)development/build/tools/mk_sources_zip.py \
+	$(hide) $(TOPDIR)development/build/tools/mk_sources_zip.py --exec-zip \
 			$(TOPDIR)development/sdk/source_source.properties \
 			$(call sdk-repo-pkg-zip,$(1),$(2),$(3)) \
 			$(TOPDIR).