Move all licensing support to pre/post_install hooks

This commit is contained in:
Adam J. Stewart 2016-05-10 15:43:24 -05:00
parent 19f4b27fd2
commit ee7ec4fa66
3 changed files with 147 additions and 127 deletions

View File

@ -813,7 +813,7 @@ points to a license server called licman1:
USE_SERVER USE_SERVER
If your package requires the license to install, you can reference the If your package requires the license to install, you can reference the
location of this global license using ``Package.global_license_file()``. location of this global license using ``self.global_license_file``.
After installation, symlinks for all of the files given in After installation, symlinks for all of the files given in
``license_files`` will be created, pointing to this global license. ``license_files`` will be created, pointing to this global license.
If you install a different version or variant of the package, Spack If you install a different version or variant of the package, Spack

View File

@ -0,0 +1,135 @@
import os
import spack
import llnl.util.tty as tty
from llnl.util.filesystem import join_path
def pre_install(pkg):
"""This hook handles global license setup for licensed software."""
if pkg.license_required:
set_up_license(pkg)
def set_up_license(pkg):
"""Prompt the user, letting them know that a license is required.
For packages that rely on license files, a global license file is
created and opened for editing.
For packages that rely on environment variables to point to a
license, a warning message is printed.
For all other packages, documentation on how to set up a license
is printed."""
# If the license can be stored in a file, create one
if pkg.license_files:
license_path = pkg.global_license_file
if not os.path.exists(license_path):
# Create a new license file
write_license_file(pkg, license_path)
# Open up file in user's favorite $EDITOR for editing
spack.editor(license_path)
tty.msg("Added global license file %s" % license_path)
else:
# Use already existing license file
tty.msg("Found already existing license %s" % license_path)
# If not a file, what about an environment variable?
elif pkg.license_vars:
tty.warn("A license is required to use %s. Please set %s to the "
"full pathname to the license file, or port@host if you"
" store your license keys on a dedicated license server" %
(pkg.name, ' or '.join(pkg.license_vars)))
# If not a file or variable, suggest a website for further info
elif pkg.license_url:
tty.warn("A license is required to use %s. See %s for details" %
(pkg.name, pkg.license_url))
# If all else fails, you're on your own
else:
tty.warn("A license is required to use %s" % pkg.name)
def write_license_file(pkg, license_path):
"""Writes empty license file.
Comments give suggestions on alternative methods of
installing a license."""
comment = pkg.license_comment
# Global license directory may not already exist
if not os.path.exists(os.path.dirname(license_path)):
os.makedirs(os.path.dirname(license_path))
license = open(license_path, 'w')
# License files
license.write("""\
{0} A license is required to use {1}.
{0}
{0} The recommended solution is to store your license key in this global
{0} license file. After installation, the following symlink(s) will be
{0} added to point to this file (relative to the installation prefix):
{0}
""".format(comment, pkg.name))
for filename in pkg.license_files:
license.write("{0}\t{1}\n".format(comment, filename))
license.write("{0}\n".format(comment))
# Environment variables
if pkg.license_vars:
license.write("""\
{0} Alternatively, use one of the following environment variable(s):
{0}
""".format(comment))
for var in pkg.license_vars:
license.write("{0}\t{1}\n".format(comment, var))
license.write("""\
{0}
{0} If you choose to store your license in a non-standard location, you may
{0} set one of these variable(s) to the full pathname to the license file, or
{0} port@host if you store your license keys on a dedicated license server.
{0} You will likely want to set this variable in a module file so that it
{0} gets loaded every time someone tries to use {1}.
{0}
""".format(comment, pkg.name))
# Documentation
if pkg.license_url:
license.write("""\
{0} For further information on how to acquire a license, please refer to:
{0}
{0}\t{1}
{0}
""".format(comment, pkg.license_url))
license.write("""\
{0} You may enter your license below.
""".format(comment))
license.close()
def post_install(pkg):
"""This hook symlinks local licenses to the global license for
licensed software."""
if pkg.license_required:
symlink_license(pkg)
def symlink_license(pkg):
"""Create local symlinks that point to the global license file."""
target = pkg.global_license_file
for filename in pkg.license_files:
link_name = join_path(pkg.prefix, filename)
if os.path.exists(target):
os.symlink(target, link_name)
tty.msg("Added local symlink %s to global license file" % link_name)

View File

