1a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov#!/usr/bin/python
2a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov#
3a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov# This tool is used to compare headers between Bionic and NDK
4a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov# script should be in development/ndk/tools for correct roots autodetection
5a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov#
6a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
7a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynovimport sys, os, os.path
8a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynovimport subprocess
9a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynovimport argparse, textwrap
10a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
11a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynovclass FileCollector:
12a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    """Collect headers from Bionic and sysroot
13a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
14a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    sysincludes data format:
15a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    sysincludes                     -- dict with arch as key
16a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    sysincludes[arch]               -- dict with includes root as key
17a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    sysincludes[arch][root]         -- dict with header name as key
18a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    sysincludes[arch][root][header] -- list [last_platform, ..., first_platform]
19a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    """
20a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
21a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def __init__(self, platforms_root, archs):
22a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Init platform roots and structures before collecting"""
23a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.platforms = []
24a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.archs = archs
25a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.sysincludes = {}
26a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for arch in self.archs:
27a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            self.sysincludes[arch] = {}
28a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
29a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        ## scaning available platforms ##
30a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for dirname in os.listdir(platforms_root):
31a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            path = os.path.join(platforms_root, dirname)
32a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            if os.path.isdir(path) and ('android' in dirname):
33a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                self.platforms.append(dirname)
34a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        try:
35a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            self.platforms.sort(key = lambda s: int(s.split('-')[1]))
36a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            self.root = platforms_root
37a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        except Exception:
38a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            print 'Wrong platforms list \n{0}'.format(str(self.platforms))
39a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
40a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def scan_dir(self, root):
41a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Non-recursive file scan in directory"""
42a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        files = []
43a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for filename in os.listdir(root):
44a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            if os.path.isfile(os.path.join(root, filename)):
45a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                files.append(filename)
46a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        return files
47a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
48a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def scan_includes(self, root):
49a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Recursive includes scan in given root"""
50a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        includes = []
51a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        includes_root = os.path.join(root, 'include')
52a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        if not os.path.isdir(includes_root):
53a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            return includes
54a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
55a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        ## recursive scanning ##
56a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        includes.append(('', self.scan_dir(includes_root)))
57a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for dirname, dirnames, filenames in os.walk(includes_root):
58a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            for subdirname in dirnames:
59a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                path = os.path.join(dirname, subdirname)
60a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                relpath = os.path.relpath(path, includes_root)
61a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                includes.append((relpath, self.scan_dir(path)))
62a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
63a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        return includes
64a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
65a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def scan_archs_includes(self, root):
66a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Scan includes for all defined archs in given root"""
67a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        includes = {}
68a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        includes['common'] = self.scan_includes(root)
69a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
70a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for arch in [a for a in self.archs if a != 'common']:
71a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            arch_root = os.path.join(root, arch)
72a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            includes[arch] = self.scan_includes(arch_root)
73a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
74a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        return includes
75a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
76a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def scan_platform_includes(self, platform):
77a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Scan all platform includes of one layer"""
78a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        platform_root = os.path.join(self.root, platform)
79a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        return self.scan_archs_includes(platform_root)
80a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
81a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def scan_bionic_includes(self, bionic_root):
82a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Scan Bionic's libc includes"""
83a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.bionic_root = bionic_root
84a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.bionic_includes = self.scan_archs_includes(bionic_root)
85a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
86a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def append_sysincludes(self, arch, root, headers, platform):
87a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Merge new platform includes layer with current sysincludes"""
88a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        if not (root in self.sysincludes[arch]):
89a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            self.sysincludes[arch][root] = {}
90a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
91a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for include in headers:
92a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            if include in self.sysincludes[arch][root]:
93a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                last_platform = self.sysincludes[arch][root][include][0]
94a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                if platform != last_platform:
95a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    self.sysincludes[arch][root][include].insert(0, platform)
96a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            else:
97a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                self.sysincludes[arch][root][include] = [platform]
98a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
99a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def update_to_platform(self, platform):
100a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Update sysincludes state by applying new platform layer"""
101a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        new_includes = self.scan_platform_includes(platform)
102a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for arch in self.archs:
103a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            for pack in new_includes[arch]:
104a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                self.append_sysincludes(arch, pack[0], pack[1], platform)
105a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
106a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def scan_sysincludes(self, target_platform):
107a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Fully automated sysincludes collector upto specified platform"""
108a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        version = int(target_platform.split('-')[1])
109a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        layers = filter(lambda s: int(s.split('-')[1]) <= version, self.platforms)
110a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for platform in layers:
111a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            self.update_to_platform(platform)
112a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
113a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
114a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynovclass BionicSysincludes:
115a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def set_roots(self):
116a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Automated roots initialization (AOSP oriented)"""
117a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        script_root = os.path.dirname(os.path.realpath(__file__))
118a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.aosp_root      = os.path.normpath(os.path.join(script_root, '../../..'))
119a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.platforms_root = os.path.join(self.aosp_root, 'development/ndk/platforms')
120a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.bionic_root    = os.path.join(self.aosp_root, 'bionic/libc')
121a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
122a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def scan_includes(self):
123a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Scan all required includes"""
124a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.collector = FileCollector(self.platforms_root, self.archs)
125a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        ## detecting latest platform ##
126a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.platforms = self.collector.platforms
127a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        latest_platform = self.platforms[-1:][0]
128a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        ## scanning both includes repositories ##
129a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.collector.scan_sysincludes(latest_platform)
130a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.collector.scan_bionic_includes(self.bionic_root)
131a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        ## scan results ##
132a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.sysincludes     = self.collector.sysincludes
133a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.bionic_includes = self.collector.bionic_includes
134a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
135a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def git_diff(self, file_origin, file_probe):
136a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Difference routine based on git diff"""
137a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        try:
138a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            subprocess.check_output(['git', 'diff', '--no-index', file_origin, file_probe])
139a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        except subprocess.CalledProcessError as error:
140a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            return error.output
141a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        return None
142a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
143a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def match_with_bionic_includes(self):
144a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Compare headers between Bionic and sysroot"""
145a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.diffs = {}
146a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        ## for every arch ##
147a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for arch in self.archs:
148a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            arch_root = (lambda s: s if s != 'common' else '')(arch)
149a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            ## for every includes directory ##
150a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            for pack in self.bionic_includes[arch]:
151a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                root = pack[0]
152a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                path_bionic = os.path.join(self.bionic_root, arch_root, 'include', root)
153a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                ## for every header that both in Bionic and sysroot ##
154a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                for include in pack[1]:
155a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    if include in self.sysincludes[arch][root]:
156a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        ## completing paths ##
157a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        platform = self.sysincludes[arch][root][include][0]
158a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        file_origin = os.path.join(path_bionic, include)
159a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        file_probe  = os.path.join(self.platforms_root, platform, arch_root, 'include', root, include)
160a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        ## comparison by git diff ##
161a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        output = self.git_diff(file_origin, file_probe)
162a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        if output is not None:
163a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                            if arch not in self.diffs:
164a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                                self.diffs[arch] = {}
165a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                            if root not in self.diffs[arch]:
166a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                                self.diffs[arch][root] = {}
167a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                            ## storing git diff ##
168a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                            self.diffs[arch][root][include] = output
169a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
170a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def print_history(self, arch, root, header):
171a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Print human-readable list header updates across platforms"""
172a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        history = self.sysincludes[arch][root][header]
173a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        for platform in self.platforms:
174a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            entry = (lambda s: s.split('-')[1] if s in history else '-')(platform)
175a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            print '{0:3}'.format(entry),
176a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        print ''
177a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
178a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def show_and_store_results(self):
179a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        """Print summary list of headers and write diff-report to file"""
180a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        try:
181a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            diff_fd = open(self.diff_file, 'w')
182a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            for arch in self.archs:
183a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                if arch not in self.diffs:
184a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    continue
185a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                print '{0}/'.format(arch)
186a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                roots = self.diffs[arch].keys()
187a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                roots.sort()
188a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                for root in roots:
189a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    print '    {0}/'.format((lambda s: s if s != '' else '../include')(root))
190a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    includes = self.diffs[arch][root].keys()
191a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    includes.sort()
192a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    for include in includes:
193a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        print '        {0:32}'.format(include),
194a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        self.print_history(arch, root, include)
195a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        diff = self.diffs[arch][root][include]
196a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        diff_fd.write(diff)
197a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        diff_fd.write('\n\n')
198a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                    print ''
199a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                print ''
200a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
201a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        finally:
202a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            diff_fd.close()
203a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
204a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    def main(self):
205a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.set_roots()
206a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.scan_includes()
207a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.match_with_bionic_includes()
208a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        self.show_and_store_results()
209a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
210a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynovif __name__ == '__main__':
211a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    ## configuring command line parser ##
212a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    parser = argparse.ArgumentParser(formatter_class = argparse.RawTextHelpFormatter,
213a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                                     description = 'Headers comparison tool between bionic and NDK platforms')
214a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    parser.epilog = textwrap.dedent('''
215a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    output format:
216a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    {architecture}/
217a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        {directory}/
218a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov            {header name}.h  {platforms history}
219a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
220a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    platforms history format:
221a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        number X means header has been changed in android-X
222a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        `-\' means it is the same
223a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
224a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    diff-report format:
225a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        git diff output for all headers
226a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov        use --diff option to specify filename
227a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    ''')
228a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
229a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    parser.add_argument('--archs', metavar = 'A', nargs = '+',
230a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        default = ['common', 'arm', 'x86', 'mips'],
231a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        help = 'list of architectures\n(default: common arm x86 mips)')
232a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    parser.add_argument('--diff', metavar = 'FILE', nargs = 1,
233a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        default = ['headers-diff-bionic-vs-ndk.diff'],
234a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov                        help = 'diff-report filename\n(default: `bionic-vs-sysincludes_report.diff\')')
235a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
236a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    ## parsing arguments ##
237a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    args = parser.parse_args()
238a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
239a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    ## doing work ##
240a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    app = BionicSysincludes()
241a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    app.archs = map((lambda s: 'arch-{0}'.format(s) if s != 'common' else s), args.archs)
242a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    app.diff_file = args.diff[0]
243a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    app.main()
244a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov
245a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    print 'Headers listed above are DIFFERENT in Bionic and NDK platforms'
246a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    print 'See `{0}\' for details'.format(app.diff_file)
247a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    print 'See --help for format description.'
248a67bdae6b1de43331cec363111a858d0da069b4dGrigoriy Kraynov    print ''
249