From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- .../latex/contrib/pythontex/pythontex_install.py | 494 +++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 macros/latex/contrib/pythontex/pythontex_install.py (limited to 'macros/latex/contrib/pythontex/pythontex_install.py') diff --git a/macros/latex/contrib/pythontex/pythontex_install.py b/macros/latex/contrib/pythontex/pythontex_install.py new file mode 100644 index 0000000000..64ac0e4d1b --- /dev/null +++ b/macros/latex/contrib/pythontex/pythontex_install.py @@ -0,0 +1,494 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +''' +Install PythonTeX + +This installation script is written to work with TeX Live and MiKTeX. Note +that PythonTeX is included in TeX Live 2013 and later, and may be installed +via the package manager. Thus, this installation script is only needed with +TeX Live when you wish to install the latest version. PythonTeX is not +currently available via the MiKTeX package manager. + +The script will automatically overwrite (and thus update) all previously +installed PythonTeX files in the designated installation location. When +Kpathsea is available, files may be installed in TEXMFDIST, TEXMFLOCAL, +TEXMFHOME, or a manually specified location. Otherwise, the installation +location must be specified manually. Installing in TEXMFDIST is useful +under TeX Live if you want to install PythonTeX and then update it in the +future via the package manager. + +The `mktexlsr` (TeX Live) or `initexmf --update-fndb` (MiKTeX) command is +executed at the end of the script, to make the system aware of any new files. + +Under TeX Live, the script attempts to create a binary wrapper (Windows) or +symlink (Linux and OS X) for launching the main PythonTeX scripts, +`pythontex*.py` and `depythontex*.py`. Under MiKTeX, it attempts to create +a batch file in `miktex/bin`. + + +Copyright (c) 2012-2014, Geoffrey M. Poore +All rights reserved. +Licensed under the BSD 3-Clause License: + http://www.opensource.org/licenses/BSD-3-Clause + +''' + + +# Imports +import sys +import platform +from os import path, mkdir, makedirs +if platform.system() != 'Windows': + # Only create symlinks if not under Windows + # (os.symlink doesn't exist under Windows) + from os import symlink, chmod, unlink +from subprocess import call, check_call, check_output +from shutil import copy +import textwrap + + +# We need a version of input that works under both Python 2 and 3 +try: + input = raw_input +except: + pass + + +# Print startup messages and notices +print('Preparing to install PythonTeX') +if platform.system() != 'Windows': + message = ''' + You may need to run this script with elevated permissions + and/or specify the environment. For example, you may need + "sudo env PATH=$PATH". That is typically necessary when your + system includes a TeX distribution, and you have manually + installed another distribution (common with Ubuntu etc.). If + the installation path you want is not automatically detected, + it may indicate a permissions issue. + ''' + print(textwrap.dedent(message)) + + +# Attempt to detect the TeX distribution +try: + if sys.version_info.major == 2: + texout = check_output(['latex', '--version']) + else: + texout = check_output(['latex', '--version']).decode('utf-8') +except: + sys.exit('Could not retrieve latex info when running "latex --version"') +if 'TeX Live' in texout: + detected_texdist = True + texlive = True + miktex = False +elif platform.system() == 'Windows' and 'MiKTeX' in texout: + detected_texdist = True + texlive = False + miktex = True +else: + detected_texdist = False + texlive = False + miktex = False + + +# Make sure all necessary files are present +# The pythontex_gallery and pythontex_quickstart are optional; we +# check for them when installing doc, and install if available +needed_files = ['pythontex.py', 'pythontex2.py', 'pythontex3.py', + 'pythontex_engines.py', 'pythontex_utils.py', + 'depythontex.py', 'depythontex2.py', 'depythontex3.py', + 'pythontex.sty', 'pythontex.ins', 'pythontex.dtx', + 'pythontex.pdf', 'README', + 'syncpdb.py'] +missing_files = False +# Print a list of all files that are missing, and exit if any are +for eachfile in needed_files: + if not path.exists(eachfile): + print('Could not find file ' + eachfile) + missing_files = True +if missing_files: + sys.exit('Exiting due to missing files.') + + +# Retrieve the location of valid TeX trees +if sys.version_info[0] == 2: + try: + texmf_dist = check_output(['kpsewhich', '-var-value', 'TEXMFDIST']).rstrip('\r\n') + except: + texmf_dist = None + try: + texmf_local = check_output(['kpsewhich', '-var-value', 'TEXMFLOCAL']).rstrip('\r\n') + except: + texmf_local = None + try: + texmf_home = check_output(['kpsewhich', '-var-value', 'TEXMFHOME']).rstrip('\r\n') + except: + texmf_home = None +else: + try: + texmf_dist = check_output(['kpsewhich', '-var-value', 'TEXMFDIST']).decode('utf-8').rstrip('\r\n') + except: + texmf_dist = None + try: + texmf_local = check_output(['kpsewhich', '-var-value', 'TEXMFLOCAL']).decode('utf-8').rstrip('\r\n') + except: + texmf_local = None + try: + texmf_home = check_output(['kpsewhich', '-var-value', 'TEXMFHOME']).decode('utf-8').rstrip('\r\n') + except: + texmf_home = None + + +# Get installation location from user +texmf_vars = [texmf_dist, texmf_local, texmf_home] +message = ''' + Choose an installation location. + + TEXMFDIST is a good choice if you want to update PythonTeX + in the future using your TeX distribution's package manager + (assuming that is supported). + + 1. TEXMFDIST + {0} + 2. TEXMFLOCAL + {1} + 3. TEXMFHOME + {2} + 4. Manual location + + 5. Exit without installing + '''.format(*[x if x else '' for x in texmf_vars]) + +if any(texmf_vars): + path_choice = '' + while (path_choice not in ('1', '2', '3', '4', '5') or + (int(path_choice) <= 3 and not texmf_vars[int(path_choice)-1])): + print(textwrap.dedent(message)) + path_choice = input('Installation location (number): ') + if path_choice == '': + sys.exit() + if path_choice == '1': + texmf_path = texmf_dist + elif path_choice == '2': + texmf_path = texmf_local + elif path_choice == '3': + texmf_path = texmf_home + elif path_choice == '4': + texmf_path = input('Enter a path:\n') + if texmf_path == '': + sys.exit() + if platform.system() == 'Windows': + if 'texlive' in texmf_path.lower(): + detected_texdist = True + texlive = True + miktex = False + elif 'miktex' in texmf_path.lower(): + detected_texdist = True + texlive = False + miktex = True + else: + sys.exit() +else: + print('Failed to detect possible installation locations automatically.') + print('TEXMF paths could not be located with kpsewhich.') + texmf_path = input('Plese enter an installation path, or press "Enter" to exit:\n') + if texmf_path == '': + sys.exit() + +# Make sure path slashes are compatible with the operating system +# Kpathsea returns forward slashes, but Windows needs back slashes +texmf_path = path.expandvars(path.expanduser(path.normcase(texmf_path))) + +# Check to make sure the path is valid +# This should only be needed for manual input, but it's a good check +if not path.isdir(texmf_path): + sys.exit('Invalid installation path. Exiting.') + +# Now check that all other needed paths are present +if path_choice != '2': + doc_path = path.join(texmf_path, 'doc', 'latex') + package_path = path.join(texmf_path, 'tex', 'latex') + scripts_path = path.join(texmf_path, 'scripts') + source_path = path.join(texmf_path, 'source', 'latex') +else: + doc_path = path.join(texmf_path, 'doc', 'latex', 'local') + package_path = path.join(texmf_path, 'tex', 'latex', 'local') + scripts_path = path.join(texmf_path, 'scripts', 'local') + source_path = path.join(texmf_path, 'source', 'latex', 'local') +# May need to create some local directories +make_paths = False +for eachpath in [doc_path, package_path, scripts_path, source_path]: + if not path.exists(eachpath): + if make_paths: + makedirs(eachpath) + print(' * Created ' + eachpath) + else: + choice = '' + while choice not in ('y', 'n'): + choice = input('Some directories do not exist. Create them? [y/n] ') + if choice == '': + sys.exit() + if choice == 'y': + make_paths = True + try: + makedirs(eachpath) + print(' * Created ' + eachpath) + except (OSError, IOError) as e: + if e.errno == 13: + print('\nInsufficient permission to install PythonTeX') + if platform.system() == 'Windows': + message = ''' + You may need to run the installer as "administrator". + This may be done under Vista and later by right-clicking on + pythontex_install.bat, then selecting "Run as administrator". + Or you can open a command prompt as administrator + (Start, Programs, Accessories, right-click Command Prompt, + Run as administrator), change to the directory in which + pythontex_install.py is located, and run + "python pythontex_install.py". + ''' + print(textwrap.dedent(message)) + call(['pause'], shell=True) + else: + print('(For example, you may need "sudo", or possibly "sudo env PATH=$PATH")\n') + sys.exit(1) + else: + raise + else: + message = ''' + Paths were not created. The following will be needed. + * {0} + * {1} + * {2} + * {3} + + Exiting. + '''.format(doc_path, package_path, scripts_path, source_path) + print(textwrap.dedent(message)) + sys.exit() + +# Modify the paths by adding the pythontex directory, which will be created +doc_path = path.join(doc_path, 'pythontex') +package_path = path.join(package_path, 'pythontex') +scripts_path = path.join(scripts_path, 'pythontex') +source_path = path.join(source_path, 'pythontex') + + +# Install files +# Use a try/except in case elevated permissions are needed (Linux and OS X) +print('\nPythonTeX will be installed in \n ' + texmf_path) +try: + # Install docs + if not path.exists(doc_path): + mkdir(doc_path) + copy('pythontex.pdf', doc_path) + copy('README', doc_path) + for doc in ('pythontex_quickstart.tex', 'pythontex_quickstart.pdf', + 'pythontex_gallery.tex', 'pythontex_gallery.pdf'): + if path.isfile(doc): + copy(doc, doc_path) + else: + doc = path.join('..', doc.rsplit('.', 1)[0], doc) + if path.isfile(doc): + copy(doc, doc_path) + # Install package + if not path.exists(package_path): + mkdir(package_path) + copy('pythontex.sty', package_path) + # Install scripts + if not path.exists(scripts_path): + mkdir(scripts_path) + copy('pythontex.py', scripts_path) + copy('depythontex.py', scripts_path) + copy('pythontex_utils.py', scripts_path) + copy('pythontex_engines.py', scripts_path) + copy('syncpdb.py', scripts_path) + for ver in [2, 3]: + copy('pythontex{0}.py'.format(ver), scripts_path) + copy('depythontex{0}.py'.format(ver), scripts_path) + # Install source + if not path.exists(source_path): + mkdir(source_path) + copy('pythontex.ins', source_path) + copy('pythontex.dtx', source_path) +except (OSError, IOError) as e: + if e.errno == 13: + print('\nInsufficient permission to install PythonTeX') + if platform.system() == 'Windows': + message = ''' + You may need to run the installer as "administrator". + This may be done under Vista and later by right-clicking on + pythontex_install.bat, then selecting "Run as administrator". + Or you can open a command prompt as administrator + (Start, Programs, Accessories, right-click Command Prompt, + Run as administrator), change to the directory in which + pythontex_install.py is located, and run + "python pythontex_install.py". + ''' + print(textwrap.dedent(message)) + call(['pause'], shell=True) + else: + print('(For example, you may need "sudo", or possibly "sudo env PATH=$PATH")\n') + sys.exit(1) + else: + raise + + +# Install binary wrappers, create symlinks, or suggest the creation of +# wrappers/batch files/symlinks. This part is operating system dependent. +if platform.system() == 'Windows': + # If under Windows, we create a binary wrapper if under TeX Live + # or a batch file if under MiKTeX. Otherwise, alert the user + # regarding the need for a wrapper or batch file. + if miktex: + try: + if sys.version_info.major == 2: + bin_path = check_output(['kpsewhich', '-var-value', 'TEXMFDIST']).rstrip('\r\n') + else: + bin_path = check_output(['kpsewhich', '-var-value', 'TEXMFDIST']).decode('utf-8').rstrip('\r\n') + bin_path = path.join(bin_path, 'miktex', 'bin') + + for s in ('pythontex.py', 'depythontex.py'): + batch = '@echo off\n"{0}" %*\n'.format(path.join(scripts_path, s)) + f = open(path.join(bin_path, s.replace('.py', '.bat')), 'w') + f.write(batch) + f.close() + except: + message = ''' + Could not create a batch file for launching pythontex.py and + depythontex.py. You will need to create a batch file manually. + Sample batch files are included with the main PythonTeX files. + The batch files should be in a location on the Windows PATH. + The bin/ directory in your TeX distribution may be a good + location. + + The scripts pythontex.py and depythontex.py are located in + the following directory: + {0} + '''.format(scripts_path) + print(textwrap.dedent(message)) + else: + # Assemble the binary path, assuming TeX Live + # The directory bin/ should be at the same level as texmf + bin_path = path.join(path.split(texmf_path)[0], 'bin', 'win32') + if path.exists(path.join(bin_path, 'runscript.exe')): + for f in ('pythontex.py', 'depythontex.py'): + copy(path.join(bin_path, 'runscript.exe'), path.join(bin_path, '{0}.exe'.format(f.rsplit('.')[0]))) + print('\nCreated binary wrapper...') + else: + message = ''' + Could not create a wrapper for launching pythontex.py and + depythontex.py; did not find runscript.exe. You will need + to create a wrapper manually, or use a batch file. Sample + batch files are included with the main PythonTeX files. + The wrapper or batch file should be in a location on the + Windows PATH. The bin/ directory in your TeX distribution + may be a good location. + + The scripts pythontex.py and depythontex.py are located in + the following directory: + {0} + '''.format(scripts_path) + print(textwrap.dedent(message)) +else: + # Optimistically proceed as if every system other than Windows can + # share one set of code. + root_path = path.split(texmf_path)[0] + # Create a list of all possible subdirectories of bin/ for TeX Live + # Source: http://www.tug.org/texlive/doc/texlive-en/texlive-en.html#x1-250003.2.1 + texlive_platforms = ['alpha-linux', 'amd64-freebsd', 'amd64-kfreebsd', + 'armel-linux', 'i386-cygwin', 'i386-freebsd', + 'i386-kfreebsd', 'i386-linux', 'i386-solaris', + 'mips-irix', 'mipsel-linux', 'powerpc-aix', + 'powerpc-linux', 'sparc-solaris', 'universal-darwin', + 'x86_64-darwin', 'x86_64-linux', 'x86_64-solaris'] + symlink_created = False + # Try to create a symlink in the standard TeX Live locations + for pltfrm in texlive_platforms: + bin_path = path.join(root_path, 'bin', pltfrm) + if path.exists(bin_path): + # Unlink any old symlinks if they exist, and create new ones + # Not doing this gave permissions errors under Ubuntu + for f in ('pythontex.py', 'pythontex2.py', 'pythontex3.py', + 'depythontex.py', 'depythontex2.py', 'depythontex3.py'): + link = path.join(bin_path, f) + if path.exists(link): + unlink(link) + symlink(path.join(scripts_path, f), link) + chmod(link, 0o775) + symlink_created = True + + # If the standard TeX Live bin/ locations didn't work, try the typical + # location for MacPorts TeX Live. This should typically be + # /opt/local/bin, but instead of assuming that location, we just climb + # two levels up from texmf-dist and then look for a bin/ directory that + # contains a tex executable. (For MacPorts, texmf-dist should be at + # /opt/local/share/texmf-dist.) + if not symlink_created and platform.system() == 'Darwin': + bin_path = path.join(path.split(root_path)[0], 'bin') + if path.exists(bin_path): + try: + # Make sure this bin/ is the bin/ we're looking for, by + # seeing if pdftex exists + check_output([path.join(bin_path, 'pdftex'), '--version']) + # Create symlinks + for f in ('pythontex.py', 'pythontex2.py', 'pythontex3.py', + 'depythontex.py', 'depythontex2.py', 'depythontex3.py'): + link = path.join(bin_path, f) + if path.exists(link): + unlink(link) + symlink(path.join(scripts_path, f), link) + chmod(link, 0o775) + symlink_created = True + except: + pass + if symlink_created: + print("\nCreated symlink in Tex's bin/ directory...") + else: + print('\nCould not automatically create a symlink to pythontex*.py and depythontex*.py.') + print('You may wish to create one manually, and make it executable via chmod.') + print('The scripts pythontex*.py and depythontex*.py are located in the following directory:') + print(' ' + scripts_path) + + +# Alert TeX to the existence of the package via mktexlsr +if not miktex: + try: + # Need to adjust if under Windows with a user-specified TeX Live + # installation and a default MiKTeX installation; want to call + # mktexlsr for the user-specified TeX Live installation + if platform.system() == 'Windows' and 'MiKTeX' in texout: + check_call(path.join(bin_path, 'mktexlsr')) + else: + check_call(['mktexlsr']) + print('\nRunning "mktexlsr" to make TeX aware of new files...') + except: + print('Could not run "mktexlsr".') + print('Your system may not be aware of newly installed files.') +else: + success = False + try: + check_call(['initexmf', '--admin', '--update-fndb']) + print('\nRunning "initexmf --admin --update-fndb" to make TeX aware of new files...') + check_call(['initexmf', '--update-fndb']) + print('\nRunning "initexmf --update-fndb" to make TeX aware of new files...') + success = True + except: + pass + if not success: + try: + check_call(['initexmf', '--update-fndb']) + print('\nRunning "initexmf --update-fndb" to make TeX aware of new files...') + print('Depending on your installation settings, you may also need to run') + print('"initexmf --admin --update-fndb"') + except: + print('Could not run "initexmf --update-fndb" or "initexmf --admin --update-fndb"') + print('Your system may not be aware of newly installed files.') + + +if platform.system() == 'Windows': + # Pause so that the user can see any errors or other messages + # input('\n[Press ENTER to exit]') + print('\n') + call(['pause'], shell=True) -- cgit v1.2.3