Skip to content

Windows Compatibility: ensuring Cwltool works on windows OS #419

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 83 commits into from
Jul 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
bee9324
added appveyor.yml script
kapilkd13 Jun 4, 2017
1285c1b
normalizing input path depending on OS
kapilkd13 Jun 4, 2017
85fa796
windows compatibility issue: windows Drive names are considered as sc…
kapilkd13 Jun 4, 2017
9db2091
all changes towards windows compatibility
kapilkd13 Jun 7, 2017
ffe3aad
setting close_fds as true
kapilkd13 Jun 7, 2017
9a5221c
disabling auto cleanup onn namedtempfile closeup
kapilkd13 Jun 7, 2017
fb42e6a
separate function for copying file and directory and seting close_fds…
kapilkd13 Jun 7, 2017
2f9ac55
using shutil.rmtree to remove dirs
kapilkd13 Jun 7, 2017
8d3ed5c
checking dirs and removing them before copytree
kapilkd13 Jun 7, 2017
b5882c5
using os.mkdir instead of tempfile.mkdtemp
kapilkd13 Jun 7, 2017
eeee83b
Revert "using os.mkdir instead of tempfile.mkdtemp"
kapilkd13 Jun 7, 2017
f957ad8
modified stagefile func
kapilkd13 Jun 7, 2017
2118bd4
odified copytree func and allowing staged files to copy
kapilkd13 Jun 8, 2017
0b601fd
enabled duplicate test
kapilkd13 Jun 8, 2017
7902707
separating windows and linux specific code
kapilkd13 Jun 9, 2017
5ddf49f
windows issue: environment var can only contain strings
kapilkd13 Jun 10, 2017
367756a
adding urljoin function else will get NotImplemented error
kapilkd13 Jun 12, 2017
236a217
subprocess executionn on windows need TEMP var always set
kapilkd13 Jun 12, 2017
b546f01
muting InplaceUpdate testcases on windows platform with pytest
kapilkd13 Jun 13, 2017
5bca2e0
pulling schema-salad from local github repo
kapilkd13 Jun 13, 2017
c311908
checking for path existence instead of / path begining
kapilkd13 Jun 14, 2017
bdebbc6
modified wf/echo.cwl, removing newline character which has differnt e…
kapilkd13 Jun 15, 2017
4dc76bd
new sha for test_partial_output
kapilkd13 Jun 15, 2017
c63c4dd
added new sha for test_scatter
kapilkd13 Jun 15, 2017
9a87223
ignoring mypy on os.lchmod
kapilkd13 Jun 15, 2017
a93ede0
using os.expanduser instead of environ[home] for cross platform compa…
kapilkd13 Jun 20, 2017
f235ccf
changing windows path to unix type before passing to docker run
kapilkd13 Jun 21, 2017
72fc2e5
on windows geteuid function is not available, pass over it on windows
kapilkd13 Jun 21, 2017
70041ce
converting windows file paths to unix like before docker run command
kapilkd13 Jun 22, 2017
69fc0fb
Adding support for non-blocking I/O read write froom stdin/stdout on …
kapilkd13 Jun 25, 2017
77c326b
force install windows version of schema-salad from github branch befo…
kapilkd13 Jun 25, 2017
8a54204
Merge branch 'master' into testing-windows
kapilkd13 Jun 25, 2017
c234e04
removing github dependency link from setup.py
kapilkd13 Jun 25, 2017
51bd3df
adding docker_path_adjust function to utils
kapilkd13 Jun 29, 2017
5ecba0e
On windows, If dockerRequirement is mentioned in hints/requirement tr…
kapilkd13 Jun 29, 2017
22ace22
moving docker_path_adjust function to utils, as it is used in other f…
kapilkd13 Jun 29, 2017
b5da59a
Merge branch 'master' into testing-windows
kapilkd13 Jun 29, 2017
c3c9df9
taking account of case where path is none in Docker_windows_path func…
kapilkd13 Jul 3, 2017
abd647b
use wb mode instead of w when writing to a file: as LF converts to CR…
kapilkd13 Jul 2, 2017
3387ae8
consider case of default-container when creating log
kapilkd13 Jul 4, 2017
b428d0e
setting a default ubuntu docker container for windows OS and changing…
kapilkd13 Jul 4, 2017
82ceb89
changing get_feature funcion, thus default docker have lower priority…
kapilkd13 Jul 4, 2017
0508997
correcting position of default container resolution into hints. Previ…
kapilkd13 Jul 4, 2017
fa7cc8e
capitalizing the drive letter when passed to docker path adjust function
kapilkd13 Jul 5, 2017
6d1e136
modified sanboxjs for non blocking I/O read appropriately for windows
kapilkd13 Jul 7, 2017
75b7f1d
use builder.tmpdir instead of directly specifying tmp
kapilkd13 Jul 12, 2017
959a2b4
In utils adding docker windows reverse path function to convert a doc…
kapilkd13 Jul 13, 2017
91e2ff7
In utils adding docker windows reverse fileuri to convert linux docke…
kapilkd13 Jul 13, 2017
6740309
Convert Docker path and File uri to valid paths on windows before rem…
kapilkd13 Jul 13, 2017
aa97c43
Convert input file path to Docker compatible on windows OS
kapilkd13 Jul 13, 2017
5163f59
convert runtime object's outdir and tmpdir Path values to Docker Comp…
kapilkd13 Jul 13, 2017
bcf3bfb
Handle dockeroutputDirectory when it is a root directory i.e. starts …
kapilkd13 Jul 13, 2017
aa1ab81
Using / to join path to a fileuri instead of os.path.join as on Windo…
kapilkd13 Jul 13, 2017
56c3416
removing Docker path and file uri conversion code
kapilkd13 Jul 13, 2017
9b2d496
On windows os.realpath appends Drive letter, we need to avoid that
kapilkd13 Jul 13, 2017
3f8208c
cleaning pathmapper, use function with docstring expaining code
kapilkd13 Jul 14, 2017
adcfa36
Cleanup: changes for windows compatibility, adding docstring for bett…
kapilkd13 Jul 14, 2017
6393295
Merge branch 'master' into testing-windows
kapilkd13 Jul 14, 2017
7c2fe22
removing linting issues and adding typehint
kapilkd13 Jul 14, 2017
fee18d0
remove unneeded type:ignore
mr-c Jul 14, 2017
2a190da
fixing file uri extension code
kapilkd13 Jul 15, 2017
583b87b
ignoring tests that use docker on Windows(Appveyor)
kapilkd13 Jul 14, 2017
b1854ac
Changing env variable from unicode to str before sending on Windows only
kapilkd13 Jul 16, 2017
4adfcb7
renaming boolean value symFunc to symLink for better readability
kapilkd13 Jul 16, 2017
575f062
renamed pathFix to convert_pathsep_to_unix and moved it to utils
kapilkd13 Jul 16, 2017
386b211
adding comment to explain the need to skip Windows Drive letters cons…
kapilkd13 Jul 16, 2017
cc2a74b
restoring checksum changes, since now all file modes have been change…
kapilkd13 Jul 16, 2017
fd70c8b
Merge branch 'master' into testing-windows
mr-c Jul 16, 2017
681da6b
Merge branch 'master' into testing-windows
mr-c Jul 17, 2017
550c406
taking care of case when dockeroutputdirectory provided is not absolu…
kapilkd13 Jul 17, 2017
5bdc1ef
Py 3 doesn't have Queue module, use multiprocessing.queue instead
kapilkd13 Jul 17, 2017
4954f2c
removed unused import urlparse from test_fetch
kapilkd13 Jul 17, 2017
e9f01e2
tests/wf/echo.cwl: encode string to bytes before writing to binary file
manu-chroma Jul 17, 2017
cfa1990
cwltool/sandboxjs.py: fix mypy errors due to import statement
manu-chroma Jul 17, 2017
1dd8476
switch back to hardcoded /tmp as TMPDIR inside Docker
kapilkd13 Jul 17, 2017
9267120
set close_fds to false on Windows else True
kapilkd13 Jul 17, 2017
c85ba19
Merge branch 'master' into testing-windows
mr-c Jul 17, 2017
b203750
Merge branch 'master' into testing-windows
mr-c Jul 17, 2017
a0c2dae
checking for default container when container is not provided in hint…
kapilkd13 Jul 17, 2017
85f3299
removing code that treats default container as lowest priority Hints
kapilkd13 Jul 17, 2017
b63d472
checking availability of default container before accessing it
kapilkd13 Jul 17, 2017
8d3f692
Merge branch 'master' into testing-windows
mr-c Jul 17, 2017
06dd0b2
removing onwindows redundant function from test folder's util.py
kapilkd13 Jul 17, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: .{build}-{branch}

