From e9f42c1a94f58e5fa916705f67716c26818a7eae Mon Sep 17 00:00:00 2001
From: "Adam J. Stewart" <ajstewart426@gmail.com>
Date: Tue, 5 Jul 2016 10:21:15 -0500
Subject: Allow spack create to automatically detect octave build system

---
 lib/spack/spack/cmd/checksum.py |   2 +-
 lib/spack/spack/cmd/create.py   | 145 +++++++++++++++++++++-------------------
 2 files changed, 78 insertions(+), 69 deletions(-)

diff --git a/lib/spack/spack/cmd/checksum.py b/lib/spack/spack/cmd/checksum.py
index 95bd4771ed..9cdb0bd012 100644
--- a/lib/spack/spack/cmd/checksum.py
+++ b/lib/spack/spack/cmd/checksum.py
@@ -59,7 +59,7 @@ def get_checksums(versions, urls, **kwargs):
             with Stage(url, keep=keep_stage) as stage:
                 stage.fetch()
                 if i == 0 and first_stage_function:
-                    first_stage_function(stage)
+                    first_stage_function(stage, url)
 
                 hashes.append((version,
                                spack.util.crypto.checksum(hashlib.md5, stage.archive_file)))
diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py
index c9fa687b74..009b2f308b 100644
--- a/lib/spack/spack/cmd/create.py
+++ b/lib/spack/spack/cmd/create.py
@@ -103,6 +103,64 @@ ${versions}
 ${install}
 """)
 
+# Build dependencies and extensions
+dependencies_dict = {
+    'autotools': "# depends_on('foo')",
+    'cmake':     "depends_on('cmake')",
+    'scons':     "depends_on('scons')",
+    'python':    "extends('python')",
+    'R':         "extends('R')",
+    'octave':    "extends('octave')",
+    'unknown':   "# depends_on('foo')"
+}
+
+# Default installation instructions
+install_dict = {
+    'autotools': """\
+        # FIXME: Modify the configure line to suit your build system here.
+        configure('--prefix={0}'.format(prefix))
+
+        # FIXME: Add logic to build and install here.
+        make()
+        make('install')""",
+
+   'cmake': """\
+        with working_dir('spack-build', create=True):
+            # FIXME: Modify the cmake line to suit your build system here.
+            cmake('..', *std_cmake_args)
+
+            # FIXME: Add logic to build and install here.
+            make()
+            make('install')""",
+
+    'scons': """\
+        # FIXME: Add logic to build and install here.
+        scons('prefix={0}'.format(prefix))
+        scons('install')""",
+
+    'python': """\
+        # FIXME: Add logic to build and install here.
+        python('setup.py', 'install', '--prefix={0}'.format(prefix))""",
+
+    'R': """\
+        # FIXME: Add logic to build and install here.
+        R('CMD', 'INSTALL', '--library={0}'.format(self.module.r_lib_dir),
+          self.stage.source_path)""",
+
+    'octave': """\
+        # FIXME: Add logic to build and install here.
+        octave('--quiet', '--norc',
+               '--built-in-docstrings-file=/dev/null',
+               '--texi-macros-file=/dev/null',
+               '--eval', 'pkg prefix {0}; pkg install {1}'.format(
+                   prefix, self.stage.archive_file))""",
+
+    'unknown': """\
+        # FIXME: Unknown build system
+        make()
+        make('install')"""
+}
+
 
 def make_version_calls(ver_hash_tuples):
     """Adds a version() call to the package for each version found."""
@@ -133,60 +191,17 @@ def setup_parser(subparser):
     setup_parser.subparser = subparser
 
 
-class ConfigureGuesser(object):
-    def __call__(self, stage):
-        """Try to guess the type of build system used by the project.
-        Set any necessary build dependencies or extensions.
-        Set the appropriate default installation instructions."""
-
-        # Build dependencies and extensions
-        dependenciesDict = {
-            'autotools': "# depends_on('foo')",
-            'cmake':     "depends_on('cmake', type='build')",
-            'scons':     "depends_on('scons', type='build')",
-            'python':    "extends('python', type=nolink)",
-            'R':         "extends('R')",
-            'unknown':   "# depends_on('foo')"
-        }
-
-        # Default installation instructions
-        installDict = {
-            'autotools': """\
-        # FIXME: Modify the configure line to suit your build system here.
-        configure('--prefix={0}'.format(prefix))
-
-        # FIXME: Add logic to build and install here.
-        make()
-        make('install')""",
-
-            'cmake':     """\
-        with working_dir('spack-build', create=True):
-            # FIXME: Modify the cmake line to suit your build system here.
-            cmake('..', *std_cmake_args)
+class BuildSystemGuesser(object):
+    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."""
 
-            # FIXME: Add logic to build and install here.
-            make()
-            make('install')""",
-
-            'scons':     """\
-        # FIXME: Add logic to build and install here.
-        scons('prefix={0}'.format(prefix))
-        scons('install')""",
-
-            'python':    """\
-        # FIXME: Add logic to build and install here.
-        python('setup.py', 'install', '--prefix={0}'.format(prefix))""",
-
-            'R':         """\
-        # FIXME: Add logic to build and install here.
-        R('CMD', 'INSTALL', '--library={0}'.format(self.module.r_lib_dir),
-          self.stage.source_path)""",
-
-            'unknown':   """\
-        # FIXME: Unknown build system
-        make()
-        make('install')"""
-        }
+        # Most octave extensions are hosted on Octave-Forge:
+        #     http://octave.sourceforge.net/index.html
+        # They all have the same base URL.
+        if 'downloads.sourceforge.net/octave/' in url:
+            self.build_system = 'octave'
+            return
 
         # A list of clues that give us an idea of the build system a package
         # uses. If the regular expression matches a file contained in the
