|
1 Repeatable buildouts: controlling eggs used |
|
2 =========================================== |
|
3 |
|
4 One of the goals of zc.buildout is to provide enough control to make |
|
5 buildouts repeatable. It should be possible to check the buildout |
|
6 configuration files for a project into a version control system and |
|
7 later use the checked in files to get the same buildout, subject to |
|
8 changes in the environment outside the buildout. |
|
9 |
|
10 An advantage of using Python eggs is that depenencies of eggs used are |
|
11 automatically determined and used. The automatic inclusion of |
|
12 depenent distributions is at odds with the goal of repeatable |
|
13 buildouts. |
|
14 |
|
15 To support repeatable buildouts, a versions section can be created |
|
16 with options for each distribution name whos version is to be fixed. |
|
17 The section can then be specified via the buildout versions option. |
|
18 |
|
19 To see how this works, we'll create two versions of a recipe egg: |
|
20 |
|
21 >>> mkdir('recipe') |
|
22 >>> write('recipe', 'recipe.py', |
|
23 ... ''' |
|
24 ... class Recipe: |
|
25 ... def __init__(*a): pass |
|
26 ... def install(self): |
|
27 ... print 'recipe v1' |
|
28 ... return () |
|
29 ... update = install |
|
30 ... ''') |
|
31 |
|
32 >>> write('recipe', 'setup.py', |
|
33 ... ''' |
|
34 ... from setuptools import setup |
|
35 ... setup(name='spam', version='1', py_modules=['recipe'], |
|
36 ... entry_points={'zc.buildout': ['default = recipe:Recipe']}, |
|
37 ... ) |
|
38 ... ''') |
|
39 |
|
40 >>> write('recipe', 'README', '') |
|
41 |
|
42 >>> print system(buildout+' setup recipe bdist_egg'), # doctest: +ELLIPSIS |
|
43 Running setup script 'recipe/setup.py'. |
|
44 ... |
|
45 |
|
46 >>> rmdir('recipe', 'build') |
|
47 |
|
48 >>> write('recipe', 'recipe.py', |
|
49 ... ''' |
|
50 ... class Recipe: |
|
51 ... def __init__(*a): pass |
|
52 ... def install(self): |
|
53 ... print 'recipe v2' |
|
54 ... return () |
|
55 ... update = install |
|
56 ... ''') |
|
57 |
|
58 >>> write('recipe', 'setup.py', |
|
59 ... ''' |
|
60 ... from setuptools import setup |
|
61 ... setup(name='spam', version='2', py_modules=['recipe'], |
|
62 ... entry_points={'zc.buildout': ['default = recipe:Recipe']}, |
|
63 ... ) |
|
64 ... ''') |
|
65 |
|
66 |
|
67 >>> print system(buildout+' setup recipe bdist_egg'), # doctest: +ELLIPSIS |
|
68 Running setup script 'recipe/setup.py'. |
|
69 ... |
|
70 |
|
71 and we'll configure a buildout to use it: |
|
72 |
|
73 >>> write('buildout.cfg', |
|
74 ... ''' |
|
75 ... [buildout] |
|
76 ... parts = foo |
|
77 ... find-links = %s |
|
78 ... |
|
79 ... [foo] |
|
80 ... recipe = spam |
|
81 ... ''' % join('recipe', 'dist')) |
|
82 |
|
83 If we run the buildout, it will use version 2: |
|
84 |
|
85 >>> print system(buildout), |
|
86 Getting distribution for 'spam'. |
|
87 Got spam 2. |
|
88 Installing foo. |
|
89 recipe v2 |
|
90 |
|
91 We can specify a versions section that lists our recipe and name it in |
|
92 the buildout section: |
|
93 |
|
94 >>> write('buildout.cfg', |
|
95 ... ''' |
|
96 ... [buildout] |
|
97 ... parts = foo |
|
98 ... find-links = %s |
|
99 ... versions = release-1 |
|
100 ... |
|
101 ... [release-1] |
|
102 ... spam = 1 |
|
103 ... eggs = 2.2 |
|
104 ... |
|
105 ... [foo] |
|
106 ... recipe = spam |
|
107 ... ''' % join('recipe', 'dist')) |
|
108 |
|
109 Here we created a release-1 section listing the version 1 for the spam |
|
110 distribution. We told the buildout to use it by specifying release-1 |
|
111 as in the versions option. |
|
112 |
|
113 Now, if we run the buildout, we'll use version 1 of the spam recipe: |
|
114 |
|
115 >>> print system(buildout), |
|
116 Getting distribution for 'spam==1'. |
|
117 Got spam 1. |
|
118 Uninstalling foo. |
|
119 Installing foo. |
|
120 recipe v1 |
|
121 |
|
122 Running the buildout in verbose mode will help us get information |
|
123 about versions used. If we run the buildout in verbose mode without |
|
124 specifying a versions section: |
|
125 |
|
126 >>> print system(buildout+' buildout:versions= -v'), # doctest: +ELLIPSIS |
|
127 Installing 'zc.buildout', 'setuptools'. |
|
128 We have a develop egg: zc.buildout 1.0.0. |
|
129 We have the best distribution that satisfies 'setuptools'. |
|
130 Picked: setuptools = 0.6 |
|
131 Installing 'spam'. |
|
132 We have the best distribution that satisfies 'spam'. |
|
133 Picked: spam = 2. |
|
134 Uninstalling foo. |
|
135 Installing foo. |
|
136 recipe v2 |
|
137 |
|
138 We'll get output that includes lines that tell us what versions |
|
139 buildout chose a for us, like:: |
|
140 |
|
141 zc.buildout.easy_install.picked: spam = 2 |
|
142 |
|
143 This allows us to discover versions that are picked dynamically, so |
|
144 that we can fix them in a versions section. |
|
145 |
|
146 If we run the buildout with the versions section: |
|
147 |
|
148 >>> print system(buildout+' -v'), # doctest: +ELLIPSIS |
|
149 Installing 'zc.buildout', 'setuptools'. |
|
150 We have a develop egg: zc.buildout 1.0.0. |
|
151 We have the best distribution that satisfies 'setuptools'. |
|
152 Picked: setuptools = 0.6 |
|
153 Installing 'spam'. |
|
154 We have the distribution that satisfies 'spam==1'. |
|
155 Uninstalling foo. |
|
156 Installing foo. |
|
157 recipe v1 |
|
158 |
|
159 We won't get output for the spam distribution, which we didn't pick, |
|
160 but we will get output for setuptools, which we didn't specify |
|
161 versions for. |
|
162 |
|
163 You can request buildout to generate an error if it picks any |
|
164 versions: |
|
165 |
|
166 >>> write('buildout.cfg', |
|
167 ... ''' |
|
168 ... [buildout] |
|
169 ... parts = foo |
|
170 ... find-links = %s |
|
171 ... versions = release-1 |
|
172 ... allow-picked-versions = false |
|
173 ... |
|
174 ... [release-1] |
|
175 ... spam = 1 |
|
176 ... eggs = 2.2 |
|
177 ... |
|
178 ... [foo] |
|
179 ... recipe = spam |
|
180 ... ''' % join('recipe', 'dist')) |