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..fe5359fd4d9ab30c9e426bc7201129a65aace1f5 |
--- /dev/null |
+++ b/build/android/pylib/base/output_manager.py |
@@ -0,0 +1,102 @@ |
+# 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 logging |
+import os |
+ |
+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 |
+ |
+ def ArchiveAndDeleteFile( |
+ self, in_filename, out_filename, out_subdir, datatype=Datatype.TEXT): |
+ """Context manager used to archive file contents asynchonously. |
jbudorick
2017/07/19 22:45:09
This doesn't appear to be a context manager any mo
mikecase (-- gone --)
2017/07/26 21:21:37
Done
|
+ |
+ Example Usage. |
+ |
+ try: |
+ // Create non-temporary File. Upload is done asynchonously. |
+ file = ... |
+ file.write(...) |
+ finally: |
+ output_manager.ArchiveAndDeleteFile() |
jbudorick
2017/07/19 22:45:09
This example doesn't pass any arguments to Archive
mikecase (-- gone --)
2017/07/26 21:21:37
Done
|
+ |
+ Args: |
jbudorick
2017/07/19 22:45:09
in_filename?
mikecase (-- gone --)
2017/07/26 21:21:37
Done
|
+ out_filename: Name for saved file. |
+ out_subdir: Directory to save |out_file| in. |
+ datatype: Datatype of file. |
+ |
+ Yields: |
jbudorick
2017/07/19 22:45:09
nit: Returns, not Yields
mikecase (-- gone --)
2017/07/26 21:21:37
Yeah, I changed the implementation a bunch. Seems
|
+ A tuple (filename, link). Filename is a file you write to and link is a |
+ URL to where the contents of the file will end up. |
+ """ |
+ assert self._allow_upload, 'Must run |SetUp| before attempting to upload!' |
jbudorick
2017/07/19 22:45:09
Do this w/ an explicit exception rather than an as
mikecase (-- gone --)
2017/07/26 21:21:37
Done
|
+ |
+ job = self._CreateArchiveJob( |
+ in_filename, out_filename, out_subdir, datatype) |
+ |
+ if job is None: |
+ return '' |
+ |
+ def archive(): |
+ try: |
+ job.Archive() |
+ finally: |
+ os.remove(in_filename) |
+ |
+ thread = reraiser_thread.ReraiserThread(func=archive) |
+ thread.start() |
+ self._thread_group.Add(thread) |
+ return job.Link() |
+ |
+ def _CreateArchiveJob(self, in_filepath, out_filename, out_subdir, datatype): |
+ """Returns an instance of Job that actually uploads/saves the file.""" |
+ 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 Job(object): |
+ |
+ def __init__(self, in_filepath, out_filename, out_subdir, datatype): |
+ self._in_filepath = in_filepath |
+ self._out_filename = out_filename |
+ self._out_subdir = out_subdir |
+ self._datatype = datatype |
+ |
+ def Link(self): |
+ raise NotImplementedError |
+ |
+ def Archive(self): |
+ raise NotImplementedError |