diff --git a/devlib/target.py b/devlib/target.py index fb628ae..8e93e21 100644 --- a/devlib/target.py +++ b/devlib/target.py @@ -29,6 +29,7 @@ import threading import xml.dom.minidom import copy from collections import namedtuple, defaultdict +from contextlib import contextmanager from pipes import quote from past.builtins import long from past.types import basestring @@ -51,6 +52,7 @@ from devlib.utils.android import AdbConnection, AndroidProperties, LogcatMonitor from devlib.utils.misc import memoized, isiterable, convert_new_lines from devlib.utils.misc import commonprefix, merge_lists from devlib.utils.misc import ABI_MAP, get_cpu_name, ranges_to_list +from devlib.utils.misc import batch_contextmanager from devlib.utils.types import integer, boolean, bitmask, identifier, caseless_string, bytes_regex @@ -70,7 +72,6 @@ GOOGLE_DNS_SERVER_ADDRESS = '8.8.8.8' installed_package_info = namedtuple('installed_package_info', 'apk_path package') - class Target(object): path = None @@ -481,6 +482,18 @@ class Target(object): def read_bool(self, path): return self.read_value(path, kind=boolean) + @contextmanager + def revertable_write_value(self, path, value, verify=True): + orig_value = self.read_value(path) + try: + self.write_value(path, value, verify) + yield + finally: + self.write_value(path, orig_value, verify) + + def batch_revertable_write_value(self, kwargs_list): + return batch_contextmanager(self.revertable_write_value, kwargs_list) + def write_value(self, path, value, verify=True): value = str(value) self.execute('echo {} > {}'.format(quote(value), quote(path)), check_exit_code=False, as_root=True) diff --git a/doc/target.rst b/doc/target.rst index ea1dc78..d7472b6 100644 --- a/doc/target.rst +++ b/doc/target.rst @@ -346,6 +346,18 @@ Target some sysfs entries silently failing to set the written value without returning an error code. +.. method:: Target.revertable_write_value(path, value [, verify]) + + Same as :meth:`Target.write_value`, but as a context manager that will write + back the previous value on exit. + +.. method:: Target.batch_revertable_write_value(kwargs_list) + + Calls :meth:`Target.revertable_write_value` with all the keyword arguments + dictionary given in the list. This is a convenience method to update + multiple files at once, leaving them in their original state on exit. If one + write fails, all the already-performed writes will be reverted as well. + .. method:: Target.read_tree_values(path, depth=1, dictcls=dict, [, tar [, decode_unicode [, strip_null_char ]]]): Read values of all sysfs (or similar) file nodes under ``path``, traversing