environment:

matrix:
- PYTHON: "C:\\Python27"
PYTHON_VERSION: "2.7.x"
PYTHON_ARCH: "32"

- PYTHON: "C:\\Python27-x64"
PYTHON_VERSION: "2.7.x"
PYTHON_ARCH: "64"

install:
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- "python --version"
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
- "pip install --disable-pip-version-check --user --upgrade pip"
- "pip install --upgrade --no-deps --force-reinstall git+git://github.com/kapilkd13/schema_salad@windows#egg=schema_salad-2.4.201706261942"

build_script:
- "%CMD_IN_ENV% python setup.py install"


test_script:

- "%CMD_IN_ENV% python setup.py test"

8 changes: 7 additions & 1 deletion cwltool/builder.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import absolute_import
import copy
import os
from typing import Any, Callable, Dict, List, Text, Type, Union

import six
Expand All @@ -15,7 +16,7 @@
from .pathmapper import (PathMapper, get_listing, normalizeFilesDirs,
visit_class)
from .stdfsaccess import StdFsAccess
from .utils import aslist
from .utils import aslist, get_feature, docker_windows_path_adjust, onWindows

# if six.PY3:
# AvroSchemaFromJSONData = avro.schema.SchemaFromJSONData
Expand Down Expand Up @@ -185,6 +186,11 @@ def tostr(self, value): # type: (Any) -> Text
if isinstance(value, dict) and value.get("class") in ("File", "Directory"):
if "path" not in value:
raise WorkflowException(u"%s object missing \"path\": %s" % (value["class"], value))

