Repository: smarr/ReBench

Issue:
Handle ~ character in environment variables
I think currently, we do not expand ~ to the user directory when it's in an environment variable.

Discussion:

Solution patch:
diff --git a/rebench/model/run_id.py b/rebench/model/run_id.py
index 726d63a..5015aaa 100644
--- a/rebench/model/run_id.py
+++ b/rebench/model/run_id.py
@@ -51,6 +51,7 @@ class RunId(object):
         self.is_failed = True
 
         self._max_invocation = 0
+        self._expandend_env = None
 
     def has_same_executable(self, other):
         return self.executable == other.executable
@@ -85,7 +86,13 @@ class RunId(object):
 
     @property
     def env(self):
-        return self.benchmark.run_details.env
+        if self._expandend_env is not None:
+            return self._expandend_env
+
+        self._expandend_env = self.benchmark.run_details.env
+        for key, value in self._expandend_env.items():
+            self._expandend_env[key] = self._expand_user(value)
+        return self._expandend_env
 
     @property
     def completed_invocations(self):
@@ -278,14 +285,21 @@ class RunId(object):
             return self._cmdline
         return self._construct_cmdline()
 
+    def _expand_user(self, possible_path):
+        # split will change the type of quotes, which may cause issues with shell variables
+        parts = shlex.split(possible_path)
+        for i, part in enumerate(parts):
+            expanded = os.path.expanduser(part)
+            if '~' in expanded and ':' in expanded:
+                path_list = expanded.split(':')
+                expanded = ':'.join([os.path.expanduser(p) for p in path_list])
+            parts[i] = expanded
+        return shlex.join(parts)
+
     def cmdline_for_next_invocation(self):
         """Replace the invocation number in the command line"""
         cmdline = self.cmdline() % {'invocation': self.completed_invocations + 1}
-        # split will change the type of quotes, which may cause issues with shell variables
-        parts = shlex.split(cmdline)
-        for i, part in enumerate(parts):
-            parts[i] = os.path.expanduser(part)
-        cmdline = shlex.join(parts)
+        cmdline = self._expand_user(cmdline)
         return cmdline
 
     def _construct_cmdline(self):


Test patch:
diff --git a/rebench/tests/model/runs_config_test.py b/rebench/tests/model/runs_config_test.py
index 1765af4..68eaa39 100644
--- a/rebench/tests/model/runs_config_test.py
+++ b/rebench/tests/model/runs_config_test.py
@@ -87,10 +87,25 @@ class RunsConfigTestCase(ReBenchTestCase):
             self.ui, None, data_file=self._tmp_file)
         runs = self._cnf.get_runs()
         sorted_runs = sorted(list(runs), key=lambda r: r.cmdline())
-        self._run = sorted_runs[0]
 
-        expected_cmd = '~/tests/vm1.py 1 Bench ~/suiteFolder/Bench1'.replace('~', expanduser('~'))
+        run = sorted_runs[0]
+
+        expected_cmd = '~/tests/vm1.py 1 -cp ~/foo:~/bar Bench ~/suiteFolder/Bench1'.replace(
+            '~', expanduser('~'))
         self.assertNotIn("~", expected_cmd)
         expected_cmd += " -message 'a string with a ~'"
-        next_invocation_cmdline = self._run.cmdline_for_next_invocation()
+        next_invocation_cmdline = run.cmdline_for_next_invocation()
         self.assertEqual(expected_cmd, next_invocation_cmdline)
+
+    def test_env_user_path_expansion(self):
+        self._cnf = Configurator(
+            load_config(self._path + '/small_expand_user.conf'), DataStore(self.ui),
+            self.ui, None, data_file=self._tmp_file)
+        runs = self._cnf.get_runs()
+        sorted_runs = sorted(list(runs), key=lambda r: r.cmdline())
+        run = sorted_runs[0]
+
+        env = run.env
+
+        self.assertNotIn("~", env['PATH'])
+        self.assertNotIn("~", env['WORKDIR'])
diff --git a/rebench/tests/small_expand_user.conf b/rebench/tests/small_expand_user.conf
index 50ba72f..3731822 100644
--- a/rebench/tests/small_expand_user.conf
+++ b/rebench/tests/small_expand_user.conf
@@ -22,7 +22,11 @@ executors:
     TestRunner1:
         path: ~/tests
         executable: vm1.py %(cores)s
+        args: '-cp ~/foo:~/bar'
         cores: [1]
+        env:
+            PATH: /usr/bin:/bin:~/bin
+            WORKDIR: ~/work
 
 experiments:
     Test: