summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/llnl/util/tty/log.py93
-rw-r--r--lib/spack/spack/cmd/create.py54
-rw-r--r--lib/spack/spack/test/__init__.py3
-rw-r--r--lib/spack/spack/test/configure_guess.py90
-rw-r--r--var/spack/packages/py-lockfile/package.py23
-rw-r--r--var/spack/packages/py-python-daemon/package.py26
6 files changed, 255 insertions, 34 deletions
diff --git a/lib/spack/llnl/util/tty/log.py b/lib/spack/llnl/util/tty/log.py
index 6ccd0e66d9..5a52d45bc7 100644
--- a/lib/spack/llnl/util/tty/log.py
+++ b/lib/spack/llnl/util/tty/log.py
@@ -29,6 +29,7 @@ import os
import re
import select
import inspect
+
import llnl.util.tty as tty
import llnl.util.tty.color as color
@@ -45,6 +46,59 @@ class _SkipWithBlock():
pass
+class keyboard_input(object):
+ """Disable canonical input and echo on a stream within a with block.
+
+ Use this with sys.stdin for keyboard input, e.g.:
+
+ with keyboard_input(sys.stdin):
+ r, w, x = select.select([sys.stdin], [], [])
+ # ... do something with keypresses ...
+
+ When the with block completes, this will restore settings before
+ canonical and echo were disabled.
+ """
+ def __init__(self, stream):
+ self.stream = stream
+
+
+ def __enter__(self):
+ self.old_cfg = None
+
+ # Ignore all this if the input stream is not a tty.
+ if not self.stream.isatty():
+ return
+
+ try:
+ # import and mark whether it worked.
+ import termios
+
+ # save old termios settings
+ fd = self.stream.fileno()
+ self.old_cfg = termios.tcgetattr(fd)
+
+ # create new settings with canonical input and echo
+ # disabled, so keypresses are immediate & don't echo.
+ self.new_cfg = termios.tcgetattr(fd)
+ self.new_cfg[3] &= ~termios.ICANON
+ self.new_cfg[3] &= ~termios.ECHO
+
+ # Apply new settings for terminal
+ termios.tcsetattr(fd, termios.TCSADRAIN, self.new_cfg)
+
+ except Exception, e:
+ pass # Some OS's do not support termios, so ignore.
+
+
+ def __exit__(self, exc_type, exception, traceback):
+ # If termios was avaialble, restore old settings after the
+ # with block
+ if self.old_cfg:
+ import termios
+ termios.tcsetattr(
+ self.stream.fileno(), termios.TCSADRAIN, self.old_cfg)
+
+
class log_output(object):
"""Redirects output and error of enclosed block to a file.
@@ -94,21 +148,30 @@ class log_output(object):
read_file = os.fdopen(read, 'r', 0)
with self.stream as log_file:
- while True:
- rlist, w, x = select.select([read_file], [], [])
- if not rlist:
- break
-
- line = read_file.readline()
- if not line:
- break
-
- # Echo to stdout if requested.
- if self.echo:
- sys.stdout.write(line)
-
- # Stripped output to log file.
- log_file.write(_strip(line))
+ with keyboard_input(sys.stdin):
+ while True:
+ rlist, w, x = select.select([read_file, sys.stdin], [], [])
+ if not rlist:
+ break
+
+ # Allow user to toggle echo with 'v' key.
+ # Currently ignores other chars.
+ if sys.stdin in rlist:
+ if sys.stdin.read(1) == 'v':
+ self.echo = not self.echo
+
+ # handle output from the with block process.
+ if read_file in rlist:
+ line = read_file.readline()
+ if not line:
+ break
+
+ # Echo to stdout if requested.
+ if self.echo:
+ sys.stdout.write(line)
+
+ # Stripped output to log file.
+ log_file.write(_strip(line))
read_file.flush()
read_file.close()
diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py
index c734f58b99..46e6bcec14 100644
--- a/lib/spack/spack/cmd/create.py
+++ b/lib/spack/spack/cmd/create.py
@@ -103,21 +103,35 @@ class ConfigureGuesser(object):
"""Try to guess the type of build system used by the project, and return
an appropriate configure line.
"""
+ autotools = "configure('--prefix=%s' % prefix)"
+ cmake = "cmake('.', *std_cmake_args)"
+ python = "python('setup.py', 'install', '--prefix=%s' % prefix)"
+
+ config_lines = ((r'/configure$', 'autotools', autotools),
+ (r'/CMakeLists.txt$', 'cmake', cmake),
+ (r'/setup.py$', 'python', python))
+
+ # Peek inside the tarball.
tar = which('tar')
output = tar(
"--exclude=*/*/*", "-tf", stage.archive_file, return_output=True)
-
- autotools = 'configure("--prefix=%s" % prefix)'
- cmake = 'cmake(".", *std_cmake_args)'
- lines = output.split('\n')
-
- if any(re.search(r'/configure$', l) for l in lines):
- self.configure = autotools
- elif any(re.search(r'/CMakeLists.txt$', l) for l in lines):
- self.configure = cmake
+ lines = output.split("\n")
+
+ # Set the configure line to the one that matched.
+ for pattern, bs, cl in config_lines:
+ if any(re.search(pattern, l) for l in lines):
+ config_line = cl
+ build_system = bs
+ break
else:
- # Both, with cmake commented out
- self.configure = '%s\n # %s' % (autotools, cmake)
+ # None matched -- just put both, with cmake commented out
+ config_line = "# FIXME: Spack couldn't guess one, so here are some options:\n"
+ config_line += " # " + autotools + "\n"
+ config_line += " # " + cmake
+ build_system = 'unknown'
+
+ self.configure = config_line
+ self.build_system = build_system
def make_version_calls(ver_hash_tuples):
@@ -152,13 +166,6 @@ def create(parser, args):
tty.msg("This looks like a URL for %s version %s." % (name, version))
tty.msg("Creating template for package %s" % name)
- # Create a directory for the new package.
- pkg_path = spack.db.filename_for_package_name(name)
- if os.path.exists(pkg_path) and not args.force:
- tty.die("%s already exists." % pkg_path)
- else:
- mkdirp(os.path.dirname(pkg_path))
-
versions = spack.package.find_versions_of_archive(url)
rkeys = sorted(versions.keys(), reverse=True)
versions = OrderedDict(zip(rkeys, (versions[v] for v in rkeys)))
@@ -190,6 +197,17 @@ 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.
+ if guesser.build_system == 'python':
+ name = 'py-%s' % name
+
+ # Create a directory for the new package.
+ pkg_path = spack.db.filename_for_package_name(name)
+ if os.path.exists(pkg_path) and not args.force:
+ tty.die("%s already exists." % pkg_path)
+ else:
+ mkdirp(os.path.dirname(pkg_path))
+
# Write out a template for the file
with open(pkg_path, "w") as pkg_file:
pkg_file.write(
diff --git a/lib/spack/spack/test/__init__.py b/lib/spack/spack/test/__init__.py
index 8d4b0c6cde..6b3715be6f 100644
--- a/lib/spack/spack/test/__init__.py
+++ b/lib/spack/spack/test/__init__.py
@@ -55,7 +55,8 @@ test_names = ['versions',
'link_tree',
'spec_yaml',
'optional_deps',
- 'make_executable']
+ 'make_executable',
+ 'configure_guess']
def list_tests():
diff --git a/lib/spack/spack/test/configure_guess.py b/lib/spack/spack/test/configure_guess.py
new file mode 100644
index 0000000000..766dd51d52
--- /dev/null
+++ b/lib/spack/spack/test/configure_guess.py
@@ -0,0 +1,90 @@
+##############################################################################
+# Copyright (c) 2013-2015, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/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 General Public License (as published by
+# the Free Software Foundation) version 2.1 dated 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 General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+import os
+import unittest
+import shutil
+import tempfile
+
+from llnl.util.filesystem import *
+
+from spack.cmd.create import ConfigureGuesser
+from spack.stage import Stage
+
+from spack.fetch_strategy import URLFetchStrategy
+from spack.directory_layout import YamlDirectoryLayout
+from spack.util.executable import which
+from spack.test.mock_packages_test import *
+from spack.test.mock_repo import MockArchive
+
+
+class InstallTest(unittest.TestCase):
+ """Tests the configure guesser in spack create"""
+
+ def setUp(self):
+ self.tar = which('tar')
+ self.tmpdir = tempfile.mkdtemp()
+ self.orig_dir = os.getcwd()
+ os.chdir(self.tmpdir)
+ self.stage = None
+
+
+ def tearDown(self):
+ shutil.rmtree(self.tmpdir, ignore_errors=True)
+ if self.stage:
+ self.stage.destroy()
+ os.chdir(self.orig_dir)
+
+
+ def check_archive(self, filename, system):
+ mkdirp('archive')
+ touch(join_path('archive', filename))
+ self.tar('czf', 'archive.tar.gz', 'archive')
+
+ url = 'file://' + join_path(os.getcwd(), 'archive.tar.gz')
+ print url
+ self.stage = Stage(url)
+ self.stage.fetch()
+
+ guesser = ConfigureGuesser()
+ guesser(self.stage)
+ self.assertEqual(system, guesser.build_system)
+
+
+ def test_python(self):
+ self.check_archive('setup.py', 'python')
+
+
+ def test_autotools(self):
+ self.check_archive('configure', 'autotools')
+
+
+ def test_cmake(self):
+ self.check_archive('CMakeLists.txt', 'cmake')
+
+
+ def test_unknown(self):
+ self.check_archive('foobar', 'unknown')
+
+
diff --git a/var/spack/packages/py-lockfile/package.py b/var/spack/packages/py-lockfile/package.py
new file mode 100644
index 0000000000..8722914d94
--- /dev/null
+++ b/var/spack/packages/py-lockfile/package.py
@@ -0,0 +1,23 @@
+from spack import *
+
+class PyLockfile(Package):
+ """The lockfile package exports a LockFile class which provides a
+ simple API for locking files. Unlike the Windows msvcrt.locking
+ function, the fcntl.lockf and flock functions, and the
+ deprecated posixfile module, the API is identical across both
+ Unix (including Linux and Mac) and Windows platforms. The lock
+ mechanism relies on the atomic nature of the link (on Unix) and
+ mkdir (on Windows) system calls. An implementation based on
+ SQLite is also provided, more as a demonstration of the
+ possibilities it provides than as production-quality code.
+ """
+ homepage = "https://pypi.python.org/pypi/lockfile"
+ url = "https://pypi.python.org/packages/source/l/lockfile/lockfile-0.10.2.tar.gz"
+
+ version('0.10.2', '1aa6175a6d57f082cd12e7ac6102ab15')
+
+ extends("python")
+ depends_on("py-setuptools")
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
diff --git a/var/spack/packages/py-python-daemon/package.py b/var/spack/packages/py-python-daemon/package.py
new file mode 100644
index 0000000000..12cbe9101c
--- /dev/null
+++ b/var/spack/packages/py-python-daemon/package.py
@@ -0,0 +1,26 @@
+from spack import *
+
+class PyPythonDaemon(Package):
+ """Library to implement a well-behaved Unix daemon process.
+
+ This library implements the well-behaved daemon specification of
+ PEP Standard daemon process.
+
+ A well-behaved Unix daemon process is tricky to get right, but the
+ required steps are much the same for every daemon program. A
+ DaemonContext instance holds the behaviour and configured process
+ environment for the program; use the instance as a context manager
+ to enter a daemon state.
+ """
+ homepage = "https://pypi.python.org/pypi/python-daemon/"
+ url = "https://pypi.python.org/packages/source/p/python-daemon/python-daemon-2.0.5.tar.gz"
+
+ version('2.0.5', '73e7f49f525c51fa4a995aea4d80de41')
+
+ extends("python")
+ depends_on("py-setuptools")
+ depends_on("py-lockfile")
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
+