~ntt-pf-lab/nova/monkey_patch_notification

« back to all changes in this revision

Viewing changes to vendor/Twisted-10.0.0/doc/historic/2003/pycon/releasing/releasing.html

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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>