-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.py
126 lines (101 loc) · 5.17 KB
/
setup.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
from setuptools import setup
setup(name='buildbit',
version='0.4.0',
description='Yet another build system inspired by make and python decorators',
classifiers=[
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Environment :: Console",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Natural Language :: English",
"Operating System :: OS Independent",
"Topic :: Software Development :: Build Tools"
],
author='robochat',
author_email='[email protected]',
url='https://github.com/robochat/buildbit',
license='GPLv3',
keywords='make build',
#packages=[],
#package_data={'?' :['']},
#py_modules=[''],
#scripts=[],
#data_files=[('',[,'README.md'])],
install_requires=['orderedset','unittest2'],
#zip_safe=False,
long_description="""\
This is a build system for compiling programs or performing tasks involving many files.
Most importantly it tries to do rebuilds efficiently by only rerunning those tasks for
which prerequisite files have changed. It is heavily heavily inspired by GNU make but
instead of being a DSL around shell script snipnets, it is used from within a python
script and so has all of the features of python available for use.
The main interface is an object factory called Rule, that defines the dependency graph. ::
Rule(targets=[],reqs=[],order_only=[],func=None,PHONY=False,shared=False)
The recipe functions can be supplied as an argument or assigned to the 'func' attribute
of the returned object or Rule can be used as a function decorator. The recipe functions
is either a python function or a command line string. The command lines string/sequence of
strings (see subprocess module) can contain various space separated list of paths using
the following parameters:
* targets, $@
* allreqs, $+
* reqs, $^
* order_only, $|
* updated_only, $?
which we can include using python format specification i.e. ``ls {reqs} > {targets[0]}``.
Alternatively, we can access the rule instance directly using
``ls {self.reqs} > {self.targets[0]}``. Similarly, the build functions can optionally take
a single parameter which will be passed the rule instance so that they can access the
rule attributes in a similar manner i.e. ::
def changed(self):
print self.updated_only
(I tend to use self as the parameter name even though the functions are not bound methods
of the rule instances).
The targets, reqs and order_only parameters of Rule will accept sequences or simple strings
of file paths. These can also contain wildcards conforming to the format used by the
python standard libraries fnmatch or glob where metacharacters are ``[][!]*?``. In addition
the wildcard character '``%``' can be used as in gmake to create pattern rules.
The system calculated build sequence should be independent of the order of the rules and
the order of their prerequisites in order to avoid surprising behaviour. For this reason
meta rules are considered separately from explicit rules during the build sequence calculation
i.e. an 'instantiated' meta rule doesn't get included in the explicit rule list which could
affect the processing of the rules that come after it. However, the presence of files in
the build directory can affect wildcard prerequisites and change the behaviour of rebuilds
just like with gmake or any similar system.
Here is a small example of usage::
from bob import Rule as rule
from sh import touch
rule('tests',None,func=['mkdir','{targets}'])
r1 = rule('tests/test1.txt',None,order_only='tests')
r2 = rule('tests/test2.txt',None)
r3 = rule('tests/test3.txt',None)
@rule(['tests/foo.txt','tests/foo2.txt'],'tests/test*.txt',shared=True)
@rule('tests/ex%.txt','tests/test%.txt')
def mytouch(self):
touch(self.targets)
for r in r1,r2,r3:
r.func = mytouch
rule('All',['tests','tests/foo2.txt','tests/ex2.txt'],PHONY=True)
if __name__=="__main__":
rule.main() #supplies a simple commandline interface
# Can alternatively easily run buildbit from within script.
if False: #__name__=="__main__":
buildseq = rule.calc_build('All')
print buildseq
response=raw_input("run build? [(y)es/(n)o]")
if response in ('y','yes'):
rule.build(buildseq)
There are some differences from GNU make. In buildbit, we can explicitly decide whether
we want rules to be shared between targets or not in order to have more efficient builds.
Wildcard prerequisites will search the rules with explicitly defined targets for any
matches as well as the filesystem. Also, pattern rules are not currently shared across
their targets unlike in gmake.
To Do
~~~~~
Add class for shared pattern rules
write unit tests
create dependency graphs (using graphviz)
""",
)