Initial import to Tizen
[profile/ivi/python-twisted.git] / doc / historic / 2003 / pycon / releasing / releasing.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2 <html>
3 <head>
4 <title>Managing the Release of a Large Python Project</title>
5 </head>
6
7 <body>
8 <h1>Managing the Release of a Large Python Project</h1>
9
10 <ul>
11 <li>Christopher Armstrong <a href="mailto:radix@twistedmatrix.com">radix@twistedmatrix.com</a></li>
12 <li>Moshe Zadka <a href="mailto:moshez@twistedmatrix.com">moshez@twistedmatrix.com</a></li>
13 </ul>
14
15 <h2>Abstract</h2>
16 <p>
17
18 Twisted is a Python networking framework. At last count, the project
19 contains nearly 60,000 lines of effective code (not comments or blank
20 lines). When preparing a release, many details must be checked, and
21 many steps must be followed. We describe here the technologies and
22 tools we use, and explain how we built tools on top of them which help
23 us make releasing as painless as possible.
24
25 </p>
26
27 <h2>Introduction</h2>
28 <p>
29
30 One of the virtues of Python is the ease of distributing code. Its
31 module system and the lack of necessity of compilation are what make
32 this possible. This means that for simple Python projects, nothing
33 more complicated then tar is needed to prepare a distribution of a
34 library. However, Twisted has auto-generated documentation in several
35 formats, including docstring generated documentation, HOWTOs written
36 in HTML, and manpages written in nroff. As Twisted grew more complex
37 and popular, a detailed procedure for putting out a release was made
38 necessary. However, human fallibility being what it is, it was decided
39 that most of these steps should be automated.
40
41 </p>
42
43 <h2>Overview of Steps</h2>
44 <p>
45
46 Despite heavy automation, there are still a number of manual steps
47 involved in the release process. We've reduced the amount of manual
48 steps quite a bit, and most of what's left is not fully automatable,
49 although the process could be made easier (see <q>Future
50 Directions</q> below).
51
52 </p>
53
54 <ul>
55   <li>Test
56   <ul>
57     <li>Unit tests</li>
58     <li>Acceptance tests</li>
59     <li>Pre-release tests</li>
60   </ul>
61   </li>
62   <li>Update the Changelog and README files</li>
63   <li>Run the release script
64   <ul>
65     <li>unix runs admin/release-twisted</li>
66     <li>Win32 runs win32/bdist_wininst.bat</li>
67   </ul>
68   </li>
69   <li>Deploy: update twisted deployment on twistedmatrix.com</li>
70   <li>Upload to SourceForge mirror</li>
71   <li>Update Website</li>
72 </ul>
73
74
75
76 <h2>Testing</h2>
77
78 <p>
79
80 Twisted has three categories of tests: unit, acceptance, and
81 pre-release. Testing is an important part of releasing quality
82 software, of course, so these will be explained.
83
84 </p>
85
86
87 <p>
88
89 Unit tests are run as often as possible by each of the developers as
90 they write code, and must pass before they commit any changes to
91 CVS. While the Twisted team tries to follow the XP practice of
92 ensuring all code is releasable, this isn't always true. Thus, running
93 the unit tests on several platforms before releasing is necessary.
94 Our BuildBot runs the unit tests constantly on several hosts and
95 multiple platforms, so the <a
96 href="http://twistedmatrix.com/users/warner.twistd/">status page</a>
97 is simply checked for green lights before a release.
98
99 </p>
100
101 <p>
102
103 Acceptance tests (which, unfortunately, are not quite the same as <a
104 href="http://xprogramming.org/">Extreme Programming's</a> Acceptance
105 Tests) are simply interactive tests of various Twisted services. There
106 is a script that executes several system commands that use the Twisted
107 end-user executables and start several clients (web browsers, IRC
108 clients, etc) to allow the user to interactively test the different
109 services that Twisted offers. These are only routinely run before a
110 release, but we also encourage developers to run these before they
111 make major changes.
112
113 </p>
114
115 <p>
116
117 The pre-release tests are for ensuring the web server (One of the most
118 popular parts of Twisted, and which the twistedmatrix.com web site
119 uses) runs correctly in a semi-production environment. The script
120 starts up a web server on twistedmatrix.com, similar to the one on
121 port 80, but on an out-of-the-way port. <q>lynx</q> is then run
122 several times, with URLs strategically chosen to test different
123 features of the web server. Afterwards, the log of the web server is
124 displayed and the user is to check for any errors.
125
126 </p>
127
128
129 <h2>The release-twisted Script</h2>
130
131 <p>
132
133 Like many other build/release systems, the automated parts of our
134 release system started out as a number of small shell
135 scripts. Eventually these became a single Python script which was a
136 large improvement, but still had many problems, especially since our
137 release process became more complex (documentation generation,
138 different types of archive formats, etc). This led to problems with
139 steps in the middle of the process breaking; the release manager would
140 need to restart the entire thing, or enter the remaining commands
141 manually.
142
143 </p>
144
145 <p>
146
147 The solution that we came up with was a simple framework for
148 pseudo-transactions; Every step of the process is implemented with a
149 class that has <code class="python">doIt</code> and <code
150 class="python">undoIt</code> methods. Each step also has a
151 command-line argument associated with it, so a typical run of the
152 script looks something like this:
153
154 <pre class="shell">
155 $SOMEWHERE/admin/release-twisted -V $VERSION -o $LASTVERSION --checkout \
156 --release=/twisted/Releases --upver --tag --exp --dist --docs --balls \
157 --rel --deb --debi
158 </pre>
159
160 </p>
161
162 <h3>Transactions</h3>
163
164 <p>
165
166 As stated above, our transaction system is very simple. One of our
167 rather simple transaction classes is <code
168 class="python">Export</code>.
169
170 </p>
171
172
173 <pre class="python">
174 class Export(Transaction):
175     def doIt(self, opts):
176         print "Export"
177         root = opts['cvsroot']
178         ver = opts['release-version']
179         sh('cvs -d%s export -r release-%s Twisted' % (root, ver.replace('.', '_')))
180
181     def undoIt(self, opts, fail):
182         sh('rm -rf Twisted')
183 </pre>
184
185
186 <p>
187
188 One useful feature to note is the <code
189 class="python">sensitiveUndo</code> attribute on Transaction
190 classes. If a transaction has this set, the user will be prompted
191 before running the <code class="python">undoIt</code> method. This is
192 useful for very long-running processes, like documentation generation,
193 debian package building, and uploading to sourceforge. If something
194 goes wrong in the middle of one of these processes, we want to give
195 the user a chance to manually fix the problem rather than redoing the
196 entire transaction. They can then continue from the next command by
197 omitting the commands that have already been accomplished from the
198 <code class="shell">release-twisted</code> arguments.
199
200 </p>
201
202 <p>
203
204 A list of all of the transactions defined in release-twisted follows.
205
206 </p>
207
208 <dl>
209 <dt>CheckOut</dt>
210 <dd>
211
212   checks out the latest revision of Twisted from CVS and puts it in
213   the <q>Twisted CVS</q> directory.
214
215 </dd>
216
217 <dt>UpdateVersion</dt>
218 <dd>
219
220   changes the version number of the current release -- updating
221   twisted/copyright.py (the canonical location for the current
222   version) and a few other text files where the current version is
223   mentioned.
224
225 </dd>
226
227
228 <dt>Tag</dt>
229 <dd>
230
231   tags the revisions in the current source tree with the version
232   passed in on the command line.
233
234 </dd>
235
236
237 <dt>Export</dt>
238
239 <dd>
240
241   runs the cvs <q>export</q> command, which is similar to
242   <q>checkout</q>, but leaves out CVS support directories; this is
243   what we package up in the archives.
244
245 </dd>
246
247
248 <dt>PrepareDist</dt>
249 <dd>
250
251   simply copies the directory containing the version of Twisted to be
252   released to a new directory specifically for the release
253   process. The reason that we have this extra copy is that sometimes
254   one will want to create a release from a directory that wasn't
255   created from the <q>Export</q> command; having the release script
256   munge that directory in-place would be impolite.
257
258 </dd>
259
260
261 <dt>GenerateDocs</dt>
262
263 <dd>
264
265   generates the various documentation: HTML API documentation (via
266   Epydoc), HTML, PostScript, and PDF howto documentation (via
267   twisted.lore), and HTML man-pages (via lore, converted from the
268   nroff source).
269
270 </dd>
271
272 <dt>CreateTarballs</dt>
273 <dd>
274
275   creates the various archives that each Twisted release involves:
276   tarred and gzipped or bzip2ed versions of archives with code plus
277   documentation, code without documentation, and only documentation.
278
279 </dd>
280
281
282 <dt>Release</dt>
283
284 <dd>
285
286   copies all of the archives to a directory specified by the --release
287   parameter. This is meant to be a publically accessible directory,
288   thus the name <q>Release</q>.
289
290 </dd>
291
292 <dt>MakeDebs</dt>
293
294 <dd>
295
296   creates the .deb packages and support files for the Twisted Debian
297   packages.
298   
299 </dd>
300
301 <dt>InstallDebs</dt>
302
303 <dd>
304
305   Creates an apt-gettable Debian package repository in the
306   (unfortunately hard-coded) <q>/twisted/Debian</q> directory.
307
308 </dd>
309
310 <dt>Sourceforge</dt>
311
312 <dd>
313   
314   uploads the archives and debian packages to Twisted's sourceforge
315   mirror at <a
316   href="http://twisted.sourceforge.net">http://twisted.sourceforge.net/</a>.
317
318 </dd>
319
320
321 <dt>UpgradeDebian</dt>
322
323 <dd>
324
325   Installs the recently-generated Debian packages via <q>dpkg</q> on
326   the local machine.
327   
328 </dd>
329   
330 </dl>
331
332
333 <h2>setup.py</h2>
334
335 <p>
336
337 Twisted has an extensive and very customized setup.py script. We have
338 a number of C extension modules and try to ensure that they all build,
339 or at least fail gracefully, on win32, Mac OSX, Linux and other
340 popular unix-style OSes.
341
342 </p>
343
344 <p>
345
346 We have overridden three of the distutils <q>command classes</q>:
347 <code class="python">build_ext</code>, <code
348 class="python">install_scripts</code>, and <code
349 class="python">install_data</code>.
350
351 </p>
352
353
354 <h3>Building C extensions</h3>
355
356 <p>
357
358 <code class="python">build_ext_twisted</code> detects, based on
359 various features of the platform, which C extensions to build. It
360 overrides the <code class="python">build_extensions</code> method to
361 first check which C extensions are appropriate to build for the
362 current platform before proceeding as normal (by calling the
363 superclass's <code class="python">build_extensions</code>). The
364 module-detection consists of several simple tests for platform
365 features and conditional additions to the `extensions' attribute. One
366 especially useful feature is the <code
367 class="python">_check_header</code> method, which takes the name of an
368 arbitrary head file and tries to compile (via the distutil's C
369 compiler interafce) a simple C file that only #includes it.
370
371 </p>
372
373
374 <h3>Installing scripts</h3>
375
376
377 <p>
378
379 <code class="python">install_data_twisted</code> ensures that the data
380 files are installed along-side the python modules in the twisted
381 package. This is accomplished with the incantation:
382
383 </p>
384
385 <pre class="python">
386 class install_data_twisted(install_data):
387     def finalize_options (self):
388         self.set_undefined_options('install',
389             ('install_lib', 'install_dir')
390         )
391         install_data.finalize_options(self)
392 </pre>
393
394
395
396 <h3>Windows Releases</h3>
397
398 <!--
399 <p>
400 This section will cover the problems with packaging Python projects
401 for windows, especially ones which contain scripts. The problem of
402 clickability is especially acute, as windows determines types by
403 extensions and not by #! lines.
404 </p>
405 -->
406
407 <p>
408
409 Packaging software for windows involves a unique set of problems. The
410 problem of clickability is especially acute; Several customizations to
411 the distutils setup had to be made.
412
413 </p>
414
415 <p>
416
417 The first customization was to make the <q>scripts</q> end with a
418 <q>.py</q> extension, since Windows relies on extension rather than a
419 she-bang line to specify what interpreter should execute a file. This
420 was accomplished by overriding the <code
421 class="python">install_scripts</code> command, like so:
422
423 </p>
424
425 <pre class="python">
426 class install_scripts_twisted(install_scripts):
427     """Renames scripts so they end with '.py' on Windows."""
428
429     def run(self):
430         install_scripts.run(self)
431         if os.name == "nt":
432             for file in self.get_outputs():
433                 if not file.endswith(".py"):
434                     os.rename(file, file + ".py")
435 </pre>
436
437
438 <p>
439
440 We also wanted to have a Start-menu group with a number of icons for
441 running different Twisted programs. This was accomplished with a
442 post-install script specified with the command-line parameter
443 <code class="shell">--install-script=twisted_postinstall.py</code>.
444
445 </p>
446
447
448
449 <h2>Future Directions</h2>
450
451 <p>
452
453 The theme is, of course, automation, and there are still many manual
454 steps involved in a Twisted release. The currently most annoying step
455 is updating the documentation and downloads section of the
456 twistedmatrix.com website. Automating this would be a major
457 improvement to the time it takes from the running of the release
458 script to a fully completed release.
459
460 </p>
461
462 <p>
463
464 Another major improvement will involve further integration with
465 BuildBot. Currently we have BuildBot running unit tests, building C
466 extensions, and generating documentation on several hosts. Eventually
467 we would like to have it constantly generating full release archives,
468 and have an additional web form for <q>finalizing</q> any particular
469 build that we deem releasable. The result would be uploading the
470 release to the mirrors and updating the website.
471
472 </p>
473
474 <p>
475
476 The tagging scheme used by the release-twisted scripts can sometimes
477 be problematic. If we find serious problems in the code-base after the
478 Tag command is executed (which is fairly early in the process), we are
479 forced to fix the bug and increase the version number. This can be
480 prevented by, instead of making the official tag, using the unofficial
481 tag <q>releasing-$version</q> (as opposed to <q>release-$version</q>)
482 at that early stage. Once most of the steps are complete, the official
483 tag will be made. If something in between goes wrong, we can just
484 re-use the unofficial <q>releasing-$version</q> tag and not worry
485 about users trying to use that tag.
486
487 </p>
488
489
490 </body>
491 </html>