Mini Shell
# coding: utf-8
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import glob
import os
import re
import errno
from subprocess import check_output, CalledProcessError, STDOUT
# Used both for config and some state like available_versions cache
# mainly because it's easier to put it in cagefs as a one dir
# We have symlink to that dir in /etc
# for ease of use the selector config and avoiding problem with cagefs
CONFIG_DIR = '/usr/share/l.v.e-manager/cl.python'
ALT_NAMES = 'alt-python'
# It's also used to construct base_dir:
ALT_PYTHON_PREFIX = '/opt/alt/python'
class PythonError(Exception):
"""Top level error class for admin's part of Python selector"""
pass
class PythonConfigError(PythonError):
"""Generic error class for PythonConfig"""
pass
def create_config_dirs():
try:
os.makedirs(CONFIG_DIR)
except OSError as e:
if e.errno != errno.EEXIST: # ignore only "File exists" error
raise
def is_major_version(ver):
"""Return True if specified MAJOR version is valid for processing"""
if not isinstance(ver, str):
return False
if not re.match(r'^\d+\.\d+$', ver):
return False
return True
def scan_python_versions():
""" Search CL python interpreters and return dict with info about them """
res = {}
for folder in glob.glob('{}*'.format(ALT_PYTHON_PREFIX)):
# extract major version of python interpreter
# get two last digits from the string such as `/opt/alt/python27`
maj_ver = ''.join(filter(str.isdigit, folder.split('/')[-1]))
maj_ver = f'{maj_ver[0]}.{maj_ver[1:]}'
# extract full version of python interpreter
# from the string such as `Python 2.7.14`
python_bin = '{}/bin/python{}'.format(folder, maj_ver)
if not os.path.isfile(python_bin):
continue
try:
# Starting from 3.4, python command output --version information to stdout instead of stderr
# https://docs.python.org/3/whatsnew/3.4.html#changes-in-python-command-behavior
full_ver = check_output([python_bin, '-V'], text=True, stderr=STDOUT)
except CalledProcessError:
continue
if full_ver != "":
full_ver = full_ver.split()[1]
res[maj_ver] = {
'full_version': full_ver,
'root_path': folder,
}
return res
__all__ = (
'CONFIG_DIR',
'ALT_NAMES',
'ALT_PYTHON_PREFIX',
'PythonError',
'PythonConfigError',
'create_config_dirs',
'is_major_version',
'scan_python_versions',
)
Zerion Mini Shell 1.0