Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Remove use of stage symlinks #12072

Merged
merged 19 commits into from Aug 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 18 additions & 8 deletions etc/spack/defaults/config.yaml
Expand Up @@ -37,18 +37,28 @@ config:

# Temporary locations Spack can try to use for builds.
#
# Spack will use the first one it finds that exists and is writable.
# You can use $tempdir to refer to the system default temp directory
# (as returned by tempfile.gettempdir()).
# Recommended options are given below.
#
# A value of $spack/var/spack/stage indicates that Spack should run
# builds directly inside its install directory without staging them in
# Builds can be faster in temporary directories on some (e.g., HPC) systems.
# Specifying `$tempdir` will ensure use of the system default temporary
# directory (as returned by `tempfile.gettempdir()`). Spack will append
# `spack-stage` and, if the username is not already in the path, the value
# of `$user` to the path. The latter is used to avoid conflicts between
# users in shared temporary spaces.
#
# Another option that prevents conflicts and potential permission issues is
# to specify `~/.spack/stage`, which ensures each user builds in their home
# directory.
#
# A more traditional path uses the value of `$spack/var/spack/stage`, which
# builds directly inside Spack's instance without staging them in a
# temporary space.
#
# The build stage can be purged with `spack clean --stage`.
# The build stage can be purged with `spack clean --stage` and
# `spack clean -a`, so it is important that the specified directory uniquely
# identifies Spack staging to avoid accidentally wiping out non-Spack work.
build_stage:
- $tempdir
- $spack/var/spack/stage
- $tempdir/spack-stage


# Cache directory for already downloaded source tarballs and archived
Expand Down
31 changes: 16 additions & 15 deletions lib/spack/docs/config_yaml.rst
Expand Up @@ -85,38 +85,39 @@ See :ref:`modules` for details.

Spack is designed to run out of a user home directory, and on many
systems the home directory is a (slow) network file system. On most systems,
building in a temporary file system results in faster builds than building
in the home directory. Usually, there is also more space available in
the temporary location than in the home directory. So, Spack tries to
create build stages in temporary space.
building in a temporary file system is faster. Usually, there is also more
space available in the temporary location than in the home directory. If the
username is not already in the path, Spack will also append the value of
`$user` to the path.

.. warning:: We highly recommend appending `spack-stage` to `$tempdir` in order
to ensure `spack clean` does not delete everything in `$tempdir`.

By default, Spack's ``build_stage`` is configured like this:

.. code-block:: yaml

build_stage:
- $tempdir
- $spack/var/spack/stage
- $tempdir/spack-stage

This is an ordered list of paths that Spack should search when trying to
This can be an ordered list of paths that Spack should search when trying to
find a temporary directory for the build stage. The list is searched in
order, and Spack will use the first directory to which it has write access.
See :ref:`config-file-variables` for more on ``$tempdir`` and ``$spack``.
Specifying `~/.spack/stage` first will ensure each user builds in their home
directory. The historic Spack stage path `$spack/var/spack/stage` will build
directly inside the Spack instance. See :ref:`config-file-variables` for more
on ``$tempdir`` and ``$spack``.

When Spack builds a package, it creates a temporary directory within the
``build_stage``, and it creates a symbolic link to that directory in
``$spack/var/spack/stage``. This is used to track the temporary
directory. After the package is successfully installed, Spack deletes
``build_stage``. After the package is successfully installed, Spack deletes
the temporary directory it used to build. Unsuccessful builds are not
deleted, but you can manually purge them with :ref:`spack clean --stage
<cmd-spack-clean>`.

.. note::

The last item in the list is ``$spack/var/spack/stage``. If this is the
only writable directory in the ``build_stage`` list, Spack will build
*directly* in ``$spack/var/spack/stage`` and will not link to temporary
space.
The build will fail if there is no writable directory in the ``build_stage``
list.

--------------------
``source_cache``
Expand Down
20 changes: 15 additions & 5 deletions lib/spack/llnl/util/filesystem.py
Expand Up @@ -347,12 +347,22 @@ def copy_tree(src, dest, symlinks=True, ignore=None, _permissions=False):
else:
tty.debug('Copying {0} to {1}'.format(src, dest))

