Source code for pymyinstall.win_installer.win_extract
# -*- coding: utf-8 -*-
"""
Helpers, inspired from `utils.py <https://github.com/winpython/winpython/blob/master/winpython/utils.py>`_
:githublink:`%|py|6`
"""
from __future__ import print_function
import sys
import os
import os.path as osp
import subprocess
import tarfile
import zipfile
import fnmatch
# import winreg
import glob
import shutil
from ..installcustom.install_custom_python import unzip7_files
from .win_helper import patch_shebang_line
if sys.version_info[0] == 2:
FileNotFoundError = Exception
[docs]def is_program_installed(basename):
"""
Return program absolute path if installed in PATH
Otherwise, return None
:param basename: base name
:return: boolean
:githublink:`%|py|33`
"""
if os.path.exists(basename):
return True
for path in os.environ["PATH"].split(os.pathsep):
abspath = osp.join(path, basename)
if osp.isfile(abspath):
return abspath
[docs]def extract_msi(fname, targetdir=None, verbose=False, fLOG=print):
"""
Extract .msi installer to a temporary directory (if targetdir
is None). Return the temporary directory path
:param fname: local installer (exe)
:param targetdir: where to install
:param verbose: verbose
:param fLOG: logging function
:return: targetdir
:githublink:`%|py|52`
"""
extract = 'msiexec.exe'
bname = osp.basename(fname)
args = ['/a', '%s' % bname]
if not verbose:
args += ['/quiet', '/qn']
args += ['TARGETDIR=%s' % targetdir]
cmd = [extract] + args
fLOG("[pymy] RUN: ", cmd)
subprocess.call(cmd, cwd=osp.dirname(fname))
fLOG('fname=%s' % fname)
fLOG('TARGETDIR=%s' % targetdir)
if "python-3" in fname.lower():
subprocess.call(
[r'%s\%s' % (targetdir, 'python.exe'), '-m', 'ensurepip'],
cwd=osp.dirname(r'%s\%s' % (targetdir, 'pythons.exe')))
# We patch ensurepip live (shame) !!!!
# rational: https://github.com/pypa/pip/issues/2328
for fname in glob.glob(r'%s\Scripts\*.exe' % targetdir):
patch_shebang_line(fname)
return targetdir
[docs]def extract_exe(fname, targetdir=None, verbose=False, fLOG=print, szip="7z.exe"):
"""
Extract *.exe* archive to a temporary directory (if targetdir
is None). Return the temporary directory path
:param fname: local installer (exe)
:param targetdir: where to install
:param verbose: verbose
:param szip: path to 7z.exe
:param fLOG: logging function
:return: targetdir
:githublink:`%|py|87`
"""
extract = szip
if not is_program_installed(extract):
pp = os.environ["PATH"].split(";")
raise FileNotFoundError(
"Required program '%s' was not found in PATH:\n %s" % (extract, "\n ".join(pp)))
bname = osp.basename(fname)
args = ['x', '-o%s' % targetdir, '-aos', bname]
if verbose:
retcode = subprocess.call([extract] + args, cwd=osp.dirname(fname))
else:
p = subprocess.Popen([extract] + args, cwd=osp.dirname(fname),
stdout=subprocess.PIPE)
p.communicate()
p.stdout.close()
retcode = p.returncode
if retcode != 0:
raise RuntimeError("Failed to extract %s (return code: %d),\nCMD: %s\nCMD*: %s\nin %s"
% (fname, retcode, str([extract] + args), " ".join([extract] + args), targetdir))
return targetdir
[docs]def extract_archive(fname, targetdir=None, verbose=False, fLOG=print):
"""
Extract .zip, .exe (considered to be a zip archive) or .tar.gz archive
to a temporary directory (if targetdir is None).
Return the temporary directory path
:param fname: zip file or exe file
:param targetdir: where to install
:param verbose: verbose
:param fLOG: logging function
:return: targetdir
:githublink:`%|py|120`
"""
if osp.splitext(fname)[1] in ('.zip', '.exe'):
obj = zipfile.ZipFile(fname, mode="r")
elif osp.splitext(fname)[1] in ('.7z'):
unzip7_files(fname, fLOG=fLOG, dest=targetdir)
return targetdir
elif fname.endswith('.tar.gz'):
obj = tarfile.open(fname, mode='r:gz')
else:
raise RuntimeError("Unsupported archive filename %s" % fname)
obj.extractall(path=targetdir)
return targetdir
[docs]def clean_msi(folder, pattern, verbose=False, fLOG=print):
"""
clean all files follwing a specific pattern
:param folder: folder
:param pattern: files to remove
:param verbose: display more information
:param fLOG: logging function
:return: removed files (as operation)
:githublink:`%|py|143`
"""
def find(loc, pattern):
exes = []
for root, dirnames, filenames in os.walk(loc):
for filename in fnmatch.filter(filenames, pattern):
exes.append(os.path.join(root, filename))
return exes
remove = find(folder, pattern)
operations = []
for r in remove:
if verbose:
fLOG("[pymy] remove", r)
os.remove(r)
operations.append(("remove", r))
return operations
[docs]def extract_copy(fname, targetdir=None, verbose=False, fLOG=print, szip=None):
"""
Copy *.exe* to targetdir
:param fname: local installer (exe)
:param targetdir: where to install
:param verbose: verbose
:param fLOG: logging function
:param szip: unused
:return: targetdir
:githublink:`%|py|170`
"""
shutil.copy(fname, targetdir)