install-texlive 0.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,107 @@
1
+ import logging
2
+ import os
3
+ import pexpect
4
+ import re
5
+ import requests
6
+ from io import BytesIO
7
+ import tarfile
8
+ from functools import lru_cache
9
+ from io import StringIO
10
+ from html.parser import HTMLParser
11
+ from ._version import __version__, __version_tuple__
12
+
13
+
14
+ __all__ = [
15
+ "__version__",
16
+ "__version_tuple__",
17
+ "command",
18
+ "download",
19
+ "get_mirror",
20
+ "get_size",
21
+ "is_current",
22
+ "URL",
23
+ "OLDURL",
24
+ ]
25
+
26
+
27
+ log = logging.getLogger(__name__)
28
+
29
+ URL = 'https://mirror.ctan.org/systems/texlive/tlnet/'
30
+ OLDURL = 'https://ftp.tu-chemnitz.de/pub/tug/historic/systems/texlive/{v}/tlnet-final/'
31
+
32
+
33
+ class GetText(HTMLParser):
34
+ """Only extract text of html page"""
35
+
36
+ def __init__(self):
37
+ super().__init__()
38
+ self._text = StringIO()
39
+
40
+ def handle_data(self, d):
41
+ self._text.write(d)
42
+
43
+ @property
44
+ def text(self):
45
+ return self._text.getvalue()
46
+
47
+
48
+ @lru_cache
49
+ def is_current(version):
50
+ r = requests.get('https://tug.org/texlive/')
51
+ r.raise_for_status()
52
+
53
+ parser = GetText()
54
+ parser.feed(r.text)
55
+
56
+ m = re.search(r'Current release: TeX Live ([0-9]{4})', parser.text)
57
+ if not m:
58
+ raise ValueError('Could not determine current TeX Live version')
59
+
60
+ current_version = int(m.groups()[0])
61
+ log.debug('Current version of TeX Live is {}'.format(current_version))
62
+ return current_version == version
63
+
64
+
65
+ def get_mirror():
66
+ """Get a CTAN mirror"""
67
+ r = requests.get(URL, allow_redirects=False)
68
+ r.raise_for_status()
69
+ return r.headers["Location"]
70
+
71
+
72
+ def download(version=None, outdir='.', url=None):
73
+ os.makedirs(outdir, exist_ok=True)
74
+
75
+ if version is None or is_current(version):
76
+ url = url or URL
77
+ url = url.rstrip("/") + '/install-tl-unx.tar.gz'
78
+ else:
79
+ url = OLDURL.format(v=version) + 'install-tl-unx.tar.gz'
80
+
81
+ log.debug('Downloading from {}'.format(url))
82
+
83
+ ret = requests.get(url)
84
+ ret.raise_for_status()
85
+
86
+ tar = tarfile.open(fileobj=BytesIO(ret.content), mode='r:gz')
87
+ tar.extractall(outdir)
88
+
89
+
90
+ def command(process, pattern, send, **kwargs):
91
+ process.expect(pattern, **kwargs)
92
+ process.sendline(send)
93
+
94
+
95
+ def get_size(process):
96
+ timeout = process.timeout
97
+ process.timeout = 1
98
+ lines = ''
99
+ try:
100
+ while True:
101
+ lines += process.readline().decode()
102
+ except pexpect.TIMEOUT:
103
+ pass
104
+
105
+ size = re.findall(r'disk space required: ([0-9]+ MB)', lines)[-1]
106
+ process.timeout = timeout
107
+ return size
@@ -0,0 +1,153 @@
1
+ import pexpect
2
+ from glob import glob
3
+ import os
4
+ import sys
5
+ import logging
6
+ import tempfile
7
+ import re
8
+ import subprocess as sp
9
+
10
+ from . import command, download, OLDURL, get_size, is_current, get_mirror
11
+ from .parser import parser
12
+
13
+
14
+ logging.basicConfig(level=logging.INFO)
15
+ log = logging.getLogger('install_texlive')
16
+
17
+ timeout = 30
18
+
19
+
20
+ def main():
21
+ args = parser.parse_args()
22
+
23
+ if args.verbose:
24
+ log.level = logging.DEBUG
25
+
26
+ if args.prefix:
27
+ args.prefix = os.path.abspath(args.prefix)
28
+ os.environ['TEXLIVE_INSTALL_PREFIX'] = args.prefix
29
+ os.makedirs(args.prefix, exist_ok=True)
30
+
31
+ os.environ["TEXLIVE_INSTALL_ENV_NOCHECK"] = "1"
32
+ log.info('Installing texlive to {}'.format(args.prefix or '/usr/local/texlive'))
33
+
34
+ if args.repository is None:
35
+ if args.version is None or is_current(args.version):
36
+ args.repository = get_mirror()
37
+ else:
38
+ args.repository = OLDURL.format(v=args.version)
39
+
40
+ if args.install_tl:
41
+ install_script = args.install_tl
42
+ cmd = install_script
43
+ else:
44
+ log.info("Using repository: %s", args.repository)
45
+ directory = os.path.join(
46
+ tempfile.gettempdir(), 'texlive-{}'.format(args.version or 'current')
47
+ )
48
+ download(version=args.version, outdir=directory, url=args.repository)
49
+ install_script = glob(os.path.join(directory, 'install-tl-*/install-tl'))[-1]
50
+ cmd = install_script + ' --repository={}'.format(args.repository)
51
+
52
+ log.info(cmd)
53
+
54
+ tl = pexpect.spawn(cmd, timeout=timeout)
55
+
56
+ try:
57
+ command(tl, 'installation.profile', 'N', timeout=5)
58
+ except pexpect.TIMEOUT:
59
+ pass
60
+
61
+ try:
62
+ command(tl, 'Import settings', 'y' if args.keep_config else 'n', timeout=5)
63
+ except pexpect.TIMEOUT:
64
+ log.info('No previous installation found')
65
+
66
+ try:
67
+ if args.scheme:
68
+ command(tl, 'Enter command:', 'S', timeout=timeout)
69
+ command(tl, 'Enter letter', args.scheme, timeout=timeout)
70
+ command(tl, 'Enter letter', 'R', timeout=timeout)
71
+
72
+ if args.collections:
73
+ command(tl, 'Enter command:', 'C', timeout=timeout)
74
+ command(tl, 'Enter letter', args.collections, timeout=timeout)
75
+ command(tl, 'Enter letter', 'R', timeout=timeout)
76
+
77
+ if not args.docs:
78
+ command(tl, 'Enter command:', 'O', timeout=timeout)
79
+ command(tl, 'Enter command:', 'D', timeout=timeout)
80
+ command(tl, 'Enter command:', 'R', timeout=timeout)
81
+
82
+ if not args.source:
83
+ command(tl, 'Enter command:', 'O', timeout=timeout)
84
+ command(tl, 'Enter command:', 'S', timeout=timeout)
85
+ command(tl, 'Enter command:', 'R', timeout=timeout)
86
+
87
+ log.info('Installation size will be {}'.format(get_size(tl)))
88
+ log.info('Starting installation')
89
+ command(tl, 'Enter command:', 'I', timeout=timeout)
90
+ except pexpect.TIMEOUT:
91
+ log.error('Something went wrong')
92
+ sys.exit(1)
93
+
94
+ lines = ''
95
+ try:
96
+ while not tl.terminated:
97
+ line = tl.readline().decode()
98
+ log.debug(line.strip())
99
+ lines += line
100
+ except pexpect.EOF:
101
+ log.error('EOF')
102
+
103
+ tl.close()
104
+ if tl.exitstatus == 0:
105
+ log.info('Installation installed succesfully')
106
+ else:
107
+ log.error('Installation did not finish succesfully')
108
+ sys.exit(tl.exitstatus)
109
+
110
+ bindir = re.findall(r'Most importantly, add\s+(.*)\s+to your PATH', lines)[0].strip()
111
+ version = re.findall(r'20[0-9][0-9]', bindir)[0]
112
+ env = os.environ
113
+ env['PATH'] = os.path.abspath(bindir) + ':' + env['PATH']
114
+
115
+ repo = args.repository
116
+ if args.version is not None and not is_current(args.version):
117
+ repo = OLDURL.format(v=version)
118
+
119
+ if repo is not None:
120
+ log.info("Setting repository to %s", repo)
121
+ sp.run(
122
+ ['tlmgr', 'option', 'repository', repo],
123
+ env=env,
124
+ check=True,
125
+ )
126
+
127
+ if args.update:
128
+ log.info('Start updating')
129
+ sp.run(
130
+ ['tlmgr', 'update', '--self', '--all', '--reinstall-forcibly-removed'],
131
+ env=env,
132
+ check=True,
133
+ )
134
+ log.info('Finished')
135
+
136
+ additional_packages = []
137
+ if args.install:
138
+ additional_packages.extend(args.install.split(','))
139
+
140
+ if args.package_file:
141
+ with open(args.package_file, 'r') as f:
142
+ additional_packages.extend(f.read().splitlines())
143
+
144
+ if additional_packages:
145
+ log.info('Start installing additional packages')
146
+ # tlmgr must always be up to date to install packages
147
+ sp.run(['tlmgr', 'update', '--self'], env=env, check=True)
148
+ sp.run(['tlmgr', 'install', *additional_packages], env=env, check=True)
149
+ log.info('Finished')
150
+
151
+
152
+ if __name__ == '__main__':
153
+ main()
@@ -0,0 +1,16 @@
1
+ # file generated by setuptools_scm
2
+ # don't change, don't track in version control
3
+ TYPE_CHECKING = False
4
+ if TYPE_CHECKING:
5
+ from typing import Tuple, Union
6
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
7
+ else:
8
+ VERSION_TUPLE = object
9
+
10
+ version: str
11
+ __version__: str
12
+ __version_tuple__: VERSION_TUPLE
13
+ version_tuple: VERSION_TUPLE
14
+
15
+ __version__ = version = '0.3.6'
16
+ __version_tuple__ = version_tuple = (0, 3, 6)
@@ -0,0 +1,73 @@
1
+ from argparse import ArgumentParser
2
+ from . import __version__
3
+
4
+ parser = ArgumentParser(prog='install_texlive')
5
+
6
+ parser.add_argument('-V', '--version', action='version', version=__version__)
7
+
8
+ parser.add_argument(
9
+ '-v', '--verbose', action='store_true', help='Create more verbose output'
10
+ )
11
+
12
+ parser.add_argument(
13
+ '-t', '--texlive-version', dest='version', type=int,
14
+ help='TeX Live version to install',
15
+ )
16
+
17
+ parser.add_argument(
18
+ '--install-tl',
19
+ help='Path to the install-tl script. If not given, TeX Live will be downloaded.',
20
+ )
21
+
22
+ parser.add_argument(
23
+ '-k', '--keep-config', action='store_true',
24
+ help='If an existing installation is found, keep its config',
25
+ )
26
+
27
+ parser.add_argument(
28
+ '-p', '--prefix',
29
+ help='Installation prefix, equivalent to setting TEXLIVE_INSTALL_PREFIX'
30
+ )
31
+
32
+ parser.add_argument(
33
+ '-c', '--collections',
34
+ help=(
35
+ 'The TeX Live package collections to install.'
36
+ ' E.g. -a to deselect all and only install the absolute basic TeX packages'
37
+ )
38
+ )
39
+
40
+ parser.add_argument(
41
+ '-s', '--scheme', choices=set('abcdefghijk'),
42
+ help='The TeX Live scheme to install. Default is "full"'
43
+ )
44
+
45
+ parser.add_argument(
46
+ '-u', '--update', action='store_true',
47
+ help='Update TeX Live after installation is finished'
48
+ )
49
+
50
+ parser.add_argument(
51
+ '-i', '--install',
52
+ help='Additional packages to install after the main Installation has finished as comma separated list'
53
+ )
54
+
55
+ parser.add_argument(
56
+ '-f', '--package-file',
57
+ help='A file with one package per line to be install after the main installation has finished'
58
+ )
59
+
60
+ parser.add_argument(
61
+ '--source', action='store_true',
62
+ help='Install the source tree',
63
+ )
64
+
65
+ parser.add_argument(
66
+ '--docs', action='store_true',
67
+ help='Install the docs tree',
68
+ )
69
+
70
+ parser.add_argument(
71
+ "-r", "--repository",
72
+ help="If given, set ctan mirror to this URL.",
73
+ )
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Maximilian Nöthe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,75 @@
1
+ Metadata-Version: 2.1
2
+ Name: install-texlive
3
+ Version: 0.3.6
4
+ Summary: Install texlive without human interaction in the process
5
+ Author-email: Maximilian Linhoff <maximilian.linhoff@tu-dortmund.de>
6
+ License: MIT License
7
+ Project-URL: repository, http://github.com/maxnoe/texlive-batch-installation
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Operating System :: POSIX :: Linux
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Topic :: Text Processing :: Markup :: LaTeX
14
+ Requires-Python: >=3.8
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: pexpect
18
+ Requires-Dist: requests
19
+
20
+ # texlive batch install [![CI](https://github.com/maxnoe/texlive-batch-installation/actions/workflows/ci.yml/badge.svg)](https://github.com/maxnoe/texlive-batch-installation/actions/workflows/ci.yml)
21
+
22
+ The TeX Live installer does not allow for interaction-less installation.
23
+
24
+ This is the reason why I created this project using pexpect to talk to the `install-tl`
25
+ script.
26
+
27
+ Usage:
28
+ ```
29
+ usage: install_texlive [-h] [-v] [-t VERSION] [--install-tl INSTALL_TL] [-k]
30
+ [-p PREFIX] [-c COLLECTIONS]
31
+ [-s {f,g,d,i,k,c,e,h,b,j,a}] [-u] [-i INSTALL]
32
+ [--source] [--docs]
33
+
34
+ optional arguments:
35
+ -h, --help show this help message and exit
36
+ -v, --verbose Create more verbose output
37
+ -t VERSION, --texlive-version VERSION
38
+ TeX Live version to install
39
+ --install-tl INSTALL_TL
40
+ Path to the install-tl script. If not given, TeX Live
41
+ will be downloaded.
42
+ -k, --keep-config If an existing installation is found, keep its config
43
+ -p PREFIX, --prefix PREFIX
44
+ Installation prefix, equivalent to setting
45
+ TEXLIVE_INSTALL_PREFIX
46
+ -c COLLECTIONS, --collections COLLECTIONS
47
+ The TeX Live package collections to install. E.g. -a
48
+ to deselect all and only install the absolute basic
49
+ TeX packages
50
+ -s {f,g,d,i,k,c,e,h,b,j,a}, --scheme {f,g,d,i,k,c,e,h,b,j,a}
51
+ The TeX Live scheme to install. Default is "full"
52
+ -u, --update Update TeX Live after installation is finished
53
+ -i INSTALL, --install INSTALL
54
+ Additional packages to install after the main
55
+ Installation has finished
56
+ --source Install the source tree
57
+ --docs Install the docs tree
58
+ ```
59
+
60
+
61
+ For a minimal installation (e.g. for CI jobs building documents), it is recommended to
62
+ only install the bare minimum selection of package collections: `-c "-a"` and then
63
+ have a file `tex-packages.txt` with the actually needed packages to compile the document:
64
+
65
+ ```
66
+ $ python -m install_texlive -p .texlive -t 2022 --collections='-a' --package-file tex-packages.txt --update
67
+ ```
68
+
69
+ To find out which package provides which style file (e.g. to find out which CTAN package provides `scrartcl.cls`), this command is helpful:
70
+
71
+ ```
72
+ $ tlmgr search --global --file '/scrartcl.cls'
73
+ koma-script:
74
+ texmf-dist/tex/latex/koma-script/scrartcl.cls
75
+ ```
@@ -0,0 +1,10 @@
1
+ install_texlive/__init__.py,sha256=mK0uasqQri-tUt3KG9WVx7J3ZrcDyfEGGlM5pzLTFV8,2451
2
+ install_texlive/__main__.py,sha256=X9XdbhqaimEvi-Dz6TiWuRdah8Y6Krotk5Z9ai5j0o0,4820
3
+ install_texlive/_version.py,sha256=IKAQ4gPrCQ2FWMXOFRqouULC2EQI1zCb4iXHsnfbmTQ,411
4
+ install_texlive/parser.py,sha256=6OZ_4O31u2kUAyNVe88oDNEC25zsLLFExdGzz5qWd94,1867
5
+ install_texlive-0.3.6.dist-info/LICENSE,sha256=MIkG_hnxh9RQYWgUERVBckmpXcsoW7SHCEk6ot9iV1g,1084
6
+ install_texlive-0.3.6.dist-info/METADATA,sha256=Cmqjp3QOicOzcNSwM_2Qx0bPEseIcTk9CWnLSyLekhg,3281
7
+ install_texlive-0.3.6.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
8
+ install_texlive-0.3.6.dist-info/entry_points.txt,sha256=P82eQ6iVKuEJ4BFMe5JFm4m7yXL36iE1wHgOLhoAmQ4,66
9
+ install_texlive-0.3.6.dist-info/top_level.txt,sha256=VF-eECw7YjwN94dkuMuVjgPnNnp9PCwIOVImOVCTUzc,16
10
+ install_texlive-0.3.6.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.43.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ install_texlive = install_texlive.__main__:main
@@ -0,0 +1 @@
1
+ install_texlive