Source code for spack.hooks.licensing

# Copyright 2013-2022 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
# SPDX-License-Identifier: (Apache-2.0 OR MIT)

import os

import llnl.util.tty as tty
from llnl.util.filesystem import mkdirp
from llnl.util.symlink import symlink

from spack.util.editor import editor
from spack.util.executable import Executable, which

[docs]def pre_install(spec): """This hook handles global license setup for licensed software.""" pkg = spec.package if pkg.license_required and not pkg.spec.external: set_up_license(pkg)
[docs]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 editor_exe = None if 'VISUAL' in os.environ: editor_exe = Executable(os.environ['VISUAL']) # gvim runs in the background by default so we force it to run # in the foreground to make sure the license file is updated # before we try to install if 'gvim' in os.environ['VISUAL']: editor_exe.add_default_arg('-f') elif 'EDITOR' in os.environ: editor_exe = Executable(os.environ['EDITOR']) else: editor_exe = which('vim', 'vi', 'emacs', 'nano') if editor_exe is None: raise EnvironmentError( 'No text editor found! Please set the VISUAL and/or EDITOR' ' environment variable(s) to your preferred text editor.') def editor_wrapper(exe, args): editor_exe(license_path) editor(license_path, _exec_func=editor_wrapper) 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" % (, ' 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.license_url)) # If all else fails, you're on your own else: tty.warn("A license is required to use %s" %
[docs]def write_license_file(pkg, license_path): """Writes empty license file. Comments give suggestions on alternative methods of installing a license.""" # License files linktargets = "" for f in pkg.license_files: linktargets += "\t%s\n" % f # Environment variables envvars = "" if pkg.license_vars: for varname in pkg.license_vars: envvars += "\t%s\n" % varname # Documentation url = "" if pkg.license_url: url += "\t%s\n" % pkg.license_url # Assemble. NB: pkg.license_comment will be prepended upon output. txt = """ A license is required to use package '{0}'. * If your system is already properly configured for such a license, save this file UNCHANGED. The system may be configured if: - A license file is installed in a default location. """.format( if envvars: txt += """\ - One of the following environment variable(s) is set for you, possibly via a module file: {0} """.format(envvars) txt += """\ * Otherwise, depending on the license you have, enter AT THE BEGINNING of this file: - the contents of your license file, or - the address(es) of your license server. After installation, the following symlink(s) will be added to point to this Spack-global file (relative to the installation prefix). {0} """.format(linktargets) if url: txt += """\ * For further information on licensing, see: {0} """.format(url) txt += """\ Recap: - You may not need to modify this file at all. - Otherwise, enter your license or server address AT THE BEGINNING. """ # Global license directory may not already exist if not os.path.exists(os.path.dirname(license_path)): os.makedirs(os.path.dirname(license_path)) # Output with open(license_path, 'w') as f: for line in txt.splitlines(): f.write("{0}{1}\n".format(pkg.license_comment, line)) f.close()
[docs]def post_install(spec): """This hook symlinks local licenses to the global license for licensed software. """ pkg = spec.package if pkg.license_required and not pkg.spec.external: symlink_license(pkg)