From 61208ce2e02f12240d5160d962eb626d5c90232b Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Thu, 23 Aug 2018 09:57:56 +0100 Subject: [PATCH] target: read_tree_values: handle multiline values Extend Target.read_tree_values() to handle notes that contain line breaks in their values. Underlying this method, is a call to grep -r '' /tree/root/ When files under that location contain multiple lines, grep will output each line prefixed with the path; e.g. a file "test" with the contents "one\n\ntwo\n" will be output by grep as: /tree/root/test: one /tree/root/test: /tree/root/test: two Previous implementation of read_tree_values() was assuming one value per line, and that the paths were unique. Since it wasn't checking for duplicate paths, it would simply override the earlier entries resulting with the value of "two" for test. This change ensure that such multiline values are now handled correctly, and the entire value is preserved. To keep compatibility with existing uses of read_tree_values(), the trailing new lines are stripped. --- devlib/target.py | 9 ++++++--- tests/test_target.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 tests/test_target.py diff --git a/devlib/target.py b/devlib/target.py index 5c4cfd2..147239f 100644 --- a/devlib/target.py +++ b/devlib/target.py @@ -24,7 +24,7 @@ import tarfile import tempfile import threading import xml.dom.minidom -from collections import namedtuple +from collections import namedtuple, defaultdict from devlib.host import LocalConnection, PACKAGE_BIN_DIRECTORY from devlib.module import get_module @@ -676,12 +676,15 @@ class Target(object): command = 'read_tree_values {} {}'.format(path, depth) output = self._execute_util(command, as_root=self.is_rooted, check_exit_code=check_exit_code) - result = {} + + accumulator = defaultdict(list) for entry in output.strip().split('\n'): if ':' not in entry: continue path, value = entry.strip().split(':', 1) - result[path] = value + accumulator[path].append(value) + + result = {k: '\n'.join(v).strip() for k, v in accumulator.items()} return result def read_tree_values(self, path, depth=1, dictcls=dict, check_exit_code=True): diff --git a/tests/test_target.py b/tests/test_target.py new file mode 100644 index 0000000..0cb54fe --- /dev/null +++ b/tests/test_target.py @@ -0,0 +1,32 @@ +import os +import shutil +import tempfile +from unittest import TestCase + +from devlib import LocalLinuxTarget + + +class TestReadTreeValues(TestCase): + + def test_read_multiline_values(self): + data = { + 'test1': '1', + 'test2': '2\n\n', + 'test3': '3\n\n4\n\n', + } + + tempdir = tempfile.mkdtemp(prefix='devlib-test-') + for key, value in data.items(): + path = os.path.join(tempdir, key) + with open(path, 'w') as wfh: + wfh.write(value) + + t = LocalLinuxTarget(connection_settings={'unrooted': True}) + raw_result = t.read_tree_values_flat(tempdir) + result = {os.path.basename(k): v for k, v in raw_result.items()} + + shutil.rmtree(tempdir) + + self.assertEqual({k: v.strip() + for k, v in data.items()}, + result)