PageRenderTime 82ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/desktop/core/ext-py/Twisted/doc/historic/2003/pycon/releasing/releasing.html

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