@@ -224,12 +239,6 @@ class ConfigureGuesser(object):
 
         self.build_system = build_system
 
-        # Set any necessary build dependencies or extensions.
-        self.dependencies = dependenciesDict[build_system]
-
-        # Set the appropriate default installation instructions
-        self.install = installDict[build_system]
-
 
 def guess_name_and_version(url, args):
     # Try to deduce name and version of the new package from the URL
@@ -334,8 +343,8 @@ def create(parser, args):
     # Fetch tarballs (prompting user if necessary)
     versions, urls = fetch_tarballs(url, name, version)
 
-    # Try to guess what configure system is used.
-    guesser = ConfigureGuesser()
+    # Try to guess what build system is used.
+    guesser = BuildSystemGuesser()
     ver_hash_tuples = spack.cmd.checksum.get_checksums(
         versions, urls,
         first_stage_function=guesser,
@@ -344,13 +353,13 @@ def create(parser, args):
     if not ver_hash_tuples:
         tty.die("Could not fetch any tarballs for %s" % name)
 
-    # Prepend 'py-' to python package names, by convention.
+    # Add prefix to package name if it is an extension.
     if guesser.build_system == 'python':
-        name = 'py-%s' % name
-
-    # Prepend 'r-' to R package names, by convention.
+        name = 'py-{0}'.format(name)
     if guesser.build_system == 'R':
-        name = 'r-%s' % name
+        name = 'r-{0}'.format(name)
+    if guesser.build_system == 'octave':
+        name = 'octave-{0}'.format(name)
 
     # Create a directory for the new package.
     pkg_path = repo.filename_for_package_name(name)
@@ -367,8 +376,8 @@ def create(parser, args):
                 class_name=mod_to_class(name),
                 url=url,
                 versions=make_version_calls(ver_hash_tuples),
-                dependencies=guesser.dependencies,
-                install=guesser.install))
+                dependencies=dependencies_dict[guesser.build_system],
+                install=install_dict[guesser.build_system]))
 
     # If everything checks out, go ahead and edit.
     spack.editor(pkg_path)
-- 
cgit v1.2.3-70-g09d2