2 # -*- coding: utf-8 -*-
5 # This file is part of LyX, the document processor.
6 # Licence details can be found in the file COPYING.
9 # Full author contact details are available in file CREDITS.
11 import sys, os, re, shutil, glob, logging
14 logging.basicConfig(level = logging.DEBUG,
15 format = '%(levelname)s: %(message)s', # ignore application name
16 filename = 'configure.log',
19 # Add a handler to log to console
20 console = logging.StreamHandler()
21 console.setLevel(logging.INFO) # the console only print out general information
22 formatter = logging.Formatter('%(message)s') # only print out the message itself
23 console.setFormatter(formatter)
24 logger = logging.getLogger('LyX')
25 logger.addHandler(console)
27 def writeToFile(filename, lines, append = False):
28 " utility function: write or append lines to filename "
30 file = open(filename, 'a')
32 file = open(filename, 'w')
38 ''' utility function: shortcut for appending lines to outfile
39 add newline at the end of lines.
41 if lines.strip() != '':
42 writeToFile(outfile, lines + '\n', append = True)
43 logger.debug('Add to RC:\n' + lines + '\n\n')
46 def removeFiles(filenames):
47 '''utility function: 'rm -f'
48 ignore errors when file does not exist, or is a directory.
50 for file in filenames:
53 logger.debug('Removing file %s' % file)
55 logger.debug('Failed to remove file %s' % file)
60 '''utility function: run a command and get its output as a string
70 ''' I do not really know why this is useful, but we might as well keep it.
72 Only set these to C if already set. These must not be set unconditionally
73 because not all systems understand e.g. LANG=C (notably SCO).
74 Fixing LC_MESSAGES prevents Solaris sh from translating var values in set!
75 Non-C LC_CTYPE values break the ctype check.
77 os.environ['LANG'] = os.getenv('LANG', 'C')
78 os.environ['LC'] = os.getenv('LC_ALL', 'C')
79 os.environ['LC_MESSAGE'] = os.getenv('LC_MESSAGE', 'C')
80 os.environ['LC_CTYPE'] = os.getenv('LC_CTYPE', 'C')
83 def createDirectories():
84 ''' Create the build directories if necessary '''
85 for dir in ['bind', 'clipart', 'doc', 'examples', 'images', 'kbd', \
86 'layouts', 'scripts', 'templates', 'ui' ]:
87 if not os.path.isdir( dir ):
90 logger.debug('Create directory %s.' % dir)
92 logger.error('Failed to create directory %s.' % dir)
97 ''' Determine the path-style needed by the TeX engine on Win32 (Cygwin) '''
98 windows_style_tex_paths = ''
100 return windows_style_tex_paths
101 if os.name == 'nt' or sys.platform == 'cygwin':
102 from tempfile import mkstemp
103 fd, tmpfname = mkstemp(suffix='.ltx')
105 inpname = tmpfname.replace('\\', '/')
107 inpname = cmdOutput('cygpath -m ' + tmpfname)
108 logname = os.path.basename(inpname.replace('.ltx', '.log'))
109 inpname = inpname.replace('~', '\\string~')
110 os.write(fd, r'\relax')
112 latex_out = cmdOutput(r'latex "\nonstopmode\input{%s}"' % inpname)
113 if 'Error' in latex_out:
114 logger.warning("configure: TeX engine needs posix-style paths in latex files")
115 windows_style_tex_paths = 'false'
117 logger.info("configure: TeX engine needs windows-style paths in latex files")
118 windows_style_tex_paths = 'true'
119 removeFiles([tmpfname, logname, 'texput.log'])
120 return windows_style_tex_paths
123 ## Searching some useful programs
124 def checkProg(description, progs, rc_entry = [], path = [], not_found = ''):
126 This function will search a program in $PATH plus given path
127 If found, return directory and program name (not the options).
129 description: description of the program
131 progs: check programs, for each prog, the first word is used
132 for searching but the whole string is used to replace
133 %% for a rc_entry. So, feel free to add '$$i' etc for programs.
135 path: additional pathes
137 rc_entry: entry to outfile, can be
138 1. emtpy: no rc entry will be added
139 2. one pattern: %% will be replaced by the first found program,
140 or '' if no program is found.
141 3. several patterns for each prog and not_found. This is used
142 when different programs have different usages. If you do not
143 want not_found entry to be added to the RC file, you can specify
144 an entry for each prog and use '' for the not_found entry.
146 not_found: the value that should be used instead of '' if no program
150 # one rc entry for each progs plus not_found entry
151 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
152 logger.error("rc entry should have one item or item for each prog and not_found.")
154 logger.info('checking for ' + description + '...')
155 ## print '(' + ','.join(progs) + ')',
156 for idx in range(len(progs)):
157 # ac_prog may have options, ac_word is the command name
159 ac_word = ac_prog.split(' ')[0]
160 msg = '+checking for "' + ac_word + '"... '
161 path = os.environ["PATH"].split(os.pathsep) + path
163 if "PATHEXT" in os.environ:
164 extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
167 if os.path.isfile( os.path.join(ac_dir, ac_word + ext) ):
168 logger.info(msg + ' yes')
169 # write rc entries for this command
170 if len(rc_entry) == 1:
171 addToRC(rc_entry[0].replace('%%', ac_prog))
172 elif len(rc_entry) > 1:
173 addToRC(rc_entry[idx].replace('%%', ac_prog))
174 return [ac_dir, ac_word]
176 logger.info(msg + ' no')
177 # write rc entries for 'not found'
178 if len(rc_entry) > 0: # the last one.
179 addToRC(rc_entry[-1].replace('%%', not_found))
180 return ['', not_found]
183 def checkProgAlternatives(description, progs, rc_entry = [], alt_rc_entry = [], path = [], not_found = ''):
185 The same as checkProg, but additionally, all found programs will be added
188 # one rc entry for each progs plus not_found entry
189 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
190 logger.error("rc entry should have one item or item for each prog and not_found.")
192 logger.info('checking for ' + description + '...')
193 ## print '(' + ','.join(progs) + ')',
196 real_ac_word = not_found
197 for idx in range(len(progs)):
198 # ac_prog may have options, ac_word is the command name
200 ac_word = ac_prog.split(' ')[0]
201 msg = '+checking for "' + ac_word + '"... '
202 path = os.environ["PATH"].split(os.pathsep) + path
204 if "PATHEXT" in os.environ:
205 extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
209 if os.path.isfile( os.path.join(ac_dir, ac_word + ext) ):
210 logger.info(msg + ' yes')
211 pr = re.compile(r'(\\\S+)(.*)$')
213 # write rc entries for this command
214 if found_prime == False:
215 if len(rc_entry) == 1:
216 addToRC(rc_entry[0].replace('%%', ac_prog))
217 elif len(rc_entry) > 1:
218 addToRC(rc_entry[idx].replace('%%', ac_prog))
220 real_ac_word = ac_word
222 if len(alt_rc_entry) == 1:
223 alt_rc = alt_rc_entry[0]
225 # if no explicit alt_rc is given, construct one
226 m = pr.match(rc_entry[0])
228 alt_rc = m.group(1) + "_alternatives" + m.group(2)
229 addToRC(alt_rc.replace('%%', ac_prog))
230 elif len(alt_rc_entry) > 1:
231 alt_rc = alt_rc_entry[idx]
233 # if no explicit alt_rc is given, construct one
234 m = pr.match(rc_entry[idx])
236 alt_rc = m.group(1) + "_alternatives" + m.group(2)
237 addToRC(alt_rc.replace('%%', ac_prog))
242 if found_alt == False:
244 logger.info(msg + ' no')
246 return [real_ac_dir, real_ac_word]
247 # write rc entries for 'not found'
248 if len(rc_entry) > 0: # the last one.
249 addToRC(rc_entry[-1].replace('%%', not_found))
250 return ['', not_found]
253 def addViewerAlternatives(rcs):
254 r = re.compile(r'\\Format (\S+).*$')
257 for idxx in range(len(rcs)):
261 alt = r'\viewer_alternatives ' + m.group(1) + " %%"
263 m = r.match(rcs[idxx])
267 alt += r'\viewer_alternatives ' + m.group(1) + " %%"
271 def addEditorAlternatives(rcs):
272 r = re.compile(r'\\Format (\S+).*$')
275 for idxx in range(len(rcs)):
279 alt = r'\editor_alternatives ' + m.group(1) + " %%"
281 m = r.match(rcs[idxx])
285 alt += r'\editor_alternatives ' + m.group(1) + " %%"
289 def checkViewer(description, progs, rc_entry = [], path = []):
290 ''' The same as checkProgAlternatives, but for viewers '''
291 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
292 logger.error("rc entry should have one item or item for each prog and not_found.")
295 for idx in range(len(progs)):
296 if len(rc_entry) == 1:
297 rcs = rc_entry[0].split('\n')
298 alt = addViewerAlternatives(rcs)
299 alt_rc_entry.insert(0, alt)
300 elif len(rc_entry) > 1:
301 rcs = rc_entry[idx].split('\n')
302 alt = addViewerAlternatives(rcs)
303 alt_rc_entry.insert(idx, alt)
304 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
307 def checkEditor(description, progs, rc_entry = [], path = []):
308 ''' The same as checkProgAlternatives, but for editors '''
309 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
310 logger.error("rc entry should have one item or item for each prog and not_found.")
313 for idx in range(len(progs)):
314 if len(rc_entry) == 1:
315 rcs = rc_entry[0].split('\n')
316 alt = addEditorAlternatives(rcs)
317 alt_rc_entry.insert(0, alt)
318 elif len(rc_entry) > 1:
319 rcs = rc_entry[idx].split('\n')
320 alt = addEditorAlternatives(rcs)
321 alt_rc_entry.insert(idx, alt)
322 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
325 def checkViewerNoRC(description, progs, rc_entry = [], path = []):
326 ''' The same as checkViewer, but do not add rc entry '''
327 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
328 logger.error("rc entry should have one item or item for each prog and not_found.")
331 for idx in range(len(progs)):
332 if len(rc_entry) == 1:
333 rcs = rc_entry[0].split('\n')
334 alt = addViewerAlternatives(rcs)
335 alt_rc_entry.insert(0, alt)
336 elif len(rc_entry) > 1:
337 rcs = rc_entry[idx].split('\n')
338 alt = addViewerAlternatives(rcs)
339 alt_rc_entry.insert(idx, alt)
341 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
344 def checkEditorNoRC(description, progs, rc_entry = [], path = []):
345 ''' The same as checkViewer, but do not add rc entry '''
346 if len(rc_entry) > 1 and len(rc_entry) != len(progs) + 1:
347 logger.error("rc entry should have one item or item for each prog and not_found.")
350 for idx in range(len(progs)):
351 if len(rc_entry) == 1:
352 rcs = rc_entry[0].split('\n')
353 alt = addEditorAlternatives(rcs)
354 alt_rc_entry.insert(0, alt)
355 elif len(rc_entry) > 1:
356 rcs = rc_entry[idx].split('\n')
357 alt = addEditorAlternatives(rcs)
358 alt_rc_entry.insert(idx, alt)
360 return checkProgAlternatives(description, progs, rc_entry, alt_rc_entry, path, not_found = 'auto')
363 def checkViewerEditor(description, progs, rc_entry = [], path = []):
364 ''' The same as checkProgAlternatives, but for viewers and editors '''
365 checkEditorNoRC(description, progs, rc_entry, path)
366 return checkViewer(description, progs, rc_entry, path)
370 ''' Check whether DTL tools are available (Windows only) '''
371 # Find programs! Returned path is not used now
372 if ((os.name == 'nt' or sys.platform == 'cygwin') and
373 checkProg('DVI to DTL converter', ['dv2dt']) != ['', ''] and
374 checkProg('DTL to DVI converter', ['dt2dv']) != ['', '']):
381 def checkLatex(dtl_tools):
382 ''' Check latex, return lyx_check_config '''
383 path, LATEX = checkProg('a Latex2e program', ['latex $$i', 'latex2e $$i'])
384 path, PPLATEX = checkProg('a DVI postprocessing program', ['pplatex $$i'])
385 #-----------------------------------------------------------------
386 path, PLATEX = checkProg('pLaTeX, the Japanese LaTeX', ['platex $$i'])
388 # check if PLATEX is pLaTeX2e
389 writeToFile('chklatex.ltx', '''
393 # run platex on chklatex.ltx and check result
394 if cmdOutput(PLATEX + ' chklatex.ltx').find('pLaTeX2e') != -1:
395 # We have the Japanese pLaTeX2e
396 addToRC(r'\converter platex dvi "%s" "latex=platex"' % PLATEX)
399 removeFiles(['chklatex.ltx', 'chklatex.log'])
400 #-----------------------------------------------------------------
401 # use LATEX to convert from latex to dvi if PPLATEX is not available
405 # Windows only: DraftDVI
406 addToRC(r'''\converter latex dvi2 "%s" "latex"
407 \converter dvi2 dvi "python -tt $$s/scripts/clean_dvi.py $$i $$o" ""''' % PPLATEX)
409 addToRC(r'\converter latex dvi "%s" "latex"' % PPLATEX)
412 # Check if latex is usable
413 writeToFile('chklatex.ltx', '''
414 \\nonstopmode\\makeatletter
415 \\ifx\\undefined\\documentclass\\else
416 \\message{ThisIsLaTeX2e}
420 # run latex on chklatex.ltx and check result
421 if cmdOutput(LATEX + ' chklatex.ltx').find('ThisIsLaTeX2e') != -1:
425 logger.warning("Latex not usable (not LaTeX2e) ")
426 # remove temporary files
427 removeFiles(['chklatex.ltx', 'chklatex.log'])
432 ''' Check if luatex is there and usable '''
433 path, LUATEX = checkProg('LuaTeX', ['lualatex $$i'])
434 path, DVILUATEX = checkProg('LuaTeX (DVI)', ['dvilualatex $$i'])
436 # luatex binary is there
437 msg = "checking if LuaTeX is usable ..."
438 # Check if luatex is usable
439 writeToFile('luatest.tex', '''
440 \\nonstopmode\\documentclass{minimal}
441 \\usepackage{fontspec}
446 # run lualatex on luatest.tex and check result
447 luatest = cmdOutput(LUATEX + ' luatest.tex')
448 if luatest.find('XeTeX is required to compile this document') != -1:
449 # fontspec/luatex too old! We do not support this version.
450 logger.info(msg + ' no (probably not recent enough)')
451 elif luatest.find('! LaTeX Error: File `fontspec.sty\' not found') != -1:
453 logger.info(msg + ' no (missing fontspec)')
456 logger.info(msg + ' yes')
457 addToRC(r'\converter luatex pdf5 "%s" "latex=lualatex"' % LUATEX)
459 addToRC(r'\converter luatex dvi3 "%s" "latex=lualatex"' % DVILUATEX)
460 # remove temporary files
461 removeFiles(['luatest.tex', 'luatest.log', 'luatest.aux', 'luatest.pdf'])
464 def checkModule(module):
465 ''' Check for a Python module, return the status '''
466 msg = 'checking for "' + module + ' module"... '
469 logger.info(msg + ' yes')
472 logger.info(msg + ' no')
476 def checkFormatEntries(dtl_tools):
477 ''' Check all formats (\Format entries) '''
478 checkViewerEditor('a Tgif viewer and editor', ['tgif'],
479 rc_entry = [r'\Format tgif obj Tgif "" "%%" "%%" "vector"'])
481 checkViewerEditor('a FIG viewer and editor', ['xfig', 'jfig3-itext.jar', 'jfig3.jar'],
482 rc_entry = [r'\Format fig fig FIG "" "%%" "%%" "vector"'])
484 checkViewerEditor('a Dia viewer and editor', ['dia'],
485 rc_entry = [r'\Format dia dia DIA "" "%%" "%%" "vector"'])
487 checkViewerEditor('a Grace viewer and editor', ['xmgrace'],
488 rc_entry = [r'\Format agr agr Grace "" "%%" "%%" "vector"'])
490 checkViewerEditor('a FEN viewer and editor', ['xboard -lpf $$i -mode EditPosition'],
491 rc_entry = [r'\Format fen fen FEN "" "%%" "%%" ""'])
493 checkViewerEditor('a SVG viewer and editor', ['inkscape'],
494 rc_entry = [r'\Format svg svg SVG "" "%%" "%%" "vector"'])
496 path, iv = checkViewerNoRC('a raster image viewer', ['xv', 'kview', 'gimp-remote', 'gimp'],
497 rc_entry = [r'''\Format bmp bmp BMP "" "%s" "%s" ""
498 \Format gif gif GIF "" "%s" "%s" ""
499 \Format jpg jpg JPEG "" "%s" "%s" ""
500 \Format pbm pbm PBM "" "%s" "%s" ""
501 \Format pgm pgm PGM "" "%s" "%s" ""
502 \Format png png PNG "" "%s" "%s" ""
503 \Format ppm ppm PPM "" "%s" "%s" ""
504 \Format tiff tif TIFF "" "%s" "%s" ""
505 \Format xbm xbm XBM "" "%s" "%s" ""
506 \Format xpm xpm XPM "" "%s" "%s" ""'''])
507 path, ie = checkEditorNoRC('a raster image editor', ['gimp-remote', 'gimp'],
508 rc_entry = [r'''\Format bmp bmp BMP "" "%s" "%s" ""
509 \Format gif gif GIF "" "%s" "%s" ""
510 \Format jpg jpg JPEG "" "%s" "%s" ""
511 \Format pbm pbm PBM "" "%s" "%s" ""
512 \Format pgm pgm PGM "" "%s" "%s" ""
513 \Format png png PNG "" "%s" "%s" ""
514 \Format ppm ppm PPM "" "%s" "%s" ""
515 \Format tiff tif TIFF "" "%s" "%s" ""
516 \Format xbm xbm XBM "" "%s" "%s" ""
517 \Format xpm xpm XPM "" "%s" "%s" ""'''])
518 addToRC(r'''\Format bmp bmp BMP "" "%s" "%s" ""
519 \Format gif gif GIF "" "%s" "%s" ""
520 \Format jpg jpg JPEG "" "%s" "%s" ""
521 \Format pbm pbm PBM "" "%s" "%s" ""
522 \Format pgm pgm PGM "" "%s" "%s" ""
523 \Format png png PNG "" "%s" "%s" ""
524 \Format ppm ppm PPM "" "%s" "%s" ""
525 \Format tiff tif TIFF "" "%s" "%s" ""
526 \Format xbm xbm XBM "" "%s" "%s" ""
527 \Format xpm xpm XPM "" "%s" "%s" ""''' % \
528 (iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie, iv, ie) )
530 checkViewerEditor('a text editor', ['xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
531 'nedit', 'gedit', 'notepad'],
532 rc_entry = [r'''\Format asciichess asc "Plain text (chess output)" "" "" "%%" ""
533 \Format asciiimage asc "Plain text (image)" "" "" "%%" ""
534 \Format asciixfig asc "Plain text (Xfig output)" "" "" "%%" ""
535 \Format dateout tmp "date (output)" "" "" "%%" ""
536 \Format docbook sgml DocBook B "" "%%" "document,menu=export"
537 \Format docbook-xml xml "Docbook (XML)" "" "" "%%" "document,menu=export"
538 \Format dot dot "Graphviz Dot" "" "" "%%" "vector"
539 \Format platex tex "LaTeX (pLaTeX)" "" "" "%%" "document,menu=export"
540 \Format literate nw NoWeb N "" "%%" "document,menu=export"
541 \Format sweave Rnw "Sweave" S "" "%%" "document,menu=export"
542 \Format lilypond ly "LilyPond music" "" "" "%%" "vector"
543 \Format lilypond-book lytex "LilyPond book (LaTeX)" "" "" "%%" "document,menu=export"
544 \Format latex tex "LaTeX (plain)" L "" "%%" "document,menu=export"
545 \Format luatex tex "LaTeX (LuaTeX)" "" "" "%%" "document,menu=export"
546 \Format pdflatex tex "LaTeX (pdflatex)" "" "" "%%" "document,menu=export"
547 \Format xetex tex "LaTeX (XeTeX)" "" "" "%%" "document,menu=export"
548 \Format text txt "Plain text" a "" "%%" "document,menu=export"
549 \Format text2 txt "Plain text (pstotext)" "" "" "%%" "document"
550 \Format text3 txt "Plain text (ps2ascii)" "" "" "%%" "document"
551 \Format text4 txt "Plain text (catdvi)" "" "" "%%" "document"
552 \Format textparagraph txt "Plain Text, Join Lines" "" "" "%%" "document"''' ])
553 #Spreadsheets using ssconvert from gnumeric
554 checkViewer('gnumeric spreadsheet software', ['gnumeric'],
555 rc_entry = [r'''\Format gnumeric gnumeric "Gnumeric spreadsheet" "" "" "%%" "document"
556 \Format excel xls "Excel spreadsheet" "" "" "%%" "document"
557 \Format oocalc ods "OpenOffice spreadsheet" "" "" "%%" "document"'''])
559 path, xhtmlview = checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
560 rc_entry = [r'\Format xhtml xhtml "LyXHTML" y "%%" "" "document,menu=export"'])
562 addToRC(r'\Format xhtml xhtml "LyXHTML" y "" "" "document,menu=export"')
564 checkEditor('a BibTeX editor', ['jabref', 'JabRef', \
565 'pybliographic', 'bibdesk', 'gbib', 'kbib', \
566 'kbibtex', 'sixpack', 'bibedit', 'tkbibtex' \
567 'xemacs', 'gvim', 'kedit', 'kwrite', 'kate', \
568 'nedit', 'gedit', 'notepad'],
569 rc_entry = [r'''\Format bibtex bib "BibTeX" "" "" "%%" ""''' ])
571 #checkProg('a Postscript interpreter', ['gs'],
572 # rc_entry = [ r'\ps_command "%%"' ])
573 checkViewer('a Postscript previewer', ['kghostview', 'okular', 'evince', 'gv', 'ghostview -swap'],
574 rc_entry = [r'''\Format eps eps EPS "" "%%" "" "vector"
575 \Format ps ps Postscript t "%%" "" "document,vector"'''])
576 # for xdg-open issues look here: http://www.mail-archive.com/lyx-devel@lists.lyx.org/msg151818.html
577 checkViewer('a PDF previewer', ['kpdf', 'okular', 'evince', 'kghostview', 'xpdf', 'acrobat', 'acroread', \
579 rc_entry = [r'''\Format pdf pdf "PDF (ps2pdf)" P "%%" "" "document,vector,menu=export"
580 \Format pdf2 pdf "PDF (pdflatex)" F "%%" "" "document,vector,menu=export"
581 \Format pdf3 pdf "PDF (dvipdfm)" m "%%" "" "document,vector,menu=export"
582 \Format pdf4 pdf "PDF (XeTeX)" X "%%" "" "document,vector,menu=export"
583 \Format pdf5 pdf "PDF (LuaTeX)" u "%%" "" "document,vector,menu=export"'''])
585 checkViewer('a DVI previewer', ['xdvi', 'kdvi', 'okular', 'yap', 'dviout -Set=!m'],
586 rc_entry = [r'''\Format dvi dvi DVI D "%%" "" "document,vector,menu=export"
587 \Format dvi3 dvi "DVI (LuaTeX)" V "%%" "" "document,vector,menu=export"'''])
589 # Windows only: DraftDVI
590 addToRC(r'\Format dvi2 dvi DraftDVI "" "" "" "vector"')
592 checkViewer('an HTML previewer', ['firefox', 'mozilla file://$$p$$i', 'netscape'],
593 rc_entry = [r'\Format html html HTML H "%%" "" "document,menu=export"'])
595 checkViewerEditor('Noteedit', ['noteedit'],
596 rc_entry = [r'\Format noteedit not Noteedit "" "%%" "%%" "vector"'])
598 checkViewerEditor('an OpenDocument/OpenOffice viewer', ['swriter', 'oowriter', 'abiword'],
599 rc_entry = [r'''\Format odt odt OpenDocument "" "%%" "%%" "document,vector,menu=export"
600 \Format sxw sxw "OpenOffice.Org (sxw)" "" "" "" "document,vector"'''])
602 checkViewerEditor('a Rich Text and Word viewer', ['swriter', 'oowriter', 'abiword'],
603 rc_entry = [r'''\Format rtf rtf "Rich Text Format" "" "%%" "%%" "document,vector,menu=export"
604 \Format word doc "MS Word" W "%%" "%%" "document,vector,menu=export"'''])
606 # entries that do not need checkProg
607 addToRC(r'''\Format date "" "date command" "" "" "" ""
608 \Format csv csv "Table (CSV)" "" "" "" "document"
609 \Format fax "" Fax "" "" "" "document"
610 \Format lyx lyx LyX "" "" "" ""
611 \Format lyx13x 13.lyx "LyX 1.3.x" "" "" "" "document"
612 \Format lyx14x 14.lyx "LyX 1.4.x" "" "" "" "document"
613 \Format lyx15x 15.lyx "LyX 1.5.x" "" "" "" "document"
614 \Format lyx16x 16.lyx "LyX 1.6.x" "" "" "" "document,menu=export"
615 \Format clyx cjklyx "CJK LyX 1.4.x (big5)" "" "" "" "document"
616 \Format jlyx cjklyx "CJK LyX 1.4.x (euc-jp)" "" "" "" "document"
617 \Format klyx cjklyx "CJK LyX 1.4.x (euc-kr)" "" "" "" "document"
618 \Format lyxpreview lyxpreview "LyX Preview" "" "" "" ""
619 \Format lyxpreview-lytex lyxpreview-lytex "LyX Preview (LilyPond book)" "" "" "" ""
620 \Format lyxpreview-platex lyxpreview-platex "LyX Preview (pLaTeX)" "" "" "" ""
621 \Format pdftex pdftex_t PDFTEX "" "" "" ""
622 \Format program "" Program "" "" "" ""
623 \Format pstex pstex_t PSTEX "" "" "" ""
624 \Format wmf wmf "Windows Metafile" "" "" "" "vector"
625 \Format emf emf "Enhanced Metafile" "" "" "" "vector"
626 \Format wordhtml html "HTML (MS Word)" "" "" "" "document"
630 def checkConverterEntries():
631 ''' Check all converters (\converter entries) '''
632 checkProg('the pdflatex program', ['pdflatex $$i'],
633 rc_entry = [ r'\converter pdflatex pdf2 "%%" "latex=pdflatex"' ])
635 checkProg('XeTeX', ['xelatex $$i'],
636 rc_entry = [ r'\converter xetex pdf4 "%%" "latex=xelatex"' ])
640 ''' If we're running LyX in-place then tex2lyx will be found in
641 ../src/tex2lyx. Add this directory to the PATH temporarily and
643 Use PATH to avoid any problems with paths-with-spaces.
645 path_orig = os.environ["PATH"]
646 os.environ["PATH"] = os.path.join('..', 'src', 'tex2lyx') + \
647 os.pathsep + path_orig
649 # First search for tex2lyx with version suffix (bug 6986)
650 checkProg('a LaTeX/Noweb -> LyX converter', ['tex2lyx' + version_suffix, 'tex2lyx'],
651 rc_entry = [r'''\converter latex lyx "%% -f $$i $$o" ""
652 \converter literate lyx "%% -n -f $$i $$o" ""'''])
654 os.environ["PATH"] = path_orig
657 checkProg('a Noweb -> LaTeX converter', ['noweave -delay -index $$i > $$o'],
658 rc_entry = [r'''\converter literate latex "%%" ""
659 \converter literate pdflatex "%%" ""'''])
661 checkProg('a Sweave -> LaTeX converter', ['Rscript --verbose --no-save --no-restore $$s/scripts/lyxsweave.R $$p$$i $$p$$o $$e $$r'],
662 rc_entry = [r'''\converter sweave latex "%%" ""
663 \converter sweave pdflatex "%%" ""
664 \converter sweave xetex "%%" ""
665 \converter sweave luatex "%%" ""'''])
667 checkProg('an HTML -> LaTeX converter', ['html2latex $$i', 'gnuhtml2latex $$i', \
668 'htmltolatex -input $$i -output $$o', 'java -jar htmltolatex.jar -input $$i -output $$o'],
669 rc_entry = [ r'\converter html latex "%%" ""' ])
671 checkProg('an MS Word -> LaTeX converter', ['wvCleanLatex $$i $$o'],
672 rc_entry = [ r'\converter word latex "%%" ""' ])
674 # eLyXer: search as an executable (elyxer.py, elyxer)
675 path, elyxer = checkProg('a LyX -> HTML converter',
676 ['elyxer.py --directory $$r $$i $$o', 'elyxer --directory $$r $$i $$o'],
677 rc_entry = [ r'\converter lyx html "%%" ""' ])
678 path, elyxer = checkProg('a LyX -> HTML (MS Word) converter',
679 ['elyxer.py --html --directory $$r $$i $$o', 'elyxer --html --directory $$r $$i $$o'],
680 rc_entry = [ r'\converter lyx wordhtml "%%" ""' ])
681 if elyxer.find('elyxer') >= 0:
682 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
683 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
685 # search for HTML converters other than eLyXer
686 # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
687 path, htmlconv = checkProg('a LaTeX -> HTML converter', ['htlatex $$i', 'htlatex.sh $$i', \
688 '/usr/share/tex4ht/htlatex $$i', 'tth -t -e2 -L$$b < $$i > $$o', \
689 'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
690 rc_entry = [ r'\converter latex html "%%" "needaux"' ])
691 if htmlconv.find('htlatex') >= 0 or htmlconv == 'latex2html':
692 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
694 addToRC(r'''\copier html "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
695 path, htmlconv = checkProg('a LaTeX -> HTML (MS Word) converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'", \
696 "htlatex.sh $$i 'html,word' 'symbol/!' '-cvalidate'", \
697 "/usr/share/tex4ht/htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
698 rc_entry = [ r'\converter latex wordhtml "%%" "needaux"' ])
699 if htmlconv.find('htlatex') >= 0:
700 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
702 addToRC(r'''\copier wordhtml "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
705 # Check if LyXBlogger is installed
706 lyxblogger_found = checkModule('lyxblogger')
708 addToRC(r'\Format blog blog "LyXBlogger" "" "" "" "document"')
709 addToRC(r'\converter xhtml blog "python -m lyxblogger $$i" ""')
712 checkProg('an OpenOffice.org -> LaTeX converter', ['w2l -clean $$i'],
713 rc_entry = [ r'\converter sxw latex "%%" ""' ])
715 checkProg('an OpenDocument -> LaTeX converter', ['w2l -clean $$i'],
716 rc_entry = [ r'\converter odt latex "%%" ""' ])
717 # According to http://www.tug.org/applications/tex4ht/mn-commands.html
718 # the command mk4ht oolatex $$i has to be used as default,
719 # but as this would require to have Perl installed, in MiKTeX oolatex is
720 # directly available as application.
721 # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
722 # Both SuSE and debian have oolatex
723 checkProg('a LaTeX -> Open Document converter', [
724 'oolatex $$i', 'mk4ht oolatex $$i', 'oolatex.sh $$i', '/usr/share/tex4ht/oolatex $$i',
725 'htlatex $$i \'xhtml,ooffice\' \'ooffice/! -cmozhtf\' \'-coo\' \'-cvalidate\''],
726 rc_entry = [ r'\converter latex odt "%%" "needaux"' ])
727 # On windows it is called latex2rt.exe
728 checkProg('a LaTeX -> RTF converter', ['latex2rtf -p -S -o $$o $$i', 'latex2rt -p -S -o $$o $$i'],
729 rc_entry = [ r'\converter latex rtf "%%" "needaux"' ])
731 checkProg('a RTF -> HTML converter', ['unrtf --html $$i > $$o'],
732 rc_entry = [ r'\converter rtf html "%%" ""' ])
734 checkProg('a PS to PDF converter', ['ps2pdf13 $$i $$o'],
735 rc_entry = [ r'\converter ps pdf "%%" ""' ])
737 checkProg('a PS to TXT converter', ['pstotext $$i > $$o'],
738 rc_entry = [ r'\converter ps text2 "%%" ""' ])
740 checkProg('a PS to TXT converter', ['ps2ascii $$i $$o'],
741 rc_entry = [ r'\converter ps text3 "%%" ""' ])
743 checkProg('a PS to EPS converter', ['ps2eps $$i'],
744 rc_entry = [ r'\converter ps eps "%%" ""' ])
746 checkProg('a PDF to PS converter', ['pdf2ps $$i $$o', 'pdftops $$i $$o'],
747 rc_entry = [ r'\converter pdf ps "%%" ""' ])
749 checkProg('a PDF to EPS converter', ['pdftops -eps -f 1 -l 1 $$i $$o'],
750 rc_entry = [ r'\converter pdf eps "%%" ""' ])
752 checkProg('a DVI to TXT converter', ['catdvi $$i > $$o'],
753 rc_entry = [ r'\converter dvi text4 "%%" ""' ])
755 checkProg('a DVI to PS converter', ['dvips -o $$o $$i'],
756 rc_entry = [ r'\converter dvi ps "%%" ""' ])
758 checkProg('a DVI to PDF converter', ['dvipdfmx -o $$o $$i', 'dvipdfm -o $$o $$i'],
759 rc_entry = [ r'\converter dvi pdf3 "%%" ""' ])
761 path, dvipng = checkProg('dvipng', ['dvipng'])
762 path, dv2dt = checkProg('DVI to DTL converter', ['dv2dt'])
763 if dvipng == "dvipng" and dv2dt == 'dv2dt':
764 addToRC(r'\converter lyxpreview png "python -tt $$s/scripts/lyxpreview2bitmap.py" ""')
766 # set empty converter to override the default imagemagick
767 addToRC(r'\converter lyxpreview png "" ""')
769 addToRC(r'\converter lyxpreview ppm "python -tt $$s/scripts/lyxpreview2bitmap.py" ""')
771 # set empty converter to override the default imagemagick
772 addToRC(r'\converter lyxpreview ppm "" ""')
774 checkProg('a fax program', ['kdeprintfax $$i', 'ksendfax $$i', 'hylapex $$i'],
775 rc_entry = [ r'\converter ps fax "%%" ""'])
777 path, fig2dev = checkProg('a FIG -> Image converter', ['fig2dev'])
778 if fig2dev == "fig2dev":
779 addToRC(r'''\converter fig eps "fig2dev -L eps $$i $$o" ""
780 \converter fig ppm "fig2dev -L ppm $$i $$o" ""
781 \converter fig png "fig2dev -L png $$i $$o" ""
782 \converter fig pdftex "python -tt $$s/scripts/fig2pdftex.py $$i $$o" ""
783 \converter fig pstex "python -tt $$s/scripts/fig2pstex.py $$i $$o" ""''')
785 checkProg('a TIFF -> PS converter', ['tiff2ps $$i > $$o'],
786 rc_entry = [ r'\converter tiff eps "%%" ""', ''])
788 checkProg('a TGIF -> EPS/PPM converter', ['tgif'],
790 r'''\converter tgif eps "tgif -print -color -eps -stdout $$i > $$o" ""
791 \converter tgif png "tgif -print -color -png -o $$d $$i" ""
792 \converter tgif pdf "tgif -print -color -pdf -stdout $$i > $$o" ""''',
795 checkProg('a WMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
796 rc_entry = [ r'\converter wmf eps "%%" ""'])
798 checkProg('an EMF -> EPS converter', ['metafile2eps $$i $$o', 'wmf2eps -o $$o $$i'],
799 rc_entry = [ r'\converter emf eps "%%" ""'])
801 checkProg('an EPS -> PDF converter', ['epstopdf'],
802 rc_entry = [ r'\converter eps pdf "epstopdf --outfile=$$o $$i" ""', ''])
804 # no agr -> pdf converter, since the pdf library used by gracebat is not
805 # free software and therefore not compiled in in many installations.
806 # Fortunately, this is not a big problem, because we will use epstopdf to
807 # convert from agr to pdf via eps without loss of quality.
808 checkProg('a Grace -> Image converter', ['gracebat'],
810 r'''\converter agr eps "gracebat -hardcopy -printfile $$o -hdevice EPS $$i 2>/dev/null" ""
811 \converter agr png "gracebat -hardcopy -printfile $$o -hdevice PNG $$i 2>/dev/null" ""
812 \converter agr jpg "gracebat -hardcopy -printfile $$o -hdevice JPEG $$i 2>/dev/null" ""
813 \converter agr ppm "gracebat -hardcopy -printfile $$o -hdevice PNM $$i 2>/dev/null" ""''',
816 checkProg('a Dot -> Image converter', ['dot'],
818 r'''\converter dot eps "dot -Teps $$i -o $$o" ""
819 \converter dot png "dot -Tpng $$i -o $$o" ""''',
822 checkProg('a Dia -> PNG converter', ['dia -e $$o -t png $$i'],
823 rc_entry = [ r'\converter dia png "%%" ""'])
825 checkProg('a Dia -> EPS converter', ['dia -e $$o -t eps $$i'],
826 rc_entry = [ r'\converter dia eps "%%" ""'])
828 checkProg('a SVG -> PDF converter', ['rsvg-convert -f pdf -o $$o $$i', 'inkscape --file=$$p/$$i --export-area-drawing --without-gui --export-pdf=$$p/$$o'],
829 rc_entry = [ r'\converter svg pdf "%%" ""'])
831 checkProg('a SVG -> EPS converter', ['rsvg-convert -f ps -o $$o $$i', 'inkscape --file=$$p/$$i --export-area-drawing --without-gui --export-eps=$$p/$$o'],
832 rc_entry = [ r'\converter svg eps "%%" ""'])
833 # the PNG export via Inkscape must not have the full path ($$p) for the file
834 checkProg('a SVG -> PNG converter', ['rsvg-convert -f png -o $$o $$i', 'inkscape --without-gui --file=$$i --export-png=$$o'],
835 rc_entry = [ r'\converter svg png "%%" ""'])
838 # gnumeric/xls/ods to tex
839 checkProg('a spreadsheet -> latex converter', ['ssconvert'],
840 rc_entry = [ r'''\converter gnumeric latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""
841 \converter ods latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""
842 \converter xls latex "ssconvert --export-type=Gnumeric_html:latex $$i $$o" ""''',
845 path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond'])
847 version_string = cmdOutput("lilypond --version")
848 match = re.match('GNU LilyPond (\S+)', version_string)
850 version_number = match.groups()[0]
851 version = version_number.split('.')
852 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 11):
853 addToRC(r'''\converter lilypond eps "lilypond -dbackend=eps -dsafe --ps $$i" ""
854 \converter lilypond png "lilypond -dbackend=eps -dsafe --png $$i" ""''')
855 addToRC(r'\converter lilypond pdf "lilypond -dbackend=eps -dsafe --pdf $$i" ""')
856 logger.info('+ found LilyPond version %s.' % version_number)
857 elif int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 6):
858 addToRC(r'''\converter lilypond eps "lilypond -b eps --ps --safe $$i" ""
859 \converter lilypond png "lilypond -b eps --png $$i" ""''')
860 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 9):
861 addToRC(r'\converter lilypond pdf "lilypond -b eps --pdf --safe $$i" ""')
862 logger.info('+ found LilyPond version %s.' % version_number)
864 logger.info('+ found LilyPond, but version %s is too old.' % version_number)
866 logger.info('+ found LilyPond, but could not extract version number.')
868 path, lilypond_book = checkProg('a LilyPond book (LaTeX) -> LaTeX converter', ['lilypond-book'])
869 if (lilypond_book != ''):
870 version_string = cmdOutput("lilypond-book --version")
871 match = re.match('^(\S+)$', version_string)
873 version_number = match.groups()[0]
874 version = version_number.split('.')
875 if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 13):
877 addToRC(r'\converter lyxpreview-lytex ppm "python -tt $$s/scripts/lyxpreview-lytex2bitmap.py" ""')
879 # set empty converter to override the default imagemagick
880 addToRC(r'\converter lyxpreview-lytex ppm "" ""')
881 if dvipng == "dvipng" and dv2dt == 'dv2dt':
882 addToRC(r'\converter lyxpreview-lytex png "python -tt $$s/scripts/lyxpreview-lytex2bitmap.py" ""')
884 # set empty converter to override the default imagemagick
885 addToRC(r'\converter lyxpreview-lytex png "" ""')
886 # Note: The --lily-output-dir flag is required because lilypond-book
887 # does not process input again unless the input has changed,
888 # even if the output format being requested is different. So
889 # once a .eps file exists, lilypond-book won't create a .pdf
890 # even when requested with --pdf. This is a problem if a user
891 # clicks View PDF after having done a View DVI. To circumvent
892 # this, use different output folders for eps and pdf outputs.
893 addToRC(r'\converter lilypond-book latex "lilypond-book --safe --lily-output-dir=ly-eps $$i" ""')
894 addToRC(r'\converter lilypond-book pdflatex "lilypond-book --safe --pdf --latex-program=pdflatex --lily-output-dir=ly-pdf $$i" ""')
895 addToRC(r'\converter lilypond-book xetex "lilypond-book --safe --pdf --latex-program=xelatex --lily-output-dir=ly-pdf $$i" ""')
896 addToRC(r'\converter lilypond-book luatex "lilypond-book --safe --pdf --latex-program=lualatex --lily-output-dir=ly-pdf $$i" ""')
897 logger.info('+ found LilyPond-book version %s.' % version_number)
899 logger.info('+ found LilyPond-book, but version %s is too old.' % version_number)
901 logger.info('+ found LilyPond-book, but could not extract version number.')
903 checkProg('a Noteedit -> LilyPond converter', ['noteedit --export-lilypond $$i'],
904 rc_entry = [ r'\converter noteedit lilypond "%%" ""', ''])
906 # Currently, lyxpak outputs a gzip compressed tar archive on *nix
907 # and a zip archive on Windows.
908 # So, we configure the appropriate version according to the platform.
909 cmd = r'\converter lyx %s "python -tt $$s/scripts/lyxpak.py $$r/$$i" ""'
911 addToRC(r'\Format lyxzip zip "LyX Archive (zip)" "" "" "" "document,menu=export"')
912 addToRC(cmd % "lyxzip")
914 addToRC(r'\Format lyxgz gz "LyX Archive (tar.gz)" "" "" "" "document,menu=export"')
915 addToRC(cmd % "lyxgz")
918 # FIXME: no rc_entry? comment it out
919 # checkProg('Image converter', ['convert $$i $$o'])
921 # Entries that do not need checkProg
922 addToRC(r'''\converter lyxpreview-platex ppm "python -tt $$s/scripts/lyxpreview-platex2bitmap.py" ""
923 \converter csv lyx "python -tt $$s/scripts/csv2lyx.py $$i $$o" ""
924 \converter date dateout "python -tt $$s/scripts/date.py %d-%m-%Y > $$o" ""
925 \converter docbook docbook-xml "cp $$i $$o" "xml"
926 \converter fen asciichess "python -tt $$s/scripts/fen2ascii.py $$i $$o" ""
927 \converter lyx lyx13x "python -tt $$s/lyx2lyx/lyx2lyx -t 221 $$i > $$o" ""
928 \converter lyx lyx14x "python -tt $$s/lyx2lyx/lyx2lyx -t 245 $$i > $$o" ""
929 \converter lyx lyx15x "python -tt $$s/lyx2lyx/lyx2lyx -t 276 $$i > $$o" ""
930 \converter lyx lyx16x "python -tt $$s/lyx2lyx/lyx2lyx -t 345 $$i > $$o" ""
931 \converter lyx clyx "python -tt $$s/lyx2lyx/lyx2lyx -c big5 -t 245 $$i > $$o" ""
932 \converter lyx jlyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp -t 245 $$i > $$o" ""
933 \converter lyx klyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr -t 245 $$i > $$o" ""
934 \converter clyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c big5 $$i > $$o" ""
935 \converter jlyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp $$i > $$o" ""
936 \converter klyx lyx "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr $$i > $$o" ""
941 ''' Check docbook '''
942 path, DOCBOOK = checkProg('SGML-tools 2.x (DocBook), db2x scripts or xsltproc', ['sgmltools', 'db2dvi', 'xsltproc'],
944 r'''\converter docbook dvi "sgmltools -b dvi $$i" ""
945 \converter docbook html "sgmltools -b html $$i" ""''',
946 r'''\converter docbook dvi "db2dvi $$i" ""
947 \converter docbook html "db2html $$i" ""''',
948 r'''\converter docbook dvi "" ""
949 \converter docbook html "" ""''',
950 r'''\converter docbook dvi "" ""
951 \converter docbook html "" ""'''])
954 return ('yes', 'true', '\\def\\hasdocbook{yes}')
956 return ('no', 'false', '')
959 def checkOtherEntries():
960 ''' entries other than Format and Converter '''
961 checkProg('ChkTeX', ['chktex -n1 -n3 -n6 -n9 -n22 -n25 -n30 -n38'],
962 rc_entry = [ r'\chktex_command "%%"' ])
963 checkProgAlternatives('BibTeX or alternative programs', ['bibtex', 'bibtex8', 'biber'],
964 rc_entry = [ r'\bibtex_command "%%"' ],
965 alt_rc_entry = [ r'\bibtex_alternatives "%%"' ])
966 checkProg('a specific Japanese BibTeX variant', ['pbibtex', 'jbibtex', 'bibtex'],
967 rc_entry = [ r'\jbibtex_command "%%"' ])
968 checkProgAlternatives('available index processors', ['texindy', 'makeindex -c -q', 'xindy'],
969 rc_entry = [ r'\index_command "%%"' ],
970 alt_rc_entry = [ r'\index_alternatives "%%"' ])
971 checkProg('an index processor appropriate to Japanese', ['mendex -c -q', 'jmakeindex -c -q', 'makeindex -c -q'],
972 rc_entry = [ r'\jindex_command "%%"' ])
973 path, splitindex = checkProg('the splitindex processor', ['splitindex.pl', 'splitindex'],
974 rc_entry = [ r'\splitindex_command "%%"' ])
976 checkProg('the splitindex processor (java version)', ['splitindex.class'],
977 rc_entry = [ r'\splitindex_command "java splitindex"' ])
978 checkProg('a nomenclature processor', ['makeindex'],
979 rc_entry = [ r'\nomencl_command "makeindex -s nomencl.ist"' ])
980 ## FIXME: OCTAVE is not used anywhere
981 # path, OCTAVE = checkProg('Octave', ['octave'])
982 ## FIXME: MAPLE is not used anywhere
983 # path, MAPLE = checkProg('Maple', ['maple'])
984 checkProg('a spool command', ['lp', 'lpr'],
986 r'''\print_spool_printerprefix "-d "
987 \print_spool_command "lp"''',
988 r'''\print_spool_printerprefix "-P",
989 \print_spool_command "lpr"''',
991 # Add the rest of the entries (no checkProg is required)
992 addToRC(r'''\copier fig "python -tt $$s/scripts/fig_copy.py $$i $$o"
993 \copier pstex "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
994 \copier pdftex "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
995 \copier program "python -tt $$s/scripts/ext_copy.py $$i $$o"
999 def processLayoutFile(file, bool_docbook):
1000 ''' process layout file and get a line of result
1002 Declare lines look like this: (article.layout, scrbook.layout, svjog.layout)
1004 \DeclareLaTeXClass{article}
1005 \DeclareLaTeXClass[scrbook]{book (koma-script)}
1006 \DeclareLaTeXClass[svjour,svjog.clo]{article (Springer - svjour/jog)}
1010 "article" "article" "article" "false" "article.cls"
1011 "scrbook" "scrbook" "book (koma-script)" "false" "scrbook.cls"
1012 "svjog" "svjour" "article (Springer - svjour/jog)" "false" "svjour.cls,svjog.clo"
1014 def checkForClassExtension(x):
1015 '''if the extension for a latex class is not
1016 provided, add .cls to the classname'''
1018 return x.strip() + '.cls'
1021 classname = file.split(os.sep)[-1].split('.')[0]
1022 # return ('LaTeX', '[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article}
1023 p = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
1024 for line in open(file).readlines():
1025 res = p.search(line)
1027 (classtype, optAll, opt, opt1, desc) = res.groups()
1028 avai = {'LaTeX':'false', 'DocBook':bool_docbook}[classtype]
1031 prereq_latex = checkForClassExtension(classname)
1033 prereq_list = optAll[1:-1].split(',')
1034 prereq_list = map(checkForClassExtension, prereq_list)
1035 prereq_latex = ','.join(prereq_list)
1036 prereq_docbook = {'true':'', 'false':'docbook'}[bool_docbook]
1037 prereq = {'LaTeX':prereq_latex, 'DocBook':prereq_docbook}[classtype]
1038 return '"%s" "%s" "%s" "%s" "%s"\n' % (classname, opt, desc, avai, prereq)
1039 logger.warning("Layout file " + file + " has no \DeclareXXClass line. ")
1043 def checkLatexConfig(check_config, bool_docbook):
1044 ''' Explore the LaTeX configuration
1045 Return None (will be passed to sys.exit()) for success.
1047 msg = 'checking LaTeX configuration... '
1048 # if --without-latex-config is forced, or if there is no previous
1049 # version of textclass.lst, re-generate a default file.
1050 if not os.path.isfile('textclass.lst') or not check_config:
1051 # remove the files only if we want to regenerate
1052 removeFiles(['textclass.lst', 'packages.lst'])
1054 # Then, generate a default textclass.lst. In case configure.py
1055 # fails, we still have something to start lyx.
1056 logger.info(msg + ' default values')
1057 logger.info('+checking list of textclasses... ')
1058 tx = open('textclass.lst', 'w')
1060 # This file declares layouts and their associated definition files
1061 # (include dir. relative to the place where this file is).
1062 # It contains only default values, since chkconfig.ltx could not be run
1063 # for some reason. Run ./configure.py if you need to update it after a
1064 # configuration change.
1066 # build the list of available layout files and convert it to commands
1069 for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
1070 glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
1072 if not os.path.isfile(file):
1074 # get stuff between /xxxx.layout .
1075 classname = file.split(os.sep)[-1].split('.')[0]
1077 cleanclass = classname.replace(' ', '_')
1078 cleanclass = cleanclass.replace('-', '_')
1079 # make sure the same class is not considered twice
1080 if foundClasses.count(cleanclass) == 0: # not found before
1081 foundClasses.append(cleanclass)
1082 retval = processLayoutFile(file, bool_docbook)
1086 logger.info('\tdone')
1087 if not check_config:
1089 # the following will generate textclass.lst.tmp, and packages.lst.tmp
1090 logger.info(msg + '\tauto')
1091 removeFiles(['wrap_chkconfig.ltx', 'chkconfig.vars', \
1092 'chkconfig.classes', 'chklayouts.tex'])
1094 if not os.path.isfile( 'chkconfig.ltx' ):
1095 shutil.copyfile( os.path.join(srcdir, 'chkconfig.ltx'), 'chkconfig.ltx' )
1097 writeToFile('wrap_chkconfig.ltx', '%s\n\\input{chkconfig.ltx}\n' % docbook_cmd)
1098 # Construct the list of classes to test for.
1099 # build the list of available layout files and convert it to commands
1101 declare = re.compile(r'\Declare(LaTeX|DocBook)Class\s*(\[([^,]*)(,.*)*\])*\s*{(.*)}')
1102 empty = re.compile(r'^\s*$')
1103 testclasses = list()
1104 for file in glob.glob( os.path.join('layouts', '*.layout') ) + \
1105 glob.glob( os.path.join(srcdir, 'layouts', '*.layout' ) ) :
1106 nodeclaration = False
1107 if not os.path.isfile(file):
1109 classname = file.split(os.sep)[-1].split('.')[0]
1110 for line in open(file).readlines():
1111 if not empty.match(line) and line[0] != '#':
1112 logger.warning("Failed to find valid \Declare line for layout file `" + file + "'.\n\t=> Skipping this file!")
1113 nodeclaration = True
1115 if declare.search(line) == None:
1117 testclasses.append("\\TestDocClass{%s}{%s}" % (classname, line[1:].strip()))
1122 cl = open('chklayouts.tex', 'w')
1123 for line in testclasses:
1124 cl.write(line + '\n')
1127 # we have chklayouts.tex, then process it
1128 fout = os.popen(LATEX + ' wrap_chkconfig.ltx')
1130 line = fout.readline()
1133 if re.match('^\+', line):
1134 logger.info(line.strip())
1135 # if the command succeeds, None will be returned
1138 # currently, values in chhkconfig are only used to set
1141 for line in open('chkconfig.vars').readlines():
1142 key, val = re.sub('-', '_', line).split('=')
1144 values[key] = val.strip("'")
1145 # chk_fontenc may not exist
1147 addToRC(r'\font_encoding "%s"' % values["chk_fontenc"])
1150 if rmcopy: # remove the copied file
1151 removeFiles( [ 'chkconfig.ltx' ] )
1152 # if configure successed, move textclass.lst.tmp to textclass.lst
1153 # and packages.lst.tmp to packages.lst
1154 if os.path.isfile('textclass.lst.tmp') and len(open('textclass.lst.tmp').read()) > 0 \
1155 and os.path.isfile('packages.lst.tmp') and len(open('packages.lst.tmp').read()) > 0:
1156 shutil.move('textclass.lst.tmp', 'textclass.lst')
1157 shutil.move('packages.lst.tmp', 'packages.lst')
1161 def checkModulesConfig():
1162 removeFiles(['lyxmodules.lst', 'chkmodules.tex'])
1164 logger.info('+checking list of modules... ')
1165 tx = open('lyxmodules.lst', 'w')
1166 tx.write('''## This file declares modules and their associated definition files.
1167 ## It has been automatically generated by configure
1168 ## Use "Options/Reconfigure" if you need to update it after a
1169 ## configuration change.
1170 ## "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
1173 # build the list of available modules
1175 # note that this searches the local directory first, then the
1176 # system directory. that way, we pick up the user's version first.
1177 for file in glob.glob( os.path.join('layouts', '*.module') ) + \
1178 glob.glob( os.path.join(srcdir, 'layouts', '*.module' ) ) :
1181 if not os.path.isfile(file):
1184 filename = file.split(os.sep)[-1]
1185 filename = filename[:-7]
1186 if seen.count(filename):
1189 seen.append(filename)
1190 retval = processModuleFile(file, filename, bool_docbook)
1194 logger.info('\tdone')
1197 def processModuleFile(file, filename, bool_docbook):
1198 ''' process module file and get a line of result
1200 The top of a module file should look like this:
1201 #\DeclareLyXModule[LaTeX Packages]{ModuleName}
1203 #...body of description...
1205 #Requires: [list of required modules]
1206 #Excludes: [list of excluded modules]
1207 #Category: [category name]
1208 The last three lines are optional (though do give a category).
1210 "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
1212 remods = re.compile(r'\DeclareLyXModule\s*(?:\[([^]]*?)\])?{(.*)}')
1213 rereqs = re.compile(r'#+\s*Requires: (.*)')
1214 reexcs = re.compile(r'#+\s*Excludes: (.*)')
1215 recaty = re.compile(r'#+\s*Category: (.*)')
1216 redbeg = re.compile(r'#+\s*DescriptionBegin\s*$')
1217 redend = re.compile(r'#+\s*DescriptionEnd\s*$')
1219 modname = desc = pkgs = req = excl = catgy = ""
1220 readingDescription = False
1223 for line in open(file).readlines():
1224 if readingDescription:
1225 res = redend.search(line)
1227 readingDescription = False
1228 desc = " ".join(descLines)
1230 desc = desc.replace('"', '\\"')
1232 descLines.append(line[1:].strip())
1234 res = redbeg.search(line)
1236 readingDescription = True
1238 res = remods.search(line)
1240 (pkgs, modname) = res.groups()
1244 tmp = [s.strip() for s in pkgs.split(",")]
1245 pkgs = ",".join(tmp)
1247 res = rereqs.search(line)
1250 tmp = [s.strip() for s in req.split("|")]
1253 res = reexcs.search(line)
1256 tmp = [s.strip() for s in excl.split("|")]
1257 excl = "|".join(tmp)
1259 res = recaty.search(line)
1261 catgy = res.group(1)
1265 logger.warning("Module file without \DeclareLyXModule line. ")
1269 # this module has some latex dependencies:
1270 # append the dependencies to chkmodules.tex,
1271 # which is \input'ed by chkconfig.ltx
1272 testpackages = list()
1273 for pkg in pkgs.split(","):
1275 # this is a converter dependency: skip
1277 if pkg.endswith(".sty"):
1279 testpackages.append("\\TestPackage{%s}" % (pkg,))
1280 cm = open('chkmodules.tex', 'a')
1281 for line in testpackages:
1282 cm.write(line + '\n')
1285 return '"%s" "%s" "%s" "%s" "%s" "%s" "%s"\n' % (modname, filename, desc, pkgs, req, excl, catgy)
1289 def checkTeXAllowSpaces():
1290 ''' Let's check whether spaces are allowed in TeX file names '''
1291 tex_allows_spaces = 'false'
1292 if lyx_check_config:
1293 msg = "Checking whether TeX allows spaces in file names... "
1294 writeToFile('a b.tex', r'\message{working^^J}' )
1297 latex_out = cmdOutput(LATEX + r""" "\nonstopmode\input{\"a b\"}" """)
1299 latex_out = cmdOutput(LATEX + r""" '\nonstopmode\input{"a b"}' """)
1302 if 'working' in latex_out:
1303 logger.info(msg + 'yes')
1304 tex_allows_spaces = 'true'
1306 logger.info(msg + 'no')
1307 tex_allows_spaces = 'false'
1308 addToRC(r'\tex_allows_spaces ' + tex_allows_spaces)
1309 removeFiles( [ 'a b.tex', 'a b.log', 'texput.log' ])
1312 def removeTempFiles():
1314 if not lyx_keep_temps:
1315 removeFiles(['chkconfig.vars', \
1316 'wrap_chkconfig.ltx', 'wrap_chkconfig.log', \
1317 'chklayouts.tex', 'chkmodules.tex', 'missfont.log',
1318 'chklatex.ltx', 'chklatex.log'])
1321 if __name__ == '__main__':
1322 lyx_check_config = True
1323 outfile = 'lyxrc.defaults'
1325 lyx_keep_temps = False
1327 ## Parse the command line
1328 for op in sys.argv[1:]: # default shell/for list is $*, the options
1329 if op in [ '-help', '--help', '-h' ]:
1330 print '''Usage: configure [options]
1332 --help show this help lines
1333 --keep-temps keep temporary files (for debug. purposes)
1334 --without-latex-config do not run LaTeX to determine configuration
1335 --with-version-suffix=suffix suffix of binary installed files
1338 elif op == '--without-latex-config':
1339 lyx_check_config = False
1340 elif op == '--keep-temps':
1341 lyx_keep_temps = True
1342 elif op[0:22] == '--with-version-suffix=': # never mind if op is not long enough
1343 version_suffix = op[22:]
1345 print "Unknown option", op
1348 # check if we run from the right directory
1349 srcdir = os.path.dirname(sys.argv[0])
1352 if not os.path.isfile( os.path.join(srcdir, 'chkconfig.ltx') ):
1353 logger.error("configure: error: cannot find chkconfig.ltx script")
1357 dtl_tools = checkDTLtools()
1358 ## Write the first part of outfile
1359 writeToFile(outfile, '''# This file has been automatically generated by LyX' lib/configure.py
1360 # script. It contains default settings that have been determined by
1361 # examining your system. PLEASE DO NOT MODIFY ANYTHING HERE! If you
1362 # want to customize LyX, use LyX' Preferences dialog or modify directly
1363 # the "preferences" file instead. Any setting in that file will
1364 # override the values given here.
1367 LATEX = checkLatex(dtl_tools)
1368 checkFormatEntries(dtl_tools)
1369 checkConverterEntries()
1370 (chk_docbook, bool_docbook, docbook_cmd) = checkDocBook()
1371 checkTeXAllowSpaces()
1372 windows_style_tex_paths = checkTeXPaths()
1373 if windows_style_tex_paths != '':
1374 addToRC(r'\tex_expects_windows_paths %s' % windows_style_tex_paths)
1376 checkModulesConfig()
1377 # --without-latex-config can disable lyx_check_config
1378 ret = checkLatexConfig(lyx_check_config and LATEX != '', bool_docbook)
1380 # The return error code can be 256. Because most systems expect an error code
1381 # in the range 0-127, 256 can be interpretted as 'success'. Because we expect
1382 # a None for success, 'ret is not None' is used to exit.
1383 sys.exit(ret is not None)