#!/usr/bin/python # # Copyright (C) 2011 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import re import os import sys import getopt import zipfile VERBOSE = False TOP_FOLDER = "src" _RE_PKG = re.compile("^\s*package\s+([^\s;]+)\s*;.*") # Holds cmd-line arguments and context information class Params(object): def __init__(self): self.DRY = False self.PROPS = None self.SRC = None self.DST = None self.CNT_USED = 0 self.CNT_NOPKG = 0 # DIR is the list of directories to scan in TOPDIR. self.DIR = "frameworks libcore" # IGNORE is a list of namespaces to ignore. Must be java # package definitions (e.g. "com.blah.foo.") self.IGNORE = [ "sun.", "libcore.", "dalvik.", "com.test.", "com.google.", "coretestutils.", "test.", "test2.", "tests." ] self.zipfile = None def verbose(msg, *args): """Prints a verbose message to stderr if --verbose is set.""" global VERBOSE if VERBOSE: if args: msg = msg % args print >>sys.stderr, msg # Prints a usage summary def usage(error=None): print """ Description: This script collects all framework Java sources from the current android source code and places them in a source.zip file that can be distributed by the SDK Manager. Usage: %s [-n|-v] <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). """ % sys.argv[0] if error: print >>sys.stderr, "Error:", error # Parse command line args, returns a Params instance or sys.exit(2) on error # after printing the error and the usage. def parseArgs(argv): global VERBOSE p = Params() error = None try: opts, args = getopt.getopt(argv[1:], "vns:", [ "--verbose", "--dry", "--sourcedir=" ]) except getopt.GetoptError, e: error = str(e) if error is None: for o, a in opts: if o in [ "-n", "--dry" ]: p.DRY = True if o in [ "-v", "--verbose" ]: VERBOSE = True elif o in [ "-s", "--sourcedir" ]: p.DIR = a if len(args) != 3: error = "Missing arguments: <source> <dest>" else: p.PROPS = args[0] p.DST = args[1] p.SRC = args[2] if not os.path.isfile(p.PROPS): error = "%s is not a file" % p.PROPS if not os.path.isdir(p.SRC): error = "%s is not a directory" % p.SRC if error: usage(error) sys.exit(2) return p # Recursively parses the given directory and processes java files found def parseSrcDir(p, srcdir): if not os.path.exists(srcdir): verbose("Error: Skipping unknown directory %s", srcdir) return for filename in os.listdir(srcdir): filepath = os.path.join(srcdir, filename) if filename.endswith(".java") and os.path.isfile(filepath): pkg = checkJavaFile(filepath) if not pkg: verbose("No package found in %s", filepath) if pkg: # Should we ignore this package? for ignore in p.IGNORE: if pkg.startswith(ignore): verbose("Ignore package %s [%s]", pkg, filepath) pkg = None break if pkg: pkg = pkg.replace(".", os.path.sep) # e.g. android.view => android/view copy(p, filepath, pkg) p.CNT_USED += 1 else: p.CNT_NOPKG += 1 elif os.path.isdir(filepath): parseSrcDir(p, filepath) # Check a java file to find its package declaration, if any def checkJavaFile(path): try: f = None try: f = file(path) for l in f.readlines(): m = _RE_PKG.match(l) if m: return m.group(1) finally: if f: f.close() except Exception: pass return None # 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 p.DRY: print >>sys.stderr, "zip %s [%s]" % (arc_path, filepath) elif p.zipfile is not None: p.zipfile.write(filepath, arc_path) def main(): p = parseArgs(sys.argv) 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") for d in p.DIR.split(): if d: parseSrcDir(p, os.path.join(p.SRC, d)) finally: if z is not None: z.close() print "%s: %d java files copied" % (p.DST, p.CNT_USED) if p.CNT_NOPKG: print "%s: %d java files ignored" % (p.DST, p.CNT_NOPKG) if p.DRY: print >>sys.stderr, "This was in *DRY* mode. No copies done." if __name__ == "__main__": main() # For emacs: # -*- tab-width: 4; -*-