target: add support for target side scripts

Some complex operations are faster if executed on the target side with the
help of a small script. For example, reading the current frequency and
or governor for all the online CPUs.

This patch adds a support script to be deployed on the target as well as
an internal utility function which allows to call functions provided by
that support script.

The support script has to be cross platform, thus:
1. only a limited set of shell functions can be used, which must be supported
   both in BASH and the Android shell
2. some paths needs to be defined depending on the specific target

To address the last constrain, this patch provides a "template" script which
contains some tokens "__DEVLIB_<TOKEN>__" that are replaced right before to
push the script on the target.

Signed-off-by: Patrick Bellasi <patrick.bellasi@arm.com>
diff --git a/.gitignore b/.gitignore
index d15a155..6475149 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@
 *.orig
 .ropeproject
 *.egg-info
+devlib/bin/scripts/shutils
diff --git a/devlib/bin/scripts/shutils.in b/devlib/bin/scripts/shutils.in
new file mode 100755
index 0000000..33bb0e1
--- /dev/null
+++ b/devlib/bin/scripts/shutils.in
@@ -0,0 +1,21 @@
+#!__DEVLIB_SHELL__
+
+CMD=$1
+shift
+
+BUSYBOX=${BUSYBOX:-__DEVLIB_BUSYBOX__}
+GREP=${GREP:-$BUSYBOX grep}
+SED=${SED:-$BUSYBOX sed}
+
+
+################################################################################
+# Main Function Dispatcher
+################################################################################
+
+case $CMD in
+*)
+    echo "Command [$CMD] not supported"
+    exit -1
+esac
+
+# vim: tabstop=4 shiftwidth=4
diff --git a/devlib/target.py b/devlib/target.py
index e744110..b0a3737 100644
--- a/devlib/target.py
+++ b/devlib/target.py
@@ -197,6 +197,22 @@
         self.execute('mkdir -p {}'.format(self.working_directory))
         self.execute('mkdir -p {}'.format(self.executables_directory))
         self.busybox = self.install(os.path.join(PACKAGE_BIN_DIRECTORY, self.abi, 'busybox'))
+
+        # Setup shutils script for the target
+        shutils_ifile = os.path.join(PACKAGE_BIN_DIRECTORY, 'scripts', 'shutils.in')
+        shutils_ofile = os.path.join(PACKAGE_BIN_DIRECTORY, 'scripts', 'shutils')
+        shell_path = '/bin/sh'
+        if self.os == 'android':
+            shell_path = '/system/bin/sh'
+        with open(shutils_ifile) as fh:
+            lines = fh.readlines()
+        with open(shutils_ofile, 'w') as ofile:
+            for line in lines:
+                line = line.replace("__DEVLIB_SHELL__", shell_path)
+                line = line.replace("__DEVLIB_BUSYBOX__", self.busybox)
+                ofile.write(line)
+        self.shutils = self.install(os.path.join(PACKAGE_BIN_DIRECTORY, 'scripts', 'shutils'))
+
         for host_exe in (executables or []):  # pylint: disable=superfluous-parens
             self.install(host_exe)
 
@@ -227,6 +243,10 @@
 
     # execution
 
+    def _execute_util(self, command, timeout=None, check_exit_code=True, as_root=False):
+        command = '{} {}'.format(self.shutils, command)
+        return self.conn.execute(command, timeout, check_exit_code, as_root)
+
     def execute(self, command, timeout=None, check_exit_code=True, as_root=False):
         return self.conn.execute(command, timeout, check_exit_code, as_root)