diff --git a/lib/ansible/runner/action_plugins/copy.py b/lib/ansible/runner/action_plugins/copy.py index d84b3f550e6..c59042fb2b4 100644 --- a/lib/ansible/runner/action_plugins/copy.py +++ b/lib/ansible/runner/action_plugins/copy.py @@ -136,8 +136,8 @@ class ActionModule(object): # If it's recursive copy, destination is always a dir, # explicitly mark it so (note - copy module relies on this). - if not dest.endswith("/"): - dest += "/" + if not conn.shell.path_has_trailing_slash(dest): + dest = conn.shell.join_path(dest, '') else: source_files.append((source, os.path.basename(source))) @@ -169,10 +169,10 @@ class ActionModule(object): # This is kind of optimization - if user told us destination is # dir, do path manipulation right away, otherwise we still check # for dest being a dir via remote call below. - if dest.endswith("/"): # CCTODO: Fixme for powershell - dest_file = os.path.join(dest, source_rel) + if conn.shell.path_has_trailing_slash(dest): + dest_file = conn.shell.join_path(dest, source_rel) else: - dest_file = dest + dest_file = conn.shell.join_path(dest) # Attempt to get the remote MD5 Hash. remote_md5 = self.runner._remote_md5(conn, tmp_path, dest_file) @@ -186,7 +186,7 @@ class ActionModule(object): return ReturnData(conn=conn, result=result) else: # Append the relative source location to the destination and retry remote_md5. - dest_file = os.path.join(dest, source_rel) # CCTODO + dest_file = conn.shell.join_path(dest, source_rel) remote_md5 = self.runner._remote_md5(conn, tmp_path, dest_file) if remote_md5 != '1' and not force: diff --git a/lib/ansible/runner/action_plugins/fetch.py b/lib/ansible/runner/action_plugins/fetch.py index 2d7f7e974d8..1600e8803c8 100644 --- a/lib/ansible/runner/action_plugins/fetch.py +++ b/lib/ansible/runner/action_plugins/fetch.py @@ -59,7 +59,7 @@ class ActionModule(object): source = os.path.expanduser(source) if flat: - if dest.endswith("/"): # CCTODO + if dest.endswith("/"): # CCTODO: Fix path for Windows hosts. # if the path ends with "/", we'll use the source filename as the # destination filename base = os.path.basename(source) diff --git a/lib/ansible/runner/action_plugins/template.py b/lib/ansible/runner/action_plugins/template.py index 774a2be6ff7..623d173c095 100644 --- a/lib/ansible/runner/action_plugins/template.py +++ b/lib/ansible/runner/action_plugins/template.py @@ -79,7 +79,7 @@ class ActionModule(object): source = utils.path_dwim(self.runner.basedir, source) - if dest.endswith("/"): # CCTODO + if dest.endswith("/"): # CCTODO: Fix path for Windows hosts. base = os.path.basename(source) dest = os.path.join(dest, base) diff --git a/lib/ansible/runner/action_plugins/unarchive.py b/lib/ansible/runner/action_plugins/unarchive.py index be0070fca16..16c0bc8117e 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) + dest = os.path.expanduser(dest) # 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/powershell.py b/lib/ansible/runner/shell_plugins/powershell.py index 1d6c74b5879..031077215e6 100644 --- a/lib/ansible/runner/shell_plugins/powershell.py +++ b/lib/ansible/runner/shell_plugins/powershell.py @@ -58,6 +58,10 @@ class ShellModule(object): def join_path(self, *args): return os.path.join(*args).replace('/', '\\') + def path_has_trailing_slash(self, path): + # Allow Windows paths to be specified using either slash. + return path.endswith('/') or path.endswith('\\') + def chmod(self, mode, path): return '' diff --git a/lib/ansible/runner/shell_plugins/sh.py b/lib/ansible/runner/shell_plugins/sh.py index 8b74386d851..1ee225830b5 100644 --- a/lib/ansible/runner/shell_plugins/sh.py +++ b/lib/ansible/runner/shell_plugins/sh.py @@ -33,6 +33,9 @@ class ShellModule(object): def join_path(self, *args): return os.path.join(*args) + def path_has_trailing_slash(self, path): + return path.endswith('/') + def chmod(self, mode, path): path = pipes.quote(path) return 'chmod %s %s' % (mode, path)