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

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

Issue 2933993002: Add local results details pages.
Patch Set: More doc fixes. 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 yield f
54 f.PrepareArchive()
jbudorick 2017/08/23 16:16:19 The remainder of this function won't execute if an
mikecase (-- gone --) 2017/08/24 05:29:07 Done. GOod catch
55
56 def archive():
57 try:
58 f.Archive()
59 finally:
60 os.remove(f.name)
61
62 thread = reraiser_thread.ReraiserThread(func=archive)
63 thread.start()
64 self._thread_group.Add(thread)
65
66 def _CreateArchivedFile(self, out_filename, out_subdir, datatype):
67 """Returns an instance of ArchivedFile."""
68 raise NotImplementedError
69
70 def SetUp(self):
71 self._allow_upload = True
72 self._thread_group = reraiser_thread.ReraiserThreadGroup()
73
74 def TearDown(self):
75 self._allow_upload = False
76 logging.info('Finishing archiving output.')
77 self._thread_group.JoinAll()
78
79 def __enter__(self):
80 self.SetUp()
81 return self
82
83 def __exit__(self, _exc_type, _exc_val, _exc_tb):
84 self.TearDown()
85
jbudorick 2017/08/23 16:16:19 super nit: +1 blank line
mikecase (-- gone --) 2017/08/24 05:29:07 Done
86 class ArchivedFile(object):
87
88 def __init__(self, out_filename, out_subdir, datatype):
89 self._out_filename = out_filename
90 self._out_subdir = out_subdir
91 self._datatype = datatype
92
93 self._f = tempfile.NamedTemporaryFile(delete=False)
jbudorick 2017/08/23 16:16:19 Does this ever get removed?
mikecase (-- gone --) 2017/08/24 05:29:07 Yes. so, I think Im doing it an alright way. os.r
jbudorick 2017/08/24 13:18:45 ah, ok.
94 self.name = self._f.name
jbudorick 2017/08/23 16:16:19 nit: @property for this?
mikecase (-- gone --) 2017/08/24 05:29:07 Good idea, for some reason I forgot about those...
95 self._ready_to_archive = False
96
97 def write(self, *args, **kwargs):
98 if self._ready_to_archive:
99 raise Exception('Cannot write to file after archiving has begun!')
100 self._f.write(*args, **kwargs)
101
102 def flush(self, *args, **kwargs):
103 if self._ready_to_archive:
104 raise Exception('Cannot flush file after archiving has begun!')
105 self._f.flush(*args, **kwargs)
106
107 def Link(self):
108 """Returns location of archived file."""
109 if not self._ready_to_archive:
110 raise Exception('Cannot get link to archived file before archiving'
jbudorick 2017/08/23 16:16:19 super nit: +1 space after archiving, otherwise thi
mikecase (-- gone --) 2017/08/24 05:29:07 Done
111 'has begun')
112 return self._Link()
113
114 def _Link(self):
115 """Note for when overriding this function.
116
117 This function will certainly be called before the file
118 has finished being archived. Therefore, this needs to be able to know the
119 exact location of the archived file before it is finished being archived.
120 """
121 raise NotImplementedError
122
123 def PrepareArchive(self):
124 """Meant to be called synchronously to prepare file for async archiving."""
125 self.flush()
126 self._ready_to_archive = True
127 self._PrepareArchive()
128
129 def _PrepareArchive(self):
130 """Note for when overriding this function.
131
132 This function is needed for things such as computing the location of
133 content addressed files. This is called after the file is written but
134 before archiving has begun.
135 """
136 pass
137
138 def Archive(self):
139 """Archives file."""
140 assert self._ready_to_archive
jbudorick 2017/08/23 16:16:20 I think this should be an Exception, analogous to
mikecase (-- gone --) 2017/08/24 05:29:07 Well, this isnt well documented, but the only thin
141 self._Archive()
142
143 def _Archive(self):
144 raise NotImplementedError
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698