From 50df071ad9a1b936ffbb4121036a36ed5ab38ffa Mon Sep 17 00:00:00 2001
From: "Adam J. Stewart" <ajstewart426@gmail.com>
Date: Mon, 3 Apr 2017 17:34:16 -0500
Subject: [PATCH] Overhaul Spack's URL parsing (#2972)

* Remove fake URLs from Spack

* Ignore long lines for URLs that start with ftp:

* Preliminary changes to version regexes

* New redesign of version regexes

* Allow letters in version-only

* Fix detection of versions that end in Final

* Rearrange a few regexes and add examples

* Add tests for common download repositories

* Add test cases for common tarball naming schemes

* Finalize version regexes

* spack url test -> spack url summary

* Clean up comments

* Rearrange suffix checks

* Use query strings for name detection

* Remove no longer necessary url_for_version functions

* Strip off extraneous information after package name

* Add one more test

* Dot in square brackets does not need to be escaped

* Move renaming outside of parse_name_offset

* Fix versions for a couple more packages

* Fix flake8 and doc tests

* Correctly parse Python, Lua, and Bio++ package names

* Use effective URLs for mfem

* Add checksummed version to mitos

* Remove url_for_version from STAR-CCM+ package

* Revert changes to version numbers with underscores and dashes

* Fix name detection for tbb

* Correctly parse Ruby gems

* Reverted mfem back to shortened URLs.

* Updated instructions for better security

* Remove preferred=True from newest version

* Add tests for new `spack url list` flags

* Add tests for strip_name_suffixes

* Add unit tests for version separators

* Fix bugs related to parseable name but in parseable version

* Remove dead code, update docstring

* Ignore 'binary' at end of version string

* Remove platform from version

* Flip libedit version numbers

* Re-support weird NCO alpha/beta versions

* Rebase and remove one new fake URL

* Add / to beginning of regex to avoid picking up similarly named packages

* Ignore weird tar versions

* Fix bug in url parse --spider when no versions found

* Less strict version matching for spack versions

* Don't rename Python packages

* Be a little more selective, version must begin with a digit

* Re-add fake URLs

* Fix up several other packages

* Ignore more file endings

* Add parsing support for Miniconda

* Update tab completion

* XFAILS are now PASSES for 2 web tests
---
 lib/spack/docs/developer_guide.rst            |   8 +-
 lib/spack/spack/cmd/create.py                 |  25 +-
 lib/spack/spack/cmd/flake8.py                 |   2 +-
 lib/spack/spack/cmd/url.py                    |  92 +-
 lib/spack/spack/cmd/versions.py               |   2 +-
 lib/spack/spack/test/cmd/url.py               |  21 +-
 lib/spack/spack/test/url_extrapolate.py       | 101 ---
 lib/spack/spack/test/url_parse.py             | 794 +++++++++++++-----
 lib/spack/spack/test/url_substitution.py      |  84 +-
 lib/spack/spack/test/web.py                   |   3 -
 lib/spack/spack/url.py                        | 513 +++++++----
 lib/spack/spack/util/naming.py                |  45 +
 lib/spack/spack/util/web.py                   |  12 +-
 lib/spack/spack/version.py                    |  29 -
 share/spack/spack-completion.bash             |   9 +-
 .../builtin/packages/automake/package.py      |   2 +-
 .../builtin/packages/bib2xhtml/package.py     |   3 -
 .../repos/builtin/packages/bison/package.py   |   2 +-
 .../builtin/packages/blast-plus/package.py    |   5 -
 .../repos/builtin/packages/boost/package.py   |  10 +-
 .../repos/builtin/packages/bowtie2/package.py |   7 +-
 .../repos/builtin/packages/cddlib/package.py  |  18 +-
 .../repos/builtin/packages/cdo/package.py     |  10 +-
 .../repos/builtin/packages/cfitsio/package.py |   1 +
 .../repos/builtin/packages/cppad/package.py   |   5 +-
 .../builtin/packages/cryptopp/package.py      |   1 +
 .../repos/builtin/packages/dakota/package.py  |   4 -
 .../builtin/packages/exonerate/package.py     |   2 +-
 .../repos/builtin/packages/ferret/package.py  |  11 +-
 .../builtin/packages/gdk-pixbuf/package.py    |   4 +-
 .../repos/builtin/packages/go/package.py      |   7 -
 .../repos/builtin/packages/gource/package.py  |   4 -
 .../repos/builtin/packages/ibmisc/package.py  |   4 +-
 .../repos/builtin/packages/icet/package.py    |   6 +-
 .../builtin/packages/image-magick/package.py  |   3 -
 .../repos/builtin/packages/jdk/package.py     |   4 +-
 .../repos/builtin/packages/libedit/package.py |   8 +-
 .../repos/builtin/packages/libgd/package.py   |   4 -
 .../builtin/packages/libsodium/package.py     |   1 +
 .../builtin/packages/libxstream/package.py    |   4 +-
 .../repos/builtin/packages/meep/package.py    |   2 +
 .../repos/builtin/packages/metis/package.py   |  20 +-
 .../repos/builtin/packages/mfem/package.py    |  23 +-
 .../repos/builtin/packages/mitos/package.py   |   5 +-
 .../repos/builtin/packages/moab/package.py    |   2 +-
 .../repos/builtin/packages/mxml/package.py    |   3 -
 .../repos/builtin/packages/nettle/package.py  |   2 +-
 .../builtin/packages/nextflow/package.py      |   5 +-
 .../repos/builtin/packages/oce/package.py     |   5 +-
 .../repos/builtin/packages/octopus/package.py |   8 +-
 .../builtin/packages/openjpeg/package.py      |   4 -
 .../repos/builtin/packages/panda/package.py   |   4 +-
 .../builtin/packages/parmetis/package.py      |  12 +-
 .../repos/builtin/packages/prank/package.py   |   2 +-
 .../builtin/packages/py-autopep8/package.py   |  13 +-
 .../repos/builtin/packages/py-cdo/package.py  |   5 +-
 .../builtin/packages/py-markdown/package.py   |   4 -
 .../repos/builtin/packages/py-proj/package.py |   5 +-
 .../builtin/packages/py-pypar/package.py      |   3 -
 .../builtin/packages/py-rtree/package.py      |  17 +-
 .../repos/builtin/packages/r-lava/package.py  |   2 +-
 .../repos/builtin/packages/root/package.py    |   6 +-
 .../repos/builtin/packages/rose/package.py    |   7 +-
 .../builtin/packages/rust-bindgen/package.py  |   4 +-
 .../repos/builtin/packages/scorep/package.py  |  11 +-
 .../repos/builtin/packages/scotch/package.py  |   9 +-
 .../repos/builtin/packages/silo/package.py    |   5 +-
 .../builtin/packages/star-ccm-plus/package.py |   5 +-
 .../builtin/packages/sublime-text/package.py  |   4 +-
 .../repos/builtin/packages/tcl/package.py     |   5 +-
 .../repos/builtin/packages/tetgen/package.py  |   2 +-
 .../repos/builtin/packages/tinyxml/package.py |   4 +
 .../repos/builtin/packages/tk/package.py      |   5 +-
 .../builtin/packages/trilinos/package.py      |  10 +-
 .../repos/builtin/packages/unison/package.py  |   2 +-
 .../repos/builtin/packages/voropp/package.py  |  11 +-
 .../repos/builtin/packages/vtk/package.py     |   1 +
 .../builtin/packages/xsdktrilinos/package.py  |  10 +-
 .../repos/builtin/packages/yorick/package.py  |  10 +-
 .../repos/builtin/packages/zoltan/package.py  |   5 +-
 80 files changed, 1325 insertions(+), 807 deletions(-)
 delete mode 100644 lib/spack/spack/test/url_extrapolate.py

diff --git a/lib/spack/docs/developer_guide.rst b/lib/spack/docs/developer_guide.rst
index 0ce4029950..ea8d50c6ca 100644
--- a/lib/spack/docs/developer_guide.rst
+++ b/lib/spack/docs/developer_guide.rst
@@ -447,16 +447,16 @@ the string that it detected to be the name and version. The
 ``--incorrect-name`` and ``--incorrect-version`` flags can be used to
 print URLs that were not being parsed correctly.
 
-""""""""""""""""""
-``spack url test``
-""""""""""""""""""
+"""""""""""""""""""""
+``spack url summary``
+"""""""""""""""""""""
 
 This command attempts to parse every URL for every package in Spack
 and prints a summary of how many of them are being correctly parsed.
 It also prints a histogram showing which regular expressions are being
 matched and how frequently:
 
-.. command-output:: spack url test
+.. command-output:: spack url summary
 
 This command is essential for anyone adding or changing the regular
 expressions that parse names and versions. By running this command
diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py
index cc90669158..906c7e1aec 100644
--- a/lib/spack/spack/cmd/create.py
+++ b/lib/spack/spack/cmd/create.py
@@ -31,13 +31,13 @@
 import spack
 import spack.cmd
 import spack.cmd.checksum
-import spack.url
 import spack.util.web
 from llnl.util.filesystem import mkdirp
 from spack.repository import Repo
 from spack.spec import Spec
 from spack.util.executable import which
 from spack.util.naming import *
+from spack.url import *
 
 description = "create a new package file"
 
@@ -382,6 +382,10 @@ class BuildSystemGuesser:
     can take a peek at the fetched tarball and discern the build system it uses
     """
 
+    def __init__(self):
+        """Sets the default build system."""
+        self.build_system = 'generic'
+
     def __call__(self, stage, url):
         """Try to guess the type of build system used by a project based on
         the contents of its archive or the URL it was downloaded from."""
@@ -427,14 +431,11 @@ def __call__(self, stage, url):
 
         # Determine the build system based on the files contained
         # in the archive.
-        build_system = 'generic'
         for pattern, bs in clues:
             if any(re.search(pattern, l) for l in lines):
-                build_system = bs
+                self.build_system = bs
                 break
 
-        self.build_system = build_system
-
 
 def get_name(args):
     """Get the name of the package based on the supplied arguments.
@@ -458,9 +459,9 @@ def get_name(args):
     elif args.url:
         # Try to guess the package name based on the URL
         try:
-            name = spack.url.parse_name(args.url)
+            name = parse_name(args.url)
             tty.msg("This looks like a URL for {0}".format(name))
-        except spack.url.UndetectableNameError:
+        except UndetectableNameError:
             tty.die("Couldn't guess a name for this package.",
                     "  Please report this bug. In the meantime, try running:",
                     "  `spack create --name <name> <url>`")
@@ -515,11 +516,16 @@ def get_versions(args, name):
 
     if args.url:
         # Find available versions
-        url_dict = spack.util.web.find_versions_of_archive(args.url)
+        try:
+            url_dict = spack.util.web.find_versions_of_archive(args.url)
+        except UndetectableVersionError:
+            # Use fake versions
+            tty.warn("Couldn't detect version in: {0}".format(args.url))
+            return versions, guesser
 
         if not url_dict:
             # If no versions were found, revert to what the user provided
-            version = spack.url.parse_version(args.url)
+            version = parse_version(args.url)
             url_dict = {version: args.url}
 
         versions = spack.cmd.checksum.get_checksums(
@@ -611,6 +617,7 @@ def create(parser, args):
     url = get_url(args)
     versions, guesser = get_versions(args, name)
     build_system = get_build_system(args, guesser)
+    name = simplify_name(name)
 
     # Create the package template object
     PackageClass = templates[build_system]
diff --git a/lib/spack/spack/cmd/flake8.py b/lib/spack/spack/cmd/flake8.py
index 19724142bb..a6dc941190 100644
--- a/lib/spack/spack/cmd/flake8.py
+++ b/lib/spack/spack/cmd/flake8.py
@@ -70,7 +70,7 @@
     # exemptions applied to all files.
     r'.py$': {
         # Exempt lines with URLs from overlong line errors.
-        501: [r'(https?|file)\:']
+        501: [r'(https?|ftp|file)\:']
     },
 }
 
diff --git a/lib/spack/spack/cmd/url.py b/lib/spack/spack/cmd/url.py
index 6823f0febd..1128e08a43 100644
--- a/lib/spack/spack/cmd/url.py
+++ b/lib/spack/spack/cmd/url.py
@@ -31,6 +31,7 @@
 from llnl.util import tty
 from spack.url import *
 from spack.util.web import find_versions_of_archive
+from spack.util.naming import simplify_name
 
 description = "debugging tool for url parsing"
 
@@ -65,20 +66,27 @@ def setup_parser(subparser):
     excl_args.add_argument(
         '-n', '--incorrect-name', action='store_true',
         help='only list urls for which the name was incorrectly parsed')
+    excl_args.add_argument(
+        '-N', '--correct-name', action='store_true',
+        help='only list urls for which the name was correctly parsed')
     excl_args.add_argument(
         '-v', '--incorrect-version', action='store_true',
         help='only list urls for which the version was incorrectly parsed')
+    excl_args.add_argument(
+        '-V', '--correct-version', action='store_true',
+        help='only list urls for which the version was correctly parsed')
 
-    # Test
+    # Summary
     sp.add_parser(
-        'test', help='print a summary of how well we are parsing package urls')
+        'summary',
+        help='print a summary of how well we are parsing package urls')
 
 
 def url(parser, args):
     action = {
-        'parse': url_parse,
-        'list':  url_list,
-        'test':  url_test
+        'parse':   url_parse,
+        'list':    url_list,
+        'summary': url_summary
     }
 
     action[args.subcommand](args)
@@ -116,6 +124,10 @@ def url_parse(args):
         tty.msg('Spidering for versions:')
         versions = find_versions_of_archive(url)
 
+        if not versions:
+            print('  Found no versions for {0}'.format(name))
+            return
+
         max_len = max(len(str(v)) for v in versions)
 
         for v in sorted(versions):
@@ -145,7 +157,7 @@ def url_list(args):
     return len(urls)
 
 
-def url_test(args):
+def url_summary(args):
     # Collect statistics on how many URLs were correctly parsed
     total_urls       = 0
     correct_names    = 0
@@ -205,19 +217,19 @@ def url_test(args):
         correct_versions, total_urls, correct_versions / total_urls))
     print()
 
-    tty.msg('Statistics on name regular expresions:')
+    tty.msg('Statistics on name regular expressions:')
 
     print()
-    print('    Index  Count  Regular Expresion')
+    print('    Index  Count  Regular Expression')
     for ni in name_regex_dict:
         print('    {0:>3}: {1:>6}   r{2!r}'.format(
             ni, name_count_dict[ni], name_regex_dict[ni]))
     print()
 
-    tty.msg('Statistics on version regular expresions:')
+    tty.msg('Statistics on version regular expressions:')
 
     print()
-    print('    Index  Count  Regular Expresion')
+    print('    Index  Count  Regular Expression')
     for vi in version_regex_dict:
         print('    {0:>3}: {1:>6}   r{2!r}'.format(
             vi, version_count_dict[vi], version_regex_dict[vi]))
@@ -257,22 +269,38 @@ def url_list_parsing(args, urls, url, pkg):
     :rtype: set
     """
     if url:
-        if args.incorrect_name:
-            # Only add URLs whose name was incorrectly parsed
+        if args.correct_name or args.incorrect_name:
+            # Attempt to parse the name
             try:
                 name = parse_name(url)
-                if not name_parsed_correctly(pkg, name):
+                if (args.correct_name and
+                    name_parsed_correctly(pkg, name)):
+                    # Add correctly parsed URLs
+                    urls.add(url)
+                elif (args.incorrect_name and
+                      not name_parsed_correctly(pkg, name)):
+                    # Add incorrectly parsed URLs
                     urls.add(url)
             except UndetectableNameError:
-                urls.add(url)
-        elif args.incorrect_version:
-            # Only add URLs whose version was incorrectly parsed
+                if args.incorrect_name:
+                    # Add incorrectly parsed URLs
+                    urls.add(url)
+        elif args.correct_version or args.incorrect_version:
+            # Attempt to parse the version
             try:
                 version = parse_version(url)
-                if not version_parsed_correctly(pkg, version):
+                if (args.correct_version and
+                    version_parsed_correctly(pkg, version)):
+                    # Add correctly parsed URLs
+                    urls.add(url)
+                elif (args.incorrect_version and
+                      not version_parsed_correctly(pkg, version)):
+                    # Add incorrectly parsed URLs
                     urls.add(url)
             except UndetectableVersionError:
-                urls.add(url)
+                if args.incorrect_version:
+                    # Add incorrectly parsed URLs
+                    urls.add(url)
         else:
             urls.add(url)
 
@@ -289,6 +317,8 @@ def name_parsed_correctly(pkg, name):
     """
     pkg_name = pkg.name
 
+    name = simplify_name(name)
+
     # After determining a name, `spack create` determines a build system.
     # Some build systems prepend a special string to the front of the name.
     # Since this can't be guessed from the URL, it would be unfair to say