# Path adjust for windows file path when passing to docker, docker accepts unix like path only
(docker_req, docker_is_req) = get_feature(self, "DockerRequirement")
if onWindows() and docker_req is not None: # docker_req is none only when there is no dockerRequirement mentioned in hints and Requirement
return docker_windows_path_adjust(value["path"])
return value["path"]
else:
return Text(value)
Expand Down
10 changes: 7 additions & 3 deletions cwltool/draft2tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
_logger_validation_warnings, compute_checksums,
normalizeFilesDirs, shortname, uniquename)
from .stdfsaccess import StdFsAccess
from .utils import aslist
from .utils import aslist, docker_windows_path_adjust, convert_pathsep_to_unix
from six.moves import map

ACCEPTLIST_EN_STRICT_RE = re.compile(r"^[a-zA-Z0-9._+-]+$")
Expand Down Expand Up @@ -107,7 +107,7 @@ def revmap_file(builder, outdir, f):

if "location" in f:
if f["location"].startswith("file://"):
path = uri_file_path(f["location"])
path = convert_pathsep_to_unix(uri_file_path(f["location"]))
revmap_f = builder.pathmapper.reversemap(path)
if revmap_f:
f["location"] = revmap_f[1]
Expand Down Expand Up @@ -156,7 +156,7 @@ def run(self, **kwargs):
def check_adjust(builder, f):
# type: (Builder, Dict[Text, Any]) -> Dict[Text, Any]

