Skip to content

Commit 9402ea5

Browse files
authored
Merge pull request #477 from jcwinkler/improved_setup
Improved setup
2 parents 5f44a14 + d1ac598 commit 9402ea5

File tree

4 files changed

+283
-539
lines changed

4 files changed

+283
-539
lines changed

docs/source/install/advanced.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,13 @@ options to adapt the installation process to your system configuration:
3838
--typst-executable TYPST_EXECUTABLE
3939
Full path to typst executable.
4040

41+
--use-tk
42+
Use the Tk Interface (tkinter) for the user interface instead of the GTK3 UI.
43+
This might be useful in cases where the GTK3 installation is broken, i.e.
44+
when loading of the framework works but execution errors occur. In that case
45+
TexText will not fall back to tkinter automatically. Hence, this switch can
46+
be used to bypass the GTK3 framework.
47+
4148
--portable-apps-dir INSTALLATION_DIRECTORY_OF_PORTABLEAPPS
4249
Windows only: If you use Inkscape from PortableApps use this parameter
4350
to specifiy the directory into which PortableApps has been installed, e.g.
@@ -58,7 +65,8 @@ options to adapt the installation process to your system configuration:
5865
Don't install extension (just check the requirements).
5966

6067
--keep-previous-installation-files
61-
Keep/discard files from previous installation, suppress prompt.
68+
Keep files from previous installation which might have been modified
69+
by the user (e.g. preamble files) without prompting the user
6270

6371
--all-users
6472
Install globally for all users (sudo/ admin privileges required)
@@ -71,3 +79,6 @@ options to adapt the installation process to your system configuration:
7179

7280
--color always, --color never
7381
Enables/disable console colors.
82+
83+
--verbose
84+
Print additional messages during setup

setup.py

Lines changed: 70 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
set_logging_levels, \
2525
TexTextRequirementsChecker, \
2626
defaults, \
27-
LoggingColors, \
27+
TexTextLogFormatter, \
2828
SUCCESS
2929

3030
from textext.utility import Settings, Cache
@@ -60,10 +60,7 @@ def query_yes_no(question, default="yes"):
6060
prompt = " [y/N] "
6161
else:
6262
raise ValueError("invalid default answer: '%s'" % default)
63-
if sys.version_info[0] > 2:
64-
read_input = input
65-
else:
66-
read_input = raw_input
63+
read_input = input
6764
while True:
6865
sys.stdout.write(question + prompt)
6966
choice = read_input().lower()
@@ -108,9 +105,9 @@ def __enter__(self):
108105
dst = os.path.join(self.tmp_dir, old_name)
109106
if os.path.isfile(src):
110107
if not os.path.isdir(os.path.dirname(dst)):
111-
logger.info("Creating directory `%s`" % os.path.dirname(dst) )
108+
logger.debug("Creating directory `%s`" % os.path.dirname(dst) )
112109
os.makedirs(os.path.dirname(dst))
113-
logger.info("Stashing `%s`" % dst)
110+
logger.debug("Stashing `%s`" % dst)
114111
shutil.copy2(src, dst)
115112

116113
def __exit__(self, exc_type, exc_val, exc_tb):
@@ -119,9 +116,9 @@ def __exit__(self, exc_type, exc_val, exc_tb):
119116
dst = os.path.join(self.unstash_to, new_name)
120117
if os.path.isfile(src):
121118
if not os.path.isdir(os.path.dirname(dst)):
122-
logger.info("Creating directory `%s`" % os.path.dirname(dst) )
119+
logger.debug("Creating directory `%s`" % os.path.dirname(dst) )
123120
os.makedirs(os.path.dirname(dst))
124-
logger.info("Restoring old `%s` -> `%s`" % (old_name, dst))
121+
logger.debug("Restoring old `%s` -> `%s`" % (old_name, dst))
125122
shutil.copy2(src, dst)
126123

127124

@@ -159,7 +156,7 @@ def copy_extension_files(src, dst, if_already_exists="raise"):
159156
logger.critical("Can't copy files to `%s`: it's not a directory")
160157
raise CopyFileOverDirectoryError("Can't copy files to `%s`: it's not a directory")
161158
else:
162-
logger.info("Creating directory `%s`" % dst)
159+
logger.debug("Creating directory `%s`" % dst)
163160
os.makedirs(dst)
164161

165162
for file in glob.glob(src):
@@ -174,17 +171,17 @@ def copy_extension_files(src, dst, if_already_exists="raise"):
174171
logger.critical("Can't copy `%s`: `%s` already exists" % (file, destination))
175172
raise CopyFileAlreadyExistsError("Can't copy `%s`: `%s` already exists" % (file, destination))
176173
elif if_already_exists == "skip":
177-
logger.info("Skipping `%s`" % file)
174+
logger.debug("Skipping `%s`" % file)
178175
continue
179176
elif if_already_exists == "overwrite":
180-
logger.info("Overwriting `%s`" % destination)
177+
logger.debug("Overwriting `%s`" % destination)
181178
pass
182179

