'Calls do_stage(), then applied patches to the expanded tarball if they
haven\'t been applied already.'

def do_patch(self):

    if (not self.spec.concrete):
        raise ValueError('Can    only    patch    concrete    packages.')
    self.do_stage()
    has_patch_fun = (hasattr(self, 'patch') and callable(self.patch))
    if ((not self.patches) and (not has_patch_fun)):
        tty.msg(('No    patches    needed    for    %s' % self.name))
        return
    archive_dir = self.stage.source_path
    good_file = join_path(archive_dir, '.spack_patched')
    no_patches_file = join_path(archive_dir, '.spack_no_patches')
    bad_file = join_path(archive_dir, '.spack_patch_failed')
    if os.path.isfile(bad_file):
        tty.msg('Patching    failed    last    time.    Restaging.')
        self.stage.restage()
    self.stage.chdir_to_source()
    if os.path.isfile(good_file):
        tty.msg(('Already    patched    %s' % self.name))
        return
    elif os.path.isfile(no_patches_file):
        tty.msg(('No    patches    needed    for    %s' % self.name))
        return
    patched = False
    for (spec, patch_list) in self.patches.items():
        if self.spec.satisfies(spec):
            for patch in patch_list:
                try:
                    patch.apply(self.stage)
                    tty.msg(('Applied    patch    %s' % patch.path_or_url))
                    patched = True
                except:
                    tty.msg(('Patch    %s    failed.' % patch.path_or_url))
                    touch(bad_file)
                    raise
    if has_patch_fun:
        try:
            self.patch()
            tty.msg(('Ran    patch()    for    %s' % self.name))
            patched = True
        except spack.multimethod.NoSuchMethodError:
            tty.msg(('No    patches    needed    for    %s' % self.name))
        except:
            tty.msg(('patch()    function    failed    for    %s' % self.name))
            touch(bad_file)
            raise
    if os.path.isfile(bad_file):
        os.remove(bad_file)
    if patched:
        touch(good_file)
    else:
        touch(no_patches_file)
