#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
#
import os
import re
import subprocess
import sys
"""Exception that is raised when a module reports a module as a
dependency without a path to that module."""
return _("Could not find the file for {name} imported "
"""Exception that is raised when a module is installed into a path
example) but has a different version of python specified in its
return _("The file to be installed at {ip} declares a "
"python version of {decl_v}. However, the path suggests "
"that the version should be {inst_v}. The text of the "
"""Exception that is raised when a python file to be analyzed contains a
syntax error."""
return _("The file to be installed at {ip} appears to be a "
"python file but contains a syntax error that prevents "
"it from being analyzed. The text of the file can be found"
"at {lp}. The error happened on line {line} at offset "
"""This exception is raised when the subprocess created to analyze the
module using a different version of python exits with an error code."""
return _("The command {cmd}\nexited with return code {rc} "
"""This exception is used when the output from the subprocess does not
follow the expected format."""
return _("The command {cmd} produced the following lines "
"which cannot be understood:\n{lines}").format(
"""This exception is used when an executable file starts with
python version may be inferred."""
return _("The file to be installed in {ip} does not specify "
"a specific version of python either in its installed path "
"nor in its text. Such a file cannot be analyzed for "
"dependencies since the version of python it will be used "
"with is unknown. The text of the file is here: "
"""Class representing the dependency created by importing a module
in python."""
"""Analyze the file delivered by the action for any python dependencies.
The 'action' parameter contain the action which delivers the file.
The 'pkg_vars' parameter contains the variants against which
the action's package was published.
The 'script_path' parameter is None of the file is not executable, or
is the path for the binary which is used to execute the file.
The 'run_paths' parameter is a list of paths that should be searched
for modules.
"""
# There are three conditions which determine whether python dependency
# analysis is performed on a file with python in its #! line.
# 1) Is the file executable. (Represented in the table below by X)
# 2) Is the file installed into a directory which provides information
# about what version of python should be used for it.
# (Represented by D)
# 3) Does the first line of the file include a specific version of
# python. (Represented by F)
#
# Conditions || Perform Analysis
# X D F || Y, if F and D disagree, display a warning in the output
# || and use D to analyze the file.
# X D !F || Y
# X !D F || Y
# X !D !F || N, and display a warning in the output.
# !X D F || Y
# !X D !F || Y
# !X !D F || N
# !X !D !F || N
deps = []
errs = []
path_version = None
dir_major = None
dir_minor = None
file_major = None
file_minor = None
cur_major = None
cur_minor = None
# Version of python to use to do the analysis.
analysis_major = None
analysis_minor = None
if install_match:
script_match = None
if script_path:
if script_match:
if executable:
# Check whether the version of python declared in the #! line
# of the file and the version of python implied by the directory
# the file is delivered into match.
if install_match and script_match and \
if install_match:
elif script_match:
else:
# An example of this case is an executable file in
elif install_match:
if analysis_major is None or analysis_minor is None:
# If the version implied by the directory hierarchy matches the version
# of python running, use the default analyzer and don't fork and exec.
try:
for m in loaded_modules
]):
# Add the directory the python file will be
# installed in to the paths used to find modules
# for import. This allows relative imports to
# work correctly.
except SyntaxError as e:
except Exception as e:
# If the version implied by the directory hierarchy does not match the
# version of python running, it's necessary to fork and run the
# appropriate version of python.
# Tell Python to not create .pyc, .pyo, etc. cache files for any Python
# modules our script imports.
if run_paths:
try:
except Exception as e:
str(e))], {}
if sp.returncode:
err))
bad_lines = []
for l in out.splitlines():
l = l.strip()
if l.startswith("DEP "):
try:
except Exception:
else:
elif l.startswith("ERR "):
else:
if bad_lines: