1#!/usr/bin/python
2#
3# Copyright (C) 2009 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""
18Description:
19   This script collects all framework Java sources from the current android
20   source code and places them in a source folder suitable for the eclipse ADT
21   plugin.
22
23See usage() below.
24
25Copyright (C) 2009 The Android Open Source Project
26Licensed under the Apache License, Version 2.0 (the "License").
27"""
28
29import re
30import os
31import sys
32import getopt
33import shutil
34
35_RE_PKG = re.compile("^\s*package\s+([^\s;]+)\s*;.*")
36
37# Holds cmd-line arguments
38class Params(object):
39    def __init__(self):
40        self.DRY = False
41        self.DIR = "frameworks libcore"
42        self.SRC = None
43        self.DST = None
44        self.CNT_USED = 0
45        self.CNT_NOPKG = 0
46
47
48# Prints a usage summary
49def usage(error=None):
50    print """
51 Description:
52   This script collects all framework Java sources from the current android
53   source code and places them in a source folder suitable for the eclipse ADT
54   plugin.
55
56 Usage:
57   %s [-n] <android-git-repo root> <sdk/platforms/xyz/sources>
58
59 The source and destination directories must already exist.
60 Use -n for a dry-run.
61
62""" % sys.argv[0]
63
64    if error:
65        print >>sys.stderr, "Error:", error
66
67
68# Parse command line args, returns a Params instance or sys.exit(2) on error
69# after printing the error and the usage.
70def parseArgs(argv):
71    p = Params()
72    error = None
73
74    try:
75        opts, args = getopt.getopt(argv[1:],
76                                   "ns:",
77                                   [ "--dry", "--sourcedir=" ])
78    except getopt.GetoptError, e:
79        error = str(e)
80
81    if error is None:
82        for o, a in opts:
83            if o in [ "-n", "--dry" ]:
84                p.DRY = True
85            elif o in [ "-s", "--sourcedir" ]:
86                p.DIR = a
87
88        if len(args) != 2:
89            error = "Missing arguments: <source> <dest>"
90        else:
91            p.SRC = args[0]
92            p.DST = args[1]
93
94            if not os.path.isdir(p.SRC):
95                error = "%s is not a directory" % p.SRC
96            elif not os.path.isdir(p.DST):
97                error = "%s is not a directory" % p.DST
98
99    if error:
100        usage(error)
101        sys.exit(2)
102
103    return p
104
105
106# Recursively parses the given directory and process java files found
107def parseSrcDir(p, srcdir):
108    if not os.path.exists(srcdir):
109        print >>sys.stderr, "Error: Skipping unknown directory", srcdir
110        return
111
112    for f in os.listdir(srcdir):
113        fp = os.path.join(srcdir, f)
114        if f.endswith(".java") and os.path.isfile(fp):
115            pkg = checkJavaFile(fp)
116            if pkg:
117                pkg = pkg.replace(".", os.path.sep)  # e.g. android.view => android/view
118                copy(p, fp, f, pkg)
119                p.CNT_USED += 1   # one more copied
120            else:
121                p.CNT_NOPKG += 1  # this java file lacked a package declaration
122        elif os.path.isdir(fp):
123            parseSrcDir(p, fp)
124
125
126# Check a java file to find its package declaration, if any
127def checkJavaFile(path):
128    print "Process", path
129
130    try:
131        f = None
132        try:
133            f = file(path)
134            for l in f.readlines():
135                m = _RE_PKG.match(l)
136                if m:
137                    return m.group(1)
138        finally:
139            if f: f.close()
140    except Exception:
141        pass
142
143    return None
144
145
146# Create destination directory based on package name then copy the
147# source file in there
148def copy(p, fp, f, pkg):
149    dstdir = os.path.join(p.DST, pkg)
150    _mkdir(p, dstdir)
151    _cp(p, fp, os.path.join(dstdir, f))
152
153
154def _mkdir(p, dir):
155    if not os.path.isdir(dir):
156        if p.DRY:
157            print "mkdir", dir
158        else:
159            os.makedirs(dir)
160
161
162def _cp(p, src, dst):
163    if p.DRY:
164        print "cp", src, dst
165    else:
166        shutil.copyfile(src, dst)
167
168
169def main():
170    p = parseArgs(sys.argv)
171    for d in p.DIR.split():
172        if d:
173            parseSrcDir(p, os.path.join(p.SRC, d))
174    print "%d java files copied" % p.CNT_USED
175    if p.CNT_NOPKG: print "%d java files ignored (no package)" % p.CNT_NOPKG
176    if p.DRY: print "This was in *DRY* mode. No copies done."
177
178
179if __name__ == "__main__":
180    main()
181