@@ -158,7 +158,7 @@ def main():
158158 args .obj_dir , args .nowarns )
159159 task_commit = LaTeXCommit (db , task_latex , args .output )
160160 task_bibtex = BibTeX (db , task_latex , args .bibtex_cmd , args .bibtex_args ,
161- args .nowarns )
161+ args .nowarns , args . obj_dir )
162162 tasks = [task_latex , task_commit , task_bibtex ]
163163 stable = run_tasks (tasks , args .max_iterations )
164164
@@ -1471,12 +1471,13 @@ class LaTeXFilter:
14711471#
14721472
14731473class BibTeX (Task ):
1474- def __init__ (self , db , latex_task , cmd , cmd_args , nowarns ):
1474+ def __init__ (self , db , latex_task , cmd , cmd_args , nowarns , obj_dir ):
14751475 super ().__init__ (db , 'bibtex::' + normalize_input_path (
14761476 latex_task .get_tex_filename ()))
14771477 self .__latex_task = latex_task
14781478 self .__cmd = cmd
14791479 self .__cmd_args = cmd_args
1480+ self .__obj_dir = obj_dir
14801481
14811482 def stable (self ):
14821483 # If bibtex doesn't have its inputs, then it's stable because
@@ -1512,6 +1513,10 @@ class BibTeX(Task):
15121513 re .search (r'^\\bibdata\{' , aux_data , flags = re .M ):
15131514 return True
15141515
1516+ if re .search (r'^\\abx@aux@cite\{' , aux_data , flags = re .M ):
1517+ # biber citation
1518+ return True
1519+
15151520 # Recurse into included aux files (see aux_input_command), in
15161521 # case \bibliography appears in an \included file.
15171522 for m in re .finditer (r'^\\@input\{([^}]*)\}' , aux_data , flags = re .M ):
@@ -1522,10 +1527,18 @@ class BibTeX(Task):
15221527 return False
15231528
15241529 def _input_args (self ):
1525- aux_name = os .path .basename (self .__latex_task .get_jobname ()) + '.aux'
1526- return [self .__cmd ] + self .__cmd_args + [aux_name ]
1530+ if self .__is_biber ():
1531+ aux_name = os .path .basename (self .__latex_task .get_jobname ())
1532+ biber_args = ["--input-directory" , self .__obj_dir ,
1533+ "--output-directory" , self .__obj_dir ]
1534+ else :
1535+ aux_name = os .path .basename (self .__latex_task .get_jobname ()) + '.aux'
1536+ biber_args = []
1537+ return [self .__cmd ] + biber_args + self .__cmd_args + [aux_name ]
15271538
15281539 def _input_cwd (self ):
1540+ if self .__is_biber ():
1541+ return "."
15291542 return os .path .dirname (self .__latex_task .get_jobname ())
15301543
15311544 def _input_auxfile (self , auxname ):
@@ -1539,7 +1552,8 @@ class BibTeX(Task):
15391552 h = hashlib .sha256 ()
15401553 for line in aux :
15411554 if line .startswith ((b'\\ citation{' , b'\\ bibdata{' ,
1542- b'\\ bibstyle{' , b'\\ @input{' )):
1555+ b'\\ bibstyle{' , b'\\ @input{' ,
1556+ b'\\ abx@aux@cite{' )):
15431557 h .update (line )
15441558 return h .hexdigest ()
15451559 except FileNotFoundError :
@@ -1552,6 +1566,9 @@ class BibTeX(Task):
15521566 return first + ':'
15531567 return first + ':' + rest
15541568
1569+ def __is_biber (self ):
1570+ return "biber" in self .__cmd
1571+
15551572 def _execute (self ):
15561573 # This gets complicated when \include is involved. \include
15571574 # switches to a different aux file and records its path in the
@@ -1583,7 +1600,7 @@ class BibTeX(Task):
15831600 except OSError as e :
15841601 raise TaskError ('failed to execute bibtex task: ' + str (e )) from e
15851602
1586- inputs , auxnames = self .__parse_inputs (stdout , cwd , env )
1603+ inputs , auxnames , outbase = self .__parse_inputs (stdout , cwd , env )
15871604 if not inputs and not auxnames :
15881605 # BibTeX failed catastrophically.
15891606 print (stdout , file = sys .stderr )
@@ -1599,7 +1616,8 @@ class BibTeX(Task):
15991616 for path in inputs :
16001617 self ._input ('file' , path )
16011618
1602- outbase = auxnames [0 ][:- 4 ]
1619+ if self .__is_biber ():
1620+ outbase = os .path .join (cwd , outbase )
16031621 outputs = [outbase + '.bbl' , outbase + '.blg' ]
16041622 return RunResult (outputs , {'outbase' : outbase , 'status' : status ,
16051623 'inputs' : inputs })
@@ -1635,6 +1653,7 @@ class BibTeX(Task):
16351653 kpathsea = Kpathsea ('bibtex' )
16361654 inputs = []
16371655 auxnames = []
1656+ outbase = None
16381657 for line in log .splitlines ():
16391658 m = re .match ('(?:The top-level auxiliary file:'
16401659 '|A level-[0-9]+ auxiliary file:) (.*)' , line )
@@ -1660,7 +1679,21 @@ class BibTeX(Task):
16601679
16611680 inputs .append (filename )
16621681
1663- return inputs , auxnames
1682+ # biber output
1683+ m = re .search ("Found BibTeX data source '(.*?)'" ,
1684+ line )
1685+ if m :
1686+ filename = m .group (1 )
1687+ inputs .append (filename )
1688+
1689+ m = re .search ("Logfile is '(.*?)'" , line )
1690+ if m :
1691+ outbase = m .group (1 )[:- 4 ]
1692+
1693+ if outbase is None :
1694+ outbase = auxnames [0 ][:- 4 ]
1695+
1696+ return inputs , auxnames , outbase
16641697
16651698 def report (self ):
16661699 extra = self ._get_result_extra ()
@@ -1779,6 +1812,21 @@ class BibTeXFilter:
17791812 if match ('Aborted at line ([0-9]+) of file (.*)' ):
17801813 return ('info' , m .group (2 ), int (m .group (1 )), 'aborted' )
17811814
1815+ # biber type errors
1816+ if match ('^.*> WARN - (.*)$' ):
1817+ print ('warning' , None , None , m .group (1 ))
1818+ m2 = re .match ("(.*) in file '(.*?)', skipping ..." , m .group (1 ))
1819+ if m2 :
1820+ return ('warning' , m2 .group (2 ), "0" , m2 .group (1 ))
1821+ return ('warning' , None , None , m .group (1 ))
1822+
1823+ if match ('^.*> ERROR - (.*)$' ):
1824+ m2 = re .match ("BibTeX subsystem: (.*?), line (\d+), (.*)$" , m .group (1 ))
1825+ if m2 :
1826+ return ('error' , m2 .group (1 ), m2 .group (2 ), m2 .group (3 ))
1827+ return ('error' , None , None , m .group (1 ))
1828+
1829+
17821830 def __canonicalize (self , msg ):
17831831 if msg .startswith ('Warning' ):
17841832 msg = re .sub ('^Warning-*' , '' , msg )
0 commit comments