• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# Copyright (C) 2017 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import datetime
18import logging
19import os
20import shutil
21
22def NotNoneStr(item):
23    '''Convert a veriable to string only if it is not None'''
24    return str(item) if item is not None else None
25
26class ReportFileUtil(object):
27    '''Utility class for report file saving.
28
29    Contains methods to save report files or read incremental parts of
30    report files to a destination folder and get URLs.
31    Used by profiling util, systrace util, and host log reporting.
32
33    Attributes:
34        _flatten_source_dir: bool, whether to flatten source directory
35                             structure in destination directory. Current
36                             implementation assumes no duplicated fine names
37        _use_destination_date_dir: bool, whether to create date directory
38                                   in destination directory
39        _source_dir: string, source directory that contains report files
40        _destination_dir: string, destination directory for report saving
41        _url_prefix: string, a prefix added to relative destination file paths.
42                     If set to None, will use parent directory path.
43    '''
44
45    def __init__(self,
46                 flatten_source_dir=False,
47                 use_destination_date_dir=False,
48                 source_dir=None,
49                 destination_dir=None,
50                 url_prefix=None):
51        source_dir = NotNoneStr(source_dir)
52        destination_dir = NotNoneStr(destination_dir)
53        url_prefix = NotNoneStr(url_prefix)
54
55        self._flatten_source_dir = flatten_source_dir
56        self._use_destination_date_dir = use_destination_date_dir
57        self._source_dir = source_dir
58        self._destination_dir = destination_dir
59        self._url_prefix = url_prefix
60
61    def _ConvertReportPath(self,
62                           src_path,
63                           root_dir=None,
64                           new_file_name=None,
65                           file_name_prefix=None):
66        '''Convert report source file path to destination path and url.
67
68        Args:
69            src_path: string, source report file path.
70            new_file_name: string, new file name to use on destination.
71            file_name_prefix: string, prefix added to destination file name.
72                              if new_file_name is set, prefix will be added
73                              to new_file_name as well.
74
75        Returns:
76            tuple(string, string), containing destination path and url
77        '''
78        root_dir = NotNoneStr(root_dir)
79        new_file_name = NotNoneStr(new_file_name)
80        file_name_prefix = NotNoneStr(file_name_prefix)
81
82        dir_path = os.path.dirname(src_path)
83
84        relative_path = os.path.basename(src_path)
85        if new_file_name:
86            relative_path = new_file_name
87        if file_name_prefix:
88            relative_path = file_name_prefix + relative_path
89        if not self._flatten_source_dir and root_dir:
90            relative_path = os.path.join(
91                os.path.relpath(dir_path, root_dir), relative_path)
92        if self._use_destination_date_dir:
93            now = datetime.datetime.now()
94            date = now.strftime('%Y-%m-%d')
95            relative_path = os.path.join(date, relative_path)
96
97        dest_path = os.path.join(self._destination_dir, relative_path)
98
99        url = dest_path
100        if self._url_prefix is not None:
101            url = self._url_prefix + relative_path
102
103        return dest_path, url
104
105    def _PushReportFile(self, src_path, dest_path):
106        '''Push a report file to destination.
107
108        Args:
109            src_path: string, source path of report file
110            dest_path: string, destination path of report file
111        '''
112        src_path = NotNoneStr(src_path)
113        dest_path = NotNoneStr(dest_path)
114
115        parent_dir = os.path.dirname(dest_path)
116        if not os.path.exists(parent_dir):
117            try:
118                os.makedirs(parent_dir)
119            except OSError as e:
120                logging.exception(e)
121        shutil.copy(src_path, dest_path)
122
123    def SaveReport(self, src_path, new_file_name=None, file_name_prefix=None):
124        '''Save report file to destination.
125
126        Args:
127            src_path: string, source report file path.
128            new_file_name: string, new file name to use on destination.
129            file_name_prefix: string, prefix added to destination file name.
130                              if new_file_name is set, prefix will be added
131                              to new_file_name as well.
132
133        Returns:
134            string, destination URL of saved report file.
135            If url_prefix is set to None, will return destination path of
136            report files. If error happens during read or write operation,
137            this method will return None.
138        '''
139        src_path = NotNoneStr(src_path)
140        new_file_name = NotNoneStr(new_file_name)
141        file_name_prefix = NotNoneStr(file_name_prefix)
142
143        try:
144            dest_path, url = self._ConvertReportPath(
145                src_path,
146                new_file_name=new_file_name,
147                file_name_prefix=file_name_prefix)
148            self._PushReportFile(src_path, dest_path)
149
150            return url
151        except IOError as e:
152            logging.exception(e)
153
154    def SaveReportsFromDirectory(self, source_dir=None, file_name_prefix=None):
155        '''Save report files from source directory to destination.
156
157        Args:
158            source_dir: string, source directory where report files are stored.
159                        if None, class attribute source_dir will be used.
160                        Default is None.
161            file_name_prefix: string, prefix added to destination file name
162
163        Returns:
164            A list of string, containing destination URLs of saved report files.
165            If url_prefix is set to None, will return destination path of
166            report files. If error happens during read or write operation,
167            this method will return None.
168        '''
169        source_dir = NotNoneStr(source_dir)
170        file_name_prefix = NotNoneStr(file_name_prefix)
171        if not source_dir:
172            source_dir = self._source_dir
173
174        try:
175            urls = []
176
177            for (dirpath, dirnames, filenames) in os.walk(
178                    source_dir, followlinks=False):
179                for filename in filenames:
180                    src_path = os.path.join(dirpath, filename)
181                    dest_path, url = self._ConvertReportPath(
182                        src_path,
183                        root_dir=source_dir,
184                        file_name_prefix=file_name_prefix)
185
186                    #TODO(yuexima): handle duplicated destination file names
187                    self._PushReportFile(src_path, dest_path)
188                    urls.append(url)
189
190            return urls
191        except IOError as e:
192            logging.exception(e)
193