ll.make
– Object oriented make replacement
ll.make
provides tools for building projects.
Like make it allows you to specify dependencies between files and actions to be executed when files don’t exist or are out of date with respect to one of their sources. But unlike make you can do this in an object oriented way and targets are not only limited to files.
Relevant classes are:
Project
, which is the container for all actions in a project andAction
(and subclasses), which are used to transform input data and read and write files (or other entities like database records).
A simple script that copies a file foo.txt
to bar.txt
reencoding it from "latin-1"
to "utf-8"
in the process looks like
this:
from ll import make
class MyProject(make.Project):
name = "Acme.MyProject"
def create(self):
make.Project.create(self)
source = self.add(make.FileAction("foo.txt"))
temp = source.callattr("decode", "iso-8859-1")
temp = temp.callattr("encode", "utf-8")
target = self.add(make.FileAction("bar.txt", temp))
self.writecreatedone()
p = MyProject()
p.create()
if __name__ == "__main__":
p.build("bar.txt")
- ll.make.filechanged(key)[source]
Get the last modified date (or
bigbang
, if the file doesn’t exist).
- class ll.make.Level[source]
Bases:
object
Stores information about the recursive execution of
Action
s.
- ll.make.report(func)[source]
Standard decorator for
Action.get()
methods.This decorator handles proper reporting of nested action calls. If it isn’t used, only the output of calls to
Project.writestep()
will be visible to the user.
- exception ll.make.RedefinedTargetWarning[source]
Bases:
Warning
Warning that will be issued when a target is added to a project and a target with the same key already exists.
- exception ll.make.UndefinedTargetError[source]
Bases:
KeyError
Exception that will be raised when a target with the specified key doesn’t exist within the project.
- ll.make.getoutputs(project, since, input)[source]
Recursively iterate through the object
input
(if it’s atuple
,list
ordict
) and return a tuple containing:An object (
data
) of the same structure asinput
, where every action object encountered is replaced with the output of that action;A timestamp (
changed
) which the newest timestamp among all the change timestamps of the actions encountered.
If none of the actions has any data newer than
since
(i.e. none of the actions produced any new data)data
will benodata
.
- class ll.make.Action[source]
Bases:
object
An
Action
is responsible for transforming input data into output data. It may have no, one or many inputs which themselves may be other actions. It fetches, combines and transforms the output data of those actions and returns its own output data.- get(project, since)[source]
This method (i.e. the implementations in subclasses) is the workhorse of
ll.make
.get()
must return the output data of the action if this data has changed sincesince
(which is adatetime.datetime
object in UTC). If the data hasn’t changed sincesince
the special objectnodata
must be returned.In both cases the action must make sure that the data is internally consistent, i.e. if the input data is the output data of other actions
self
has to ensure that those other actions update their data too, independent from the fact whetherget()
will return new data or not.Two special values can be passed for
since
:bigbang
This timestamp is older than any timestamp that can appear in real life. Since all data is newer than this,
get()
must always return output data.bigcrunch
This timestamp is newer than any timestamp that can appear in real life. Since there can be no data newer than this,
get()
can only return output data in this case if ensuring internal consistency resulted in new data.
In all cases
get()
must set the instance attributechanged
to the timestamp of the last change to the data before returning. In most cases this if the newestchanged
timestamp of the input actions.
- execute(project, *args, **kwargs)[source]
Execute the action: transform the input data in
args
andkwargs
and return the resulting output data. This method must be implemented in subclasses.
- getkey()[source]
Get the nearest key from
self
or its inputs. This is used byModuleAction
for the filename.
- call(*args, **kwargs)[source]
Return a
CallAction
for callingself
s output with positional arguments fromargs
and keyword arguments fromkwargs
.
- getattr(attrname)[source]
Return a
GetAttrAction
for gettingself
s attribute namedattrname
.
- callattr(attrname, *args, **kwargs)[source]
Return a
CallAttrAction
for callingself
s attribute namedattrname
with positional arguments fromargs
and keyword arguments fromkwargs
.
- __iter__()[source]
Return an iterator over the input actions of
self
.
- iterallinputs()[source]
Return an iterator over all input actions of
self
(i.e. recursively).
- findpaths(input)[source]
Find dependency paths leading from
self
to the other actioninput
. I.e. ifself
depends directly or indirectly oninput
, this generator will produce all pathsp
wherep[0] is self
andp[-1] is input
andp[i+1] in p[i]
for alli
inrange(len(p)-1)
.
- class ll.make.ObjectAction[source]
Bases:
Action
An
ObjectAction
returns an object.
- class ll.make.TransformAction[source]
Bases:
Action
A
TransformAction
depends on exactly one input action and transforms the input data into output data.
- class ll.make.CollectAction[source]
Bases:
TransformAction
A
CollectAction
is aTransformAction
that simply outputs its input data unmodified, but updates a number of other actions in the process.- addinputs(*otherinputs)[source]
Register all actions in
otherinputs
as additional actions that have to be updated beforeself
is updated.
- class ll.make.PhonyAction[source]
Bases:
Action
A
PhonyAction
doesn’t do anything. It may depend on any number of additional input actions which will be updated when this action gets updated. If there’s new data from any of these actions, aPhonyAction
will returnNone
(andnodata
otherwise as usual).- __init__(*inputs, **kwargs)[source]
Create a
PhonyAction
object.doc
describes the action and is printed by the methodProject.writephonytargets()
.
- addinputs(*inputs)[source]
Register all actions in
inputs
as additional actions that have to be updated onceself
is updated.
- class ll.make.FileAction[source]
Bases:
TransformAction
A
FileAction
is used for reading and writing files (and other objects providing the appropriate interface).- __init__(key, input=None, encoding=None, errors=None)[source]
Create a
FileAction
object withkey
as the “filename”.key
must be an object that provides a methodopen()
for opening readable and writable streams to the file.input
is the data written to the file (or the action producing the data).encoding
is the encoding to be used for reading/writing. Ifencoding
isNone
binary i/o will be used.errors
is the codec error handling name for encoding/decoding text.
- write(project, data)[source]
Write
data
to the file and return it.
- read(project)[source]
Read the content from the file and return it.
- get(project, since)[source]
If a
FileAction
object doesn’t have an input action it reads the input file and returns the content if the file has changed sincesince
(otherwisenodata
is returned).If a
FileAction
object does have an input action and the output data from this input action is newer than the fileself.key
the data will be written to the file. Otherwise (i.e. the file is up to date) the data will be read from the file.
- chmod(mode=420)[source]
Return a
ModeAction
that will change the file permissions ofself
tomode
.
- chown(user=None, group=None)[source]
Return an
OwnerAction
that will change the user and/or group ownership ofself
.
- class ll.make.MkDirAction[source]
Bases:
TransformAction
This action creates the a directory (passing through its input data).
- __init__(key, mode=511)[source]
Create a
MkDirAction
instance.mode
(which defaults to0o777
) will be used as the permission bit pattern for the new directory.
- execute(project, data)[source]
Create the directory with the permission bits specified in the constructor.
- class ll.make.PipeAction[source]
Bases:
TransformAction
This action pipes the input through an external shell command.
- __init__(input, command)[source]
Create a
PipeAction
instance.command
is the shell command to be executed (which must read it’s input from stdin and write its output to stdout).
- class ll.make.CacheAction[source]
Bases:
TransformAction
A
CacheAction
is aTransformAction
that passes through its input data, but caches it, so that it can be reused during the same build round.
- class ll.make.GetAttrAction[source]
Bases:
TransformAction
This action gets an attribute from its input object.
- class ll.make.CallAction[source]
Bases:
Action
This action calls a function or any other callable object with a number of arguments. Both positional and keyword arguments are supported and the function and the arguments can be static objects or actions.
- class ll.make.CallAttrAction[source]
Bases:
Action
This action calls an attribute of an object with a number of arguments. Both positional and keyword arguments are supported and the object, the attribute name and the arguments can be static objects or actions.
- class ll.make.CommandAction[source]
Bases:
TransformAction
This action executes a system command (via
os.system()
) and passes through the input data.- __init__(command, input=None)[source]
Create a new
CommandAction
object.command
is the command that will executed whenexecute()
is called.
- class ll.make.ModeAction[source]
Bases:
TransformAction
ModeAction
changes file permissions and passes through the input data.- __init__(input=None, mode=420)[source]
Create an
ModeAction
object.mode
(which defaults to0644
) will be use as the permission bit pattern.
- execute(project, data, mode)[source]
Change the permission bits of the file
self.getkey()
.
- class ll.make.OwnerAction[source]
Bases:
TransformAction
OwnerAction
changes the user and/or group ownership of a file and passes through the input data.- __init__(input=None, user=None, group=None)[source]
Create a new
OwnerAction
object.user
can either be a numerical user id or a user name orNone
. If it isNone
no user ownership will be changed. The same applies togroup
.
- execute(project, data, user, group)[source]
Change the ownership of the file
self.getkey()
.
- class ll.make.ModuleAction[source]
Bases:
TransformAction
This action will turn the input string into a Python module.
- __init__(input=None)[source]
Create an
ModuleAction
.This object must have an input action (which might be a
FileAction
that creates the source file).
- addinputs(*inputs)[source]
Register all actions in
inputs
as modules used by this module. These actions must beModuleAction
objects too.Normally it isn’t necessary to call the method directly. Instead fetch the required module inside your module like this:
from ll import make mymodule = make.currentproject.get("mymodule.py")
This will record your module as depending on
mymodule
, so ifmymodule
changes, your module will be reloaded too. For this to work you need to have anModuleAction
added to the project with the key"mymodule.py"
.
- class ll.make.FOPAction[source]
Bases:
TransformAction
This action transforms an XML string (containing XSL-FO) into PDF. For it to work Apache FOP is required. The command line is hardcoded but it’s simple to overwrite the class attribute
command
in a subclass.
- class ll.make.Project[source]
Bases:
dict
A
Project
collects allAction
objects from a project. It is responsible for initiating the build process and for generating a report about the progress of the build process.- strtimedelta(delta)[source]
Return a nicely formatted and colored string for the
datetime.timedelta
valuedelta
.delta
may also beNone
in with case"0"
will be returned.
- strdatetime(dt)[source]
Return a nicely formatted and colored string for the
datetime.datetime
valuedt
.
- strcounter(counter)[source]
Return a nicely formatted and colored string for the counter value
counter
.
- strerror(text)[source]
Return a nicely formatted and colored string for the error text
text
.
- strkey(key)[source]
Return a nicely formatted and colored string for the action key
key
.
- straction(action)[source]
Return a nicely formatted and colored string for the action
action
.
- __setitem__(key, target)[source]
Add the action
target
toself
as a target and register it under the keykey
.
- add(target, key=None)[source]
Add the action
target
as a target toself
. Ifkey
is notNone
,target
will be registered under this key, otherwise it will be registered under its own key (i.e.target.key
).
- __getitem__(key)[source]
Return the target with the key
key
. If an key can’t be found, it will be wrapped in all.url.URL
object and retried. Ifkey
still can’t be found aUndefinedTargetError
will be raised.
- has_key(key)[source]
Return whether the target with the key
key
exists in the project.
- __contains__(key)[source]
Return whether the target with the key
key
exists in the project.
- create()[source]
Create all dependencies for the project. Overwrite in subclasses.
This method should only be called once, otherwise you’ll get lots of
RedefinedTargetWarning
s. But you can callclear()
to remove all targets before callingcreate()
. You can also use the methodrecreate()
for that.
- argparser()[source]
Return an
argparse
parser for parsing the command line arguments. This can be overwritten in subclasses to add more arguments.
- parseargs(args=None)[source]
Use the parser returned by
argparser()
to parse the argument sequenceargs
, modifyself
accordingly and return the result of the parsersparse_args()
call.
- get(target)[source]
Get up-to-date output data from the target
target
(which must be an action registered withself
(or the id of one). During the call the global variablecurrentproject
will be set toself
.
- build(*targets)[source]
Rebuild all targets in
targets
. Items intargets
must be actions registered withself
(or their ids).
- buildwithargs(args=None)[source]
For calling make scripts from the command line.
args
defaults tosys.argv
. Any positional arguments in the command line will be treated as target ids. If there are no positional arguments, a list of all registeredPhonyAction
objects will be output.
- write(*texts)[source]
All screen output is done through this method. This makes it possible to redirect the output (e.g. to logfiles) in subclasses.
- writeln(*texts)[source]
All screen output is done through this method. This makes it possible to redirect the output (e.g. to logfiles) in subclasses.
- writeerror(*texts)[source]
Output an error.
- warn(warning, stacklevel)[source]
Issue a warning through the Python warnings framework
- writestacklevel(level, *texts)[source]
Output
texts
indentedlevel
levels.
- writestack(*texts)[source]
Output
texts
indented properly for the current nesting of action execution.
- writestep(action, *texts)[source]
Output
texts
as the description of the data transformation done by the actionarction
.
- writenote(action, *texts)[source]
Output
texts
as the note for the data transformation done by the actionaction
.
- writecreatedone()[source]
Can be called at the end of an overwritten
create()
to report the number of registered targets.
- writephonytargets()[source]
Show a list of all
PhonyAction
objects in the project and their documentation.
- findpaths(target, source)[source]
Find dependency paths leading from the action
target
to the actionsource
.