def do_patch()

in lib/ramble/spack/package.py [0:0]


    def do_patch(self):
        """Applies patches if they haven't been applied already."""
        if not self.spec.concrete:
            raise ValueError("Can only patch concrete packages.")

        # Kick off the stage first.  This creates the stage.
        self.do_stage()

        # Package can add its own patch function.
        has_patch_fun = hasattr(self, 'patch') and callable(self.patch)

        # Get the patches from the spec (this is a shortcut for the MV-variant)
        patches = self.spec.patches

        # If there are no patches, note it.
        if not patches and not has_patch_fun:
            tty.msg('No patches needed for {0}'.format(self.name))
            return

        # Construct paths to special files in the archive dir used to
        # keep track of whether patches were successfully applied.
        archive_dir = self.stage.source_path
        good_file = os.path.join(archive_dir, '.spack_patched')
        no_patches_file = os.path.join(archive_dir, '.spack_no_patches')
        bad_file = os.path.join(archive_dir, '.spack_patch_failed')

        # If we encounter an archive that failed to patch, restage it
        # so that we can apply all the patches again.
        if os.path.isfile(bad_file):
            tty.debug('Patching failed last time. Restaging.')
            self.stage.restage()

        # If this file exists, then we already applied all the patches.
        if os.path.isfile(good_file):
            tty.msg('Already patched {0}'.format(self.name))
            return
        elif os.path.isfile(no_patches_file):
            tty.msg('No patches needed for {0}'.format(self.name))
            return

        # Apply all the patches for specs that match this one
        patched = False
        for patch in patches:
            try:
                with fsys.working_dir(self.stage.source_path):
                    patch.apply(self.stage)
                tty.msg('Applied patch {0}'.format(patch.path_or_url))
                patched = True
            except spack.error.SpackError as e:
                tty.debug(e)

                # Touch bad file if anything goes wrong.
                tty.msg('Patch %s failed.' % patch.path_or_url)
                fsys.touch(bad_file)
                raise

        if has_patch_fun:
            try:
                with fsys.working_dir(self.stage.source_path):
                    self.patch()
                tty.msg('Ran patch() for {0}'.format(self.name))
                patched = True
            except spack.multimethod.NoSuchMethodError:
                # We are running a multimethod without a default case.
                # If there's no default it means we don't need to patch.
                if not patched:
                    # if we didn't apply a patch from a patch()
                    # directive, AND the patch function didn't apply, say
                    # no patches are needed.  Otherwise, we already
                    # printed a message for each patch.
                    tty.msg('No patches needed for {0}'.format(self.name))
            except spack.error.SpackError as e:
                tty.debug(e)

                # Touch bad file if anything goes wrong.
                tty.msg('patch() function failed for {0}'.format(self.name))
                fsys.touch(bad_file)
                raise

        # Get rid of any old failed file -- patches have either succeeded
        # or are not needed.  This is mostly defensive -- it's needed
        # if the restage() method doesn't clean *everything* (e.g., for a repo)
        if os.path.isfile(bad_file):
            os.remove(bad_file)

        # touch good or no patches file so that we skip next time.
        if patched:
            fsys.touch(good_file)
        else:
            fsys.touch(no_patches_file)