@@ -311,9 +341,33 @@ def version_parsed_correctly(pkg, version):
     :returns: True if the name was correctly parsed, else False
     :rtype: bool
     """
+    version = remove_separators(version)
+
     # If the version parsed from the URL is listed in a version()
     # directive, we assume it was correctly parsed
     for pkg_version in pkg.versions:
-        if str(pkg_version) == str(version):
+        pkg_version = remove_separators(pkg_version)
+        if pkg_version == version:
             return True
     return False
+
+
+def remove_separators(version):
+    """Removes separator characters ('.', '_', and '-') from a version.
+
+    A version like 1.2.3 may be displayed as 1_2_3 in the URL.
+    Make sure 1.2.3, 1-2-3, 1_2_3, and 123 are considered equal.
+    Unfortunately, this also means that 1.23 and 12.3 are equal.
+
+    :param version: A version
+    :type version: str or Version
+    :returns: The version with all separator characters removed
+    :rtype: str
+    """
+    version = str(version)
+
+    version = version.replace('.', '')
+    version = version.replace('_', '')
+    version = version.replace('-', '')
+
+    return version
diff --git a/lib/spack/spack/cmd/versions.py b/lib/spack/spack/cmd/versions.py
index f65ef14406..a6f6805fb0 100644
--- a/lib/spack/spack/cmd/versions.py
+++ b/lib/spack/spack/cmd/versions.py
@@ -53,6 +53,6 @@ def versions(parser, args):
             tty.debug("Check the list_url and list_depth attribute on the "
                       "package to help Spack find versions.")
         else:
-            print("  Found no unckecksummed versions for %s" % pkg.name)
+            print("  Found no unchecksummed versions for %s" % pkg.name)
     else:
         colify(sorted(remote_versions, reverse=True), indent=2)
diff --git a/lib/spack/spack/test/cmd/url.py b/lib/spack/spack/test/cmd/url.py
index 4c60d814ce..3bc0bc7820 100644
--- a/lib/spack/spack/test/cmd/url.py
+++ b/lib/spack/spack/test/cmd/url.py
@@ -48,11 +48,12 @@ def test_name_parsed_correctly():
     assert name_parsed_correctly(MyPackage('r-devtools',     []), 'devtools')
     assert name_parsed_correctly(MyPackage('py-numpy',       []), 'numpy')
     assert name_parsed_correctly(MyPackage('octave-splines', []), 'splines')
+    assert name_parsed_correctly(MyPackage('imagemagick',    []), 'ImageMagick')  # noqa
+    assert name_parsed_correctly(MyPackage('th-data',        []), 'TH.data')
 
     # Expected False
     assert not name_parsed_correctly(MyPackage('',            []), 'hdf5')
     assert not name_parsed_correctly(MyPackage('hdf5',        []), '')
-    assert not name_parsed_correctly(MyPackage('imagemagick', []), 'ImageMagick')  # noqa
     assert not name_parsed_correctly(MyPackage('yaml-cpp',    []), 'yamlcpp')
     assert not name_parsed_correctly(MyPackage('yamlcpp',     []), 'yaml-cpp')
     assert not name_parsed_correctly(MyPackage('r-py-parser', []), 'parser')
@@ -64,6 +65,8 @@ def test_version_parsed_correctly():
     assert version_parsed_correctly(MyPackage('', ['1.2.3']),        '1.2.3')
     assert version_parsed_correctly(MyPackage('', ['5.4a', '5.4b']), '5.4a')
     assert version_parsed_correctly(MyPackage('', ['5.4a', '5.4b']), '5.4b')
+    assert version_parsed_correctly(MyPackage('', ['1.63.0']),       '1_63_0')
+    assert version_parsed_correctly(MyPackage('', ['0.94h']),        '094h')
 
     # Expected False
     assert not version_parsed_correctly(MyPackage('', []),         '1.2.3')
@@ -95,7 +98,7 @@ def test_url_list(parser):
     colored_urls = url_list(args)
     assert colored_urls == total_urls
 
-    # The following two options should print fewer URLs than the default.
+    # The following options should print fewer URLs than the default.
     # If they print the same number of URLs, something is horribly broken.
     # If they say we missed 0 URLs, something is probably broken too.
     args = parser.parse_args(['list', '--incorrect-name'])
@@ -106,11 +109,19 @@ def test_url_list(parser):
     incorrect_version_urls = url_list(args)
     assert 0 < incorrect_version_urls < total_urls
 
+    args = parser.parse_args(['list', '--correct-name'])
+    correct_name_urls = url_list(args)
+    assert 0 < correct_name_urls < total_urls
 
-def test_url_test(parser):
-    args = parser.parse_args(['test'])
+    args = parser.parse_args(['list', '--correct-version'])
+    correct_version_urls = url_list(args)
+    assert 0 < correct_version_urls < total_urls
+
+
+def test_url_summary(parser):
+    args = parser.parse_args(['summary'])
     (total_urls, correct_names, correct_versions,
-     name_count_dict, version_count_dict) = url_test(args)
+     name_count_dict, version_count_dict) = url_summary(args)
 
     assert 0 < correct_names    <= sum(name_count_dict.values())    <= total_urls  # noqa
     assert 0 < correct_versions <= sum(version_count_dict.values()) <= total_urls  # noqa
diff --git a/lib/spack/spack/test/url_extrapolate.py b/lib/spack/spack/test/url_extrapolate.py
deleted file mode 100644
index 5f5cf555ae..0000000000
--- a/lib/spack/spack/test/url_extrapolate.py
+++ /dev/null
@@ -1,101 +0,0 @@
-##############################################################################
-# Copyright (c) 2013-2016, 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 LICENSE file 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
-##############################################################################
-"""Tests ability of spack to extrapolate URL versions from
-existing versions.
-"""
-import unittest
-
-import spack.url as url
-
-
-class UrlExtrapolateTest(unittest.TestCase):
-
-    def check_url(self, base, version, new_url):
-        self.assertEqual(url.substitute_version(base, version), new_url)
-
-    def test_libelf_version(self):
-        base = "http://www.mr511.de/software/libelf-0.8.13.tar.gz"
-        self.check_url(base, '0.8.13', base)
-        self.check_url(
-            base, '0.8.12', "http://www.mr511.de/software/libelf-0.8.12.tar.gz")
-        self.check_url(
-            base, '0.3.1',  "http://www.mr511.de/software/libelf-0.3.1.tar.gz")
-        self.check_url(
-            base, '1.3.1b', "http://www.mr511.de/software/libelf-1.3.1b.tar.gz")
-
-    def test_libdwarf_version(self):
-        base = "http://www.prevanders.net/libdwarf-20130729.tar.gz"
-        self.check_url(base, '20130729', base)
-        self.check_url(
-            base, '8.12', "http://www.prevanders.net/libdwarf-8.12.tar.gz")
-
-    def test_dyninst_version(self):
-        # Dyninst has a version twice in the URL.
-        base = "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.1.2/DyninstAPI-8.1.2.tgz"
-        self.check_url(base, '8.1.2', base)
-        self.check_url(base, '8.2',
-                       "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.2/DyninstAPI-8.2.tgz")
-        self.check_url(base, '8.3.1',
-                       "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.3.1/DyninstAPI-8.3.1.tgz")
-
-    def test_partial_version_prefix(self):
-        # Test now with a partial prefix earlier in the URL -- this is
-        # hard to figure out so Spack only substitutes the last
-        # instance of the version.
-        base = "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.1/DyninstAPI-8.1.2.tgz"
-        self.check_url(base, '8.1.2', base)
-        self.check_url(base, '8.1.4',
-                       "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.1/DyninstAPI-8.1.4.tgz")
-        self.check_url(base, '8.2',
-                       "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.1/DyninstAPI-8.2.tgz")
-        self.check_url(base, '8.3.1',
-                       "http://www.dyninst.org/sites/default/files/downloads/dyninst/8.1/DyninstAPI-8.3.1.tgz")
-
-    def test_scalasca_partial_version(self):
-        # Note that this probably doesn't actually work, but sites are
-        # inconsistent about their directory structure, so it's not
-        # clear what is right.  This test is for consistency and to
-        # document behavior.  If you figure out a good way to handle
-        # this case, fix the tests too.
-        self.check_url('http://apps.fz-juelich.de/scalasca/releases/cube/4.3/dist/cube-4.3-TP1.tar.gz', '8.3.1',
-                       'http://apps.fz-juelich.de/scalasca/releases/cube/4.3/dist/cube-8.3.1.tar.gz')
-        self.check_url('http://apps.fz-juelich.de/scalasca/releases/cube/4.3/dist/cube-4.3-TP1.tar.gz', '8.3.1',
-                       'http://apps.fz-juelich.de/scalasca/releases/cube/4.3/dist/cube-8.3.1.tar.gz')
-
-    def test_mpileaks_version(self):
-        self.check_url('https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz', '2.1.3',
-                       'https://github.com/hpc/mpileaks/releases/download/v2.1.3/mpileaks-2.1.3.tar.gz')
-
-    def test_gcc(self):
-        self.check_url('http://open-source-box.org/gcc/gcc-4.9.2/gcc-4.9.2.tar.bz2', '4.7',
-                       'http://open-source-box.org/gcc/gcc-4.7/gcc-4.7.tar.bz2')
-        self.check_url('http://open-source-box.org/gcc/gcc-4.4.7/gcc-4.4.7.tar.bz2', '4.4.7',
-                       'http://open-source-box.org/gcc/gcc-4.4.7/gcc-4.4.7.tar.bz2')
-
-    def test_github_raw(self):
-        self.check_url('https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v2.0.7.tgz?raw=true', '2.0.7',
-                       'https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v2.0.7.tgz?raw=true')
-        self.check_url('https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v2.0.7.tgz?raw=true', '4.7',
-                       'https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v4.7.tgz?raw=true')
diff --git a/lib/spack/spack/test/url_parse.py b/lib/spack/spack/test/url_parse.py
index 8913de94d0..2af7c6ae0b 100644
--- a/lib/spack/spack/test/url_parse.py
+++ b/lib/spack/spack/test/url_parse.py
@@ -22,246 +22,667 @@
 # License along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##############################################################################
-"""\
-This file has a bunch of versions tests taken from the excellent version
-detection in Homebrew.
-"""
+"""Tests Spack's ability to parse the name and version of a package
+based on its URL."""
+
+import os
 import unittest
 
-import spack.url as url
+from spack.url import *
 
 
-class UrlParseTest(unittest.TestCase):
+class UrlStripVersionSuffixesTest(unittest.TestCase):
+    """Tests for spack.url.strip_version_suffixes"""
 
-    def assert_not_detected(self, string):
-        self.assertRaises(
-            url.UndetectableVersionError, url.parse_name_and_version, string)
+    def check(self, before, after):
+        stripped = strip_version_suffixes(before)
+        self.assertEqual(stripped, after)
 
-    def check(self, name, v, string, **kwargs):
-        # Make sure correct name and version are extracted.
-        parsed_name, parsed_v = url.parse_name_and_version(string)
-        self.assertEqual(parsed_name, name)
-        self.assertEqual(parsed_v, url.Version(v))
+    def test_no_suffix(self):
+        self.check('rgb-1.0.6',
+                   'rgb-1.0.6')
 
-        # Some URLs (like boost) are special and need to override the
-        # built-in functionality.
-        if kwargs.get('no_check_url', False):
-            return
+    def test_misleading_prefix(self):
+        self.check('jpegsrc.v9b',
+                   'jpegsrc.v9b')
+        self.check('turbolinux702',
+                   'turbolinux702')
+        self.check('converge_install_2.3.16',
+                   'converge_install_2.3.16')
 
-        # Make sure Spack formulates the right URL when we try to
-        # build one with a specific version.
-        self.assertEqual(string, url.substitute_version(string, v))
+    # Download type
 
-    def test_wwwoffle_version(self):
-        self.check(
-            'wwwoffle', '2.9h',
-            'http://www.gedanken.demon.co.uk/download-wwwoffle/wwwoffle-2.9h.tgz')
+    def test_src(self):
+        self.check('apache-ant-1.9.7-src',
+                   'apache-ant-1.9.7')
+        self.check('go1.7.4.src',
+                   'go1.7.4')
+
+    def test_source(self):
+        self.check('bowtie2-2.2.5-source',
+                   'bowtie2-2.2.5')
+        self.check('grib_api-1.17.0-Source',
+                   'grib_api-1.17.0')
+
+    def test_full(self):
+        self.check('julia-0.4.3-full',
+                   'julia-0.4.3')
+
+    def test_bin(self):
+        self.check('apache-maven-3.3.9-bin',
+                   'apache-maven-3.3.9')
+
+    def test_binary(self):
+        self.check('Jmol-14.8.0-binary',
+                   'Jmol-14.8.0')
+
+    def test_gem(self):
+        self.check('rubysl-date-2.0.9.gem',
+                   'rubysl-date-2.0.9')
+
+    def test_tar(self):
+        self.check('gromacs-4.6.1-tar',
+                   'gromacs-4.6.1')
+
+    def test_sh(self):
+        self.check('Miniconda2-4.3.11-Linux-x86_64.sh',
+                   'Miniconda2-4.3.11')
+
+    # Download version
+
+    def test_stable(self):
+        self.check('libevent-2.0.21-stable',
+                   'libevent-2.0.21')
+
+    def test_final(self):
+        self.check('2.6.7-final',
+                   '2.6.7')
+
+    def test_rel(self):
+        self.check('v1.9.5.1rel',
+                   'v1.9.5.1')
+
+    def test_orig(self):
+        self.check('dash_0.5.5.1.orig',
+                   'dash_0.5.5.1')
+
+    def test_plus(self):
+        self.check('ncbi-blast-2.6.0+-src',
+                   'ncbi-blast-2.6.0')
+
+    # License
+
+    def test_gpl(self):
+        self.check('cppad-20170114.gpl',
+                   'cppad-20170114')
+
+    # OS
+
+    def test_linux(self):
+        self.check('astyle_2.04_linux',
+                   'astyle_2.04')
+
+    def test_unix(self):
+        self.check('install-tl-unx',
+                   'install-tl')
+
+    def test_macos(self):
+        self.check('astyle_1.23_macosx',
+                   'astyle_1.23')
+        self.check('haxe-2.08-osx',
+                   'haxe-2.08')
+
+    # PyPI
+
+    def test_wheel(self):
+        self.check('entrypoints-0.2.2-py2.py3-none-any.whl',
+                   'entrypoints-0.2.2')
+        self.check('numpy-1.12.0-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl',  # noqa
+                   'numpy-1.12.0')
+
+    def test_exe(self):
+        self.check('PyYAML-3.12.win-amd64-py3.5.exe',
+                   'PyYAML-3.12')
+
+    # Combinations of multiple patterns
+
+    def test_complex_all(self):
+        self.check('p7zip_9.04_src_all',
+                   'p7zip_9.04')
+
+    def test_complex_run(self):
+        self.check('cuda_8.0.44_linux.run',
+                   'cuda_8.0.44')
+
+    def test_complex_file(self):
+        self.check('ack-2.14-single-file',
+                   'ack-2.14')
+
+    def test_complex_jar(self):
+        self.check('antlr-3.4-complete.jar',
+                   'antlr-3.4')
+
+    def test_complex_oss(self):
+        self.check('tbb44_20160128oss_src_0',
+                   'tbb44_20160128')
+
+    def test_complex_darwin(self):
+        self.check('ghc-7.0.4-x86_64-apple-darwin',
+                   'ghc-7.0.4')
+        self.check('ghc-7.0.4-i386-apple-darwin',
+                   'ghc-7.0.4')
+
+    def test_complex_arch(self):
+        self.check('VizGlow_v2.2alpha17-R21November2016-Linux-x86_64-Install',
+                   'VizGlow_v2.2alpha17-R21November2016')
+        self.check('jdk-8u92-linux-x64',
+                   'jdk-8u92')
+        self.check('cuda_6.5.14_linux_64.run',
+                   'cuda_6.5.14')
+
+    def test_complex_with(self):
+        self.check('mafft-7.221-with-extensions-src',
+                   'mafft-7.221')
+        self.check('spark-2.0.0-bin-without-hadoop',
+                   'spark-2.0.0')
+
+    def test_complex_public(self):
+        self.check('dakota-6.3-public.src',
+                   'dakota-6.3')
+
+    def test_complex_universal(self):
+        self.check('synergy-1.3.6p2-MacOSX-Universal',
+                   'synergy-1.3.6p2')
+
+
+class UrlStripNameSuffixesTest(unittest.TestCase):
+    """Tests for spack.url.strip_name_suffixes"""
+
+    def check(self, before, version, after):
+        stripped = strip_name_suffixes(before, version)
+        self.assertEqual(stripped, after)
+
+    def test_no_suffix(self):
+        self.check('rgb-1.0.6', '1.0.6',
+                   'rgb')
+        self.check('nauty26r7', '26r7',
+                   'nauty')
+
+    # Download type
+
+    def test_install(self):
+        self.check('converge_install_2.3.16', '2.3.16',
+                   'converge')
+
+    def test_src(self):
+        self.check('jpegsrc.v9b', '9b',
+                   'jpeg')
+
+    def test_std(self):
+        self.check('ghostscript-fonts-std-8.11', '8.11',
+                   'ghostscript-fonts')
+
+    # Download version
+
+    def test_snapshot(self):
+        self.check('gts-snapshot-121130', '121130',
+                   'gts')
+
+    def test_distrib(self):
+        self.check('zoltan_distrib_v3.83', '3.83',
+                   'zoltan')
+
+    # VCS
 
-    def test_version_sourceforge_download(self):
+    def test_bazaar(self):
+        self.check('libvterm-0+bzr681', '681',
+                   'libvterm')
+
+    # License
+
+    def test_gpl(self):
+        self.check('PyQt-x11-gpl-4.11.3', '4.11.3',
+                   'PyQt-x11')
+
+
+class UrlParseOffsetTest(unittest.TestCase):
+
+    def check(self, name, noffset, ver, voffset, path):
+        # Make sure parse_name_offset and parse_name_version are working
+        v, vstart, vlen, vi, vre = parse_version_offset(path)
+        n, nstart, nlen, ni, nre = parse_name_offset(path, v)
+
+        self.assertEqual(n, name)
+        self.assertEqual(v, ver)
+        self.assertEqual(nstart, noffset)
+        self.assertEqual(vstart, voffset)
+
+    def test_name_in_path(self):
         self.check(
-            'foo-bar', '1.21',
-            'http://sourceforge.net/foo_bar-1.21.tar.gz/download')
+            'antlr', 25, '2.7.7', 40,
+            'https://github.com/antlr/antlr/tarball/v2.7.7')
+
+    def test_name_in_stem(self):
         self.check(
-            'foo-bar', '1.21',
-            'http://sf.net/foo_bar-1.21.tar.gz/download')
+            'gmp', 32, '6.0.0a', 36,
+            'https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2')
 
-    def test_no_version(self):
-        self.assert_not_detected('http://example.com/blah.tar')
-        self.assert_not_detected('foo')
+    def test_name_in_suffix(self):
+        # Don't think I've ever seen one of these before
+        # We don't look for it, so it would probably fail anyway
+        pass
 
-    def test_version_all_dots(self):
+    def test_version_in_path(self):
         self.check(
-            'foo-bar-la', '1.14', 'http://example.com/foo.bar.la.1.14.zip')
+            'nextflow', 31, '0.20.1', 59,
+            'https://github.com/nextflow-io/nextflow/releases/download/v0.20.1/nextflow')
 
-    def test_version_underscore_separator(self):
+    def test_version_in_stem(self):
         self.check(
-            'grc', '1.1',
-            'http://example.com/grc_1.1.tar.gz')
-
-    def test_boost_version_style(self):
+            'zlib', 24, '1.2.10', 29,
+            'http://zlib.net/fossils/zlib-1.2.10.tar.gz')
+        self.check(
+            'slepc', 51, '3.6.2', 57,
+            'http://slepc.upv.es/download/download.php?filename=slepc-3.6.2.tar.gz')
         self.check(
-            'boost', '1.39.0',
-            'http://example.com/boost_1_39_0.tar.bz2',
-            no_check_url=True)
+            'cloog', 61, '0.18.1', 67,
+            'http://www.bastoul.net/cloog/pages/download/count.php3?url=./cloog-0.18.1.tar.gz')
+        self.check(
+            'libxc', 58, '2.2.2', 64,
+            'http://www.tddft.org/programs/octopus/down.php?file=libxc/libxc-2.2.2.tar.gz')
 
-    def test_erlang_version_style(self):
+    def test_version_in_suffix(self):
+        self.check(
+            'swiftsim', 36, '0.3.0', 76,
+            'http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0')
         self.check(
-            'otp', 'R13B',
-            'http://erlang.org/download/otp_src_R13B.tar.gz')
+            'sionlib', 30, '1.7.1', 59,
+            'http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1')
 
-    def test_another_erlang_version_style(self):
+    def test_regex_in_name(self):
         self.check(
-            'otp', 'R15B01',
-            'https://github.com/erlang/otp/tarball/OTP_R15B01')
+            'voro++', 40, '0.4.6', 47,
+            'http://math.lbl.gov/voro++/download/dir/voro++-0.4.6.tar.gz')
+
+
+class UrlParseNameAndVersionTest(unittest.TestCase):
+
+    def assert_not_detected(self, string):
+        self.assertRaises(
+            UndetectableVersionError, parse_name_and_version, string)
+
+    def check(self, name, v, string, **kwargs):
+        # Make sure correct name and version are extracted.
+        parsed_name, parsed_v = parse_name_and_version(string)
+        self.assertEqual(parsed_name, name)
+        self.assertEqual(parsed_v, Version(v))
+
+        # Make sure Spack formulates the right URL when we try to
+        # build one with a specific version.
+        self.assertEqual(string, substitute_version(string, v))
+
+    # Common Repositories
 
-    def test_yet_another_erlang_version_style(self):
+    def test_github_downloads(self):
+        # name/archive/ver.ver
         self.check(
-            'otp', 'R15B03-1',
-            'https://github.com/erlang/otp/tarball/OTP_R15B03-1')
+            'nco', '4.6.2',
+            'https://github.com/nco/nco/archive/4.6.2.tar.gz')
+        # name/archive/vver.ver
+        self.check(
+            'vim', '8.0.0134',
+            'https://github.com/vim/vim/archive/v8.0.0134.tar.gz')
+        # name/archive/name-ver.ver
+        self.check(
+            'oce', '0.18',
+            'https://github.com/tpaviot/oce/archive/OCE-0.18.tar.gz')
+        # name/releases/download/vver/name-ver.ver
+        self.check(
+            'libmesh', '1.0.0',
+            'https://github.com/libMesh/libmesh/releases/download/v1.0.0/libmesh-1.0.0.tar.bz2')
+        # name/tarball/vver.ver
+        self.check(
+            'git', '2.7.1',
+            'https://github.com/git/git/tarball/v2.7.1')
+        # name/zipball/vver.ver
+        self.check(
+            'git', '2.7.1',
+            'https://github.com/git/git/zipball/v2.7.1')
 
-    def test_p7zip_version_style(self):
+    def test_gitlab_downloads(self):
+        # name/repository/archive.ext?ref=vver.ver
+        self.check(
+            'swiftsim', '0.3.0',
+            'http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0')
+        # name/repository/archive.ext?ref=name-ver.ver
         self.check(
-            'p7zip', '9.04',
-            'http://kent.dl.sourceforge.net/sourceforge/p7zip/p7zip_9.04_src_all.tar.bz2')
+             'icet', '1.2.3',
+             'https://gitlab.kitware.com/icet/icet/repository/archive.tar.gz?ref=IceT-1.2.3')
 
-    def test_new_github_style(self):
+    def test_bitbucket_downloads(self):
+        # name/get/ver.ver
         self.check(
-            'libnet', '1.1.4',
-            'https://github.com/sam-github/libnet/tarball/libnet-1.1.4')
+            'eigen', '3.2.7',
+            'https://bitbucket.org/eigen/eigen/get/3.2.7.tar.bz2')
+        # name/get/vver.ver
+        self.check(
+            'hoomd-blue', '1.3.3',
+            'https://bitbucket.org/glotzer/hoomd-blue/get/v1.3.3.tar.bz2')
+        # name/downloads/name-ver.ver
+        self.check(
+            'dolfin', '2016.1.0',
+            'https://bitbucket.org/fenics-project/dolfin/downloads/dolfin-2016.1.0.tar.gz')
 
-    def test_gloox_beta_style(self):
+    def test_sourceforge_downloads(self):
+        # name-ver.ver
         self.check(
-            'gloox', '1.0-beta7',
-            'http://camaya.net/download/gloox-1.0-beta7.tar.bz2')
+            'libpng', '1.6.27',
+            'http://download.sourceforge.net/libpng/libpng-1.6.27.tar.gz')
+        self.check(
+            'lcms2', '2.6',
+            'http://downloads.sourceforge.net/project/lcms/lcms/2.6/lcms2-2.6.tar.gz')
+        self.check(
+            'modules', '3.2.10',
+            'http://prdownloads.sourceforge.net/modules/modules-3.2.10.tar.gz')
+        # name-ver.ver.ext/download
+        self.check(
+            'glew', '2.0.0',
+            'https://sourceforge.net/projects/glew/files/glew/2.0.0/glew-2.0.0.tgz/download')
 
-    def test_sphinx_beta_style(self):
+    def test_cran_downloads(self):
+        # name.name_ver.ver-ver.ver
         self.check(
-            'sphinx', '1.10-beta',
-            'http://sphinxsearch.com/downloads/sphinx-1.10-beta.tar.gz')
+            'TH.data', '1.0-8',
+            'https://cran.r-project.org/src/contrib/TH.data_1.0-8.tar.gz')
+        self.check(
+            'knitr', '1.14',
+            'https://cran.rstudio.com/src/contrib/knitr_1.14.tar.gz')
+        self.check(
+            'devtools', '1.12.0',
+            'https://cloud.r-project.org/src/contrib/devtools_1.12.0.tar.gz')
 
-    def test_astyle_verson_style(self):
+    def test_pypi_downloads(self):
+        # name.name_name-ver.ver
+        self.check(
+            '3to2', '1.1.1',
+            'https://pypi.python.org/packages/source/3/3to2/3to2-1.1.1.zip')
         self.check(
-            'astyle', '1.23',
-            'http://kent.dl.sourceforge.net/sourceforge/astyle/astyle_1.23_macosx.tar.gz')
+            'mpmath', '0.19',
+            'https://pypi.python.org/packages/source/m/mpmath/mpmath-all-0.19.tar.gz')
+        self.check(
+            'pandas', '0.16.0',
+            'https://pypi.python.org/packages/source/p/pandas/pandas-0.16.0.tar.gz#md5=bfe311f05dc0c351f8955fbd1e296e73')
+        self.check(
+            'sphinx_rtd_theme', '0.1.10a0',
+            'https://pypi.python.org/packages/da/6b/1b75f13d8aa3333f19c6cdf1f0bc9f52ea739cae464fbee050307c121857/sphinx_rtd_theme-0.1.10a0.tar.gz')
+        self.check(
+            'backports.ssl_match_hostname', '3.5.0.1',
+            'https://pypi.io/packages/source/b/backports.ssl_match_hostname/backports.ssl_match_hostname-3.5.0.1.tar.gz')
 
-    def test_version_dos2unix(self):
+    def test_bazaar_downloads(self):
         self.check(
-            'dos2unix', '3.1',
-            'http://www.sfr-fresh.com/linux/misc/dos2unix-3.1.tar.gz')
+            'libvterm', '681',
+            'http://www.leonerd.org.uk/code/libvterm/libvterm-0+bzr681.tar.gz')
 
-    def test_version_internal_dash(self):
+    # Common Tarball Formats
+
+    def test_version_only(self):
+        # ver.ver
+        self.check(
+            'eigen', '3.2.7',
+            'https://bitbucket.org/eigen/eigen/get/3.2.7.tar.bz2')
+        # ver.ver-ver
+        self.check(
+            'ImageMagick', '7.0.2-7',
+            'https://github.com/ImageMagick/ImageMagick/archive/7.0.2-7.tar.gz')
+        # vver.ver
         self.check(
-            'foo-arse', '1.1-2',
-            'http://example.com/foo-arse-1.1-2.tar.gz')
+            'CGNS', '3.3.0',
+            'https://github.com/CGNS/CGNS/archive/v3.3.0.tar.gz')
+        # vver_ver
+        self.check(
+            'luafilesystem', '1_6_3',
+            'https://github.com/keplerproject/luafilesystem/archive/v1_6_3.tar.gz')
 
-    def test_version_single_digit(self):
+    def test_no_separators(self):
+        # namever
+        self.check(
+            'turbolinux', '702',
+            'file://{0}/turbolinux702.tar.gz'.format(os.getcwd()))
         self.check(
-            'foo-bar', '45',
-            'http://example.com/foo_bar.45.tar.gz')
+            'nauty', '26r7',
+            'http://pallini.di.uniroma1.it/nauty26r7.tar.gz')
 
-    def test_noseparator_single_digit(self):
+    def test_dashes_only(self):
+        # name-name-ver-ver
+        self.check(
+            'Trilinos', '12-10-1',
+            'https://github.com/trilinos/Trilinos/archive/trilinos-release-12-10-1.tar.gz')
+        self.check(
+            'panda', '2016-03-07',
+            'http://comopt.ifi.uni-heidelberg.de/software/PANDA/downloads/panda-2016-03-07.tar')
         self.check(
-            'foo-bar', '45',
-            'http://example.com/foo_bar45.tar.gz')
+            'gts', '121130',
+            'http://gts.sourceforge.net/tarballs/gts-snapshot-121130.tar.gz')
+        self.check(
+            'cdd', '061a',
+            'http://www.cs.mcgill.ca/~fukuda/download/cdd/cdd-061a.tar.gz')
 
-    def test_version_developer_that_hates_us_format(self):
+    def test_underscores_only(self):
+        # name_name_ver_ver
+        self.check(
+            'tinyxml', '2_6_2',
+            'https://sourceforge.net/projects/tinyxml/files/tinyxml/2.6.2/tinyxml_2_6_2.tar.gz')
+        self.check(
+            'boost', '1_55_0',
+            'http://downloads.sourceforge.net/project/boost/boost/1.55.0/boost_1_55_0.tar.bz2')
         self.check(
-            'foo-bar-la', '1.2.3',
-            'http://example.com/foo-bar-la.1.2.3.tar.gz')
+            'yorick', '2_2_04',
+            'https://github.com/dhmunro/yorick/archive/y_2_2_04.tar.gz')
+        # name_namever_ver
+        self.check(
+            'tbb', '44_20160413',
+            'https://www.threadingbuildingblocks.org/sites/default/files/software_releases/source/tbb44_20160413oss_src.tgz')
 
-    def test_version_regular(self):
+    def test_dots_only(self):
+        # name.name.ver.ver
+        self.check(
+            'prank', '150803',
+            'http://wasabiapp.org/download/prank/prank.source.150803.tgz')
+        self.check(
+            'jpeg', '9b',
+            'http://www.ijg.org/files/jpegsrc.v9b.tar.gz')
+        self.check(
+            'openjpeg', '2.1',
+            'https://github.com/uclouvain/openjpeg/archive/version.2.1.tar.gz')
+        # name.namever.ver
+        self.check(
+            'atlas', '3.11.34',
+            'http://sourceforge.net/projects/math-atlas/files/Developer%20%28unstable%29/3.11.34/atlas3.11.34.tar.bz2')
         self.check(
-            'foo-bar', '1.21',
-            'http://example.com/foo_bar-1.21.tar.gz')
+            'visit', '2.10.1',
+            'http://portal.nersc.gov/project/visit/releases/2.10.1/visit2.10.1.tar.gz')
+        self.check(
+            'geant', '4.10.01.p03',
+            'http://geant4.cern.ch/support/source/geant4.10.01.p03.tar.gz')
+        self.check(
+            'tcl', '8.6.5',
+            'http://prdownloads.sourceforge.net/tcl/tcl8.6.5-src.tar.gz')
 
-    def test_version_gitlab(self):
+    def test_dash_dot(self):
+        # name-name-ver.ver
+        # digit in name
         self.check(
-             'vtk', '7.0.0',
-             'https://gitlab.kitware.com/vtk/vtk/repository/'
-             'archive.tar.bz2?ref=v7.0.0')
+            'm4', '1.4.17',
+            'https://ftp.gnu.org/gnu/m4/m4-1.4.17.tar.gz')
+        # letter in version
         self.check(
-             'icet', '1.2.3',
-             'https://gitlab.kitware.com/icet/icet/repository/'
-             'archive.tar.gz?ref=IceT-1.2.3')
+            'gmp', '6.0.0a',
+            'https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2')
+        # version starts with 'v'
+        self.check(
+            'LaunchMON', '1.0.2',
+            'https://github.com/LLNL/LaunchMON/releases/download/v1.0.2/launchmon-v1.0.2.tar.gz')
+        # name-ver-ver.ver
         self.check(
-             'foo', '42.1337',
-             'http://example.com/org/foo/repository/'
-             'archive.zip?ref=42.1337bar')
+            'libedit', '20150325-3.1',
+            'http://thrysoee.dk/editline/libedit-20150325-3.1.tar.gz')
 
-    def test_version_github(self):
+    def test_dash_underscore(self):
+        # name-name-ver_ver
         self.check(
-            'yajl', '1.0.5',
-            'http://github.com/lloyd/yajl/tarball/1.0.5')
+            'icu4c', '57_1',
+            'http://download.icu-project.org/files/icu4c/57.1/icu4c-57_1-src.tgz')
 
-    def test_version_github_with_high_patch_number(self):
+    def test_underscore_dot(self):
+        # name_name_ver.ver
         self.check(
-            'yajl', '1.2.34',
-            'http://github.com/lloyd/yajl/tarball/v1.2.34')
+            'superlu_dist', '4.1',
+            'http://crd-legacy.lbl.gov/~xiaoye/SuperLU/superlu_dist_4.1.tar.gz')
+        self.check(
+            'pexsi', '0.9.0',
+            'https://math.berkeley.edu/~linlin/pexsi/download/pexsi_v0.9.0.tar.gz')
+        # name_name.ver.ver
+        self.check(
+            'fer', '696',
+            'ftp://ftp.pmel.noaa.gov/ferret/pub/source/fer_source.v696.tar.gz')
 
-    def test_yet_another_version(self):
+    def test_dash_dot_dash_dot(self):
+        # name-name-ver.ver-ver.ver
+        self.check(
+            'sowing', '1.1.23-p1',
+            'http://ftp.mcs.anl.gov/pub/petsc/externalpackages/sowing-1.1.23-p1.tar.gz')
         self.check(
-            'mad', '0.15.1b',
-            'http://example.com/mad-0.15.1b.tar.gz')
+            'bib2xhtml', '3.0-15-gf506',
+            'http://www.spinellis.gr/sw/textproc/bib2xhtml/bib2xhtml-v3.0-15-gf506.tar.gz')
+        # namever.ver-ver.ver
+        self.check(
+            'go', '1.4-bootstrap-20161024',
+            'https://storage.googleapis.com/golang/go1.4-bootstrap-20161024.tar.gz')
 
-    def test_lame_version_style(self):
+    def test_underscore_dash_dot(self):
+        # name_name-ver.ver
+        self.check(
+            'the_silver_searcher', '0.32.0',
+            'http://geoff.greer.fm/ag/releases/the_silver_searcher-0.32.0.tar.gz')
         self.check(
-            'lame', '398-2',
-            'http://kent.dl.sourceforge.net/sourceforge/lame/lame-398-2.tar.gz')
+            'sphinx_rtd_theme', '0.1.10a0',
+            'https://pypi.python.org/packages/source/s/sphinx_rtd_theme/sphinx_rtd_theme-0.1.10a0.tar.gz')
 
-    def test_ruby_version_style(self):
+    def test_dot_underscore_dot_dash_dot(self):
+        # name.name_ver.ver-ver.ver
         self.check(
-            'ruby', '1.9.1-p243',
-            'ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz')
+            'TH.data', '1.0-8',
+            'https://cran.r-project.org/src/contrib/TH.data_1.0-8.tar.gz')
+        self.check(
+            'XML', '3.98-1.4',
+            'https://cran.r-project.org/src/contrib/XML_3.98-1.4.tar.gz')
 
-    def test_omega_version_style(self):
+    def test_dash_dot_underscore_dot(self):
+        # name-name-ver.ver_ver.ver
+        self.check(
+            'pypar', '2.1.5_108',
+            'https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/pypar/pypar-2.1.5_108.tgz')
+        # name-namever.ver_ver.ver
         self.check(
-            'omega', '0.80.2',
-            'http://www.alcyone.com/binaries/omega/omega-0.80.2-src.tar.gz')
+            'STAR-CCM+', '11.06.010_02',
+            'file://{0}/STAR-CCM+11.06.010_02_linux-x86_64.tar.gz'.format(os.getcwd()))
 
-    def test_rc_style(self):
+    # Weird URLS
+
+    def test_version_in_path(self):
+        # github.com/repo/name/releases/download/name-vver/name
         self.check(
-            'libvorbis', '1.2.2rc1',
-            'http://downloads.xiph.org/releases/vorbis/libvorbis-1.2.2rc1.tar.bz2')
+            'nextflow', '0.20.1',
+            'https://github.com/nextflow-io/nextflow/releases/download/v0.20.1/nextflow')
 
-    def test_dash_rc_style(self):
+    def test_suffix_queries(self):
         self.check(
-            'js', '1.8.0-rc1',
-            'http://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz')
+            'swiftsim', '0.3.0',
+            'http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0')
+        self.check(
+            'sionlib', '1.7.1',
+            'http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1')
 
-    def test_angband_version_style(self):
+    def test_stem_queries(self):
+        self.check(
+            'slepc', '3.6.2',
+            'http://slepc.upv.es/download/download.php?filename=slepc-3.6.2.tar.gz')
         self.check(
-            'angband', '3.0.9b',
-            'http://rephial.org/downloads/3.0/angband-3.0.9b-src.tar.gz')
+            'otf', '1.12.5salmon',
+            'http://wwwpub.zih.tu-dresden.de/%7Emlieber/dcount/dcount.php?package=otf&get=OTF-1.12.5salmon.tar.gz')
 
-    def test_stable_suffix(self):
+    def test_single_character_name(self):
         self.check(
-            'libevent', '1.4.14b',
-            'http://www.monkey.org/~provos/libevent-1.4.14b-stable.tar.gz')
+            'R', '3.3.2',
+            'https://cloud.r-project.org/src/base/R-3/R-3.3.2.tar.gz')
+
+    def test_single_digit_version(self):
+        pass
 
-    def test_debian_style_1(self):
+    def test_name_starts_with_digit(self):
         self.check(
-            'sl', '3.03',
-            'http://ftp.de.debian.org/debian/pool/main/s/sl/sl_3.03.orig.tar.gz')
+            '3to2', '1.1.1',
+            'https://pypi.python.org/packages/source/3/3to2/3to2-1.1.1.zip')
 
-    def test_debian_style_2(self):
+    def plus_in_name(self):
         self.check(
-            'mmv', '1.01b',
-            'http://ftp.de.debian.org/debian/pool/main/m/mmv/mmv_1.01b.orig.tar.gz')
+            'gtk+', '2.24.31',
+            'http://ftp.gnome.org/pub/gnome/sources/gtk+/2.24/gtk+-2.24.31.tar.xz')
+        self.check(
+            'voro++', '0.4.6',
+            'http://math.lbl.gov/voro++/download/dir/voro++-0.4.6.tar.gz')
+
+    def test_no_version(self):
+        self.assert_not_detected('http://www.netlib.org/blas/blast-forum/cblas.tgz')
+        self.assert_not_detected('http://www.netlib.org/voronoi/triangle.zip')
 
-    def test_imagemagick_style(self):
+    def test_download_php(self):
+        # Name comes before download.php
+        self.check(
+            'sionlib', '1.7.1',
+            'http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1')
+        # Ignore download.php
+        self.check(
+            'slepc', '3.6.2',
+            'http://slepc.upv.es/download/download.php?filename=slepc-3.6.2.tar.gz')
         self.check(
-            'imagemagick', '6.7.5-7',
+            'ScientificPython', '2.8.1',
+            'https://sourcesup.renater.fr/frs/download.php/file/4411/ScientificPython-2.8.1.tar.gz')
 
-            'http://downloads.sf.net/project/machomebrew/mirror/ImageMagick-6.7.5-7.tar.bz2')
+    def test_gloox_beta_style(self):
+        self.check(
+            'gloox', '1.0-beta7',
+            'http://camaya.net/download/gloox-1.0-beta7.tar.bz2')
 
-    def test_dash_version_dash_style(self):
+    def test_sphinx_beta_style(self):
         self.check(
-            'antlr', '3.4',
-            'http://www.antlr.org/download/antlr-3.4-complete.jar')
+            'sphinx', '1.10-beta',
+            'http://sphinxsearch.com/downloads/sphinx-1.10-beta.tar.gz')
 
-    def test_apache_version_style(self):
+    def test_ruby_version_style(self):
         self.check(
-            'apache-cassandra', '1.2.0-rc2',
-            'http://www.apache.org/dyn/closer.cgi?path=/cassandra/1.2.0/apache-cassandra-1.2.0-rc2-bin.tar.gz')
+            'ruby', '1.9.1-p243',
+            'ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p243.tar.gz')
 
-    def test_jpeg_style(self):
+    def test_rc_style(self):
         self.check(
-            'jpegsrc', '8d',
-            'http://www.ijg.org/files/jpegsrc.v8d.tar.gz')
+            'libvorbis', '1.2.2rc1',
+            'http://downloads.xiph.org/releases/vorbis/libvorbis-1.2.2rc1.tar.bz2')
 
-    def test_pypy_version(self):
+    def test_dash_rc_style(self):
         self.check(
-            'pypy', '1.4.1',
-            'http://pypy.org/download/pypy-1.4.1-osx.tar.bz2')
+            'js', '1.8.0-rc1',
+            'http://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz')
 
-    def test_openssl_version(self):
+    def test_apache_version_style(self):
         self.check(
-            'openssl', '0.9.8s',
-            'http://www.openssl.org/source/openssl-0.9.8s.tar.gz')
+            'apache-cassandra', '1.2.0-rc2',
+            'http://www.apache.org/dyn/closer.cgi?path=/cassandra/1.2.0/apache-cassandra-1.2.0-rc2-bin.tar.gz')
 
     def test_xaw3d_version(self):
         self.check(
-            'xaw3d', '1.5E',
+            'Xaw3d', '1.5E',
             'ftp://ftp.visi.com/users/hawkeyd/X/Xaw3d-1.5E.tar.gz')
 
     def test_fann_version(self):
@@ -269,16 +690,6 @@ def test_fann_version(self):
             'fann', '2.1.0beta',
             'http://downloads.sourceforge.net/project/fann/fann/2.1.0beta/fann-2.1.0beta.zip')
 
-    def test_iges_version(self):
-        self.check(
-            'grads', '2.0.1',
-            'ftp://iges.org/grads/2.0/grads-2.0.1-bin-darwin9.8-intel.tar.gz')
-
-    def test_haxe_version(self):
-        self.check(
-            'haxe', '2.08',
-            'http://haxe.org/file/haxe-2.08-osx.tar.gz')
-
     def test_imap_version(self):
         self.check(
             'imap', '2007f',
@@ -289,26 +700,6 @@ def test_suite3270_version(self):
             'suite3270', '3.3.12ga7',
             'http://sourceforge.net/projects/x3270/files/x3270/3.3.12ga7/suite3270-3.3.12ga7-src.tgz')
 
-    def test_synergy_version(self):
-        self.check(
-            'synergy', '1.3.6p2',
-            'http://synergy.googlecode.com/files/synergy-1.3.6p2-MacOSX-Universal.zip')
-
-    def test_mvapich2_19_version(self):
-        self.check(
-            'mvapich2', '1.9',
-            'http://mvapich.cse.ohio-state.edu/download/mvapich2/mv2/mvapich2-1.9.tgz')
-
-    def test_mvapich2_20_version(self):
-        self.check(
-            'mvapich2', '2.0',
-            'http://mvapich.cse.ohio-state.edu/download/mvapich/mv2/mvapich2-2.0.tar.gz')
-
-    def test_hdf5_version(self):
-        self.check(
-            'hdf5', '1.8.13',
-            'http://www.hdfgroup.org/ftp/HDF5/current/src/hdf5-1.8.13.tar.bz2')
-
     def test_scalasca_version(self):
         self.check(
             'cube', '4.2.3',
@@ -317,55 +708,20 @@ def test_scalasca_version(self):
             'cube', '4.3-TP1',
             'http://apps.fz-juelich.de/scalasca/releases/cube/4.3/dist/cube-4.3-TP1.tar.gz')
 
-    def test_mpileaks_version(self):
-        self.check(
-            'mpileaks', '1.0',
-            'https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz')
-        self.check(
-            'mpileaks', '1.0',
-            'https://github.com/hpc/mpileaks/releases/download/1.0/mpileaks-1.0.tar.gz')
-
-    def test_gcc_version(self):
-        self.check(
-            'gcc', '4.4.7',
-            'http://open-source-box.org/gcc/gcc-4.4.7/gcc-4.4.7.tar.bz2')
-
-    def test_gcc_version_precedence(self):
-        # prefer the version in the tarball, not in the url prefix.
-        self.check(
-            'gcc', '4.4.7',
-            'http://open-source-box.org/gcc/gcc-4.9.2/gcc-4.4.7.tar.bz2')
-
     def test_github_raw_url(self):
         self.check(
-            'powerparser', '2.0.7',
+            'CLAMR', '2.0.7',
             'https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v2.0.7.tgz?raw=true')
 
-    def test_r_xml_version(self):
+    def test_luaposix_version(self):
         self.check(
-            'xml', '3.98-1.4',
-            'https://cran.r-project.org/src/contrib/XML_3.98-1.4.tar.gz')
+            'luaposix', '33.4.0',
+            'https://github.com/luaposix/luaposix/archive/release-v33.4.0.tar.gz')
 
     def test_nco_version(self):
         self.check(
             'nco', '4.6.2-beta03',
             'https://github.com/nco/nco/archive/4.6.2-beta03.tar.gz')
-
         self.check(
             'nco', '4.6.3-alpha04',
             'https://github.com/nco/nco/archive/4.6.3-alpha04.tar.gz')
-
-    def test_yorick_version(self):
-        self.check(
-            'yorick', '2_2_04',
-            'https://github.com/dhmunro/yorick/archive/y_2_2_04.tar.gz')
-
-    def test_luaposix_version(self):
-        self.check(
-            'luaposix', '33.4.0',
-            'https://github.com/luaposix/luaposix/archive/release-v33.4.0.tar.gz')
-
-    def test_sionlib_version(self):
-        self.check(
-            'sionlib', '1.7.1',
-            'http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1')
diff --git a/lib/spack/spack/test/url_substitution.py b/lib/spack/spack/test/url_substitution.py
index ea6374e3d2..449a3b29bf 100644
--- a/lib/spack/spack/test/url_substitution.py
+++ b/lib/spack/spack/test/url_substitution.py
@@ -22,44 +22,64 @@
 # License along with this program; if not, write to the Free Software
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##############################################################################
-"""\
-This test does sanity checks on substituting new versions into URLs
-"""
+"""Tests Spack's ability to substitute a different version into a URL."""
+
+import os
 import unittest
