Commits

yanchuan sim  committed 3e4ebab Merge

Merge branches 'master' and 'develop'

  • Participants
  • Parent commits e96ac2c, 7baeb85

Comments (0)

Files changed (2)

 yc-make-latex is a simple Python script that handles compiling of LaTeX and related files.
 
-Version 0.1
+Author: yanchuan <yanchuan@yanchuan.sg>
+
+Version 0.1 (Jan 27, 2011)
 - Supports compiling LaTeX files and running BibTeX alternatively until there are no citation errors (naive implementation).
 - Supports running .plt scripts with gnuplot and detecting the eps files that are being produced.
-- Supports converting .eps files to .pdf
+- Supports converting .eps files to .pdf.
+- Only compile files for which the output is missing or has changed.
 
 VERSION = 0.1
 
+LATEX_PROG = 'pdflatex'
+EPSTOPDF_PROG = 'epstopdf'
+BIBTEX_PROG = 'bibtex'
+GNUPLOT_PROG = 'gnuplot'
+
+OUTPUT_EXT = {'.tex': '.pdf', '.eps': '.pdf'}
+DELETE_EXT = {'.tex': ['.aux', '.bbl', '.blg', '.log', '.auxlock', '.dpth', '.synctex.gz']}
+MAX_LATEX_RUNS = 3
+
 parser = argparse.ArgumentParser(description='Compiles LaTeX/related file given on the command line. A sequence of files maybe given and it will be compiled in order. Currently supports .tex, .plt')
-parser.add_argument('files', metavar='file', nargs='+', type=file, help='List of files to compile. They can be .tex, .plt.')
+parser.add_argument('files', metavar='file', nargs='*', type=file, help='List of files to compile. They can be .tex, .plt.')
 parser.add_argument('-f', '--force', action='store_true', default=False, help='Force compile all the files given on the command line without checking to see if it has been modified since last compilation.')
-parser.add_argument('-c', '--clean', action='store_true', default=False, help='Clean up all intermediate files on success.')
+parser.add_argument('-c', '--clean', action='store_true', default=False, help='Clean up all intermediate files regardless of success or failure.')
 parser.add_argument('-v', '--verbose', action='store_true', default=False, help='Print info messages.')
 parser.add_argument('-V', '--version', action='store_true', default=False, help='Print version information.')
 
-OUTPUT_EXT = {'.tex': '.pdf', '.eps': '.pdf'}
-DELETE_EXT = {'.tex': ['.aux', '.bbl', '.blg', '.log']}
-MAX_LATEX_RUNS = 3
+my_path = os.path.realpath(__file__)
+my_last_time = os.path.getmtime(my_path)
 
 def main():
   if A.version: parser.exit(message='ycmakelatex.py version {} by yanchuan <yanchuan@yanchuan.sg>\n'.format(VERSION))
 
-  my_path = os.path.realpath(__file__)
-
-  # get the last time my script was run
-  my_last_time = os.path.getmtime(my_path)
+  if not A.files and not (A.clean or A.version):
+    parser.error('You need to specify at least -c/-v or a file to process.')
 
-  # update the mtime, which is when the script was run
   os.utime(my_path, None)
 
   processed = []
 
   for f in A.files:
     # check if file has been modified since the last time we ran this script
-    if A.force or os.path.getmtime(f.name) > my_last_time or output_not_found(f):
-      processed.append(f.name)
+    if A.force or need_processing(f):
       try:
         process_files(f)
       except MyError as e:
         print_error('{}: {}'.format(os.path.basename(__file__), e.msg))
+        if A.clean: cleanup_files(f)
+        if processed: print_message('The following files were processed: {}'.format(', '.join(processed)))
         sys.exit(-1)
       #end try
+      processed.append(f.name)
     #end if
-    
+
     if A.clean: cleanup_files(f)
   #end for
 
-  if not processed: print_message('There was nothing to do.')
-  else: print_message('The following files were processed: {}'.format(', '.join(processed)))
+  if not A.files and A.clean:
+    print_message('Cleaning up intermediate files in current folder.')
+
+    for exts in DELETE_EXT.itervalues():
+      for file in os.listdir('.'):
+        for ext in exts:
+          if file.endswith(ext):
+            os.unlink(file)
+            print_info('Deleted: {}'.format(file))
+          #end if
+  #end if
+
+  if A.files:
+    if not processed: print_message('There was nothing to do.')
+    else: print_message('The following files were processed: {}'.format(', '.join(processed)))
+  #end if
+
   os.utime(my_path, None)
 #end def
 
