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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: build/android/pylib/base/output_manager.py
diff --git a/build/android/pylib/base/output_manager.py b/build/android/pylib/base/output_manager.py
new file mode 100644
index 0000000000000000000000000000000000000000..885186cf03a254f7fd951358f2149f37172378e4
--- /dev/null
+++ b/build/android/pylib/base/output_manager.py
@@ -0,0 +1,152 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import contextlib
+import logging
+import os
+import tempfile
+
+from devil.utils import reraiser_thread
+
+
+class Datatype(object):
+ HTML = 'html'
+ IMAGE = 'image'
+ TEXT = 'text'
+
+
+class OutputManager(object):
+
+ def __init__(self):
+ """OutputManager Constructor.
+
+ This class provides a simple interface to save test output. Subclasses
+ of this will allow users to save test results in the cloud or locally.
+ """
+ self._allow_upload = False
+ self._thread_group = None
+
+ @contextlib.contextmanager
+ def ArchivedTempfile(
+ self, out_filename, out_subdir, datatype=Datatype.TEXT):
+ """Archive file contents asynchonously and then deletes file.
+
+ Args:
+ out_filename: Name for saved file.
+ out_subdir: Directory to save |out_filename| to.
+ datatype: Datatype of file.
+
+ Returns:
+ An ArchivedFile file. This file will be uploaded async when the context
+ manager exits. AFTER the context manager exits, you can get the link to
+ where the file will be stored using the Link() API. You can use typical
+ file APIs to write and flish the ArchivedFile. You can also use file.name
+ to get the local filepath to where the underlying file exists. If you do
+ this, you are responsible of flushing the file before exiting the context
+ manager.
+ """
+ if not self._allow_upload:
+ raise Exception('Must run |SetUp| before attempting to upload!')
+
+ f = self._CreateArchivedFile(out_filename, out_subdir, datatype)
+ try:
+ yield f
+ finally:
+ f.PrepareArchive()
+
+ def archive():
+ try:
+ f.Archive()
+ finally:
+ os.remove(f.name)
+
+ thread = reraiser_thread.ReraiserThread(func=archive)
+ thread.start()
+ self._thread_group.Add(thread)
+
+ def _CreateArchivedFile(self, out_filename, out_subdir, datatype):
+ """Returns an instance of ArchivedFile."""
+ raise NotImplementedError
+
+ def SetUp(self):
+ self._allow_upload = True
+ self._thread_group = reraiser_thread.ReraiserThreadGroup()
+
+ def TearDown(self):
+ self._allow_upload = False
+ logging.info('Finishing archiving output.')
+ self._thread_group.JoinAll()
+
+ def __enter__(self):
+ self.SetUp()
+ return self
+
+ def __exit__(self, _exc_type, _exc_val, _exc_tb):
+ self.TearDown()
+
+
+class ArchivedFile(object):
+
+ def __init__(self, out_filename, out_subdir, datatype):
+ self._out_filename = out_filename
+ self._out_subdir = out_subdir
+ self._datatype = datatype
+
+ self._f = tempfile.NamedTemporaryFile(delete=False)
+ self._ready_to_archive = False
+
+ @property
+ def name(self):
+ return self._f.name
+
+ def write(self, *args, **kwargs):
+ if self._ready_to_archive:
+ raise Exception('Cannot write to file after archiving has begun!')
+ self._f.write(*args, **kwargs)
+
+ def flush(self, *args, **kwargs):
+ if self._ready_to_archive:
+ raise Exception('Cannot flush file after archiving has begun!')
+ self._f.flush(*args, **kwargs)
+
+ def Link(self):
+ """Returns location of archived file."""
+ if not self._ready_to_archive:
+ raise Exception('Cannot get link to archived file before archiving '
+ 'has begun')
+ return self._Link()
+
+ def _Link(self):
+ """Note for when overriding this function.
+
+ This function will certainly be called before the file
+ has finished being archived. Therefore, this needs to be able to know the
+ exact location of the archived file before it is finished being archived.
+ """
+ raise NotImplementedError
+
+ def PrepareArchive(self):
+ """Meant to be called synchronously to prepare file for async archiving."""
+ self.flush()
+ self._ready_to_archive = True
+ self._PrepareArchive()
+
+ def _PrepareArchive(self):
+ """Note for when overriding this function.
+
+ This function is needed for things such as computing the location of
+ content addressed files. This is called after the file is written but
+ before archiving has begun.
+ """
+ pass
+
+ def Archive(self):
+ """Archives file."""
+ if not self._ready_to_archive:
+ raise Exception('File is not ready to archive. Be sure you are not '
+ 'writing to the file and PrepareArchive has been called')
+ self._Archive()
+
+ def _Archive(self):
+ raise NotImplementedError
« 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