• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4#
5# Copyright (c) 2020 Huawei Device Co., Ltd.
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10#     http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
17#
18
19import os
20import subprocess
21from datetime import datetime
22from distutils.spawn import find_executable
23from hb_internal.common.utils import exec_command
24from hb_internal.common.utils import hb_warning
25
26
27class PreBuild:
28    def __init__(self, config):
29        self._root_path = config.root_path
30        self._out_path = config.out_path
31        self._log_path = config.log_path
32
33    def set_ccache(self):
34        ccache_local_dir = os.environ.get('CCACHE_LOCAL_DIR')
35        ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX')
36        if not ccache_local_dir:
37            ccache_local_dir = '.ccache'
38        ccache_base = os.environ.get('CCACHE_BASE')
39        if ccache_base is None:
40            ccache_base = os.path.join(self._root_path, ccache_local_dir)
41            if not os.path.exists(ccache_base):
42                os.makedirs(ccache_base)
43        ccache_log_file_name = "ccache.log"
44        if ccache_log_suffix:
45            ccache_log_file_name = "ccache." + ccache_log_suffix + ".log"
46
47        logfile = os.path.join(self._root_path, ccache_log_file_name)
48        if os.path.exists(logfile):
49            oldfile_name = ccache_log_file_name + ".old"
50            oldfile = os.path.join(self._root_path, oldfile_name)
51            if os.path.exists(oldfile):
52                os.unlink(oldfile)
53            os.rename(logfile, oldfile)
54
55        ccache_path = find_executable('ccache')
56        if ccache_path is None:
57            hb_warning('Failed to find ccache, ccache disabled.')
58            return
59        os.environ['CCACHE_EXEC'] = ccache_path
60        os.environ['CCACHE_LOGFILE'] = logfile
61        os.environ['USE_CCACHE'] = '1'
62        os.environ['CCACHE_DIR'] = ccache_base
63        os.environ['CCACHE_UMASK'] = '002'
64        os.environ['CCACHE_BASEDIR'] = self._root_path
65        ccache_max_size = os.environ.get('CCACHE_MAXSIZE')
66        if not ccache_max_size:
67            ccache_max_size = '100G'
68
69        cmd = ['ccache', '-M', ccache_max_size]
70        exec_command(cmd, log_path=self._log_path)
71
72    def set_pycache(self):
73        pycache_dir = os.path.join(self._root_path, '.pycache')
74        os.environ['PYCACHE_DIR'] = pycache_dir
75        pyd_start_cmd = [
76            'python3',
77            '{}/build/scripts/util/pyd.py'.format(self._root_path),
78            '--root',
79            pycache_dir,
80            '--start',
81        ]
82        cmd = ['/bin/bash', '-c', ' '.join(pyd_start_cmd), '&']
83        subprocess.Popen(cmd)
84
85    def rename_last_logfile(self):
86        logfile = os.path.join(self._out_path, 'build.log')
87        if os.path.exists(logfile):
88            mtime = os.stat(logfile).st_mtime
89            os.rename(logfile, '{}/build.{}.log'.format(self._out_path, mtime))
90
91    def prepare(self, args):
92        actions = [self.set_ccache, self.rename_last_logfile]
93        for action in actions:
94            action()
95
96
97class PostBuild:
98    def __init__(self, config):
99        self._root_path = config.root_path
100        self._out_path = config.out_path
101        self._log_path = config.log_path
102
103    def clean(self, start_time, disable_post_build_args):
104        if not disable_post_build_args or 'stat_ccache' not in disable_post_build_args:
105                self.stat_ccache()
106        if not disable_post_build_args or 'generate_ninja_trace' not in disable_post_build_args:
107                self.generate_ninja_trace(start_time)
108        if not disable_post_build_args or 'get_warning_list' not in disable_post_build_args:
109                self.get_warning_list()
110        if not disable_post_build_args or 'compute_overlap_rate' not in disable_post_build_args:
111                self.compute_overlap_rate()
112
113    def package_image(self):
114        image_path = os.path.join(self._out_path, 'packages/phone/images/')
115        if os.path.exists(image_path):
116            packaged_file_path = os.path.join(self._out_path, 'images.tar.gz')
117            cmd = ['tar', '-zcvf', packaged_file_path, image_path]
118            exec_command(cmd, log_path=self._log_path)
119
120    def stat_pycache(self):
121        cmd = [
122            'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path),
123            '--stat'
124        ]
125        exec_command(cmd, log_path=self._log_path)
126
127    def manage_cache_data(self):
128        cmd = [
129            'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path),
130            '--manage'
131        ]
132        exec_command(cmd, log_path=self._log_path)
133
134    def stop_pyd(self):
135        cmd = [
136            'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path),
137            '--stop'
138        ]
139        exec_command(cmd, log_path=self._log_path)
140
141    def stat_ccache(self):
142        ccache_path = find_executable('ccache')
143        if ccache_path is None:
144            return
145
146        ccache_log_file_name = "ccache.log"
147        ccache_log_suffix = os.environ.get('CCACHE_LOG_SUFFIX')
148        if ccache_log_suffix:
149            ccache_log_file_name = "ccache." + ccache_log_suffix + ".log"
150        cmd = [
151            'python3', '{}/build/scripts/summary_ccache_hitrate.py'.format(
152                self._root_path), '{}/{}'.format(self._root_path, ccache_log_file_name)
153        ]
154        exec_command(cmd, log_path=self._log_path)
155
156    def get_warning_list(self):
157        cmd = [
158            'python3',
159            '{}/build/scripts/get_warnings.py'.format(self._root_path),
160            '--build-log-file',
161            '{}/build.log'.format(self._out_path),
162            '--warning-out-file',
163            '{}/packages/WarningList.txt'.format(self._out_path),
164        ]
165        exec_command(cmd, log_path=self._log_path)
166
167    def generate_ninja_trace(self, start_time):
168        def get_unixtime(dt):
169            epoch = datetime.utcfromtimestamp(0)
170            unixtime = '%f' % ((dt - epoch).total_seconds() * 10**9)
171            return str(unixtime)
172
173        cmd = [
174            'python3',
175            '{}/build/scripts/ninja2trace.py'.format(self._root_path),
176            '--ninja-log',
177            '{}/.ninja_log'.format(self._out_path),
178            "--trace-file",
179            "{}/build.trace".format(self._out_path),
180            "--ninja-start-time",
181            get_unixtime(start_time),
182            "--duration-file",
183            "{}/sorted_action_duration.txt".format(self._out_path),
184        ]
185        exec_command(cmd, log_path=self._log_path)
186
187    def compute_overlap_rate(self):
188        cmd = [
189            'python3',
190            '{}/build/ohos/statistics/build_overlap_statistics.py'.format(
191                self._root_path), "--build-out-dir", self._out_path,
192            "--subsystem-config-file",
193            "{}/build/subsystem_config.json".format(self._root_path),
194            "--root-source-dir", self._root_path
195        ]
196        exec_command(cmd, log_path=self._log_path)
197