@ -397,6 +397,17 @@ def __init__(self, spec):
if self.is_extension: if self.is_extension:
spack.repo.get(self.extendee_spec)._check_extendable() spack.repo.get(self.extendee_spec)._check_extendable()
@property
def global_license_file(self):
"""Returns the path where a global license file should be stored."""
if not self.license_files:
return
spack_root = ancestor(__file__, 4)
global_license_dir = join_path(spack_root, 'etc', 'spack', 'licenses')
return join_path(global_license_dir, self.name,
os.path.basename(self.license_files[0]))
@property @property
def version(self): def version(self):
if not self.spec.versions.concrete: if not self.spec.versions.concrete:
@ -899,10 +910,6 @@ def build_process():
"""Forked for each build. Has its own process and python """Forked for each build. Has its own process and python
module space set up by build_environment.fork().""" module space set up by build_environment.fork()."""
# Set up a global license if one is required
if self.license_required:
self.set_up_license()
start_time = time.time() start_time = time.time()
if not fake: if not fake:
if not skip_patch: if not skip_patch:
@ -965,10 +972,6 @@ def build_process():
self._total_time = time.time() - start_time self._total_time = time.time() - start_time
build_time = self._total_time - self._fetch_time build_time = self._total_time - self._fetch_time
# Symlink local license to global license if one is required
if self.license_required and self.license_files:
self.symlink_license()
tty.msg("Successfully installed %s" % self.name, tty.msg("Successfully installed %s" % self.name,
"Fetch: %s. Build: %s. Total: %s." % "Fetch: %s. Build: %s. Total: %s." %
(_hms(self._fetch_time), _hms(build_time), (_hms(self._fetch_time), _hms(build_time),
@ -1019,124 +1022,6 @@ def check_paths(path_list, filetype, predicate):
"Install failed for %s. Nothing was installed!" % self.name) "Install failed for %s. Nothing was installed!" % self.name)
def global_license_file(self):
"""Returns the path where a global license file should be stored."""
if not self.license_files:
return
spack_root = ancestor(__file__, 4)
global_license_dir = join_path(spack_root, 'etc', 'spack', 'licenses')
return join_path(global_license_dir, self.name,
os.path.basename(self.license_files[0]))
def set_up_license(self):
"""Prompt the user, letting them know that a license is required."""
# If the license can be stored in a file, create one
if self.license_files:
license_path = self.global_license_file()
if not os.path.exists(license_path):
# Create a new license file
self.write_license_file(license_path)
# Open up file in user's favorite $EDITOR for editing
spack.editor(license_path)
tty.msg("Added global license file %s" % license_path)
else:
# Use already existing license file
tty.msg("Found already existing license %s" % license_path)
# If not a file, what about an environment variable?
elif self.license_vars:
tty.warn("A license is required to use %s. Please set %s to the "
"full pathname to the license file, or port@host if you"
" store your license keys on a dedicated license server" %
(self.name, ' or '.join(self.license_vars)))
# If not a file or variable, suggest a website for further info
elif self.license_url:
tty.warn("A license is required to use %s. See %s for details" %
(self.name, self.license_url))
# If all else fails, you're on your own
else:
tty.warn("A license is required to use %s" % self.name)
def write_license_file(self, license_path):
"""Writes empty license file.
Comments give suggestions on alternative methods of
installing a license."""
comment = self.license_comment
# Global license directory may not already exist
if not os.path.exists(os.path.dirname(license_path)):
os.makedirs(os.path.dirname(license_path))
license = open(license_path, 'w')
# License files
license.write("""\
{0} A license is required to use {1}.
{0}
{0} The recommended solution is to store your license key in this global
{0} license file. After installation, the following symlink(s) will be
{0} added to point to this file (relative to the installation prefix):
{0}
""".format(comment, self.name))
for filename in self.license_files:
license.write("{0}\t{1}\n".format(comment, filename))
license.write("{0}\n".format(comment))
# Environment variables
if self.license_vars:
license.write("""\
{0} Alternatively, use one of the following environment variable(s):
{0}
""".format(comment))
for var in self.license_vars:
license.write("{0}\t{1}\n".format(comment, var))
license.write("""\
{0}
{0} If you choose to store your license in a non-standard location, you may
{0} set one of these variable(s) to the full pathname to the license file, or
{0} port@host if you store your license keys on a dedicated license server.
{0} You will likely want to set this variable in a module file so that it
{0} gets loaded every time someone tries to use {1}.
{0}
""".format(comment, self.name))
# Documentation
if self.license_url:
license.write("""\
{0} For further information on how to acquire a license, please refer to:
{0}
{0}\t{1}
{0}
""".format(comment, self.license_url))
license.write("""\
{0} You may enter your license below.
""".format(comment))
license.close()
def symlink_license(self):
"""Create local symlinks that point to the global license file."""
target = self.global_license_file()
for filename in self.license_files:
link_name = join_path(self.prefix, filename)
if os.path.exists(target):
os.symlink(target, link_name)
tty.msg("Added local symlink %s to global license file" % link_name)
def do_install_dependencies(self, **kwargs): def do_install_dependencies(self, **kwargs):
# Pass along paths of dependencies here # Pass along paths of dependencies here
for dep in self.spec.dependencies.values(): for dep in self.spec.dependencies.values():