Documentation for dependency patching.
This commit is contained in:
parent
4f8c7d57eb
commit
96d2488e0c
@ -1212,27 +1212,47 @@ structure like this:
|
||||
package.py
|
||||
ad_lustre_rwcontig_open_source.patch
|
||||
|
||||
If you supply a URL instead of a filename, you need to supply a checksum,
|
||||
like this:
|
||||
If you supply a URL instead of a filename, you need to supply a
|
||||
``sha256`` checksum, like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
patch('http://www.nwchem-sw.org/images/Tddft_mxvec20.patch',
|
||||
sha256='252c0af58be3d90e5dc5e0d16658434c9efa5d20a5df6c10bf72c2d77f780866')
|
||||
|
||||
Spack includes the hashes of patches in its versioning information, so
|
||||
that the same package with different patches applied will have different
|
||||
hash identifiers. To ensure that the hashing scheme is consistent, you
|
||||
must use a ``sha256`` checksum for the patch. Patches will be fetched
|
||||
from their URLs, checked, and applied to your source code. You can use
|
||||
the ``spack sha256`` command to generate a checksum for a patch file or
|
||||
URL.
|
||||
|
||||
Spack can also handle compressed patches. If you use these, Spack needs
|
||||
a little more help. Specifically, it needs *two* checksums: the
|
||||
``sha256`` of the patch and ``archive_sha256`` for the compressed
|
||||
archive. ``archive_sha256`` helps Spack ensure that the downloaded
|
||||
file is not corrupted or malicious, before running it through a tool like
|
||||
``tar`` or ``zip``. The ``sha256`` of the patch is still required so
|
||||
that it can be included in specs. Providing it in the package file
|
||||
ensures that Spack won't have to download and decompress patches it won't
|
||||
end up using at install time. Both the archive and patch checksum are
|
||||
checked when patch archives are downloaded.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
patch('http://www.nwchem-sw.org/images/Tddft_mxvec20.patch.gz',
|
||||
md5='f91c6a04df56e228fe946291d2f38c9a')
|
||||
sha256='252c0af58be3d90e5dc5e0d16658434c9efa5d20a5df6c10bf72c2d77f780866',
|
||||
archive_sha256='4e8092a161ec6c3a1b5253176fcf33ce7ba23ee2ff27c75dbced589dabacd06e')
|
||||
|
||||
This directive provides an ``md5`` checksum. You can use other hashing
|
||||
algorihtms like ``sha256`` as well. The patch will be fetched from the
|
||||
URL, checked, and applied to your source code. You can use the ``spack
|
||||
md5`` command to generate a checksum for a patch file.
|
||||
``patch`` keyword arguments are described below.
|
||||
|
||||
``patch`` can take two options keyword arguments. They are:
|
||||
""""""""""""""""""""""""""""""
|
||||
``sha256``, ``archive_sha256``
|
||||
""""""""""""""""""""""""""""""
|
||||
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
``md5``, ``sha256``, ``sha512``, etc.
|
||||
""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Use one of these when you supply a patch to be downloaded from a remote
|
||||
site. The downloaded file will be validated using the given checksum.
|
||||
Hashes of downloaded patch and compressed archive, respectively. Only
|
||||
needed for patches fetched from URLs.
|
||||
|
||||
""""""""
|
||||
``when``
|
||||
@ -1309,6 +1329,21 @@ if you run install, hit ctrl-C, and run install again, the code in the
|
||||
patch function is only run once. Also, you can tell Spack to run only
|
||||
the patching part of the build using the :ref:`cmd-spack-patch` command.
|
||||
|
||||
.. _patch_dependency_patching:
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
Dependency patching
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
So far we've covered how the ``patch`` directive can be used by a package
|
||||
to patch *its own* source code. Packages can *also* specify patches to be
|
||||
applied to their dependencies, if they require special modifications. As
|
||||
with all packages in Spack, a patched dependency library can coexist with
|
||||
other versions of that library. See the `section on depends_on
|
||||
<dependency_dependency_patching_>`_ for more details.
|
||||
|
||||
.. _handling_rpaths:
|
||||
|
||||
---------------
|
||||
Handling RPATHs
|
||||
---------------
|
||||
@ -1482,7 +1517,7 @@ particular constraints, and package authors can use specs to describe
|
||||
relationships between packages.
|
||||
|
||||
^^^^^^^^^^^^^^
|
||||
Version Ranges
|
||||
Version ranges
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Although some packages require a specific version for their dependencies,
|
||||
@ -1530,7 +1565,7 @@ correct way to specify this would be:
|
||||
|
||||
|
||||
^^^^^^^^^^^^^^^^
|
||||
Dependency Types
|
||||
Dependency types
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
Not all dependencies are created equal, and Spack allows you to specify
|
||||
@ -1566,6 +1601,91 @@ inject the dependency's ``prefix/lib`` directory, but the package needs to
|
||||
be in ``PATH`` and ``PYTHONPATH`` during the build process and later when
|
||||
a user wants to run the package.
|
||||
|
||||
.. _dependency_dependency_patching:
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
Dependency patching
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Some packages maintain special patches on their dependencies, either to
|
||||
add new features or to fix bugs. This typically makes a package harder
|
||||
to maintain, and we encourage developers to upstream (contribute back)
|
||||
their changes rather than maintaining patches. However, in some cases
|
||||
it's not possible to upstream. Maybe the dependency's developers don't
|
||||
accept changes, or maybe they just haven't had time to integrate them.
|
||||
|
||||
For times like these, Spack's ``depends_on`` directive can optionally
|
||||
take a patch or list of patches:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class SpecialTool(Package):
|
||||
...
|
||||
depends_on('binutils', patches='special-binutils-feature.patch')
|
||||
...
|
||||
|
||||
Here, the ``special-tool`` package requires a special feature in
|
||||
``binutils``, so it provides an extra ``patches=<filename>`` keyword
|
||||
argument. This is similar to the `patch directive <patching_>`_, with
|
||||
one small difference. Here, ``special-tool`` is responsible for the
|
||||
patch, so it should live in ``special-tool``'s directory in the package
|
||||
repository, not the ``binutils`` directory.
|
||||
|
||||
If you need something more sophisticated than this, you can simply nest a
|
||||
``patch()`` directive inside of ``depends_on``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class SpecialTool(Package):
|
||||
...
|
||||
depends_on(
|
||||
'binutils',
|
||||
patches=patch('special-binutils-feature.patch',
|
||||
level=3,
|
||||
when='@:1.3'), # condition on binutils
|
||||
when='@2.0:') # condition on special-tool
|
||||
...
|
||||
|
||||
Note that there are two optional ``when`` conditions here -- one on the
|
||||
``patch`` directive and the other on ``depends_on``. The condition in
|
||||
the ``patch`` directive applies to ``binutils`` (the package being
|
||||
patched), while the condition in ``depends_on`` applies to
|
||||
``special-tool``. See `patch directive <patching_>`_ for details on all
|
||||
the arguments the ``patch`` directive can take.
|
||||
|
||||
Finally, if you need *multiple* patches on a dependency, you can provide
|
||||
a list for ``patches``, e.g.:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class SpecialTool(Package):
|
||||
...
|
||||
depends_on(
|
||||
'binutils',
|
||||
patches=[
|
||||
'binutils-bugfix1.patch',
|
||||
'binutils-bugfix2.patch',
|
||||
patch('https://example.com/special-binutils-feature.patch',
|
||||
sha256='252c0af58be3d90e5dc5e0d16658434c9efa5d20a5df6c10bf72c2d77f780866',
|
||||
when='@:1.3')],
|
||||
when='@2.0:')
|
||||
...
|
||||
|
||||
As with ``patch`` directives, patches are applied in the order they
|
||||
appear in the package file (or in this case, in the list).
|
||||
|
||||
.. note::
|
||||
|
||||
You may wonder whether dependency patching will interfere with other
|
||||
packages that depend on ``binutils``. It won't.
|
||||
|
||||
As described in patching_, Patching a package adds the ``sha256`` of
|
||||
the patch to the package's spec, which means it will have a
|
||||
*different* unique hash than other versions without the patch. The
|
||||
patched version coexists with unpatched versions, and Spack's support
|
||||
for handling_rpaths_ guarantees that each installation finds the
|
||||
right version. If two packages depend on ``binutils`` patched *the
|
||||
same* way, they can both use a single installation of ``binutils``.
|
||||
|
||||
.. _setup-dependent-environment:
|
||||
|
||||
|
@ -42,13 +42,15 @@ def setup_parser(subparser):
|
||||
help="files/urls to checksum")
|
||||
|
||||
|
||||
def compute_md5_checksum(url):
|
||||
def compute_checksum(url, algo):
|
||||
algo = getattr(hashlib, algo)
|
||||
|
||||
if not os.path.isfile(url):
|
||||
with Stage(url) as stage:
|
||||
stage.fetch()
|
||||
value = spack.util.crypto.checksum(hashlib.md5, stage.archive_file)
|
||||
value = spack.util.crypto.checksum(algo, stage.archive_file)
|
||||
else:
|
||||
value = spack.util.crypto.checksum(hashlib.md5, url)
|
||||
value = spack.util.crypto.checksum(algo, url)
|
||||
return value
|
||||
|
||||
|
||||
@ -61,7 +63,7 @@ def normalized(files):
|
||||
yield value
|
||||
|
||||
|
||||
def md5(parser, args):
|
||||
def do_checksum(parser, args, algo):
|
||||
if not args.files:
|
||||
setup_parser.parser.print_help()
|
||||
return 1
|
||||
@ -70,7 +72,7 @@ def md5(parser, args):
|
||||
results = []
|
||||
for url in urls:
|
||||
try:
|
||||
checksum = compute_md5_checksum(url)
|
||||
checksum = compute_checksum(url, algo)
|
||||
results.append((checksum, url))
|
||||
except FailedDownloadError as e:
|
||||
tty.warn("Failed to fetch %s" % url)
|
||||
@ -79,8 +81,12 @@ def md5(parser, args):
|
||||
tty.warn("Error when reading %s" % url)
|
||||
tty.warn("%s" % e)
|
||||
|
||||
# Dump the MD5s at last without interleaving them with downloads
|
||||
# Dump the hashes last, without interleaving them with downloads
|
||||
checksum = 'checksum' if len(results) == 1 else 'checksums'
|
||||
tty.msg("%d MD5 %s:" % (len(results), checksum))
|
||||
tty.msg("%d %s %s:" % (len(results), algo, checksum))
|
||||
for checksum, url in results:
|
||||
print("{0} {1}".format(checksum, url))
|
||||
|
||||
|
||||
def md5(parser, args):
|
||||
do_checksum(parser, args, 'md5')
|
||||
|
40
lib/spack/spack/cmd/sha256.py
Normal file
40
lib/spack/spack/cmd/sha256.py
Normal file
@ -0,0 +1,40 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2013-2017, Lawrence Livermore National Security, LLC.
|
||||
# Produced at the Lawrence Livermore National Laboratory.
|
||||
#
|
||||
# This file is part of Spack.
|
||||
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||
# LLNL-CODE-647188
|
||||
#
|
||||
# For details, see https://github.com/llnl/spack
|
||||
# Please also see the NOTICE and LICENSE files for our notice and the LGPL.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License (as
|
||||
# published by the Free Software Foundation) version 2.1, February 1999.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
|
||||
# conditions of the GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
from spack.cmd.md5 import do_checksum
|
||||
|
||||
description = "calculate sha256 checksums for files/urls"
|
||||
section = "packaging"
|
||||
level = "long"
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
setup_parser.parser = subparser
|
||||
subparser.add_argument('files', nargs=argparse.REMAINDER,
|
||||
help="files/urls to checksum")
|
||||
|
||||
|
||||
def sha256(parser, args):
|
||||
do_checksum(parser, args, 'sha256')
|
Loading…
Reference in New Issue
Block a user