diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index 6351e2aab8..8f271f0500 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -1159,6 +1159,27 @@ class Runner(object): # ***************************************************** + def _remote_expand_user(self, conn, path, tmp): + ''' takes a remote path and performs tilde expansion on the remote host ''' + if not path.startswith('~'): + return path + split_path = path.split(os.path.sep, 1) + cmd = conn.shell.expand_user(split_path[0]) + data = self._low_level_exec_command(conn, cmd, tmp, sudoable=False, su=False) + initial_fragment = utils.last_non_blank_line(data['stdout']) + + if not initial_fragment: + # Something went wrong trying to expand the path remotely. Return + # the original string + return path + + if len(split_path) > 1: + return os.path.join(initial_fragment, *split_path[1:]) + else: + return initial_fragment + + # ***************************************************** + def _remote_checksum(self, conn, tmp, path, inject): ''' takes a remote checksum and returns 1 if no file ''' python_interp = inject['hostvars'][inject['inventory_hostname']].get('ansible_python_interpreter', 'python') diff --git a/lib/ansible/runner/action_plugins/assemble.py b/lib/ansible/runner/action_plugins/assemble.py index b0a45c4970..287e934865 100644 --- a/lib/ansible/runner/action_plugins/assemble.py +++ b/lib/ansible/runner/action_plugins/assemble.py @@ -109,6 +109,7 @@ class ActionModule(object): path = self._assemble_from_fragments(src, delimiter, _re) path_checksum = utils.checksum_s(path) + dest = self.runner._remote_expand_user(conn, dest, tmp) remote_checksum = self.runner._remote_checksum(conn, tmp, dest, inject) if path_checksum != remote_checksum: diff --git a/lib/ansible/runner/action_plugins/copy.py b/lib/ansible/runner/action_plugins/copy.py index 55524bca38..b180448988 100644 --- a/lib/ansible/runner/action_plugins/copy.py +++ b/lib/ansible/runner/action_plugins/copy.py @@ -157,6 +157,9 @@ class ActionModule(object): if "-tmp-" not in tmp_path: tmp_path = self.runner._make_tmp_path(conn) + # expand any user home dir specifier + dest = self.runner._remote_expand_user(conn, dest, tmp_path) + for source_full, source_rel in source_files: # Generate a hash of the local file. local_checksum = utils.checksum(source_full) diff --git a/lib/ansible/runner/action_plugins/fetch.py b/lib/ansible/runner/action_plugins/fetch.py index 030058498a..20574e6433 100644 --- a/lib/ansible/runner/action_plugins/fetch.py +++ b/lib/ansible/runner/action_plugins/fetch.py @@ -71,6 +71,7 @@ class ActionModule(object): return ReturnData(conn=conn, result=results) source = conn.shell.join_path(source) + source = self.runner._remote_expand_user(conn, source, tmp) # calculate checksum for the remote file remote_checksum = self.runner._remote_checksum(conn, tmp, source, inject) diff --git a/lib/ansible/runner/action_plugins/template.py b/lib/ansible/runner/action_plugins/template.py index 75fd7ff5a6..fd38c61063 100644 --- a/lib/ansible/runner/action_plugins/template.py +++ b/lib/ansible/runner/action_plugins/template.py @@ -75,6 +75,8 @@ class ActionModule(object): else: source = utils.path_dwim(self.runner.basedir, source) + # Expand any user home dir specification + dest = self.runner._remote_expand_user(conn, dest, tmp) if dest.endswith("/"): # CCTODO: Fix path for Windows hosts. base = os.path.basename(source) diff --git a/lib/ansible/runner/action_plugins/unarchive.py b/lib/ansible/runner/action_plugins/unarchive.py index f570a29d5c..2a1c8d1cd6 100644 --- a/lib/ansible/runner/action_plugins/unarchive.py +++ b/lib/ansible/runner/action_plugins/unarchive.py @@ -54,7 +54,7 @@ class ActionModule(object): result = dict(failed=True, msg="src (or content) and dest are required") return ReturnData(conn=conn, result=result) - dest = os.path.expanduser(dest) # CCTODO: Fix path for Windows hosts. + dest = self.runner._remote_expand_user(conn, dest, tmp) # CCTODO: Fix path for Windows hosts. source = template.template(self.runner.basedir, os.path.expanduser(source), inject) if copy: if '_original_file' in inject: diff --git a/lib/ansible/runner/shell_plugins/sh.py b/lib/ansible/runner/shell_plugins/sh.py index 713e41b3f6..38698e7b4e 100644 --- a/lib/ansible/runner/shell_plugins/sh.py +++ b/lib/ansible/runner/shell_plugins/sh.py @@ -37,12 +37,10 @@ class ShellModule(object): return path.endswith('/') def chmod(self, mode, path): - #path = os.path.expanduser(path) path = pipes.quote(path) return 'chmod %s %s' % (mode, path) def remove(self, path, recurse=False): - #path = os.path.expanduser(path) path = pipes.quote(path) if recurse: return "rm -rf %s >/dev/null 2>&1" % path @@ -61,8 +59,11 @@ class ShellModule(object): cmd += ' && echo %s' % basetmp return cmd + def expand_user(self, user_path): + # Quote the user portion but leave the tilde to be expanded + return 'echo ~%s' % pipes.quote(user_path[1:]) + def checksum(self, path, python_interp): - #path = os.path.expanduser(path) path = pipes.quote(path) # The following test needs to be SH-compliant. BASH-isms will # not work if /bin/sh points to a non-BASH shell.