|
Packit Service |
76cb02 |
# This file is part of Rubber and thus covered by the GPL
|
|
Packit Service |
76cb02 |
# (c) Emmanuel Beffara, 2002--2006
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
This module contains all the classes used to manage the building
|
|
Packit Service |
76cb02 |
dependencies.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
cd7d79 |
from __future__ import print_function
|
|
Packit Service |
76cb02 |
import os
|
|
Packit Service |
76cb02 |
import time
|
|
Packit Service |
76cb02 |
import subprocess
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
cd7d79 |
from dbtexmf.dblatex.grubber.msg import _, msg
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
class Depend (object): #{{{2
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
This is a base class to represent file dependencies. It provides the base
|
|
Packit Service |
76cb02 |
functionality of date checking and recursive making, supposing the
|
|
Packit Service |
76cb02 |
existence of a method `run()' in the object. This method is supposed to
|
|
Packit Service |
76cb02 |
rebuild the files of this node, returning zero on success and something
|
|
Packit Service |
76cb02 |
else on failure.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
def __init__ (self, env, prods=None, sources={}, loc={}):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Initialize the object for a given set of output files and a given set
|
|
Packit Service |
76cb02 |
of sources. The argument `prods' is a list of file names, and the
|
|
Packit Service |
76cb02 |
argument `sources' is a dictionary that associates file names with
|
|
Packit Service |
76cb02 |
dependency nodes. The optional argument `loc' is a dictionary that
|
|
Packit Service |
76cb02 |
describes where in the sources this dependency was created.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
self.env = env
|
|
Packit Service |
76cb02 |
if prods:
|
|
Packit Service |
76cb02 |
self.prods = prods
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
self.prods = []
|
|
Packit Service |
76cb02 |
self.set_date()
|
|
Packit Service |
76cb02 |
self.sources = sources
|
|
Packit Service |
76cb02 |
self.making = 0
|
|
Packit Service |
76cb02 |
self.failed_dep = None
|
|
Packit Service |
76cb02 |
self.loc = loc
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def set_date (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Define the date of the last build of this node as that of the most
|
|
Packit Service |
76cb02 |
recent file among the products. If some product does not exist or
|
|
Packit Service |
76cb02 |
there are ne products, the date is set to None.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
if self.prods == []:
|
|
Packit Service |
76cb02 |
# This is a special case used in rubber.Environment
|
|
Packit Service |
76cb02 |
self.date = None
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
try:
|
|
Packit Service |
76cb02 |
# We set the node's date to that of the most recently modified
|
|
Packit Service |
76cb02 |
# product file, assuming all other files were up to date then
|
|
Packit Service |
76cb02 |
# (though not necessarily modified).
|
|
Packit Service |
76cb02 |
self.date = max(map(os.path.getmtime, self.prods))
|
|
Packit Service |
76cb02 |
except OSError:
|
|
Packit Service |
76cb02 |
# If some product file does not exist, set the last
|
|
Packit Service |
76cb02 |
# modification date to None.
|
|
Packit Service |
76cb02 |
self.date = None
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def should_make (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Check the dependencies. Return true if this node has to be recompiled,
|
|
Packit Service |
76cb02 |
i.e. if some dependency is modified. Nothing recursive is done here.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
if not self.date:
|
|
Packit Service |
76cb02 |
return 1
|
|
Packit Service |
76cb02 |
for src in self.sources.values():
|
|
Packit Service |
76cb02 |
if src.date > self.date:
|
|
Packit Service |
76cb02 |
return 1
|
|
Packit Service |
76cb02 |
return 0
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def make (self, force=0):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Make the destination file. This recursively makes all dependencies,
|
|
Packit Service |
76cb02 |
then compiles the target if dependencies were modified. The semantics
|
|
Packit Service |
76cb02 |
of the return value is the following:
|
|
Packit Service |
76cb02 |
- 0 means that the process failed somewhere (in this node or in one of
|
|
Packit Service |
76cb02 |
its dependencies)
|
|
Packit Service |
76cb02 |
- 1 means that nothing had to be done
|
|
Packit Service |
76cb02 |
- 2 means that something was recompiled (therefore nodes that depend
|
|
Packit Service |
76cb02 |
on this one have to be remade)
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
if self.making:
|
|
Packit Service |
cd7d79 |
print("FIXME: cyclic make")
|
|
Packit Service |
76cb02 |
return 1
|
|
Packit Service |
76cb02 |
self.making = 1
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
# Make the sources
|
|
Packit Service |
76cb02 |
self.failed_dep = None
|
|
Packit Service |
76cb02 |
must_make = force
|
|
Packit Service |
76cb02 |
for src in self.sources.values():
|
|
Packit Service |
76cb02 |
ret = src.make()
|
|
Packit Service |
76cb02 |
if ret == 0:
|
|
Packit Service |
76cb02 |
self.making = 0
|
|
Packit Service |
76cb02 |
self.failed_dep = src.failed_dep
|
|
Packit Service |
76cb02 |
return 0
|
|
Packit Service |
76cb02 |
if ret == 2:
|
|
Packit Service |
76cb02 |
must_make = 1
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
# Make this node if necessary
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
if must_make or self.should_make():
|
|
Packit Service |
76cb02 |
if force:
|
|
Packit Service |
76cb02 |
ret = self.force_run()
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
ret = self.run()
|
|
Packit Service |
76cb02 |
if ret:
|
|
Packit Service |
76cb02 |
self.making = 0
|
|
Packit Service |
76cb02 |
self.failed_dep = self
|
|
Packit Service |
76cb02 |
return 0
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
# Here we must take the integer part of the value returned by
|
|
Packit Service |
76cb02 |
# time.time() because the modification times for files, returned
|
|
Packit Service |
76cb02 |
# by os.path.getmtime(), is an integer. Keeping the fractional
|
|
Packit Service |
76cb02 |
# part could lead to errors in time comparison with the main log
|
|
Packit Service |
76cb02 |
# file when the compilation of the document is shorter than one
|
|
Packit Service |
76cb02 |
# second...
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
self.date = int(time.time())
|
|
Packit Service |
76cb02 |
self.making = 0
|
|
Packit Service |
76cb02 |
return 2
|
|
Packit Service |
76cb02 |
self.making = 0
|
|
Packit Service |
76cb02 |
return 1
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def force_run (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
This method is called instead of 'run' when rebuilding this node was
|
|
Packit Service |
76cb02 |
forced. By default it is equivalent to 'run'.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
return self.run()
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def failed (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Return a reference to the node that caused the failure of the last
|
|
Packit Service |
76cb02 |
call to "make". If there was no failure, return None.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
return self.failed_dep
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def get_errors (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Report the errors that caused the failure of the last call to run.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
if None:
|
|
Packit Service |
76cb02 |
yield None
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def clean (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Remove the files produced by this rule and recursively clean all
|
|
Packit Service |
76cb02 |
dependencies.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
for file in self.prods:
|
|
Packit Service |
76cb02 |
if os.path.exists(file):
|
|
Packit Service |
76cb02 |
msg.log(_("removing %s") % file)
|
|
Packit Service |
76cb02 |
os.unlink(file)
|
|
Packit Service |
76cb02 |
for src in self.sources.values():
|
|
Packit Service |
76cb02 |
src.clean()
|
|
Packit Service |
76cb02 |
self.date = None
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def reinit (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Reinitializing depends on actual dependency leaf
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
pass
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def leaves (self):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Return a list of all source files that are required by this node and
|
|
Packit Service |
76cb02 |
cannot be built, i.e. the leaves of the dependency tree.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
if self.sources == {}:
|
|
Packit Service |
76cb02 |
return self.prods
|
|
Packit Service |
76cb02 |
ret = []
|
|
Packit Service |
76cb02 |
for dep in self.sources.values():
|
|
Packit Service |
76cb02 |
ret.extend(dep.leaves())
|
|
Packit Service |
76cb02 |
return ret
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
class DependLeaf (Depend): #{{{2
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
This class specializes Depend for leaf nodes, i.e. source files with no
|
|
Packit Service |
76cb02 |
dependencies.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
def __init__ (self, env, *dest, **args):
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Initialize the node. The arguments of this method are the file
|
|
Packit Service |
76cb02 |
names, since one single node may contain several files.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Depend.__init__(self, env, prods=list(dest), **args)
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def run (self):
|
|
Packit Service |
76cb02 |
# FIXME
|
|
Packit Service |
76cb02 |
if len(self.prods) == 1:
|
|
Packit Service |
76cb02 |
msg.error(_("%r does not exist") % self.prods[0], **self.loc)
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
msg.error(_("one of %r does not exist") % self.prods, **self.loc)
|
|
Packit Service |
76cb02 |
return 1
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def clean (self):
|
|
Packit Service |
76cb02 |
pass
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
class DependShell (Depend): #{{{2
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
This class specializes Depend for generating files using shell commands.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
def __init__ (self, env, cmd, **args):
|
|
Packit Service |
76cb02 |
Depend.__init__(self, env, **args)
|
|
Packit Service |
76cb02 |
self.cmd = cmd
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def run (self):
|
|
Packit Service |
76cb02 |
msg.progress(_("running %s") % self.cmd[0])
|
|
Packit Service |
76cb02 |
rc = subprocess.call(self.cmd, stdout=msg.stdout)
|
|
Packit Service |
76cb02 |
if rc != 0:
|
|
Packit Service |
76cb02 |
msg.error(_("execution of %s failed") % self.cmd[0])
|
|
Packit Service |
76cb02 |
return 1
|
|
Packit Service |
76cb02 |
return 0
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
class Maker:
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
Very simple builder environment. Much simpler than the original rubber
|
|
Packit Service |
76cb02 |
Environment.
|
|
Packit Service |
76cb02 |
"""
|
|
Packit Service |
76cb02 |
def __init__(self):
|
|
Packit Service |
76cb02 |
self.dep_nodes = []
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def dep_last(self):
|
|
Packit Service |
76cb02 |
if not(self.dep_nodes):
|
|
Packit Service |
76cb02 |
return None
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
return self.dep_nodes[-1]
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def dep_append(self, dep):
|
|
Packit Service |
76cb02 |
self.dep_nodes.append(dep)
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def make(self, force=0):
|
|
Packit Service |
76cb02 |
if not(self.dep_nodes):
|
|
Packit Service |
76cb02 |
return 0
|
|
Packit Service |
76cb02 |
# Just ask the last one to compile
|
|
Packit Service |
76cb02 |
rc = self.dep_nodes[-1].make(force=force)
|
|
Packit Service |
76cb02 |
if (rc == 0):
|
|
Packit Service |
76cb02 |
return -1
|
|
Packit Service |
76cb02 |
else:
|
|
Packit Service |
76cb02 |
return 0
|
|
Packit Service |
76cb02 |
|
|
Packit Service |
76cb02 |
def reinit(self):
|
|
Packit Service |
76cb02 |
# Forget the old dependency nodes
|
|
Packit Service |
76cb02 |
self.__init__()
|
|
Packit Service |
76cb02 |
|