-def process_files(f):
+def need_processing(f):
+  if os.path.getmtime(f.name) > my_last_time: return True
+
   (root, ext) = os.path.splitext(f.name)
 
-  try:
-    PROCESS_EXT[ext.lower()](f)
+  if ext == '.plt':
+    for eps_file in see_inside_plt(f):
+      pdf_file = eps_file[:-4] + OUTPUT_EXT['.eps']
 
-  except KeyError:
-    raise MyError('Extension {} is not supported!'.format(ext))
-  #end try
+      if not os.access(pdf_file, os.F_OK): return True
+      if os.path.getmtime(pdf_file) > my_last_time: return True
+    #end for
+
+    return False
+  #end if
+
+  if ext not in OUTPUT_EXT: return True
+  if os.access(root + OUTPUT_EXT[ext], os.F_OK): return False
 
   return True
 #end def
 
-def output_not_found(f):
+def process_files(f):
   (root, ext) = os.path.splitext(f.name)
 
-  if ext not in OUTPUT_EXT: return True
-  if os.access(root + OUTPUT_EXT[ext], os.F_OK): return False
+  try:
+    PROCESS_EXT[ext.lower()](f)
+
+  except KeyError:
+    raise MyError('Extension {} is not supported!'.format(ext))
+  #end try
 
   return True
 #end def
 
 def process_tex(f, run_count=0):
   # start compiling
-  command = ['pdflatex', '-halt-on-error', '-interaction=nonstopmode', f.name]
+  command = [LATEX_PROG, '-halt-on-error', '-interaction=nonstopmode', f.name]
   try:
     print_info('pdfLaTeX {}'.format(f.name))
     output = subprocess.check_output(command)
 
 def process_bibtex(f):
   noext, ext = os.path.splitext(f.name)
-  command = ['bibtex', noext]
+  command = [BIBTEX_PROG, noext]
 
   try:
     print_info('BibTeX {}'.format(f.name))
 #end def
 
 def process_plt(f):
-  command = ['gnuplot', f.name]
+  command = [GNUPLOT_PROG, f.name]
   time_now = time.time() - 1
+
+  eps_outputs = see_inside_plt(f)
+
   try:
     output = subprocess.check_output(command)
-    
-    for file in os.listdir('.'):
-      if file.endswith('.eps') and os.path.getmtime(file) >= time_now: 
-        retval = process_eps(open(file))
-        if retval: 
-          try: os.unlink(file)
-          except: pass
-        #end if
+
+    for file in eps_outputs:
+      retval = process_eps(open(file))
+      if retval:
+        try: os.unlink(file)
+        except: pass
       #end if
     #end for
   except subprocess.CalledProcessError as e:
 #end def
 
 def process_eps(f):
-  command = ['epstopdf', f.name]
+  command = [EPSTOPDF_PROG, f.name]
   try:
     print_info('epstopdf {}'.format(f.name))
     output = subprocess.check_output(command)
   except subprocess.CalledProcessError as e:
     raise MyError('epstopdf {} failed!'.format(f.name))
   #end try
-  
+
   return True
 #end def
 
+def see_inside_plt(f):
+  re_setoutput = re.compile(r'.*set output \'(.+\.eps)\'.*')
+  eps_outputs = []
+
+  f.seek(0)
+  for line in f:
+    line = line.rstrip().strip()
+
+    if line.startswith('#'): continue
+
+    m = re_setoutput.match(line)
+    if m: eps_outputs.append(m.group(1))
+  #end for
+
+  return eps_outputs
+#end def
+
+
 def parse_bibtex_output(output):
   lines = output.split('\n')
 
 if __name__ == "__main__":
   PROCESS_EXT = {'.tex': process_tex, '.plt': process_plt, '.eps': process_eps}
 
-  A = parser.parse_args()
+  try:
+    A = parser.parse_args()
 
-  main()
+    main()
+  except IOError as e:
+    print_error(e)
 #end if