-import spack.url as url
+from spack.url import substitute_version
+
+
+class UrlSubstitutionTest(unittest.TestCase):
 
+    def check(self, base, version, new_url):
+        self.assertEqual(substitute_version(base, version), new_url)
 
-base = "https://comp.llnl.gov/linear_solvers/download/hypre-2.9.0b.tar.gz"
-stem = "https://comp.llnl.gov/linear_solvers/download/hypre-"
+    def test_same_version(self):
+        # Ensures that substituting the same version results in the same URL
+        self.check(
+            'http://www.mr511.de/software/libelf-0.8.13.tar.gz', '0.8.13',
+            'http://www.mr511.de/software/libelf-0.8.13.tar.gz')
 
+    def test_different_version(self):
+        # Test a completely different version syntax
+        self.check(
+            'http://www.prevanders.net/libdwarf-20130729.tar.gz', '8.12',
+            'http://www.prevanders.net/libdwarf-8.12.tar.gz')
 
-class PackageSanityTest(unittest.TestCase):
+    def test_double_version(self):
+        # Test a URL where the version appears twice
+        # It should get substituted both times
+        self.check(
+            'https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz', '2.1.3',
+            'https://github.com/hpc/mpileaks/releases/download/v2.1.3/mpileaks-2.1.3.tar.gz')
 
-    def test_hypre_url_substitution(self):
-        self.assertEqual(url.substitute_version(base, '2.9.0b'), base)
-        self.assertEqual(
-            url.substitute_version(base, '2.8.0b'), stem + "2.8.0b.tar.gz")
-        self.assertEqual(
-            url.substitute_version(base, '2.7.0b'), stem + "2.7.0b.tar.gz")
-        self.assertEqual(
-            url.substitute_version(base, '2.6.0b'), stem + "2.6.0b.tar.gz")
-        self.assertEqual(
-            url.substitute_version(base, '1.14.0b'), stem + "1.14.0b.tar.gz")
-        self.assertEqual(
-            url.substitute_version(base, '1.13.0b'), stem + "1.13.0b.tar.gz")
-        self.assertEqual(
-            url.substitute_version(base, '2.0.0'), stem + "2.0.0.tar.gz")
-        self.assertEqual(
-            url.substitute_version(base, '1.6.0'), stem + "1.6.0.tar.gz")
+    def test_partial_version_prefix(self):
+        # Test now with a partial prefix earlier in the URL
+        # This is hard to figure out so Spack only substitutes
+        # the last instance of the version
+        self.check(
+            'https://www.open-mpi.org/software/ompi/v2.1/downloads/openmpi-2.1.0.tar.bz2', '2.2.0',
+            'https://www.open-mpi.org/software/ompi/v2.1/downloads/openmpi-2.2.0.tar.bz2')
+        self.check(
+            'https://www.open-mpi.org/software/ompi/v2.1/downloads/openmpi-2.1.0.tar.bz2', '2.2',
+            'https://www.open-mpi.org/software/ompi/v2.1/downloads/openmpi-2.2.tar.bz2')
 