183180
if os.path.isfile(file):
184-
logger.info("Copying `%s` to `%s`" % (file, destination))
181+
logger.debug(f"Copying '{file}' to '{destination}'")
185182
shutil.copy(file, destination)
186183
else:
187-
logger.info("Creating directory `%s`" % destination)
184+
logger.debug("Creating directory '{destination}'")
188185

189186
if os.path.exists(destination):
190187
if not os.path.isdir(destination):
@@ -199,10 +196,10 @@ def copy_extension_files(src, dst, if_already_exists="raise"):
199196

200197
def remove_previous_installation(extension_dir):
201198
previous_installation_files_and_folders = [
202-
"asktext.py",
199+
"textext", # <- Whole textext directory (more recent versions of TexText)
200+
"asktext.py", # <- Files directly in the extension directory (old versions of TexText)
203201
"default_packages.tex",
204202
"latexlogparser.py",
205-
"textext",
206203
"textext.inx",
207204
"textext.py",
208205
"typesetter.py",
@@ -211,10 +208,10 @@ def remove_previous_installation(extension_dir):
211208
for file_or_dir in previous_installation_files_and_folders:
212209
file_or_dir = os.path.abspath(os.path.join(extension_dir, file_or_dir))
213210
if os.path.isfile(file_or_dir) or os.path.islink(file_or_dir):
214-
logger.info("Removing `%s`" % file_or_dir)
211+
logger.debug("Removing `%s`" % file_or_dir)
215212
os.remove(file_or_dir)
216213
elif os.path.isdir(file_or_dir):
217-
logger.info("Removing `%s`" % file_or_dir)
214+
logger.debug("Removing `%s`" % file_or_dir)
218215
shutil.rmtree(file_or_dir)
219216
else:
220217
logger.debug("`%s` is not found" % file_or_dir)
@@ -223,15 +220,14 @@ def remove_previous_installation(extension_dir):
223220
if __name__ == "__main__":
224221

225222
EXIT_SUCCESS = 0
226-
EXIT_REQUIREMENT_CHECK_UNKNOWN = 64
227223
EXIT_REQUIREMENT_CHECK_FAILED = 65
228224
EXIT_BAD_COMMAND_LINE_ARGUMENT_VALUE = 2
229225

230226
parser = argparse.ArgumentParser(description='Install TexText')
231227

232228
parser.add_argument(
233229
"--inkscape-extensions-path",
234-
default=defaults.inkscape_user_extensions_path,
230+
default=None,
235231
type=str,
236232
help="Path to inkscape extensions directory"
237233
)
@@ -285,6 +281,13 @@ def remove_previous_installation(extension_dir):
285281
help="Bypass minimal requirements check"
286282
)
287283

284+
parser.add_argument(
285+
"--use-tk",
286+
default=False,
287+
action='store_true',
288+
help="Use the Tk Interface (tkinter) for the user interface instead of the GTK3 UI"
289+
)
290+
288291
parser.add_argument(
289292
"--skip-extension-install",
290293
default=False,
@@ -296,7 +299,8 @@ def remove_previous_installation(extension_dir):
296299
"--keep-previous-installation-files",
297300
default=None,
298301
action='store_true',
299-
help="Keep/discard files from previous installation, suppress prompt"
302+
help="Keep files from previous installation which maybe modified by the user "
303+
"(e.g. preamble files) without prompting the user"
300304
)
301305

302306
parser.add_argument(
@@ -313,34 +317,51 @@ def remove_previous_installation(extension_dir):
313317
help="Enables/disable console colors"
314318
)
315319

320+
parser.add_argument(
321+
"--verbose",
322+
default=False,
323+
action="store_true",
324+
help="Print additional messages during setup"
325+
)
326+
327+
# Files which maybe modified by the user and which, be default, should
328+
# be kept upon user request
316329
files_to_keep = { # old_name : new_name
317330
"default_packages.tex": "textext/default_packages.tex", # old layout
318-
"textext/default_packages.tex": "textext/default_packages.tex"
331+
"textext/default_packages.tex": "textext/default_packages.tex",
332+
"textext/default_preamble_typst.typ": "textext/default_preamble_typst.typ"
319333
}
320334

321335
args = parser.parse_args()
322336

