Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: build/android/pylib/base/output_manager.py

Issue 2933993002: Add local results details pages.
Patch Set: Fix some of Johns comments. Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2017 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import contextlib
6 import logging
7 import os
8 import tempfile
9
10 from devil.utils import reraiser_thread
11
12
13 class Datatype(object):
14 HTML = 'html'
15 IMAGE = 'image'
16 TEXT = 'text'
17
18
19 class OutputManager(object):
20
21 def __init__(self):
22 """OutputManager Constructor.
23
24 This class provides a simple interface to save test output. Subclasses
25 of this will allow users to save test results in the cloud or locally.
26 """
27 self._allow_upload = False
28 self._thread_group = None
29
30 @contextlib.contextmanager
31 def ArchivedTempfile(
32 self, out_filename, out_subdir, datatype=Datatype.TEXT):
33 """Archive file contents asynchonously and then deletes file.
34
35 Args:
36 out_filename: Name for saved file.
37 out_subdir: Directory to save |out_filename| to.
38 datatype: Datatype of file.
39
40 Returns:
41 An ArchivedFile file. This file will be uploaded async when the context
42 manager exits. AFTER the context manager exits, you can get the link to
43 where the file will be stored using the Link() API. You can use typical
44 file APIs to write and flish the ArchivedFile. You can also use file.name
45 to get the local filepath to where the underlying file exists. If you do
46 this, you are responsible of flushing the file before exiting the context
47 manager.
48 """
49 if not self._allow_upload:
50 raise Exception('Must run |SetUp| before attempting to upload!')
51
52 f = self._CreateArchivedFile(out_filename, out_subdir, datatype)
53 try:
54 yield f
55 finally:
56 f.PrepareArchive()
57
58 def archive():
59 try:
60 f.Archive()
61 finally:
62 os.remove(f.name)
63
64 thread = reraiser_thread.ReraiserThread(func=archive)
65 thread.start()
66 self._thread_group.Add(thread)
67
68 def _CreateArchivedFile(self, out_filename, out_subdir, datatype):
69 """Returns an instance of ArchivedFile."""
70 raise NotImplementedError
71
72 def SetUp(self):
73 self._allow_upload = True
74 self._thread_group = reraiser_thread.ReraiserThreadGroup()
75
76 def TearDown(self):
77 self._allow_upload = False
78 logging.info('Finishing archiving output.')
79 self._thread_group.JoinAll()
80
81 def __enter__(self):
82 self.SetUp()
83 return self
84
85 def __exit__(self, _exc_type, _exc_val, _exc_tb):
86 self.TearDown()
87
88
89 class ArchivedFile(object):
90
91 def __init__(self, out_filename, out_subdir, datatype):
92 self._out_filename = out_filename
93 self._out_subdir = out_subdir
94 self._datatype = datatype
95
96 self._f = tempfile.NamedTemporaryFile(delete=False)
97 self._ready_to_archive = False
98
99 @property
100 def name(self):
101 return self._f.name
102
103 def write(self, *args, **kwargs):
104 if self._ready_to_archive:
105 raise Exception('Cannot write to file after archiving has begun!')
106 self._f.write(*args, **kwargs)
107
108 def flush(self, *args, **kwargs):
109 if self._ready_to_archive:
110 raise Exception('Cannot flush file after archiving has begun!')
111 self._f.flush(*args, **kwargs)
112
113 def Link(self):
114 """Returns location of archived file."""
115 if not self._ready_to_archive:
116 raise Exception('Cannot get link to archived file before archiving '
117 'has begun')
118 return self._Link()
119
120 def _Link(self):
121 """Note for when overriding this function.
122
123 This function will certainly be called before the file
124 has finished being archived. Therefore, this needs to be able to know the
125 exact location of the archived file before it is finished being archived.
126 """
127 raise NotImplementedError
128
129 def PrepareArchive(self):
130 """Meant to be called synchronously to prepare file for async archiving."""
131 self.flush()
132 self._ready_to_archive = True
133 self._PrepareArchive()
134
135 def _PrepareArchive(self):
136 """Note for when overriding this function.
137
138 This function is needed for things such as computing the location of
139 content addressed files. This is called after the file is written but
140 before archiving has begun.
141 """
142 pass
143
144 def Archive(self):
145 """Archives file."""
146 if not self._ready_to_archive:
147 raise Exception('File is not ready to archive. Be sure you are not '
148 'writing to the file and PrepareArchive has been called')
149 self._Archive()
150
151 def _Archive(self):
152 raise NotImplementedError
OLDNEW
« no previous file with comments | « build/android/pylib/base/environment_factory.py ('k') | build/android/pylib/base/output_manager_factory.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698