-    def test_otf2_url_substitution(self):
-        base = "http://www.vi-hps.org/upload/packages/otf2/otf2-1.4.tar.gz"
+    def test_no_separator(self):
+        # No separator between the name and version of the package
+        self.check(
+            'file://{0}/turbolinux702.tar.gz'.format(os.getcwd()), '703',
+            'file://{0}/turbolinux703.tar.gz'.format(os.getcwd()))
 
-        self.assertEqual(url.substitute_version(base, '1.4'), base)
+    def test_github_raw(self):
+        self.check(
+            'https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v2.0.7.tgz?raw=true', '2.0.7',
+            'https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v2.0.7.tgz?raw=true')
+        self.check(
+            'https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v2.0.7.tgz?raw=true', '4.7',
+            'https://github.com/losalamos/CLAMR/blob/packages/PowerParser_v4.7.tgz?raw=true')
 
-        self.assertEqual(
-            url.substitute_version(base, '1.3.1'),
-            "http://www.vi-hps.org/upload/packages/otf2/otf2-1.3.1.tar.gz")
-        self.assertEqual(
-            url.substitute_version(base, '1.2.1'),
-            "http://www.vi-hps.org/upload/packages/otf2/otf2-1.2.1.tar.gz")
+    def test_regex(self):
+        # Package name contains regex characters
+        self.check(
+            'http://math.lbl.gov/voro++/download/dir/voro++-0.4.6.tar.gz', '1.2.3',
+            'http://math.lbl.gov/voro++/download/dir/voro++-1.2.3.tar.gz')
diff --git a/lib/spack/spack/test/web.py b/lib/spack/spack/test/web.py
index 9a7f4d9f8b..9fa95a8d18 100644
--- a/lib/spack/spack/test/web.py
+++ b/lib/spack/spack/test/web.py
@@ -23,7 +23,6 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##############################################################################
 """Tests for web.py."""
-import pytest
 import os
 
 import spack
@@ -141,7 +140,6 @@ def test_find_versions_of_archive_2():
     assert ver('2.0.0') in versions
 
 
-@pytest.mark.xfail
 def test_find_exotic_versions_of_archive_2():
     versions = find_versions_of_archive(root_tarball, root, list_depth=2)
     # up for grabs to make this better.
@@ -157,7 +155,6 @@ def test_find_versions_of_archive_3():
     assert ver('4.5') in versions
 
 
-@pytest.mark.xfail
 def test_find_exotic_versions_of_archive_3():
     versions = find_versions_of_archive(root_tarball, root, list_depth=3)
     assert ver('2.0.0b2') in versions