mkdirp(dest)
abs_src = os.path.abspath(src)
if not abs_src.endswith(os.path.sep):
abs_src += os.path.sep
abs_dest = os.path.abspath(dest)
if not abs_dest.endswith(os.path.sep):
abs_dest += os.path.sep

# Stop early to avoid unnecessary recursion if being asked to copy from a
# parent directory.
if abs_dest.startswith(abs_src):
tldahlgren marked this conversation as resolved.
Show resolved Hide resolved
raise ValueError('Cannot copy ancestor directory {0} into {1}'.
format(abs_src, abs_dest))

src = os.path.abspath(src)
dest = os.path.abspath(dest)
mkdirp(dest)

for s, d in traverse_tree(src, dest, order='pre',
for s, d in traverse_tree(abs_src, abs_dest, order='pre',
follow_symlinks=not symlinks,
ignore=ignore,
follow_nonexisting=True):
Expand All @@ -361,7 +371,7 @@ def copy_tree(src, dest, symlinks=True, ignore=None, _permissions=False):
if symlinks:
target = os.readlink(s)
if os.path.isabs(target):
new_target = re.sub(src, dest, target)
new_target = re.sub(abs_src, abs_dest, target)
if new_target != target:
tty.debug("Redirecting link {0} to {1}"
.format(target, new_target))
Expand Down
3 changes: 2 additions & 1 deletion lib/spack/spack/cmd/location.py
Expand Up @@ -14,6 +14,7 @@
import spack.environment
import spack.paths
import spack.repo
import spack.stage

description = "print out locations of packages and spack directories"
section = "basic"
Expand Down Expand Up @@ -76,7 +77,7 @@ def location(parser, args):
print(spack.repo.path.first_repo().root)

elif args.stages:
print(spack.paths.stage_path)
print(spack.stage.get_stage_root())

else:
specs = spack.cmd.parse_specs(args.spec)
Expand Down
3 changes: 2 additions & 1 deletion lib/spack/spack/compilers/clang.py
Expand Up @@ -12,6 +12,7 @@
import llnl.util.tty as tty

import spack.paths
import spack.stage
from spack.compiler import Compiler, UnsupportedCompilerFlag
from spack.util.executable import Executable
from spack.version import ver
Expand Down Expand Up @@ -279,7 +280,7 @@ def setup_custom_environment(self, pkg, env):
raise OSError(msg)

real_root = os.path.dirname(os.path.dirname(real_root))
developer_root = os.path.join(spack.paths.stage_path,
developer_root = os.path.join(spack.stage.get_stage_root(),
'xcode-select',
self.name,
str(self.version))
Expand Down
1 change: 1 addition & 0 deletions lib/spack/spack/config.py
Expand Up @@ -101,6 +101,7 @@
'checksum': True,
'dirty': False,
'build_jobs': min(16, multiprocessing.cpu_count()),
'build_stage': '$tempdir/spack-stage',
}
}

Expand Down
4 changes: 1 addition & 3 deletions lib/spack/spack/package.py
Expand Up @@ -1756,9 +1756,7 @@ def check_for_unfinished_installation(
else:
partial = True

stage_is_managed_in_spack = self.stage.path.startswith(
spack.paths.stage_path)
if restage and stage_is_managed_in_spack:
if restage and self.stage.managed_by_spack:
self.stage.destroy()
self.stage.create()

Expand Down
5 changes: 2 additions & 3 deletions lib/spack/spack/patch.py
Expand Up @@ -192,9 +192,8 @@ def fetch(self, stage):
fetch_digest = self.archive_sha256

fetcher = fs.URLFetchStrategy(self.url, fetch_digest)
mirror = os.path.join(
os.path.dirname(stage.mirror_path),
os.path.basename(self.url))
mirror = os.path.join(os.path.dirname(stage.mirror_path),
os.path.basename(self.url))

self.stage = spack.stage.Stage(fetcher, mirror_path=mirror)
self.stage.create()
Expand Down
1 change: 0 additions & 1 deletion lib/spack/spack/paths.py
Expand Up @@ -38,7 +38,6 @@
test_path = os.path.join(module_path, "test")
hooks_path = os.path.join(module_path, "hooks")
var_path = os.path.join(prefix, "var", "spack")
stage_path = os.path.join(var_path, "stage")
repos_path = os.path.join(var_path, "repos")
share_path = os.path.join(prefix, "share", "spack")

Expand Down