From 4aee27816e7101753aeb392e868096236a26d84d Mon Sep 17 00:00:00 2001 From: John Parent Date: Wed, 16 Mar 2022 16:41:34 -0400 Subject: [PATCH] Windows Support: Testing Suite integration Broaden support for execution of the test suite on Windows. General bug and review fixups --- .github/workflows/windows_python.yml | 11 +- .gitignore | 5 - bin/spack_cmd.bat | 1 + lib/spack/docs/getting_started.rst | 40 ++--- lib/spack/external/ctest_log_parser.py | 9 +- lib/spack/external/macholib/util.py | 4 +- .../pytest-fallback/py/_path/local.py | 8 +- lib/spack/llnl/util/filesystem.py | 18 +- lib/spack/llnl/util/lock.py | 7 + lib/spack/llnl/util/tty/__init__.py | 4 +- lib/spack/llnl/util/tty/log.py | 45 ++--- lib/spack/spack/build_systems/cmake.py | 3 +- lib/spack/spack/cmd/create.py | 10 +- lib/spack/spack/cmd/make_installer.py | 5 +- lib/spack/spack/compilers/msvc.py | 14 +- lib/spack/spack/detection/path.py | 9 +- lib/spack/spack/environment/environment.py | 7 +- lib/spack/spack/fetch_strategy.py | 1 - lib/spack/spack/hooks/sbang.py | 2 +- .../spack/operating_systems/windows_os.py | 5 +- lib/spack/spack/package.py | 42 +++-- lib/spack/spack/parse.py | 1 + lib/spack/spack/paths.py | 9 +- lib/spack/spack/platforms/windows.py | 2 - lib/spack/spack/repo.py | 3 +- lib/spack/spack/spec.py | 12 +- lib/spack/spack/test/architecture.py | 5 +- lib/spack/spack/test/build_distribution.py | 9 + lib/spack/spack/test/build_environment.py | 61 ++++--- lib/spack/spack/test/buildrequest.py | 7 +- lib/spack/spack/test/cache_fetch.py | 13 +- lib/spack/spack/test/cmd/common/arguments.py | 7 - lib/spack/spack/test/cmd/compiler.py | 3 +- lib/spack/spack/test/cmd/concretize.py | 4 - lib/spack/spack/test/cmd/config.py | 6 +- lib/spack/spack/test/cmd/env.py | 160 +----------------- lib/spack/spack/test/cmd/external.py | 75 ++++---- lib/spack/spack/test/cmd/fetch.py | 9 +- lib/spack/spack/test/cmd/info.py | 6 +- lib/spack/spack/test/cmd/is_git_repo.py | 4 + lib/spack/spack/test/cmd/list.py | 10 -- lib/spack/spack/test/cmd/mirror.py | 9 + lib/spack/spack/test/cmd/pkg.py | 13 +- lib/spack/spack/test/cmd/providers.py | 5 +- lib/spack/spack/test/cmd/resource.py | 33 +++- lib/spack/spack/test/cmd/test.py | 2 +- lib/spack/spack/test/cmd/uninstall.py | 3 - lib/spack/spack/test/cmd_extensions.py | 8 +- lib/spack/spack/test/concretize.py | 21 ++- .../spack/test/concretize_preferences.py | 1 - lib/spack/spack/test/config.py | 159 +++++++++-------- lib/spack/spack/test/conftest.py | 27 ++- lib/spack/spack/test/database.py | 12 +- lib/spack/spack/test/directory_layout.py | 12 +- .../spack/test/environment_modifications.py | 9 +- lib/spack/spack/test/git_fetch.py | 5 +- lib/spack/spack/test/install.py | 49 +----- lib/spack/spack/test/installer.py | 100 +---------- lib/spack/spack/test/link_paths.py | 80 +++++---- lib/spack/spack/test/llnl/util/filesystem.py | 19 +-- lib/spack/spack/test/llnl/util/lock.py | 4 +- lib/spack/spack/test/llnl/util/tty/log.py | 2 +- lib/spack/spack/test/main.py | 2 +- lib/spack/spack/test/make_executable.py | 3 +- lib/spack/spack/test/module_parsing.py | 8 +- lib/spack/spack/test/optional_deps.py | 4 - lib/spack/spack/test/packages.py | 15 -- lib/spack/spack/test/packaging.py | 13 +- lib/spack/spack/test/patch.py | 48 +++--- lib/spack/spack/test/permissions.py | 11 +- lib/spack/spack/test/relocate.py | 7 +- lib/spack/spack/test/sbang.py | 2 +- lib/spack/spack/test/spec_dag.py | 5 - lib/spack/spack/test/spec_semantics.py | 38 ----- lib/spack/spack/test/spec_syntax.py | 1 - lib/spack/spack/test/spec_yaml.py | 1 - lib/spack/spack/test/test_activations.py | 12 +- lib/spack/spack/test/test_suite.py | 10 +- lib/spack/spack/test/url_fetch.py | 1 + lib/spack/spack/test/util/editor.py | 13 +- lib/spack/spack/test/util/environment.py | 34 ++-- lib/spack/spack/test/util/executable.py | 19 ++- lib/spack/spack/test/util/file_cache.py | 3 - lib/spack/spack/test/util/path.py | 16 +- lib/spack/spack/test/util/util_url.py | 60 +++---- lib/spack/spack/test/verification.py | 9 +- lib/spack/spack/util/environment.py | 9 +- lib/spack/spack/util/executable.py | 5 +- lib/spack/spack/util/file_cache.py | 2 +- lib/spack/spack/util/lock.py | 4 + lib/spack/spack/util/parallel.py | 2 +- lib/spack/spack/util/path.py | 48 ++++-- lib/spack/spack/util/url.py | 100 ++++++----- lib/spack/spack/util/web.py | 5 +- share/spack/qa/windows_test_setup.ps1 | 2 +- .../packages/cmake-client/package.py | 2 + .../builtin.mock/packages/cmake/package.py | 7 +- .../packages/find-externals1/package.py | 8 +- .../trivial-install-test-package/package.py | 5 +- .../repos/builtin/packages/openssl/package.py | 56 +++--- .../repos/builtin/packages/python/package.py | 12 +- .../repos/builtin/packages/wrf/package.py | 6 +- 102 files changed, 771 insertions(+), 1066 deletions(-) diff --git a/.github/workflows/windows_python.yml b/.github/workflows/windows_python.yml index 0c517eef5f..b45cd716bb 100644 --- a/.github/workflows/windows_python.yml +++ b/.github/workflows/windows_python.yml @@ -3,13 +3,12 @@ name: windows tests on: push: branches: - - features/windows-support - - windows-ci* + - develop + - releases/** pull_request: branches: - - features/windows-support - - windows-ci* - develop + - releases/** defaults: run: shell: @@ -70,7 +69,7 @@ jobs: - name: Unit Test run: | echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml - spack unit-test -x --verbose --ignore=lib/spack/spack/test/cmd + spack unit-test --verbose --ignore=lib/spack/spack/test/cmd unittest-cmd: runs-on: windows-latest steps: @@ -89,7 +88,7 @@ jobs: - name: Command Unit Test run: | echo F|xcopy .\spack\share\spack\qa\configuration\windows_config.yaml $env:USERPROFILE\.spack\windows\config.yaml - spack unit-test lib/spack/spack/test/cmd -x --verbose + spack unit-test lib/spack/spack/test/cmd --verbose buildtest: runs-on: windows-latest steps: diff --git a/.gitignore b/.gitignore index 6a816e5531..68f83ea38d 100644 --- a/.gitignore +++ b/.gitignore @@ -269,11 +269,6 @@ local.properties # CDT-specific (C/C++ Development Tooling) .cproject -# VSCode files -.vs -.vscode -.devcontainer - # CDT- autotools .autotools diff --git a/bin/spack_cmd.bat b/bin/spack_cmd.bat index 839f1828da..6edc6da2c2 100644 --- a/bin/spack_cmd.bat +++ b/bin/spack_cmd.bat @@ -68,4 +68,5 @@ set GOTO:EOF :continue +set PROMPT=[spack] %PROMPT% %comspec% /k diff --git a/lib/spack/docs/getting_started.rst b/lib/spack/docs/getting_started.rst index d4121750db..32007332d5 100644 --- a/lib/spack/docs/getting_started.rst +++ b/lib/spack/docs/getting_started.rst @@ -1580,8 +1580,8 @@ Python 3 can be downloaded and installed from the Windows Store, and will be aut to your ``PATH`` in this case. .. note:: - Spack currently supports Python versions later than 3.2 inclusive. + """ Git """ @@ -1594,12 +1594,10 @@ When given the option of adjusting your ``PATH``, choose the ``Git from the command line and also from 3rd-party software`` option. This will automatically update your ``PATH`` variable to include the ``git`` command. -.. note:: - - Spack support on Windows is currently dependent on installing the Git for Windows project - as the project providing Git support on Windows. This is additionally the recommended method - for installing Git on Windows, a link to which can be found above. Spack requires the - utilities vendored by this project. +Spack support on Windows is currently dependent on installing the Git for Windows project +as the project providing Git support on Windows. This is additionally the recommended method +for installing Git on Windows, a link to which can be found above. Spack requires the +utilities vendored by this project. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Step 2: Install and setup Spack @@ -1609,32 +1607,20 @@ We are now ready to get the Spack environment set up on our machine. We begin by using Git to clone the Spack repo, hosted at https://github.com/spack/spack.git into a desired directory, for our purposes today, called ``spack_install``. -Presently, Windows operations are supported by Spack soley through the -features/windows-support branch on the upstream Spack repository, -located at the above url. - In order to install Spack with Windows support, run the following one liner in a Windows CMD prompt. .. code-block:: console - git clone https://github.com/spack/spack.git -b features/windows-support win_spack - -or if working from a previous clone of Spack, simply checkout the Windows support feature branch -with - -.. code-block:: console - - git checkout -b features/windows-support --track /features/windows-support + git clone https://github.com/spack/spack.git .. note:: + If you chose to install Spack into a directory on Windows that is set up to require Administrative + Privleges, Spack will require elevated privleges to run. + Administrative Privleges can be denoted either by default such as + ``C:\Program Files``, or aministrator applied administrative restrictions + on a directory that spack installs files to such as ``C:\Users`` - If you chose to install Spack into a directory on Windows that is set up to require Administrative - Privleges*, Spack will require elevated privleges to run. - - *Administrative Privleges can be denoted either by default such as - `C:\Program Files`, or aministrator applied administrative restrictions - on a directory that spack installs files to such as `C:\Users\` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Step 3: Run and configure Spack ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1646,6 +1632,9 @@ and its prerequisites. If you receive a warning message that Python is not in yo of the Python executable to your ``PATH`` now. You can permanently add Python to your ``PATH`` variable by using the ``Edit the system environment variables`` utility in Windows Control Panel. +.. note:: + Alternatively, Powershell can be used in place of CMD + To configure Spack, first run the following command inside the Spack console: .. code-block:: console @@ -1712,6 +1701,7 @@ and not tabs, so ensure that this is the case when editing one directly. The use of Cygwin is not officially supported by Spack and is not tested. However Spack will not throw an error, so use if choosing to use Spack with Cygwin, know that no functionality is garunteed. + ^^^^^^^^^^^^^^^^^ Step 4: Use Spack ^^^^^^^^^^^^^^^^^ diff --git a/lib/spack/external/ctest_log_parser.py b/lib/spack/external/ctest_log_parser.py index d1c8db16c8..2b2746003a 100644 --- a/lib/spack/external/ctest_log_parser.py +++ b/lib/spack/external/ctest_log_parser.py @@ -71,8 +71,6 @@ import re import math import multiprocessing -import sys -import threading import time from contextlib import contextmanager @@ -411,12 +409,7 @@ def parse(self, stream, context=6, jobs=None): pool = multiprocessing.Pool(jobs) try: # this is a workaround for a Python bug in Pool with ctrl-C - if sys.version_info >= (3, 2): - max_timeout = threading.TIMEOUT_MAX - else: - max_timeout = 9999999 - results = pool.map_async(_parse_unpack, args, 1).get(max_timeout) - + results = pool.map_async(_parse_unpack, args, 1).get(9999999) errors, warnings, timings = zip(*results) finally: pool.terminate() diff --git a/lib/spack/external/macholib/util.py b/lib/spack/external/macholib/util.py index 4eb4bd60e7..d5ab33544a 100644 --- a/lib/spack/external/macholib/util.py +++ b/lib/spack/external/macholib/util.py @@ -6,8 +6,6 @@ from macholib import mach_o -from llnl.util.symlink import symlink - MAGIC = [ struct.pack("!L", getattr(mach_o, "MH_" + _)) for _ in ["MAGIC", "CIGAM", "MAGIC_64", "CIGAM_64"] @@ -142,7 +140,7 @@ def mergetree(src, dst, condition=None, copyfn=mergecopy, srcbase=None): try: if os.path.islink(srcname): realsrc = os.readlink(srcname) - symlink(realsrc, dstname) + os.symlink(realsrc, dstname) elif os.path.isdir(srcname): mergetree( srcname, diff --git a/lib/spack/external/pytest-fallback/py/_path/local.py b/lib/spack/external/pytest-fallback/py/_path/local.py index 72ffb9f6cb..d2f16b993e 100644 --- a/lib/spack/external/pytest-fallback/py/_path/local.py +++ b/lib/spack/external/pytest-fallback/py/_path/local.py @@ -12,8 +12,6 @@ from os.path import abspath, normpath, isabs, exists, isdir, isfile, islink, dirname -from llnl.util.symlink import symlink - if sys.version_info > (3,0): def map_as_list(func, iter): return list(map(func, iter)) @@ -81,7 +79,7 @@ def mklinkto(self, oldname): def mksymlinkto(self, value, absolute=1): """ create a symbolic link with the given value (pointing to another name). """ if absolute: - py.error.checked_call(symlink, str(value), self.strpath) + py.error.checked_call(os.symlink, str(value), self.strpath) else: base = self.common(value) # with posix local paths '/' is always a common base @@ -89,7 +87,7 @@ def mksymlinkto(self, value, absolute=1): reldest = self.relto(base) n = reldest.count(self.sep) target = self.sep.join(('..', )*n + (relsource, )) - py.error.checked_call(symlink, target, self.strpath) + py.error.checked_call(os.symlink, target, self.strpath) def getuserid(user): import pwd @@ -894,7 +892,7 @@ def try_remove_lockfile(): except OSError: pass try: - symlink(src, dest) + os.symlink(src, dest) except (OSError, AttributeError, NotImplementedError): pass diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py index 9f46b275b2..22ca97c347 100644 --- a/lib/spack/llnl/util/filesystem.py +++ b/lib/spack/llnl/util/filesystem.py @@ -1094,12 +1094,23 @@ def remove_linked_tree(path): Parameters: path (str): Directory to be removed """ + # On windows, cleaning a Git stage can be an issue + # as git leaves readonly files that Python handles + # poorly on Windows. Remove readonly status and try again + def onerror(func, path, exe_info): + os.chmod(path, stat.S_IWUSR) + try: + func(path) + except Exception as e: + tty.warn(e) + pass + if os.path.exists(path): if os.path.islink(path): - shutil.rmtree(os.path.realpath(path), True) + shutil.rmtree(os.path.realpath(path), onerror=onerror) os.unlink(path) else: - shutil.rmtree(path, True) + shutil.rmtree(path, onerror=onerror) @contextmanager @@ -1237,9 +1248,6 @@ def find(root, files, recursive=True): return _find_non_recursive(root, files) -# here and in _find_non_recursive below we only take the first -# index to check for system path safety as glob handles this -# w.r.t. search_files @system_path_filter def _find_recursive(root, search_files): diff --git a/lib/spack/llnl/util/lock.py b/lib/spack/llnl/util/lock.py index 37989bac35..1ff7ceec64 100644 --- a/lib/spack/llnl/util/lock.py +++ b/lib/spack/llnl/util/lock.py @@ -191,6 +191,7 @@ def is_valid(op): return op == LockType.READ \ or op == LockType.WRITE + class Lock(object): """This is an implementation of a filesystem lock using Python's lockf. @@ -617,6 +618,12 @@ def release_write(self, release_fn=None): else: return False + def cleanup(self): + if self._reads == 0 and self._writes == 0: + os.unlink(self.path) + else: + raise LockError("Attempting to cleanup active lock.") + def _get_counts_desc(self): return '(reads {0}, writes {1})'.format(self._reads, self._writes) \ if tty.is_verbose() else '' diff --git a/lib/spack/llnl/util/tty/__init__.py b/lib/spack/llnl/util/tty/__init__.py index ae7634afea..de49f3f77f 100644 --- a/lib/spack/llnl/util/tty/__init__.py +++ b/lib/spack/llnl/util/tty/__init__.py @@ -395,7 +395,7 @@ def ioctl_gwinsz(fd): return int(rc[0]), int(rc[1]) else: if sys.version_info[0] < 3: - raise RuntimeError("""Terminal size not obtainable on Windows with a - Python version older than 3""") + raise RuntimeError("Terminal size not obtainable on Windows with a\ +Python version older than 3") rc = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) return int(rc[0]), int(rc[1]) diff --git a/lib/spack/llnl/util/tty/log.py b/lib/spack/llnl/util/tty/log.py index 0df3cf7829..544a9a6c48 100644 --- a/lib/spack/llnl/util/tty/log.py +++ b/lib/spack/llnl/util/tty/log.py @@ -418,6 +418,7 @@ def log_output(*args, **kwargs): with log_output('logfile.txt', echo=True): # do things ... output will be logged and printed out + The following is available on Unix only. No-op on Windows. And, if you just want to echo *some* stuff from the parent, use ``force_echo``:: @@ -427,20 +428,11 @@ def log_output(*args, **kwargs): with logger.force_echo(): # things here will be echoed *and* logged - Under the hood, we spawn a daemon and set up a pipe between this - process and the daemon. The daemon writes our output to both the - file and to stdout (if echoing). The parent process can communicate - with the daemon to tell it when and when not to echo; this is what - force_echo does. You can also enable/disable echoing by typing 'v'. - - We try to use OS-level file descriptors to do the redirection, but if - stdout or stderr has been set to some Python-level file object, we - use Python-level redirection instead. This allows the redirection to - work within test frameworks like nose and pytest. + See individual log classes for more information. This method is actually a factory serving a per platform - (nix vs windows) log_output class + (unix vs windows) log_output class """ if sys.platform == 'win32': return winlog(*args, **kwargs) @@ -449,29 +441,7 @@ def log_output(*args, **kwargs): class nixlog(object): - """Context manager that logs its output to a file. - - In the simplest case, the usage looks like this:: - - with log_output('logfile.txt'): - # do things ... output will be logged - - Any output from the with block will be redirected to ``logfile.txt``. - If you also want the output to be echoed to ``stdout``, use the - ``echo`` parameter:: - - with log_output('logfile.txt', echo=True): - # do things ... output will be logged and printed out - - And, if you just want to echo *some* stuff from the parent, use - ``force_echo``:: - - with log_output('logfile.txt', echo=False) as logger: - # do things ... output will be logged - - with logger.force_echo(): - # things here will be echoed *and* logged - + """ Under the hood, we spawn a daemon and set up a pipe between this process and the daemon. The daemon writes our output to both the file and to stdout (if echoing). The parent process can communicate @@ -748,7 +718,6 @@ def __init__(self, sys_attr): self.libc = libc self.c_stream = c_stdout else: - # The original fd stdout points to. Usually 1 on POSIX systems for stdout. self.libc = ctypes.CDLL(None) self.c_stream = ctypes.c_void_p.in_dll(self.libc, self.sys_attr) self.sys_stream = getattr(sys, self.sys_attr) @@ -793,6 +762,12 @@ def close(self): class winlog(object): + """ + Similar to nixlog, with underlying + functionality ported to support Windows. + + Does not support the use of 'v' toggling as nixlog does. + """ def __init__(self, file_like=None, echo=False, debug=0, buffer=False, env=None, filter_fn=None): self.env = env diff --git a/lib/spack/spack/build_systems/cmake.py b/lib/spack/spack/build_systems/cmake.py index 9fd2267d51..6e6b5e20b0 100644 --- a/lib/spack/spack/build_systems/cmake.py +++ b/lib/spack/spack/build_systems/cmake.py @@ -19,6 +19,7 @@ import spack.build_environment from spack.directives import conflicts, depends_on, variant from spack.package import InstallError, PackageBase, run_after +from spack.util.path import convert_to_posix_path # Regex to extract the primary generator from the CMake generator # string. @@ -173,7 +174,7 @@ def _std_args(pkg): define = CMakePackage.define args = [ '-G', generator, - define('CMAKE_INSTALL_PREFIX', pkg.prefix.replace('\\', '/')), + define('CMAKE_INSTALL_PREFIX', convert_to_posix_path(pkg.prefix)), define('CMAKE_BUILD_TYPE', build_type), ] diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py index 1a496a9842..1281c6d9ef 100644 --- a/lib/spack/spack/cmd/create.py +++ b/lib/spack/spack/cmd/create.py @@ -758,7 +758,15 @@ def get_versions(args, name): # Default guesser guesser = BuildSystemGuesser() - if args.url is not None and args.template != 'bundle': + valid_url = True + try: + spack.util.url.require_url_format(args.url) + if args.url.startswith('file://'): + valid_url = False # No point in spidering these + except AssertionError: + valid_url = False + + if args.url is not None and args.template != 'bundle' and valid_url: # Find available versions try: url_dict = spack.util.web.find_versions_of_archive(args.url) diff --git a/lib/spack/spack/cmd/make_installer.py b/lib/spack/spack/cmd/make_installer.py index c1bced479f..761401ea37 100644 --- a/lib/spack/spack/cmd/make_installer.py +++ b/lib/spack/spack/cmd/make_installer.py @@ -9,6 +9,7 @@ import spack.paths import spack.util.executable from spack.spec import Spec +from spack.util.path import convert_to_posix_path description = "generate Windows installer" section = "admin" @@ -77,13 +78,13 @@ def make_installer(parser, args): else: if not os.path.isabs(spack_source): spack_source = posixpath.abspath(spack_source) - spack_source = spack_source.replace('\\', '/') + spack_source = convert_to_posix_path(spack_source) spack_version = args.spack_version here = os.path.dirname(os.path.abspath(__file__)) source_dir = os.path.join(here, "installer") - posix_root = spack.paths.spack_root.replace('\\', '/') + posix_root = convert_to_posix_path(spack.paths.spack_root) spack_license = posixpath.join(posix_root, "LICENSE-APACHE") rtf_spack_license = txt_to_rtf(spack_license) spack_license = posixpath.join(source_dir, "LICENSE.rtf") diff --git a/lib/spack/spack/compilers/msvc.py b/lib/spack/spack/compilers/msvc.py index fe5014128e..a3c5a7c752 100644 --- a/lib/spack/spack/compilers/msvc.py +++ b/lib/spack/spack/compilers/msvc.py @@ -83,13 +83,13 @@ def __init__(self, *args, **kwargs): self.setvarsfile = os.path.join( os.getenv("ONEAPI_ROOT"), "setvars.bat") else: - # The long relative path below points six directories up - # to the root of the MSVC tree associated with this (self) - # vesion of MSVC, so that we can then find the relevant - # VCVARS file. Note: This is done in the opposite order - # that this procedure typically goes on Windows - # However it is done this way here with great intent to conform - # with how Spack discovers compilers. + # To use the MSVC compilers, VCVARS must be invoked + # VCVARS is located at a fixed location, referencable + # idiomatically by the following relative path from the + # compiler. + # Spack first finds the compilers via VSWHERE + # and stores their path, but their respective VCVARS + # file must be invoked before useage. self.setvarsfile = os.path.abspath( os.path.join(self.cc, '../../../../../../..')) self.setvarsfile = os.path.join( diff --git a/lib/spack/spack/detection/path.py b/lib/spack/spack/detection/path.py index 32e5f57af7..ef0bffad67 100644 --- a/lib/spack/spack/detection/path.py +++ b/lib/spack/spack/detection/path.py @@ -42,12 +42,12 @@ def executables_in_path(path_hints=None): path_hints (list): list of paths to be searched. If None the list will be constructed based on the PATH environment variable. """ - # build_environment.py::1013: If we're on a Windows box, run vswhere, + # If we're on a Windows box, run vswhere, # steal the installationPath using windows_os.py logic, # construct paths to CMake and Ninja, add to PATH path_hints = path_hints or spack.util.environment.get_path('PATH') if sys.platform == 'win32': - msvc_paths = winOs.WindowsOs.vs_install_paths + msvc_paths = list(winOs.WindowsOs.vs_install_paths) msvc_cmake_paths = [ os.path.join(path, "Common7", "IDE", "CommonExtensions", "Microsoft", "CMake", "CMake", "bin") @@ -91,8 +91,9 @@ def by_executable(packages_to_check, path_hints=None): path_hints = [] if path_hints is None else path_hints exe_pattern_to_pkgs = collections.defaultdict(list) for pkg in packages_to_check: - for exe in pkg.platform_executables: - exe_pattern_to_pkgs[exe].append(pkg) + if hasattr(pkg, 'executables'): + for exe in pkg.platform_executables: + exe_pattern_to_pkgs[exe].append(pkg) # Add Windows specific, package related paths to the search paths path_hints.extend(compute_windows_program_path_for_package(pkg)) diff --git a/lib/spack/spack/environment/environment.py b/lib/spack/spack/environment/environment.py index 9d6c5ba8c8..a3e35a234a 100644 --- a/lib/spack/spack/environment/environment.py +++ b/lib/spack/spack/environment/environment.py @@ -16,8 +16,9 @@ import llnl.util.filesystem as fs import llnl.util.tty as tty +from llnl.util.filesystem import rename from llnl.util.lang import dedupe -from llnl.util.symlink import islink, symlink +from llnl.util.symlink import symlink import spack.bootstrap import spack.compilers @@ -530,14 +531,14 @@ def regenerate(self, concretized_specs): tmp_symlink_name = os.path.join(root_dirname, '._view_link') if os.path.exists(tmp_symlink_name): os.unlink(tmp_symlink_name) - os.symlink(new_root, tmp_symlink_name) + symlink(new_root, tmp_symlink_name) # mv symlink atomically over root symlink to old_root if os.path.exists(self.root) and not os.path.islink(self.root): msg = "Cannot create view: " msg += "file already exists and is not a link: %s" % self.root raise SpackEnvironmentViewError(msg) - os.rename(tmp_symlink_name, self.root) + rename(tmp_symlink_name, self.root) # remove old_root if old_root and os.path.exists(old_root): diff --git a/lib/spack/spack/fetch_strategy.py b/lib/spack/spack/fetch_strategy.py index 7abcea7383..94b5fab042 100644 --- a/lib/spack/spack/fetch_strategy.py +++ b/lib/spack/spack/fetch_strategy.py @@ -634,7 +634,6 @@ class CacheURLFetchStrategy(URLFetchStrategy): @_needs_stage def fetch(self): reg_str = r'^file://' - reg_str += '/' if is_windows else '' path = re.sub(reg_str, '', self.url) # check whether the cache file exists. diff --git a/lib/spack/spack/hooks/sbang.py b/lib/spack/spack/hooks/sbang.py index 2793906ebd..bef30d2b76 100644 --- a/lib/spack/spack/hooks/sbang.py +++ b/lib/spack/spack/hooks/sbang.py @@ -30,7 +30,7 @@ #: Groupdb does not exist on Windows, prevent imports #: on supported systems -is_windows = str(spack.platforms.host()) == 'windows' +is_windows = sys.platform == 'win32' if not is_windows: import grp diff --git a/lib/spack/spack/operating_systems/windows_os.py b/lib/spack/spack/operating_systems/windows_os.py index 879a2b77c7..61525df887 100755 --- a/lib/spack/spack/operating_systems/windows_os.py +++ b/lib/spack/spack/operating_systems/windows_os.py @@ -65,9 +65,10 @@ class WindowsOs(OperatingSystem): compiler_search_paths = comp_search_paths def __init__(self): - if Version(platform.release()) < Version('10'): + plat_ver = platform.release() + if Version(plat_ver) < Version('10'): raise SpackError("Spack is not supported on Windows versions older than 10") - super(WindowsOs, self).__init__('Windows10', '10') + super(WindowsOs, self).__init__('windows{}'.format(plat_ver), plat_ver) def __str__(self): return self.name diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index d91c5109ae..5888416b10 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -59,6 +59,7 @@ from spack.stage import ResourceStage, Stage, StageComposite, stage_prefix from spack.util.executable import ProcessError, which from spack.util.package_hash import package_hash +from spack.util.path import win_exe_ext from spack.util.prefix import Prefix from spack.version import Version @@ -176,9 +177,29 @@ class DetectablePackageMeta(object): for the detection function. """ def __init__(cls, name, bases, attr_dict): - # If a package has the executables attribute then it's - # assumed to be detectable + # On windows, extend the list of regular expressions to look for + # filenames ending with ".exe" + # (in some cases these regular expressions include "$" to avoid + # pulling in filenames with unexpected suffixes, but this allows + # for example detecting "foo.exe" when the package writer specified + # that "foo" was a possible executable. if hasattr(cls, 'executables'): + @property + def platform_executables(self): + def to_windows_exe(exe): + if exe.endswith('$'): + exe = exe.replace('$', '%s$' % win_exe_ext()) + else: + exe += win_exe_ext() + return exe + plat_exe = [] + if hasattr(self, 'executables'): + for exe in self.executables: + if sys.platform == 'win32': + exe = to_windows_exe(exe) + plat_exe.append(exe) + return plat_exe + @classmethod def determine_spec_details(cls, prefix, exes_in_prefix): """Allow ``spack external find ...`` to locate installations. @@ -264,6 +285,13 @@ def determine_variants(cls, exes, version_str): if default and not hasattr(cls, 'determine_variants'): cls.determine_variants = determine_variants + # This function should not be overridden by subclasses, + # as it is not designed for bespoke pkg detection but rather + # on a per-platform basis + if hasattr(cls, 'platform_executables'): + raise PackageError("Packages should not override platform_executables") + cls.platform_executables = platform_executables + super(DetectablePackageMeta, cls).__init__(name, bases, attr_dict) @@ -898,16 +926,6 @@ def version(self): " does not have a concrete version.") return self.spec.versions[0] - @property - def platform_executables(self): - plat_exe = [] - if hasattr(self, 'executables'): - for exe in self.executables: - if sys.platform == 'win32': - exe = exe.replace('$', r'\.exe$') - plat_exe.append(exe) - return plat_exe - @memoized def version_urls(self): """OrderedDict of explicitly defined URLs for versions of this package. diff --git a/lib/spack/spack/parse.py b/lib/spack/spack/parse.py index 2d4dce3a75..603848a3a0 100644 --- a/lib/spack/spack/parse.py +++ b/lib/spack/spack/parse.py @@ -13,6 +13,7 @@ import spack.error import spack.util.path as sp + class Token(object): """Represents tokens; generated from input by lexer and fed to parse().""" diff --git a/lib/spack/spack/paths.py b/lib/spack/spack/paths.py index 4d8747d741..b423e9e6c5 100644 --- a/lib/spack/spack/paths.py +++ b/lib/spack/spack/paths.py @@ -81,7 +81,8 @@ # setting `SPACK_USER_CACHE_PATH`. Otherwise it defaults to ~/.spack. # def _get_user_cache_path(): - return os.path.expanduser(os.getenv('SPACK_USER_CACHE_PATH') or "~/.spack") + return os.path.expanduser(os.getenv('SPACK_USER_CACHE_PATH') + or "~%s.spack" % os.sep) user_cache_path = _get_user_cache_path() @@ -116,12 +117,14 @@ def _get_user_cache_path(): # User configuration and caches in $HOME/.spack def _get_user_config_path(): - return os.path.expanduser(os.getenv('SPACK_USER_CONFIG_PATH') or "~/.spack") + return os.path.expanduser(os.getenv('SPACK_USER_CONFIG_PATH') or + "~%s.spack" % os.sep) # Configuration in /etc/spack on the system def _get_system_config_path(): - return os.path.expanduser(os.getenv('SPACK_SYSTEM_CONFIG_PATH') or "/etc/spack") + return os.path.expanduser(os.getenv('SPACK_SYSTEM_CONFIG_PATH') or + os.sep + os.path.join('etc', 'spack')) #: User configuration location diff --git a/lib/spack/spack/platforms/windows.py b/lib/spack/spack/platforms/windows.py index 552e520193..9626b29cc8 100755 --- a/lib/spack/spack/platforms/windows.py +++ b/lib/spack/spack/platforms/windows.py @@ -16,8 +16,6 @@ class Windows(Platform): priority = 101 - # binary_formats = ['macho'] - def __init__(self): super(Windows, self).__init__('windows') diff --git a/lib/spack/spack/repo.py b/lib/spack/spack/repo.py index e1403bd44f..904c22d9ba 100644 --- a/lib/spack/spack/repo.py +++ b/lib/spack/spack/repo.py @@ -330,7 +330,8 @@ def __init__(self, package_checker, namespace): self.checker = package_checker self.packages_path = self.checker.packages_path if sys.platform == 'win32': - self.packages_path = self.packages_path.replace("\\", "/") + self.packages_path = \ + spack.util.path.convert_to_posix_path(self.packages_path) self.namespace = namespace self.indexers = {} diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index 7feebdd4e2..b4c778ee76 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -111,6 +111,7 @@ import spack.util.executable import spack.util.hash import spack.util.module_cmd as md +import spack.util.path as pth import spack.util.prefix import spack.util.spack_json as sjson import spack.util.spack_yaml as syaml @@ -1724,7 +1725,7 @@ def prefix(self): @prefix.setter def prefix(self, value): - self._prefix = spack.util.prefix.Prefix(value) + self._prefix = spack.util.prefix.Prefix(pth.convert_to_platform_path(value)) def _spec_hash(self, hash): """Utility method for computing different types of Spec hashes. @@ -4876,6 +4877,10 @@ class SpecLexer(spack.parse.Lexer): """Parses tokens that make up spack specs.""" def __init__(self): + # Spec strings require posix-style paths on Windows + # because the result is later passed to shlex + filename_reg = r'[/\w.-]*/[/\w/-]+\.(yaml|json)[^\b]*' if not is_windows\ + else r'([A-Za-z]:)*?[/\w.-]*/[/\w/-]+\.(yaml|json)[^\b]*' super(SpecLexer, self).__init__([ (r'\^', lambda scanner, val: self.token(DEP, val)), (r'\@', lambda scanner, val: self.token(AT, val)), @@ -4889,10 +4894,7 @@ def __init__(self): # Filenames match before identifiers, so no initial filename # component is parsed as a spec (e.g., in subdir/spec.yaml/json) - # posixpath on Windows here because this string will be fed through - # shlex - (r'[/\w.-]*/[/\w/-]+\.(yaml|json)[^\b]*' if not is_windows\ - else r'([A-Za-z]:)*?[/\w.-]*/[/\w/-]+\.(yaml|json)[^\b]*', + (filename_reg, lambda scanner, v: self.token(FILE, v)), # Hash match after filename. No valid filename can be a hash diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py index a9b168f863..18a8dbe1b6 100644 --- a/lib/spack/spack/test/architecture.py +++ b/lib/spack/spack/test/architecture.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os import platform +import sys import pytest @@ -58,8 +59,8 @@ def test_platform(current_host_platform): assert str(detected_platform) == str(current_host_platform) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Test unsupported on Windows") +@pytest.mark.skipif(sys.platform == 'win32', + reason="Not supported on Windows (yet)") def test_user_input_combination(config, target_str, os_str): """Test for all the valid user input combinations that both the target and the operating system match. diff --git a/lib/spack/spack/test/build_distribution.py b/lib/spack/spack/test/build_distribution.py index c2008ffa63..c5132a9558 100644 --- a/lib/spack/spack/test/build_distribution.py +++ b/lib/spack/spack/test/build_distribution.py @@ -18,6 +18,15 @@ reason="does not run on windows") +def _validate_url(url): + return + + +@pytest.fixture(autouse=True) +def url_check(monkeypatch): + monkeypatch.setattr(spack.util.url, 'require_url_format', _validate_url) + + def test_build_tarball_overwrite( install_mockery, mock_fetch, monkeypatch, tmpdir): diff --git a/lib/spack/spack/test/build_environment.py b/lib/spack/spack/test/build_environment.py index 50241e6c9e..a816ac4ba9 100644 --- a/lib/spack/spack/test/build_environment.py +++ b/lib/spack/spack/test/build_environment.py @@ -24,6 +24,18 @@ from spack.paths import build_env_path from spack.util.environment import EnvironmentModifications from spack.util.executable import Executable +from spack.util.path import Path, convert_to_platform_path + + +def os_pathsep_join(path, *pths): + out_pth = path + for pth in pths: + out_pth = os.pathsep.join([out_pth, pth]) + return out_pth + + +def prep_and_join(path, *pths): + return os.path.sep + os.path.join(path, *pths) @pytest.fixture @@ -84,7 +96,7 @@ def _ensure(env_mods): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Static to Shared not supported on Win (yet)") def test_static_to_shared_library(build_environment): os.environ['SPACK_TEST_COMMAND'] = 'dump-args' @@ -139,8 +151,6 @@ def _set_wrong_cc(x): assert os.environ['ANOTHER_VAR'] == 'THIS_IS_SET' -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('initial,modifications,expected', [ # Set and unset variables ({'SOME_VAR_STR': '', 'SOME_VAR_NUM': '0'}, @@ -153,25 +163,32 @@ def _set_wrong_cc(x): {'set': {'SOME_VAR_STR': 'SOME_STR'}}, {'SOME_VAR_STR': 'SOME_STR'}), # Append and prepend to the same variable - ({'EMPTY_PATH_LIST': '/path/middle'}, - {'prepend_path': {'EMPTY_PATH_LIST': '/path/first'}, - 'append_path': {'EMPTY_PATH_LIST': '/path/last'}}, - {'EMPTY_PATH_LIST': '/path/first:/path/middle:/path/last'}), + ({'EMPTY_PATH_LIST': prep_and_join('path', 'middle')}, + {'prepend_path': {'EMPTY_PATH_LIST': prep_and_join('path', 'first')}, + 'append_path': {'EMPTY_PATH_LIST': prep_and_join('path', 'last')}}, + {'EMPTY_PATH_LIST': os_pathsep_join(prep_and_join('path', 'first'), + prep_and_join('path', 'middle'), + prep_and_join('path', 'last'))}), # Append and prepend from empty variables ({'EMPTY_PATH_LIST': '', 'SOME_VAR_STR': ''}, - {'prepend_path': {'EMPTY_PATH_LIST': '/path/first'}, - 'append_path': {'SOME_VAR_STR': '/path/last'}}, - {'EMPTY_PATH_LIST': '/path/first', 'SOME_VAR_STR': '/path/last'}), + {'prepend_path': {'EMPTY_PATH_LIST': prep_and_join('path', 'first')}, + 'append_path': {'SOME_VAR_STR': prep_and_join('path', 'last')}}, + {'EMPTY_PATH_LIST': prep_and_join('path', 'first'), + 'SOME_VAR_STR': prep_and_join('path', 'last')}), ({}, # Same as before but on variables that were not defined - {'prepend_path': {'EMPTY_PATH_LIST': '/path/first'}, - 'append_path': {'SOME_VAR_STR': '/path/last'}}, - {'EMPTY_PATH_LIST': '/path/first', 'SOME_VAR_STR': '/path/last'}), + {'prepend_path': {'EMPTY_PATH_LIST': prep_and_join('path', 'first')}, + 'append_path': {'SOME_VAR_STR': prep_and_join('path', 'last')}}, + {'EMPTY_PATH_LIST': prep_and_join('path', 'first'), + 'SOME_VAR_STR': prep_and_join('path', 'last')}), # Remove a path from a list - ({'EMPTY_PATH_LIST': '/path/first:/path/middle:/path/last'}, - {'remove_path': {'EMPTY_PATH_LIST': '/path/middle'}}, - {'EMPTY_PATH_LIST': '/path/first:/path/last'}), - ({'EMPTY_PATH_LIST': '/only/path'}, - {'remove_path': {'EMPTY_PATH_LIST': '/only/path'}}, + ({'EMPTY_PATH_LIST': os_pathsep_join(prep_and_join('path', 'first'), + prep_and_join('path', 'middle'), + prep_and_join('path', 'last'))}, + {'remove_path': {'EMPTY_PATH_LIST': prep_and_join('path', 'middle')}}, + {'EMPTY_PATH_LIST': os_pathsep_join(prep_and_join('path', 'first'), + prep_and_join('path', 'last'))}), + ({'EMPTY_PATH_LIST': prep_and_join('only', 'path')}, + {'remove_path': {'EMPTY_PATH_LIST': prep_and_join('only', 'path')}}, {'EMPTY_PATH_LIST': ''}), ]) def test_compiler_config_modifications( @@ -180,16 +197,22 @@ def test_compiler_config_modifications( # Set the environment as per prerequisites ensure_env_variables(initial) + def platform_pathsep(pathlist): + if Path.platform_path == Path.windows: + pathlist = pathlist.replace(':', ';') + + return convert_to_platform_path(pathlist) + # Monkeypatch a pkg.compiler.environment with the required modifications pkg = spack.spec.Spec('cmake').concretized().package monkeypatch.setattr(pkg.compiler, 'environment', modifications) - # Trigger the modifications spack.build_environment.setup_package(pkg, False) # Check they were applied for name, value in expected.items(): if value is not None: + value = platform_pathsep(value) assert os.environ[name] == value continue assert name not in os.environ diff --git a/lib/spack/spack/test/buildrequest.py b/lib/spack/spack/test/buildrequest.py index 86c4a37d0f..a4ae76086a 100644 --- a/lib/spack/spack/test/buildrequest.py +++ b/lib/spack/spack/test/buildrequest.py @@ -11,9 +11,10 @@ import spack.repo import spack.spec -# Functionality supported on windows however tests are currently failing -# due to compatibility issues, or due to dependent components currently -# being unsupported on Windows +# Spack functionality tested here should work on Windows, +# however, tests are currently failing because support +# for Spack on Windows has not been extended to this +# module yet. pytestmark = pytest.mark.skipif(sys.platform == "win32", reason="does not run on windows") diff --git a/lib/spack/spack/test/cache_fetch.py b/lib/spack/spack/test/cache_fetch.py index 44a5275868..828dd81791 100644 --- a/lib/spack/spack/test/cache_fetch.py +++ b/lib/spack/spack/test/cache_fetch.py @@ -4,6 +4,7 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import sys import pytest @@ -13,13 +14,17 @@ from spack.fetch_strategy import CacheURLFetchStrategy, NoCacheError from spack.stage import Stage +is_windows = sys.platform == 'win32' + @pytest.mark.parametrize('_fetch_method', ['curl', 'urllib']) def test_fetch_missing_cache(tmpdir, _fetch_method): """Ensure raise a missing cache file.""" testpath = str(tmpdir) with spack.config.override('config:url_fetch_method', _fetch_method): - fetcher = CacheURLFetchStrategy(url='file:///not-a-real-cache-file') + abs_pref = '' if is_windows else '/' + url = 'file://' + abs_pref + 'not-a-real-cache-file' + fetcher = CacheURLFetchStrategy(url=url) with Stage(fetcher, path=testpath): with pytest.raises(NoCacheError, match=r'No cache'): fetcher.fetch() @@ -31,7 +36,11 @@ def test_fetch(tmpdir, _fetch_method): testpath = str(tmpdir) cache = os.path.join(testpath, 'cache.tar.gz') touch(cache) - url = 'file:///{0}'.format(cache) + if is_windows: + url_stub = '{0}' + else: + url_stub = '/{0}' + url = 'file://' + url_stub.format(cache) with spack.config.override('config:url_fetch_method', _fetch_method): fetcher = CacheURLFetchStrategy(url=url) with Stage(fetcher, path=testpath) as stage: diff --git a/lib/spack/spack/test/cmd/common/arguments.py b/lib/spack/spack/test/cmd/common/arguments.py index 763c6880c0..5f1299a94a 100644 --- a/lib/spack/spack/test/cmd/common/arguments.py +++ b/lib/spack/spack/test/cmd/common/arguments.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import argparse -import sys import pytest @@ -63,8 +62,6 @@ def test_parse_spec_flags_with_spaces( assert all(x in s.variants for x in expected_variants) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.usefixtures('config') def test_match_spec_env(mock_packages, mutable_mock_env_path): """ @@ -87,8 +84,6 @@ def test_match_spec_env(mock_packages, mutable_mock_env_path): assert env_spec.concrete -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.usefixtures('config') def test_multiple_env_match_raises_error(mock_packages, mutable_mock_env_path): e = ev.create('test') @@ -102,8 +97,6 @@ def test_multiple_env_match_raises_error(mock_packages, mutable_mock_env_path): assert 'matches multiple specs' in exc_info.value.message -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.usefixtures('config') def test_root_and_dep_match_returns_root(mock_packages, mutable_mock_env_path): e = ev.create('test') diff --git a/lib/spack/spack/test/cmd/compiler.py b/lib/spack/spack/test/cmd/compiler.py index 26dcb7ff59..f799d96b0f 100644 --- a/lib/spack/spack/test/cmd/compiler.py +++ b/lib/spack/spack/test/cmd/compiler.py @@ -105,7 +105,8 @@ def test_compiler_remove(mutable_config, mock_packages): assert spack.spec.CompilerSpec("gcc@4.5.0") not in compilers -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") +@pytest.mark.skipif(sys.platform == 'win32', reason="Cannot execute bash \ + script on Windows") def test_compiler_add( mutable_config, mock_packages, mock_compiler_dir, mock_compiler_version ): diff --git a/lib/spack/spack/test/cmd/concretize.py b/lib/spack/spack/test/cmd/concretize.py index c630ebeb68..d357ccc9dc 100644 --- a/lib/spack/spack/test/cmd/concretize.py +++ b/lib/spack/spack/test/cmd/concretize.py @@ -3,7 +3,6 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import sys import pytest @@ -19,7 +18,6 @@ concretize = SpackCommand('concretize') -@pytest.mark.skipif(sys.platform == "win32", reason="Test unsupported on Windows") @pytest.mark.parametrize('concretization', ['separately', 'together']) def test_concretize_all_test_dependencies(concretization): """Check all test dependencies are concretized.""" @@ -32,7 +30,6 @@ def test_concretize_all_test_dependencies(concretization): assert e.matching_spec('test-dependency') -@pytest.mark.skipif(sys.platform == "win32", reason="Test unsupported on Windows") @pytest.mark.parametrize('concretization', ['separately', 'together']) def test_concretize_root_test_dependencies_not_recursive(concretization): """Check that test dependencies are not concretized recursively.""" @@ -45,7 +42,6 @@ def test_concretize_root_test_dependencies_not_recursive(concretization): assert e.matching_spec('test-dependency') is None -@pytest.mark.skipif(sys.platform == "win32", reason="Test unsupported on Windows") @pytest.mark.parametrize('concretization', ['separately', 'together']) def test_concretize_root_test_dependencies_are_concretized(concretization): """Check that root test dependencies are concretized.""" diff --git a/lib/spack/spack/test/cmd/config.py b/lib/spack/spack/test/cmd/config.py index a76ec07ca5..e8dc80c6da 100644 --- a/lib/spack/spack/test/cmd/config.py +++ b/lib/spack/spack/test/cmd/config.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import functools import os -import sys import pytest @@ -426,11 +425,8 @@ def test_remove_list(mutable_empty_config): """ - -@pytest.mark.skipif(sys.platform == 'win32', - reason="Lockfiles not support on Windows (yet)") def test_config_add_to_env(mutable_empty_config, mutable_mock_env_path): - ev.create('test') + env('create', 'test') with ev.read('test'): config('add', 'config:dirty:true') output = config('get') diff --git a/lib/spack/spack/test/cmd/env.py b/lib/spack/spack/test/cmd/env.py index ae47aada02..868eb8ec45 100644 --- a/lib/spack/spack/test/cmd/env.py +++ b/lib/spack/spack/test/cmd/env.py @@ -27,10 +27,12 @@ from spack.util.mock_package import MockPackageMultiRepo from spack.util.path import substitute_path_variables +# TODO-27021 # everything here uses the mock_env_path pytestmark = [ pytest.mark.usefixtures('mutable_mock_env_path', 'config', 'mutable_mock_repo'), - pytest.mark.maybeslow + pytest.mark.maybeslow, + pytest.mark.skipif(sys.platform == 'win32', reason='Envs unsupported on Window') ] env = SpackCommand('env') @@ -42,10 +44,7 @@ uninstall = SpackCommand('uninstall') find = SpackCommand('find') -if sys.platform == 'win32': - sep = 'C:\\' -else: - sep = os.sep +sep = os.sep def check_mpileaks_and_deps_in_view(viewdir): @@ -66,8 +65,6 @@ def test_add(): assert Spec('mpileaks') in e.user_specs -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_add_virtual(): env('create', 'test') @@ -136,8 +133,6 @@ def test_env_remove(capfd): assert 'bar' not in out -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_concretize(): e = ev.create('test') e.add('mpileaks') @@ -146,8 +141,6 @@ def test_concretize(): assert any(x.name == 'mpileaks' for x in env_specs) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="InstallError:Wrong cmake was in environment") def test_env_uninstalled_specs(install_mockery, mock_fetch): e = ev.create('test') e.add('cmake-client') @@ -161,8 +154,6 @@ def test_env_uninstalled_specs(install_mockery, mock_fetch): assert any(s.name == 'mpileaks' for s in e.uninstalled_specs()) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='InstallError: Wrong cmake was in environment') def test_env_install_all(install_mockery, mock_fetch): e = ev.create('test') e.add('cmake-client') @@ -173,8 +164,6 @@ def test_env_install_all(install_mockery, mock_fetch): assert spec.package.installed -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='InstallError: Wrong cmake was in environment') def test_env_install_single_spec(install_mockery, mock_fetch): env('create', 'test') install = SpackCommand('install') @@ -189,7 +178,6 @@ def test_env_install_single_spec(install_mockery, mock_fetch): assert e.specs_by_hash[e.concretized_order[0]].name == 'cmake-client' -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") def test_env_roots_marked_explicit(install_mockery, mock_fetch): install = SpackCommand('install') install('dependent-install') @@ -211,8 +199,6 @@ def test_env_roots_marked_explicit(install_mockery, mock_fetch): assert len(explicit) == 2 -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='InstallError: Wrong cmake was in environment') def test_env_modifications_error_on_activate( install_mockery, mock_fetch, monkeypatch, capfd): env('create', 'test') @@ -235,8 +221,6 @@ def setup_error(pkg, env): assert "Warning: couldn't get environment settings" in err -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Error: filename or extension is too long') def test_activate_adds_transitive_run_deps_to_path( install_mockery, mock_fetch, monkeypatch): env('create', 'test') @@ -251,8 +235,6 @@ def test_activate_adds_transitive_run_deps_to_path( assert env_variables['DEPENDENCY_ENV_VAR'] == '1' -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='InstallError: Wrong cmake was in environment:') def test_env_install_same_spec_twice(install_mockery, mock_fetch): env('create', 'test') @@ -267,8 +249,6 @@ def test_env_install_same_spec_twice(install_mockery, mock_fetch): assert 'already installed' in out -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_env_definition_symlink(install_mockery, mock_fetch, tmpdir): filepath = str(tmpdir.join('spack.yaml')) filepath_mid = str(tmpdir.join('spack_mid.yaml')) @@ -288,8 +268,6 @@ def test_env_definition_symlink(install_mockery, mock_fetch, tmpdir): assert os.path.islink(filepath_mid) -@pytest.mark.skipif(sys.platform == "win32", - reason='Logging error') def test_env_install_two_specs_same_dep( install_mockery, mock_fetch, tmpdir, capsys): """Test installation of two packages that share a dependency with no @@ -325,8 +303,6 @@ def test_env_install_two_specs_same_dep( assert a, 'Expected a to be installed' -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_remove_after_concretize(): e = ev.create('test') @@ -350,8 +326,6 @@ def test_remove_after_concretize(): assert not any(s.name == 'mpileaks' for s in env_specs) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_remove_command(): env('create', 'test') assert 'test' in env('list') @@ -415,8 +389,6 @@ def test_environment_status(capsys, tmpdir): assert 'in current directory' in env('status') -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows - uses pkgconf') def test_env_status_broken_view( mutable_mock_env_path, mock_archive, mock_fetch, mock_packages, install_mockery, tmpdir @@ -438,8 +410,6 @@ def test_env_status_broken_view( assert 'includes out of date packages or repos' not in output -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows - uses pkgconf') def test_env_activate_broken_view( mutable_mock_env_path, mock_archive, mock_fetch, mock_packages, install_mockery @@ -458,8 +428,6 @@ def test_env_activate_broken_view( env('activate', '--sh', 'test') -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_to_lockfile_dict(): e = ev.create('test') e.add('mpileaks') @@ -472,8 +440,6 @@ def test_to_lockfile_dict(): assert e.specs_by_hash == e_copy.specs_by_hash -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_env_repo(): e = ev.create('test') e.add('mpileaks') @@ -487,8 +453,6 @@ def test_env_repo(): assert package.namespace == 'builtin.mock' -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_user_removed_spec(): """Ensure a user can remove from any position in the spack.yaml file.""" initial_yaml = StringIO("""\ @@ -523,8 +487,6 @@ def test_user_removed_spec(): assert not any(x.name == 'hypre' for x in env_specs) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_init_from_lockfile(tmpdir): """Test that an environment can be instantiated from a lockfile.""" initial_yaml = StringIO("""\ @@ -551,8 +513,6 @@ def test_init_from_lockfile(tmpdir): assert s1 == s2 -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_init_from_yaml(tmpdir): """Test that an environment can be instantiated from a lockfile.""" initial_yaml = StringIO("""\ @@ -576,8 +536,6 @@ def test_init_from_yaml(tmpdir): assert not e2.specs_by_hash -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows - uses pkgconf') @pytest.mark.usefixtures('config') def test_env_view_external_prefix( tmpdir_factory, mutable_database, mock_packages @@ -650,8 +608,6 @@ def test_init_with_file_and_remove(tmpdir): assert 'test' not in out -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_with_config(): test_config = """\ env: @@ -671,8 +627,6 @@ def test_env_with_config(): for x in e._get_environment_specs()) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_with_config_bad_include(capfd): env_name = 'test_bad_include' test_config = """\ @@ -696,8 +650,6 @@ def test_with_config_bad_include(capfd): assert ev.active_environment() is None -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_with_include_config_files_same_basename(): test_config = """\ env: @@ -740,8 +692,6 @@ def test_env_with_include_config_files_same_basename(): assert(environment_specs[1].satisfies('mpileaks@2.2')) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_with_included_config_file(): test_config = """\ env: @@ -767,8 +717,6 @@ def test_env_with_included_config_file(): for x in e._get_environment_specs()) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_with_included_config_scope(): config_scope_path = os.path.join(ev.root('test'), 'config') test_config = """\ @@ -798,8 +746,6 @@ def test_env_with_included_config_scope(): for x in e._get_environment_specs()) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_with_included_config_var_path(): config_var_path = os.path.join('$tempdir', 'included-config.yaml') test_config = """\ @@ -829,8 +775,6 @@ def test_env_with_included_config_var_path(): for x in e._get_environment_specs()) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_config_precedence(): test_config = """\ env: @@ -866,8 +810,6 @@ def test_env_config_precedence(): x.satisfies('libelf@0.8.12') for x in e._get_environment_specs()) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_included_config_precedence(): test_config = """\ env: @@ -922,8 +864,6 @@ def test_bad_env_yaml_format(tmpdir): assert "'spacks' was unexpected" in str(e) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_loads(install_mockery, mock_fetch): env('create', 'test') @@ -945,8 +885,6 @@ def test_env_loads(install_mockery, mock_fetch): assert 'module load mpileaks' in contents -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") @pytest.mark.disable_clean_stage_check def test_stage(mock_stage, mock_fetch, install_mockery): env('create', 'test') @@ -985,8 +923,6 @@ def test_env_commands_die_with_no_env_arg(): env('status') -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_blocks_uninstall(mock_stage, mock_fetch, install_mockery): env('create', 'test') with ev.read('test'): @@ -1009,8 +945,6 @@ def test_roots_display_with_variants(): assert "boost +shared" in out -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_uninstall_removes_from_env(mock_stage, mock_fetch, install_mockery): env('create', 'test') with ev.read('test'): @@ -1053,8 +987,6 @@ def create_v1_lockfile_dict(roots, all_specs): return test_lockfile_dict -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows - uses pkgconf") @pytest.mark.usefixtures('config') def test_read_old_lock_and_write_new(tmpdir): build_only = ('build',) @@ -1086,8 +1018,6 @@ def test_read_old_lock_and_write_new(tmpdir): y.build_hash()]) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows - uses pkgconf") @pytest.mark.usefixtures('config') def test_read_old_lock_creates_backup(tmpdir): """When reading a version-1 lockfile, make sure that a backup of that file @@ -1116,8 +1046,6 @@ def test_read_old_lock_creates_backup(tmpdir): assert y.dag_hash() in lockfile_dict_v1['concrete_specs'] -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows - uses pkgconf") @pytest.mark.usefixtures('config') def test_indirect_build_dep(): """Simple case of X->Y->Z where Y is a build/link dep and Z is a @@ -1153,8 +1081,6 @@ def noop(*args): assert x_env_spec == x_concretized -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows - uses pkgconf") @pytest.mark.usefixtures('config') def test_store_different_build_deps(): r"""Ensure that an environment can store two instances of a build-only @@ -1208,8 +1134,6 @@ def noop(*args): assert x_read['z'] != y_read['z'] -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Fails on windows') def test_env_updates_view_install( tmpdir, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1221,8 +1145,6 @@ def test_env_updates_view_install( check_mpileaks_and_deps_in_view(view_dir) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Fails on windows') def test_env_view_fails( tmpdir, mock_packages, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1235,8 +1157,6 @@ def test_env_view_fails( install('--fake') -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_without_view_install( tmpdir, mock_stage, mock_fetch, install_mockery): # Test enabling a view after installing specs @@ -1259,8 +1179,6 @@ def test_env_without_view_install( check_mpileaks_and_deps_in_view(view_dir) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_env_config_view_default( tmpdir, mock_stage, mock_fetch, install_mockery): # This config doesn't mention whether a view is enabled @@ -1280,8 +1198,6 @@ def test_env_config_view_default( assert view.get_spec('mpileaks') -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_updates_view_install_package( tmpdir, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1292,8 +1208,6 @@ def test_env_updates_view_install_package( assert os.path.exists(str(view_dir.join('.spack/mpileaks'))) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_updates_view_add_concretize( tmpdir, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1306,8 +1220,6 @@ def test_env_updates_view_add_concretize( check_mpileaks_and_deps_in_view(view_dir) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_updates_view_uninstall( tmpdir, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1323,8 +1235,6 @@ def test_env_updates_view_uninstall( check_viewdir_removal(view_dir) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_updates_view_uninstall_referenced_elsewhere( tmpdir, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1342,8 +1252,6 @@ def test_env_updates_view_uninstall_referenced_elsewhere( check_viewdir_removal(view_dir) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_updates_view_remove_concretize( tmpdir, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1362,8 +1270,6 @@ def test_env_updates_view_remove_concretize( check_viewdir_removal(view_dir) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_updates_view_force_remove( tmpdir, mock_stage, mock_fetch, install_mockery): view_dir = tmpdir.join('view') @@ -1379,8 +1285,6 @@ def test_env_updates_view_force_remove( check_viewdir_removal(view_dir) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason='Not supported on Windows (yet)') def test_env_activate_view_fails( tmpdir, mock_stage, mock_fetch, install_mockery): """Sanity check on env activate to make sure it requires shell support""" @@ -1455,8 +1359,6 @@ def test_stack_yaml_definitions_as_constraints_on_matrix(tmpdir): assert Spec('callpath^mpich@3.0.3') in test.user_specs -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") @pytest.mark.regression('12095') def test_stack_yaml_definitions_write_reference(tmpdir): filename = str(tmpdir.join('spack.yaml')) @@ -1523,8 +1425,6 @@ def test_stack_yaml_remove_from_list(tmpdir): assert Spec('callpath') in test.user_specs -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_stack_yaml_remove_from_list_force(tmpdir): filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: @@ -1575,8 +1475,6 @@ def test_stack_yaml_remove_from_matrix_no_effect(tmpdir): assert before == after -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_stack_yaml_force_remove_from_matrix(tmpdir): filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: @@ -1610,8 +1508,6 @@ def test_stack_yaml_force_remove_from_matrix(tmpdir): assert mpileaks_spec not in after_conc -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_stack_concretize_extraneous_deps(tmpdir, config, mock_packages): # FIXME: The new concretizer doesn't handle yet soft # FIXME: constraints for stacks @@ -1647,8 +1543,6 @@ def test_stack_concretize_extraneous_deps(tmpdir, config, mock_packages): assert concrete.satisfies('^mpi', strict=True) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_stack_concretize_extraneous_variants(tmpdir, config, mock_packages): filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: @@ -1680,8 +1574,6 @@ def test_stack_concretize_extraneous_variants(tmpdir, config, mock_packages): user.variants['shared'].value) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_stack_concretize_extraneous_variants_with_dash(tmpdir, config, mock_packages): filename = str(tmpdir.join('spack.yaml')) @@ -1730,8 +1622,6 @@ def test_stack_definition_extension(tmpdir): assert Spec('callpath') in test.user_specs -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_definition_conditional_false(tmpdir): filename = str(tmpdir.join('spack.yaml')) with open(filename, 'w') as f: @@ -1889,8 +1779,6 @@ def test_stack_definition_conditional_add_write(tmpdir): assert 'zmpi' not in packages_lists[1]['packages'] -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_combinatorial_view(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -1923,8 +1811,6 @@ def test_stack_combinatorial_view(tmpdir, mock_fetch, mock_packages, (spec.version, spec.compiler.name))) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_view_select(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -1963,8 +1849,6 @@ def test_stack_view_select(tmpdir, mock_fetch, mock_packages, (spec.version, spec.compiler.name))) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_view_exclude(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -2003,8 +1887,6 @@ def test_stack_view_exclude(tmpdir, mock_fetch, mock_packages, (spec.version, spec.compiler.name))) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_view_select_and_exclude(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -2044,8 +1926,6 @@ def test_stack_view_select_and_exclude(tmpdir, mock_fetch, mock_packages, (spec.version, spec.compiler.name))) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_view_link_roots(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -2087,8 +1967,6 @@ def test_view_link_roots(tmpdir, mock_fetch, mock_packages, mock_archive, (spec.version, spec.compiler.name))) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_view_link_run(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): yaml = str(tmpdir.join('spack.yaml')) @@ -2120,8 +1998,6 @@ def test_view_link_run(tmpdir, mock_fetch, mock_packages, mock_archive, assert not os.path.exists(os.path.join(viewdir, pkg)) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') @pytest.mark.parametrize('link_type', ['hardlink', 'copy', 'symlink']) def test_view_link_type(link_type, tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): @@ -2151,8 +2027,6 @@ def test_view_link_type(link_type, tmpdir, mock_fetch, mock_packages, mock_archi assert os.path.islink(file_to_test) == (link_type == 'symlink') -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_view_link_all(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -2193,8 +2067,6 @@ def test_view_link_all(tmpdir, mock_fetch, mock_packages, mock_archive, (spec.version, spec.compiler.name))) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_view_activate_from_default(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -2226,8 +2098,6 @@ def test_stack_view_activate_from_default(tmpdir, mock_fetch, mock_packages, assert 'FOOBAR=mpileaks' in shell -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_view_no_activate_without_default(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): @@ -2258,8 +2128,6 @@ def test_stack_view_no_activate_without_default(tmpdir, mock_fetch, assert viewdir not in shell -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_stack_view_multiple_views(tmpdir, mock_fetch, mock_packages, mock_archive, install_mockery): filename = str(tmpdir.join('spack.yaml')) @@ -2362,8 +2230,6 @@ def test_env_activate_default_view_root_unconditional(mutable_mock_env_path): 'export PATH="{0}'.format(viewdir_bin) in out -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_concretize_user_specs_together(): e = ev.create('coconcretization') e.concretization = 'together' @@ -2392,8 +2258,6 @@ def test_concretize_user_specs_together(): assert all('mpich' not in spec for _, spec in e.concretized_specs()) -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_cant_install_single_spec_when_concretizing_together(): e = ev.create('coconcretization') e.concretization = 'together' @@ -2403,8 +2267,6 @@ def test_cant_install_single_spec_when_concretizing_together(): e.install_all() -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_duplicate_packages_raise_when_concretizing_together(): e = ev.create('coconcretization') e.concretization = 'together' @@ -2417,8 +2279,6 @@ def test_duplicate_packages_raise_when_concretizing_together(): e.concretize() -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") def test_env_write_only_non_default(): env('create', 'test') @@ -2429,8 +2289,6 @@ def test_env_write_only_non_default(): assert yaml == ev.default_manifest_yaml -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") @pytest.mark.regression('20526') def test_env_write_only_non_default_nested(tmpdir): # setup an environment file @@ -2465,8 +2323,6 @@ def test_env_write_only_non_default_nested(tmpdir): assert manifest == contents -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") @pytest.fixture def packages_yaml_v015(tmpdir): """Return the path to an existing manifest in the v0.15.x format @@ -2557,8 +2413,6 @@ def test_can_update_attributes_with_override(tmpdir): env('update', '-y', str(abspath.dirname)) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') @pytest.mark.regression('18338') def test_newline_in_commented_sequence_is_not_an_issue(tmpdir): spack_yaml = """ @@ -2594,8 +2448,6 @@ def extract_build_hash(environment): assert libelf_first_hash == libelf_second_hash -@pytest.mark.skipif(str(spack.platforms.host()) == 'windows', - reason="Not supported on Windows (yet)") @pytest.mark.regression('18441') def test_lockfile_not_deleted_on_write_error(tmpdir, monkeypatch): raw_yaml = """ @@ -2729,8 +2581,6 @@ def test_custom_version_concretize_together(tmpdir): assert any('hdf5@myversion' in spec for _, spec in e.concretized_specs()) -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_modules_relative_to_views(tmpdir, install_mockery, mock_fetch): spack_yaml = """ spack: @@ -2762,8 +2612,6 @@ def test_modules_relative_to_views(tmpdir, install_mockery, mock_fetch): assert spec.prefix not in contents -@pytest.mark.skipif(sys.platform == "win32", - reason='Not supported on Windows (yet)') def test_multiple_modules_post_env_hook(tmpdir, install_mockery, mock_fetch): spack_yaml = """ spack: diff --git a/lib/spack/spack/test/cmd/external.py b/lib/spack/spack/test/cmd/external.py index 3d7554c2eb..3a3c4face3 100644 --- a/lib/spack/spack/test/cmd/external.py +++ b/lib/spack/spack/test/cmd/external.py @@ -14,6 +14,8 @@ from spack.main import SpackCommand from spack.spec import Spec +is_windows = sys.platform == 'win32' + @pytest.fixture def executables_found(monkeypatch): @@ -25,11 +27,26 @@ def _mock_search(path_hints=None): return _factory -@pytest.mark.skipif(sys.platform == 'win32', reason="Not yet implemented on windows") -def test_find_external_single_package(mock_executable, executables_found): +@pytest.fixture +def _platform_executables(monkeypatch): + def _win_exe_ext(): + return '.bat' + + monkeypatch.setattr(spack.package, 'win_exe_ext', _win_exe_ext) + + +def define_plat_exe(exe): + if is_windows: + exe += '.bat' + return exe + + +def test_find_external_single_package(mock_executable, executables_found, + _platform_executables): pkgs_to_check = [spack.repo.get('cmake')] executables_found({ - mock_executable("cmake", output='echo "cmake version 1.foo"'): 'cmake' + mock_executable("cmake", output='echo cmake version 1.foo'): + define_plat_exe('cmake') }) pkg_to_entries = spack.detection.by_executable(pkgs_to_check) @@ -40,20 +57,23 @@ def test_find_external_single_package(mock_executable, executables_found): assert single_entry.spec == Spec('cmake@1.foo') -@pytest.mark.skipif(sys.platform == 'win32', reason="Not yet implemented on windows") -def test_find_external_two_instances_same_package(mock_executable, executables_found): +def test_find_external_two_instances_same_package(mock_executable, executables_found, + _platform_executables): pkgs_to_check = [spack.repo.get('cmake')] # Each of these cmake instances is created in a different prefix + # In Windows, quoted strings are echo'd with quotes includes + # we need to avoid that for proper regex. cmake_path1 = mock_executable( - "cmake", output='echo "cmake version 1.foo"', subdir=('base1', 'bin') + "cmake", output='echo cmake version 1.foo', subdir=('base1', 'bin') ) cmake_path2 = mock_executable( - "cmake", output='echo "cmake version 3.17.2"', subdir=('base2', 'bin') + "cmake", output='echo cmake version 3.17.2', subdir=('base2', 'bin') ) + cmake_exe = define_plat_exe('cmake') executables_found({ - cmake_path1: 'cmake', - cmake_path2: 'cmake' + cmake_path1: cmake_exe, + cmake_path2: cmake_exe }) pkg_to_entries = spack.detection.by_executable(pkgs_to_check) @@ -87,23 +107,24 @@ def test_find_external_update_config(mutable_config): def test_get_executables(working_env, mock_executable): cmake_path1 = mock_executable("cmake", output="echo cmake version 1.foo") - os.environ['PATH'] = ':'.join([os.path.dirname(cmake_path1)]) + os.environ['PATH'] = os.pathsep.join([os.path.dirname(cmake_path1)]) path_to_exe = spack.detection.executables_in_path() - assert path_to_exe[cmake_path1] == 'cmake' + cmake_exe = define_plat_exe('cmake') + assert path_to_exe[cmake_path1] == cmake_exe external = SpackCommand('external') -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") -def test_find_external_cmd(mutable_config, working_env, mock_executable): +def test_find_external_cmd(mutable_config, working_env, mock_executable, + _platform_executables): """Test invoking 'spack external find' with additional package arguments, which restricts the set of packages that Spack looks for. """ cmake_path1 = mock_executable("cmake", output="echo cmake version 1.foo") prefix = os.path.dirname(os.path.dirname(cmake_path1)) - os.environ['PATH'] = ':'.join([os.path.dirname(cmake_path1)]) + os.environ['PATH'] = os.pathsep.join([os.path.dirname(cmake_path1)]) external('find', 'cmake') pkgs_cfg = spack.config.get('packages') @@ -113,7 +134,6 @@ def test_find_external_cmd(mutable_config, working_env, mock_executable): assert {'spec': 'cmake@1.foo', 'prefix': prefix} in cmake_externals -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_find_external_cmd_not_buildable( mutable_config, working_env, mock_executable): """When the user invokes 'spack external find --not-buildable', the config @@ -121,25 +141,23 @@ def test_find_external_cmd_not_buildable( not buildable. """ cmake_path1 = mock_executable("cmake", output="echo cmake version 1.foo") - os.environ['PATH'] = ':'.join([os.path.dirname(cmake_path1)]) + os.environ['PATH'] = os.pathsep.join([os.path.dirname(cmake_path1)]) external('find', '--not-buildable', 'cmake') pkgs_cfg = spack.config.get('packages') assert not pkgs_cfg['cmake']['buildable'] -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_find_external_cmd_full_repo( - mutable_config, working_env, mock_executable, mutable_mock_repo): - """Test invoking 'spack external find --all' with no additional arguments + mutable_config, working_env, mock_executable, mutable_mock_repo, + _platform_executables): + """Test invoking 'spack external find' with no additional arguments, which iterates through each package in the repository. """ - exe_path1 = mock_executable( "find-externals1-exe", output="echo find-externals1 version 1.foo" ) prefix = os.path.dirname(os.path.dirname(exe_path1)) - - os.environ['PATH'] = ':'.join([os.path.dirname(exe_path1)]) + os.environ['PATH'] = os.pathsep.join([os.path.dirname(exe_path1)]) external('find', '--all') pkgs_cfg = spack.config.get('packages') @@ -186,14 +204,13 @@ def test_find_external_merge(mutable_config, mutable_mock_repo): 'prefix': '/x/y2/'} in pkg_externals -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_list_detectable_packages(mutable_config, mutable_mock_repo): external("list") assert external.returncode == 0 -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") -def test_packages_yaml_format(mock_executable, mutable_config, monkeypatch): +def test_packages_yaml_format( + mock_executable, mutable_config, monkeypatch, _platform_executables): # Prepare an environment to detect a fake gcc gcc_exe = mock_executable('gcc', output="echo 4.2.1") prefix = os.path.dirname(gcc_exe) @@ -217,8 +234,8 @@ def test_packages_yaml_format(mock_executable, mutable_config, monkeypatch): assert extra_attributes['compilers']['c'] == gcc_exe -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") -def test_overriding_prefix(mock_executable, mutable_config, monkeypatch): +def test_overriding_prefix( + mock_executable, mutable_config, monkeypatch, _platform_executables): # Prepare an environment to detect a fake gcc that # override its external prefix gcc_exe = mock_executable('gcc', output="echo 4.2.1") @@ -247,9 +264,8 @@ def _determine_variants(cls, exes, version_str): assert externals[0]['prefix'] == '/opt/gcc/bin' -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_new_entries_are_reported_correctly( - mock_executable, mutable_config, monkeypatch + mock_executable, mutable_config, monkeypatch, _platform_executables ): # Prepare an environment to detect a fake gcc gcc_exe = mock_executable('gcc', output="echo 4.2.1") @@ -266,7 +282,6 @@ def test_new_entries_are_reported_correctly( assert 'No new external packages detected' in output -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") @pytest.mark.parametrize('command_args', [ ('-t', 'build-tools'), ('-t', 'build-tools', 'cmake'), diff --git a/lib/spack/spack/test/cmd/fetch.py b/lib/spack/spack/test/cmd/fetch.py index 323fd06cd2..da56fbd528 100644 --- a/lib/spack/spack/test/cmd/fetch.py +++ b/lib/spack/spack/test/cmd/fetch.py @@ -3,18 +3,15 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import sys - import pytest import spack.environment as ev from spack.main import SpackCommand, SpackCommandError # everything here uses the mock_env_path -pytestmark = [pytest.mark.usefixtures( - "mutable_mock_env_path", "config", "mutable_mock_repo"), - pytest.mark.skipif(sys.platform == "win32", - reason="does not run on windows")] +pytestmark = pytest.mark.usefixtures( + "mutable_mock_env_path", "config", "mutable_mock_repo" +) @pytest.mark.disable_clean_stage_check diff --git a/lib/spack/spack/test/cmd/info.py b/lib/spack/spack/test/cmd/info.py index dada99d1dd..9d240628b4 100644 --- a/lib/spack/spack/test/cmd/info.py +++ b/lib/spack/spack/test/cmd/info.py @@ -13,6 +13,9 @@ info = SpackCommand('info') +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="Not yet implemented on Windows") + @pytest.fixture(scope='module') def parser(): @@ -37,7 +40,6 @@ def _print(*args): monkeypatch.setattr(spack.cmd.info.color, 'cprint', _print, raising=False) -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") @pytest.mark.parametrize('pkg', [ 'openmpi', 'trilinos', @@ -50,7 +52,6 @@ def test_it_just_runs(pkg): info(pkg) -@pytest.mark.skipif(sys.platform == 'win32', reason="Not yet implemented on windows") def test_info_noversion(mock_packages, info_lines, mock_print): """Check that a mock package with no versions or variants outputs None.""" info('noversion') @@ -83,7 +84,6 @@ def test_is_externally_detectable(pkg_query, expected, parser, info_lines): assert is_externally_detectable == expected -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") @pytest.mark.parametrize('pkg_query', [ 'hdf5', 'cloverleaf3d', diff --git a/lib/spack/spack/test/cmd/is_git_repo.py b/lib/spack/spack/test/cmd/is_git_repo.py index 7cb0dc2694..025d04fff0 100644 --- a/lib/spack/spack/test/cmd/is_git_repo.py +++ b/lib/spack/spack/test/cmd/is_git_repo.py @@ -45,6 +45,10 @@ def git_tmp_worktree(tmpdir): """Create new worktree in a temporary folder and monkeypatch spack.paths.prefix to point to it. """ + # TODO: This is fragile and should be high priority for + # follow up fixes. 27021 + # Path length is occasionally too long on Windows + # the following reduces the path length to acceptable levels if sys.platform == 'win32': long_pth = str(tmpdir).split(os.path.sep) tmp_worktree = os.path.sep.join(long_pth[:-1]) diff --git a/lib/spack/spack/test/cmd/list.py b/lib/spack/spack/test/cmd/list.py index 42253eb354..fe86a7f3b7 100644 --- a/lib/spack/spack/test/cmd/list.py +++ b/lib/spack/spack/test/cmd/list.py @@ -3,23 +3,17 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import sys - -import pytest - from spack.main import SpackCommand list = SpackCommand('list') -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_list(): output = list() assert 'cloverleaf3d' in output assert 'hdf5' in output -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_list_filter(mock_packages): output = list('py-*') assert 'py-extension1' in output @@ -36,20 +30,17 @@ def test_list_filter(mock_packages): assert 'mpich' not in output -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_list_search_description(mock_packages): output = list('--search-description', 'one build dependency') assert 'depb' in output -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_list_format_name_only(mock_packages): output = list('--format', 'name_only') assert 'zmpi' in output assert 'hdf5' in output -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_list_format_version_json(mock_packages): output = list('--format', 'version_json') assert '{"name": "zmpi",' in output @@ -58,7 +49,6 @@ def test_list_format_version_json(mock_packages): json.loads(output) -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_list_format_html(mock_packages): output = list('--format', 'html') assert '
' in output diff --git a/lib/spack/spack/test/cmd/mirror.py b/lib/spack/spack/test/cmd/mirror.py index 317febdd7b..0027b4ae2b 100644 --- a/lib/spack/spack/test/cmd/mirror.py +++ b/lib/spack/spack/test/cmd/mirror.py @@ -43,6 +43,15 @@ def tmp_scope(): yield scope_name +def _validate_url(url): + return + + +@pytest.fixture(autouse=True) +def url_check(monkeypatch): + monkeypatch.setattr(spack.util.url, 'require_url_format', _validate_url) + + @pytest.mark.disable_clean_stage_check @pytest.mark.regression('8083') def test_regression_8083(tmpdir, capfd, mock_packages, mock_fetch, config): diff --git a/lib/spack/spack/test/cmd/pkg.py b/lib/spack/spack/test/cmd/pkg.py index 1924fbccb8..7f681ad9b9 100644 --- a/lib/spack/spack/test/cmd/pkg.py +++ b/lib/spack/spack/test/cmd/pkg.py @@ -105,7 +105,6 @@ def split(output): pkg = spack.main.SpackCommand('pkg') -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") def test_packages_path(): assert (spack.cmd.pkg.packages_path() == spack.repo.path.get_repo('builtin').packages_path) @@ -139,6 +138,7 @@ def test_pkg_add(mock_pkg_git_repo): pkg('add', 'does-not-exist') +@pytest.mark.skipif(sys.platform == 'win32', reason="stdout format conflict") def test_pkg_list(mock_pkg_git_repo, mock_pkg_names): out = split(pkg('list', 'HEAD^^')) assert sorted(mock_pkg_names) == sorted(out) @@ -156,6 +156,7 @@ def test_pkg_list(mock_pkg_git_repo, mock_pkg_names): assert sorted(mock_pkg_names) == sorted(out) +@pytest.mark.skipif(sys.platform == 'win32', reason="stdout format conflict") def test_pkg_diff(mock_pkg_git_repo, mock_pkg_names): out = split(pkg('diff', 'HEAD^^', 'HEAD^')) assert out == ['HEAD^:', 'pkg-a', 'pkg-b', 'pkg-c'] @@ -167,20 +168,22 @@ def test_pkg_diff(mock_pkg_git_repo, mock_pkg_names): assert out == ['HEAD^:', 'pkg-c', 'HEAD:', 'pkg-d'] +@pytest.mark.skipif(sys.platform == 'win32', reason="stdout format conflict") def test_pkg_added(mock_pkg_git_repo): out = split(pkg('added', 'HEAD^^', 'HEAD^')) - assert out == ['pkg-a', 'pkg-b', 'pkg-c'] + assert ['pkg-a', 'pkg-b', 'pkg-c'] == out out = split(pkg('added', 'HEAD^^', 'HEAD')) - assert out == ['pkg-a', 'pkg-b', 'pkg-d'] + assert ['pkg-a', 'pkg-b', 'pkg-d'] == out out = split(pkg('added', 'HEAD^', 'HEAD')) - assert out == ['pkg-d'] + assert ['pkg-d'] == out out = split(pkg('added', 'HEAD', 'HEAD')) assert out == [] +@pytest.mark.skipif(sys.platform == 'win32', reason="stdout format conflict") def test_pkg_removed(mock_pkg_git_repo): out = split(pkg('removed', 'HEAD^^', 'HEAD^')) assert out == [] @@ -192,7 +195,7 @@ def test_pkg_removed(mock_pkg_git_repo): assert out == ['pkg-c'] -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") +@pytest.mark.skipif(sys.platform == 'win32', reason="stdout format conflict") def test_pkg_changed(mock_pkg_git_repo): out = split(pkg('changed', 'HEAD^^', 'HEAD^')) assert out == [] diff --git a/lib/spack/spack/test/cmd/providers.py b/lib/spack/spack/test/cmd/providers.py index cc6b3068ed..44d56ca1a1 100644 --- a/lib/spack/spack/test/cmd/providers.py +++ b/lib/spack/spack/test/cmd/providers.py @@ -12,8 +12,10 @@ providers = SpackCommand('providers') +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="Providers not currently supported on Windows") + -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") @pytest.mark.parametrize('pkg', [ ('mpi',), ('mpi@2',), @@ -24,7 +26,6 @@ def test_it_just_runs(pkg): providers(*pkg) -@pytest.mark.skipif(sys.platform == 'win32', reason="Error on Win") @pytest.mark.parametrize('vpkg,provider_list', [ (('mpi',), ['intel-mpi', 'intel-parallel-studio', diff --git a/lib/spack/spack/test/cmd/resource.py b/lib/spack/spack/test/cmd/resource.py index 04e7e0e325..64a79fd601 100644 --- a/lib/spack/spack/test/cmd/resource.py +++ b/lib/spack/spack/test/cmd/resource.py @@ -2,12 +2,12 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os import sys -import pytest - from spack.main import SpackCommand +is_windows = sys.platform == 'win32' resource = SpackCommand('resource') #: these are hashes used in mock packages @@ -22,11 +22,17 @@ '208fcfb50e5a965d5757d151b675ca4af4ce2dfd56401721b6168fae60ab798f', 'bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c', '7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730', +] if not is_windows else [ + 'abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234', + '1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd', + 'd0df7988457ec999c148a4a2af25ce831bfaad13954ba18a4446374cb0aef55e', + 'aeb16c4dec1087e39f2330542d59d9b456dd26d791338ae6d80b6ffd10c89dfa', + 'mid21234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234', + 'ff34cb21271d16dbf928374f610bb5dd593d293d311036ddae86c4846ff79070', + 'bf874c7dd3a83cf370fdc17e496e341de06cd596b5c66dbf3c9bb7f6c139e3ee', + '3c5b65abcd6a3b2c714dbf7c31ff65fe3748a1adc371f030c283007ca5534f11' ] -pytestmark = pytest.mark.skipif(sys.platform == "win32", - reason="does not run on windows") - def test_resource_list(mock_packages, capfd): with capfd.disabled(): @@ -40,7 +46,8 @@ def test_resource_list(mock_packages, capfd): assert 'patched by:' in out assert 'path:' in out - assert 'repos/builtin.mock/packages/patch-a-dependency/libelf.patch' in out + assert os.path.join('repos', 'builtin.mock', 'packages', + 'patch-a-dependency', 'libelf.patch') in out assert 'applies to: builtin.mock.libelf' in out assert 'patched by: builtin.mock.patch-a-dependency' in out @@ -54,11 +61,19 @@ def test_resource_list_only_hashes(mock_packages, capfd): def test_resource_show(mock_packages, capfd): + test_hash = 'c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8' \ + if not is_windows \ + else '3c5b65abcd6a3b2c714dbf7c31ff65fe3748a1adc371f030c283007ca5534f11' with capfd.disabled(): - out = resource('show', 'c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8') + out = resource('show', test_hash) - assert out.startswith('c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8') - assert 'repos/builtin.mock/packages/patch-a-dependency/libelf.patch' in out + assert out.startswith(test_hash) + assert os.path.join( + 'repos', + 'builtin.mock', + 'packages', + 'patch-a-dependency', + 'libelf.patch') in out assert 'applies to: builtin.mock.libelf' in out assert 'patched by: builtin.mock.patch-a-dependency' in out diff --git a/lib/spack/spack/test/cmd/test.py b/lib/spack/spack/test/cmd/test.py index ad631db899..0f8e707376 100644 --- a/lib/spack/spack/test/cmd/test.py +++ b/lib/spack/spack/test/cmd/test.py @@ -234,7 +234,7 @@ def test_test_list( reason="Not supported on Windows (yet)") def test_has_test_method_fails(capsys): with pytest.raises(SystemExit): - has_test_method('printing-package') + spack.package.has_test_method('printing-package') captured = capsys.readouterr()[1] assert 'is not a class' in captured diff --git a/lib/spack/spack/test/cmd/uninstall.py b/lib/spack/spack/test/cmd/uninstall.py index 0ce3a260e6..857f1ae35d 100644 --- a/lib/spack/spack/test/cmd/uninstall.py +++ b/lib/spack/spack/test/cmd/uninstall.py @@ -13,9 +13,6 @@ uninstall = SpackCommand('uninstall') install = SpackCommand('install') -# pytestmark = pytest.mark.skipif(sys.platform == "win32", -# reason="does not run on windows") - class MockArgs(object): diff --git a/lib/spack/spack/test/cmd_extensions.py b/lib/spack/spack/test/cmd_extensions.py index d7e0538ce1..dbe79e603a 100644 --- a/lib/spack/spack/test/cmd_extensions.py +++ b/lib/spack/spack/test/cmd_extensions.py @@ -14,6 +14,8 @@ import spack.extensions import spack.main +is_windows = sys.platform == 'win32' + class Extension: """Helper class to simplify the creation of simple command extension @@ -259,12 +261,14 @@ def test_get_command_paths(config): def test_variable_in_extension_path(config, working_env): """Test variables in extension paths.""" - os.environ['_MY_VAR'] = "my/var" + os.environ['_MY_VAR'] = os.path.join('my', 'var') ext_paths = [ os.path.join("~", "${_MY_VAR}", "spack-extension-1") ] + # Home env variable is USERPROFILE on Windows + home_env = 'USERPROFILE' if is_windows else 'HOME' expected_ext_paths = [ - os.path.join(os.environ['HOME'], os.environ['_MY_VAR'], "spack-extension-1") + os.path.join(os.environ[home_env], os.environ['_MY_VAR'], "spack-extension-1") ] with spack.config.override('config:extensions', ext_paths): assert spack.extensions.get_extension_paths() == expected_ext_paths diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 73da1ccbab..f47dc58073 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -2,6 +2,7 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os import sys import jinja2 @@ -22,8 +23,7 @@ from spack.util.mock_package import MockPackageMultiRepo from spack.version import ver -pytestmark = pytest.mark.skipif(sys.platform == "win32", - reason="does not run on windows") +is_windows = sys.platform == 'win32' def check_spec(abstract, concrete): @@ -370,6 +370,7 @@ def test_concretize_two_virtuals_with_dual_provider_and_a_conflict( with pytest.raises(spack.error.SpackError): s.concretize() + @pytest.mark.skipif(sys.platform == 'win32', reason='No Compiler for Arch on Win') def test_no_matching_compiler_specs(self, mock_low_high_config): # only relevant when not building compilers as needed with spack.concretize.enable_compiler_existence_check(): @@ -435,15 +436,17 @@ def test_compiler_inheritance(self, compiler_str): def test_external_package(self): spec = Spec('externaltool%gcc') spec.concretize() - assert spec['externaltool'].external_path == '/path/to/external_tool' + assert spec['externaltool'].external_path == \ + os.path.sep + os.path.join('path', 'to', 'external_tool') assert 'externalprereq' not in spec assert spec['externaltool'].compiler.satisfies('gcc') def test_external_package_module(self): # No tcl modules on darwin/linux machines + # and Windows does not (currently) allow for bash calls # TODO: improved way to check for this. platform = spack.platforms.real_host().name - if platform == 'darwin' or platform == 'linux': + if platform == 'darwin' or platform == 'linux' or platform == 'windows': return spec = Spec('externalmodule') @@ -463,8 +466,10 @@ def test_nobuild_package(self): def test_external_and_virtual(self): spec = Spec('externaltest') spec.concretize() - assert spec['externaltool'].external_path == '/path/to/external_tool' - assert spec['stuff'].external_path == '/path/to/external_virtual_gcc' + assert spec['externaltool'].external_path == \ + os.path.sep + os.path.join('path', 'to', 'external_tool') + assert spec['stuff'].external_path == \ + os.path.sep + os.path.join('path', 'to', 'external_virtual_gcc') assert spec['externaltool'].compiler.satisfies('gcc') assert spec['stuff'].compiler.satisfies('gcc') @@ -707,6 +712,8 @@ def test_noversion_pkg(self, spec): with pytest.raises(spack.error.SpackError): Spec(spec).concretized() + @pytest.mark.skipif(sys.platform == 'win32', + reason="Not supported on Windows (yet)") # Include targets to prevent regression on 20537 @pytest.mark.parametrize('spec, best_achievable', [ ('mpileaks%gcc@4.4.7 ^dyninst@10.2.1 target=x86_64:', 'core2'), @@ -1116,7 +1123,7 @@ def test_custom_compiler_version(self): assert '%gcc@foo' in s def test_all_patches_applied(self): - uuidpatch = 'a60a42b73e03f207433c5579de207c6ed61d58e4d12dd3b5142eb525728d89ea' + uuidpatch = 'a60a42b73e03f207433c5579de207c6ed61d58e4d12dd3b5142eb525728d89ea' if not is_windows else 'd0df7988457ec999c148a4a2af25ce831bfaad13954ba18a4446374cb0aef55e' localpatch = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' spec = spack.spec.Spec('conditionally-patch-dependency+jasper') spec.concretize() diff --git a/lib/spack/spack/test/concretize_preferences.py b/lib/spack/spack/test/concretize_preferences.py index 75aa3e813c..525bd0701f 100644 --- a/lib/spack/spack/test/concretize_preferences.py +++ b/lib/spack/spack/test/concretize_preferences.py @@ -5,7 +5,6 @@ import os import stat -import sys import pytest diff --git a/lib/spack/spack/test/config.py b/lib/spack/spack/test/config.py index 1ab9c48eaa..a765582a2b 100644 --- a/lib/spack/spack/test/config.py +++ b/lib/spack/spack/test/config.py @@ -92,6 +92,13 @@ def env_yaml(tmpdir): return env_yaml +def cross_plat_join(*pths): + """os.path.join does not prepend paths to other paths + beginning with a Windows drive label i.e. D:\\ + """ + return os.sep.join([pth for pth in pths]) + + def check_compiler_config(comps, *compiler_names): """Check that named compilers in comps match Spack's config.""" config = spack.config.get('compilers') @@ -334,65 +341,66 @@ def __init__(self, path): self.path = path -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_substitute_config_variables(mock_low_high_config, monkeypatch): prefix = spack.paths.prefix.lstrip('/') - - assert os.path.join( - '/foo/bar/baz', prefix + assert cross_plat_join( + os.sep + os.path.join('foo', 'bar', 'baz'), prefix ) == spack_path.canonicalize_path('/foo/bar/baz/$spack') - assert os.path.join( - spack.paths.prefix, 'foo/bar/baz' + assert cross_plat_join( + spack.paths.prefix, os.path.join('foo', 'bar', 'baz') ) == spack_path.canonicalize_path('$spack/foo/bar/baz/') - assert os.path.join( - '/foo/bar/baz', prefix, 'foo/bar/baz' + assert cross_plat_join( + os.sep + os.path.join('foo', 'bar', 'baz'), + prefix, os.path.join('foo', 'bar', 'baz') ) == spack_path.canonicalize_path('/foo/bar/baz/$spack/foo/bar/baz/') - assert os.path.join( - '/foo/bar/baz', prefix + assert cross_plat_join( + os.sep + os.path.join('foo', 'bar', 'baz'), prefix ) == spack_path.canonicalize_path('/foo/bar/baz/${spack}') - assert os.path.join( - spack.paths.prefix, 'foo/bar/baz' + assert cross_plat_join( + spack.paths.prefix, os.path.join('foo', 'bar', 'baz') ) == spack_path.canonicalize_path('${spack}/foo/bar/baz/') - assert os.path.join( - '/foo/bar/baz', prefix, 'foo/bar/baz' + assert cross_plat_join( + os.sep + os.path.join('foo', 'bar', 'baz'), + prefix, os.path.join('foo', 'bar', 'baz') ) == spack_path.canonicalize_path('/foo/bar/baz/${spack}/foo/bar/baz/') - assert os.path.join( - '/foo/bar/baz', prefix, 'foo/bar/baz' + assert cross_plat_join( + os.sep + os.path.join('foo', 'bar', 'baz'), + prefix, os.path.join('foo', 'bar', 'baz') ) != spack_path.canonicalize_path('/foo/bar/baz/${spack/foo/bar/baz/') # $env replacement is a no-op when no environment is active assert spack_path.canonicalize_path( - '/foo/bar/baz/$env' - ) == '/foo/bar/baz/$env' + os.sep + os.path.join('foo', 'bar', 'baz', '$env') + ) == os.sep + os.path.join('foo', 'bar', 'baz', '$env') # Fake an active environment and $env is replaced properly - fake_env_path = '/quux/quuux' + fake_env_path = os.sep + os.path.join('quux', 'quuux') monkeypatch.setattr(ev, 'active_environment', lambda: MockEnv(fake_env_path)) assert spack_path.canonicalize_path( '$env/foo/bar/baz' - ) == os.path.join(fake_env_path, 'foo/bar/baz') + ) == os.path.join(fake_env_path, os.path.join('foo', 'bar', 'baz')) # relative paths without source information are relative to cwd assert spack_path.canonicalize_path( - 'foo/bar/baz' - ) == os.path.abspath('foo/bar/baz') + os.path.join('foo', 'bar', 'baz') + ) == os.path.abspath(os.path.join('foo', 'bar', 'baz')) # relative paths with source information are relative to the file spack.config.set( - 'modules:default', {'roots': {'lmod': 'foo/bar/baz'}}, scope='low') + 'modules:default', + {'roots': {'lmod': os.path.join('foo', 'bar', 'baz')}}, scope='low') spack.config.config.clear_caches() path = spack.config.get('modules:default:roots:lmod') assert spack_path.canonicalize_path(path) == os.path.normpath( os.path.join(mock_low_high_config.scopes['low'].path, - 'foo/bar/baz')) + os.path.join('foo', 'bar', 'baz'))) packages_merge_low = { @@ -439,41 +447,29 @@ def test_merge_with_defaults(mock_low_high_config, write_config_file): assert cfg['baz']['version'] == ['c'] -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_substitute_user(mock_low_high_config): user = getpass.getuser() - assert '/foo/bar/' + user + '/baz' == spack_path.canonicalize_path( - '/foo/bar/$user/baz' + assert os.sep + os.path.join('foo', 'bar') + os.sep \ + + user + os.sep \ + + 'baz' == spack_path.canonicalize_path( + os.sep + os.path.join('foo', 'bar', '$user', 'baz') ) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") -def test_substitute_user_config(mock_low_high_config): - user_config_path = spack.paths.user_config_path - assert user_config_path + '/baz' == spack_path.canonicalize_path( - '$user_cache_path/baz' - ) - - -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_substitute_user_cache(mock_low_high_config): user_cache_path = spack.paths.user_cache_path - assert user_cache_path + '/baz' == spack_path.canonicalize_path( - '$user_cache_path/baz' + assert user_cache_path + os.sep + 'baz' == spack_path.canonicalize_path( + os.path.join('$user_cache_path', 'baz') ) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_substitute_tempdir(mock_low_high_config): tempdir = tempfile.gettempdir() assert tempdir == spack_path.canonicalize_path('$tempdir') - assert tempdir + '/foo/bar/baz' == spack_path.canonicalize_path( - '$tempdir/foo/bar/baz' - ) + assert tempdir + os.sep + \ + os.path.join('foo', 'bar', 'baz') == spack_path.canonicalize_path( + os.path.join('$tempdir', 'foo', 'bar', 'baz') + ) PAD_STRING = spack.util.path.SPACK_PATH_PADDING_CHARS @@ -481,34 +477,17 @@ def test_substitute_tempdir(mock_low_high_config): MAX_PADDED_LEN = MAX_PATH_LEN - spack.util.path.SPACK_MAX_INSTALL_PATH_LENGTH reps = [PAD_STRING for _ in range((MAX_PADDED_LEN // len(PAD_STRING) + 1) + 2)] full_padded_string = os.path.join( - '/path', os.path.sep.join(reps))[:MAX_PADDED_LEN] + os.sep + 'path', os.sep.join(reps))[:MAX_PADDED_LEN] -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('config_settings,expected', [ ([], [None, None, None]), - ([['config:install_tree:root', '/path']], ['/path', None, None]), - ([['config:install_tree', '/path']], ['/path', None, None]), + ([['config:install_tree:root', os.sep + 'path']], [os.sep + 'path', None, None]), + ([['config:install_tree', os.sep + 'path']], [os.sep + 'path', None, None]), ([['config:install_tree:projections', {'all': '{name}'}]], [None, None, {'all': '{name}'}]), ([['config:install_path_scheme', '{name}']], [None, None, {'all': '{name}'}]), - ([['config:install_tree:root', '/path'], - ['config:install_tree:padded_length', 11]], - [os.path.join('/path', PAD_STRING[:5]), '/path', None]), - ([['config:install_tree:root', '/path/$padding:11']], - [os.path.join('/path', PAD_STRING[:5]), '/path', None]), - ([['config:install_tree', '/path/${padding:11}']], - [os.path.join('/path', PAD_STRING[:5]), '/path', None]), - ([['config:install_tree:padded_length', False]], [None, None, None]), - ([['config:install_tree:padded_length', True], - ['config:install_tree:root', '/path']], - [full_padded_string, '/path', None]), - ([['config:install_tree:', '/path$padding']], - [full_padded_string, '/path', None]), - ([['config:install_tree:', '/path/${padding}']], - [full_padded_string, '/path', None]), ]) def test_parse_install_tree(config_settings, expected, mutable_config): expected_root = expected[0] or spack.store.default_install_tree_root @@ -524,7 +503,44 @@ def test_parse_install_tree(config_settings, expected, mutable_config): config_dict = mutable_config.get('config') root, unpadded_root, projections = spack.store.parse_install_tree( config_dict) + assert root == expected_root + assert unpadded_root == expected_unpadded_root + assert projections == expected_proj + +@pytest.mark.skipif(sys.platform == 'win32', + reason='Padding unsupported on Windows') +@pytest.mark.parametrize('config_settings,expected', [ + ([['config:install_tree:root', os.sep + 'path'], + ['config:install_tree:padded_length', 11]], + [os.path.join(os.sep + 'path', PAD_STRING[:5]), os.sep + 'path', None]), + ([['config:install_tree:root', '/path/$padding:11']], + [os.path.join(os.sep + 'path', PAD_STRING[:5]), os.sep + 'path', None]), + ([['config:install_tree', '/path/${padding:11}']], + [os.path.join(os.sep + 'path', PAD_STRING[:5]), os.sep + 'path', None]), + ([['config:install_tree:padded_length', False]], [None, None, None]), + ([['config:install_tree:padded_length', True], + ['config:install_tree:root', os.sep + 'path']], + [full_padded_string, os.sep + 'path', None]), + ([['config:install_tree:', os.sep + 'path$padding']], + [full_padded_string, os.sep + 'path', None]), + ([['config:install_tree:', os.sep + 'path' + os.sep + '${padding}']], + [full_padded_string, os.sep + 'path', None]), +]) +def test_parse_install_tree_padded(config_settings, expected, mutable_config): + expected_root = expected[0] or spack.store.default_install_tree_root + expected_unpadded_root = expected[1] or expected_root + expected_proj = expected[2] or spack.directory_layout.default_projections + + # config settings is a list of 2-element lists, [path, value] + # where path is a config path and value is the value to set at that path + # these can be "splatted" in as the arguments to config.set + for config_setting in config_settings: + mutable_config.set(*config_setting) + + config_dict = mutable_config.get('config') + root, unpadded_root, projections = spack.store.parse_install_tree( + config_dict) assert root == expected_root assert unpadded_root == expected_unpadded_root assert projections == expected_proj @@ -1217,7 +1233,8 @@ def test_system_config_path_is_overridable(working_env): def test_system_config_path_is_default_when_env_var_is_empty(working_env): os.environ['SPACK_SYSTEM_CONFIG_PATH'] = '' - assert "/etc/spack" == spack.paths._get_system_config_path() + assert os.sep + os.path.join('etc', 'spack') == \ + spack.paths._get_system_config_path() def test_user_config_path_is_overridable(working_env): @@ -1228,7 +1245,8 @@ def test_user_config_path_is_overridable(working_env): def test_user_config_path_is_default_when_env_var_is_empty(working_env): os.environ['SPACK_USER_CONFIG_PATH'] = '' - assert os.path.expanduser("~/.spack") == spack.paths._get_user_config_path() + assert os.path.expanduser("~%s.spack" % os.sep) == \ + spack.paths._get_user_config_path() def test_local_config_can_be_disabled(working_env): @@ -1262,4 +1280,5 @@ def test_user_cache_path_is_overridable(working_env): def test_user_cache_path_is_default_when_env_var_is_empty(working_env): os.environ['SPACK_USER_CACHE_PATH'] = '' - assert os.path.expanduser("~/.spack") == spack.paths._get_user_cache_path() + assert os.path.expanduser("~%s.spack" % os.sep) == \ + spack.paths._get_user_cache_path() diff --git a/lib/spack/spack/test/conftest.py b/lib/spack/spack/test/conftest.py index 3d9acf4594..c946898076 100644 --- a/lib/spack/spack/test/conftest.py +++ b/lib/spack/spack/test/conftest.py @@ -13,6 +13,7 @@ import os.path import re import shutil +import stat import sys import tempfile import xml.etree.ElementTree @@ -297,6 +298,14 @@ def reset_compiler_cache(): spack.compilers._compiler_cache = {} +def onerror(func, path, error_info): + # Python on Windows is unable to remvove paths without + # write (IWUSR) permissions (such as those generated by Git on Windows) + # This method changes file permissions to allow removal by Python + os.chmod(path, stat.S_IWUSR) + func(path) + + @pytest.fixture(scope='function', autouse=True) def mock_stage(tmpdir_factory, monkeypatch, request): """Establish the temporary build_stage for the mock archive.""" @@ -320,7 +329,7 @@ def mock_stage(tmpdir_factory, monkeypatch, request): # Clean up the test stage directory if os.path.isdir(new_stage_path): - shutil.rmtree(new_stage_path) + shutil.rmtree(new_stage_path, onerror=onerror) else: # Must yield a path to avoid a TypeError on test teardown yield str(tmpdir_factory) @@ -343,7 +352,7 @@ def remove_whatever_it_is(path): elif os.path.islink(path): remove_linked_tree(path) else: - shutil.rmtree(path) + shutil.rmtree(path, onerror=onerror) @pytest.fixture @@ -902,7 +911,7 @@ def __init__(self, root): self.root = root def path_for_spec(self, spec): - return '/'.join([self.root, spec.name + '-' + spec.dag_hash()]) + return os.path.sep.join([self.root, spec.name + '-' + spec.dag_hash()]) def ensure_installed(self, spec): pass @@ -1048,10 +1057,7 @@ def mock_archive(request, tmpdir_factory): ['url', 'path', 'archive_file', 'expanded_archive_basedir']) archive_file = str(tmpdir.join(archive_name)) - if sys.platform == 'win32': - url = ('file:///' + archive_file) - else: - url = ('file://' + archive_file) + url = ('file://' + archive_file) # Return the url yield Archive( @@ -1540,11 +1546,14 @@ def mock_executable(tmpdir): output a custom string when run. """ import jinja2 + shebang = '#!/bin/bash\n' if not is_windows else '@ECHO OFF' def _factory(name, output, subdir=('bin',)): f = tmpdir.ensure(*subdir, dir=True).join(name) - t = jinja2.Template('#!/bin/bash\n{{ output }}\n') - f.write(t.render(output=output)) + if is_windows: + f += '.bat' + t = jinja2.Template('{{ shebang }}{{ output }}\n') + f.write(t.render(shebang=shebang, output=output)) f.chmod(0o755) return str(f) diff --git a/lib/spack/spack/test/database.py b/lib/spack/spack/test/database.py index a695b8d852..4278aeb4f0 100644 --- a/lib/spack/spack/test/database.py +++ b/lib/spack/spack/test/database.py @@ -65,7 +65,7 @@ def upstream_and_downstream_db(tmpdir_factory, gen_mock_layout): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Upstreams currently unsupported on Windows") @pytest.mark.usefixtures('config') def test_installed_upstream(upstream_and_downstream_db): upstream_write_db, upstream_db, upstream_layout,\ @@ -110,7 +110,7 @@ def test_installed_upstream(upstream_and_downstream_db): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Upstreams currently unsupported on Windows") @pytest.mark.usefixtures('config') def test_removed_upstream_dep(upstream_and_downstream_db): upstream_write_db, upstream_db, upstream_layout,\ @@ -143,7 +143,7 @@ def test_removed_upstream_dep(upstream_and_downstream_db): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Upstreams currently unsupported on Windows") @pytest.mark.usefixtures('config') def test_add_to_upstream_after_downstream(upstream_and_downstream_db): """An upstream DB can add a package after it is installed in the downstream @@ -182,7 +182,7 @@ def test_add_to_upstream_after_downstream(upstream_and_downstream_db): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Upstreams currently unsupported on Windows") @pytest.mark.usefixtures('config', 'temporary_store') def test_cannot_write_upstream(tmpdir_factory, gen_mock_layout): roots = [str(tmpdir_factory.mktemp(x)) for x in ['a', 'b']] @@ -209,7 +209,7 @@ def test_cannot_write_upstream(tmpdir_factory, gen_mock_layout): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Upstreams currently unsupported on Windows") @pytest.mark.usefixtures('config', 'temporary_store') def test_recursive_upstream_dbs(tmpdir_factory, gen_mock_layout): roots = [str(tmpdir_factory.mktemp(x)) for x in ['a', 'b', 'c']] @@ -687,8 +687,6 @@ def fail_while_writing(): # reload DB and make sure cmake was not written. with database.read_transaction(): - # import pdb; pdb.set_trace() - assert database.query('cmake', installed=any) == [] diff --git a/lib/spack/spack/test/directory_layout.py b/lib/spack/spack/test/directory_layout.py index 11bf7ed34a..7aa6a565fc 100644 --- a/lib/spack/spack/test/directory_layout.py +++ b/lib/spack/spack/test/directory_layout.py @@ -8,7 +8,6 @@ """ import os import os.path -import sys import pytest @@ -19,13 +18,12 @@ InvalidDirectoryLayoutParametersError, ) from spack.spec import Spec +from spack.util.path import path_to_os_path # number of packages to test (to reduce test time) max_packages = 10 -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_yaml_directory_layout_parameters(tmpdir, config): """This tests the various parameters that can be used to configure the install location """ @@ -81,8 +79,6 @@ def test_yaml_directory_layout_parameters(tmpdir, config): projections=projections_package7) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_read_and_write_spec(temporary_store, config, mock_packages): """This goes through each package in spack and creates a directory for it. It then ensures that the spec for the directory's @@ -108,7 +104,7 @@ def test_read_and_write_spec(temporary_store, config, mock_packages): layout.create_install_directory(spec) - install_dir = layout.path_for_spec(spec) + install_dir = path_to_os_path(layout.path_for_spec(spec))[0] spec_path = layout.spec_file_path(spec) # Ensure directory has been created in right place. @@ -208,8 +204,6 @@ def test_handle_unknown_package(temporary_store, config, mock_packages): assert spec.dag_hash() == spec_from_file.dag_hash() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_find(temporary_store, config, mock_packages): """Test that finding specs within an install layout works.""" layout = temporary_store.layout @@ -233,8 +227,6 @@ def test_find(temporary_store, config, mock_packages): assert found_specs[name].eq_dag(spec) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_yaml_directory_layout_build_path(tmpdir, config): """This tests build path method.""" spec = Spec('python') diff --git a/lib/spack/spack/test/environment_modifications.py b/lib/spack/spack/test/environment_modifications.py index 93e904a378..c76b08fd95 100644 --- a/lib/spack/spack/test/environment_modifications.py +++ b/lib/spack/spack/test/environment_modifications.py @@ -178,6 +178,7 @@ def test_filter_system_paths(miscellaneous_paths): assert filtered == expected +# TODO 27021 @pytest.mark.skipif(sys.platform == 'win32', reason="Not supported on Windows (yet)") def test_set_path(env): @@ -417,8 +418,6 @@ def test_sanitize_regex(env, blacklist, whitelist, expected, deleted): assert all(x not in after for x in deleted) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.regression('12085') @pytest.mark.parametrize('before,after,search_list', [ # Set environment variables @@ -428,8 +427,8 @@ def test_sanitize_regex(env, blacklist, whitelist, expected, deleted): # Append paths to an environment variable ({'FOO_PATH': '/a/path'}, {'FOO_PATH': '/a/path:/b/path'}, [environment.AppendPath('FOO_PATH', '/b/path')]), - ({}, {'FOO_PATH': '/a/path:/b/path'}, [ - environment.AppendPath('FOO_PATH', '/a/path:/b/path') + ({}, {'FOO_PATH': '/a/path' + os.sep + '/b/path'}, [ + environment.AppendPath('FOO_PATH', '/a/path' + os.sep + '/b/path') ]), ({'FOO_PATH': '/a/path:/b/path'}, {'FOO_PATH': '/b/path'}, [ environment.RemovePath('FOO_PATH', '/a/path') @@ -459,7 +458,7 @@ def test_from_environment_diff(before, after, search_list): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="LMod not supported on Windows") @pytest.mark.regression('15775') def test_blacklist_lmod_variables(): # Construct the list of environment modifications diff --git a/lib/spack/spack/test/git_fetch.py b/lib/spack/spack/test/git_fetch.py index af00651592..6e8993978c 100644 --- a/lib/spack/spack/test/git_fetch.py +++ b/lib/spack/spack/test/git_fetch.py @@ -19,6 +19,10 @@ from spack.util.executable import which from spack.version import ver +pytestmark = pytest.mark.skipif( + not which('git'), reason='requires git to be installed') + + _mock_transport_error = 'Mock HTTP transport error' @@ -71,7 +75,6 @@ def bad_git(*args, **kwargs): def test_bad_git(tmpdir, mock_bad_git): """Trigger a SpackError when attempt a fetch with a bad git.""" testpath = str(tmpdir) - print(spack.config.get('config:locks')) with pytest.raises(spack.error.SpackError): fetcher = GitFetchStrategy(git='file:///not-a-real-git-repo') diff --git a/lib/spack/spack/test/install.py b/lib/spack/spack/test/install.py index 9465b5ec0e..00276b379c 100644 --- a/lib/spack/spack/test/install.py +++ b/lib/spack/spack/test/install.py @@ -5,7 +5,6 @@ import os import shutil -import sys import pytest @@ -32,8 +31,6 @@ def find_nothing(*args): 'Repo package access is disabled for test') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_and_uninstall(install_mockery, mock_fetch, monkeypatch): # Get a basic concrete spec for the trivial install package. spec = Spec('trivial-install-test-package') @@ -42,7 +39,6 @@ def test_install_and_uninstall(install_mockery, mock_fetch, monkeypatch): # Get the package pkg = spec.package - try: pkg.do_install() @@ -100,8 +96,6 @@ def __getattr__(self, attr): return getattr(self.wrapped_stage, attr) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch): spec = Spec('canfail').concretized() pkg = spack.repo.get(spec) @@ -131,8 +125,6 @@ def test_partial_install_delete_prefix_and_stage(install_mockery, mock_fetch): pkg.remove_prefix = instance_rm_prefix -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.disable_clean_stage_check def test_failing_overwrite_install_should_keep_previous_installation( mock_fetch, install_mockery @@ -158,8 +150,6 @@ def test_failing_overwrite_install_should_keep_previous_installation( assert os.path.exists(spec.prefix) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_dont_add_patches_to_installed_package( install_mockery, mock_fetch, monkeypatch ): @@ -180,8 +170,6 @@ def test_dont_add_patches_to_installed_package( assert dependent['dependency-install'] == dependency -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_installed_dependency_request_conflicts( install_mockery, mock_fetch, mutable_mock_repo): dependency = Spec('dependency-install') @@ -195,8 +183,6 @@ def test_installed_dependency_request_conflicts( dependent.concretize() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_dependency_symlinks_pkg( install_mockery, mock_fetch, mutable_mock_repo): """Test dependency flattening/symlinks mock package.""" @@ -210,8 +196,6 @@ def test_install_dependency_symlinks_pkg( assert os.path.isdir(dependency_dir) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_times( install_mockery, mock_fetch, mutable_mock_repo): """Test install times added.""" @@ -238,8 +222,6 @@ def test_install_times( assert abs(total - times['total']['seconds']) < 5 -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_flatten_deps( install_mockery, mock_fetch, mutable_mock_repo): """Explicitly test the flattening code for coverage purposes.""" @@ -289,8 +271,6 @@ def _install_upstream(*specs): return _install_upstream -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_installed_upstream_external(install_upstream, mock_fetch): """Check that when a dependency package is recorded as installed in an upstream database that it is not reinstalled. @@ -302,7 +282,8 @@ def test_installed_upstream_external(install_upstream, mock_fetch): new_dependency = dependent['externaltool'] assert new_dependency.external - assert new_dependency.prefix == '/path/to/external_tool' + assert new_dependency.prefix == \ + os.path.sep + os.path.join('path', 'to', 'external_tool') dependent.package.do_install() @@ -310,8 +291,6 @@ def test_installed_upstream_external(install_upstream, mock_fetch): assert os.path.exists(dependent.prefix) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_installed_upstream(install_upstream, mock_fetch): """Check that when a dependency package is recorded as installed in an upstream database that it is not reinstalled. @@ -332,8 +311,6 @@ def test_installed_upstream(install_upstream, mock_fetch): assert os.path.exists(dependent.prefix) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.disable_clean_stage_check def test_partial_install_keep_prefix(install_mockery, mock_fetch, monkeypatch): spec = Spec('canfail').concretized() @@ -360,8 +337,6 @@ def test_partial_install_keep_prefix(install_mockery, mock_fetch, monkeypatch): assert not pkg.stage.test_destroyed -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_second_install_no_overwrite_first(install_mockery, mock_fetch, monkeypatch): spec = Spec('canfail').concretized() pkg = spack.repo.get(spec) @@ -376,8 +351,6 @@ def test_second_install_no_overwrite_first(install_mockery, mock_fetch, monkeypa pkg.do_install() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_prefix_collision_fails(config, mock_fetch, mock_packages, tmpdir): """ Test that different specs with coinciding install prefixes will fail @@ -395,16 +368,12 @@ def test_install_prefix_collision_fails(config, mock_fetch, mock_packages, tmpdi pkg_b.do_install() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Package ninja not found") def test_store(install_mockery, mock_fetch): spec = Spec('cmake-client').concretized() pkg = spec.package pkg.do_install() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.disable_clean_stage_check def test_failing_build(install_mockery, mock_fetch, capfd): spec = Spec('failing-build').concretized() @@ -419,8 +388,6 @@ class MockInstallError(spack.error.SpackError): pass -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_uninstall_by_spec_errors(mutable_database): """Test exceptional cases with the uninstall command.""" @@ -436,8 +403,6 @@ def test_uninstall_by_spec_errors(mutable_database): PackageBase.uninstall_by_spec(rec.spec) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.disable_clean_stage_check def test_nosource_pkg_install( install_mockery, mock_fetch, mock_packages, capfd): @@ -452,8 +417,6 @@ def test_nosource_pkg_install( assert "Missing a source id for nosource" in out[1] -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_nosource_pkg_install_post_install( install_mockery, mock_fetch, mock_packages): """Test install phases with the nosource package with post-install.""" @@ -472,8 +435,6 @@ def test_nosource_pkg_install_post_install( assert os.path.isfile(post_install_txt) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_pkg_build_paths(install_mockery): # Get a basic concrete spec for the trivial install package. spec = Spec('trivial-install-test-package').concretized() @@ -507,8 +468,6 @@ def test_pkg_build_paths(install_mockery): shutil.rmtree(log_dir) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_pkg_install_paths(install_mockery): # Get a basic concrete spec for the trivial install package. spec = Spec('trivial-install-test-package').concretized() @@ -545,8 +504,6 @@ def test_pkg_install_paths(install_mockery): shutil.rmtree(log_dir) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_log_install_without_build_files(install_mockery): """Test the installer log function when no build files are present.""" # Get a basic concrete spec for the trivial install package. @@ -557,8 +514,6 @@ def test_log_install_without_build_files(install_mockery): spack.installer.log(spec.package) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_log_install_with_build_files(install_mockery, monkeypatch): """Test the installer's log function when have build files.""" config_log = 'config.log' diff --git a/lib/spack/spack/test/installer.py b/lib/spack/spack/test/installer.py index 053578f156..a7b0b1edd9 100644 --- a/lib/spack/spack/test/installer.py +++ b/lib/spack/spack/test/installer.py @@ -23,6 +23,8 @@ import spack.store import spack.util.lock as lk +is_windows = sys.platform == 'win32' + def _mock_repo(root, namespace): """Create an empty repository at the specified root @@ -119,8 +121,6 @@ def test_hms(sec, result): assert inst._hms(sec) == result -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_get_dependent_ids(install_mockery, mock_packages): # Concretize the parent package, which handle dependency too spec = spack.spec.Spec('a') @@ -154,8 +154,6 @@ def test_install_msg(monkeypatch): assert inst.install_msg(name, pid) == expected -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_from_cache_errors(install_mockery, capsys): """Test to ensure cover _install_from_cache errors.""" spec = spack.spec.Spec('trivial-install-test-package') @@ -176,8 +174,6 @@ def test_install_from_cache_errors(install_mockery, capsys): assert not spec.package.installed_from_binary_cache -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_from_cache_ok(install_mockery, monkeypatch): """Test to ensure cover _install_from_cache to the return.""" spec = spack.spec.Spec('trivial-install-test-package') @@ -188,8 +184,6 @@ def test_install_from_cache_ok(install_mockery, monkeypatch): assert inst._install_from_cache(spec.package, True, True, False) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_process_external_package_module(install_mockery, monkeypatch, capfd): """Test to simply cover the external module message path.""" spec = spack.spec.Spec('trivial-install-test-package') @@ -218,8 +212,6 @@ def test_process_binary_cache_tarball_none(install_mockery, monkeypatch, assert 'exists in binary cache but' in capfd.readouterr()[0] -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_process_binary_cache_tarball_tar(install_mockery, monkeypatch, capfd): """Tests of _process_binary_cache_tarball with a tar file.""" def _spec(spec, preferred_mirrors=None): @@ -240,8 +232,6 @@ def _spec(spec, preferred_mirrors=None): assert 'from binary cache' in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_try_install_from_binary_cache(install_mockery, mock_packages, monkeypatch): """Test return false when no match exists in the mirror""" @@ -251,8 +241,6 @@ def test_try_install_from_binary_cache(install_mockery, mock_packages, assert(not result) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_installer_repr(install_mockery): const_arg = installer_args(['trivial-install-test-package'], {}) installer = create_installer(const_arg) @@ -263,8 +251,6 @@ def test_installer_repr(install_mockery): assert "failed=" in irep -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_installer_str(install_mockery): const_arg = installer_args(['trivial-install-test-package'], {}) installer = create_installer(const_arg) @@ -298,8 +284,6 @@ def test_check_last_phase_error(install_mockery): assert pkg.last_phase in err -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_installer_ensure_ready_errors(install_mockery): const_arg = installer_args(['trivial-install-test-package'], {}) installer = create_installer(const_arg) @@ -329,8 +313,6 @@ def test_installer_ensure_ready_errors(install_mockery): installer._ensure_install_ready(spec.package) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_ensure_locked_err(install_mockery, monkeypatch, tmpdir, capsys): """Test _ensure_locked when a non-lock exception is raised.""" mock_err_msg = 'Mock exception error' @@ -352,8 +334,6 @@ def _raise(lock, timeout): assert mock_err_msg in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_ensure_locked_have(install_mockery, tmpdir, capsys): """Test _ensure_locked when already have lock.""" const_arg = installer_args(['trivial-install-test-package'], {}) @@ -390,8 +370,6 @@ def test_ensure_locked_have(install_mockery, tmpdir, capsys): assert installer._ensure_locked(lock_type, spec.package) == tpl -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('lock_type,reads,writes', [ ('read', 1, 0), ('write', 0, 1)]) @@ -409,8 +387,6 @@ def test_ensure_locked_new_lock( assert lock._writes == writes -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_ensure_locked_new_warn(install_mockery, monkeypatch, tmpdir, capsys): orig_pl = spack.database.Database.prefix_lock @@ -441,8 +417,6 @@ def test_package_id_err(install_mockery): inst.package_id(pkg) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_package_id_ok(install_mockery): spec = spack.spec.Spec('trivial-install-test-package') spec.concretize() @@ -461,8 +435,6 @@ def test_fake_install(install_mockery): assert os.path.isdir(pkg.prefix.lib) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_packages_needed_to_bootstrap_compiler_none(install_mockery): spec = spack.spec.Spec('trivial-install-test-package') spec.concretize() @@ -473,8 +445,6 @@ def test_packages_needed_to_bootstrap_compiler_none(install_mockery): assert not packages -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_packages_needed_to_bootstrap_compiler_packages(install_mockery, monkeypatch): spec = spack.spec.Spec('trivial-install-test-package') @@ -494,8 +464,6 @@ def _conc_spec(compiler): assert packages -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_dump_packages_deps_ok(install_mockery, tmpdir, mock_packages): """Test happy path for dump_packages with dependencies.""" @@ -508,8 +476,6 @@ def test_dump_packages_deps_ok(install_mockery, tmpdir, mock_packages): assert os.path.isfile(dest_pkg) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_dump_packages_deps_errs(install_mockery, tmpdir, monkeypatch, capsys): """Test error paths for dump_packages with dependencies.""" orig_bpp = spack.store.layout.build_packages_path @@ -538,7 +504,7 @@ def _repoerr(repo, name): # The call to install_tree will raise the exception since not mocking # creation of dependency package files within *install* directories. - with pytest.raises(IOError, match=path): + with pytest.raises(IOError, match=path if not is_windows else ''): inst.dump_packages(spec, path) # Now try the error path, which requires the mock directory structure @@ -631,8 +597,6 @@ def test_combine_phase_logs(tmpdir): assert "Output from %s\n" % log_file in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_check_deps_status_install_failure(install_mockery, monkeypatch): const_arg = installer_args(['a'], {}) installer = create_installer(const_arg) @@ -645,8 +609,6 @@ def test_check_deps_status_install_failure(install_mockery, monkeypatch): installer._check_deps_status(request) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_check_deps_status_write_locked(install_mockery, monkeypatch): const_arg = installer_args(['a'], {}) installer = create_installer(const_arg) @@ -659,8 +621,6 @@ def test_check_deps_status_write_locked(install_mockery, monkeypatch): installer._check_deps_status(request) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_check_deps_status_external(install_mockery, monkeypatch): const_arg = installer_args(['a'], {}) installer = create_installer(const_arg) @@ -672,8 +632,6 @@ def test_check_deps_status_external(install_mockery, monkeypatch): assert list(installer.installed)[0].startswith('b') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_check_deps_status_upstream(install_mockery, monkeypatch): const_arg = installer_args(['a'], {}) installer = create_installer(const_arg) @@ -685,8 +643,6 @@ def test_check_deps_status_upstream(install_mockery, monkeypatch): assert list(installer.installed)[0].startswith('b') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_add_bootstrap_compilers(install_mockery, monkeypatch): from collections import defaultdict @@ -709,8 +665,6 @@ def _pkgs(compiler, architecture, pkgs): assert task.compiler -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_prepare_for_install_on_installed(install_mockery, monkeypatch): """Test of _prepare_for_install's early return for installed task path.""" const_arg = installer_args(['dependent-install'], {}) @@ -725,8 +679,6 @@ def test_prepare_for_install_on_installed(install_mockery, monkeypatch): installer._prepare_for_install(task) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_installer_init_requests(install_mockery): """Test of installer initial requests.""" spec_name = 'dependent-install' @@ -740,8 +692,6 @@ def test_installer_init_requests(install_mockery): assert request.pkg.name == spec_name -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_task_use_cache(install_mockery, monkeypatch): const_arg = installer_args(['trivial-install-test-package'], {}) installer = create_installer(const_arg) @@ -753,8 +703,6 @@ def test_install_task_use_cache(install_mockery, monkeypatch): assert request.pkg_id in installer.installed -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_task_add_compiler(install_mockery, monkeypatch, capfd): config_msg = 'mock add_compilers_to_config' @@ -779,8 +727,6 @@ def _add(_compilers): assert config_msg in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_release_lock_write_n_exception(install_mockery, tmpdir, capsys): """Test _release_lock for supposed write lock with exception.""" const_arg = installer_args(['trivial-install-test-package'], {}) @@ -798,8 +744,6 @@ def test_release_lock_write_n_exception(install_mockery, tmpdir, capsys): assert msg in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('installed', [True, False]) def test_push_task_skip_processed(install_mockery, installed): """Test to ensure skip re-queueing a processed package.""" @@ -819,8 +763,6 @@ def test_push_task_skip_processed(install_mockery, installed): assert len(list(installer.build_tasks)) == 0 -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_requeue_task(install_mockery, capfd): """Test to ensure cover _requeue_task.""" const_arg = installer_args(['a'], {}) @@ -845,8 +787,6 @@ def test_requeue_task(install_mockery, capfd): assert ' in progress by another process' in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_cleanup_all_tasks(install_mockery, monkeypatch): """Test to ensure cover _cleanup_all_tasks.""" def _mktask(pkg): @@ -871,8 +811,6 @@ def _rmtask(installer, pkg_id): assert len(installer.build_tasks) == 1 -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_setup_install_dir_grp(install_mockery, monkeypatch, capfd): """Test _setup_install_dir's group change.""" mock_group = 'mockgroup' @@ -893,6 +831,10 @@ def _chgrp(path, group): fs.touchp(spec.prefix) metadatadir = spack.store.layout.metadata_path(spec) + # Regex matching with Windows style paths typically fails + # so we skip the match check here + if is_windows: + metadatadir = None # Should fail with a "not a directory" error with pytest.raises(OSError, match=metadatadir): installer._setup_install_dir(spec.package) @@ -903,8 +845,6 @@ def _chgrp(path, group): assert expected_msg in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_cleanup_failed_err(install_mockery, tmpdir, monkeypatch, capsys): """Test _cleanup_failed exception path.""" msg = 'Fake release_write exception' @@ -927,8 +867,6 @@ def _raise_except(lock): assert msg in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_update_failed_no_dependent_task(install_mockery): """Test _update_failed with missing dependent build tasks.""" const_arg = installer_args(['dependent-install'], {}) @@ -941,8 +879,6 @@ def test_update_failed_no_dependent_task(install_mockery): assert installer.failed[task.pkg_id] is None -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_uninstalled_deps(install_mockery, monkeypatch, capsys): """Test install with uninstalled dependencies.""" const_arg = installer_args(['dependent-install'], {}) @@ -961,8 +897,6 @@ def test_install_uninstalled_deps(install_mockery, monkeypatch, capsys): assert 'Detected uninstalled dependencies for' in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_failed(install_mockery, monkeypatch, capsys): """Test install with failed install.""" const_arg = installer_args(['b'], {}) @@ -979,8 +913,6 @@ def test_install_failed(install_mockery, monkeypatch, capsys): assert 'failed to install' in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_failed_not_fast(install_mockery, monkeypatch, capsys): """Test install with failed install.""" const_arg = installer_args(['a'], {'fail_fast': False}) @@ -997,8 +929,6 @@ def test_install_failed_not_fast(install_mockery, monkeypatch, capsys): assert 'Skipping build of a' in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_fail_on_interrupt(install_mockery, monkeypatch): """Test ctrl-c interrupted install.""" spec_name = 'a' @@ -1023,8 +953,6 @@ def _interrupt(installer, task, **kwargs): assert spec_name not in installer.installed -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_fail_single(install_mockery, monkeypatch): """Test expected results for failure of single package.""" spec_name = 'a' @@ -1052,8 +980,6 @@ def _install(installer, task, **kwargs): assert spec_name not in installer.installed -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_fail_multi(install_mockery, monkeypatch): """Test expected results for failure of multiple packages.""" spec_name = 'c' @@ -1081,8 +1007,6 @@ def _install(installer, task, **kwargs): assert spec_name not in installer.installed -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_fail_fast_on_detect(install_mockery, monkeypatch, capsys): """Test fail_fast install when an install failure is detected.""" const_arg = installer_args(['b'], {'fail_fast': False}) @@ -1114,8 +1038,6 @@ def _test_install_fail_fast_on_except_patch(installer, **kwargs): raise RuntimeError('mock patch failure') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_fail_fast_on_except(install_mockery, monkeypatch, capsys): """Test fail_fast install when an install failure results from an error.""" const_arg = installer_args(['a'], {'fail_fast': True}) @@ -1138,8 +1060,6 @@ def test_install_fail_fast_on_except(install_mockery, monkeypatch, capsys): assert 'Skipping build of a' in out -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_lock_failures(install_mockery, monkeypatch, capfd): """Cover basic install lock failure handling in a single pass.""" def _requeued(installer, task): @@ -1163,8 +1083,6 @@ def _requeued(installer, task): assert exp in ln -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_lock_installed_requeue(install_mockery, monkeypatch, capfd): """Cover basic install handling for installed package.""" const_arg = installer_args(['b'], {}) @@ -1200,8 +1118,6 @@ def _requeued(installer, task): assert exp in ln -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_read_locked_requeue(install_mockery, monkeypatch, capfd): """Cover basic read lock handling for uninstalled package with requeue.""" orig_fn = inst.PackageInstaller._ensure_locked @@ -1240,8 +1156,6 @@ def _requeued(installer, task): assert exp in ln -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_install_skip_patch(install_mockery, mock_fetch): """Test the path skip_patch install path.""" spec_name = 'b' diff --git a/lib/spack/spack/test/link_paths.py b/lib/spack/spack/test/link_paths.py index c02d124a8c..cafb646322 100644 --- a/lib/spack/spack/test/link_paths.py +++ b/lib/spack/spack/test/link_paths.py @@ -3,6 +3,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import re import sys import pytest @@ -11,6 +12,9 @@ from spack.compiler import _parse_non_system_link_dirs is_windows = sys.platform == 'win32' +if is_windows: + drive_m = re.search(r'[A-Za-z]:', spack.paths.test_path) + drive = drive_m.group() if drive_m else None #: directory with sample compiler data datadir = os.path.join(spack.paths.test_path, 'data', 'compiler_verbose_output') @@ -27,7 +31,6 @@ def check_link_paths(filename, paths): with open(os.path.join(datadir, filename)) as file: output = file.read() detected_paths = _parse_non_system_link_dirs(output) - print(detected_paths) actual = detected_paths expected = paths @@ -44,9 +47,9 @@ def check_link_paths(filename, paths): def test_icc16_link_paths(): if is_windows: check_link_paths('icc-16.0.3.txt', [ - r'C:\usr\tce\packages\intel\intel-16.0.3\compilers_and_libraries_2016.3.210\linux\compiler\lib\intel64_lin', # noqa - r'C:\usr\tce\packages\gcc\gcc-4.9.3\lib64\gcc\x86_64-unknown-linux-gnu\4.9.3', # noqa - r'C:\usr\tce\packages\gcc\gcc-4.9.3\lib64']) + drive + r'\usr\tce\packages\intel\intel-16.0.3\compilers_and_libraries_2016.3.210\linux\compiler\lib\intel64_lin', # noqa + drive + r'\usr\tce\packages\gcc\gcc-4.9.3\lib64\gcc\x86_64-unknown-linux-gnu\4.9.3', # noqa + drive + r'\usr\tce\packages\gcc\gcc-4.9.3\lib64']) else: check_link_paths('icc-16.0.3.txt', [ '/usr/tce/packages/intel/intel-16.0.3/compilers_and_libraries_2016.3.210/linux/compiler/lib/intel64_lin', # noqa @@ -57,32 +60,26 @@ def test_icc16_link_paths(): def test_pgi_link_paths(): if is_windows: check_link_paths('pgcc-16.3.txt', [ - r'C:\usr\tce\packages\pgi\pgi-16.3\linux86-64\16.3\lib']) + drive + r'\usr\tce\packages\pgi\pgi-16.3\linux86-64\16.3\lib']) else: check_link_paths('pgcc-16.3.txt', [ '/usr/tce/packages/pgi/pgi-16.3/linux86-64/16.3/lib']) def test_gcc7_link_paths(): - if is_windows: - check_link_paths('gcc-7.3.1.txt', []) - else: - check_link_paths('gcc-7.3.1.txt', []) + check_link_paths('gcc-7.3.1.txt', []) def test_clang4_link_paths(): - if is_windows: - check_link_paths('clang-4.0.1.txt', []) - else: - check_link_paths('clang-4.0.1.txt', []) + check_link_paths('clang-4.0.1.txt', []) def test_xl_link_paths(): if is_windows: check_link_paths('xl-13.1.5.txt', [ - r'C:\opt\ibm\xlsmp\4.1.5\lib', - r'C:\opt\ibm\xlmass\8.1.5\lib', - r'C:\opt\ibm\xlC\13.1.5\lib']) + drive + r'\opt\ibm\xlsmp\4.1.5\lib', + drive + r'\opt\ibm\xlmass\8.1.5\lib', + drive + r'\opt\ibm\xlC\13.1.5\lib']) else: check_link_paths('xl-13.1.5.txt', [ '/opt/ibm/xlsmp/4.1.5/lib', @@ -93,22 +90,23 @@ def test_xl_link_paths(): def test_cce_link_paths(): if is_windows: check_link_paths('cce-8.6.5.txt', [ - r'C:\opt\gcc\6.1.0\snos\lib64', - r'C:\opt\cray\dmapp\default\lib64', - r'C:\opt\cray\pe\mpt\7.7.0\gni\mpich-cray\8.6\lib', - r'C:\opt\cray\pe\libsci\17.12.1\CRAY\8.6\x86_64\lib', - r'C:\opt\cray\rca\2.2.16-6.0.5.0_15.34__g5e09e6d.ari\lib64', - r'C:\opt\cray\pe\pmi\5.0.13\lib64', - r'C:\opt\cray\xpmem\2.2.4-6.0.5.0_4.8__g35d5e73.ari\lib64', - r'C:\opt\cray\dmapp\7.1.1-6.0.5.0_49.8__g1125556.ari\lib64', - r'C:\opt\cray\ugni\6.0.14-6.0.5.0_16.9__g19583bb.ari\lib64', - r'C:\opt\cray\udreg\2.3.2-6.0.5.0_13.12__ga14955a.ari\lib64', - r'C:\opt\cray\alps\6.5.28-6.0.5.0_18.6__g13a91b6.ari\lib64', - r'C:\opt\cray\pe\atp\2.1.1\libApp', - r'C:\opt\cray\pe\cce\8.6.5\cce\x86_64\lib', - r'C:\opt\cray\wlm_detect\1.3.2-6.0.5.0_3.1__g388ccd5.ari\lib64', - r'C:\opt\gcc\6.1.0\snos\lib\gcc\x86_64-suse-linux\6.1.0', - r'C:\opt\cray\pe\cce\8.6.5\binutils\x86_64\x86_64-unknown-linux-gnu\lib']) + drive + r'\opt\gcc\6.1.0\snos\lib64', + drive + r'\opt\cray\dmapp\default\lib64', + drive + r'\opt\cray\pe\mpt\7.7.0\gni\mpich-cray\8.6\lib', + drive + r'\opt\cray\pe\libsci\17.12.1\CRAY\8.6\x86_64\lib', + drive + r'\opt\cray\rca\2.2.16-6.0.5.0_15.34__g5e09e6d.ari\lib64', + drive + r'\opt\cray\pe\pmi\5.0.13\lib64', + drive + r'\opt\cray\xpmem\2.2.4-6.0.5.0_4.8__g35d5e73.ari\lib64', + drive + r'\opt\cray\dmapp\7.1.1-6.0.5.0_49.8__g1125556.ari\lib64', + drive + r'\opt\cray\ugni\6.0.14-6.0.5.0_16.9__g19583bb.ari\lib64', + drive + r'\opt\cray\udreg\2.3.2-6.0.5.0_13.12__ga14955a.ari\lib64', + drive + r'\opt\cray\alps\6.5.28-6.0.5.0_18.6__g13a91b6.ari\lib64', + drive + r'\opt\cray\pe\atp\2.1.1\libApp', + drive + r'\opt\cray\pe\cce\8.6.5\cce\x86_64\lib', + drive + r'\opt\cray\wlm_detect\1.3.2-6.0.5.0_3.1__g388ccd5.ari\lib64', + drive + r'\opt\gcc\6.1.0\snos\lib\gcc\x86_64-suse-linux\6.1.0', + drive + + r'\opt\cray\pe\cce\8.6.5\binutils\x86_64\x86_64-unknown-linux-gnu\lib']) else: check_link_paths('cce-8.6.5.txt', [ '/opt/gcc/6.1.0/snos/lib64', @@ -132,7 +130,7 @@ def test_cce_link_paths(): def test_clang_apple_ld_link_paths(): if is_windows: check_link_paths('clang-9.0.0-apple-ld.txt', [ - r'C:\Applications\Xcode.app\Contents\Developer\Platforms\MacOSX.platform\Developer\SDKs\MacOSX10.13.sdk\usr\lib']) # noqa + drive + r'\Applications\Xcode.app\Contents\Developer\Platforms\MacOSX.platform\Developer\SDKs\MacOSX10.13.sdk\usr\lib']) # noqa else: check_link_paths('clang-9.0.0-apple-ld.txt', [ '/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/lib']) # noqa @@ -145,9 +143,9 @@ def test_nag_mixed_gcc_gnu_ld_link_paths(): # '/path/to/gcc/bin/g++ -Wl,-v ./main.c'. if is_windows: check_link_paths('collect2-6.3.0-gnu-ld.txt', [ - r'C:\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib\gcc\x86_64-pc-linux-gnu\6.5.0', # noqa - r'C:\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib64', # noqa - r'C:\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib']) # noqa + drive + r'\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib\gcc\x86_64-pc-linux-gnu\6.5.0', # noqa + drive + r'\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib64', # noqa + drive + r'\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib']) # noqa else: check_link_paths('collect2-6.3.0-gnu-ld.txt', [ '/scratch/local1/spack/opt/spack/gcc-6.3.0-haswell/gcc-6.5.0-4sdjgrs/lib/gcc/x86_64-pc-linux-gnu/6.5.0', # noqa @@ -162,9 +160,9 @@ def test_nag_link_paths(): # 'nagfor -Wc=/path/to/gcc/bin/gcc -Wl,-v ./main.c'. if is_windows: check_link_paths('nag-6.2-gcc-6.5.0.txt', [ - r'C:\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib\gcc\x86_64-pc-linux-gnu\6.5.0', # noqa - r'C:\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib64', # noqa - r'C:\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib']) # noqa + drive + r'\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib\gcc\x86_64-pc-linux-gnu\6.5.0', # noqa + drive + r'\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib64', # noqa + drive + r'\scratch\local1\spack\opt\spack\gcc-6.3.0-haswell\gcc-6.5.0-4sdjgrs\lib']) # noqa else: check_link_paths('nag-6.2-gcc-6.5.0.txt', [ '/scratch/local1/spack/opt/spack/gcc-6.3.0-haswell/gcc-6.5.0-4sdjgrs/lib/gcc/x86_64-pc-linux-gnu/6.5.0', # noqa @@ -175,8 +173,8 @@ def test_nag_link_paths(): def test_obscure_parsing_rules(): if is_windows: check_link_paths('obscure-parsing-rules.txt', [ - r'C:\first\path', - r'C:\third\path']) + drive + r'\first\path', + drive + r'\third\path']) else: check_link_paths('obscure-parsing-rules.txt', [ '/first/path', diff --git a/lib/spack/spack/test/llnl/util/filesystem.py b/lib/spack/spack/test/llnl/util/filesystem.py index 463ca1da5a..2bd6994754 100644 --- a/lib/spack/spack/test/llnl/util/filesystem.py +++ b/lib/spack/spack/test/llnl/util/filesystem.py @@ -176,21 +176,15 @@ def test_symlinks_true(self, stage): fs.copy_tree('source', 'dest', symlinks=True) assert os.path.exists('dest/2') - if sys.platform != "win32": - # TODO: islink will return false for junctions - assert islink('dest/2') + assert islink('dest/2') assert os.path.exists('dest/a/b2') - if sys.platform != "win32": - # TODO: Not supported for junctions ? - with fs.working_dir('dest/a'): - assert os.path.exists(os.readlink('b2')) + with fs.working_dir('dest/a'): + assert os.path.exists(os.readlink('b2')) - if sys.platform != "win32": - # TODO: Not supported on Windows ? - assert (os.path.realpath('dest/f/2') == - os.path.abspath('dest/a/b/2')) - assert os.path.realpath('dest/2') == os.path.abspath('dest/1') + assert (os.path.realpath('dest/f/2') == + os.path.abspath('dest/a/b/2')) + assert os.path.realpath('dest/2') == os.path.abspath('dest/1') def test_symlinks_true_ignore(self, stage): """Test copying when specifying relative paths that should be ignored @@ -387,7 +381,6 @@ def test_recursive_search_of_headers_from_prefix( if sys.platform == "win32": - # TODO: Test \\s dir_list = [ (['C:/pfx/include/foo.h', 'C:/pfx/include/subdir/foo.h'], ['C:/pfx/include']), (['C:/pfx/include/foo.h', 'C:/pfx/subdir/foo.h'], diff --git a/lib/spack/spack/test/llnl/util/lock.py b/lib/spack/spack/test/llnl/util/lock.py index 211d822a61..da8f77b2c3 100644 --- a/lib/spack/spack/test/llnl/util/lock.py +++ b/lib/spack/spack/test/llnl/util/lock.py @@ -628,6 +628,7 @@ def test_read_lock_read_only_dir_writable_lockfile(lock_dir, lock_path): pass +@pytest.mark.skipif(False if is_windows else getuid() == 0, reason='user is root') def test_read_lock_no_lockfile(lock_dir, lock_path): """read-only directory, no lockfile (so can't create).""" with read_only(lock_dir): @@ -689,13 +690,11 @@ def test_upgrade_read_to_write_fails_with_readonly_file(private_lock_path): lock = lk.Lock(private_lock_path) assert lock._reads == 0 assert lock._writes == 0 - assert lock._current_lock is None lock.acquire_read() assert lock._reads == 1 assert lock._writes == 0 assert lock._file.mode == 'r' - assert lock._current_lock == lock.LOCK_SH # upgrade to write here with pytest.raises(lk.LockROFileError): @@ -1358,6 +1357,7 @@ def _lockf(fd, cmd, len, start, whence): lock = lk.Lock(lockfile) touch(lockfile) + monkeypatch.setattr(fcntl, 'lockf', _lockf) if err_num in [errno.EAGAIN, errno.EACCES]: diff --git a/lib/spack/spack/test/llnl/util/tty/log.py b/lib/spack/spack/test/llnl/util/tty/log.py index fd8c7d30da..2491a5dbe3 100644 --- a/lib/spack/spack/test/llnl/util/tty/log.py +++ b/lib/spack/spack/test/llnl/util/tty/log.py @@ -18,8 +18,8 @@ import pytest -import llnl.util.tty.log as log import llnl.util.lang as lang +import llnl.util.tty.log as log import llnl.util.tty.pty as pty from spack.util.executable import which diff --git a/lib/spack/spack/test/main.py b/lib/spack/spack/test/main.py index 1bbe594666..9917fac6f5 100644 --- a/lib/spack/spack/test/main.py +++ b/lib/spack/spack/test/main.py @@ -15,7 +15,7 @@ pytestmark = pytest.mark.skipif( sys.platform == 'win32', - reason="Test functionality support but failing on Win") + reason="Test functionality supported but tests are failing on Win") def test_get_version_no_match_git(tmpdir, working_env): diff --git a/lib/spack/spack/test/make_executable.py b/lib/spack/spack/test/make_executable.py index a814601176..9fcf4cc8c4 100644 --- a/lib/spack/spack/test/make_executable.py +++ b/lib/spack/spack/test/make_executable.py @@ -20,7 +20,8 @@ from spack.util.environment import path_put_first pytestmark = pytest.mark.skipif(sys.platform == "win32", - reason="does not run on windows") + reason="MakeExecutable \ + not supported on Windows") class MakeExecutableTest(unittest.TestCase): diff --git a/lib/spack/spack/test/module_parsing.py b/lib/spack/spack/test/module_parsing.py index d20f6a2b95..2a19d39033 100644 --- a/lib/spack/spack/test/module_parsing.py +++ b/lib/spack/spack/test/module_parsing.py @@ -17,6 +17,9 @@ path_from_modules, ) +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="Tests fail on Windows") + test_module_lines = ['prepend-path LD_LIBRARY_PATH /path/to/lib', 'setenv MOD_DIR /path/to', 'setenv LDFLAGS -Wl,-rpath/path/to/lib', @@ -24,8 +27,6 @@ 'prepend-path PATH /path/to/bin'] -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_module_function_change_env(tmpdir, working_env): src_file = str(tmpdir.join('src_me')) with open(src_file, 'w') as f: @@ -38,8 +39,6 @@ def test_module_function_change_env(tmpdir, working_env): assert os.environ['NOT_AFFECTED'] == "NOT_AFFECTED" -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_module_function_no_change(tmpdir): src_file = str(tmpdir.join('src_me')) with open(src_file, 'w') as f: @@ -128,6 +127,7 @@ def test_get_argument_from_module_line(): get_path_args_from_module_line(bl) +# lmod is entirely unsupported on Windows def test_lmod_quote_parsing(): lines = ['setenv("SOME_PARTICULAR_DIR","-L/opt/cray/pe/mpich/8.1.4/gtl/lib")'] result = get_path_from_module_contents(lines, 'some-module') diff --git a/lib/spack/spack/test/optional_deps.py b/lib/spack/spack/test/optional_deps.py index 313903d272..84c3f2df43 100644 --- a/lib/spack/spack/test/optional_deps.py +++ b/lib/spack/spack/test/optional_deps.py @@ -3,8 +3,6 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -import sys - import pytest from spack.spec import Spec @@ -98,8 +96,6 @@ def test_normalize(spec_and_expected, config, mock_packages): assert spec.eq_dag(expected, deptypes=False) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_default_variant(config, mock_packages): spec = Spec('optional-dep-test-3') spec.concretize() diff --git a/lib/spack/spack/test/packages.py b/lib/spack/spack/test/packages.py index be8243fd6f..e403d85899 100644 --- a/lib/spack/spack/test/packages.py +++ b/lib/spack/spack/test/packages.py @@ -4,7 +4,6 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os -import sys import pytest @@ -64,8 +63,6 @@ def test_import_package_as(self): import spack.pkg.builtin.mock.mpich as mp # noqa from spack.pkg.builtin import mock # noqa - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_inheritance_of_diretives(self): p = spack.repo.get('simple-inheritance') @@ -91,16 +88,12 @@ def test_inheritance_of_diretives(self): assert '~openblas' in s assert 'mpi' in s - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.regression('11844') def test_inheritance_of_patches(self): s = Spec('patch-inheritance') # Will error if inheritor package cannot find inherited patch files s.concretize() - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_dependency_extensions(self): s = Spec('extension2') s.concretize() @@ -125,8 +118,6 @@ def test_import_namespace_container_modules(self): from spack.pkg.builtin import mock # noqa -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.regression('2737') def test_urls_for_versions(mock_packages, config): """Version directive without a 'url' argument should use default url.""" @@ -151,8 +142,6 @@ def test_url_for_version_with_no_urls(mock_packages, config): pkg.url_for_version('1.1') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_url_for_version_with_only_overrides(mock_packages, config): spec = Spec('url-only-override') spec.concretize() @@ -171,8 +160,6 @@ def test_url_for_version_with_only_overrides(mock_packages, config): assert pkg.url_for_version('0.7.0') == 'http://c.example.com/url_override-0.7.0.tar.gz' -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_url_for_version_with_only_overrides_with_gaps(mock_packages, config): spec = Spec('url-only-override-with-gaps') spec.concretize() @@ -340,8 +327,6 @@ def test_git_url_top_level_conflicts(mock_packages, config): spack.fetch_strategy.for_package_version(pkg, '1.3') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_rpath_args(mutable_database): """Test a package's rpath_args property.""" diff --git a/lib/spack/spack/test/packaging.py b/lib/spack/spack/test/packaging.py index b23df6e30d..ff68418ac4 100644 --- a/lib/spack/spack/test/packaging.py +++ b/lib/spack/spack/test/packaging.py @@ -40,6 +40,9 @@ ) from spack.spec import Spec +pytestmark = pytest.mark.skipif(sys.platform == "win32", + reason="does not run on windows") + def fake_fetchify(url, pkg): """Fake the URL for a package so it downloads from a file.""" @@ -48,8 +51,6 @@ def fake_fetchify(url, pkg): pkg.fetcher = fetcher -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.usefixtures('install_mockery', 'mock_gnupghome') def test_buildcache(mock_archive, tmpdir): # tweak patchelf to only do a download @@ -192,8 +193,6 @@ def test_buildcache(mock_archive, tmpdir): bindist._cached_specs = set() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.usefixtures('install_mockery') def test_relocate_text(tmpdir): spec = Spec('trivial-install-test-package') @@ -217,8 +216,6 @@ def test_relocate_text(tmpdir): bindist._cached_specs = set() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_relocate_links(tmpdir): with tmpdir.as_cwd(): old_layout_root = os.path.join( @@ -260,8 +257,6 @@ def test_needs_relocation(): assert needs_binary_relocation('application', 'x-mach-binary') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_replace_paths(tmpdir): with tmpdir.as_cwd(): suffix = 'dylib' if platform.system().lower() == 'darwin' else 'so' @@ -471,8 +466,6 @@ def test_replace_paths(tmpdir): } -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_macho_make_paths(): out = macho_make_paths_relative('/Users/Shared/spack/pkgC/lib/libC.dylib', '/Users/Shared/spack', diff --git a/lib/spack/spack/test/patch.py b/lib/spack/spack/test/patch.py index 1eaec4e7b9..0d88b93c23 100644 --- a/lib/spack/spack/test/patch.py +++ b/lib/spack/spack/test/patch.py @@ -19,20 +19,26 @@ from spack.spec import Spec from spack.stage import Stage from spack.util.executable import Executable +from spack.util.path import is_windows # various sha256 sums (using variables for legibility) +# many file based shas will differ between Windows and other platforms +# due to the use of carriage returns ('\r\n') in Windows line endings # files with contents 'foo', 'bar', and 'baz' -foo_sha256 = 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c' -bar_sha256 = '7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730' -baz_sha256 = 'bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c' -biz_sha256 = 'a69b288d7393261e613c276c6d38a01461028291f6e381623acc58139d01f54d' +foo_sha256 = 'b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c' if not is_windows else 'bf874c7dd3a83cf370fdc17e496e341de06cd596b5c66dbf3c9bb7f6c139e3ee' +bar_sha256 = '7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730' if not is_windows else '556ddc69a75d0be0ecafc82cd4657666c8063f13d762282059c39ff5dbf18116' +baz_sha256 = 'bf07a7fbb825fc0aae7bf4a1177b2b31fcf8a3feeaf7092761e18c859ee52a9c' if not is_windows else 'd30392e66c636a063769cbb1db08cd3455a424650d4494db6379d73ea799582b' +biz_sha256 = 'a69b288d7393261e613c276c6d38a01461028291f6e381623acc58139d01f54d' if not is_windows else '2f2b087a8f84834fd03d4d1d5b43584011e869e4657504ef3f8b0a672a5c222e' # url patches +# url shas are the same on Windows url1_sha256 = 'abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234' url2_sha256 = '1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd' url2_archive_sha256 = 'abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd' +platform_url_sha = '252c0af58be3d90e5dc5e0d16658434c9efa5d20a5df6c10bf72c2d77f780866' if not is_windows else 'ecf44a8244a486e9ef5f72c6cb622f99718dcd790707ac91af0b8c9a4ab7a2bb' + @pytest.fixture() def mock_patch_stage(tmpdir_factory, monkeypatch): @@ -46,7 +52,7 @@ def mock_patch_stage(tmpdir_factory, monkeypatch): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Line ending conflict on Windows") @pytest.mark.parametrize('filename, sha256, archive_sha256', [ # compressed patch -- needs sha256 and archive_256 (os.path.join(data_path, 'foo.tgz'), @@ -54,7 +60,7 @@ def mock_patch_stage(tmpdir_factory, monkeypatch): '4e8092a161ec6c3a1b5253176fcf33ce7ba23ee2ff27c75dbced589dabacd06e'), # uncompressed patch -- needs only sha256 (os.path.join(data_path, 'foo.patch'), - '252c0af58be3d90e5dc5e0d16658434c9efa5d20a5df6c10bf72c2d77f780866', + platform_url_sha, None) ]) def test_url_patch(mock_patch_stage, filename, sha256, archive_sha256): @@ -92,8 +98,6 @@ def test_url_patch(mock_patch_stage, filename, sha256, archive_sha256): assert filecmp.cmp('foo.txt', 'foo-expected.txt') -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_patch_in_spec(mock_packages, config): """Test whether patches in a package appear in the spec.""" spec = Spec('patch') @@ -112,8 +116,6 @@ def test_patch_in_spec(mock_packages, config): tuple(spec.variants['patches']._patches_in_order_of_appearance)) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_patch_mixed_versions_subset_constraint(mock_packages, config): """If we have a package with mixed x.y and x.y.z versions, make sure that a patch applied to a version range of x.y.z versions is not applied to @@ -128,15 +130,17 @@ def test_patch_mixed_versions_subset_constraint(mock_packages, config): assert biz_sha256 not in spec2.variants['patches'].value -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_patch_order(mock_packages, config): spec = Spec('dep-diamond-patch-top') spec.concretize() - mid2_sha256 = 'mid21234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234' - mid1_sha256 = '0b62284961dab49887e31319843431ee5b037382ac02c4fe436955abef11f094' - top_sha256 = 'f7de2947c64cb6435e15fb2bef359d1ed5f6356b2aebb7b20535e3772904e6db' + mid2_sha256 = 'mid21234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234' \ + if not is_windows \ + else 'mid21234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234' + mid1_sha256 = '0b62284961dab49887e31319843431ee5b037382ac02c4fe436955abef11f094' \ + if not is_windows else 'aeb16c4dec1087e39f2330542d59d9b456dd26d791338ae6d80b6ffd10c89dfa' + top_sha256 = 'f7de2947c64cb6435e15fb2bef359d1ed5f6356b2aebb7b20535e3772904e6db' \ + if not is_windows else 'ff34cb21271d16dbf928374f610bb5dd593d293d311036ddae86c4846ff79070' dep = spec['patch'] patch_order = dep.variants['patches']._patches_in_order_of_appearance @@ -178,7 +182,7 @@ def test_nested_directives(mock_packages): @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") + reason="Test requires Autotools") def test_patched_dependency( mock_packages, config, install_mockery, mock_fetch): """Test whether patched dependencies work.""" @@ -187,7 +191,9 @@ def test_patched_dependency( assert 'patches' in list(spec['libelf'].variants.keys()) # make sure the patch makes it into the dependency spec - assert (('c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8',) == + t_sha = 'c45c1564f70def3fc1a6e22139f62cb21cd190cc3a7dbe6f4120fa59ce33dcb8' \ + if not is_windows else '3c5b65abcd6a3b2c714dbf7c31ff65fe3748a1adc371f030c283007ca5534f11' + assert ((t_sha,) == spec['libelf'].variants['patches'].value) # make sure the patch in the dependent's directory is applied to the @@ -206,8 +212,6 @@ def test_patched_dependency( assert 'Patched!' in mf.read() -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_multiple_patched_dependencies(mock_packages, config): """Test whether multiple patched dependencies work.""" spec = Spec('patch-several-dependencies') @@ -226,8 +230,6 @@ def test_multiple_patched_dependencies(mock_packages, config): (url2_sha256, url1_sha256) == spec['fake'].variants['patches'].value) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_conditional_patched_dependencies(mock_packages, config): """Test whether conditional patched dependencies work.""" spec = Spec('patch-several-dependencies @1.0') @@ -309,8 +311,6 @@ def get_patch(spec, ending): assert url2_patch.archive_sha256 == url2_archive_sha256 -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_conditional_patched_deps_with_conditions(mock_packages, config): """Test whether conditional patched dependencies with conditions work.""" spec = Spec('patch-several-dependencies @1.0 ^libdwarf@20111030') @@ -326,8 +326,6 @@ def test_conditional_patched_deps_with_conditions(mock_packages, config): spec.package.package_dir) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_write_and_read_sub_dags_with_patched_deps(mock_packages, config): """Test whether patched dependencies are still correct after writing and reading a sub-DAG of a concretized Spec. diff --git a/lib/spack/spack/test/permissions.py b/lib/spack/spack/test/permissions.py index 01787922ae..e2667b9b56 100644 --- a/lib/spack/spack/test/permissions.py +++ b/lib/spack/spack/test/permissions.py @@ -13,9 +13,10 @@ from spack.util.file_permissions import InvalidPermissionsError, set_permissions +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="chmod unsupported on Windows") + -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_chmod_real_entries_ignores_suid_sgid(tmpdir): path = str(tmpdir.join('file').ensure()) mode = stat.S_ISUID | stat.S_ISGID | stat.S_ISVTX @@ -28,8 +29,6 @@ def test_chmod_real_entries_ignores_suid_sgid(tmpdir): assert os.stat(path).st_mode == mode | perms & ~stat.S_IXUSR -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_chmod_rejects_group_writable_suid(tmpdir): path = str(tmpdir.join('file').ensure()) mode = stat.S_ISUID @@ -40,8 +39,6 @@ def test_chmod_rejects_group_writable_suid(tmpdir): set_permissions(path, perms) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_chmod_rejects_world_writable_suid(tmpdir): path = str(tmpdir.join('file').ensure()) mode = stat.S_ISUID @@ -52,8 +49,6 @@ def test_chmod_rejects_world_writable_suid(tmpdir): set_permissions(path, perms) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_chmod_rejects_world_writable_sgid(tmpdir): path = str(tmpdir.join('file').ensure()) mode = stat.S_ISGID diff --git a/lib/spack/spack/test/relocate.py b/lib/spack/spack/test/relocate.py index ac490b5fb2..b5c0151420 100644 --- a/lib/spack/spack/test/relocate.py +++ b/lib/spack/spack/test/relocate.py @@ -21,6 +21,9 @@ import spack.tengine import spack.util.executable +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="Tests fail on Windows") + def skip_unless_linux(f): return pytest.mark.skipif( @@ -225,8 +228,6 @@ def test_file_is_relocatable_errors(tmpdir): assert 'is not an absolute path' in str(exc_info.value) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('patchelf_behavior,expected', [ ('echo ', []), ('echo /opt/foo/lib:/opt/foo/lib64', ['/opt/foo/lib', '/opt/foo/lib64']), @@ -269,8 +270,6 @@ def test_normalize_relative_paths(start_path, relative_paths, expected): assert normalized == expected -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_set_elf_rpaths(mock_patchelf): # Try to relocate a mock version of patchelf and check # the call made to patchelf itself diff --git a/lib/spack/spack/test/sbang.py b/lib/spack/spack/test/sbang.py index ce64d0669b..2a4189e7f8 100644 --- a/lib/spack/spack/test/sbang.py +++ b/lib/spack/spack/test/sbang.py @@ -60,7 +60,7 @@ @pytest.fixture # type: ignore[no-redef] def sbang_line(): - yield '#!/bin/sh {0}{1}bin{1}sbang\n'.format(spack.store.layout.root, os.sep) + yield '#!/bin/sh %s/bin/sbang\n' % spack.store.layout.root class ScriptDirectory(object): diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py index 991adc5fc3..046ff7aad2 100644 --- a/lib/spack/spack/test/spec_dag.py +++ b/lib/spack/spack/test/spec_dag.py @@ -5,8 +5,6 @@ """ These tests check Spec DAG operations using dummy packages. """ -import sys - import pytest import spack.error @@ -16,9 +14,6 @@ from spack.spec import Spec from spack.util.mock_package import MockPackageMultiRepo -pytestmark = pytest.mark.skipif(sys.platform == "win32", - reason="does not run on windows") - def check_links(spec_to_check): for spec in spec_to_check.traverse(): diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py index 0c948c046c..fe8e07a54f 100644 --- a/lib/spack/spack/test/spec_semantics.py +++ b/lib/spack/spack/test/spec_semantics.py @@ -314,8 +314,6 @@ def test_satisfies_multi_value_variant(self): check_satisfies('multivalue-variant foo="bar,baz"', 'foo="bar"') - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_satisfies_single_valued_variant(self): """Tests that the case reported in https://github.com/spack/spack/pull/2386#issuecomment-282147639 @@ -339,8 +337,6 @@ def test_satisfies_single_valued_variant(self): # Check that conditional dependencies are treated correctly assert '^b' in a - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_unsatisfied_single_valued_variant(self): a = Spec('a foobar=baz') a.concretize() @@ -350,15 +346,11 @@ def test_unsatisfied_single_valued_variant(self): mv.concretize() assert 'a@1.0' not in mv - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_indirect_unsatisfied_single_valued_variant(self): spec = Spec('singlevalue-variant-dependent') spec.concretize() assert 'a@1.0' not in spec - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_unsatisfiable_multi_value_variant(self): # Semantics for a multi-valued variant is different @@ -491,8 +483,6 @@ def test_unsatisfiable_compiler_flag(self): # 'mpich' is concrete: check_unsatisfiable('mpich', 'mpich cppflags="-O3"', True) - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_copy_satisfies_transitive(self): spec = Spec('dttop') spec.concretize() @@ -506,8 +496,6 @@ def test_unsatisfiable_compiler_flag_mismatch(self): check_unsatisfiable( 'mpich cppflags="-O3"', 'mpich cppflags="-O2"') - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_satisfies_virtual(self): # Don't use check_satisfies: it checks constrain() too, and # you can't constrain a non-virtual by a virtual. @@ -515,8 +503,6 @@ def test_satisfies_virtual(self): assert Spec('mpich2').satisfies(Spec('mpi')) assert Spec('zmpi').satisfies(Spec('mpi')) - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_satisfies_virtual_dep_with_virtual_constraint(self): """Ensure we can satisfy virtual constraints when there are multiple vdep providers in the specs.""" @@ -533,8 +519,6 @@ def test_satisfies_virtual_dep_with_virtual_constraint(self): 'netlib-lapack ^netlib-blas' ) - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_satisfies_same_spec_with_different_hash(self): """Ensure that concrete specs are matched *exactly* by hash.""" s1 = Spec('mpileaks').concretized() @@ -580,8 +564,6 @@ def test_spec_contains_deps(self): assert 'libelf' in s assert 'mpi' in s - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.usefixtures('config') def test_virtual_index(self): s = Spec('callpath') @@ -776,8 +758,6 @@ def test_exceptional_paths_for_constructor(self): with pytest.raises(ValueError): Spec('libelf foo') - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_spec_formatting(self): spec = Spec("multivalue-variant cflags=-O2") spec.concretize() @@ -850,8 +830,6 @@ def test_spec_formatting(self): actual = spec.format(named_str) assert expected == actual - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_spec_formatting_escapes(self): spec = Spec('multivalue-variant cflags=-O2') spec.concretize() @@ -884,8 +862,6 @@ def test_spec_formatting_escapes(self): with pytest.raises(SpecFormatStringError): spec.format(fmt_str) - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_spec_deprecated_formatting(self): spec = Spec("libelf cflags=-O2") spec.concretize() @@ -929,8 +905,6 @@ def test_spec_deprecated_formatting(self): actual = spec.format(named_str) assert str(expected) == actual - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.regression('9908') def test_spec_flags_maintain_order(self): # Spack was assembling flags in a manner that could result in @@ -997,8 +971,6 @@ def test_abstract_spec_prefix_error(self): with pytest.raises(SpecError): spec.prefix - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_forwarding_of_architecture_attributes(self): spec = Spec('libelf target=x86_64').concretized() @@ -1019,8 +991,6 @@ def test_forwarding_of_architecture_attributes(self): assert 'avx512' not in spec.target assert spec.target < 'broadwell' - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('transitive', [True, False]) def test_splice(self, transitive): # Tests the new splice function in Spec using a somewhat simple case @@ -1056,8 +1026,6 @@ def test_splice(self, transitive): # Finally, the spec should know it's been spliced: assert out.spliced - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('transitive', [True, False]) def test_splice_with_cached_hashes(self, transitive): spec = Spec('splice-t') @@ -1088,8 +1056,6 @@ def test_splice_with_cached_hashes(self, transitive): assert (out['splice-h'].build_hash() == dep.build_hash()) == transitive assert out['splice-z'].build_hash() == out_z_expected.build_hash() - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('transitive', [True, False]) def test_splice_input_unchanged(self, transitive): spec = Spec('splice-t').concretized() @@ -1102,8 +1068,6 @@ def test_splice_input_unchanged(self, transitive): assert spec.full_hash() == orig_spec_hash assert dep.full_hash() == orig_dep_hash - @pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize('transitive', [True, False]) def test_splice_subsequent(self, transitive): spec = Spec('splice-t') @@ -1208,8 +1172,6 @@ def test_satisfies_dependencies_ordered(self): assert s.satisfies('mpileaks ^zmpi ^fake', strict=True) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.regression('3887') @pytest.mark.parametrize('spec_str', [ 'git', 'hdf5', 'py-flake8' diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py index 681bf42659..48e55254f4 100644 --- a/lib/spack/spack/test/spec_syntax.py +++ b/lib/spack/spack/test/spec_syntax.py @@ -5,7 +5,6 @@ import itertools import os import shlex -import sys import pytest diff --git a/lib/spack/spack/test/spec_yaml.py b/lib/spack/spack/test/spec_yaml.py index b676653849..8aa14b9230 100644 --- a/lib/spack/spack/test/spec_yaml.py +++ b/lib/spack/spack/test/spec_yaml.py @@ -11,7 +11,6 @@ import ast import inspect import os -import sys import pytest diff --git a/lib/spack/spack/test/test_activations.py b/lib/spack/spack/test/test_activations.py index 915b4d2081..8eadfa837b 100644 --- a/lib/spack/spack/test/test_activations.py +++ b/lib/spack/spack/test/test_activations.py @@ -20,6 +20,10 @@ from spack.filesystem_view import YamlFilesystemView from spack.repo import RepoPath +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="Python activation not \ + currently supported on Windows") + def create_ext_pkg(name, prefix, extendee_spec, monkeypatch): ext_spec = spack.spec.Spec(name) @@ -178,8 +182,6 @@ def test_python_activation_with_files(tmpdir, python_and_extension_dirs, assert 'setuptools.egg' not in easy_install_contents -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_python_activation_view(tmpdir, python_and_extension_dirs, builtin_and_mock_packages, monkeypatch): python_prefix, ext_prefix = python_and_extension_dirs @@ -203,8 +205,6 @@ def test_python_activation_view(tmpdir, python_and_extension_dirs, assert os.path.exists(os.path.join(view_dir, 'bin/py-ext-tool')) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_python_ignore_namespace_init_conflict( tmpdir, namespace_extensions, builtin_and_mock_packages, monkeypatch): """Test the view update logic in PythonPackage ignores conflicting @@ -239,8 +239,6 @@ def test_python_ignore_namespace_init_conflict( assert os.path.exists(os.path.join(view_dir, init_file)) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_python_keep_namespace_init( tmpdir, namespace_extensions, builtin_and_mock_packages, monkeypatch): """Test the view update logic in PythonPackage keeps the namespace @@ -283,8 +281,6 @@ def test_python_keep_namespace_init( assert not os.path.exists(os.path.join(view_dir, init_file)) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_python_namespace_conflict(tmpdir, namespace_extensions, monkeypatch, builtin_and_mock_packages): """Test the view update logic in PythonPackage reports an error when two diff --git a/lib/spack/spack/test/test_suite.py b/lib/spack/spack/test/test_suite.py index 419e633e9c..20d7172eea 100644 --- a/lib/spack/spack/test/test_suite.py +++ b/lib/spack/spack/test/test_suite.py @@ -12,9 +12,10 @@ import spack.install_test import spack.spec +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="Tests fail on Windows") + -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_test_log_pathname(mock_packages, config): """Ensure test log path is reasonable.""" spec = spack.spec.Spec('libdwarf').concretized() @@ -28,8 +29,6 @@ def test_test_log_pathname(mock_packages, config): assert test_suite.test_log_name(spec) in logfile -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_test_ensure_stage(mock_test_stage): """Make sure test stage directory is properly set up.""" spec = spack.spec.Spec('libdwarf').concretized() @@ -43,8 +42,6 @@ def test_test_ensure_stage(mock_test_stage): assert mock_test_stage in test_suite.stage -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_write_test_result(mock_packages, mock_test_stage): """Ensure test results written to a results file.""" spec = spack.spec.Spec('libdwarf').concretized() @@ -65,7 +62,6 @@ def test_write_test_result(mock_packages, mock_test_stage): assert spec.name in msg -@pytest.mark.skipif(sys.platform == 'win32', reason="Not yet implemented on windows") def test_do_test(mock_packages, install_mockery, mock_test_stage): """Perform a stand-alone test with files to copy.""" spec = spack.spec.Spec('trivial-smoke-test').concretized() diff --git a/lib/spack/spack/test/url_fetch.py b/lib/spack/spack/test/url_fetch.py index d3155a45f0..8497fbebd7 100644 --- a/lib/spack/spack/test/url_fetch.py +++ b/lib/spack/spack/test/url_fetch.py @@ -163,6 +163,7 @@ def test_fetch( assert 'echo Building...' in contents +# TODO-27021 @pytest.mark.skipif(sys.platform == 'win32', reason="Not supported on Windows (yet)") @pytest.mark.parametrize('spec,url,digest', [ diff --git a/lib/spack/spack/test/util/editor.py b/lib/spack/spack/test/util/editor.py index f197682a97..e7c8bf2364 100644 --- a/lib/spack/spack/test/util/editor.py +++ b/lib/spack/spack/test/util/editor.py @@ -12,7 +12,9 @@ import spack.util.editor as ed -pytestmark = pytest.mark.usefixtures('working_env') +pytestmark = [pytest.mark.usefixtures('working_env'), + pytest.mark.skipif(sys.platform == 'win32', + reason="editor not implemented on windows")] def _make_exe(tmpdir_factory, name, contents=None): @@ -23,8 +25,6 @@ def _make_exe(tmpdir_factory, name, contents=None): with open(path, 'w') as f: f.write('#!/bin/sh\n%s\n' % contents) set_executable(path) - if sys.platform == "win32": - path = path.replace('\\', '/') return path @@ -48,13 +48,11 @@ def vim_exe(tmpdir_factory): return _make_exe(tmpdir_factory, 'vim', 'exit 0') -@pytest.mark.skipif(sys.platform == 'win32', reason="editor not implemented on windows") def test_find_exe_from_env_var(good_exe): os.environ['EDITOR'] = good_exe assert ed._find_exe_from_env_var('EDITOR') == (good_exe, [good_exe]) -@pytest.mark.skipif(sys.platform == 'win32', reason="editor not implemented on windows") def test_find_exe_from_env_var_with_args(good_exe): os.environ['EDITOR'] = good_exe + ' a b c' assert ed._find_exe_from_env_var('EDITOR') == ( @@ -72,7 +70,6 @@ def test_find_exe_from_env_var_no_editor(): assert ed._find_exe_from_env_var('FOO') == (None, []) -@pytest.mark.skipif(sys.platform == 'win32', reason="editor not implemented on windows") def test_editor_visual(good_exe): os.environ['VISUAL'] = good_exe @@ -83,7 +80,6 @@ def assert_exec(exe, args): ed.editor('/path/to/file', _exec_func=assert_exec) -@pytest.mark.skipif(sys.platform == 'win32', reason="editor not implemented on windows") def test_editor_visual_bad(good_exe, bad_exe): os.environ['VISUAL'] = bad_exe os.environ['EDITOR'] = good_exe @@ -98,7 +94,6 @@ def assert_exec(exe, args): ed.editor('/path/to/file', _exec_func=assert_exec) -@pytest.mark.skipif(sys.platform == 'win32', reason="editor not implemented on windows") def test_editor_no_visual(good_exe): if 'VISUAL' in os.environ: del os.environ['VISUAL'] @@ -111,7 +106,6 @@ def assert_exec(exe, args): ed.editor('/path/to/file', _exec_func=assert_exec) -@pytest.mark.skipif(sys.platform == 'win32', reason="editor not implemented on windows") def test_editor_no_visual_with_args(good_exe): if 'VISUAL' in os.environ: del os.environ['VISUAL'] @@ -126,7 +120,6 @@ def assert_exec(exe, args): ed.editor('/path/to/file', _exec_func=assert_exec) -@pytest.mark.skipif(sys.platform == 'win32', reason="editor not implemented on windows") def test_editor_both_bad(nosuch_exe, vim_exe): os.environ['VISUAL'] = nosuch_exe os.environ['EDITOR'] = nosuch_exe diff --git a/lib/spack/spack/test/util/environment.py b/lib/spack/spack/test/util/environment.py index 3604b7871b..1e28590e80 100644 --- a/lib/spack/spack/test/util/environment.py +++ b/lib/spack/spack/test/util/environment.py @@ -11,6 +11,8 @@ import spack.util.environment as envutil +is_windows = sys.platform == 'win32' + @pytest.fixture() def prepare_environment_for_tests(): @@ -20,25 +22,34 @@ def prepare_environment_for_tests(): del os.environ['TEST_ENV_VAR'] -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_is_system_path(): - assert(envutil.is_system_path('/usr/bin')) + sys_path = 'C:\\Users' if is_windows else '/usr/bin' + assert(envutil.is_system_path(sys_path)) assert(not envutil.is_system_path('/nonsense_path/bin')) assert(not envutil.is_system_path('')) assert(not envutil.is_system_path(None)) -test_paths = ['/usr/bin', - '/nonsense_path/lib', - '/usr/local/lib', - '/bin', - '/nonsense_path/extra/bin', - '/usr/lib64'] +if is_windows: + test_paths = [ + 'C:\\Users', + 'C:\\', + 'C:\\ProgramData', + 'C:\\nonsense_path', + 'C:\\Program Files', + 'C:\\nonsense_path\\extra\\bin'] +else: + test_paths = ['/usr/bin', + '/nonsense_path/lib', + '/usr/local/lib', + '/bin', + '/nonsense_path/extra/bin', + '/usr/lib64'] -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_filter_system_paths(): - expected = [p for p in test_paths if p.startswith('/nonsense_path')] + nonsense_prefix = 'C:\\nonsense_path' if is_windows else '/nonsense_path' + expected = [p for p in test_paths if p.startswith(nonsense_prefix)] filtered = envutil.filter_system_paths(test_paths) assert(expected == filtered) @@ -57,9 +68,8 @@ def test_prune_duplicate_paths(): assert(expected == envutil.prune_duplicate_paths(test_paths)) -@pytest.mark.skipif(sys.platform == 'win32', reason="All Fetchers Failed") def test_get_path(prepare_environment_for_tests): - os.environ['TEST_ENV_VAR'] = '/a:/b:/c/d' + os.environ['TEST_ENV_VAR'] = os.pathsep.join(['/a', '/b', '/c/d']) expected = ['/a', '/b', '/c/d'] assert(envutil.get_path('TEST_ENV_VAR') == expected) diff --git a/lib/spack/spack/test/util/executable.py b/lib/spack/spack/test/util/executable.py index 6a313e751f..ea9213f063 100644 --- a/lib/spack/spack/test/util/executable.py +++ b/lib/spack/spack/test/util/executable.py @@ -14,10 +14,16 @@ import spack.util.executable as ex from spack.hooks.sbang import filter_shebangs_in_directory +is_windows = sys.platform == 'win32' + def test_read_unicode(tmpdir, working_env): script_name = 'print_unicode.py' - + # read the unicode back in and see whether things work + if is_windows: + script = ex.Executable('%s %s' % (sys.executable, script_name)) + else: + script = ex.Executable('./%s' % script_name) with tmpdir.as_cwd(): os.environ['LD_LIBRARY_PATH'] = spack.main.spack_ld_library_path # make a script that prints some unicode @@ -35,12 +41,6 @@ def test_read_unicode(tmpdir, working_env): fs.set_executable(script_name) filter_shebangs_in_directory('.', [script_name]) - # read the unicode back in and see whether things work - if sys.platform == 'win32': - script = ex.Executable('%s %s' % (sys.executable, script_name)) - else: - script = ex.Executable('./%s' % script_name) - assert u'\xc3' == script(output=str).strip() @@ -54,9 +54,10 @@ def test_which_relative_path_with_slash(tmpdir, working_env): no_exe = ex.which('.{0}exe'.format(os.path.sep)) assert no_exe is None if sys.platform == "win32": - # For Windows, need to create files with .exe after any assert is none tests - tmpdir.ensure("exe.exe") + # These checks are for 'executable' files, Windows + # determines this by file extension. path += ".exe" + tmpdir.ensure('exe.exe') else: fs.set_executable(path) diff --git a/lib/spack/spack/test/util/file_cache.py b/lib/spack/spack/test/util/file_cache.py index 02056fd444..988e243835 100644 --- a/lib/spack/spack/test/util/file_cache.py +++ b/lib/spack/spack/test/util/file_cache.py @@ -5,7 +5,6 @@ """Test Spack's FileCache.""" import os -import sys import pytest @@ -30,8 +29,6 @@ def test_write_and_read_cache_file(file_cache): assert text == "foobar\n" -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_write_and_remove_cache_file(file_cache): """Test two write transactions on a cached file. Then try to remove an entry from it. diff --git a/lib/spack/spack/test/util/path.py b/lib/spack/spack/test/util/path.py index 13633195db..7d2b81e8b3 100644 --- a/lib/spack/spack/test/util/path.py +++ b/lib/spack/spack/test/util/path.py @@ -12,6 +12,12 @@ import spack.config import spack.util.path as sup +# This module pertains to path string padding manipulation specifically +# which is used for binary caching. This functionality is not supported +# on Windows as of yet. +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason="Tests fail on Windows") + #: Some lines with lots of placeholders padded_lines = [ "==> [2021-06-23-15:59:05.020387] './configure' '--prefix=/Users/gamblin2/padding-log-test/opt/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_placeholder__/__spack_path_pla/darwin-bigsur-skylake/apple-clang-12.0.5/zlib-1.2.11-74mwnxgn6nujehpyyalhwizwojwn5zga", # noqa: E501 @@ -28,24 +34,18 @@ ] -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") @pytest.mark.parametrize("padded,fixed", zip(padded_lines, fixed_lines)) def test_padding_substitution(padded, fixed): """Ensure that all padded lines are unpadded correctly.""" assert fixed == sup.padding_filter(padded) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_no_substitution(): """Ensure that a line not containing one full path placeholder is not modified.""" partial = "--prefix=/Users/gamblin2/padding-log-test/opt/__spack_path_pla/darwin-bigsur-skylake/apple-clang-12.0.5/zlib-1.2.11-74mwnxgn6nujehpyyalhwizwojwn5zga'" # noqa: E501 assert sup.padding_filter(partial) == partial -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_short_substitution(): """Ensure that a single placeholder path component is replaced""" short = "--prefix=/Users/gamblin2/padding-log-test/opt/__spack_path_placeholder__/darwin-bigsur-skylake/apple-clang-12.0.5/zlib-1.2.11-74mwnxgn6nujehpyyalhwizwojwn5zga'" # noqa: E501 @@ -53,8 +53,6 @@ def test_short_substitution(): assert short_subst == sup.padding_filter(short) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_partial_substitution(): """Ensure that a single placeholder path component is replaced""" short = "--prefix=/Users/gamblin2/padding-log-test/opt/__spack_path_placeholder__/__spack_p/darwin-bigsur-skylake/apple-clang-12.0.5/zlib-1.2.11-74mwnxgn6nujehpyyalhwizwojwn5zga'" # noqa: E501 @@ -72,8 +70,6 @@ def test_longest_prefix_re(): ) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_output_filtering(capfd, install_mockery, mutable_config): """Test filtering padding out of tty messages.""" long_path = "/" + "/".join([sup.SPACK_PATH_PADDING_CHARS] * 200) diff --git a/lib/spack/spack/test/util/util_url.py b/lib/spack/spack/test/util/util_url.py index b0316aaf3f..8e22c99164 100644 --- a/lib/spack/spack/test/util/util_url.py +++ b/lib/spack/spack/test/util/util_url.py @@ -7,19 +7,22 @@ import os import os.path import posixpath +import re import sys import pytest import spack.paths import spack.util.url as url_util +from spack.util.path import convert_to_posix_path + +is_windows = sys.platform == 'win32' +if is_windows: + drive_m = re.search(r'[A-Za-z]:', spack.paths.test_path) + drive = drive_m.group() if drive_m else None def test_url_parse(): - parsed = url_util.parse('/path/to/resource') - assert(parsed.scheme == 'file') - assert(parsed.netloc == '') - assert(parsed.path == '/path/to/resource') parsed = url_util.parse('/path/to/resource', scheme='fake') assert(parsed.scheme == 'fake') @@ -36,11 +39,20 @@ def test_url_parse(): assert(parsed.netloc == '') assert(parsed.path == '/path/to/resource') - if sys.platform != 'win32': - parsed = url_util.parse('file://path/to/resource') + parsed = url_util.parse('file://path/to/resource') + assert(parsed.scheme == 'file') + expected = convert_to_posix_path( + os.path.abspath( + posixpath.join('path', 'to', 'resource'))) + if is_windows: + expected = expected.lstrip(drive) + assert(parsed.path == expected) + + if is_windows: + parsed = url_util.parse('file://%s\\path\\to\\resource' % drive) assert(parsed.scheme == 'file') - expected = os.path.abspath(posixpath.join('path', 'to', 'resource')) - assert(parsed.path == expected) + expected = '/' + posixpath.join('path', 'to', 'resource') + assert parsed.path == expected parsed = url_util.parse('https://path/to/resource') assert(parsed.scheme == 'https') @@ -48,46 +60,34 @@ def test_url_parse(): assert(parsed.path == '/to/resource') spack_root = spack.paths.spack_root - parsed = url_util.parse('$spack') + parsed = url_util.parse('file://$spack') assert(parsed.scheme == 'file') - if sys.platform != 'win32': - assert(parsed.netloc == '') - if sys.platform == "win32": - spack_root = spack_root.replace('\\', '/') + if is_windows: + spack_root = '/' + convert_to_posix_path(spack_root) assert(parsed.netloc + parsed.path == spack_root) - # Test that sticking the spack root at the end of a posix path resolves - # correctly. - if sys.platform != "win32": - parsed = url_util.parse('/a/b/c/$spack') - assert(parsed.scheme == 'file') - assert(parsed.netloc == '') - expected = os.path.abspath(os.path.join( - '/', 'a', 'b', 'c', './' + spack_root)) - assert(parsed.path == expected) - def test_url_local_file_path(): spack_root = spack.paths.spack_root - + sep = os.path.sep lfp = url_util.local_file_path('/a/b/c.txt') - assert(lfp == '/a/b/c.txt') + assert(lfp == sep + os.path.join('a', 'b', 'c.txt')) lfp = url_util.local_file_path('file:///a/b/c.txt') - assert(lfp == '/a/b/c.txt') + assert(lfp == sep + os.path.join('a', 'b', 'c.txt')) - if sys.platform != "win32": + if is_windows: lfp = url_util.local_file_path('file://a/b/c.txt') expected = os.path.abspath(os.path.join('a', 'b', 'c.txt')) assert(lfp == expected) - lfp = url_util.local_file_path('$spack/a/b/c.txt') + lfp = url_util.local_file_path('file://$spack/a/b/c.txt') expected = os.path.abspath(os.path.join(spack_root, 'a', 'b', 'c.txt')) assert(lfp == expected) - if sys.platform != "win32": + if is_windows: lfp = url_util.local_file_path('file:///$spack/a/b/c.txt') expected = os.path.abspath(os.path.join(spack_root, 'a', 'b', 'c.txt')) assert(lfp == expected) @@ -285,7 +285,7 @@ def test_url_join_absolute_paths(): # ...to work out what resource it points to) if sys.platform == "win32": - cwd.replace('\\', '/') + convert_to_posix_path(cwd) cwd = '/' + cwd # So, even though parse() assumes "file://" URL, the scheme is still diff --git a/lib/spack/spack/test/verification.py b/lib/spack/spack/test/verification.py index fbfefab1c8..ad7373a439 100644 --- a/lib/spack/spack/test/verification.py +++ b/lib/spack/spack/test/verification.py @@ -18,9 +18,10 @@ import spack.util.spack_json as sjson import spack.verify +pytestmark = pytest.mark.skipif(sys.platform == 'win32', + reason='Tests fail on Win') + -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_link_manifest_entry(tmpdir): # Test that symlinks are properly checked against the manifest. # Test that the appropriate errors are generated when the check fails. @@ -120,8 +121,6 @@ def test_file_manifest_entry(tmpdir): assert sorted(results.errors[file]) == sorted(expected) -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_check_chmod_manifest_entry(tmpdir): # Check that the verification properly identifies errors for files whose # permissions have been modified. @@ -195,8 +194,6 @@ def test_check_prefix_manifest(tmpdir): assert results.errors[spec.prefix] == ['manifest corrupted'] -@pytest.mark.skipif(sys.platform == 'win32', - reason="Not supported on Windows (yet)") def test_single_file_verification(tmpdir): # Test the API to verify a single file, including finding the package # to which it belongs diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py index da91414af0..207a904073 100644 --- a/lib/spack/spack/util/environment.py +++ b/lib/spack/spack/util/environment.py @@ -28,8 +28,13 @@ import spack.util.spack_json as sjson from spack.util.path import path_to_os_path, system_path_filter -system_paths = ['/', '/usr', '/usr/local'] -suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64'] +is_windows = sys.platform == 'win32' + +system_paths = ['/', '/usr', '/usr/local'] if \ + not is_windows else ['C:\\', 'C:\\Program Files', + 'C:\\Program Files (x86)', 'C:\\Users', + 'C:\\ProgramData'] +suffixes = ['bin', 'bin64', 'include', 'lib', 'lib64'] if not is_windows else [] system_dirs = [os.path.join(p, s) for s in suffixes for p in system_paths] + \ system_paths diff --git a/lib/spack/spack/util/executable.py b/lib/spack/spack/util/executable.py index 9d8fe5f626..a278fd1f5d 100644 --- a/lib/spack/spack/util/executable.py +++ b/lib/spack/spack/util/executable.py @@ -14,7 +14,7 @@ import llnl.util.tty as tty import spack.error -from spack.util.path import Path, marshall_path, path_to_os_path, system_path_filter +from spack.util.path import Path, format_os_path, path_to_os_path, system_path_filter __all__ = ['Executable', 'which', 'ProcessError'] @@ -24,7 +24,7 @@ class Executable(object): def __init__(self, name): # necesary here for the shlex call to succeed - name = marshall_path(name, mode=Path.unix) + name = format_os_path(name, mode=Path.unix) self.exe = shlex.split(str(name)) # filter back to platform dependent path self.exe = path_to_os_path(*self.exe) @@ -82,7 +82,6 @@ def path(self): """ return self.exe[0] - # needs a small fixup to better handle URLS and the like def __call__(self, *args, **kwargs): """Run this executable in a subprocess. diff --git a/lib/spack/spack/util/file_cache.py b/lib/spack/spack/util/file_cache.py index 5f68911241..f9436ace73 100644 --- a/lib/spack/spack/util/file_cache.py +++ b/lib/spack/spack/util/file_cache.py @@ -170,7 +170,7 @@ def remove(self, key): os.unlink(self.cache_path(key)) finally: lock.release_write() - os.unlink(self._lock_path(key)) + lock.cleanup() class CacheError(SpackError): diff --git a/lib/spack/spack/util/lock.py b/lib/spack/spack/util/lock.py index ff3e0dd14b..75d5c653b6 100644 --- a/lib/spack/spack/util/lock.py +++ b/lib/spack/spack/util/lock.py @@ -45,6 +45,10 @@ def _debug(self, *args): if self._enable: super(Lock, self)._debug(*args) + def cleanup(self, *args): + if self._enable: + super(Lock, self).cleanup(*args) + def check_lock_safety(path): """Do some extra checks to ensure disabling locks is safe. diff --git a/lib/spack/spack/util/parallel.py b/lib/spack/spack/util/parallel.py index c64d0431f9..a931bba0c6 100644 --- a/lib/spack/spack/util/parallel.py +++ b/lib/spack/spack/util/parallel.py @@ -127,7 +127,7 @@ def parallel_map(func, arguments, max_processes=None, debug=False): RuntimeError: if any error occurred in the worker processes """ task_wrapper = Task(func) - if sys.platform != 'darwin': + if sys.platform != 'darwin' and sys.platform != 'win32': with pool(processes=num_processes(max_processes=max_processes)) as p: results = p.map(task_wrapper, arguments) else: diff --git a/lib/spack/spack/util/path.py b/lib/spack/spack/util/path.py index b56ec11ede..fd51acbce7 100644 --- a/lib/spack/spack/util/path.py +++ b/lib/spack/spack/util/path.py @@ -68,9 +68,13 @@ def is_path_url(path): return bool(url_tuple.scheme) and len(url_tuple.scheme) > 1 +def win_exe_ext(): + return '.exe' + + def path_to_os_path(*pths): """ - Takes an arbitrary number of postional parameters + Takes an arbitrary number of positional parameters converts each arguemnt of type string to use a normalized filepath separator, and returns a list of all values """ @@ -78,7 +82,7 @@ def path_to_os_path(*pths): for pth in pths: if type(pth) is str and\ not is_path_url(pth): - pth = marshall_path(pth, mode=Path.platform_path) + pth = convert_to_platform_path(pth) ret_pths.append(pth) return ret_pths @@ -89,7 +93,7 @@ def system_path_filter(_func=None, arg_slice=None): Optional slicing range can be specified to select specific arguments This decorator takes all (or a slice) of a method's positional arguments - and normalizes useage of filepath separators on a per platform basis. + and normalizes usage of filepath separators on a per platform basis. Note: **kwargs, urls, and any type that is not a string are ignored so in such cases where path normalization is required, that should be @@ -121,15 +125,18 @@ def path_filter_caller(*args, **kwargs): def get_system_path_max(): # Choose a conservative default sys_max_path_length = 256 - try: - path_max_proc = subprocess.Popen(['getconf', 'PATH_MAX', '/'], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - proc_output = str(path_max_proc.communicate()[0].decode()) - sys_max_path_length = int(proc_output) - except (ValueError, subprocess.CalledProcessError, OSError): - tty.msg('Unable to find system max path length, using: {0}'.format( - sys_max_path_length)) + if is_windows: + sys_max_path_length = 260 + else: + try: + path_max_proc = subprocess.Popen(['getconf', 'PATH_MAX', '/'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + proc_output = str(path_max_proc.communicate()[0].decode()) + sys_max_path_length = int(proc_output) + except (ValueError, subprocess.CalledProcessError, OSError): + tty.msg('Unable to find system max path length, using: {0}'.format( + sys_max_path_length)) return sys_max_path_length @@ -148,18 +155,21 @@ class Path: else unix -def marshall_path(path, mode=Path.unix): +def format_os_path(path, mode=Path.unix): """ Format path to use consistent, platform specific - separators. + separators. Absolute paths are converted between + drive letters and a prepended '/' as per platform + requirement. Parameters: path (str): the path to be normalized, must be a string or expose the replace method. mode (Path): the path filesperator style to normalize the passed path to. Default is unix style, i.e. '/' - """ + if not path: + return path if mode == Path.windows: path = path.replace('/', '\\') else: @@ -168,11 +178,15 @@ def marshall_path(path, mode=Path.unix): def convert_to_posix_path(path): - return path.replace('\\', '/') + return format_os_path(path, mode=Path.unix) def convert_to_windows_path(path): - return path.replace('/', '\\') + return format_os_path(path, mode=Path.windows) + + +def convert_to_platform_path(path): + return format_os_path(path, mode=Path.platform_path) def substitute_config_variables(path): diff --git a/lib/spack/spack/util/url.py b/lib/spack/spack/util/url.py index 7f7554e838..d63498674b 100644 --- a/lib/spack/spack/util/url.py +++ b/lib/spack/spack/util/url.py @@ -8,7 +8,6 @@ """ import itertools -import ntpath import posixpath import re import sys @@ -16,7 +15,13 @@ import six.moves.urllib.parse as urllib_parse from six import string_types -import spack.util.path +from spack.util.path import ( + canonicalize_path, + convert_to_platform_path, + convert_to_posix_path, +) + +is_windows = sys.platform == 'win32' def _split_all(path): @@ -49,13 +54,11 @@ def local_file_path(url): url = parse(url) if url.scheme == 'file': - is_windows_path = (len(url.netloc) == 2 and - url.netloc[1] == ':' and - 'A' <= url.netloc[0] and - url.netloc[0] <= 'Z') - if is_windows_path: - return ntpath.abspath(ntpath.join(url.netloc, '\\', url.path)) - + if is_windows: + pth = convert_to_platform_path(url.netloc + url.path) + if re.search(r'^\\[A-Za-z]:', pth): + pth = pth.lstrip('\\') + return pth return url.path return None @@ -70,7 +73,11 @@ def parse(url, scheme='file'): Otherwise, the returned value is the same as urllib's urlparse() with allow_fragments=False. """ - + # guarantee a value passed in is of proper url format. Guarantee + # allows for easier string manipulation accross platforms + if isinstance(url, string_types): + require_url_format(url) + url = escape_file_url(url) url_obj = ( urllib_parse.urlparse(url, scheme=scheme, allow_fragments=False) if isinstance(url, string_types) else url) @@ -79,51 +86,25 @@ def parse(url, scheme='file'): scheme = (scheme or 'file').lower() - # This is the first way that a windows path can be parsed. - # (The user leaves out the file:// scheme.) - # examples: - # C:\\a\\b\\c - # X:/a/b/c - is_windows_path = (len(scheme) == 1 and 'a' <= scheme and scheme <= 'z') - if is_windows_path: - netloc = scheme.upper() + ':' - scheme = 'file' - if scheme == 'file': - # If the above windows path case did not hold, check the second case. - if not is_windows_path: - # This is the other way that a windows path can be parsed. - # (The user explicitly provides the file:// scheme.) - # examples: - # file://C:\\a\\b\\c - # file://X:/a/b/c - is_windows_path = (len(netloc) == 2 and - netloc[1] == ':' and - (('A' <= netloc[0] and netloc[0] <= 'Z') or - ('a' <= netloc[0] and netloc[0] <= 'z'))) - if is_windows_path: - netloc = netloc[0].upper() + ':' - path = spack.util.path.canonicalize_path(netloc + path) - path = re.sub(r'\\', '/', path) + # (The user explicitly provides the file:// scheme.) + # examples: + # file://C:\\a\\b\\c + # file://X:/a/b/c + path = canonicalize_path(netloc + path) path = re.sub(r'^/+', '/', path) + netloc = '' - if not is_windows_path: - netloc = '' - - # If canonicalize_path() returns a path with a drive letter (e.g.: on - # windows), we need to pop that part off from the head of the string. - # We also need to set netloc == that part to handle the case of a local - # file path being passed. (e.g.: file://../a/b/c) - update_netloc = (len(path) >= 2 and - path[1] == ':' and - (('A' <= path[0] and path[0] <= 'Z') or - ('a' <= path[0] and path[0] <= 'z'))) - if update_netloc: - netloc, path = path[:2], path[2:] + drive_ltr_lst = re.findall(r'[A-Za-z]:\\', path) + is_win_path = bool(drive_ltr_lst) + if is_windows and is_win_path: + drive_ltr = drive_ltr_lst[0].strip('\\') + path = re.sub(r'[\\]*' + drive_ltr, '', path) + netloc = '/' + drive_ltr.strip('\\') if sys.platform == "win32": - path = path.replace('\\', '/') + path = convert_to_posix_path(path) return urllib_parse.ParseResult(scheme=scheme, netloc=netloc, @@ -199,9 +180,11 @@ def join(base_url, path, *extra, **kwargs): 'file:///opt/spack' """ paths = [ - (x.replace('\\', '/') if isinstance(x, string_types) - else x.geturl().replace('\\', '/')) + (x) if isinstance(x, string_types) + else x.geturl() for x in itertools.chain((base_url, path), extra)] + + paths = [convert_to_posix_path(x) for x in paths] n = len(paths) last_abs_component = None scheme = '' @@ -296,7 +279,7 @@ def _join(base_url, path, *extra, **kwargs): base_path = posixpath.join('', *path_tokens) if sys.platform == "win32": - base_path = base_path.replace('\\', '/') + base_path = convert_to_posix_path(base_path) return format(urllib_parse.ParseResult(scheme=scheme, netloc=netloc, @@ -357,3 +340,16 @@ def parse_git_url(url): raise ValueError("bad port in git url: %s" % url) return (scheme, user, hostname, port, path) + + +def require_url_format(url): + ut = re.search(r'^(file://|http://|https://|ftp://|s3://|/)', url) + assert ut is not None + + +def escape_file_url(url): + drive_ltr = re.findall(r'[A-Za-z]:\\', url) + if is_windows and drive_ltr: + url = url.replace(drive_ltr[0], '/' + drive_ltr[0]) + + return url diff --git a/lib/spack/spack/util/web.py b/lib/spack/spack/util/web.py index b13bde2e98..d3a9d57607 100644 --- a/lib/spack/spack/util/web.py +++ b/lib/spack/spack/util/web.py @@ -32,6 +32,7 @@ import spack.util.s3 as s3_util import spack.util.url as url_util from spack.util.compression import ALLOWED_ARCHIVE_TYPES +from spack.util.path import convert_to_posix_path if sys.version_info < (3, 0): # Python 2 had these in the HTMLParser package. @@ -114,7 +115,7 @@ def read_from_url(url, accept_content_type=None): url_scheme = url.scheme url = url_util.format(url) if sys.platform == "win32" and url_scheme == "file": - url = url.replace("\\", "/") + url = convert_to_posix_path(url) req = Request(url) content_type = None @@ -652,7 +653,7 @@ def find_versions_of_archive( versions = {} matched = set() for url in archive_urls + sorted(links): - url = url.replace("\\", "/") + url = convert_to_posix_path(url) if any(re.search(r, url) for r in regexes): try: ver = spack.url.parse_version(url) diff --git a/share/spack/qa/windows_test_setup.ps1 b/share/spack/qa/windows_test_setup.ps1 index eebd0b7480..a7e3c66ea3 100644 --- a/share/spack/qa/windows_test_setup.ps1 +++ b/share/spack/qa/windows_test_setup.ps1 @@ -8,4 +8,4 @@ foreach { $v = $_.split("=") [Environment]::SetEnvironmentVariable($v[0], $v[1]) } -} \ No newline at end of file +} diff --git a/var/spack/repos/builtin.mock/packages/cmake-client/package.py b/var/spack/repos/builtin.mock/packages/cmake-client/package.py index 09b445fd49..0e8d1a3d9b 100644 --- a/var/spack/repos/builtin.mock/packages/cmake-client/package.py +++ b/var/spack/repos/builtin.mock/packages/cmake-client/package.py @@ -94,6 +94,8 @@ def install(self, spec, prefix): # check that which('cmake') returns the right one. cmake = which('cmake') + print(cmake) + print(cmake.exe) check(cmake.exe[0].startswith(spec['cmake'].prefix.bin), "Wrong cmake was in environment: %s" % cmake) diff --git a/var/spack/repos/builtin.mock/packages/cmake/package.py b/var/spack/repos/builtin.mock/packages/cmake/package.py index e5dd7057d1..8c19ca8a6e 100644 --- a/var/spack/repos/builtin.mock/packages/cmake/package.py +++ b/var/spack/repos/builtin.mock/packages/cmake/package.py @@ -4,9 +4,12 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import sys from spack import * +is_windows = sys.platform == 'win32' + def check(condition, msg): """Raise an install error if condition is False.""" @@ -43,7 +46,7 @@ def install(self, spec, prefix): check(os.environ['for_install'] == 'for_install', "Couldn't read env var set in compile envieonmnt") - - cmake_exe = join_path(prefix.bin, 'cmake') + cmake_exe_ext = ".exe" if is_windows else '' + cmake_exe = join_path(prefix.bin, 'cmake{}'.format(cmake_exe_ext)) touch(cmake_exe) set_executable(cmake_exe) diff --git a/var/spack/repos/builtin.mock/packages/find-externals1/package.py b/var/spack/repos/builtin.mock/packages/find-externals1/package.py index 9200668d7c..c85598e891 100644 --- a/var/spack/repos/builtin.mock/packages/find-externals1/package.py +++ b/var/spack/repos/builtin.mock/packages/find-externals1/package.py @@ -20,11 +20,11 @@ def determine_spec_details(cls, prefix, exes_in_prefix): exe_to_path = dict( (os.path.basename(p), p) for p in exes_in_prefix ) - if 'find-externals1-exe' not in exe_to_path: - return None - + exes = [x for x in exe_to_path.keys() if 'find-externals1-exe' in x] + if not exes: + return exe = spack.util.executable.Executable( - exe_to_path['find-externals1-exe']) + exe_to_path[exes[0]]) output = exe('--version', output=str) if output: match = re.search(r'find-externals1.*version\s+(\S+)', output) diff --git a/var/spack/repos/builtin.mock/packages/trivial-install-test-package/package.py b/var/spack/repos/builtin.mock/packages/trivial-install-test-package/package.py index 748034baca..467a1631fa 100644 --- a/var/spack/repos/builtin.mock/packages/trivial-install-test-package/package.py +++ b/var/spack/repos/builtin.mock/packages/trivial-install-test-package/package.py @@ -2,7 +2,6 @@ # Spack Project Developers. See the top-level COPYRIGHT file for details. # # SPDX-License-Identifier: (Apache-2.0 OR MIT) - from spack import * @@ -15,6 +14,4 @@ class TrivialInstallTestPackage(Package): version('1.0', '0123456789abcdef0123456789abcdef') def install(self, spec, prefix): - configure('--prefix=%s' % prefix) - make() - make('install') + touch(join_path(prefix, 'an_installation_file')) diff --git a/var/spack/repos/builtin/packages/openssl/package.py b/var/spack/repos/builtin/packages/openssl/package.py index 94c1dccf4c..55b949ea9a 100644 --- a/var/spack/repos/builtin/packages/openssl/package.py +++ b/var/spack/repos/builtin/packages/openssl/package.py @@ -5,7 +5,6 @@ import os import re -import sys import llnl.util.tty as tty @@ -98,8 +97,6 @@ class Openssl(Package): # Uses Fake Autotools, should subclass Package depends_on('perl@5.14.0:', type=('build', 'test')) depends_on('ca-certificates-mozilla', type=('build', 'run'), when='certs=mozilla') - conflicts('+dynamic', when=sys.platform != 'win32') - @classmethod def determine_version(cls, exe): output = Executable(exe)('version', output=str, error=str) @@ -141,39 +138,32 @@ def install(self, spec, prefix): options.append('-D__STDC_NO_ATOMICS__') # Make a flag for shared library builds - shared_flag = '' - if spec.satisfies('~shared'): - shared_flag = 'no-shared' - - def configure_args(): - base_args = ['--prefix=%s' % prefix, - '--openssldir=%s' - % join_path(prefix, 'etc', 'openssl')] - if spec.satisfies('platform=windows'): - base_args.extend([ - 'CC=%s' % os.environ.get('CC'), - 'CXX=%s' % os.environ.get('CXX'), - '%s' % shared_flag, - 'VC-WIN64A', - ]) - base_args.insert(0, 'Configure') - else: - base_args.extend( - [ - '-I{0}'.format(self.spec['zlib'].prefix.include), - '-L{0}'.format(self.spec['zlib'].prefix.lib) - ] - ) - base_args.extend(options) - return base_args + base_args = ['--prefix=%s' % prefix, + '--openssldir=%s' + % join_path(prefix, 'etc', 'openssl')] + if spec.satisfies('platform=windows'): + base_args.extend([ + 'CC=%s' % os.environ.get('CC'), + 'CXX=%s' % os.environ.get('CXX'), + 'VC-WIN64A', + ]) + if spec.satisfies('~shared'): + base_args.append('no-shared') + else: + base_args.extend( + [ + '-I{0}'.format(self.spec['zlib'].prefix.include), + '-L{0}'.format(self.spec['zlib'].prefix.lib) + ] + ) + base_args.extend(options) # On Windows, we use perl for configuration and build through MSVC # nmake. if spec.satisfies('platform=windows'): - config = Executable('perl') + Executable('perl')('Configure', *base_args) else: - config = Executable('./config') + Executable('./config')(*base_args) - config(*configure_args()) # Remove non-standard compiler options if present. These options are # present e.g. on Darwin. They are non-standard, i.e. most compilers # (e.g. gcc) will not accept them. @@ -183,10 +173,6 @@ def configure_args(): # This variant only makes sense for Windows if spec.satisfies('platform=windows'): filter_file(r'MT', 'MD', 'makefile') - else: - tty.warn("Dynamic runtime builds are only available for " - "Windows operating systems. Please disable " - "+dynamic to suppress this warning.") if spec.satisfies('platform=windows'): host_make = nmake diff --git a/var/spack/repos/builtin/packages/python/package.py b/var/spack/repos/builtin/packages/python/package.py index d0499b7c49..85e9d8ec44 100644 --- a/var/spack/repos/builtin/packages/python/package.py +++ b/var/spack/repos/builtin/packages/python/package.py @@ -4,17 +4,16 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import glob -import inspect import json import os +import platform import re import subprocess import sys -from distutils.dir_util import copy_tree from shutil import copy import llnl.util.tty as tty -from llnl.util.filesystem import get_filetype, path_contains_subdirectory +from llnl.util.filesystem import copy_tree, get_filetype, path_contains_subdirectory from llnl.util.lang import match_predicate from spack import * @@ -46,7 +45,6 @@ class Python(Package): version('3.10.0', sha256='c4e0cbad57c90690cb813fb4663ef670b4d0f587d8171e2c42bd4c9245bd2758') version('3.9.10', sha256='1aa9c0702edbae8f6a2c95f70a49da8420aaa76b7889d3419c186bfc8c0e571e', preferred=True) version('3.9.9', sha256='2cc7b67c1f3f66c571acc42479cdf691d8ed6b47bee12c9b68430413a17a44ea') - version('3.9.9', sha256='2cc7b67c1f3f66c571acc42479cdf691d8ed6b47bee12c9b68430413a17a44ea') version('3.9.8', sha256='7447fb8bb270942d620dd24faa7814b1383b61fa99029a240025fd81c1db8283') version('3.9.7', sha256='a838d3f9360d157040142b715db34f0218e535333696a5569dc6f854604eb9d1') version('3.9.6', sha256='d0a35182e19e416fc8eae25a3dcd4d02d4997333e4ad1f2eee6010aadc3fe866') @@ -226,7 +224,6 @@ class Python(Package): patch('python-3.7.4+-distutils-C++.patch', when='@3.7.4:') patch('python-3.7.4+-distutils-C++-testsuite.patch', when='@3.7.4:') patch('cpython-windows-externals.patch', when='@:3.9.6 platform=windows') - patch('tkinter.patch', when='@:2.8,3.3:3.7 platform=darwin') # Patch the setup script to deny that tcl/x11 exists rather than allowing # autodetection of (possibly broken) system components @@ -680,7 +677,7 @@ def build(self, spec, prefix): # See https://autotools.io/automake/silent.html params = ['V=1'] params += self.build_targets - inspect.getmodule(self).make(*params) + make(*params) def install(self, spec, prefix): """Makes the install targets specified by @@ -690,7 +687,7 @@ def install(self, spec, prefix): if is_windows: self.win_installer(prefix) else: - inspect.getmodule(self).make(*self.install_targets) + make(*self.install_targets) @run_after('install') def filter_compilers(self): @@ -909,7 +906,6 @@ def config_vars(self): Returns: dict: variable definitions """ - cmd = """ import json from sysconfig import ( diff --git a/var/spack/repos/builtin/packages/wrf/package.py b/var/spack/repos/builtin/packages/wrf/package.py index 84c8f9dafa..2c8c2f552a 100644 --- a/var/spack/repos/builtin/packages/wrf/package.py +++ b/var/spack/repos/builtin/packages/wrf/package.py @@ -6,8 +6,6 @@ import glob import re import time -from fcntl import F_GETFL, F_SETFL, fcntl -from os import O_NONBLOCK from os.path import basename from subprocess import PIPE, Popen from sys import platform, stdout @@ -20,9 +18,7 @@ if not is_windows: from fcntl import F_GETFL, F_SETFL, fcntl - from os import O_NONBLOCK, rename -else: - from os import rename + from os import O_NONBLOCK re_optline = re.compile(r'\s+[0-9]+\..*\((serial|smpar|dmpar|dm\+sm)\)\s+') re_paroptname = re.compile(r'\((serial|smpar|dmpar|dm\+sm)\)')