337+
if args.inkscape_extensions_path is None:
338+
args.inkscape_extensions_path = defaults.inkscape_user_extensions_path
339+
323340
if args.color == "always":
324-
LoggingColors.enable_colors = True
341+
TexTextLogFormatter.enable_colors = True
325342
elif args.color == "never":
326-
LoggingColors.enable_colors = False
343+
TexTextLogFormatter.enable_colors = False
327344

328345
set_logging_levels()
329346
logger = logging.getLogger('TexText')
330347
logger.setLevel(logging.DEBUG)
331348
ch = logging.StreamHandler()
332-
ch.setLevel(logging.INFO)
333-
formatter = logging.Formatter('[%(name)s][%(levelname)6s]: %(message)s')
334-
ch.setFormatter(formatter)
349+
ch.setLevel(logging.INFO if not args.verbose else logging.DEBUG)
350+
ch_formatter = TexTextLogFormatter("%(message)s")
351+
ch.setFormatter(ch_formatter)
335352
logger.addHandler(ch)
336353

337354
# Explicit path spec since on Windows working directory must be the python.exe directory
338355
# which is usually read-only for standard users
339-
fh = logging.FileHandler(os.path.join(os.path.dirname(__file__), "textextsetup.log"))
340-
fh.setLevel(ch.level)
341-
fh.setFormatter(formatter)
356+
fh = logging.FileHandler(os.path.join(os.path.dirname(__file__), "textextsetup.log"), mode="w")
357+
fh.setLevel(logging.DEBUG)
358+
fh_formatter = logging.Formatter("[%(name)s][%(levelname)6s]: %(message)s")
359+
fh.setFormatter(fh_formatter)
342360
logger.addHandler(fh)
343361

362+
logger.info("Installing TexText with the following arguments:")
363+
logger.info("".join(f"{key}: {value}, " for key, value in vars(args).items())[:-2])
364+
344365
# Address special Portable Apps directory structure
345366
if args.portable_apps_dir:
346367
if not os.path.isdir(args.portable_apps_dir):
@@ -362,13 +383,7 @@ def remove_previous_installation(extension_dir):
362383

363384
checker = TexTextRequirementsChecker(logger, settings)
364385

365-
for executable_name in [
366-
"inkscape",
367-
"lualatex",
368-
"pdflatex",
369-
"xelatex",
370-
"typst",
371-
]:
386+
for executable_name in ["inkscape", "lualatex", "pdflatex", "xelatex", "typst"]:
372387
executable_path = getattr(args, "%s_executable" % executable_name)
373388
if executable_path is not None:
374389
if not checker.check_executable(executable_path):
@@ -382,16 +397,12 @@ def remove_previous_installation(extension_dir):
382397
if not args.skip_requirements_check:
383398

384399
check_result = checker.check()
385-
if check_result == None:
386-
logger.error("Automatic requirements check is incomplete")
387-
logger.error("Please check requirements list manually and run:")
388-
logger.error(" ".join(sys.argv + ["--skip-requirements-check"]))
389-
exit(EXIT_REQUIREMENT_CHECK_UNKNOWN)
390-
391-
if check_result == False:
400+
if not check_result:
392401
logger.error("Automatic requirements check found issue")
393402
logger.error("Follow instruction above and run install script again")
394-
logger.error("To bypass requirement check pass `--skip-requirements-check` to setup.py")
403+
logger.error("--> To bypass requirement check and force installation of TexText")
404+
logger.error("--> pass the `--skip-requirements-check` option to setup.py:")
405+
logger.error("--> setup.py --skip-requirements-check")
395406
exit(EXIT_REQUIREMENT_CHECK_FAILED)
396407

397408
if not args.skip_extension_install:
@@ -441,14 +452,15 @@ def remove_previous_installation(extension_dir):
441452
args.inkscape_extensions_path = os.path.expanduser(args.inkscape_extensions_path)
442453

443454
if args.keep_previous_installation_files is None:
455+
logger.debug("Checking for previous installation files which have been modified by the user")
444456
found_files_to_keep = {}
445457
for old_filename, new_filename in files_to_keep.items():
446458
if not os.path.isfile(os.path.join(args.inkscape_extensions_path, old_filename)):
447459
logger.debug("%s not found" % old_filename)
448460
else:
449461
logger.debug("%s found" % old_filename)
450462
if not os.path.isfile(os.path.join("extension", new_filename)):
451-
logger.info("`%s` is not found in distribution, keep old file" % new_filename)
463+
logger.debug("`%s` is not found in distribution, keep old file" % new_filename)
452464
found_files_to_keep[old_filename] = new_filename
453465
continue
454466
with open(os.path.join(args.inkscape_extensions_path, old_filename)) as f_old, \
@@ -465,7 +477,7 @@ def remove_previous_installation(extension_dir):
465477
file_s = "file" if len(found_files_to_keep) == 1 else "files"
466478
for old_filename, new_filename in found_files_to_keep.items():
467479
if os.path.isfile(os.path.join("extension", new_filename)):
468-
logger.warn("Existing `%s` differs from newer version in distribution" % old_filename)
480+
logger.warning("Existing `%s` differs from newer version in distribution" % old_filename)
469481
if query_yes_no("Keep `%s` from previous installation?" % old_filename):
470482
files_to_keep[old_filename] = new_filename
471483