diff --git a/lib/spack/spack/url.py b/lib/spack/spack/url.py
index 38ff74f7bc..174f7d0b3c 100644
--- a/lib/spack/spack/url.py
+++ b/lib/spack/spack/url.py
@@ -71,7 +71,7 @@ def find_list_url(url):
 
     url_types = [
         # e.g. https://github.com/llnl/callpath/archive/v1.0.1.tar.gz
-        (r'^(https://github.com/[^/]+/[^/]+)/archive/',
+        (r'(.*github\.com/[^/]+/[^/]+)/archive/',
          lambda m: m.group(1) + '/releases')]
 
     for pattern, fun in url_types:
@@ -101,6 +101,177 @@ def strip_query_and_fragment(path):
         return (path, '')  # Ignore URL parse errors here
 
 
+def strip_version_suffixes(path):
+    """Some tarballs contain extraneous information after the version:
+
+    * ``bowtie2-2.2.5-source``
+    * ``libevent-2.0.21-stable``
+    * ``cuda_8.0.44_linux.run``
+
+    These strings are not part of the version number and should be ignored.
+    This function strips those suffixes off and returns the remaining string.
+    The goal is that the version is always the last thing in ``path``:
+
+    * ``bowtie2-2.2.5``
+    * ``libevent-2.0.21``
+    * ``cuda_8.0.44``
+
+    :param str path: The filename or URL for the package
+    :return: The ``path`` with any extraneous suffixes removed
+    :rtype: str
+    """
+    # NOTE: This could be done with complicated regexes in parse_version_offset
+    # NOTE: The problem is that we would have to add these regexes to the end
+    # NOTE: of every single version regex. Easier to just strip them off
+    # NOTE: permanently
+
+    suffix_regexes = [
+        # Download type
+        '[Ii]nstall',
+        'all',
+        'src(_0)?',
+        '[Ss]ources?',
+        'file',
+        'full',
+        'single',
+        'public',
+        'with[a-zA-Z_-]+',
+        'bin',
+        'binary',
+        'run',
+        '[Uu]niversal',
+        'jar',
+        'complete',
+        'oss',
+        'gem',
+        'tar',
+        'sh',
+
+        # Download version
+        'stable',
+        '[Ff]inal',
+        'rel',
+        'orig',
+        'dist',
+        '\+',
+
+        # License
+        'gpl',
+
+        # Arch
+        # Needs to come before and after OS, appears in both orders
+        'ia32',
+        'intel',
+        'amd64',
+        'x64',
+        'x86_64',
+        'x86',
+        'i[36]86',
+        'ppc64(le)?',
+        'armv?(7l|6l|64)',
+
+        # OS
+        '[Ll]inux(_64)?',
+        '[Uu]ni?x',
+        '[Ss]un[Oo][Ss]',
+        '[Mm]ac[Oo][Ss][Xx]?',
+        '[Oo][Ss][Xx]',
+        '[Dd]arwin(64)?',
+        '[Aa]pple',
+        '[Ww]indows',
+        '[Ww]in(64|32)?',
+        '[Cc]ygwin(64|32)?',
+        '[Mm]ingw',
+
+        # Arch
+        # Needs to come before and after OS, appears in both orders
+        'ia32',
+        'intel',
+        'amd64',
+        'x64',
+        'x86_64',
+        'x86',
+        'i[36]86',
+        'ppc64(le)?',
+        'armv?(7l|6l|64)?',
+
+        # PyPI
+        '[._-]py[23].*\.whl',
+        '[._-]cp[23].*\.whl',
+        '[._-]win.*\.exe',
+    ]
+
+    for regex in suffix_regexes:
+        # Remove the suffix from the end of the path
+        # This may be done multiple times
+        path = re.sub(r'[._-]?' + regex + '$', '', path)
+
+    return path
+
+
+def strip_name_suffixes(path, version):
+    """Most tarballs contain a package name followed by a version number.
+    However, some also contain extraneous information in-between the name
+    and version:
+
+    * ``rgb-1.0.6``
+    * ``converge_install_2.3.16``
+    * ``jpegsrc.v9b``
+
+    These strings are not part of the package name and should be ignored.
+    This function strips the version number and any extraneous suffixes
+    off and returns the remaining string. The goal is that the name is
+    always the last thing in ``path``:
+
+    * ``rgb``
+    * ``converge``
+    * ``jpeg``
+
+    :param str path: The filename or URL for the package
+    :param str version: The version detected for this URL
+    :return: The ``path`` with any extraneous suffixes removed
+    :rtype: str
+    """
+    # NOTE: This could be done with complicated regexes in parse_name_offset
+    # NOTE: The problem is that we would have to add these regexes to every
+    # NOTE: single name regex. Easier to just strip them off permanently
+
+    suffix_regexes = [
+        # Strip off the version and anything after it
+
+        # name-ver
+        # name_ver
+        # name.ver
+        r'[._-]v?' + str(version) + '.*',
+
+        # namever
+        str(version) + '.*',
+
+        # Download type
+        'install',
+        'src',
+        '(open)?[Ss]ources?',
+        '[._-]std',
+
+        # Download version
+        'snapshot',
+        'distrib',
+
+        # VCS
+        '0\+bzr',
+
+        # License
+        'gpl',
+    ]
+
+    for regex in suffix_regexes:
+        # Remove the suffix from the end of the path
+        # This may be done multiple times
+        path = re.sub('[._-]?' + regex + '$', '', path)
+
+    return path
+
+
 def split_url_extension(path):
     """Some URLs have a query string, e.g.:
 
@@ -125,7 +296,7 @@ def split_url_extension(path):
     prefix, ext, suffix = path, '', ''
 
     # Strip off sourceforge download suffix.
-    match = re.search(r'((?:sourceforge.net|sf.net)/.*)(/download)$', path)
+    match = re.search(r'((?:sourceforge\.net|sf\.net)/.*)(/download)$', path)
     if match:
         prefix, suffix = match.groups()
 
@@ -189,8 +360,20 @@ def parse_version_offset(path):
     path, ext, suffix = split_url_extension(path)
 
     # stem:   Everything from path after the final '/'
-    stem = os.path.basename(path)
-    offset = len(path) - len(stem)
+    original_stem = os.path.basename(path)
+
+    # Try to strip off anything after the version number
+    stem = strip_version_suffixes(original_stem)
+
+    # Assumptions:
+    #
+    # 1. version always comes after the name
+    # 2. separators include '-', '_', and '.'
+    # 3. names can contain A-Z, a-z, 0-9, '+', separators
+    # 4. versions can contain A-Z, a-z, 0-9, separators
+    # 5. versions always start with a digit
+    # 6. versions are often prefixed by a 'v' character
+    # 7. separators are most reliable to determine name/version boundaries
 
     # List of the following format:
     #
@@ -202,87 +385,118 @@ def parse_version_offset(path):
     # The first regex that matches string will be used to determine
     # the version of the package. Thefore, hyperspecific regexes should
     # come first while generic, catch-all regexes should come last.
+    # With that said, regular expressions are slow, so if possible, put
+    # ones that only catch one or two URLs at the bottom.
     version_regexes = [
-        # GitHub tarballs, e.g. v1.2.3
-        (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+)$', path),
+        # 1st Pass: Simplest case
+        # Assume name contains no digits and version contains no letters
+        # e.g. libpng-1.6.27
+        (r'^[a-zA-Z+._-]+[._-]v?(\d[\d._-]*)$', stem),
 
-        # e.g. https://github.com/sam-github/libnet/tarball/libnet-1.1.4
-        (r'github.com/.+/(?:zip|tar)ball/.*-((\d+\.)+\d+)$', path),
+        # 2nd Pass: Version only
+        # Assume version contains no letters
 
-        # e.g. https://github.com/isaacs/npm/tarball/v0.2.5-1
-        (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+-(\d+))$', path),
+        # ver
+        # e.g. 3.2.7, 7.0.2-7, v3.3.0, v1_6_3
+        (r'^v?(\d[\d._-]*)$', stem),
 
-        # e.g. https://github.com/petdance/ack/tarball/1.93_02
-        (r'github.com/.+/(?:zip|tar)ball/v?((\d+\.)+\d+_(\d+))$', path),
+        # 3rd Pass: No separator characters are used
+        # Assume name contains no digits
 
-        # Yorick is very special.
-        # e.g. https://github.com/dhmunro/yorick/archive/y_2_2_04.tar.gz
-        (r'github.com/[^/]+/yorick/archive/y_(\d+(?:_\d+)*)$', path),
+        # namever
+        # e.g. turbolinux702, nauty26r7
+        (r'^[a-zA-Z+]*(\d[\da-zA-Z]*)$', stem),
 
-        # e.g. https://github.com/hpc/lwgrp/archive/v1.0.1.tar.gz
-        (r'github.com/[^/]+/[^/]+/archive/(?:release-)?v?(\w+(?:[.-]\w+)*)$', path),  # noqa
+        # 4th Pass: A single separator character is used
+        # Assume name contains no digits
 
-        # e.g. https://github.com/erlang/otp/tarball/OTP_R15B01 (erlang style)
-        (r'[-_](R\d+[AB]\d*(-\d+)?)', path),
+        # name-name-ver-ver
+        # e.g. panda-2016-03-07, gts-snapshot-121130, cdd-061a
+        (r'^[a-zA-Z+-]*(\d[\da-zA-Z-]*)$', stem),
 
-        # e.g., https://github.com/hpc/libcircle/releases/download/0.2.1-rc.1/libcircle-0.2.1-rc.1.tar.gz
-        # e.g.,
-        # https://github.com/hpc/mpileaks/releases/download/v1.0/mpileaks-1.0.tar.gz
-        (r'github.com/[^/]+/[^/]+/releases/download/v?([^/]+)/.*$', path),
+        # name_name_ver_ver
+        # e.g. tinyxml_2_6_2, boost_1_55_0, tbb2017_20161128, v1_6_3
+        (r'^[a-zA-Z+_]*(\d[\da-zA-Z_]*)$', stem),
 
-        # GitLab syntax:
-        #   {baseUrl}{/organization}{/projectName}/repository/archive.{fileEnding}?ref={gitTag}
-        #   as with github releases, we hope a version can be found in the
-        #   git tag
-        # Search dotted versions:
-        #   e.g., https://gitlab.kitware.com/vtk/vtk/repository/archive.tar.bz2?ref=v7.0.0
-        #   e.g., https://example.com/org/repo/repository/archive.tar.bz2?ref=SomePrefix-2.1.1
-        #   e.g., http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1
-        (r'\?ref=(?:.*-|v)*((\d+\.)+\d+).*$', suffix),
-        (r'\?version=((\d+\.)+\d+)', suffix),
+        # name.name.ver.ver
+        # e.g. prank.source.150803, jpegsrc.v9b, atlas3.11.34, geant4.10.01.p03
+        (r'^[a-zA-Z+.]*(\d[\da-zA-Z.]*)$', stem),
 
-        # e.g. boost_1_39_0
-        (r'((\d+_)+\d+)$', stem),
+        # 5th Pass: Two separator characters are used
+        # Name may contain digits, version may contain letters
 
-        # e.g. foobar-4.5.1-1
-        # e.g. ruby-1.9.1-p243
-        (r'-((\d+\.)*\d\.\d+-(p|rc|RC)?\d+)(?:[-._](?:bin|dist|stable|src|sources))?$', stem),  # noqa
+        # name-name-ver.ver
+        # e.g. m4-1.4.17, gmp-6.0.0a, launchmon-v1.0.2
+        (r'^[a-zA-Z\d+-]+-v?(\d[\da-zA-Z.]*)$', stem),
 
-        # e.g. lame-398-1
-        (r'-((\d)+-\d)', stem),
+        # name-name-ver_ver
+        # e.g. icu4c-57_1
+        (r'^[a-zA-Z\d+-]+-v?(\d[\da-zA-Z_]*)$', stem),
 
-        # e.g. foobar_1.2-3 or 3.98-1.4
-        (r'_((\d+\.)+\d+(-(\d+(\.\d+)?))?[a-z]?)', stem),
+        # name_name_ver.ver
+        # e.g. superlu_dist_4.1, pexsi_v0.9.0
+        (r'^[a-zA-Z\d+_]+_v?(\d[\da-zA-Z.]*)$', stem),
 
-        # e.g. foobar-4.5.1
-        (r'-((\d+\.)*\d+)$', stem),
+        # name_name.ver.ver
+        # e.g. fer_source.v696
+        (r'^[a-zA-Z\d+_]+\.v?(\d[\da-zA-Z.]*)$', stem),
 
-        # e.g. foobar-4.5.1b, foobar4.5RC, foobar.v4.5.1b
-        (r'[-._]?v?((\d+\.)*\d+[-._]?([a-z]|rc|RC|tp|TP?)\d*)$', stem),
+        # name-name-ver.ver-ver.ver
+        # e.g. sowing-1.1.23-p1, bib2xhtml-v3.0-15-gf506, 4.6.3-alpha04
+        (r'^(?:[a-zA-Z\d+-]+-)?v?(\d[\da-zA-Z.-]*)$', stem),
 
-        # e.g. foobar-4.5.0-beta1, or foobar-4.50-beta
-        (r'-((\d+\.)*\d+-beta(\d+)?)$', stem),
+        # namever.ver-ver.ver
+        # e.g. go1.4-bootstrap-20161024
+        (r'^[a-zA-Z+]+v?(\d[\da-zA-Z.-]*)$', stem),
 
-        # e.g. foobar4.5.1
-        (r'((\d+\.)*\d+)$', stem),
+        # 6th Pass: All three separator characters are used
+        # Name may contain digits, version may contain letters
 
-        # e.g. foobar-4.5.0-bin
-        (r'-((\d+\.)+\d+[a-z]?)[-._](bin|dist|stable|src|sources?)$', stem),
+        # name_name-ver.ver
+        # e.g. the_silver_searcher-0.32.0, sphinx_rtd_theme-0.1.10a0
+        (r'^[a-zA-Z\d+_]+-v?(\d[\da-zA-Z.]*)$', stem),
 
-        # e.g. dash_0.5.5.1.orig.tar.gz (Debian style)
-        (r'_((\d+\.)+\d+[a-z]?)[.]orig$', stem),
+        # name.name_ver.ver-ver.ver
+        # e.g. TH.data_1.0-8, XML_3.98-1.4
+        (r'^[a-zA-Z\d+.]+_v?(\d[\da-zA-Z.-]*)$', stem),
 
-        # e.g. http://www.openssl.org/source/openssl-0.9.8s.tar.gz
-        (r'-v?([^-]+(-alpha|-beta)?)', stem),
+        # name-name-ver.ver_ver.ver
+        # e.g. pypar-2.1.5_108
+        (r'^[a-zA-Z\d+-]+-v?(\d[\da-zA-Z._]*)$', stem),
 
-        # e.g. astyle_1.23_macosx.tar.gz
-        (r'_([^_]+(_alpha|_beta)?)', stem),
+        # name.name_name-ver.ver
+        # e.g. tap.py-1.6, backports.ssl_match_hostname-3.5.0.1
+        (r'^[a-zA-Z\d+._]+-v?(\d[\da-zA-Z.]*)$', stem),
 
-        # e.g. http://mirrors.jenkins-ci.org/war/1.486/jenkins.war
-        (r'\/(\d\.\d+)\/', path),
+        # name-namever.ver_ver.ver
+        # e.g. STAR-CCM+11.06.010_02
+        (r'^[a-zA-Z+-]+(\d[\da-zA-Z._]*)$', stem),
 
-        # e.g. http://www.ijg.org/files/jpegsrc.v8d.tar.gz
-        (r'\.v(\d+[a-z]?)', stem)
+        # 7th Pass: Specific VCS
+
+        # bazaar
+        # e.g. libvterm-0+bzr681
+        (r'bzr(\d[\da-zA-Z._-]*)$', stem),
+
+        # 8th Pass: Version in path
+
+        # github.com/repo/name/releases/download/vver/name
+        # e.g. https://github.com/nextflow-io/nextflow/releases/download/v0.20.1/nextflow
+        (r'github\.com/[^/]+/[^/]+/releases/download/[a-zA-Z+._-]*v?(\d[\da-zA-Z._-]*)/', path),  # noqa
+
+        # 9th Pass: Query strings
+
+        # e.g. http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0
+        (r'\?ref=[a-zA-Z+._-]*v?(\d[\da-zA-Z._-]*)$', suffix),
+
+        # e.g. http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1
+        (r'\?version=v?(\d[\da-zA-Z._-]*)$', suffix),
+
+        # e.g. http://slepc.upv.es/download/download.php?filename=slepc-3.6.2.tar.gz
+        (r'\?filename=[a-zA-Z\d+-]+-v?(\d[\da-zA-Z.]*)$', stem),
+
+        # e.g. http://wwwpub.zih.tu-dresden.de/%7Emlieber/dcount/dcount.php?package=otf&get=OTF-1.12.5salmon.tar.gz
+        (r'\?package=[a-zA-Z\d+-]+&get=[a-zA-Z\d+-]+-v?(\d[\da-zA-Z.]*)$', stem),  # noqa
     ]
 
     for i, version_regex in enumerate(version_regexes):
@@ -292,9 +506,15 @@ def parse_version_offset(path):
             version = match.group(1)
             start   = match.start(1)
 
-            # if we matched from the basename, then add offset in.
+            # If we matched from the stem or suffix, we need to add offset
+            offset = 0
             if match_string is stem:
-                start += offset
+                offset = len(path) - len(original_stem)
+            elif match_string is suffix:
+                offset = len(path)
+                if ext:
+                    offset += len(ext) + 1  # .tar.gz is converted to tar.gz
+            start += offset
 
             return version, start, len(version), i, regex
 
@@ -342,7 +562,7 @@ def parse_name_offset(path, v=None):
         except UndetectableVersionError:
             # Not all URLs contain a version. We still want to be able
             # to determine a name if possible.
-            v = ''
+            v = 'unknown'
 
     # path:   The prefix of the URL, everything before the ext and suffix
     # ext:    The file extension
@@ -350,8 +570,10 @@ def parse_name_offset(path, v=None):
     path, ext, suffix = split_url_extension(path)
 
     # stem:   Everything from path after the final '/'
-    stem = os.path.basename(path)
-    offset = len(path) - len(stem)
+    original_stem = os.path.basename(path)
+
+    # Try to strip off anything after the package name
+    stem = strip_name_suffixes(original_stem, v)
 
     # List of the following format:
     #
@@ -363,26 +585,45 @@ def parse_name_offset(path, v=None):
     # The first regex that matches string will be used to determine
     # the name of the package. Thefore, hyperspecific regexes should
     # come first while generic, catch-all regexes should come last.
+    # With that said, regular expressions are slow, so if possible, put
+    # ones that only catch one or two URLs at the bottom.
     name_regexes = [
-        (r'/sourceforge/([^/]+)/', path),
-        (r'github.com/[^/]+/[^/]+/releases/download/%s/(.*)-%s$' %
-         (v, v), path),
-        (r'/([^/]+)/(tarball|zipball)/', path),
-        (r'/([^/]+)[_.-](bin|dist|stable|src|sources)[_.-]%s' % v, path),
-        (r'github.com/[^/]+/([^/]+)/archive', path),
-        (r'github.com/[^/]+/([^/]+)/releases', path),
-        (r'[^/]+/([^/]+)/repository/archive', path),  # gitlab
-        (r'([^/]+)/download.php', path),
-
-        (r'([^/]+)[_.-]v?%s' % v, stem),   # prefer the stem
-        (r'([^/]+)%s' % v, stem),
-
-        # accept the path if name is not in stem.
-        (r'/([^/]+)[_.-]v?%s' % v, path),
-        (r'/([^/]+)%s' % v, path),
-
-        (r'^([^/]+)[_.-]v?%s' % v, path),
-        (r'^([^/]+)%s' % v, path)
+        # 1st Pass: Common repositories
+
+        # GitHub: github.com/repo/name/
+        # e.g. https://github.com/nco/nco/archive/4.6.2.tar.gz
+        (r'github\.com/[^/]+/([^/]+)', path),
+
+        # GitLab: gitlab.*/repo/name/
+        # e.g. http://gitlab.cosma.dur.ac.uk/swift/swiftsim/repository/archive.tar.gz?ref=v0.3.0
+        (r'gitlab[^/]+/[^/]+/([^/]+)', path),
+
+        # Bitbucket: bitbucket.org/repo/name/
+        # e.g. https://bitbucket.org/glotzer/hoomd-blue/get/v1.3.3.tar.bz2
+        (r'bitbucket\.org/[^/]+/([^/]+)', path),
+
+        # PyPI: pypi.(python.org|io)/packages/source/first-letter/name/
+        # e.g. https://pypi.python.org/packages/source/m/mpmath/mpmath-all-0.19.tar.gz
+        # e.g. https://pypi.io/packages/source/b/backports.ssl_match_hostname/backports.ssl_match_hostname-3.5.0.1.tar.gz
+        (r'pypi\.(?:python\.org|io)/packages/source/[A-Za-z\d]/([^/]+)', path),
+
+        # 2nd Pass: Query strings
+
+        # ?filename=name-ver.ver
+        # e.g. http://slepc.upv.es/download/download.php?filename=slepc-3.6.2.tar.gz
+        (r'\?filename=([A-Za-z\d+-]+)$', stem),
+
+        # ?package=name
+        # e.g. http://wwwpub.zih.tu-dresden.de/%7Emlieber/dcount/dcount.php?package=otf&get=OTF-1.12.5salmon.tar.gz
+        (r'\?package=([A-Za-z\d+-]+)', stem),
+
+        # download.php
+        # e.g. http://apps.fz-juelich.de/jsc/sionlib/download.php?version=1.7.1
+        (r'([^/]+)/download.php$', path),
+
+        # 3rd Pass: Name followed by version in archive
+
+        (r'^([A-Za-z\d+\._-]+)$', stem),
     ]
 
     for i, name_regex in enumerate(name_regexes):
@@ -392,13 +633,15 @@ def parse_name_offset(path, v=None):
             name  = match.group(1)
             start = match.start(1)
 
-            # if we matched from the basename, then add offset in.
+            # If we matched from the stem or suffix, we need to add offset
+            offset = 0
             if match_string is stem:
-                start += offset
-
-            # package names should be lowercase and separated by dashes.
-            name = name.lower()
-            name = re.sub('[_.]', '-', name)
+                offset = len(path) - len(original_stem)
+            elif match_string is suffix:
+                offset = len(path)
+                if ext:
+                    offset += len(ext) + 1  # .tar.gz is converted to tar.gz
+            start += offset
 
             return name, start, len(name), i, regex
 
@@ -431,6 +674,9 @@ def parse_name_and_version(path):
         The version of the package
 
     :rtype: tuple
+
+    :raises UndetectableVersionError: If the URL does not match any regexes
+    :raises UndetectableNameError: If the URL does not match any regexes
     """
     ver = parse_version(path)
     name = parse_name(path, ver)
@@ -457,6 +703,22 @@ def cumsum(elts, init=0, fn=lambda x: x):
     return sums
 
 
+def find_all(substring, string):
+    """Returns a list containing the indices of
+    every occurrence of substring in string."""
+
+    occurrences = []
+    index = 0
+    while index < len(string):
+        index = string.find(substring, index)
+        if index == -1:
+            break
+        occurrences.append(index)
+        index += len(substring)
+
+    return occurrences
+
+
 def substitution_offsets(path):
     """This returns offsets for substituting versions and names in the
        provided path.  It is a helper for :func:`substitute_version`.
@@ -468,65 +730,34 @@ def substitution_offsets(path):
     except UndetectableNameError:
         return (None, -1, -1, (), ver, vs, vl, (vs,))
     except UndetectableVersionError:
-        return (None, -1, -1, (), None, -1, -1, ())
-
-    # protect extensions like bz2 from getting inadvertently
-    # considered versions.
-    path = comp.strip_extension(path)
-
-    # Construct a case-insensitive regular expression for the package name.
-    name_re = '(%s)' % insensitize(name)
-
-    # Split the string apart by things that match the name so that if the
-    # name contains numbers or things that look like versions, we don't
-    # accidentally substitute them with a version.
-    name_parts = re.split(name_re, path)
-
-    offsets = cumsum(name_parts, 0, len)
-    name_offsets = offsets[1::2]
+        try:
+            name, ns, nl, ni, nregex = parse_name_offset(path)
+            return (name, ns, nl, (ns,), None, -1, -1, ())
+        except UndetectableNameError:
+            return (None, -1, -1, (), None, -1, -1, ())
 
-    ver_offsets = []
-    for i in range(0, len(name_parts), 2):
-        vparts = re.split(ver, name_parts[i])
-        voffsets = cumsum(vparts, offsets[i], len)
-        ver_offsets.extend(voffsets[1::2])
+    # Find the index of every occurrence of name and ver in path
+    name_offsets = find_all(name, path)
+    ver_offsets  = find_all(ver,  path)
 
-    return (name, ns, nl, tuple(name_offsets),
-            ver,  vs, vl, tuple(ver_offsets))
+    return (name, ns, nl, name_offsets,
+            ver,  vs, vl, ver_offsets)
 
 
 def wildcard_version(path):
     """Find the version in the supplied path, and return a regular expression
        that will match this path with any version in its place.
     """
-    # Get name and version, so we can treat them specially
-    name, v = parse_name_and_version(path)
+    # Get version so we can replace it with a wildcard
+    version = parse_version(path)
 
-    path, ext, suffix = split_url_extension(path)
+    # Split path by versions
+    vparts = path.split(str(version))
+
+    # Replace each version with a generic capture group to find versions
+    # and escape everything else so it's not interpreted as a regex
+    result = '(\d.*)'.join(re.escape(vp) for vp in vparts)
 
-    # Construct a case-insensitive regular expression for the package name.
-    name_re = '(%s)' % insensitize(name)
-
-    # Split the string apart by things that match the name so that if the
-    # name contains numbers or things that look like versions, we don't
-    # catch them with the version wildcard.
-    name_parts = re.split(name_re, path)
-
-    # Even elements in the array did *not* match the name
-    for i in range(0, len(name_parts), 2):
-        # Split each part by things that look like versions.
-        vparts = re.split(v.wildcard(), name_parts[i])
-
-        # Replace each version with a generic capture group to find versions.
-        # And escape everything else so it's not interpreted as a regex
-        vgroup = '(%s)' % v.wildcard()
-        name_parts[i] = vgroup.join(re.escape(vp) for vp in vparts)
-
-    # Put it all back together with original name matches intact.
-    result = ''.join(name_parts)
-    if ext:
-        result += '.' + ext
-    result += suffix
     return result
 
 
diff --git a/lib/spack/spack/util/naming.py b/lib/spack/spack/util/naming.py
index 1f2bfa88cf..cd35008aed 100644
--- a/lib/spack/spack/util/naming.py
+++ b/lib/spack/spack/util/naming.py
@@ -39,6 +39,7 @@
     'validate_fully_qualified_module_name',
     'validate_module_name',
     'possible_spack_module_names',
+    'simplify_name',
     'NamespaceTrie']
 
 # Valid module names can contain '-' but can't start with it.
@@ -108,6 +109,50 @@ def possible_spack_module_names(python_mod_name):
     return results
 
 
+def simplify_name(name):
+    """Simplifies a name which may include uppercase letters, periods,
+    underscores, and pluses. In general, we want our package names to
+    only contain lowercase letters, digits, and dashes.
+
+    :param str name: The original name of the package
+    :return: The new name of the package
+    :rtype: str
+    """
+    # Convert CamelCase to Dashed-Names
+    # e.g. ImageMagick -> Image-Magick
+    # e.g. SuiteSparse -> Suite-Sparse
+    # name = re.sub('([a-z])([A-Z])', r'\1-\2', name)
+
+    # Rename Intel downloads
+    # e.g. l_daal, l_ipp, l_mkl -> daal, ipp, mkl
+    if name.startswith('l_'):
+        name = name[2:]
+
+    # Convert UPPERCASE to lowercase
+    # e.g. SAMRAI -> samrai
+    name = name.lower()
+
+    # Replace '_' and '.' with '-'
+    # e.g. backports.ssl_match_hostname -> backports-ssl-match-hostname
+    name = name.replace('_', '-')
+    name = name.replace('.', '-')
+
+    # Replace "++" with "pp" and "+" with "-plus"
+    # e.g. gtk+   -> gtk-plus
+    # e.g. voro++ -> voropp
+    name = name.replace('++', 'pp')
+    name = name.replace('+', '-plus')
+
+    # Simplify Lua package names
+    # We don't want "lua" to occur multiple times in the name
+    name = re.sub('^(lua)([^-])', r'\1-\2', name)
+
+    # Simplify Bio++ package names
+    name = re.sub('^(bpp)([^-])', r'\1-\2', name)
+
+    return name
+
+
 def valid_module_name(mod_name):
     """Return whether mod_name is valid for use in Spack."""
     return bool(re.match(_valid_module_re, mod_name))
diff --git a/lib/spack/spack/util/web.py b/lib/spack/spack/util/web.py
index 8e2dd34635..f803c6cea3 100644
--- a/lib/spack/spack/util/web.py
+++ b/lib/spack/spack/util/web.py
@@ -268,6 +268,14 @@ def find_versions_of_archive(archive_urls, list_url=None, list_depth=0):
         # part, not the full path.
         url_regex = os.path.basename(url_regex)
 
+        # We need to add a / to the beginning of the regex to prevent
+        # Spack from picking up similarly named packages like:
+        #   https://cran.r-project.org/src/contrib/pls_2.6-0.tar.gz
+        #   https://cran.r-project.org/src/contrib/enpls_5.7.tar.gz
+        #   https://cran.r-project.org/src/contrib/autopls_1.3.tar.gz
+        #   https://cran.r-project.org/src/contrib/matrixpls_1.0.4.tar.gz
+        url_regex = '/' + url_regex
+
         # We need to add a $ anchor to the end of the regex to prevent
         # Spack from picking up signature files like:
         #   .asc
@@ -275,7 +283,9 @@ def find_versions_of_archive(archive_urls, list_url=None, list_depth=0):
         #   .sha256
         #   .sig
         # However, SourceForge downloads still need to end in '/download'.
-        regexes.append(url_regex + '(\/download)?$')
+        url_regex += '(\/download)?$'
+
+        regexes.append(url_regex)
 
     # Build a dict version -> URL from any links that match the wildcards.
     versions = {}
diff --git a/lib/spack/spack/version.py b/lib/spack/spack/version.py
index c8395aeb29..89fcc9aaa7 100644
--- a/lib/spack/spack/version.py
+++ b/lib/spack/spack/version.py
@@ -194,35 +194,6 @@ def satisfies(self, other):
         nother = len(other.version)
         return nother <= nself and self.version[:nother] == other.version
 
-    def wildcard(self):
-        """Create a regex that will match variants of this version string."""
-        def a_or_n(seg):
-            if type(seg) == int:
-                return r'[0-9]+'
-            else:
-                return r'[a-zA-Z]+'
-
-        version = self.version
-
-        # Use a wildcard for separators, in case a version is written
-        # two different ways (e.g., boost writes 1_55_0 and 1.55.0)
-        sep_re = '[_.-]'
-        separators = ('',) + (sep_re,) * len(self.separators)
-
-        version += (version[-1],) * 2
-        separators += (sep_re,) * 2
-
-        segments = [a_or_n(seg) for seg in version]
-
-        wc = segments[0]
-        for i in range(1, len(separators)):
-            wc += '(?:' + separators[i] + segments[i]
-
-        # Add possible alpha or beta indicator at the end of each segemnt
-        # We treat these specially b/c they're so common.
-        wc += '(?:[a-z]|alpha|beta)?)?' * (len(segments) - 1)
-        return wc
-
     def __iter__(self):
         return iter(self.version)
 
diff --git a/share/spack/spack-completion.bash b/share/spack/spack-completion.bash
index 726e1c81cb..819dcc06ab 100755
--- a/share/spack/spack-completion.bash
+++ b/share/spack/spack-completion.bash
@@ -732,20 +732,21 @@ function _spack_url {
     then
         compgen -W "-h --help" -- "$cur"
     else
-        compgen -W "list parse test" -- "$cur"
+        compgen -W "list parse summary" -- "$cur"
     fi
 }
 
 function _spack_url_list {
-    compgen -W "-h --help -c --color -e --extrapolation -n --incorrect-name
-                -v --incorrect-version" -- "$cur"
+    compgen -W "-h --help -c --color -e --extrapolation
+                -n --incorrect-name -N --correct-name
+                -v --incorrect-version -V --correct-version" -- "$cur"
 }
 
 function _spack_url_parse {
     compgen -W "-h --help -s --spider" -- "$cur"
 }
 
-function _spack_url_test {
+function _spack_url_summary {
     compgen -W "-h --help" -- "$cur"
 }
 
diff --git a/var/spack/repos/builtin/packages/automake/package.py b/var/spack/repos/builtin/packages/automake/package.py
index 8643f5d836..4f022e5cad 100644
--- a/var/spack/repos/builtin/packages/automake/package.py
+++ b/var/spack/repos/builtin/packages/automake/package.py
@@ -29,7 +29,7 @@ class Automake(AutotoolsPackage):
     """Automake -- make file builder part of autotools"""
 
     homepage = 'http://www.gnu.org/software/automake/'
-    url      = 'http://ftp.gnu.org/gnu/automake/automake-1.14.tar.gz'
+    url      = 'http://ftp.gnu.org/gnu/automake/automake-1.15.tar.gz'
 
     version('1.15',   '716946a105ca228ab545fc37a70df3a3')
     version('1.14.1', 'd052a3e884631b9c7892f2efce542d75')
diff --git a/var/spack/repos/builtin/packages/bib2xhtml/package.py b/var/spack/repos/builtin/packages/bib2xhtml/package.py
index b356038180..56038eea18 100644
--- a/var/spack/repos/builtin/packages/bib2xhtml/package.py
+++ b/var/spack/repos/builtin/packages/bib2xhtml/package.py
@@ -33,9 +33,6 @@ class Bib2xhtml(Package):
 
     version('3.0-15-gf506', 'a26ba02fe0053bbbf2277bdf0acf8645')
 
-    def url_for_version(self, v):
-        return ('http://www.spinellis.gr/sw/textproc/bib2xhtml/bib2xhtml-v%s.tar.gz' % v)
-
     def install(self, spec, prefix):
         # Add the bst include files to the install directory
         bst_include = join_path(prefix.share, 'bib2xhtml')
diff --git a/var/spack/repos/builtin/packages/bison/package.py b/var/spack/repos/builtin/packages/bison/package.py
index 133fcc5fc3..e9bfa32b39 100644
--- a/var/spack/repos/builtin/packages/bison/package.py
+++ b/var/spack/repos/builtin/packages/bison/package.py
@@ -31,7 +31,7 @@ class Bison(AutotoolsPackage):
     generalized LR (GLR) parser employing LALR(1) parser tables."""
 
     homepage = "http://www.gnu.org/software/bison/"
-    url      = "http://ftp.gnu.org/gnu/bison/bison-3.0.tar.gz"
+    url      = "http://ftp.gnu.org/gnu/bison/bison-3.0.4.tar.gz"
 
     version('3.0.4', 'a586e11cd4aff49c3ff6d3b6a4c9ccf8')
     version('2.7',   'ded660799e76fb1667d594de1f7a0da9')
diff --git a/var/spack/repos/builtin/packages/blast-plus/package.py b/var/spack/repos/builtin/packages/blast-plus/package.py
index 02db14f478..53f09c03a3 100644
--- a/var/spack/repos/builtin/packages/blast-plus/package.py
+++ b/var/spack/repos/builtin/packages/blast-plus/package.py
@@ -39,14 +39,9 @@
 class BlastPlus(AutotoolsPackage):
     """Basic Local Alignment Search Tool."""
 
-
     homepage = "http://blast.ncbi.nlm.nih.gov/"
     url      = "https://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/2.6.0/ncbi-blast-2.6.0+-src.tar.gz"
 
-    def url_for_version(self, version):
-        url = "https://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/{0}/ncbi-blast-{0}+-src.tar.gz"
-        return url.format(version)
-
     version('2.6.0',  'c8ce8055b10c4d774d995f88c7cc6225')
     version('2.2.30', 'f8e9a5eb368173142fe6867208b73715')
 
diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py
index 7570987ad8..06df688ea1 100644
--- a/var/spack/repos/builtin/packages/boost/package.py
+++ b/var/spack/repos/builtin/packages/boost/package.py
@@ -141,14 +141,8 @@ class Boost(Package):
     patch('xl_1_62_0_le.patch', when='@1.62.0%xl')
 
     def url_for_version(self, version):
-        """
-        Handle Boost's weird URLs,
-        which write the version two different ways.
-        """
-        parts = [str(p) for p in Version(version)]
-        dots = ".".join(parts)
-        underscores = "_".join(parts)
-        return "http://downloads.sourceforge.net/project/boost/boost/%s/boost_%s.tar.bz2" % (dots, underscores)
+        url = "http://downloads.sourceforge.net/project/boost/boost/{0}/boost_{1}.tar.bz2"
+        return url.format(version.dotted, version.underscored)
 
     def determine_toolset(self, spec):
         if spec.satisfies("platform=darwin"):
diff --git a/var/spack/repos/builtin/packages/bowtie2/package.py b/var/spack/repos/builtin/packages/bowtie2/package.py
index 6dbcea8dd0..dc850d817f 100644
--- a/var/spack/repos/builtin/packages/bowtie2/package.py
+++ b/var/spack/repos/builtin/packages/bowtie2/package.py
@@ -29,7 +29,10 @@
 class Bowtie2(Package):
     """Bowtie 2 is an ultrafast and memory-efficient tool for aligning
        sequencing reads to long reference sequences"""
+
     homepage = "bowtie-bio.sourceforge.net/bowtie2/index.shtml"
+    url      = "http://downloads.sourceforge.net/project/bowtie-bio/bowtie2/2.3.1/bowtie2-2.3.1-source.zip"
+
     version('2.3.1', 'b4efa22612e98e0c23de3d2c9f2f2478')
     version('2.2.5', '51fa97a862d248d7ee660efc1147c75f')
 
@@ -38,10 +41,6 @@ class Bowtie2(Package):
     patch('bowtie2-2.2.5.patch', when='@2.2.5', level=0)
     patch('bowtie2-2.3.1.patch', when='@2.3.1', level=0)
 
-    def url_for_version(self, version):
-        url="http://downloads.sourceforge.net/project/bowtie-bio/bowtie2/{0}/bowtie2-{0}-source.zip"
-        return url.format(version)
-
     def install(self, spec, prefix):
         make()
         mkdirp(prefix.bin)
diff --git a/var/spack/repos/builtin/packages/cddlib/package.py b/var/spack/repos/builtin/packages/cddlib/package.py
index 50dc5ad472..002c302599 100644
--- a/var/spack/repos/builtin/packages/cddlib/package.py
+++ b/var/spack/repos/builtin/packages/cddlib/package.py
@@ -31,19 +31,9 @@ class Cddlib(AutotoolsPackage):
     Method of Motzkin et al. for generating all vertices (i.e. extreme points)
     and extreme rays of a general convex polyhedron in R^d given by a system
     of linear inequalities"""
-    homepage = "https://www.inf.ethz.ch/personal/fukudak/cdd_home/"
-    # This is the original download url. It is currently down [2016-08-23],
-    # but should be reinstated or updated once the issue is resolved.
-    # url = "ftp://ftp.ifor.math.ethz.ch/pub/fukuda/cdd/cddlib-094h.tar.gz"
-    url = "http://pkgs.fedoraproject.org/lookaside/pkgs/cddlib/cddlib-094h.tar.gz/1467d270860bbcb26d3ebae424690e7c/cddlib-094h.tar.gz"
 
-    def url_for_version(self, version):
-        # Since the commit id is part of the version, we can't
-        # auto-generate the string, and we need to explicitly list all
-        # known versions here. Currently, there is only one version.
-        if str(version) == '0.94h':
-            return "http://pkgs.fedoraproject.org/lookaside/pkgs/cddlib/cddlib-094h.tar.gz/1467d270860bbcb26d3ebae424690e7c/cddlib-094h.tar.gz"
-        raise InstallError("Unsupported version %s" % str(version))
+    homepage = "https://www.inf.ethz.ch/personal/fukudak/cdd_home/"
+    url      = "ftp://ftp.math.ethz.ch/users/fukudak/cdd/cddlib-094h.tar.gz"
 
     version('0.94h', '1467d270860bbcb26d3ebae424690e7c')
 
@@ -51,3 +41,7 @@ def url_for_version(self, version):
 
     depends_on("gmp")
     depends_on("libtool", type="build")
+
+    def url_for_version(self, version):
+        url = "ftp://ftp.math.ethz.ch/users/fukudak/cdd/cddlib-{0}.tar.gz"
+        return url.format(version.joined)
diff --git a/var/spack/repos/builtin/packages/cdo/package.py b/var/spack/repos/builtin/packages/cdo/package.py
index 775dc31cf3..90039d4479 100644
--- a/var/spack/repos/builtin/packages/cdo/package.py
+++ b/var/spack/repos/builtin/packages/cdo/package.py
@@ -30,9 +30,13 @@ class Cdo(Package):
     Climate and NWP model Data. """
 
     homepage = "https://code.zmaw.de/projects/cdo"
+    url      = "https://code.zmaw.de/attachments/download/12760/cdo-1.7.2.tar.gz"
+    list_url = "https://code.zmaw.de/projects/cdo/files"
 
-    version('1.7.2', 'f08e4ce8739a4f2b63fc81a24db3ee31', url='https://code.zmaw.de/attachments/download/12760/cdo-1.7.2.tar.gz')
-    version('1.6.9', 'bf0997bf20e812f35e10188a930e24e2', url='https://code.zmaw.de/attachments/download/10198/cdo-1.6.9.tar.gz')
+    version('1.7.2', 'f08e4ce8739a4f2b63fc81a24db3ee31',
+            url='https://code.zmaw.de/attachments/download/12760/cdo-1.7.2.tar.gz')
+    version('1.6.9', 'bf0997bf20e812f35e10188a930e24e2',
+            url='https://code.zmaw.de/attachments/download/10198/cdo-1.6.9.tar.gz')
 
     variant('szip', default=True, description='Enable szip compression for GRIB1')
     variant('hdf5', default=False, description='Enable HDF5 support')
@@ -54,7 +58,7 @@ class Cdo(Package):
     depends_on('proj', when='+proj')
     depends_on('curl', when='+curl')
     depends_on('fftw', when='+fftw')
-    depends_on('magics', when='+magics') 
+    depends_on('magics', when='+magics')
 
     def install(self, spec, prefix):
         config_args = ["--prefix=" + prefix,
diff --git a/var/spack/repos/builtin/packages/cfitsio/package.py b/var/spack/repos/builtin/packages/cfitsio/package.py
index 811b3ca9bc..b382f87f5b 100644
--- a/var/spack/repos/builtin/packages/cfitsio/package.py
+++ b/var/spack/repos/builtin/packages/cfitsio/package.py
@@ -31,6 +31,7 @@ class Cfitsio(AutotoolsPackage):
     """
 
     homepage = 'http://heasarc.gsfc.nasa.gov/fitsio/'
+    url      = 'http://heasarc.gsfc.nasa.gov/FTP/software/fitsio/c/cfitsio3410.tar.gz'
 
     version('3.410', '8a4a66fcdd816aae41768baa0b025552')
     version('3.370', 'abebd2d02ba5b0503c633581e3bfa116')
diff --git a/var/spack/repos/builtin/packages/cppad/package.py b/var/spack/repos/builtin/packages/cppad/package.py
index 1ec31bbeef..e17a070294 100644
--- a/var/spack/repos/builtin/packages/cppad/package.py
+++ b/var/spack/repos/builtin/packages/cppad/package.py
@@ -29,16 +29,13 @@ class Cppad(CMakePackage):
     """A Package for Differentiation of C++ Algorithms."""
 
     homepage = "https://www.coin-or.org/CppAD/"
+    url      = "http://www.coin-or.org/download/source/CppAD/cppad-20170114.gpl.tgz"
 
     version('20170114', '565a534dc813fa1289764222cd8c11ea')
     version('develop', git='https://github.com/coin-or/CppAD.git')
 
     depends_on('cmake', type='build')
 
-    def url_for_version(self, version):
-        """Handle version-based custom URLs."""
-        return "http://www.coin-or.org/download/source/CppAD/cppad-%s.gpl.tgz" % (version)
-
     def cmake_args(self):
         # This package does not obey CMAKE_INSTALL_PREFIX
         args = [
diff --git a/var/spack/repos/builtin/packages/cryptopp/package.py b/var/spack/repos/builtin/packages/cryptopp/package.py
index c92f262a9a..142bd4f253 100644
--- a/var/spack/repos/builtin/packages/cryptopp/package.py
+++ b/var/spack/repos/builtin/packages/cryptopp/package.py
@@ -36,6 +36,7 @@ class Cryptopp(Package):
     """
 
     homepage = "http://www.cryptopp.com"
+    url      = "http://www.cryptopp.com/cryptopp563.zip"
 
     version('5.6.3', '3c5b70e2ec98b7a24988734446242d07')
     version('5.6.2', '7ed022585698df48e65ce9218f6c6a67')
diff --git a/var/spack/repos/builtin/packages/dakota/package.py b/var/spack/repos/builtin/packages/dakota/package.py
index e8f7d0889b..c40229f83b 100644
--- a/var/spack/repos/builtin/packages/dakota/package.py
+++ b/var/spack/repos/builtin/packages/dakota/package.py
@@ -46,7 +46,6 @@ class Dakota(Package):
 
     homepage = 'https://dakota.sandia.gov/'
     url = 'https://dakota.sandia.gov/sites/default/files/distributions/public/dakota-6.3-public.src.tar.gz'
-    _url_str = 'https://dakota.sandia.gov/sites/default/files/distributions/public/dakota-{version}-public.src.tar.gz'
 
     version('6.3', '05a58d209fae604af234c894c3f73f6d')
 
@@ -64,9 +63,6 @@ class Dakota(Package):
     depends_on('boost')
     depends_on('cmake', type='build')
 
-    def url_for_version(self, version):
-        return Dakota._url_str.format(version=version)
-
     def install(self, spec, prefix):
         options = []
         options.extend(std_cmake_args)
diff --git a/var/spack/repos/builtin/packages/exonerate/package.py b/var/spack/repos/builtin/packages/exonerate/package.py
index 7921e64058..2615d859d6 100644
--- a/var/spack/repos/builtin/packages/exonerate/package.py
+++ b/var/spack/repos/builtin/packages/exonerate/package.py
@@ -29,7 +29,7 @@ class Exonerate(Package):
     """Pairwise sequence alignment of DNA and proteins"""
 
     homepage = "http://www.ebi.ac.uk/about/vertebrate-genomics/software/exonerate"
-    url      = "http://ftp.ebi.ac.uk/pub/software/vertebrategenomics/exonerate/exonerate-2.2.0.tar.gz"
+    url      = "http://ftp.ebi.ac.uk/pub/software/vertebrategenomics/exonerate/exonerate-2.4.0.tar.gz"
 
     version('2.4.0', '126fbade003b80b663a1d530c56f1904')
 
diff --git a/var/spack/repos/builtin/packages/ferret/package.py b/var/spack/repos/builtin/packages/ferret/package.py
index 15ddfcee16..4dcff54b8f 100644
--- a/var/spack/repos/builtin/packages/ferret/package.py
+++ b/var/spack/repos/builtin/packages/ferret/package.py
@@ -31,11 +31,10 @@ class Ferret(Package):
     """Ferret is an interactive computer visualization and analysis environment
        designed to meet the needs of oceanographers and meteorologists
        analyzing large and complex gridded data sets."""
-    homepage = "http://ferret.noaa.gov/Ferret/"
-    url      = "ftp://ftp.pmel.noaa.gov/ferret/pub/source/fer_source.tar.gz"
+    homepage = "http://ferret.pmel.noaa.gov/Ferret/home"
+    url      = "ftp://ftp.pmel.noaa.gov/ferret/pub/source/fer_source.v696.tar.gz"
 
-    version('6.96', '51722027c864369f41bab5751dfff8cc',
-            url="ftp://ftp.pmel.noaa.gov/ferret/pub/source/fer_source.tar.gz")
+    version('6.96', '51722027c864369f41bab5751dfff8cc')
 
     depends_on("hdf5~mpi~fortran")
     depends_on("netcdf~mpi")
@@ -43,6 +42,10 @@ class Ferret(Package):
     depends_on("readline")
     depends_on("zlib")
 
+    def url_for_version(self, version):
+        return "ftp://ftp.pmel.noaa.gov/ferret/pub/source/fer_source.v{0}.tar.gz".format(
+            version.joined)
+
     def patch(self):
         hdf5_prefix = self.spec['hdf5'].prefix
         netcdff_prefix = self.spec['netcdf-fortran'].prefix
diff --git a/var/spack/repos/builtin/packages/gdk-pixbuf/package.py b/var/spack/repos/builtin/packages/gdk-pixbuf/package.py
index 1159744721..2f3a0b0bd7 100644
--- a/var/spack/repos/builtin/packages/gdk-pixbuf/package.py
+++ b/var/spack/repos/builtin/packages/gdk-pixbuf/package.py
@@ -32,7 +32,9 @@ class GdkPixbuf(AutotoolsPackage):
        GTK+ 2 but it was split off into a separate package in
        preparation for the change to GTK+ 3."""
     homepage = "https://developer.gnome.org/gdk-pixbuf/"
-    url      = "http://ftp.gnome.org/pub/gnome/sources/gdk-pixbuf/2.31/gdk-pixbuf-2.31.1.tar.xz"
+    url      = "http://ftp.gnome.org/pub/gnome/sources/gdk-pixbuf/2.31/gdk-pixbuf-2.31.2.tar.xz"
+    list_url = "http://ftp.acc.umu.se/pub/gnome/sources/gdk-pixbuf/"
+    list_depth = 2
 
     version('2.31.2', '6be6bbc4f356d4b79ab4226860ab8523')
 
diff --git a/var/spack/repos/builtin/packages/go/package.py b/var/spack/repos/builtin/packages/go/package.py
index 6559e90496..c095140c68 100644
--- a/var/spack/repos/builtin/packages/go/package.py
+++ b/var/spack/repos/builtin/packages/go/package.py
@@ -89,13 +89,6 @@ def patch(self):
             r'# \1\2\3',
         )
 
-    @when('@1.5.0:')
-    def patch(self):
-        pass
-
-    def url_for_version(self, version):
-        return "https://storage.googleapis.com/golang/go{0}.src.tar.gz".format(version)
-
     def install(self, spec, prefix):
         bash = which('bash')
         with working_dir('src'):
diff --git a/var/spack/repos/builtin/packages/gource/package.py b/var/spack/repos/builtin/packages/gource/package.py
index 21994ad42c..7d12697d63 100644
--- a/var/spack/repos/builtin/packages/gource/package.py
+++ b/var/spack/repos/builtin/packages/gource/package.py
@@ -52,10 +52,6 @@ class Gource(AutotoolsPackage):
     parallel = False
     force_autoreconf = True
 
-    def url_for_version(self, version):
-        tmp = 'https://github.com/acaudwell/Gource/releases/download/gource-{0}/gource-{0}.tar.gz'  # NOQA: ignore=E501
-        return tmp.format(version.dotted)
-
     def configure_args(self):
         spec = self.spec
         return [
diff --git a/var/spack/repos/builtin/packages/ibmisc/package.py b/var/spack/repos/builtin/packages/ibmisc/package.py
index f325205507..181ae6d92b 100644
--- a/var/spack/repos/builtin/packages/ibmisc/package.py
+++ b/var/spack/repos/builtin/packages/ibmisc/package.py
@@ -29,9 +29,9 @@ class Ibmisc(CMakePackage):
     """Misc. reusable utilities used by IceBin."""
 
     homepage = "https://github.com/citibeth/ibmisc"
-    url      = "https://github.com/citibeth/ibmisc/tarball/123"
+    url      = "https://github.com/citibeth/ibmisc/archive/v0.1.0.tar.gz"
 
-    version('0.1.0', '12f2a32432a11db48e00217df18e59fa')
+    version('0.1.0', '18c63db3e466c5a6fc2db3f903d06ecb')
 
     variant('everytrace', default=False,
             description='Report errors through Everytrace')
diff --git a/var/spack/repos/builtin/packages/icet/package.py b/var/spack/repos/builtin/packages/icet/package.py
index f8260f1951..ca3251ac40 100644
--- a/var/spack/repos/builtin/packages/icet/package.py
+++ b/var/spack/repos/builtin/packages/icet/package.py
@@ -30,7 +30,7 @@ class Icet(CMakePackage):
        sort-last parallel rendering library."""
 
     homepage = "http://icet.sandia.gov"
-    url = "https://example.com/icet-1.2.3.tar.gz"
+    url      = "https://gitlab.kitware.com/icet/icet/repository/archive.tar.bz2?ref=IceT-2.1.1"
 
     version('develop', branch='master',
             git='https://gitlab.kitware.com/icet/icet.git')
@@ -38,9 +38,5 @@ class Icet(CMakePackage):
 
     depends_on('mpi')
 
-    def url_for_version(self, version):
-        return ("https://gitlab.kitware.com/icet/icet/repository/"
-                "archive.tar.bz2?ref=IceT-{0}".format(version.dotted))
-
     def cmake_args(self):
         return ['-DICET_USE_OPENGL:BOOL=OFF']
diff --git a/var/spack/repos/builtin/packages/image-magick/package.py b/var/spack/repos/builtin/packages/image-magick/package.py
index 9efb0cd368..e32f1967e2 100644
--- a/var/spack/repos/builtin/packages/image-magick/package.py
+++ b/var/spack/repos/builtin/packages/image-magick/package.py
@@ -45,9 +45,6 @@ class ImageMagick(Package):
     depends_on('ghostscript')
     depends_on('ghostscript-fonts')
 
-    def url_for_version(self, version):
-        return "https://github.com/ImageMagick/ImageMagick/archive/{0}.tar.gz".format(version)
-
     def install(self, spec, prefix):
         gs_font_dir = join_path(spec['ghostscript-fonts'].prefix.share, "font")
         configure('--prefix={0}'.format(prefix),
diff --git a/var/spack/repos/builtin/packages/jdk/package.py b/var/spack/repos/builtin/packages/jdk/package.py
index 518a469435..8df01f4b67 100644
--- a/var/spack/repos/builtin/packages/jdk/package.py
+++ b/var/spack/repos/builtin/packages/jdk/package.py
@@ -45,10 +45,10 @@ class Jdk(Package):
         '-H',  # specify required License Agreement cookie
         'Cookie: oraclelicense=accept-securebackup-cookie']
 
-    version('8u66-linux-x64', '88f31f3d642c3287134297b8c10e61bf',
+    version('8u66', '88f31f3d642c3287134297b8c10e61bf',
             url="http://download.oracle.com/otn-pub/java/jdk/8u66-b17/jdk-8u66-linux-x64.tar.gz",
             curl_options=curl_options)
-    version('8u92-linux-x64', '65a1cc17ea362453a6e0eb4f13be76e4',
+    version('8u92', '65a1cc17ea362453a6e0eb4f13be76e4',
             url="http://download.oracle.com/otn-pub/java/jdk/8u92-b14/jdk-8u92-linux-x64.tar.gz",
             curl_options=curl_options)
 
diff --git a/var/spack/repos/builtin/packages/libedit/package.py b/var/spack/repos/builtin/packages/libedit/package.py
index 5dcee61cab..6887d67101 100644
--- a/var/spack/repos/builtin/packages/libedit/package.py
+++ b/var/spack/repos/builtin/packages/libedit/package.py
@@ -30,7 +30,11 @@ class Libedit(AutotoolsPackage):
     homepage = "http://thrysoee.dk/editline/"
     url      = "http://thrysoee.dk/editline/libedit-20150325-3.1.tar.gz"
 
-    version('3.1', '43cdb5df3061d78b5e9d59109871b4f6',
-            url="http://thrysoee.dk/editline/libedit-20150325-3.1.tar.gz")
+    version('3.1-20160903', '0467d27684c453a351fbcefebbcb16a3')
+    version('3.1-20150325', '43cdb5df3061d78b5e9d59109871b4f6')
 
     depends_on('ncurses')
+
+    def url_for_version(self, version):
+        url = "http://thrysoee.dk/editline/libedit-{0}-{1}.tar.gz"
+        return url.format(version[-1], version.up_to(-1))
diff --git a/var/spack/repos/builtin/packages/libgd/package.py b/var/spack/repos/builtin/packages/libgd/package.py
index adce0b7515..c70d8b56fd 100644
--- a/var/spack/repos/builtin/packages/libgd/package.py
+++ b/var/spack/repos/builtin/packages/libgd/package.py
@@ -56,7 +56,3 @@ class Libgd(AutotoolsPackage):
     depends_on('libpng')
     depends_on('libtiff')
     depends_on('fontconfig')
-
-    def url_for_version(self, version):
-        url = "https://github.com/libgd/libgd/releases/download/gd-{0}/libgd-{0}.tar.gz"
-        return url.format(version)
diff --git a/var/spack/repos/builtin/packages/libsodium/package.py b/var/spack/repos/builtin/packages/libsodium/package.py
index a7e3ab10ae..6d21d65345 100644
--- a/var/spack/repos/builtin/packages/libsodium/package.py
+++ b/var/spack/repos/builtin/packages/libsodium/package.py
@@ -30,6 +30,7 @@ class Libsodium(AutotoolsPackage):
     decryption, signatures, password hashing and more."""
     homepage = "https://download.libsodium.org/doc/"
     url      = "https://download.libsodium.org/libsodium/releases/libsodium-1.0.11.tar.gz"
+    list_url = "https://download.libsodium.org/libsodium/releases/old"
 
     version('1.0.11', 'b58928d035064b2a46fb564937b83540')
     version('1.0.10', 'ea89dcbbda0b2b6ff6a1c476231870dd')
diff --git a/var/spack/repos/builtin/packages/libxstream/package.py b/var/spack/repos/builtin/packages/libxstream/package.py
index 3201b58620..0996e6b9e8 100644
--- a/var/spack/repos/builtin/packages/libxstream/package.py
+++ b/var/spack/repos/builtin/packages/libxstream/package.py
@@ -31,9 +31,9 @@ class Libxstream(Package):
     conditions.'''
 
     homepage = 'https://github.com/hfp/libxstream'
-    url      = 'https://github.com/hfp/libxstream.git'
+    url      = 'https://github.com/hfp/libxstream/archive/0.9.0.tar.gz'
 
-    version('0.9.0', git='https://github.com/hfp/libxstream.git')
+    version('0.9.0', 'fd74b7cf5f145ff4925d91be2809571c')
 
     def patch(self):
         kwargs = {'ignore_absent': False, 'backup': True, 'string': True}
diff --git a/var/spack/repos/builtin/packages/meep/package.py b/var/spack/repos/builtin/packages/meep/package.py
index 2c1018e711..00b9c4ea09 100644
--- a/var/spack/repos/builtin/packages/meep/package.py
+++ b/var/spack/repos/builtin/packages/meep/package.py
@@ -30,6 +30,8 @@ class Meep(Package):
     software package developed at MIT to model electromagnetic systems."""
 
     homepage = "http://ab-initio.mit.edu/wiki/index.php/Meep"
+    url      = "http://ab-initio.mit.edu/meep/meep-1.3.tar.gz"
+    list_url = "http://ab-initio.mit.edu/meep/old"
 
     version('1.3',   '18a5b9e18008627a0411087e0bb60db5')
     version('1.2.1', '9be2e743c3a832ae922de9d955d016c5')
diff --git a/var/spack/repos/builtin/packages/metis/package.py b/var/spack/repos/builtin/packages/metis/package.py
index f15d544b7b..c927c22a1b 100644
--- a/var/spack/repos/builtin/packages/metis/package.py
+++ b/var/spack/repos/builtin/packages/metis/package.py
@@ -37,7 +37,8 @@ class Metis(Package):
        partitioning schemes."""
 
     homepage = "http://glaros.dtc.umn.edu/gkhome/metis/metis/overview"
-    base_url = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis"
+    url      = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz"
+    list_url = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/OLD"
 
     version('5.1.0', '5465e67079419a69e0116de24fce58fe')
     version('5.0.2', 'acb521a4e8c2e6dd559a7f9abd0468c5')
@@ -55,12 +56,11 @@ class Metis(Package):
     patch('install_gklib_defs_rename.patch', when='@5:')
 
     def url_for_version(self, version):
-        verdir = 'OLD/' if version < Version('4.0.3') else ''
-        return '%s/%smetis-%s.tar.gz' % (Metis.base_url, verdir, version)
-
-    @when('@:4')
-    def patch(self):
-        pass
+        url = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis"
+        if version < Version('4.0.3'):
+            url += "/OLD"
+        url += "/metis-{0}.tar.gz".format(version)
+        return url
 
     @when('@5:')
     def patch(self):
@@ -84,7 +84,7 @@ def patch(self):
             filter_file('#define MAX_JBUFS 128', '#define MAX_JBUFS 24',
                         join_path(source_path, 'GKlib', 'error.c'))
 
-    @when('@:4')
+    @when('@:4')  # noqa: F811
     def install(self, spec, prefix):
         # Process library spec and options
         if any('+{0}'.format(v) in spec for v in ['gdb', 'int64', 'real64']):
@@ -175,7 +175,7 @@ def install(self, spec, prefix):
             Executable(test_bin('mesh2dual'))(test_graph('metis.mesh'))
             """
 
-    @when('@5:')
+    @when('@5:')  # noqa: F811
     def install(self, spec, prefix):
         source_directory = self.stage.source_path
         build_directory = join_path(source_directory, 'build')
@@ -187,7 +187,7 @@ def install(self, spec, prefix):
         if '+shared' in spec:
             options.append('-DSHARED:BOOL=ON')
         else:
-            # Remove all RPATH options 
+            # Remove all RPATH options
             # (RPATHxxx options somehow trigger cmake to link dynamically)
             rpath_options = []
             for o in options:
diff --git a/var/spack/repos/builtin/packages/mfem/package.py b/var/spack/repos/builtin/packages/mfem/package.py
index a25583e164..b3fe5197a0 100644
--- a/var/spack/repos/builtin/packages/mfem/package.py
+++ b/var/spack/repos/builtin/packages/mfem/package.py
@@ -31,15 +31,32 @@ class Mfem(Package):
     homepage = 'http://www.mfem.org'
     url      = 'https://github.com/mfem/mfem'
 
+    # mfem is downloaded from a URL shortener at request of upstream
+    # author Tzanio Kolev <tzanio@llnl.gov>.  See here:
+    #     https://github.com/mfem/mfem/issues/53
+    #
+    # The following procedure should be used to verify security when a
+    # new verison is added:
+    #
+    # 1. Verify that no checksums on old versions have changed.
+    #
+    # 2. Verify that the shortened URL for the new version is listed at:
+    #    http://mfem.org/download/
+    #
+    # 3. Use http://getlinkinfo.com or similar to verify that the
+    #    underling download link for the latest version comes has the
+    #    prefix: http://mfem.github.io/releases
+    #
+    # If this quick verification procedure fails, additional discussion
+    # will be required to verify the new version.
+
     version('3.2',
             '2938c3deed4ec4f7fd5b5f5cfe656845282e86e2dcd477d292390058b7b94340',
-            url='http://goo.gl/Y9T75B', preferred=True, extension='.tar.gz')
+            url='http://goo.gl/Y9T75B', extension='.tar.gz')
 
     version('3.1',
             '841ea5cf58de6fae4de0f553b0e01ebaab9cd9c67fa821e8a715666ecf18fc57',
             url='http://goo.gl/xrScXn', extension='.tar.gz')
-#    version('3.1', git='https://github.com/mfem/mfem.git',
-#            commit='dbae60fe32e071989b52efaaf59d7d0eb2a3b574')
 
     variant('metis', default=False, description='Activate support for metis')
     variant('hypre', default=False, description='Activate support for hypre')
diff --git a/var/spack/repos/builtin/packages/mitos/package.py b/var/spack/repos/builtin/packages/mitos/package.py
index d577a1b285..4ccddb3592 100644
--- a/var/spack/repos/builtin/packages/mitos/package.py
+++ b/var/spack/repos/builtin/packages/mitos/package.py
@@ -30,13 +30,12 @@ class Mitos(Package):
     performance data to view with MemAxes"""
 
     homepage = "https://github.com/llnl/Mitos"
-    url = "https://github.com/llnl/Mitos"
+    url      = "https://github.com/LLNL/Mitos/archive/v0.9.1.tar.gz"
 
     version('0.9.2',
             git='https://github.com/llnl/Mitos.git',
             commit='8cb143a2e8c00353ff531a781a9ca0992b0aaa3d')
-
-    version('0.9.1', git='https://github.com/llnl/Mitos.git', tag='v0.9.1')
+    version('0.9.1', 'c6cb57f3cae54f5157affd97ef7ef79e')
 
     depends_on('dyninst@8.2.1:')
     depends_on('hwloc')
diff --git a/var/spack/repos/builtin/packages/moab/package.py b/var/spack/repos/builtin/packages/moab/package.py
index b783d7b81b..14925cfd3e 100644
--- a/var/spack/repos/builtin/packages/moab/package.py
+++ b/var/spack/repos/builtin/packages/moab/package.py
@@ -35,7 +35,7 @@ class Moab(Package):
     mesh in chunks rather than through individual entities, while also
     versatile enough to support individual entity access."""
     homepage = "https://bitbucket.org/fathomteam/moab"
-    url      = "http://ftp.mcs.anl.gov/pub/fathom/moab-4.6.3.tar.gz"
+    url      = "http://ftp.mcs.anl.gov/pub/fathom/moab-4.9.1.tar.gz"
 
     version('4.9.1', '19cc2189fa266181ad9109b18d0b2ab8')
     version('4.9.0', '40695d0a159040683cfa05586ad4a7c2')
diff --git a/var/spack/repos/builtin/packages/mxml/package.py b/var/spack/repos/builtin/packages/mxml/package.py
index cd53c67dff..435fd748b3 100644
--- a/var/spack/repos/builtin/packages/mxml/package.py
+++ b/var/spack/repos/builtin/packages/mxml/package.py
@@ -41,9 +41,6 @@ class Mxml(AutotoolsPackage):
     version('2.6', '68977789ae64985dddbd1a1a1652642e')
     version('2.5', 'f706377fba630b39fa02fd63642b17e5')
 
-    def url_for_version(self, version):
-        return "https://github.com/michaelrsweet/mxml/releases/download/release-{0}/mxml-{0}.tar.gz".format(version)
-
     # module swap PrgEnv-intel PrgEnv-$COMP
     # (Can use whatever compiler you want to use)
     # Case statement to change CC and CXX flags
diff --git a/var/spack/repos/builtin/packages/nettle/package.py b/var/spack/repos/builtin/packages/nettle/package.py
index 2b6693a18c..e9df8489c9 100644
--- a/var/spack/repos/builtin/packages/nettle/package.py
+++ b/var/spack/repos/builtin/packages/nettle/package.py
@@ -30,7 +30,7 @@ class Nettle(AutotoolsPackage):
     that is designed to fit easily in many contexts."""
 
     homepage = "https://www.lysator.liu.se/~nisse/nettle/"
-    url      = "http://ftp.gnu.org/gnu/nettle/nettle-2.7.1.tar.gz"
+    url      = "http://ftp.gnu.org/gnu/nettle/nettle-3.2.tar.gz"
 
     version('3.2',   'afb15b4764ebf1b4e6d06c62bd4d29e4')
     version('2.7.1', '003d5147911317931dd453520eb234a5')
diff --git a/var/spack/repos/builtin/packages/nextflow/package.py b/var/spack/repos/builtin/packages/nextflow/package.py
index 563ecd9b40..05f21f70b7 100644
--- a/var/spack/repos/builtin/packages/nextflow/package.py
+++ b/var/spack/repos/builtin/packages/nextflow/package.py
@@ -29,6 +29,7 @@ class Nextflow(Package):
     """Data-driven computational pipelines"""
 
     homepage = "http://www.nextflow.io"
+    url      = "https://github.com/nextflow-io/nextflow/releases/download/v0.24.1/nextflow"
 
     version('0.24.1', '80ec8c4fe8e766e0bdd1371a50410d1d',
             expand=False)
@@ -39,10 +40,6 @@ class Nextflow(Package):
 
     depends_on('jdk')
 
-    def url_for_version(self, version):
-        base_url = 'https://github.com/nextflow-io/nextflow/releases/download/v{0}/nextflow'
-        return base_url.format(version)
-
     def install(self, spec, prefix):
         mkdirp(prefix.bin)
         install("nextflow", join_path(prefix.bin, "nextflow"))
diff --git a/var/spack/repos/builtin/packages/oce/package.py b/var/spack/repos/builtin/packages/oce/package.py
index c3488c137a..950621da40 100644
--- a/var/spack/repos/builtin/packages/oce/package.py
+++ b/var/spack/repos/builtin/packages/oce/package.py
@@ -32,6 +32,7 @@ class Oce(Package):
     Open CASCADE library.
     """
     homepage = "https://github.com/tpaviot/oce"
+    url      = "https://github.com/tpaviot/oce/archive/OCE-0.18.tar.gz"
 
     version('0.18',   '226e45e77c16a4a6e127c71fefcd171410703960ae75c7ecc7eb68895446a993')
     version('0.17.2', 'bf2226be4cd192606af677cf178088e5')
@@ -46,10 +47,6 @@ class Oce(Package):
     depends_on('cmake@2.8:', type='build')
     depends_on('tbb', when='+tbb')
 
-    def url_for_version(self, version):
-        return 'https://github.com/tpaviot/oce/archive/OCE-%s.tar.gz' % (
-            version.dotted)
-
     # There is a bug in OCE which appears with Clang (version?) or GCC 6.0
     # and has to do with compiler optimization, see
     # https://github.com/tpaviot/oce/issues/576
diff --git a/var/spack/repos/builtin/packages/octopus/package.py b/var/spack/repos/builtin/packages/octopus/package.py
index 88350f50bc..8999b081e3 100644
--- a/var/spack/repos/builtin/packages/octopus/package.py
+++ b/var/spack/repos/builtin/packages/octopus/package.py
@@ -30,17 +30,11 @@ class Octopus(Package):
     theory code."""
 
     homepage = "http://www.tddft.org/programs/octopus/"
-    base_url = "http://www.tddft.org/programs/octopus/down.php?file="
+    url      = "http://www.tddft.org/programs/octopus/down.php?file=6.0/octopus-6.0.tar.gz"
 
     version('6.0', '5d1168c2a8d7fd9cb9492eaebaa7182e')
     version('5.0.1', '2b6392ab67b843f9d4ca7413fc07e822')
 
-    # Sample url is:
-    # "http://www.tddft.org/programs/octopus/down.php?file=5.0.1/octopus-5.0.1.tar.gz"
-    def url_for_version(self, version):
-        return '{0}/{1}/octopus-{1}.tar.gz'.format(Octopus.base_url,
-                                                   version.dotted)
-
     variant('scalapack', default=False,
             description='Compile with Scalapack')
     variant('metis', default=True,
diff --git a/var/spack/repos/builtin/packages/openjpeg/package.py b/var/spack/repos/builtin/packages/openjpeg/package.py
index 9790c52e7d..b22de4452a 100644
--- a/var/spack/repos/builtin/packages/openjpeg/package.py
+++ b/var/spack/repos/builtin/packages/openjpeg/package.py
@@ -43,7 +43,3 @@ class Openjpeg(CMakePackage):
     version('2.0',   'cdf266530fee8af87454f15feb619609')
     version('1.5.2', '545f98923430369a6b046ef3632ef95c')
     version('1.5.1', 'd774e4b5a0db5f0f171c4fc0aabfa14e')
-
-    def url_for_version(self, version):
-        fmt = 'https://github.com/uclouvain/openjpeg/archive/version.{0}.tar.gz'
-        return fmt.format(version.dotted)
diff --git a/var/spack/repos/builtin/packages/panda/package.py b/var/spack/repos/builtin/packages/panda/package.py
index e30c2c869d..fb14bd5643 100644
--- a/var/spack/repos/builtin/packages/panda/package.py
+++ b/var/spack/repos/builtin/packages/panda/package.py
@@ -29,9 +29,9 @@
 class Panda(Package):
     """PANDA: Parallel AdjaceNcy Decomposition Algorithm"""
     homepage = "http://comopt.ifi.uni-heidelberg.de/software/PANDA/index.html"
-    url      = "http://comopt.ifi.uni-heidelberg.de/software/PANDA/downloads/current_panda.tar"
+    url      = "http://comopt.ifi.uni-heidelberg.de/software/PANDA/downloads/panda-2016-03-07.tar"
 
-    version('current', 'b06dc312ee56e13eefea9c915b70fcef')
+    version('2016-03-07', 'b06dc312ee56e13eefea9c915b70fcef')
 
     # Note: Panda can also be built without MPI support
 
diff --git a/var/spack/repos/builtin/packages/parmetis/package.py b/var/spack/repos/builtin/packages/parmetis/package.py
index 0e6cd5390a..b07c796dd7 100644
--- a/var/spack/repos/builtin/packages/parmetis/package.py
+++ b/var/spack/repos/builtin/packages/parmetis/package.py
@@ -33,7 +33,8 @@ class Parmetis(Package):
        computing fill-reducing orderings of sparse matrices."""
 
     homepage = 'http://glaros.dtc.umn.edu/gkhome/metis/parmetis/overview'
-    base_url = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/parmetis'
+    url      = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/parmetis/parmetis-4.0.3.tar.gz'
+    list_url = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/parmetis/OLD'
 
     version('4.0.3', 'f69c479586bf6bb7aff6a9bc0c739628')
     version('4.0.2', '0912a953da5bb9b5e5e10542298ffdce')
@@ -54,8 +55,11 @@ class Parmetis(Package):
     patch('pkg-parmetis-82409d68aa1d6cbc70740d0f35024aae17f7d5cb.patch')
 
     def url_for_version(self, version):
-        verdir = 'OLD/' if version < Version('3.2.0') else ''
-        return '%s/%sparmetis-%s.tar.gz' % (Parmetis.base_url, verdir, version)
+        url = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/parmetis'
+        if version < Version('3.2.0'):
+            url += '/OLD'
+        url += '/parmetis-{0}.tar.gz'.format(version)
+        return url
 
     def install(self, spec, prefix):
         source_directory = self.stage.source_path
@@ -72,7 +76,7 @@ def install(self, spec, prefix):
         if '+shared' in spec:
             options.append('-DSHARED:BOOL=ON')
         else:
-            # Remove all RPATH options 
+            # Remove all RPATH options
             # (RPATHxxx options somehow trigger cmake to link dynamically)
             rpath_options = []
             for o in options:
diff --git a/var/spack/repos/builtin/packages/prank/package.py b/var/spack/repos/builtin/packages/prank/package.py
index d627e8a0b6..09b73e795f 100644
--- a/var/spack/repos/builtin/packages/prank/package.py
+++ b/var/spack/repos/builtin/packages/prank/package.py
@@ -29,7 +29,7 @@ class Prank(Package):
     """A powerful multiple sequence alignment browser."""
 
     homepage = "http://wasabiapp.org/software/prank/"
-    url      = "http://wasabiapp.org/download/prank/prank.source.140603.tgz"
+    url      = "http://wasabiapp.org/download/prank/prank.source.150803.tgz"
 
     version('150803', '71ac2659e91c385c96473712c0a23e8a')
 
diff --git a/var/spack/repos/builtin/packages/py-autopep8/package.py b/var/spack/repos/builtin/packages/py-autopep8/package.py
index c892e2979c..6c92def415 100644
--- a/var/spack/repos/builtin/packages/py-autopep8/package.py
+++ b/var/spack/repos/builtin/packages/py-autopep8/package.py
@@ -30,10 +30,10 @@ class PyAutopep8(PythonPackage):
     PEP 8 style guide."""
 
     homepage = "https://github.com/hhatto/autopep8"
-    url      = "https://github.com/hhatto/autopep8/archive/v1.2.4.tar.gz"
+    url      = "https://pypi.io/packages/source/a/autopep8/autopep8-1.2.4.tar.gz"
 
-    version('1.2.4', '0458db85159a9e1b45f3e71ce6c158da')
-    version('1.2.2', 'def3d023fc9dfd1b7113602e965ad8e1')
+    version('1.2.4', 'fcea19c0c5e505b425e2a78afb771f5c')
+    version('1.2.2', '3d97f9c89d14a0975bffd32a2c61c36c')
 
     extends('python', ignore='bin/pep8')
     depends_on('python@2.6:2.7,3.2:')
@@ -41,10 +41,3 @@ class PyAutopep8(PythonPackage):
     depends_on('py-pycodestyle@1.5.7:1.7.0', type=('build', 'run'))
 
     depends_on('py-setuptools', type='build')
-
-    def url_for_version(self, version):
-        url = "https://github.com/hhatto/autopep8/archive/{0}{1}.tar.gz"
-        if version >= Version('1.2.3'):
-            return url.format('v', version)
-        else:
-            return url.format('ver', version)
diff --git a/var/spack/repos/builtin/packages/py-cdo/package.py b/var/spack/repos/builtin/packages/py-cdo/package.py
index 3f1306a183..2bf4a2623c 100644
--- a/var/spack/repos/builtin/packages/py-cdo/package.py
+++ b/var/spack/repos/builtin/packages/py-cdo/package.py
@@ -30,10 +30,9 @@ class PyCdo(PythonPackage):
     Operators from Python."""
 
     homepage = "https://pypi.python.org/pypi/cdo"
-    url      = "https://pypi.python.org/packages/sources/c/cdo/cdo-1.3.2.tar.gz"
+    url      = "https://pypi.io/packages/source/c/cdo/cdo-1.3.2.tar.gz"
 
-    version('1.3.2', '4b3686ec1b9b891f166c1c466c6db745',
-            url="https://pypi.python.org/packages/d6/13/908e7c1451e1f5fb68405f341cdcb3196a16952ebfe1f172cb788f864aa9/cdo-1.3.2.tar.gz")
+    version('1.3.2', '4b3686ec1b9b891f166c1c466c6db745')
 
     depends_on('cdo')
 
diff --git a/var/spack/repos/builtin/packages/py-markdown/package.py b/var/spack/repos/builtin/packages/py-markdown/package.py
index 23c8167021..af10f1c5d3 100644
--- a/var/spack/repos/builtin/packages/py-markdown/package.py
+++ b/var/spack/repos/builtin/packages/py-markdown/package.py
@@ -50,7 +50,3 @@ class PyMarkdown(PythonPackage):
 
     depends_on('py-setuptools', type='build')
     depends_on('python@2.7:2.8,3.2:3.4')
-
-    def url_for_version(self, version):
-        base_url = "https://github.com/waylan/Python-Markdown/archive"
-        return "{0}/{1}-final.tar.gz".format(base_url, version)
diff --git a/var/spack/repos/builtin/packages/py-proj/package.py b/var/spack/repos/builtin/packages/py-proj/package.py
index 949aab88c3..cf230eb49f 100644
--- a/var/spack/repos/builtin/packages/py-proj/package.py
+++ b/var/spack/repos/builtin/packages/py-proj/package.py
@@ -32,9 +32,8 @@ class PyProj(PythonPackage):
 
     # This is not a tagged release of pyproj.
     # The changes in this "version" fix some bugs, especially with Python3 use.
-    version('1.9.5.1.1', 'd035e4bc704d136db79b43ab371b27d2',
-        url='https://www.github.com/jswhit/pyproj/tarball/0be612cc9f972e38b50a90c946a9b353e2ab140f')
-
+    version('1.9.5.1.1', git='https://www.github.com/jswhit/pyproj.git',
+            commit='0be612cc9f972e38b50a90c946a9b353e2ab140f')
     version('1.9.5.1', 'a4b80d7170fc82aee363d7f980279835')
 
     depends_on('py-cython', type='build')
diff --git a/var/spack/repos/builtin/packages/py-pypar/package.py b/var/spack/repos/builtin/packages/py-pypar/package.py
index 6ba999c063..c95698d83d 100644
--- a/var/spack/repos/builtin/packages/py-pypar/package.py
+++ b/var/spack/repos/builtin/packages/py-pypar/package.py
@@ -38,6 +38,3 @@ class PyPypar(PythonPackage):
     depends_on('py-numpy', type=('build', 'run'))
 
     build_directory = 'source'
-
-    def url_for_version(self, version):
-        return "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/pypar/pypar-%s.tgz" % version
diff --git a/var/spack/repos/builtin/packages/py-rtree/package.py b/var/spack/repos/builtin/packages/py-rtree/package.py
index 55f98ad19e..a3604b467d 100644
--- a/var/spack/repos/builtin/packages/py-rtree/package.py
+++ b/var/spack/repos/builtin/packages/py-rtree/package.py
@@ -28,22 +28,9 @@
 class PyRtree(PythonPackage):
     """Python interface to the RTREE.4 Library."""
     homepage = "http://toblerity.org/rtree/"
-    url      = "https://github.com/Toblerity/rtree/tarball/0.8.2"
+    url      = "https://pypi.io/packages/source/R/Rtree/Rtree-0.8.3.tar.gz"
 
-    # Not an official release yet.  But changes in here are required
-    # to work with Spack.  As it does with all packages, Spack
-    # installs libspatialindex in a non-system location.  Without the
-    # changes in this fork, py-rtree requires an environment variables
-    # to be set *at runtime*, in order to find libspatialindex.  That
-    # is not feasible within the Spack worldview.
-    version('0.8.2.2', 'b1fe96a73153db49ea6ce45a063d82cb',
-        url='https://github.com/citibeth/rtree/tarball/95a678cc7350857a1bb631bc41254efcd1fc0a0d')
-
-    version('0.8.2.1', '394696ca849dd9f3a5ef24fb02a41ef4',
-        url='https://github.com/citibeth/rtree/tarball/3a87d86f66a3955676b2507d3bf424ade938a22b')
-
-    # Does not work with Spack
-    # version('0.8.2', '593c7ac6babc397b8ba58f1636c1e0a0')
+    version('0.8.3', 'a27cb05a85eed0a3605c45ebccc432f8')
 
     depends_on('py-setuptools', type='build')
     depends_on('libspatialindex')
diff --git a/var/spack/repos/builtin/packages/r-lava/package.py b/var/spack/repos/builtin/packages/r-lava/package.py
index c38f9003ea..263e859c48 100644
--- a/var/spack/repos/builtin/packages/r-lava/package.py
+++ b/var/spack/repos/builtin/packages/r-lava/package.py
@@ -29,7 +29,7 @@ class RLava(RPackage):
     """Estimation and simulation of latent variable models."""
 
     homepage = "https://cran.r-project.org/package=lava"
-    url      = "https://cran.r-project.org/src/contrib/lava_1.4.6.tar.gz"
+    url      = "https://cran.r-project.org/src/contrib/lava_1.4.7.tar.gz"
     list_url = "https://cran.r-project.org/src/contrib/Archive/lava"
 
     version('1.4.7', '28039248a7039ba9281d172e4dbf9543')
diff --git a/var/spack/repos/builtin/packages/root/package.py b/var/spack/repos/builtin/packages/root/package.py
index a96d7f6bbc..a5939ace8f 100644
--- a/var/spack/repos/builtin/packages/root/package.py
+++ b/var/spack/repos/builtin/packages/root/package.py
@@ -30,7 +30,7 @@
 class Root(Package):
     """ROOT is a data analysis framework."""
     homepage = "https://root.cern.ch"
-    url      = "https://root.cern.ch/download/root_v6.07.02.source.tar.gz"
+    url      = "https://root.cern.ch/download/root_v6.06.06.source.tar.gz"
 
     version('6.06.06', '4308449892210c8d36e36924261fea26')
     version('6.06.04', '55a2f98dd4cea79c9c4e32407c2d6d17')
@@ -83,7 +83,3 @@ def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
         spack_env.set('ROOTSYS', self.prefix)
         spack_env.set('ROOT_VERSION', 'v6')
         spack_env.prepend_path('PYTHONPATH', self.prefix.lib)
-
-    def url_for_version(self, version):
-        """Handle ROOT's unusual version string."""
-        return "https://root.cern.ch/download/root_v%s.source.tar.gz" % version
diff --git a/var/spack/repos/builtin/packages/rose/package.py b/var/spack/repos/builtin/packages/rose/package.py
index 02b09f0126..5f0d12427c 100644
--- a/var/spack/repos/builtin/packages/rose/package.py
+++ b/var/spack/repos/builtin/packages/rose/package.py
@@ -35,10 +35,11 @@ class Rose(Package):
        (Developed at Lawrence Livermore National Lab)"""
 
     homepage = "http://rosecompiler.org/"
-    url      = "https://github.com/rose-compiler/edg4x-rose"
+    url      = "https://github.com/rose-compiler/rose/archive/v0.9.7.tar.gz"
 
+    version('0.9.7', 'e14ce5250078df4b09f4f40559d46c75')
     version('master', branch='master',
-            git='https://github.com/rose-compiler/edg4x-rose.git')
+            git='https://github.com/rose-compiler/rose.git')
 
     patch('add_spack_compiler_recognition.patch')
 
@@ -46,7 +47,7 @@ class Rose(Package):
     depends_on("automake@1.14", type='build')
     depends_on("libtool@2.4", type='build')
     depends_on("boost@1.54.0")
-    depends_on("jdk@8u25-linux-x64")
+    depends_on("jdk@8u25")
 
     def install(self, spec, prefix):
         # Bootstrap with autotools
diff --git a/var/spack/repos/builtin/packages/rust-bindgen/package.py b/var/spack/repos/builtin/packages/rust-bindgen/package.py
index c411bc15d1..00ccbb71cf 100644
--- a/var/spack/repos/builtin/packages/rust-bindgen/package.py
+++ b/var/spack/repos/builtin/packages/rust-bindgen/package.py
@@ -29,9 +29,9 @@
 class RustBindgen(Package):
     """The rust programming language toolchain"""
     homepage = "http://www.rust-lang.org"
-    url = "https://github.com/crabtw/rust-bindgen"
+    url = "https://github.com/servo/rust-bindgen/archive/v0.20.5.tar.gz"
 
-    version('0.16', tag='0.16', git='https://github.com/crabtw/rust-bindgen')
+    version('0.20.5', '3e4d70a5bec540324fdd95bc9e82bebc')
 
     extends("rust")
     depends_on("llvm")
diff --git a/var/spack/repos/builtin/packages/scorep/package.py b/var/spack/repos/builtin/packages/scorep/package.py
index 6b3345d83b..1a5a591c3f 100644
--- a/var/spack/repos/builtin/packages/scorep/package.py
+++ b/var/spack/repos/builtin/packages/scorep/package.py
@@ -32,14 +32,11 @@ class Scorep(Package):
     """
 
     homepage = "http://www.vi-hps.org/projects/score-p"
-    url      = "http://www.vi-hps.org/upload/packages/scorep/scorep-1.2.3.tar.gz"
+    url      = "http://www.vi-hps.org/upload/packages/scorep/scorep-2.0.2.tar.gz"
 
-    version('2.0.2', '8f00e79e1b5b96e511c5ebecd10b2888',
-            url='http://www.vi-hps.org/upload/packages/scorep/scorep-2.0.2.tar.gz')
-    version('1.4.2', '3b9a042b13bdd5836452354e6567f71e',
-            url='http://www.vi-hps.org/upload/packages/scorep/scorep-1.4.2.tar.gz')
-    version('1.3', '9db6f957b7f51fa01377a9537867a55c',
-            url='http://www.vi-hps.org/upload/packages/scorep/scorep-1.3.tar.gz')
+    version('2.0.2', '8f00e79e1b5b96e511c5ebecd10b2888')
+    version('1.4.2', '3b9a042b13bdd5836452354e6567f71e')
+    version('1.3',   '9db6f957b7f51fa01377a9537867a55c')
 
     ##########
     # Dependencies for SCORE-P are quite tight. See the homepage for more
diff --git a/var/spack/repos/builtin/packages/scotch/package.py b/var/spack/repos/builtin/packages/scotch/package.py
index b878349485..8efb629487 100644
--- a/var/spack/repos/builtin/packages/scotch/package.py
+++ b/var/spack/repos/builtin/packages/scotch/package.py
@@ -31,8 +31,7 @@ class Scotch(Package):
        partitioning, graph clustering, and sparse matrix ordering."""
 
     homepage = "http://www.labri.fr/perso/pelegrin/scotch/"
-    url = "http://gforge.inria.fr/frs/download.php/latestfile/298/scotch_6.0.3.tar.gz"  # noqa: E501
-    base_url = "http://gforge.inria.fr/frs/download.php/latestfile/298"
+    url      = "http://gforge.inria.fr/frs/download.php/latestfile/298/scotch_6.0.4.tar.gz"
     list_url = "http://gforge.inria.fr/frs/?group_id=248"
 
     version('6.0.4', 'd58b825eb95e1db77efe8c6ff42d329f')
@@ -71,12 +70,10 @@ class Scotch(Package):
     # from the Scotch hosting site.  These alternative archives include a
     # superset of the behavior in their default counterparts, so we choose to
     # always grab these versions for older Scotch versions for simplicity.
-    def url_for_version(self, version):
-        return super(Scotch, self).url_for_version(version)
-
     @when('@:6.0.0')
     def url_for_version(self, version):
-        return '%s/scotch_%s_esmumps.tar.gz' % (Scotch.base_url, version)
+        url = "http://gforge.inria.fr/frs/download.php/latestfile/298/scotch_{0}_esmumps.tar.gz"
+        return url.format(version)
 
     def patch(self):
         self.configure()
diff --git a/var/spack/repos/builtin/packages/silo/package.py b/var/spack/repos/builtin/packages/silo/package.py
index 6a9326517b..eca5d1a605 100644
--- a/var/spack/repos/builtin/packages/silo/package.py
+++ b/var/spack/repos/builtin/packages/silo/package.py
@@ -30,7 +30,7 @@ class Silo(Package):
        data to binary, disk files."""
 
     homepage = "http://wci.llnl.gov/simulation/computer-codes/silo"
-    base_url = "https://wci.llnl.gov/content/assets/docs/simulation/computer-codes/silo"
+    url      = "https://wci.llnl.gov/content/assets/docs/simulation/computer-codes/silo/silo-4.10.2/silo-4.10.2.tar.gz"
 
     version('4.10.2', '9ceac777a2f2469ac8cef40f4fab49c8')
     version('4.9', 'a83eda4f06761a86726e918fc55e782a')
@@ -67,6 +67,3 @@ def install(self, spec, prefix):
 
         make()
         make('install')
-
-    def url_for_version(self, version):
-        return '%s/silo-%s/silo-%s.tar.gz' % (Silo.base_url, version, version)
diff --git a/var/spack/repos/builtin/packages/star-ccm-plus/package.py b/var/spack/repos/builtin/packages/star-ccm-plus/package.py
index ba1516b62a..4197aec339 100644
--- a/var/spack/repos/builtin/packages/star-ccm-plus/package.py
+++ b/var/spack/repos/builtin/packages/star-ccm-plus/package.py
@@ -31,6 +31,7 @@ class StarCcmPlus(Package):
     """STAR-CCM+ (Computational Continuum Mechanics) CFD solver."""
 
     homepage = "http://mdx.plm.automation.siemens.com/star-ccm-plus"
+    url      = "file://{0}/STAR-CCM+11.06.010_02_linux-x86_64.tar.gz".format(os.getcwd())
 
     version('11.06.010_02', 'd349c6ac8293d8e6e7a53533d695588f')
 
@@ -40,10 +41,6 @@ class StarCcmPlus(Package):
     license_required = True
     license_vars = ['CDLMD_LICENSE_FILE', 'LM_LICENSE_FILE']
 
-    def url_for_version(self, version):
-        return "file://{0}/STAR-CCM+{1}_linux-x86_64.tar.gz".format(
-            os.getcwd(), version)
-
     def install(self, spec, prefix):
         # There is a known issue with the LaunchAnywhere application.
         # Specifically, it cannot handle long prompts or prompts
diff --git a/var/spack/repos/builtin/packages/sublime-text/package.py b/var/spack/repos/builtin/packages/sublime-text/package.py
index 81d8690db8..1cfb117a05 100644
--- a/var/spack/repos/builtin/packages/sublime-text/package.py
+++ b/var/spack/repos/builtin/packages/sublime-text/package.py
@@ -33,8 +33,8 @@ class SublimeText(Package):
     homepage = "http://www.sublimetext.com/"
     url      = "https://download.sublimetext.com/sublime_text_3_build_3126_x64.tar.bz2"
 
-    version('3126',  'acc34252b0ea7dff1f581c5db1564dcb')
-    version('2.0.2', '699cd26d7fe0bada29eb1b2cd7b50e4b')
+    version('3_build_3126', 'acc34252b0ea7dff1f581c5db1564dcb')
+    version('2.0.2',        '699cd26d7fe0bada29eb1b2cd7b50e4b')
 
     # Sublime text comes as a pre-compiled binary.
     # Since we can't link to Spack packages, we'll just have to
diff --git a/var/spack/repos/builtin/packages/tcl/package.py b/var/spack/repos/builtin/packages/tcl/package.py
index 79d4bc7544..8ddfc903b3 100644
--- a/var/spack/repos/builtin/packages/tcl/package.py
+++ b/var/spack/repos/builtin/packages/tcl/package.py
@@ -34,6 +34,7 @@ class Tcl(AutotoolsPackage):
        that is truly cross platform, easily deployed and highly
        extensible."""
     homepage = "http://www.tcl.tk"
+    url      = "http://prdownloads.sourceforge.net/tcl/tcl8.6.5-src.tar.gz"
 
     version('8.6.6', '5193aea8107839a79df8ac709552ecb7')
     version('8.6.5', '0e6426a4ca9401825fbc6ecf3d89a326')
@@ -45,10 +46,6 @@ class Tcl(AutotoolsPackage):
 
     configure_directory = 'unix'
 
-    def url_for_version(self, version):
-        base_url = 'http://prdownloads.sourceforge.net/tcl'
-        return '{0}/tcl{1}-src.tar.gz'.format(base_url, version)
-
     def setup_environment(self, spack_env, run_env):
         # When using Tkinter from within spack provided python+tk, python
         # will not be able to find Tcl/Tk unless TCL_LIBRARY is set.
diff --git a/var/spack/repos/builtin/packages/tetgen/package.py b/var/spack/repos/builtin/packages/tetgen/package.py
index 6e5ed79c36..2ccc9504e2 100644
--- a/var/spack/repos/builtin/packages/tetgen/package.py
+++ b/var/spack/repos/builtin/packages/tetgen/package.py
@@ -34,7 +34,7 @@ class Tetgen(Package):
        boundary conforming Delaunay meshes, and Voronoi paritions.
     """
 
-    homepage = "http://www.tetgen.org"
+    homepage = "http://wias-berlin.de/software/tetgen/"
 
     version('1.5.0', '3b9fd9cdec121e52527b0308f7aad5c1', url='http://www.tetgen.org/1.5/src/tetgen1.5.0.tar.gz')
     version('1.4.3', 'd6a4bcdde2ac804f7ec66c29dcb63c18', url='http://www.tetgen.org/files/tetgen1.4.3.tar.gz')
diff --git a/var/spack/repos/builtin/packages/tinyxml/package.py b/var/spack/repos/builtin/packages/tinyxml/package.py
index 1789d9022e..9cb4b715df 100644
--- a/var/spack/repos/builtin/packages/tinyxml/package.py
+++ b/var/spack/repos/builtin/packages/tinyxml/package.py
@@ -34,6 +34,10 @@ class Tinyxml(CMakePackage):
 
     version('2.6.2', 'cba3f50dd657cb1434674a03b21394df9913d764')
 
+    def url_for_version(self, version):
+        url = "https://sourceforge.net/projects/tinyxml/files/tinyxml/{0}/tinyxml_{1}.tar.gz"
+        return url.format(version.dotted, version.underscored)
+
     def patch(self):
         copyfile(join_path(os.path.dirname(__file__),
                            "CMakeLists.txt"), "CMakeLists.txt")
diff --git a/var/spack/repos/builtin/packages/tk/package.py b/var/spack/repos/builtin/packages/tk/package.py
index 4d9651315a..fdcb29a785 100644
--- a/var/spack/repos/builtin/packages/tk/package.py
+++ b/var/spack/repos/builtin/packages/tk/package.py
@@ -33,6 +33,7 @@ class Tk(AutotoolsPackage):
        applications that run unchanged across Windows, Mac OS X, Linux
        and more."""
     homepage = "http://www.tcl.tk"
+    url      = "http://prdownloads.sourceforge.net/tcl/tk8.6.5-src.tar.gz"
 
     version('8.6.6', 'dd7dbb3a6523c42d05f6ab6e86096e99')
     version('8.6.5', '11dbbd425c3e0201f20d6a51482ce6c4')
@@ -43,10 +44,6 @@ class Tk(AutotoolsPackage):
 
     configure_directory = 'unix'
 
-    def url_for_version(self, version):
-        base_url = "http://prdownloads.sourceforge.net/tcl"
-        return "{0}/tk{1}-src.tar.gz".format(base_url, version)
-
     def setup_environment(self, spack_env, run_env):
         # When using Tkinter from within spack provided python+tk, python
         # will not be able to find Tcl/Tk unless TK_LIBRARY is set.
diff --git a/var/spack/repos/builtin/packages/trilinos/package.py b/var/spack/repos/builtin/packages/trilinos/package.py
index 3de72ea6c8..0e0d86fa3c 100644
--- a/var/spack/repos/builtin/packages/trilinos/package.py
+++ b/var/spack/repos/builtin/packages/trilinos/package.py
@@ -44,7 +44,7 @@ class Trilinos(CMakePackage):
     A unique design feature of Trilinos is its focus on packages.
     """
     homepage = "https://trilinos.org/"
-    base_url = "https://github.com/trilinos/Trilinos/archive"
+    url      = "https://github.com/trilinos/Trilinos/archive/trilinos-release-12-10-1.tar.gz"
 
     version('develop',
             git='https://github.com/trilinos/Trilinos.git', tag='develop')
@@ -63,10 +63,6 @@ class Trilinos(CMakePackage):
     version('11.14.2', 'e7c3cdbbfe3279a8a68838b873ad6d51')
     version('11.14.1', 'b7760b142eef66c79ed13de7c9560f81')
 
-    def url_for_version(self, version):
-        return '%s/trilinos-release-%s.tar.gz' % \
-            (Trilinos.base_url, version.dashed)
-
     variant('xsdkflags',        default=False,
             description='Compile using the default xSDK configuration')
     variant('metis',        default=True,
@@ -125,6 +121,10 @@ def url_for_version(self, version):
 
     patch('umfpack_from_suitesparse.patch', when='@:12.8.1')
 
+    def url_for_version(self, version):
+        url = "https://github.com/trilinos/Trilinos/archive/trilinos-release-{0}.tar.gz"
+        return url.format(version.dashed)
+
     # check that the combination of variants makes sense
     def variants_check(self):
         if '+superlu-dist' in self.spec and self.spec.satisfies('@:11.4.3'):
diff --git a/var/spack/repos/builtin/packages/unison/package.py b/var/spack/repos/builtin/packages/unison/package.py
index 181e1e6410..aa890ea869 100644
--- a/var/spack/repos/builtin/packages/unison/package.py
+++ b/var/spack/repos/builtin/packages/unison/package.py
@@ -34,7 +34,7 @@ class Unison(Package):
        other."""
 
     homepage = "https://www.cis.upenn.edu/~bcpierce/unison/"
-    url      = "https://www.seas.upenn.edu/~bcpierce/unison//download/releases/stable/unison-2.48.3.tar.gz"
+    url      = "https://www.seas.upenn.edu/~bcpierce/unison//download/releases/stable/unison-2.48.4.tar.gz"
 
     version('2.48.4', '5334b78c7e68169df7de95f4c6c4b60f')
 
diff --git a/var/spack/repos/builtin/packages/voropp/package.py b/var/spack/repos/builtin/packages/voropp/package.py
index 0e39769927..0fc84ef252 100644
--- a/var/spack/repos/builtin/packages/voropp/package.py
+++ b/var/spack/repos/builtin/packages/voropp/package.py
@@ -31,19 +31,10 @@ class Voropp(MakefilePackage):
     scientific fields."""
 
     homepage = "http://math.lbl.gov/voro++/about.html"
-
-    # This url is wrong but it passes the test the ++ make the url parser fail,
-    # the correct url is constructed by url_for_version that has to be used in
-    # any case due to the difference between the package name and the url
-    url      = "http://math.lbl.gov/voropp/download/dir/voropp-0.4.6.tar.gz"
+    url      = "http://math.lbl.gov/voro++/download/dir/voro++-0.4.6.tar.gz"
 
     version('0.4.6', '2338b824c3b7b25590e18e8df5d68af9')
 
-    def url_for_version(self, version):
-        url = "http://math.lbl.gov/voro++/download/dir/voro++-{0}.tar.gz".format(  # noqa: E501
-            str(version))
-        return url
-
     def edit(self, spec, prefix):
         filter_file(r'CC=g\+\+',
                     'CC={0}'.format(self.compiler.cxx),
diff --git a/var/spack/repos/builtin/packages/vtk/package.py b/var/spack/repos/builtin/packages/vtk/package.py
index c577949c3a..dafeae6dbb 100644
--- a/var/spack/repos/builtin/packages/vtk/package.py
+++ b/var/spack/repos/builtin/packages/vtk/package.py
@@ -33,6 +33,7 @@ class Vtk(CMakePackage):
 
     homepage = "http://www.vtk.org"
     url      = "http://www.vtk.org/files/release/7.1/VTK-7.1.0.tar.gz"
+    list_url = "http://www.vtk.org/download/"
 
     version('7.1.0', 'a7e814c1db503d896af72458c2d0228f')
     version('7.0.0', '5fe35312db5fb2341139b8e4955c367d')
diff --git a/var/spack/repos/builtin/packages/xsdktrilinos/package.py b/var/spack/repos/builtin/packages/xsdktrilinos/package.py
index ea49054435..7e88b2f9eb 100644
--- a/var/spack/repos/builtin/packages/xsdktrilinos/package.py
+++ b/var/spack/repos/builtin/packages/xsdktrilinos/package.py
@@ -32,16 +32,12 @@ class Xsdktrilinos(CMakePackage):
     Trilinos.
     """
     homepage = "https://trilinos.org/"
-    base_url = "https://github.com/trilinos/xSDKTrilinos/archive"
+    url      = "https://github.com/trilinos/xSDKTrilinos/archive/trilinos-release-12-8-1.tar.gz"
 
     version('develop', git='https://github.com/trilinos/xSDKTrilinos.git', tag='master')
     version('12.8.1', '9cc338ded17d1e10ea6c0dc18b22dcd4')
     version('12.6.4', '44c4c54ccbac73bb8939f68797b9454a')
 
-    def url_for_version(self, version):
-        return '%s/trilinos-release-%s.tar.gz' % \
-            (Xsdktrilinos.base_url, version.dashed)
-
     variant('hypre',        default=True,
             description='Compile with Hypre preconditioner')
     variant('petsc',        default=True,
@@ -59,6 +55,10 @@ def url_for_version(self, version):
     depends_on('trilinos@12.8.1', when='@12.8.1')
     depends_on('trilinos@develop', when='@develop')
 
+    def url_for_version(self, version):
+        url = "https://github.com/trilinos/xSDKTrilinos/archive/trilinos-release-{0}.tar.gz"
+        return url.format(version.dashed)
+
     def cmake_args(self):
         spec = self.spec
 
diff --git a/var/spack/repos/builtin/packages/yorick/package.py b/var/spack/repos/builtin/packages/yorick/package.py
index 52a4d8787d..9cbd417e4e 100644
--- a/var/spack/repos/builtin/packages/yorick/package.py
+++ b/var/spack/repos/builtin/packages/yorick/package.py
@@ -31,7 +31,7 @@
 class Yorick(Package):
     """Yorick is an interpreted programming language for scientific simulations
        or calculations, postprocessing or steering large simulation codes,
-       interactive scientific graphics, and reading, writing, or translating 
+       interactive scientific graphics, and reading, writing, or translating
        files of numbers. Yorick includes an interactive graphics package, and a
        binary file package capable of translating to and from the raw numeric
        formats of all modern computers. Yorick is written in ANSI C and runs on
@@ -39,9 +39,9 @@ class Yorick(Package):
     """
 
     homepage = "http://dhmunro.github.io/yorick-doc/"
-    url =  "https://github.com/dhmunro/yorick/archive/y_2_2_04.tar.gz"
+    url      = "https://github.com/dhmunro/yorick/archive/y_2_2_04.tar.gz"
 
-    version('2.2.04', md5='1b5b0da6ad81b2d9dba64d991ec17939')
+    version('2.2.04', '1b5b0da6ad81b2d9dba64d991ec17939')
     version('master', branch='master',
             git='https://github.com/dhmunro/yorick.git')
     version('f90-plugin', branch='f90-plugin',
@@ -51,6 +51,10 @@ class Yorick(Package):
 
     depends_on('libx11', when='+X')
 
+    def url_for_version(self, version):
+        url = "https://github.com/dhmunro/yorick/archive/y_{0}.tar.gz"
+        return url.format(version.underscored)
+
     def install(self, spec, prefix):
         os.environ['FORTRAN_LINKAGE'] = '-Df_linkage'
 
diff --git a/var/spack/repos/builtin/packages/zoltan/package.py b/var/spack/repos/builtin/packages/zoltan/package.py
index 21c90a05e4..b6720b7b1e 100644
--- a/var/spack/repos/builtin/packages/zoltan/package.py
+++ b/var/spack/repos/builtin/packages/zoltan/package.py
@@ -41,7 +41,7 @@ class Zoltan(Package):
     """
 
     homepage = "http://www.cs.sandia.gov/zoltan"
-    base_url = "http://www.cs.sandia.gov/~kddevin/Zoltan_Distributions"
+    url      = "http://www.cs.sandia.gov/~kddevin/Zoltan_Distributions/zoltan_distrib_v3.83.tar.gz"
 
     version('3.83', '1ff1bc93f91e12f2c533ddb01f2c095f')
     version('3.8', '9d8fba8a990896881b85351d4327c4a9')
@@ -56,9 +56,6 @@ class Zoltan(Package):
 
     depends_on('mpi', when='+mpi')
 
-    def url_for_version(self, version):
-        return '%s/zoltan_distrib_v%s.tar.gz' % (Zoltan.base_url, version)
-
     def install(self, spec, prefix):
         # FIXME: The older Zoltan versions fail to compile the F90 MPI wrappers
         # because of some complicated generic type problem.
-- 
GitLab