From ee7ec4fa66aed5bcbdb97fddf2303b3debab5c4e Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Tue, 10 May 2016 15:43:24 -0500 Subject: Move all licensing support to pre/post_install hooks --- lib/spack/docs/packaging_guide.rst | 2 +- lib/spack/spack/hooks/licensing.py | 135 ++++++++++++++++++++++++++++++++++++ lib/spack/spack/package.py | 137 +++---------------------------------- 3 files changed, 147 insertions(+), 127 deletions(-) create mode 100644 lib/spack/spack/hooks/licensing.py diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index 65ff08d5c8..650e0ee3b2 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -813,7 +813,7 @@ points to a license server called licman1: USE_SERVER 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 ``license_files`` will be created, pointing to this global license. If you install a different version or variant of the package, Spack diff --git a/lib/spack/spack/hooks/licensing.py b/lib/spack/spack/hooks/licensing.py new file mode 100644 index 0000000000..56f7b6daa5 --- /dev/null +++ b/lib/spack/spack/hooks/licensing.py @@ -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) diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 504e1fc3bb..17d92fdf79 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -397,6 +397,17 @@ class Package(object): if self.is_extension: 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 def version(self): if not self.spec.versions.concrete: @@ -899,10 +910,6 @@ class Package(object): """Forked for each build. Has its own process and python 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() if not fake: if not skip_patch: @@ -965,10 +972,6 @@ class Package(object): self._total_time = time.time() - start_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, "Fetch: %s. Build: %s. Total: %s." % (_hms(self._fetch_time), _hms(build_time), @@ -1019,124 +1022,6 @@ class Package(object): "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): # Pass along paths of dependencies here for dep in self.spec.dependencies.values(): -- cgit v1.2.3-70-g09d2