@@ -481,6 +493,7 @@ def remove_previous_installation(extension_dir):
481493
rel_filenames=files_to_keep,
482494
tmp_dir=tmp_dir
483495
):
496+
logger.info(f"Starting installation of TexText into {args.inkscape_extensions_path}...")
484497
source_path = os.path.dirname(os.path.abspath(__file__))
485498
if os.path.dirname(source_path) == args.inkscape_extensions_path:
486499
logger.error("Can't install extension from itself")
@@ -491,6 +504,16 @@ def remove_previous_installation(extension_dir):
491504
dst=args.inkscape_extensions_path,
492505
if_already_exists="overwrite"
493506
)
507+
508+
if args.use_tk:
509+
logger.info("Force usage of Tk Interface (tkinter), setting 'gui_toolkit' to 'tk'")
510+
settings["gui"]["toolkit"] = "tk"
511+
else:
512+
try:
513+
del(settings["gui"]["toolkit"])
514+
except (KeyError, TypeError) as _:
515+
pass
516+
494517
settings.save()
495518

496519
logger.log(SUCCESS, "--> TexText has been SUCCESSFULLY installed on your system <--")

test_installation_script.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ def __call__(self, name, output="", channel='stdout'):
4747
command_name = os.path.join(self.dirname, name)
4848
with open(command_name, "w") as fout:
4949
fout.write("#!%s\n" % sys.executable)
50-
fout.write("from __future__ import print_function\n")
5150
fout.write("import sys\n")
52-
fout.write("print(%s, file=sys.%s)" % (repr(output), channel))
51+
fout.write(f"print({repr(output)}, file=sys.{channel})")
5352
os.chmod(command_name, 0o755)
5453

5554

@@ -71,15 +70,18 @@ def test_configuration(fake_commands, expected_exit_code):
7170

7271

7372
REQUIREMENT_CHECK_SUCCESS = 0
74-
REQUIREMENT_CHECK_UNKNOWN = 64
7573
REQUIREMENT_CHECK_ERROR = 65
7674

7775
good_configurations = []
7876

79-
# Definition of working combinations of Inkscape and LaTeX
80-
for latex in [("pdflatex",), ("lualatex",), ("xelatex",)]:
77+
# Definition of working combinations of Inkscape (without release number) and LaTeX
78+
for latex in [("pdflatex",), ("lualatex",), ("xelatex",), ("typst",)]:
8179
good_configurations.append([("inkscape", "Inkscape 1.4 (1:1.4+202410161351+e7c3feb100)"), latex])
8280

81+
# Definition of working combinations of Inkscape (with release number) and LaTeX
82+
for latex in [("pdflatex",), ("lualatex",), ("xelatex",), ("typst",)]:
83+
good_configurations.append([("inkscape", "Inkscape 1.4.2 (1:1.4.2+202505120737+ebf0e940d0)"), latex])
84+
8385
# Test: Installation of working combinations must succeed
8486
for good_configuration in good_configurations:
8587
test_configuration(good_configuration, REQUIREMENT_CHECK_SUCCESS)
@@ -98,6 +100,11 @@ def test_configuration(fake_commands, expected_exit_code):
98100
("inkscape", "Inkscape 0.92.3 (2405546, 2018-03-11)"),
99101
], REQUIREMENT_CHECK_ERROR)
100102

103+
# Test wrong Inkscape version and no pdflatex installed
104+
test_configuration([
105+
("inkscape", "Inkscape 1.3.2 (1:1.4+202410161351+e7c3feb100)"),
106+
], REQUIREMENT_CHECK_ERROR)
107+
101108
# Test wrong Inkscape version and pdflatex installed
102109
test_configuration([
103110
("inkscape", "Inkscape 0.92.3 (2405546, 2018-03-11)"),
@@ -109,7 +116,7 @@ def test_configuration(fake_commands, expected_exit_code):
109116
test_configuration([
110117
("inkscape",),
111118
("pdflatex",),
112-
], REQUIREMENT_CHECK_UNKNOWN)
119+
], REQUIREMENT_CHECK_ERROR)
113120

114121
# Test: Nothing is installed -> Installation must fail
115122
test_configuration([

0 commit comments

Comments
 (0)