f["path"] = builder.pathmapper.mapper(f["location"])[1]
f["path"] = docker_windows_path_adjust(builder.pathmapper.mapper(f["location"])[1])
f["dirname"], f["basename"] = os.path.split(f["path"])
if f["class"] == "File":
f["nameroot"], f["nameext"] = os.path.splitext(f["basename"])
Expand Down Expand Up @@ -230,6 +230,10 @@ def job(self,
(docker_req, docker_is_req) = self.get_requirement("DockerRequirement")
if docker_req and kwargs.get("use_container") is not False:
dockerimg = docker_req.get("dockerImageId") or docker_req.get("dockerPull")
elif kwargs.get("default_container", None) is not None and kwargs.get("use_container") is not False:
dockerimg = kwargs.get("default_container")

if dockerimg:
cmdline = ["docker", "run", dockerimg] + cmdline
keydict = {u"cmdline": cmdline}

Expand Down
5 changes: 3 additions & 2 deletions cwltool/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import logging
import re
from typing import Any, AnyStr, Dict, List, Text, Union
from .utils import docker_windows_path_adjust
import six
from six import u

Expand Down Expand Up @@ -203,8 +204,8 @@ def do_eval(ex, jobinput, requirements, outdir, tmpdir, resources,
# type: (Union[dict, AnyStr], Dict[Text, Union[Dict, List, Text]], List[Dict[Text, Any]], Text, Text, Dict[Text, Union[int, Text]], Any, bool, int, bool) -> Any

runtime = copy.copy(resources)
runtime["tmpdir"] = tmpdir
runtime["outdir"] = outdir
runtime["tmpdir"] = docker_windows_path_adjust(tmpdir)
runtime["outdir"] = docker_windows_path_adjust(outdir)

rootvars = {
u"inputs": jobinput,
Expand Down
54 changes: 34 additions & 20 deletions cwltool/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import shellescape

from .utils import copytree_with_merge, docker_windows_path_adjust, onWindows
from . import docker
from .builder import Builder
from .docker_uid import docker_vm_uid
Expand Down Expand Up @@ -106,8 +107,14 @@ def relink_initialworkdir(pathmapper, inplace_update=False):
if os.path.islink(vol.target) or os.path.isfile(vol.target):
os.remove(vol.target)
elif os.path.isdir(vol.target):
os.rmdir(vol.target)
os.symlink(vol.resolved, vol.target)
shutil.rmtree(vol.target)
if onWindows():
if vol.type in ("File", "WritableFile"):
shutil.copy(vol.resolved,vol.target)
elif vol.type in ("Directory", "WritableDirectory"):
copytree_with_merge(vol.resolved, vol.target)
else:
os.symlink(vol.resolved, vol.target)

class JobBase(object):
def __init__(self): # type: () -> None
Expand Down Expand Up @@ -278,13 +285,16 @@ def run(self, pull_image=True, rm_container=True,
if vars_to_preserve is not None:
for key, value in os.environ.items():
if key in vars_to_preserve and key not in env:
env[key] = value
env["HOME"] = self.outdir
env["TMPDIR"] = self.tmpdir

stageFiles(self.pathmapper, os.symlink, ignoreWritable=True)
# On Windows, subprocess env can't handle unicode.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then lets only call str if onWindows()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. we can do that

env[key] = str(value) if onWindows() else value
env["HOME"] = str(self.outdir) if onWindows() else self.outdir
env["TMPDIR"] = str(self.tmpdir) if onWindows() else self.tmpdir
if "PATH" not in env:
env["PATH"] = str(os.environ["PATH"]) if onWindows() else os.environ["PATH"]

stageFiles(self.pathmapper, ignoreWritable=True, symLink=True)
if self.generatemapper:
stageFiles(self.generatemapper, os.symlink, ignoreWritable=self.inplace_update)
stageFiles(self.generatemapper, ignoreWritable=self.inplace_update, symLink=True)
relink_initialworkdir(self.generatemapper, inplace_update=self.inplace_update)

self._execute([], env, rm_tmpdir=rm_tmpdir, move_outputs=move_outputs)
Expand All @@ -306,25 +316,26 @@ def add_volumes(self, pathmapper, runtime, stage_output):
containertgt = vol.target
if vol.type in ("File", "Directory"):
if not vol.resolved.startswith("_:"):
runtime.append(u"--volume=%s:%s:ro" % (vol.resolved, containertgt))
runtime.append(u"--volume=%s:%s:ro" % (docker_windows_path_adjust(vol.resolved), docker_windows_path_adjust(containertgt)))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please wrap lines longer than 80 characters for easier review :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 i will take care.

elif vol.type == "WritableFile":
if self.inplace_update:
runtime.append(u"--volume=%s:%s:rw" % (vol.resolved, containertgt))
runtime.append(u"--volume=%s:%s:rw" % (docker_windows_path_adjust(vol.resolved), docker_windows_path_adjust(containertgt)))
else:
shutil.copy(vol.resolved, vol.target)
elif vol.type == "WritableDirectory":
if vol.resolved.startswith("_:"):
os.makedirs(vol.target, 0o0755)
else:
if self.inplace_update:
runtime.append(u"--volume=%s:%s:rw" % (vol.resolved, containertgt))
runtime.append(u"--volume=%s:%s:rw" % (docker_windows_path_adjust(vol.resolved), docker_windows_path_adjust(containertgt)))
else:
shutil.copytree(vol.resolved, vol.target)
elif vol.type == "CreateFile":
createtmp = os.path.join(host_outdir, os.path.basename(vol.target))
with open(createtmp, "wb") as f:
f.write(vol.resolved.encode("utf-8"))
runtime.append(u"--volume=%s:%s:ro" % (createtmp, vol.target))
runtime.append(u"--volume=%s:%s:ro" % (docker_windows_path_adjust(createtmp), docker_windows_path_adjust(vol.target)))


def run(self, pull_image=True, rm_container=True,
rm_tmpdir=True, move_outputs="move", **kwargs):
Expand Down Expand Up @@ -361,14 +372,14 @@ def run(self, pull_image=True, rm_container=True,

runtime = [u"docker", u"run", u"-i"]

runtime.append(u"--volume=%s:%s:rw" % (os.path.realpath(self.outdir), self.builder.outdir))
runtime.append(u"--volume=%s:%s:rw" % (os.path.realpath(self.tmpdir), "/tmp"))
runtime.append(u"--volume=%s:%s:rw" % (docker_windows_path_adjust(os.path.realpath(self.outdir)), self.builder.outdir))
runtime.append(u"--volume=%s:%s:rw" % (docker_windows_path_adjust(os.path.realpath(self.tmpdir)), "/tmp"))

self.add_volumes(self.pathmapper, runtime, False)
if self.generatemapper:
self.add_volumes(self.generatemapper, runtime, True)

runtime.append(u"--workdir=%s" % (self.builder.outdir))
runtime.append(u"--workdir=%s" % (docker_windows_path_adjust(self.builder.outdir)))
runtime.append(u"--read-only=true")

if kwargs.get("custom_net", None) is not None:
Expand All @@ -379,9 +390,12 @@ def run(self, pull_image=True, rm_container=True,
if self.stdout:
runtime.append("--log-driver=none")

euid = docker_vm_uid() or os.geteuid()
if onWindows(): # windows os dont have getuid or geteuid functions
euid = docker_vm_uid()
else:
euid = docker_vm_uid() or os.geteuid()

if kwargs.get("no_match_user", None) is False:
if kwargs.get("no_match_user", None) is False and euid is not None:
runtime.append(u"--user=%s" % (euid))

if rm_container:
Expand Down Expand Up @@ -436,7 +450,7 @@ def _job_popen(

sp = subprocess.Popen(commands,
shell=False,
close_fds=True,
close_fds=not onWindows(),
stdin=stdin,
stdout=stdout,
stderr=stderr,
Expand Down Expand Up @@ -478,14 +492,14 @@ def _job_popen(
stderr_path=stderr_path,
stdin_path=stdin_path,
)
with open(os.path.join(job_dir, "job.json"), "w") as f:
with open(os.path.join(job_dir, "job.json"), "wb") as f:
json.dump(job_description, f)
try:
job_script = os.path.join(job_dir, "run_job.bash")
with open(job_script, "wb") as f:
f.write(job_script_contents.encode('utf-8'))
job_run = os.path.join(job_dir, "run_job.py")
with open(job_run, "w") as f:
with open(job_run, "wb") as f:
f.write(PYTHON_RUN_SCRIPT)
sp = subprocess.Popen(
["bash", job_script.encode("utf-8")],
Expand Down
3 changes: 2 additions & 1 deletion cwltool/load_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def fetch_document(argsworkflow, # type: Union[Text, Dict[Text, Any]]
workflowobj = None # type: CommentedMap
if isinstance(argsworkflow, string_types):
split = urllib.parse.urlsplit(argsworkflow)
if split.scheme:
# In case of Windows path, urlsplit misjudge Drive letters as scheme, here we are skipping that
if split.scheme and split.scheme in [u'http',u'https',u'file']:
uri = argsworkflow
elif os.path.exists(os.path.abspath(argsworkflow)):
uri = file_uri(str(os.path.abspath(argsworkflow)))
Expand Down
6 changes: 6 additions & 0 deletions cwltool/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
from .software_requirements import DependenciesConfiguration, get_container_from_software_requirements, SOFTWARE_REQUIREMENTS_ENABLED
from .stdfsaccess import StdFsAccess
from .update import ALLUPDATES, UPDATES
from .utils import onWindows
from ruamel.yaml.comments import Comment, CommentedSeq, CommentedMap


_logger = logging.getLogger("cwltool")
Expand Down Expand Up @@ -695,6 +697,10 @@ def main(argsl=None, # type: List[str]
argsl = sys.argv[1:]
args = arg_parser().parse_args(argsl)

# If On windows platform, A default Docker Container is Used if not explicitely provided by user
if onWindows() and not args.default_container:
args.default_container = "ubuntu"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we were going with a more basic container?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested conformance tests on Alpine(size 5mb) docker image. 2 types of test are failing 1. test that use bin/bash 2. Test that use rev command is giving wrong output(Need to find reason for it)
I found another image https://github.com/frol/docker-alpine-bash alpine-bash its size is 6 mb and it comes with bash. So after using this 2 tests are failing that use rev reverse command, others are passing. Should we add external containers in tests that use bin/bash or keep alpine-bash as default image. And if so what would be a good bash image, alpine-bash is light.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets add alpine-bash to those conformance tests, yep!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. One problem that we still have is that test 52 and 53 uses rev command. It is not posix compliant so ubuntu and alpine have different implmentation thus it gives wrong output. I thinking of adding a ubuntu container for these tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong means different output. It appears Alpine and Busybox rev tool can't handle input larger than certain character and some error occur in their buffer causing output to print multiple times. I checked it manually in a alpine docker. We had same behaviour.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting! Feel free to propose whichever container is needed for those tests


# If caller provided custom arguments, it may be not every expected
# option is set, so fill in no-op defaults to avoid crashing when
# dereferencing them in args.
Expand Down
5 changes: 4 additions & 1 deletion cwltool/pathmapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from schema_salad.sourceline import SourceLine
from six.moves import urllib

from .utils import convert_pathsep_to_unix

from .stdfsaccess import StdFsAccess, abspath

_logger = logging.getLogger("cwltool")
Expand Down Expand Up @@ -186,7 +188,8 @@ def visitlisting(self, listing, stagedir, basedir, copy=False, staged=False):

def visit(self, obj, stagedir, basedir, copy=False, staged=False):
# type: (Dict[Text, Any], Text, Text, bool, bool) -> None
tgt = os.path.join(stagedir, obj["basename"])
tgt = convert_pathsep_to_unix(
os.path.join(stagedir, obj["basename"]))
if obj["location"] in self._pathmap:
return
if obj["class"] == "Directory":
Expand Down
Loading