| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> |
| <html xmlns="http://www.w3.org/1999/xhtml"> |
| <head> |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> |
| <style type="text/css"> /* <![CDATA[ */ |
| @import "branding/css/tigris.css"; |
| @import "branding/css/inst.css"; |
| /* ]]> */</style> |
| <link rel="stylesheet" type="text/css" media="print" |
| href="branding/css/print.css"/> |
| <script type="text/javascript" src="branding/scripts/tigris.js"></script> |
| <title>Hacker's Guide to Subversion</title> |
| </head> |
| |
| <body> |
| <div class="app"> |
| |
| <h1 style="text-align: center;">Hacker's Guide to Subversion</h1> |
| |
| <p>If you are contributing code to the Subversion project, please read |
| this first.</p> |
| |
| <pre> |
| $LastChangedDate$ |
| </pre> |
| |
| |
| <!-- Other pages seem to use "h2" for ToC, but I think "h1" works |
| better, because the ToC is fundamentally different from other |
| sections and therefore it's confusing when it looks the same as |
| the others. --> |
| <div class="h1"><!-- no 'id' or 'title' attribute for ToC --> |
| <h1>Table of Contents</h1> |
| |
| <ul> |
| <li><a href="#participating" |
| >Participating in the community</a></li> |
| <li><a href="#docs" |
| >Theory and documentation</a></li> |
| <li><a href="#code-to-read" |
| >Code to read</a></li> |
| <li><a href="#directory-layout" |
| >Directory layout</a></li> |
| <li><a href="#coding-style" |
| >Coding style</a></li> |
| <li><a href="#secure-coding" |
| >Secure coding guidelines</a></li> |
| <li><a href="#destruction-of-stacked-resources" |
| >Destruction of stacked resources</a></li> |
| <li><a href="#documenting" |
| >Document everything</a></li> |
| <li><a href="#use-page-breaks" |
| >Using page breaks</a></li> |
| <li><a href="#error-messages" |
| >Error message conventions</a></li> |
| <li><a href="#other-conventions" |
| >Other conventions</a></li> |
| <li><a href="#apr-pools" |
| >APR pool usage conventions</a></li> |
| <li><a href="#apr-status-codes" |
| >APR status codes</a></li> |
| <li><a href="#exception-handling" |
| >Exception handling</a></li> |
| <li><a href="#automated-tests" |
| >Automated tests</a></li> |
| <li><a href="#write-test-cases-first" |
| >Writing test cases before code</a></li> |
| <li><a href="#server-debugging" |
| >Debugging the server</a></li> |
| <li><a href="#tracing-memory-leaks" |
| >Tracking down memory leaks</a></li> |
| <li><a href="#log-messages" |
| >Writing log messages</a></li> |
| <li><a href="#crediting" |
| >Crediting</a></li> |
| <li><a href="#patches" |
| >Patch submission guidelines</a></li> |
| <li><a href="#filing-issues" |
| >Filing bugs / issues</a></li> |
| <li><a href="#commit-access" |
| >Commit access</a></li> |
| <li><a href="#configury" |
| >The configuration/build system under unix</a></li> |
| <li><a href="#releasing" |
| >How to release a distribution tarball</a></li> |
| <li><a href="#release-numbering" |
| >Release numbering, compatibility, and deprecation</a></li> |
| <li><a href="#release-stabilization" |
| >Stabilizing and maintaining releases</a></li> |
| <li><a href="#tarball-signing" |
| >Signing source distribution packages</a></li> |
| <li><a href="#l10n" |
| >Localization (l10n)</a></li> |
| </ul> |
| |
| </div> |
| |
| |
| <div class="h2" id="participating" title="participating"> |
| <h2>Participating in the community</h2> |
| |
| <p>Although Subversion is originally sponsored and hosted by CollabNet |
| (<a href="http://www.collab.net">http://www.collab.net</a>), it's a |
| true open-source project under a BSD-style license. A number of |
| developers work for CollabNet, some work for other large companies |
| (such as RedHat), and many others are simply excellent volunteers who |
| are interested in building a better version control system.</p> |
| |
| <p>The community exists mainly through mailing lists and a Subversion |
| repository. To participate:</p> |
| |
| <p>Go to <a href="http://subversion.tigris.org/" |
| >http://subversion.tigris.org/</a> and</p> |
| |
| <ul> |
| <li><p>Join the "dev", "svn", and "announce" mailing lists. |
| The dev list, dev@subversion.tigris.org, is where almost all |
| discussion takes place. All development questions should go |
| there, though you might want to check the list archives first. |
| The "svn" list receives automated commit emails.</p></li> |
| |
| <li><p>Get a copy of the latest development sources from |
| <a href="http://svn.collab.net/repos/svn/trunk/" |
| >http://svn.collab.net/repos/svn/trunk/</a>. |
| <br /> |
| New development always takes place on trunk. Bugfixes, |
| enhancements, and new features are backported from there to the |
| various release branches.</p></li> |
| </ul> |
| |
| <p>There are many ways to join the project, either by writing code, or |
| by testing and/or helping to manage the bug database. If you'd like |
| to contribute, then look at:</p> |
| |
| <ul> |
| <li><p>The bugs/issues database |
| <a href="http://subversion.tigris.org/project_issues.html" |
| >http://subversion.tigris.org/project_issues.html</a></p></li> |
| |
| <li><p>The bite-sized tasks page |
| <a href="http://subversion.tigris.org/project_tasks.html" |
| >http://subversion.tigris.org/project_tasks.html</a></p></li> |
| </ul> |
| |
| <p>To submit code, simply send your patches to |
| dev@subversion.tigris.org. No, wait, first read the rest of this |
| file, <i>then</i> start sending patches to |
| dev@subversion.tigris.org. :-)</p> |
| |
| <p>To help manage the issues database, read over the issue summaries, |
| looking and testing for issues that are either invalid, or are |
| duplicates of other issues. Both kinds are very common, the first |
| because bugs often get unknowingly fixed as side effects of other |
| changes in the code, and the second because people sometimes file an |
| issue without noticing that it has already been reported. If you are |
| not sure about an issue, post a question to dev@subversion.tigris.org. |
| ("Subversion: We're here to help you help us!")</p> |
| |
| <p>Another way to help is to set up automated builds and test suite |
| runs of Subversion on some platform, and have the output sent to the |
| svn-breakage@subversion.tigris.org mailing list. See more details at |
| <a href="http://subversion.tigris.org/servlets/ProjectMailingListList" |
| >http://subversion.tigris.org/servlets/ProjectMailingListList</a> |
| in the description for the svn-breakage list.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="docs" title="docs"> |
| <h2>Theory and documentation</h2> |
| |
| <ol> |
| <li><p>Design</p> |
| |
| <p>A <a href="design.html">design spec</a> was written in June 2000, |
| and is a bit out of date. But it still gives a good theoretical |
| introduction to the inner workings of the repository, and to |
| Subversion's various layers.</p> |
| </li> |
| |
| <li><p>API documentation</p> |
| <p>The <a href="http://svn.collab.net/svn-doxygen/">API documentation</a> |
| is generated by Doxygen from the C header files and gives detailed |
| information about all functions, types and so on available in the |
| Subversion API. </p> |
| </li> |
| |
| <li> <p>Network Protocols</p> |
| |
| <p>The <a href="webdav-usage.html">WebDAV Usage</a> document is |
| an introduction to Subversion's ra_dav network protocol, which is |
| an extended dialect of HTTP and uses URLs beginning with |
| "http://" or "https://".</p> |
| |
| <p>The <a |
| href="http://svn.collab.net/repos/svn/trunk/subversion/libsvn_ra_svn/protocol" |
| >SVN Protocol</a> document contains a formal description of |
| Subversion ra_svn network protocol, which is a custom protocol |
| on port 3690 (by default), whose URLs begin with "svn://" or |
| "svn+ssh://".</p> |
| </li> |
| |
| <li><p>User Manual</p> |
| |
| <p>Version Control with Subversion is a book published by |
| O'Reilly that shows in detail how to effectively use Subversion. |
| The text of the book is free, and is actively being revised. |
| On-line versions are available |
| at <a href="http://svnbook.red-bean.com" |
| >http://svnbook.red-bean.com</a>. The XML source and |
| translations to other languages are maintained in their own |
| repository at <a href="http://svn.red-bean.com/svnbook" |
| >http://svn.red-bean.com/svnbook</a>.</p> |
| </li> |
| |
| <li><p>System notes</p> |
| |
| <p>A lot of the design ideas for particular aspects of the system |
| have been documented in individual files in the |
| <a href="http://svn.collab.net/repos/svn/trunk/notes/">notes/</a> |
| directory.</p> |
| </li> |
| |
| </ol> |
| |
| </div> |
| |
| |
| <div class="h2" id="code-to-read" title="code-to-read"> |
| <h2>Code to read</h2> |
| |
| <p>Before you can contribute code, you'll need to familiarize yourself |
| with the existing code base and interfaces.</p> |
| |
| <p>Check out a copy of Subversion (anonymously, if you don't yet have |
| an account with commit access) — so you can look at |
| the code.</p> |
| |
| <p>Within 'subversion/include/' are a bunch of header files with huge |
| doc comments. If you read through these, you'll have a pretty good |
| understanding of the implementation details. Here's a suggested |
| perusal order:</p> |
| |
| <ol> |
| <li><p>the basic building blocks: svn_string.h, svn_error.h, svn_types.h</p> |
| </li> |
| <li><p>useful utilities: svn_io.h, svn_path.h, svn_hash.h, svn_xml.h</p> |
| </li> |
| <li><p>the critical interface: svn_delta.h</p> |
| </li> |
| <li><p>client-side interfaces: svn_ra.h, svn_wc.h, svn_client.h</p> |
| </li> |
| <li><p>the repository and versioned filesystem: svn_repos.h, svn_fs.h</p> |
| </li> |
| </ol> |
| |
| <p>Subversion tries to stay portable by using only ANSI/ISO C and by |
| using the Apache Portable Runtime (APR) library. APR is the |
| portability layer used by the Apache httpd server, and more |
| information can be found at <a href="http://apr.apache.org/" |
| >http://apr.apache.org/</a>.</p> |
| |
| <p>Because Subversion depends so heavily on APR, it may be hard to |
| understand Subversion without first glancing over certain header files |
| in APR (look in 'apr/include/'):</p> |
| |
| <ul> |
| <li><p>memory pools: apr_pools.h</p></li> |
| <li><p>filesystem access: apr_file_io.h</p></li> |
| <li><p>hashes and arrays: apr_hash.h, apr_tables.h</p></li> |
| </ul> |
| |
| <p>Subversion also tries to deliver reliable and secure software. This |
| can only be achieved by developers who understand secure programming |
| in the C programming language. Please see 'notes/assurance.txt' for |
| the full rationale behind this. Specifically, you should make it a |
| point to carefully read David Wheeler's Secure Programming (as |
| mentioned in 'notes/assurance.txt'). If at any point you have |
| questions about the security implications of a change, you are urged |
| to ask for review on the developer mailing list.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="directory-layout" title="directory-layout"> |
| <h2>Directory layout</h2> |
| |
| <p>A rough guide to the source tree:</p> |
| |
| <ul> |
| <li><p><tt>doc/</tt><br /> |
| User and Developer documentation.</p> |
| </li> |
| <li><p><tt>www/</tt><br /> |
| Subversion web pages (live content at |
| <a href="http://subversion.tigris.org/" |
| >http://subversion.tigris.org/</a>).</p> |
| </li> |
| <li><p><tt>tools/</tt><br /> |
| Stuff that works with Subversion, but that Subversion doesn't |
| depend on. Code in tools/ is maintained collectively by the |
| Subversion project, and is under the same open source copyright as |
| Subversion itself.</p> |
| </li> |
| <li><p><tt>contrib/</tt><br /> |
| Stuff that works with Subversion, but that Subversion doesn't |
| depend on, and that is maintained by individuals who may or may |
| not participate in Subversion development. Code in contrib/ is |
| open source, but may have a different license or copyright holder |
| than Subversion itself.</p> |
| </li> |
| <li><p><tt>packages/</tt><br /> |
| Stuff to help packaging systems, like rpm and dpkg.</p> |
| </li> |
| <li><p><tt>subversion/</tt><br /> |
| Source code to Subversion itself (as opposed to external |
| libraries).</p> |
| </li> |
| <li><p><tt>subversion/include/</tt><br /> |
| Public header files for users of Subversion libraries.</p> |
| </li> |
| <li><p><tt>subversion/libsvn_fs/</tt><br /> |
| The versioning "filesystem" API.</p> |
| </li> |
| <li><p><tt>subversion/libsvn_repos/</tt><br /> |
| Repository functionality built around the `libsvn_fs' core.</p> |
| </li> |
| <li><p><tt>subversion/libsvn_delta/</tt><br /> |
| Common code for tree deltas, text deltas, and property deltas.</p> |
| </li> |
| <li><p><tt>subversion/libsvn_wc/</tt><br /> |
| Common code for working copies.</p> |
| </li> |
| <li><p><tt>subversion/libsvn_ra/</tt><br /> |
| Common code for repository access.</p> |
| </li> |
| <li><p><tt>subversion/libsvn_client/</tt><br /> |
| Common code for client operations.</p> |
| </li> |
| <li><p><tt>subversion/svn/</tt><br /> |
| The command line client.</p> |
| </li> |
| <li><p><tt>subversion/tests/</tt><br /> |
| Automated test suite.</p> |
| </li> |
| <li><p><tt>apr/</tt><br /> |
| Apache Portable Runtime library. (Note: This is not in the same |
| repository as Subversion. Read INSTALL for instructions on how to |
| get it if you don't already have it.)</p> |
| </li> |
| <li><p><tt>neon/</tt><br /> |
| Neon library from Joe Orton. (Note: This is not in the same |
| repository as Subversion. Read INSTALL for instructions on how to |
| get it if you don't already have it.)</p> |
| </li> |
| </ul> |
| |
| </div> |
| |
| |
| <div class="h2" id="coding-style" title="coding-style"> |
| <h2>Coding style</h2> |
| |
| <p>Subversion uses ANSI C, and follows the GNU coding standards, |
| except that we do not put a space between the name of a function and |
| the opening parenthesis of its parameter list. Emacs users can just |
| load svn-dev.el to get the right indentation behavior (most source |
| files here will load it automatically, if `enable-local-eval' is set |
| appropriately).</p> |
| |
| <p>Read <a href="http://www.gnu.org/prep/standards.html" |
| >http://www.gnu.org/prep/standards.html</a> for a full description of |
| the GNU coding standards. Below is a short example demonstrating the |
| most important formatting guidelines, including our |
| no-space-before-param-list-paren exception:</p> |
| |
| <pre> |
| char * /* func type on own line */ |
| argblarg(char *arg1, int arg2) /* func name on own line */ |
| { /* first brace on own line */ |
| if ((some_very_long_condition && arg2) /* indent 2 cols */ |
| || remaining_condition) /* new line before operator */ |
| { /* brace on own line, indent 2 */ |
| arg1 = some_func(arg1, arg2); /* NO SPACE BEFORE PAREN */ |
| } /* close brace on own line */ |
| else |
| { |
| do /* format do-while like this */ |
| { |
| arg1 = another_func(arg1); |
| } |
| while (*arg1); |
| } |
| } |
| </pre> |
| |
| <p>In general, be generous with parentheses even when you're sure |
| about the operator precedence, and be willing to add spaces and |
| newlines to avoid "code crunch". Don't worry too much about vertical |
| density; it's more important to make code readable than to fit that |
| extra line on the screen.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="secure-coding" title="secure-coding"> |
| <h2>Secure coding guidelines</h2> |
| |
| <p>Just like almost any other programming language, C has undesirable |
| features which enables an attacker to make your program fail in |
| predictable ways, often to the attacker's benefit. The goal of these |
| guidelines is to make you aware of the pitfalls of C as they apply to |
| the Subversion project. You are encouraged to keep these pitfalls in |
| mind when reviewing code of your peers, as even the most skilled and |
| paranoid programmers make occasional mistakes.</p> |
| |
| <p>Input validation is the act of defining legal input and rejecting |
| everything else. The code must perform input validation on all |
| untrusted input. </p> |
| |
| <p>Security boundaries:</p> |
| |
| <p>A security boundary in the Subversion server code must be |
| identified as such as this enables auditors to quickly determine the |
| quality of the boundary. Security boundaries exist where the running |
| code has access to information the user does not or where the code |
| runs with privileges above those of the user making the |
| request. Typical examples of such is code that does access control or |
| an application with the SUID bit set.</p> |
| |
| <p>Functions which make calls to a security boundary must include |
| validation checks of the arguments passed. Functions which themselves |
| are security boundaries should audit the input received and alarm when |
| invoked with improper values. </p> |
| |
| <p>[### todo: need some examples from Subversion here...]</p> |
| |
| <p>String operations:</p> |
| |
| <p>Use the string functions provided in apr_strings.h instead of |
| standard C library functions that write to strings. The APR functions |
| are safer because they do bounds-checking and dest allocation |
| automatically. Although there may be circumstances where it's |
| theoretically safe to use plain C string functions (such as when you |
| already know the lengths of the source and dest), please use the APR |
| functions anyway, so the code is less brittle and more reviewable.</p> |
| |
| <p>Password storage:</p> |
| |
| <p>Help users keep their passwords secret: When the client reads or |
| writes password locally, it should ensure that the file is mode |
| 0600. If the file is readable by other users, the client should exit |
| with a message that tells the user to change the filemode due to the |
| risk of exposure.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="destruction-of-stacked-resources" |
| title="destruction-of-stacked-resources"> |
| <h2>Destruction of stacked resources</h2> |
| |
| <p>Some resources need destruction to ensure correct functioning of the |
| application. Such resources include files, especially since open |
| files cannot be deleted on Windows.</p> |
| |
| <p>When writing an API which creates and returns a stream, in the |
| background this stream may be stacked on a file or other stream. To |
| ensure correct destruction of the resources the stream is built upon, |
| it must correctly call the destructors of the stream(s) it is built |
| upon (owns).</p> |
| |
| <p>At first in <a href="http://svn.haxx.se/dev/archive-2005-12/0487.shtml"> |
| http://svn.haxx.se/dev/archive-2005-12/0487.shtml</a> |
| and later in <a href="http://svn.haxx.se/dev/archive-2005-12/0633.shtml"> |
| http://svn.haxx.se/dev/archive-2005-12/0633.shtml</a> this |
| was discussed in more general terms for files, streams, editors and |
| window handlers.</p> |
| |
| <p>As Greg Hudson put it:</p> |
| |
| <blockquote> |
| <p>On consideration, here is where I would like us to be:</p> |
| |
| <ul><li>Streams which read from or write to an underlying object own that |
| object, i.e. closing the stream closes the underlying object, if |
| applicable.</li> |
| |
| <li>The layer (function or data type) which created a stream is |
| responsible for closing it, except when the above rule applies.</li> |
| |
| <li>Window handlers are thought of as an odd kind of stream, and passing |
| the final NULL window is considered closing the stream.</li> |
| </ul> |
| |
| <p>If you think of apply_textdelta as creating a window handler, then I |
| don't think we're too far off. svn_stream_from_aprfile isn't owning its |
| subsidiary file, svn_txdelta_apply is erroneously taking responsibility |
| for closing the window stream it is passed, and there may be some other |
| deviations.</p> |
| </blockquote> |
| |
| <p>There is one exception to the rules above though. When a stream is passed |
| to a function as an argument (for example: the 'out' parameter of |
| svn_client_cat2()), that routine can't call the streams destructor, since |
| it did not create that resource.</p> |
| |
| <p>If svn_client_cat2() creates a stream, it must also call the destructor |
| for that stream. By the above model, that stream will call the destructor |
| for the 'out' parameter. This is however wrong, because the responsibility |
| to destruct the 'out' parameter lies elsewhere.</p> |
| |
| <p>To solve this problem, at least in the stream case, svn_stream_disown() |
| has been introduced. This function wraps a stream, making sure it's |
| <em>not</em> destroyed, even though any streams stacked upon it may try |
| to do so.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="documenting" title="documenting"> |
| <h2>Document everything</h2> |
| |
| <p>Every function, whether public or internal, must start out with a |
| documentation comment that describes what the function does. The |
| documentation should mention every parameter received by the function, |
| every possible return value, and (if not obvious) the conditions under |
| which the function could return an error.</p> |
| |
| <p>For internal documentation put the parameter names in upper case |
| in the doc string, even when they are not upper case in the actual |
| declaration, so that they stand out to human readers.</p> |
| |
| <p>Use the <a href="http://www.doxygen.org/">Doxygen</a> format for |
| public interface documentation. This means anything that goes in a |
| public header file.</p> |
| |
| <p>For public or semi-public API functions, the doc string should go |
| above the function in the .h file where it is declared; otherwise, it |
| goes above the function definition in the .c file.</p> |
| |
| <p>For structure types, document each individual member of the |
| structure as well as the structure itself.</p> |
| |
| <p>Read over the Subversion code to get an overview of how |
| documentation looks in practice; in particular, see |
| subversion/include/*.h for doxygen examples.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="use-page-breaks" title="use-page-breaks"> |
| <h2>Using page breaks</h2> |
| |
| <p>We're using page breaks (the Ctrl-L character, ASCII 12) for |
| section boundaries in both code and plaintext prose files. Each |
| section starts with a page break, and immediately after the page break |
| comes the title of the section.</p> |
| |
| <p>This helps out people who use the Emacs page commands, such as |
| `pages-directory' and `narrow-to-page'. Such people are not as scarce |
| as you might think, and if you'd like to become one of them, then add |
| (require 'page-ext) to your .emacs and type C-x C-p C-h sometime.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="error-messages" title="error-messages"> |
| <h2>Error message conventions</h2> |
| |
| <p>For error messages the following conventions apply:</p> |
| |
| <ul> |
| |
| <li><p>Provide specific error messages only when there is information |
| to add to the general error message found in |
| subversion/include/svn_error_codes.h.</p></li> |
| |
| <li><p>Messages start with a capital letter.</p></li> |
| |
| <li><p>Try keeping messages below 70 characters.</p></li> |
| |
| <li><p>Don't end the error message with a period (".").</p></li> |
| |
| <li><p>Don't include newline characters in error messages.</p></li> |
| |
| <li><p>Quoting information is done using single quotes (e.g. "'some info'").</p></li> |
| |
| <li><p>Don't include the name of the function where the error occurs |
| in the error message. If Subversion is compiled using the |
| '--enable-maintainer-mode' configure-flag, it will provide this |
| information by itself.</p></li> |
| |
| <li><p>When including path or filenames in the error string, be sure |
| to quote them (e.g. "Can't find '/path/to/repos/userfile'").</p></li> |
| |
| <li><p>When including path or filenames in the error string, be sure |
| to convert them using 'svn_path_local_style()' before inclusion.</p></li> |
| |
| <li><p>Don't use Subversion-specific abbreviations (e.g. use "repository" |
| instead of "repo", "working copy" instead of "wc").</p></li> |
| |
| <li><p>If you want to add an explanation to the error, report it |
| followed by a colon and the explanation like this:</p> |
| <pre> |
| "Invalid " SVN_PROP_EXTERNALS " property on '%s': " |
| "target involves '.' or '..'". |
| </pre></li> |
| |
| <li><p>Suggestions or other additions can be added after a semi-colon, |
| like this:</p> |
| <pre> |
| "Can't write to '%s': object of same name already exists; remove " |
| "before retrying". |
| </pre></li> |
| |
| <li><p>Try to stay within the boundaries of these conventions, so please avoid |
| separating different parts of error messages by other separators such |
| as '--' and others.</p></li> |
| |
| </ul> |
| |
| <p>Also read about <a href="#l10n">Localization</a>.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="other-conventions" title="other-conventions"> |
| <h2>Other conventions</h2> |
| |
| <p>In addition to the GNU standards, Subversion uses these |
| conventions:</p> |
| |
| <ul> |
| <li><p>Use only spaces for indenting code, never tabs. Tab display |
| width is not standardized enough, and anyway it's easier to |
| manually adjust indentation that uses spaces.</p> |
| </li> |
| |
| <li><p>Restrict lines to 79 columns, so that code will display well in a |
| minimal standard display window. (There can be exceptions, such |
| as when declaring a block of 80-column text with a few extra |
| columns taken up by indentation, quotes, etc., if splitting each |
| line in two would be unreasonably messy.)</p> |
| </li> |
| |
| <li><p>All published functions, variables, and structures must be signified |
| with the corresponding library name - such as libsvn_wc's |
| svn_wc_adm_open. All library-internal declarations made in a |
| library-private header file (such as libsvn_wc/wc.h) must be signified |
| by two underscores after the library prefix (such as |
| svn_wc__ensure_directory). All declarations private to a single file |
| (such as the static function get_entry_url inside |
| libsvn_wc/update_editor.c) do not require any additional namespace |
| decorations. Symbols that need to be used outside a library, but |
| still are not public are put in a public header, but use the |
| double underscore notation. Such symbols may be used by |
| Subversion core code only, and we try to be restrictive |
| regarding the introduction of such entities.</p> |
| |
| <p>To recap:</p> |
| <pre> |
| /* Part of published API: subversion/include/svn_wc.h */ |
| svn_wc_adm_open() |
| #define SVN_WC_ADM_DIR_NAME ... |
| typedef enum svn_wc_schedule_t ... |
| /* For use within one library only: subversion/libsvn_wc/wc.h */ |
| svn_wc__ensure_directory() |
| #define SVN_WC__BASE_EXT ... |
| typedef struct svn_wc__compat_notify_baton_t ... |
| /* For use within one file: subversion/libsvn_wc/update_editor.c */ |
| get_entry_url() |
| struct handler_baton { |
| /* For internal use in svn core code only: |
| subversion/include/svn_types.h */ |
| #define SVN__STREAM_CHUNK_SIZE |
| /* subversion/include/svn_error.h */ |
| void svn_error__locate(const char *file, long line); |
| </pre> |
| </li> |
| |
| <li><p>In text strings that might be printed out (or otherwise made |
| available) to users, use only forward quotes around paths and |
| other quotable things. For example:</p> |
| <pre> |
| $ svn revert foo |
| svn: warning: svn_wc_is_wc_root: 'foo' is not a versioned resource |
| $ |
| </pre> |
| |
| <p>There used to be a lot of strings that used a backtick for |
| the first quote (`foo' instead of 'foo'), but that looked bad in |
| some fonts, and also messed up some people's auto-highlighting, |
| so we settled on the convention of always using forward |
| quotes.</p> |
| </li> |
| |
| <li><p>If you use Emacs, put something like this in your .emacs file, |
| so you get svn-dev.el and svnbook.el when needed:</p> |
| <pre> |
| ;;; Begin Subversion development section |
| (defun my-find-file-hook () |
| (let ((svn-tree-path (expand-file-name "~/projects/subversion")) |
| (book-tree-path (expand-file-name "~/projects/svnbook"))) |
| (cond |
| ((string-match svn-tree-path buffer-file-name) |
| (load (concat svn-tree-path "/tools/dev/svn-dev"))) |
| ((string-match book-tree-path buffer-file-name) |
| ;; Handle load exception for svnbook.el, because it tries to |
| ;; load psgml, and not everyone has that available. |
| (condition-case nil |
| (load (concat book-tree-path "/src/tools/svnbook")) |
| (error |
| (message "(Ignored problem loading svnbook.el.)"))))))) |
| |
| (add-hook 'find-file-hooks 'my-find-file-hook) |
| ;;; End Subversion development section |
| </pre> |
| |
| <p>You'll need to customize the path for your setup, of course. |
| You can also make the regexp to string-match more selective; for |
| example, one developer says:</p> |
| <pre> |
| > Here's the regexp I'm using: |
| > |
| > "src/svn/[^/]*/\\(subversion\\|tools\\|build\\)/" |
| > |
| > Two things to notice there: (1) I sometimes have several |
| > working copies checked out under ...src/svn, and I want the |
| > regexp to match all of them; (2) I want the hook to catch only |
| > in "our" directories within the working copy, so I match |
| > "subversion", "tools" and "build" explicitly; I don't want to |
| > use GNU style in the APR that's checked out into my repo. :-) |
| </pre> |
| </li> |
| |
| <li><p>We have a tradition of not marking files with the names of |
| individual authors (i.e., we don't put lines like |
| "Author: foo" or "@author foo" in a special position |
| at the top of a source file). This is to discourage |
| territoriality — even when a file has only one |
| author, we want to make sure others feel free to make changes. |
| People might be unnecessarily hesitant if someone appears to |
| have staked a personal claim to the file.</p> |
| </li> |
| |
| <li><p>Put two spaces between the end of one sentence and the start of |
| the next. This helps readability, and allows people to use |
| their editors' sentence-motion and -manipulation commands.</p> |
| </li> |
| |
| <li><p>There are many other unspoken conventions maintained throughout |
| the code, that are only noticed when someone unintentionally |
| fails to follow them. Just try to have a sensitive eye for the |
| way things are done, and when in doubt, ask.</p> |
| </li> |
| </ul> |
| |
| </div> |
| |
| |
| <div class="h2" id="apr-pools" title="apr-pools"> |
| <h2>APR pool usage conventions</h2> |
| |
| <p>(This assumes you already basically understand how APR pools work; |
| see apr_pools.h for details.)</p> |
| |
| <p>Applications using the Subversion libraries must call |
| apr_initialize() before calling any Subversion functions.</p> |
| |
| <p>Subversion's general pool usage strategy can be summed up in two |
| principles:</p> |
| |
| <ol> |
| <li><p>The call level that created a pool is the only place to clear or |
| destroy that pool.</p> |
| </li> |
| <li><p>When iterating an unbounded number of times, create a subpool |
| before entering the iteration, use it inside the loop and clear |
| it at the start of each iteration, then destroy it after the loop |
| is done, like so:</p> |
| <pre> |
| apr_pool_t *subpool = svn_pool_create(pool); |
| |
| for (i = 0; i < n; ++i) |
| { |
| svn_pool_clear(subpool); |
| do_operation(..., subpool); |
| } |
| |
| svn_pool_destroy(subpool); |
| </pre> |
| </li> |
| </ol> |
| |
| <p>By using a loop subpool for loop-bounded data, you ensure O(1) instead |
| of O(N) memory leakage should the function return abruptly from |
| within the loop (say, due to error). That's why you shouldn't make a |
| subpool for data which persists throughout a function, but instead |
| should use the pool passed in by the caller. That memory will be |
| reclaimed when the caller's pool is cleared or destroyed. If the |
| caller is invoking the callee in a loop, then trust the caller to take |
| care of clearing the pool on each iteration. The same logic |
| propagates all the way up the call stack.</p> |
| |
| <p>The pool you use also helps readers of the code understand object |
| lifetimes. Is a given object used only during one iteration of the |
| loop, or will it need to last beyond the end of the loop? For |
| example, pool choices indicate a lot about what's going on in this |
| code:</p> |
| |
| <pre> |
| apr_hash_t *persistent_objects = apr_hash_make(pool); |
| apr_pool_t *subpool = svn_pool_create(pool); |
| |
| for (i = 0; i < n; ++i) |
| { |
| const char *intermediate_result; |
| const char *key, *val; |
| |
| svn_pool_clear(subpool); |
| SVN_ERR(do_something(&intermediate_result, ..., subpool)); |
| SVN_ERR(get_result(intermediate_result, &key, &val, ..., pool)); |
| apr_hash_set(persistent_objects, key, APR_HASH_KEY_STRING, val); |
| } |
| svn_pool_destroy(subpool); |
| |
| return persistent_objects; |
| </pre> |
| |
| <p>Except for some legacy code, which was written before these |
| principles were fully understood, virtually all pool usage in |
| Subversion follows the above guidelines.</p> |
| |
| <p>One such legacy pattern is a tendency to allocate an object inside |
| a pool, store the pool in the object, and then free that pool (either |
| directly or through a close_foo() function) to destroy the object.</p> |
| |
| <p>For example:</p> |
| |
| <pre> |
| <span style="color: red;">/*** Example of how NOT to use pools. Don't be like this. ***/</span> |
| |
| static foo_t * |
| make_foo_object(arg1, arg2, apr_pool_t *pool) |
| { |
| apr_pool_t *subpool = svn_pool_create(pool); |
| foo_t *foo = apr_palloc(subpool, sizeof(*foo)); |
| |
| foo->field1 = arg1; |
| foo->field2 = arg2; |
| foo->pool = subpool; |
| } |
| |
| [...] |
| |
| [Now some function calls make_foo_object() and returns, passing |
| back a new foo object.] |
| |
| [...] |
| |
| [Now someone, at some random call level, decides that the foo's |
| lifetime is over, and calls svn_pool_destroy(foo->pool).] |
| </pre> |
| |
| <p>This is tempting, but it defeats the point of using pools, which is |
| to not worry so much about individual allocations, but rather about |
| overall performance and lifetime groups. Instead, foo_t generally |
| should not have a `pool' field. Just allocate as many foo objects as |
| you need in the current pool — when that pool gets |
| cleared or destroyed, they will all go away simultaneously.</p> |
| |
| <p>See also the <a href="#exception-handling">Exception handling</a> |
| section, for details of how resources associated with a pool are |
| cleaned up when that pool is destroyed.</p> |
| |
| <p>In summary:</p> |
| |
| <ul> |
| |
| <li><p>Objects should not have their own pools. An object is |
| allocated into a pool defined by the constructor's caller. The |
| caller knows the lifetime of the object and will manage it via |
| the pool.</p> |
| </li> |
| |
| <li><p>Functions should not create/destroy pools for their operation; |
| they should use a pool provided by the caller. Again, the |
| caller knows more about how the function will be used, how |
| often, how many times, etc. thus, it should be in charge of the |
| function's memory usage.</p> |
| |
| <p>For example, the caller might know that the app will exit upon |
| the function's return. Thus, the function would create extra |
| work if it built/destroyed a pool. Instead, it should use the |
| passed-in pool, which the caller is going to be tossing as part |
| of app-exit anyway.</p> |
| </li> |
| |
| <li><p>Whenever an unbounded iteration occurs, an iteration subpool |
| should be used.</p> |
| </li> |
| |
| <li><p>Given all of the above, it is pretty well mandatory to pass a |
| pool to every function. Since objects are not recording pools |
| for themselves, and the caller is always supposed to be |
| managing memory, then each function needs a pool, rather than |
| relying on some hidden magic pool. In limited cases, objects |
| may record the pool used for their construction so that they |
| can construct sub-parts, but these cases should be examined |
| carefully.</p> |
| </li> |
| </ul> |
| |
| |
| <p>See also <a href="#tracing-memory-leaks">Tracking down memory |
| leaks</a> for tips on diagnosing pool usage problems.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="apr-status-codes" title="apr-status-codes"> |
| <h2>APR status codes</h2> |
| |
| <p>Always check for APR status codes (except APR_SUCCESS) with the |
| APR_STATUS_IS_...() macros, not by direct comparison. This is required |
| for portability to non-Unix platforms.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="exception-handling" title="exception-handling"> |
| <h2>Exception handling</h2> |
| |
| <p>OK, here's how to use exceptions in Subversion.</p> |
| |
| <ol> |
| |
| <li><p>Exceptions are stored in svn_error_t structures:</p> |
| |
| <pre> |
| typedef struct svn_error |
| { |
| apr_status_t apr_err; /* APR error value, possibly SVN_ custom err */ |
| const char *message; /* details from producer of error */ |
| struct svn_error *child; /* ptr to the error we "wrap" */ |
| ap_pool_t *pool; /* place to generate message strings from */ |
| const char *file; /* Only used iff SVN_DEBUG */ |
| long line; /* Only used iff SVN_DEBUG */ |
| } svn_error_t; |
| </pre> |
| |
| </li> |
| |
| <li><p>If you are the *original* creator of an error, you would do |
| something like this:</p> |
| |
| <pre> |
| return svn_error_create(SVN_ERR_FOO, NULL, |
| "User not permitted to write file"); |
| </pre> |
| |
| <p>NOTICE the NULL field... indicating that this error has no |
| child, i.e. it is the bottom-most error.</p> |
| |
| <p>See also the <a href="#error-messages"> section on writing |
| error messages</a>.</p> |
| |
| <p>Subversion internally uses UTF-8 to store its data. This also |
| applies to the 'message' string. APR is assumed to return its data |
| in the current locale, so any text returned by APR needs |
| conversion to UTF-8 before inclusion in the message string.</p> |
| </li> |
| |
| <li><p>If you *receive* an error, you have three choices:</p> |
| |
| <ol> |
| <li><p>Handle the error yourself. Use either your own code, or |
| just call the primitive svn_handle_error(err). (This |
| routine unwinds the error stack and prints out messages |
| converting them from UTF-8 to the current locale.)</p> |
| |
| <p>When your routine receives an error which it intends to |
| ignore or handle itself, be sure to clean it up using |
| svn_error_clear(). Any time such an error is not cleared |
| constitutes a *memory leak*.</p> |
| </li> |
| |
| <li><p>Throw the error upwards, unmodified:</p> |
| |
| <pre> |
| error = some_routine(foo); |
| if (error) |
| return (error); |
| </pre> |
| |
| <p>Actually, a better way to do this would be with the |
| SVN_ERR() macro, which does the same thing:</p> |
| <pre> |
| SVN_ERR(some_routine(foo)); |
| </pre> |
| </li> |
| |
| <li><p>Throw the error upwards, wrapping it in a new error |
| structure by including it as the "child" argument:</p> |
| |
| <pre> |
| error = some_routine(foo); |
| if (error) |
| { |
| svn_error_t *wrapper = svn_error_create(SVN_ERR_FOO, error, |
| "Authorization failed"); |
| return wrapper; |
| } |
| </pre> |
| |
| <p>Of course, there's a convenience routine which creates a |
| wrapper error with the same fields as the child, except for |
| your custom message:</p> |
| |
| <pre> |
| error = some_routine(foo); |
| if (error) |
| { |
| return svn_error_quick_wrap(error, |
| "Authorization failed"); |
| } |
| </pre> |
| |
| <p>The same can (and should) be done by using the SVN_ERR_W() |
| macro:</p> |
| |
| <pre> |
| SVN_ERR_W(some_routine(foo), "Authorization failed"); |
| </pre> |
| </li> |
| </ol> |
| |
| <p>In cases (b) and (c) it is important to know that resources |
| allocated by your routine which are associated with a pool, are |
| automatically cleaned up when the pool is destroyed. This means |
| that there is no need to cleanup these resources before passing |
| the error. There is therefore no reason not to use the SVN_ERR() |
| and SVN_ERR_W() macros. Resources associated with pools are:</p> |
| |
| <ul> |
| |
| <li><p>Memory</p></li> |
| |
| <li><p>Files</p> |
| |
| <p>All files opened with apr_file_open are closed at pool |
| cleanup. Subversion uses this function in its svn_io_file_* |
| api, which means that files opened with svn_io_file_* or |
| apr_file_open will be closed at pool cleanup.</p> |
| |
| <p>Some files (lock files for example) need to be removed when |
| an operation is finished. APR has the APR_DELONCLOSE flag for |
| this purpose. The following functions create files which are |
| removed on pool cleanup:</p> |
| |
| <ul> |
| <li><p>apr_file_open and svn_io_file_open (when passed the |
| APR_DELONCLOSE flag)</p></li> |
| <li><p>svn_io_open_unique_file (when passed TRUE in its |
| delete_on_close)</p></li> |
| </ul> |
| |
| <p>Locked files are unlocked if they were locked using |
| svn_io_file_lock.</p> |
| </li> |
| </ul> |
| |
| </li> |
| </ol> |
| |
| </div> |
| |
| |
| <div class="h2" id="automated-tests" title="automated-tests"> |
| <h2>Automated tests</h2> |
| |
| <p>For a description of how to use and add tests to Subversion's |
| automated test framework, please read <a |
| href="http://svn.collab.net/repos/svn/trunk/subversion/tests/README" |
| >subversion/tests/README</a> and <a |
| href="http://svn.collab.net/repos/svn/trunk/subversion/tests/cmdline/README" |
| >subversion/tests/cmdline/README</a>.</p> |
| |
| <p>Various people have arranged for the automated test framework to |
| run at regular intervals on their own machines, sending the results to |
| the svn-breakage@subversion.tigris.org mailing list. The more |
| different platforms the tests run on, the more quickly we can detect |
| portability bugs in Subversion. If you'd like to send svn-breakage |
| messages too, use the <a |
| href="http://svn.collab.net/repos/svn/trunk/tools/test-scripts/svntest/" |
| >svntest</a> framework (start at the <a |
| href="http://svn.collab.net/repos/svn/trunk/tools/test-scripts/svntest/README" |
| >README</a>).</p> |
| |
| <p>Lieven Govaerts has set up a |
| <a href="http://buildbot.sourceforge.net/" >BuildBot</a> build/test |
| farm at <a href="http://www.mobsol.be/buildbot/" |
| >http://www.mobsol.be/buildbot/</a>, see his message</p> |
| |
| <pre> |
| <a href="http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=114212">http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=114212</a> |
| (Thread URL: <a href="http://subversion.tigris.org/servlets/BrowseList?list=dev&by=thread&from=450110">http://subversion.tigris.org/servlets/BrowseList?list=dev&by=thread&from=450110</a>) |
| Message-ID: 20060326205918.F3C50708B0@adicia.telenet-ops.be |
| From: "Lieven Govaerts" <lgo@mobsol.be> |
| To: <dev@subversion.tigris.org> |
| Subject: Update: Subversion build and test farm with Buildbot. |
| Date: Sun, 26 Mar 2006 22:56:11 +0200 |
| </pre> |
| |
| <p>for more details. (<a href="http://buildbot.sourceforge.net/" |
| >BuildBot</a> is a system for centrally managing multiple automated |
| testing environments; it's especially useful for portability testing, |
| including of uncommitted changes.)</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="write-test-cases-first" title="write-test-cases-first"> |
| <h2>Writing test cases before code</h2> |
| |
| <pre> |
| From: Karl Fogel <kfogel@collab.net> |
| Subject: writing test cases |
| To: dev@subversion.tigris.org |
| Date: Mon, 5 Mar 2001 15:58:46 -0600 |
| |
| Many of us implementing the filesystem interface have now gotten into |
| the habit of writing the test cases (see fs-test.c) *before* writing |
| the actual code. It's really helping us out a lot -- for one thing, |
| it forces one to define the task precisely in advance, and also it |
| speedily reveals the bugs in one's first try (and second, and |
| third...). |
| |
| I'd like to recommend this practice to everyone. If you're |
| implementing an interface, or adding an entirely new feature, or even |
| just fixing a bug, a test for it is a good idea. And if you're going |
| to write the test anyway, you might as well write it first. :-) |
| |
| Yoshiki Hayashi's been sending test cases with all his patches lately, |
| which is what inspired me to write this mail to encourage everyone to |
| do the same. Having those test cases makes patches easier to examine, |
| because they show the patch's purpose very clearly. It's like having |
| a second log message, one whose accuracy is verified at run-time. |
| |
| That said, I don't think we want a rigid policy about this, at least |
| not yet. If you encounter a bug somewhere in the code, but you only |
| have time to write a patch with no test case, that's okay -- having |
| the patch is still useful; someone else can write the test case. |
| |
| As Subversion gets more complex, though, the automated test suite gets |
| more crucial, so let's all get in the habit of using it early. |
| |
| -K |
| </pre> |
| |
| </div> |
| |
| |
| <div class="h2" id="server-debugging" title="server-debugging"> |
| <h2>Debugging the server</h2> |
| |
| <div class="h3" id="debugging-ra-dav" title="debugging-ra-dav"> |
| <h3>Debugging the ra_dav server</h3> |
| |
| <p>'mod_dav_svn.so' contains the main Subversion server logic; it runs |
| as a module within mod_dav, which runs as a module within httpd. |
| Since httpd is probably using dynamic shared modules, you normally |
| won't be able to set breakpoints in advance when you start Apache in a |
| debugger such as GDB. Instead, you'll need to start up, then |
| interrupt httpd, set your breakpoint, and continue:</p> |
| |
| <pre> |
| % gdb httpd |
| (gdb) run -X |
| ^C |
| (gdb) break some_func_in_mod_dav_svn |
| (gdb) continue |
| </pre> |
| |
| <p>The -X switch is equivalent to -DONE_PROCESS and -DNO_DETACH, which |
| ensure that httpd runs as a single thread and remains attached to the |
| tty, respectively. As soon as it starts, it sits and waits for |
| requests; that's when you hit control-C and set your breakpoint.</p> |
| |
| <p>You'll probably want to watch Apache's run-time logs</p> |
| |
| <pre> |
| /usr/local/apache2/logs/error_log |
| /usr/local/apache2/logs/access_log |
| </pre> |
| |
| <p>to help determine what might be going wrong and where to set |
| breakpoints.</p> |
| |
| </div> |
| |
| <div class="h3" id="debugging-ra-svn" title="debugging-ra-svn"> |
| <h3>Debugging the ra_svn client and server, on Unix</h3> |
| |
| <p>Bugs in ra_svn usually manifest themselves with one of the |
| following cryptic error messages:</p> |
| |
| <pre> |
| svn: Malformed network data |
| svn: Connection closed unexpectedly |
| </pre> |
| |
| <p>(The first message can also mean the data stream was corrupted in |
| tunnel mode by user dotfiles or hook scripts; see |
| <a href="http://subversion.tigris.org/issues/show_bug.cgi?id=1145" |
| >issue #1145</a>.) The first message generally means you to have |
| to debug the client; the second message generally means you have to |
| debug the server.</p> |
| |
| <p>It is easiest to debug ra_svn using a build with --disable-shared |
| --enable-maintainer-mode. With the latter option, the error message |
| will tell you exactly what line to set a breakpoint at; otherwise, |
| look up the line number at the end of marshal.c:vparse_tuple() where |
| it returns the "Malformed network data" error.</p> |
| |
| <p>To debug the client, simply pull it up in gdb, set a breakpoint, |
| and run the offending command:</p> |
| |
| <pre> |
| % gdb svn |
| (gdb) break marshal.c:NNN |
| (gdb) run ARGS |
| Breakpoint 1, vparse_tuple (list=___, pool=___, fmt=___, |
| ap=___) at subversion/libsvn_ra_svn/marshal.c:NNN |
| NNN "Malformed network data"); |
| </pre> |
| |
| <p>There are several bits of useful information:</p> |
| |
| <ul> |
| <li><p>A backtrace will tell you exactly what protocol exchange is |
| failing.</p> |
| </li> |
| |
| <li><p>"print *conn" will show you the connection buffer. read_buf, |
| read_ptr, and read_end represent the read buffer, which can |
| show |
| you the data the marshaller is looking at. (Since read_buf isn't |
| generally 0-terminated at read_end, be careful of falsely assuming |
| that there's garbage data in the buffer.)</p> |
| </li> |
| |
| <li><p>The format string determines what the marshaller was expecting to |
| see.</p> |
| </li> |
| </ul> |
| |
| <p>To debug the server in daemon mode, pull it up in gdb, set a |
| breakpoint (usually a "Connection closed unexpectedly" error on the |
| client indicates a "Malformed network data" error on the server, |
| although it can also indicate a core dump), and run it with the "-X" |
| option to serve a single connection:</p> |
| |
| <pre> |
| % gdb svnserve |
| (gdb) break marshal.c:NNN |
| (gdb) run -X |
| </pre> |
| |
| <p>Then run the offending client command. From there, it's just like |
| debugging the client.</p> |
| |
| <p>Debugging the server in tunnel mode is more of a pain. You'll need |
| to stick something like "{ int x = 1; while (x); }" near the top of |
| svnserve's main() and put the resulting svnserve in the user path on |
| the server. Then start an operation, gdb attach the process on the |
| server, "set x = 0", and step through the code as desired.</p> |
| |
| </div> |
| |
| </div> |
| |
| |
| <div class="h2" id="tracing-memory-leaks" title="tracing-memory-leaks"> |
| <h2>Tracking down memory leaks</h2> |
| |
| <p>Our use of APR pools makes it unusual for us to have memory leaks |
| in the strictest sense; all the memory we allocate will be cleaned up |
| eventually. But sometimes an operation takes more memory than it |
| should; for instance, a checkout of a large source tree should not use |
| much more memory than a checkout of a small source tree. When that |
| happens, it generally means we're allocating memory from a pool whose |
| lifetime is too long.</p> |
| |
| <p>If you have a favorite memory leak tracking tool, you can configure |
| with --enable-pool-debug (which will make every pool allocation use |
| its own malloc()), arrange to exit in the middle of the operation, and |
| go to it. If not, here's another way:</p> |
| |
| <ul> |
| |
| <li><p>Configure with --enable-pool-debug=verbose-alloc. Make sure to |
| rebuild all of APR and Subversion so that every allocation gets |
| file-and-line information.</p> |
| </li> |
| |
| <li><p>Run the operation, piping stderr to a file. Hopefully you have |
| lots of disk space.</p> |
| </li> |
| |
| <li><p>In the file, you'll see lots of lines which look like:</p> |
| |
| <pre> |
| POOL DEBUG: [5383/1024] PCALLOC ( 2763/ 2763/ 5419) \ |
| 0x08102D48 "subversion/svn/main.c:612" \ |
| <subversion/libsvn_subr/auth.c:122> (118/118/0) |
| </pre> |
| |
| <p>What you care about most is the tenth field (the one in |
| quotes), which gives you the file and line number where the |
| pool for this allocation was created. Go to that file and line |
| and determine the lifetime of the pool. In the example above, |
| main.c:612 indicates that this allocation was made in the |
| top-level pool of the svn client. If this were an allocation |
| which was repeated many times during the course of an |
| operation, that would indicate a source of a memory leak. The |
| eleventh field (the one in brackets) gives the file and line |
| number of the allocation itself.</p> |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| |
| <div class="h2" id="log-messages" title="log-messages"> |
| <h2>Writing log messages</h2> |
| |
| <p>Every commit needs a log message. </p> |
| |
| <p>The intended audience for a log message is a developer who is |
| already familiar with Subversion, but not necessarily familiar with |
| this particular commit. Usually when someone goes back and reads a |
| change, he no longer has in his head all the context around that |
| change. This is true even if he is the author of the change! All the |
| discussions and mailing list threads and everything else may be |
| forgotten; the only clue to what the change is about comes from the |
| log message and the diff itself. People revisit changes with |
| surprising frequency, too: for example, it might be months after the |
| original commit and now the change is being ported to a maintenance |
| branch.</p> |
| |
| <p>The log message is the introduction to the change. Start it off |
| with one line indicating the general nature of the change, and follow |
| that with a descriptive paragraph if necessary. This not only helps |
| put developers in the right frame of mind for reading the rest of the |
| log message, but also plays well with the "CIA" bot that echoes the |
| first line of each commit to realtime forums like IRC. (For details, |
| see <a href="http://cia.navi.cx/">http://cia.navi.cx/</a>.) However, |
| if the commit is just one simple change to one file, then you can |
| dispense with the general description and simply go straight to the |
| detailed description, in the standard filename-then-symbol format |
| shown below.</p> |
| |
| <p>Throughout the log message, use full sentences, not sentence |
| fragments. Fragments are more often ambiguous, and it takes only a |
| few more seconds to write out what you mean. Certain fragments like |
| "Doc fix", "New file", or "New function" are acceptable because they |
| are standard idioms, and all further details should appear in the |
| source code.</p> |
| |
| <p>The log message should name every affected function, variable, |
| macro, makefile target, grammar rule, etc, including the names of |
| symbols that are being removed in this commit. This helps people |
| searching through the logs later. Don't hide names in wildcards, |
| because the globbed portion may be what someone searches for later. |
| For example, this is bad:</p> |
| |
| <pre> |
| * subversion/libsvn_ra_pigeons/twirl.c |
| (twirling_baton_*): Removed these obsolete structures. |
| (handle_parser_warning): Pass data directly to callees, instead |
| of storing in twirling_baton_*. |
| |
| * subversion/libsvn_ra_pigeons/twirl.h: Fix indentation. |
| </pre> |
| |
| <p>Later on, when someone is trying to figure out what happened to |
| `twirling_baton_fast', they may not find it if they just search for |
| "_fast". A better entry would be:</p> |
| |
| <pre> |
| * subversion/libsvn_ra_pigeons/twirl.c |
| (twirling_baton_fast, twirling_baton_slow): Removed these |
| obsolete structures. |
| (handle_parser_warning): Pass data directly to callees, instead |
| of storing in twirling_baton_*. |
| |
| * subversion/libsvn_ra_pigeons/twirl.h: Fix indentation. |
| </pre> |
| |
| <p>The wildcard is okay in the description for |
| `handle_parser_warning', but only because the two structures were |
| mentioned by full name elsewhere in the log entry.</p> |
| |
| <p>Note how each file gets its own entry prefixed with an "*", and the |
| changes within a file are grouped by symbol, with the symbols listed |
| in parentheses followed by a colon, followed by text describing the |
| change. Please adhere to this format, even when only one file is |
| changed — not only does consistency aid readability, |
| it also allows software to colorize log entries automatically.</p> |
| |
| <p>As an exception to the above, if you make exactly the same change |
| in several files, list all the changed files in one entry. For |
| example:</p> |
| |
| <pre> |
| * subversion/libsvn_ra_pigeons/twirl.c, |
| subversion/libsvn_ra_pigeons/roost.c: |
| Include svn_private_config.h. |
| </pre> |
| |
| <p>If all the changed files are deep inside the source tree, you can |
| shorten the file name entries by noting the common prefix before the |
| change entries:</p> |
| |
| <pre> |
| [in subversion/bindings/swig/birdsong] |
| |
| * dialects/nightingale.c (get_base_pitch): Allow 3/4-tone |
| pitch variation to account for trait variability amongst |
| isolated populations Erithacus megarhynchos. |
| |
| * dialects/gallus_domesticus.c: Remove. Unreliable due to |
| extremely low brain-to-body mass ratio. |
| </pre> |
| |
| <p>If your change is related to a specific issue in the issue tracker, |
| then include a string like "issue #N" in the log message, but make |
| sure you still summarize what the change is about. For example, if a |
| patch resolves issue #1729, then the log message might be:</p> |
| |
| <pre> |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| </pre> |
| |
| <p>Try to put related changes together. For example, if you create |
| svn_ra_get_ansible2(), deprecating svn_ra_get_ansible(), then those |
| two things should be near each other in the log message:</p> |
| |
| <pre> |
| * subversion/include/svn_ra.h |
| (svn_ra_get_ansible2): New prototype, obsoletes svn_ra_get_ansible. |
| (svn_ra_get_ansible): Deprecate. |
| </pre> |
| |
| <p>For large changes or change groups, group the log entry into |
| paragraphs separated by blank lines. Each paragraph should be a set |
| of changes that accomplishes a single goal, and each group should |
| start with a sentence or two summarizing the change. Truly |
| independent changes should be made in separate commits, of course.</p> |
| |
| <p>See <a href="#crediting">Crediting</a> for how to give credit to |
| someone else if you are committing their patch, or committing a change |
| they suggested.</p> |
| |
| <p>One should never need the log entries to understand the current |
| code. If you find yourself writing a significant explanation in the |
| log, you should consider carefully whether your text doesn't actually |
| belong in a comment, alongside the code it explains. Here's an |
| example of doing it right:</p> |
| |
| <pre> |
| (consume_count): If `count' is unreasonable, return 0 and don't |
| advance input pointer. |
| </pre> |
| |
| <p>And then, in `consume_count' in `cplus-dem.c':</p> |
| |
| <pre> |
| while (isdigit((unsigned char)**type)) |
| { |
| count *= 10; |
| count += **type - '0'; |
| /* A sanity check. Otherwise a symbol like |
| `_Utf390_1__1_9223372036854775807__9223372036854775' |
| can cause this function to return a negative value. |
| In this case we just consume until the end of the string. */ |
| if (count > strlen(*type)) |
| { |
| *type = save; |
| return 0; |
| } |
| </pre> |
| |
| <p>This is why a new function, for example, needs only a log entry |
| saying "New Function" --- all the details should be in the source.</p> |
| |
| <p>You can make common-sense exceptions to the need to name everything |
| that was changed. For example, if you have made a change which |
| requires trivial changes throughout the rest of the program (e.g., |
| renaming a variable), you needn't name all the functions affected, you |
| can just say "All callers changed". However, if you rename symbols |
| (e.g., to add or remove a library prefix), please mention every |
| affected symbol, both old and new — this is the only |
| way the rename of a particular symbol would be traceable later. See |
| r20946 for an example of this.</p> |
| |
| <p>In general, there is a tension between making entries easy to find |
| by searching for identifiers, and wasting time or producing unreadable |
| entries by being exhaustive. Use the above guidelines and your best |
| judgment, and be considerate of your fellow developers. (Also, run |
| "svn log" to see how others have been writing their log entries.)</p> |
| |
| <p>Log messages for documentation or translation have somewhat looser |
| guidelines. The requirement to name every symbol obviously does not |
| apply, and if the change is just one more increment in a continuous |
| process such as translation, it's not even necessary to name every |
| file. Just briefly summarize the change, for example: "More work on |
| Malagasy translation." Please write your log messages in English, so |
| everybody involved in the project can understand the changes you |
| made.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="crediting" title="crediting"> |
| <h2>Crediting</h2> |
| |
| <p>It is very important to record code contributions in a consistent |
| and parseable way. This allows us to write scripts to figure out who |
| has been actively contributing — and what they have |
| contributed — so we can <a |
| href="http://www.red-bean.com/svnproject/contribulyzer/">spot |
| potential new committers quickly</a>. The Subversion project uses |
| human-readable but machine-parseable fields in log messages to |
| accomplish this.</p> |
| |
| <p>When committing a patch written by someone else, use |
| "Patch by: " at the beginning of a line to indicate the |
| author:</p> |
| |
| <pre> |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| |
| Patch by: J. Random <jrandom@example.com> |
| </pre> |
| |
| <p>If multiple individuals wrote the patch, list them each on a |
| separate line — making sure to start each continuation |
| line with whitespace. Non-committers should be listed by name, if |
| known, and e-mail. Committers may be listed similarly, or by their |
| canonical usernames from COMMITTERS (the leftmost column). |
| Additionally, "me" is an acceptable shorthand for the person actually |
| committing the change.</p> |
| |
| <pre> |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| |
| Patch by: J. Random <jrandom@example.com> |
| Enrico Caruso <codingtenor@codingtenor.com> |
| jcommitter |
| me |
| </pre> |
| |
| <p>If someone found the bug or pointed out the problem, but didn't |
| write the patch, indicate their contribution with |
| "Found by: ":</p> |
| |
| <pre> |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| |
| Found by: J. Random <jrandom@example.com> |
| </pre> |
| |
| <p>If someone suggested something useful, but didn't write the patch, |
| indicate their contribution with "Suggested by: ":</p> |
| |
| <pre> |
| Extend the Contribulyzer syntax to distinguish finds from ideas. |
| |
| * www/hacking.html (crediting): Adjust accordingly. |
| |
| Suggested by: dlr |
| </pre> |
| |
| <p>If someone reviewed the change, use "Review by: " |
| (or "Reviewed by: " if you prefer):</p> |
| |
| <pre> |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| |
| Review by: Eagle Eyes <eeyes@example.com> |
| </pre> |
| |
| <p>A field may have multiple lines, and a log message may contain any |
| combination of fields:</p> |
| |
| <pre> |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| |
| Patch by: J. Random <jrandom@example.com> |
| Enrico Caruso <codingtenor@codingtenor.com> |
| me |
| Found by: J. Random <jrandom@example.com> |
| Review by: Eagle Eyes <eeyes@example.com> |
| jcommitter |
| </pre> |
| |
| <p>Further details about a contribution should be listed in a |
| parenthetical aside immediately after the corresponding field. Such |
| an aside always applies to the field right above it; in the following |
| example, the fields have been spaced out for readability, but note |
| that the spacing is optional and not necessary for parseability:</p> |
| |
| <pre> |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| |
| Patch by: J. Random <jrandom@example.com> |
| (Tweaked by me.) |
| |
| Review by: Eagle Eyes <eeyes@example.com> |
| jcommitter |
| (Eagle Eyes caught an off-by-one-error in the basename extraction.) |
| </pre> |
| |
| <p>Currently, these fields</p> |
| |
| <pre> |
| Patch by: |
| Suggested by: |
| Found by: |
| Review by: |
| </pre> |
| |
| <p>are the only officially-supported crediting fields (where |
| "supported" means scripts know to look for them), and they are widely |
| used in Subversion log messages. Future fields will probably be of |
| the form "VERB by: ", and from time to time someone may use |
| a field that sounds official but really is not — for |
| example, there are a few instances of "Reported by: ". |
| These are okay, but try to use an official field, or a parenthetical |
| aside, in preference to creating your own. Also, don't use |
| "Reported by: " when the reporter is already recorded in an |
| issue; instead, simply refer to the issue.</p> |
| |
| <p>Look over Subversion's existing log messages to see how to use |
| these fields in practice. This command from the top of your trunk |
| working copy will help:</p> |
| |
| <pre> |
| svn log | contrib/client-side/search-svnlog.pl "(Patch|Review|Suggested) by: " |
| </pre> |
| |
| <p><b>Note:</b> The "Approved by: " field seen in some |
| commit messages is totally unrelated to these crediting fields, and is |
| generally not parsed by scripts. It is simply the standard syntax for |
| indicating either who approved a partial committer's commit outside |
| their usual area, or (in the case of merges to release branches) who |
| voted for the change to be merged.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="patches" title="patches"> |
| <h2>Patch submission guidelines</h2> |
| |
| <p>Mail patches to dev@subversion.tigris.org, with a subject line |
| that contains the word "PATCH" in all uppercase, for example</p> |
| |
| <pre> |
| Subject: [PATCH] fix for rev printing bug in svn status |
| </pre> |
| |
| <p>A patch submission should contain one logical change; please don't |
| mix N unrelated changes in one submission — send N |
| separate emails instead.</p> |
| |
| <p>You can put the patch's log message in the body of the email, or at |
| the top of the patch attachment (see below). Either way, it should |
| follow the guidelines given in <a href="#log-messages">Writing |
| log messages</a>, and be enclosed in triple square brackets, like so:</p> |
| |
| <pre> |
| [[[ |
| Fix issue #1729: Don't crash because of a missing file. |
| |
| * subversion/libsvn_ra_ansible/get_editor.c |
| (frobnicate_file): Check that file exists before frobnicating. |
| ]]] |
| </pre> |
| |
| <p>The brackets are not actually part of the log message, they are |
| just a way to clearly mark off the log message from its surrounding |
| context.</p> |
| |
| <p>The patch itself should be in unified diff format (e.g., "svn diff" |
| or "diff -u"). Send the patch as an attachment, with a mime-type of |
| text/x-diff, text/x-patch, or text/plain. (Most people's mailreaders |
| can display those inline, and having the patch as an attachment allows |
| them to extract the patch from the message conveniently.)</p> |
| |
| <p>If you can't attach the patch with one of these mime-types, or if |
| the patch is very short, then just include it directly in the body of |
| your message. But if your mailer forces wrapping of long lines, then |
| you must attach the patch, otherwise it is likely to get munged. |
| Never send patches in archived or compressed form (e.g., tar, gzip, |
| zip, bzip2), because that prevents people from reviewing the patch |
| directly in their mailreaders.</p> |
| |
| <p>If the patch implements a new feature, make sure to describe the |
| feature completely in your mail; if the patch fixes a bug, describe |
| the bug in detail and give a reproduction recipe. An exception to |
| these guidelines is when the patch addresses a specific issue in the |
| issues database — in that case, just make sure to |
| refer to the issue number in your log message, as described |
| in <a href="#log-messages">Writing log messages</a>.</p> |
| |
| <p>It is normal for patches to undergo several rounds of feedback and |
| change before being applied. Don't be discouraged if your patch is |
| not accepted immediately — it doesn't mean you goofed, |
| it just means that there are a *lot* of eyes looking at every code |
| submission, and it's a rare patch that doesn't have at least a little |
| room for improvement. After reading people's responses to your patch, |
| make the appropriate changes and resubmit, wait for the next round of |
| feedback, and lather, rinse, repeat, until some committer applies |
| it.</p> |
| |
| <p>If you don't get a response for a while, and don't see the patch |
| applied, it may just mean that people are really busy. Go ahead and |
| repost, and don't hesitate to point out that you're still waiting for |
| a response. One way to think of it is that patch management is highly |
| parallizable, and we need you to shoulder your share of the management |
| as well as the coding. Every patch needs someone to shepherd it |
| through the process, and the person best qualified to do that is the |
| original submitter.</p> |
| |
| <div class="h3" id="patch-manager" title="patch-manager"> |
| <h3>The "Patch Manager" Role</h3> |
| |
| <p>Subversion usually has a Patch Manager, whose job is to watch the |
| dev@ mailing list and make sure that no patches "slip through the |
| cracks".</p> |
| |
| <p>This means watching every thread containing "[PATCH]" mails, and |
| taking appropriate action based on the progress of the thread. If the |
| thread resolves on its own (because the patch gets committed, or |
| because there is consensus that the patch doesn't need to be applied, |
| or whatever) then no further action need be taken. But if the thread |
| fades out without any clear decision, then the patch needs to be saved |
| in the issue tracker. This means that a summary of any discussion |
| threads around that patch, and links to relevant mailing list |
| archives, will be added to some issue in the tracker. For a patch |
| which addresses an existing issue tracker item, the patch is saved to |
| that item. Otherwise, a new issue of type 'PATCH' is filed, and the |
| patch is saved to that new issue.</p> |
| |
| <p>The Patch Manager needs a basic technical understanding of |
| Subversion, and the ability to skim a thread and get a rough |
| understanding of whether consensus has been reached, and if so, of |
| what kind. It does *not* require actual Subversion development |
| experience or commit access. Expertise in using one's mail reading |
| software is optional, but recommended :-).</p> |
| |
| <p>The current patch manager is Hyrum Wright |
| <hyrum_wright@mail.utexas.edu>.</p> |
| |
| </div> |
| |
| </div> |
| |
| |
| <div class="h2" id="filing-issues" title="filing-issues"> |
| <h2>Filing bugs / issues</h2> |
| |
| <p>This pretty much says it all:</p> |
| |
| <pre> |
| From: Karl Fogel <kfogel@collab.net> |
| Subject: Please ask on the list before filing a new issue. |
| To: dev@subversion.tigris.org |
| Date: Tue, 30 Jul 2002 10:51:24 (CDT) |
| |
| Folks, we're getting tons of new issues, which is a Good Thing in |
| general, but some of them don't really belong in the issue tracker. |
| They're things that would be better solved by a quick conversation |
| here on the dev list. Compilation problems, behavior questions, |
| feature ideas that have been discussed before, that sort of thing. |
| |
| *Please* be more conservative about filing issues. The issues |
| database is physically much more cumbersome than email. It wastes |
| people's time to have conversations in the issues database that should |
| be had in email. (This is not a libel against the issue tracker, it's |
| just a result of the fact that the issues database is for permanent |
| storage and flow annotation, not for real-time conversation.) |
| |
| If you encounter a situation where Subversion is clearly behaving |
| wrongly, or behaving opposite to what the documentation says, then |
| it's okay to file the issue right away (after searching to make sure |
| it isn't already filed, of course!). But if you're |
| |
| a) Requesting a new feature, or |
| b) Having build problems, or |
| c) Not sure what the behavior should be, or |
| d) Disagreeing with current intended behavior, or |
| e) Not TOTALLY sure that others would agree this is a bug, or |
| f) For any reason at all not sure this should be filed, |
| |
| ...then please post to the dev list first. You'll get a faster |
| response, and others won't be forced to use the issues database to |
| have the initial real-time conversations. |
| |
| Nothing is lost this way. If we eventually conclude that it should be |
| in the issue tracker, then we can still file it later, after the |
| description and reproduction recipe have been honed on the dev list. |
| |
| Thank you, |
| -Karl |
| </pre> |
| |
| </div> |
| |
| |
| <div class="h2" id="commit-access" title="commit-access"> |
| <h2>Commit access</h2> |
| |
| <p>There are two types of commit access: full and partial. Full means |
| anywhere in the tree, partial means only in that committer's specific |
| area(s) of expertise. The COMMITTERS file lists all committers, both |
| full and partial, and says the domains for each partial committer.</p> |
| |
| <div class="h3" id="full-commit-access" title="full-commit-access"> |
| <h3>How full commit access is granted</h3> |
| |
| <p>After someone has successfully contributed a few non-trivial |
| patches, some full committer, usually whoever has reviewed and applied |
| the most patches from that contributor, proposes them for commit |
| access. This proposal is sent only to the other full committers -- |
| the ensuing discussion is private, so that everyone can feel |
| comfortable speaking their minds. Assuming there are no objections, |
| the contributor is granted commit access. The decision is made by |
| consensus; there are no formal rules governing the procedure, though |
| generally if someone strongly objects the access is not offered, or is |
| offered on a provisional basis.</p> |
| |
| <p><i>The primary criterion for full commit access is good |
| judgment.</i></p> |
| |
| <p>You do not have to be a technical wizard, or demonstrate deep |
| knowledge of the entire codebase, to become a full committer. You |
| just need to know what you don't know. If your patches adhere to the |
| guidelines in this file, adhere to all the usual unquantifiable rules |
| of coding (code should be readable, robust, maintainable, etc.), and |
| respect the Hippocratic Principle of "first, do no harm", then you |
| will probably get commit access pretty quickly. The size, complexity, |
| and quantity of your patches do not matter as much as the degree of |
| care you show in avoiding bugs and minimizing unnecessary impact on |
| the rest of the code. Many full committers are people who have not |
| made major code contributions, but rather lots of small, clean fixes, |
| each of which was an unambiguous improvement to the code. (Of course, |
| this does not mean the project needs a bunch of very trivial patches |
| whose only purpose is to gain commit access; knowing what's worth a |
| patch post and what's not is part of showing good judgement :-) .)</p> |
| |
| <p>To assist developers in discovering new committers, we record |
| patches and other contributions in a <a href="#crediting">special |
| crediting format</a>, which is then parsed to produce a |
| browser-friendly <a |
| href="http://www.red-bean.com/svnproject/contribulyzer/">contribution |
| list</a>, updated nightly. If you're thinking of proposing someone |
| for commit access and want to look over all their changes, that <a |
| href="http://www.red-bean.com/svnproject/contribulyzer/">contribution |
| list</a> might be the most convenient place to do it.</p> |
| |
| </div> |
| |
| <div class="h3" id="partial-commit-access" title="partial-commit-access"> |
| <h3>How partial commit access is granted</h3> |
| |
| <p>A full committer sponsors the partial committer. Usually this |
| means the full committer has applied several patches to the same area |
| from the proposed partial committer, and realizes things would be |
| easier if the person were just committing directly. Approval is not |
| required from the full committers; it is assumed that sponsors know |
| what they're doing and will watch the partial committer's first few |
| commits to make sure everything's going smoothly.</p> |
| |
| <p>Patches submitted by a partial committer may be committed by that |
| committer even if they are outside that person's domain. This |
| requires approval (often expressed as a +1 vote) from at least one |
| full committer. In such a case, the approval should be noted in the |
| log message, like so:</p> |
| |
| <pre> |
| Approved by: lundblad |
| </pre> |
| |
| </div> |
| |
| <div class="h3" id="contrib-area" title="contrib-area"> |
| <h3>The contrib/ area</h3> |
| |
| <p>When a tool is accepted into the <i>contrib/</i> area, we |
| automatically offer its author partial commit access to maintain the |
| tool there. Any full committer can sponsor this. Usually no |
| discussion or vote is necessary, though if there are objections then |
| the usual decision-making procedures apply (attempt to reach consensus |
| first, then vote among the full committers if consensus cannot be |
| reached).</p> |
| |
| <p>Code under contrib/ must be open source, but need not have the same |
| license or copyright holder as Subversion itself.</p> |
| |
| </div> |
| |
| <div class="h3" id="obvious-fix" title="obvious-fix"> |
| <h3>The "obvious fix" rule</h3> |
| |
| <p>Any committer, whether full or partial, may commit fixes for |
| obvious typos, grammar mistakes, and formatting problems wherever they |
| may be — in the web pages, API documentation, code |
| comments, commit messages, etc. We rely on the committer's judgement |
| to determine what is "obvious"; if you're not sure, just ask.</p> |
| |
| </div> |
| |
| </div> |
| |
| |
| <div class="h2" id="configury" title="configury"> |
| <h2>The configuration/build system under unix</h2> |
| |
| <p>Greg Stein wrote a custom build system for Subversion, which had |
| been using `automake' and recursive Makefiles. Now it uses a single, |
| top-level Makefile, generated from Makefile.in (which is kept under |
| revision control). `Makefile.in' in turn includes `build-outputs.mk', |
| which is automatically generated from `build.conf' by the |
| `gen-make.py' script. Thus, the latter two are under revision |
| control, but `build-outputs.mk' is not.</p> |
| |
| <p>Here is Greg's original mail describing the system, followed by |
| some advice about hacking it:</p> |
| |
| <pre> |
| From: Greg Stein <gstein@lyra.org> |
| Subject: new build system (was: Re: CVS update: MODIFIED: ac-helpers ...) |
| To: dev@subversion.tigris.org |
| Date: Thu, 24 May 2001 07:20:55 -0700 |
| Message-ID: <20010524072055.F5402@lyra.org> |
| |
| On Thu, May 24, 2001 at 01:40:17PM -0000, gstein@tigris.org wrote: |
| > User: gstein |
| > Date: 01/05/24 06:40:17 |
| > |
| > Modified: ac-helpers .cvsignore svn-apache.m4 |
| > Added: . Makefile.in |
| > Log: |
| > Switch over to the new non-recursive build system. |
| >... |
| |
| Okay... this is it. We're now on the build system. |
| |
| "It works on my machine." |
| |
| I suspect there may be some tweaks to make on different OSs. I'd be |
| interested to hear if Ben can really build with normal BSD make. It |
| should be possible. |
| |
| The code supports building, installation, checking, and |
| dependencies. It does *NOT* yet deal with the doc/ subdirectory. That |
| is next; I figured this could be rolled out and get the kinks worked |
| out while I do the doc/ stuff. Oh, it doesn't build Neon or APR yet |
| either. I also saw a problem where libsvn_fs wasn't getting built |
| before linking one of the test proggies (see below). |
| |
| Basic operation: same as before. |
| |
| $ ./autogen.sh |
| $ ./configure OPTIONS |
| $ make |
| $ make check |
| $ make install |
| |
| There are some "make check" scripts that need to be fixed up. That'll |
| happen RSN. Some of them create their own log, rather than spewing to |
| stdout (where the top-level make will place the output into |
| [TOP]/tests.log). |
| |
| The old Makefile.am files are still around, but I'll be tossing those |
| along with a bunch of tweaks to all the .cvsignore files. There are a |
| few other cleanups, too. But that can happen as a step two. |
| |
| [ $ cvs rm -f `find . -name Makefile.rm` |
| |
| See the mistake in that line? I didn't when I typed it. The find |
| returned nothing, so cvs rm -f proceeded to delete my entire |
| tree. And the -f made sure to delete all my source files, too. Good |
| fugging thing that I had my mods in some Emacs buffers, or I'd be |
| bitching. |
| |
| I am *so* glad that Ben coded SVN to *not* delete locally modified |
| files *and* that we have an "undel" command. I had to go and tweak a |
| bazillion Entries files to undo the delete... |
| ] |
| |
| The top-level make has a number of shortcuts in it (well, actually in |
| build-outputs.mk): |
| |
| $ make subversion/libsvn_fs/libsvn_fs.la |
| |
| or |
| |
| $ make libsvn_fs |
| |
| The two are the same. So... when your test proggie fails to link |
| because libsvn_fs isn't around, just run "make libsvn_fs" to build it |
| immediately, then go back to the regular "make". |
| |
| Note that the system still conditionally builds the FS stuff based |
| on whether DB (See 'Building on Unix' below) is available, and |
| mod_dav_svn if Apache is available. |
| |
| Handy hint: if you don't like dependencies, then you can do: |
| |
| $ ./autogen.sh -s |
| |
| That will skip the dependency generation that goes into |
| build-outputs.mk. It makes the script run quite a bit faster (48 secs |
| vs 2 secs on my poor little Pentium 120). |
| |
| Note that if you change build.conf, you can simply run: |
| |
| $ ./gen-make.py build.conf |
| |
| to regen build-outputs.mk. You don't have to go back through the whole |
| autogen.sh / configure process. |
| |
| You should also note that autogen.sh and configure run much faster now |
| that we don't have the automake crap. Oh, and our makefiles never |
| re-run configure on you out of the blue (gawd, I hated when automake |
| did that to me). |
| |
| Obviously, there are going to be some tweaky things going on. I also |
| think that the "shadow" builds or whatever they're called (different |
| source and build dirs) are totally broken. Something tweaky will have |
| to happen there. But, thankfully, we only have one Makefile to deal |
| with. |
| |
| Note that I arrange things so that we have one generated file |
| (build-outputs.mk), and one autoconf-generated file (Makefile from |
| .in). I also tried to shove as much logic/rules into |
| Makefile.in. Keeping build-outputs.mk devoid of rules (thus, implying |
| gen-make.py devoid of rules in its output generation) manes that |
| tweaking rules in Makefile.in is much more approachable to people. |
| |
| I think that is about it. Send problems to the dev@ list and/or feel |
| free to dig in and fix them yourself. My next steps are mostly |
| cleanup. After that, I'm going to toss out our use of libtool and rely |
| on APR's libtool setup (no need for us to replicate what APR already |
| did). |
| |
| Cheers, |
| -g |
| |
| -- |
| Greg Stein, http://www.lyra.org/ |
| </pre> |
| |
| <p>And here is some advice for those changing or testing the |
| configuration/build system:</p> |
| |
| <pre> |
| From: Karl Fogel <kfogel@collab.net> |
| To: dev@subversion.tigris.org |
| Subject: when changing build/config stuff, always do this first |
| Date: Wed 28 Nov 2001 |
| |
| Yo everyone: if you change part of the configuration/build system, |
| please make sure to clean out any old installed Subversion libs |
| *before* you try building with your changes. If you don't do this, |
| your changes may appear to work fine, when in fact they would fail if |
| run on a truly pristine system. |
| |
| This script demonstrates what I mean by "clean out". This is |
| `/usr/local/cleanup.sh' on my system. It cleans out the Subversion |
| libs (and the installed httpd-2.0 libs, since I'm often reinstalling |
| that too): |
| |
| #!/bin/sh |
| |
| # Take care of libs |
| cd /usr/local/lib |
| rm -f APRVARS |
| rm -f libapr* |
| rm -f libexpat* |
| rm -f libneon* |
| rm -f libsvn* |
| |
| # Take care of headers |
| cd /usr/local/include |
| rm -f apr* |
| rm -f svn* |
| rm -f neon/* |
| |
| # Take care of headers |
| cd /usr/local/apache2/lib |
| rm -f * |
| |
| When someone reports a configuration bug and you're trying to |
| reproduce it, run this first. :-) |
| |
| The voice of experience, |
| -Karl |
| </pre> |
| |
| </div> |
| |
| |
| <div class="h2" id="releasing" title="releasing"> |
| <h2>How to release a distribution tarball</h2> |
| |
| <p>See <a href="release-process.html">The Subversion Release Procedure</a>.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="release-numbering" title="release-numbering"> |
| <h2>Release numbering, compatibility, and deprecation</h2> |
| |
| <p>Subversion uses "MAJOR.MINOR.PATCH" release numbers, with the same |
| guidelines as APR (see <a href="http://apr.apache.org/versioning.html" |
| >http://apr.apache.org/versioning.html</a>), plus a few extensions, |
| described later. The general idea is:</p> |
| |
| <ol> |
| |
| <li><p>Upgrading/downgrading between different patch releases in the |
| same MAJOR.MINOR line never breaks code. It may cause bugfixes |
| to disappear/reappear, but API signatures and semantics remain |
| the same. (Of course, the semantics may change in the trivial |
| ways appropriate for bugfixes, just not in ways that would |
| force adjustments in calling code.)</p> |
| </li> |
| |
| <li><p>Upgrading to a new minor release in the same major line may |
| cause new APIs to appear, but not remove any APIs. Any code |
| written to the old minor number will work with any later minor |
| number in that line. However, downgrading afterwards may not |
| work, if new code has been written that takes advantage of the |
| new APIs.</p> |
| </li> |
| |
| <li><p>When the major number changes, all bets are off. This is the |
| only opportunity for a full reset of the APIs, and while we try |
| not to gratuitously remove interfaces, we will use it to clean |
| house a bit.</p> |
| </li> |
| |
| </ol> |
| |
| <p>Subversion extends the APR guidelines to cover client/server |
| compatibility questions:</p> |
| |
| <ol> |
| |
| <li><p>A patch or minor number release of a server (or client) never |
| breaks compatibility with a client (or server) in the same |
| major line. However, new features offered by the release might |
| be unsupported without a corresponding upgrade to the other |
| side of the connection. For updating ra_svn code specifically, |
| please observe these principles:</p> |
| |
| <ol> |
| |
| <li><p>Fields can be added to any tuple; old clients will simply |
| ignore them. (Right now, the marshalling implementation |
| does not let you put number or boolean values in the |
| optional part of a tuple, but changing that will not affect |
| the protocol.)</p> |
| |
| <p>We can use this mechanism when information is added to an |
| API call.</p> |
| </li> |
| |
| <li><p>At connection establishment time, clients and servers exchange |
| a list of capability keywords.</p> |
| |
| <p>We can use this mechanism for more complicated changes, |
| like introducing pipelining or removing information from |
| API calls.</p> |
| </li> |
| |
| <li><p>New commands can be added; trying to use an unsupported |
| command will result in an error which can be checked and dealt |
| with.</p> |
| </li> |
| |
| <li><p>The protocol version number can be bumped to allow graceful |
| refusal of old clients or servers, or to allow a client or |
| server to detect when it has to do things the old way.</p> |
| |
| <p>This mechanism is a last resort, to be used when capability |
| keywords would be too hard to manage.</p> |
| </li> |
| |
| </ol> |
| </li> |
| |
| <li><p>Working copy and repository formats are backward- and |
| forward-compatible for all patch releases in the same minor |
| series. They are forward-compatible for all minor releases in |
| the same major series; however, a minor release is allowed to |
| make a working copy or repository that doesn't work with |
| previous minor releases, where "make" could mean "upgrade" as |
| well as "create".</p> |
| </li> |
| |
| </ol> |
| |
| <p>Subversion does not use the "even==stable, odd==unstable" |
| convention; any unqualified triplet indicates a stable release:</p> |
| |
| <pre> |
| 1.0.1 --> first stable patch release of 1.0 |
| 1.1.0 --> next stable minor release of 1.x after 1.0.x |
| 1.1.1 --> first stable patch release of 1.1.x |
| 1.1.2 --> second stable patch release of 1.1.x |
| 1.2.0 --> next stable minor release after that |
| </pre> |
| |
| <p>The order of releases is semi-nonlinear — a 1.0.3 |
| *might* come out after a 1.1.0. But it's only "semi"-nonlinear |
| because eventually we declare a patch line defunct and tell people to |
| upgrade to the next minor release, so over the long run the numbering |
| is basically linear.</p> |
| |
| <p>Non-stable releases are qualified with "alphaN" or "betaN" |
| suffixes, and release candidates with "-rcN". For example, the |
| prereleases leading to 1.3.7 might look like this:</p> |
| |
| <pre> |
| subversion-1.3.7-rc1.tar.gz |
| subversion-1.3.7-rc2.tar.gz |
| subversion-1.3.7-rc3.tar.gz |
| subversion-1.3.7.tar.gz |
| </pre> |
| |
| <p>The output of 'svn --version' corresponds in the obvious way:</p> |
| |
| <pre> |
| version 1.3.7 (Release Candidate 1) |
| version 1.3.7 (Release Candidate 2) |
| version 1.3.7 (Release Candidate 3) |
| version 1.3.7 |
| </pre> |
| |
| <p>When you 'make install' subversion-1.3.7-rc1, it still installs as |
| though it were "1.3.7", of course. The qualifiers are metadata on the |
| release; we want each subsequent prerelease release to overwrite the |
| previous one, and the final release to overwrite the last |
| prerelease.</p> |
| |
| <p>For working copy builds, there is no tarball name to worry about, |
| but 'svn --version' still produces special output:</p> |
| |
| <pre> |
| version 1.3.7 (dev build) |
| </pre> |
| |
| <p>The version number is the next version that the development was |
| working towards. The important thing is to say "dev build". This |
| indicates that the build came from a working copy, which is useful in |
| bug reports.</p> |
| |
| <p>We have no mechanism for releasing dated snapshots. If we want |
| code to get wider distribution than just those who build from working |
| copies, we put out a prerelease.</p> |
| |
| <div class="h3" id="name-reuse" title="name-reuse"> |
| <h3>Reuse of release names</h3> |
| |
| <p>If a release or candidate release needs to be quickly re-issued due |
| to some non-code problem (say, a packaging glitch), it's okay to reuse |
| the same name, as long as the tarball hasn't been |
| <a href="#tarball-signing">blessed by signing</a> yet. But if it has |
| been uploaded to the standard distribution area with signatures, or if |
| the re-issue was due to a change in code a user might run, then the |
| old name must be tossed and the next name used.</p> |
| |
| </div> |
| |
| <div class="h3" id="deprecation" title="deprecation"> |
| <h3>Deprecation</h3> |
| |
| <p>When a new, improved version of an API is introduced, the old one |
| remains for compatibility, at least until the next major release. |
| However, we mark the old one as deprecated and point to the new one, |
| so people know to write to the new API if at all possible. When |
| deprecating, mention the release after which the deprecation was |
| introduced, and point to the new API. If possible, replace the old |
| API documentation with a diff to the new one. For example:</p> |
| |
| <pre> |
| /** |
| * @deprecated Provided for backward compatibility with the 1.0.0 API. |
| * |
| * Similar to svn_repos_dump_fs2(), but with the @a use_deltas |
| * parameter always set to @c FALSE. |
| */ |
| svn_error_t *svn_repos_dump_fs(svn_repos_t *repos, |
| svn_stream_t *dumpstream, |
| svn_stream_t *feedback_stream, |
| svn_revnum_t start_rev, |
| svn_revnum_t end_rev, |
| svn_boolean_t incremental, |
| svn_cancel_func_t cancel_func, |
| void *cancel_baton, |
| apr_pool_t *pool); |
| </pre> |
| |
| <p>When the major release number changes, the "best" new API in a |
| series generally replaces all the previous ones (assuming it subsumes |
| their functionality), and it will take the name of the original API. |
| Thus, marking 'svn_repos_dump_fs' as deprecated in 1.1.x doesn't mean |
| that 2.0.0 doesn't have 'svn_repos_dump_fs', it just means the |
| function's signature will be different: it will have the signature |
| held by svn_repos_dump_fs2 (or svn_repos_dump_fs3, or whatever) in |
| 1.1.x. The numbered-suffix names disappear, and there is a single |
| (shiny, new) svn_repos_dump_fs again.</p> |
| |
| <p>One exception to this replacement strategy is when the old function |
| has a totally unsatisfying name anyway. Deprecation is a chance to |
| fix that: we give the new API a totally new name, mark the old API as |
| deprecated, point to the new API; then at the major version change, we |
| remove the old API, but don't rename the new one to the old name, |
| because its new name is fine.</p> |
| |
| </div> |
| |
| </div> |
| |
| |
| <div class="h2" id="release-stabilization" title="release-stabilization"> |
| <h2>Stabilizing and maintaining releases</h2> |
| |
| <p>Minor and major number releases go through a stabilization period |
| before release, and remain in maintenance (bugfix) mode after release. |
| To start the release process, we create an "A.B.x" branch based on the |
| latest trunk, for example:</p> |
| |
| <pre> |
| $ svn cp http://svn.collab.net/repos/svn/trunk \ |
| http://svn.collab.net/repos/svn/branches/A.B.x |
| </pre> |
| |
| <p>The stabilization period for a new A.B.0 release normally lasts |
| four weeks, and allows us to make conservative bugfixes and discover |
| showstopper issues. The stabilization period begins with a release |
| candidate tarball with the version A.B.0-rc1. Further release |
| candidate tarballs may be made as blocking bugs are fixed; for |
| example, if a set of language bindings is found to be broken, it is |
| prudent to make a new release candidate when they are fixed so that |
| those language bindings may be tested.</p> |
| |
| <p>At the beginning of the final week of the stabilization period, a |
| new release candidate tarball should be made if there are any changes |
| pending since the last one. The final week of the stabilization |
| period is reserved for critical bugfixes; fixes for minor bugs should |
| be deferred to the A.B.1 release. A critical bug is a non-edge-case |
| crash, a data corruption problem, a major security hole, or something |
| equally serious.</p> |
| |
| <p>Under some circumstances, the stabilization period will be |
| extended:</p> |
| |
| <ul> |
| <li><p>If a potentially destabilizing change must be made in order to |
| fix a bug, the entire four-week stabilization period is |
| restarted. A potentially destabilizing change is one which |
| could affect many parts of Subversion in unpredictable ways, or |
| which involves adding a substantial amount of new code. Any |
| incompatible API change (only allowable in the first place if |
| the new release is an A.0.0 release) should be considered a |
| potentially destabilizing change.</p> |
| </li> |
| |
| <li><p>If a critical bugfix is made during the final week of the |
| stabilization period, the final week is restarted. The final |
| A.B.0 release is always identical to the release candidate made |
| one week before (with the exceptions discussed below).</p> |
| </li> |
| |
| </ul> |
| |
| <p>If there are disagreements over whether a change is potentially |
| destabilizing or over whether a bug is critical, they may be settled |
| with a committer vote.</p> |
| |
| <p>After the A.B.0 release is out, patch releases (A.B.1, A.B.2, etc.) |
| follow when bugfixes warrant them. Patch releases do not require a |
| four week soak, because only conservative changes go into the |
| line.</p> |
| |
| <p>Certain kinds of commits can go into A.B.0 without restarting the |
| soak period, or into a later release without affecting the testing |
| schedule or release date:</p> |
| |
| <ul> |
| <li><p>Without voting:</p> |
| <ul> |
| <li><p>Changes to the STATUS file.</p></li> |
| <li><p>Documentation file changes, including to the book, README, |
| INSTALL, www/, etc.</p></li> |
| <li><p>Changes that are a normal part of release bookkeeping, for |
| example, the steps listed in notes/releases.txt.</p></li> |
| <li><p>Changes to dist.sh by, or approved by, the release manager.</p></li> |
| <li><p>Changes to message translations in .po files or additions of |
| new .po files.</p></li> |
| </ul> |
| </li> |
| |
| <li><p>With voting:</p> |
| <ul> |
| <li><p>Anything affecting only tools/, packages/, or bindings/.</p></li> |
| <li><p>Doc fixes in core code header or source files.</p></li> |
| <li><p>Changes to printed output, such as error and usage messages, as |
| long as format string "%" codes and their args are not |
| touched.</p></li> |
| </ul> |
| </li> |
| |
| </ul> |
| |
| <p>NOTE: The requirements on message translation changes are looser |
| than for text messages in C code. Changing format specifiers in .po |
| files is allowed because their validity can be checked mechanically |
| (with the -c flag on msgfmt of GNU gettext). This is done at build |
| time if GNU gettext is in use.</p> |
| |
| <p>Core code changes, of course, require voting, and restart the soak |
| or test period, since otherwise the change could be undertested.</p> |
| |
| <p>The voting system works like this:</p> |
| |
| <p>A change to the A.B.x line must be first proposed in the |
| A.B.x/STATUS file. Each proposal consists of a short identifying |
| block (e.g., the revision number of a trunk or related-line commit, or |
| perhaps an issue number), a brief description of the change, an |
| at-most-one-line justification of why it should be in A.B.x, perhaps |
| some notes/concerns, and finally the votes. The notes and concerns |
| are meant to be brief summaries to help a reader get oriented; please |
| don't use the STATUS file for actual discussion, use dev@ instead.</p> |
| |
| <p>Here's an example, probably as complex as an entry would ever |
| get:</p> |
| |
| <pre> |
| * r98765 (issue #56789) |
| Make commit editor take a closure object for future mindreading. |
| Justification: API stability, as prep for future enhancement. |
| Notes: There was consensus on the desirability of this feature in |
| the near future; see thread at http://... (Message-Id: blahblah). |
| Concerns: Vetoed by jerenkrantz due to privacy concerns with the |
| implementation; see thread at http://... (Message-Id: blahblah) |
| Votes: |
| +1: ghudson, bliss |
| +0: cmpilato |
| -0: gstein |
| -1: jerenkrantz |
| </pre> |
| |
| <p>A change needs three +1 votes from full committers (or partial |
| committers for the involved areas), and no vetoes, to go into |
| A.B.x.</p> |
| |
| <p>If you cast a veto (i.e. -1), please state the reason in the |
| concerns field, and include a url / message-id for the list discussion |
| if any. You can go back and add the link later if the thread isn't |
| available at the time you commit the veto.</p> |
| |
| <p>Voting +1 on a change doesn't just mean you approve of it in |
| principle. It means you have thoroughly reviewed the change, and find |
| it correct and as nondisruptive as possible. When it is committed to |
| the release branch, the log message will include the names of all who |
| voted for it, as well as the original author and the person making the |
| commit. All of these people are considered equally answerable for |
| bugs.</p> |
| |
| <p>If you've reviewed a patch, and like it but have some reservations, |
| you can write "+1 (concept)" and then ask questions on the list about |
| your concerns. You can write "+0" if you like the general idea but |
| haven't reviewed the patch carefully. Neither of these votes counts |
| toward the total, but they can be useful for tracking down people who |
| are following the change and might be willing to spend more time on |
| it.</p> |
| |
| <p>There is a somewhat looser voting system for areas that are not |
| core code, and that may have fewer experts available to review changes |
| (for example, tools/, packages/, bindings/, test scripts, etc.). A |
| change in these areas can go in with a +1 from a full committer or a |
| partial committer for that area, at least one +0 or "concept +1" from |
| any other committer, and no vetoes. (If a change affects the build |
| system, however, it is considered a core change, and needs three |
| +1's.) Use your judgment and don't review changes unless you have |
| some competence to do so, of course. The goal is to get at least two |
| pairs of eyes on the change, without demanding that every reviewer |
| have the same amount of expertise as the area maintainer. This way |
| one can review for general sanity, accurate comments, obvious |
| mistakes, etc, without being forced to assert "Yes, I understand these |
| changes in every detail and have tested them."</p> |
| |
| <p>Before proposing a change in STATUS, you should try merging it onto |
| the branch to ensure that it doesn't produce merge conflicts. If |
| conflicts occur, please create a new temporary branch from the release |
| branch with your changed merged and the conflicts resolved. The |
| branch should be named A.B.x-rYYYY, where YYYY is the first revision |
| of your change in the STATUS file. Add a note in the STATUS file |
| about the existence of the temporary branch. If the change involves |
| further work, you can merge those revisions to the branch. When the |
| entry for this change is removed from STATUS, this temporary branch |
| should also be removed to avoid cluttering the /branches |
| directory.</p> |
| |
| <p>NOTE: Changes to STATUS regarding the temporary branch, including |
| voting, are always kept on the main release branch.</p> |
| |
| </div> |
| |
| |
| <div class="h2" id="tarball-signing"> |
| <h2>Signing source distribution packages (a.k.a tarballs)</h2> |
| |
| <p>Before a release or release candidate is officially made public, it is |
| made available in a temporary location for committers to test and sign. |
| The point is to have the tarballs tested on more systems than just that of the |
| person who rolled the release. When there are three signatures from full |
| committers for each of the <tt>.tar.bz2</tt>, <tt>.tar.gz</tt> and |
| <tt>.zip</tt> files, the release (candidate) can go public.</p> |
| |
| <p>Signing a tarball means that you assert certain things about it. When |
| sending your signature (see below), indicate in the mail what steps |
| you've taken to verify that the tarball is correct. Running |
| <tt>make check</tt> over all RA layers and FS backends is a good idea, |
| as well as building and testing the bindings.</p> |
| |
| <p>After having extracted and tested the tarball, you should sign it using |
| <a href="http://www.gnupg.org">gpg</a>. To do so, use a command like:</p> |
| |
| <pre> |
| gpg -ba subversion-1.3.0-rc4.tar.bz2 |
| </pre> |
| |
| <p>This will result in a file with the same name as the signed file, but with |
| a <tt>.asc</tt> extension in the appropriate format for inclusion in the |
| release announcement. Include this file in a mail, typically in reply |
| to the announcement of the unofficial tarball.</p> |
| |
| <p>If you've downloaded and tested a <tt>.tar.bz2</tt> file, it is possible to |
| sign a <tt>.tar.gz</tt> file with the same contents without having |
| to download and test it separately. The trick is to extract the |
| <tt>.bz2</tt> file, and pack it using <tt>gzip</tt> like this:</p> |
| |
| <pre> |
| bzip2 -cd subversion-1.3.0-rc4.tar.bz2 \ |
| | gzip -9n > subversion-1.3.0-rc4.tar.gz |
| </pre> |
| |
| <p>The resulting file should be identical to the file generated by the |
| release manager, and thus can be signed as described above. |
| To verify that the files are identical, you may use either the MD5 checksums |
| or the release manager's signature, both of which should be provided with the |
| tarballs. |
| </p> |
| </div> |
| |
| <div class="h2" id="l10n" title="l10n"> |
| <h2>Localization (l10n)</h2> |
| |
| <p>Translation has been divided into two domains. First, there is the |
| translation of server messages sent to connecting clients. This issue |
| has been <a |
| href="http://svn.collab.net/repos/svn/trunk/notes/l10n-problems">punted |
| for now</a>. Second there is the translation of the client and its |
| libraries.</p> |
| |
| <p>The gettext package provides services for translating messages. It |
| uses the xgettext tool to extract strings from the sources for |
| translation. This works by extracting the arguments of the _() and |
| N_() macros. The former is used in context where function calls are |
| allowed (typically anything except static initializers). The latter |
| is used whenever _() isn't. Strings marked with N_() need to be |
| passed to gettext translation routines whenever referenced in the |
| code. For an example, look at how the header and footer are handled |
| in subversion/svn/help-cmd.c.</p> |
| |
| <p>When using direct calls to gettext routines (*gettext or |
| *dgettext), keep in mind that most of Subversion code is library code. |
| Therefore the default domain is not necessarily Subversion's own |
| domain. In library code you should use the dgettext versions of the |
| gettext functions. The domain name is defined in the PACKAGE_NAME |
| define.</p> |
| |
| <p>All required setup for localization is controlled by the ENABLE_NLS |
| conditional in svn_private_config.h (for *nix) and |
| svn_private_config.hw (for Windows). Be sure to put</p> |
| |
| <pre> |
| #include "svn_private_config.h" |
| </pre> |
| |
| <p>as the last include in any file which requires localization.</p> |
| |
| <p>Also note that return values of _() and *gettext() calls are UTF-8 |
| encoded; this means that they should be translated to the current |
| locale being written as any form of program output.</p> |
| |
| <p>The GNU gettext manual |
| (<a |
| href="http://www.gnu.org/software/gettext/manual/html_node/gettext_toc.html" |
| >http://www.gnu.org/software/gettext/manual/html_node/gettext_toc.html</a>) |
| provides additional information on writing translatable programs in |
| its section "Preparing Program Sources". Its hints mainly apply to |
| string composition.</p> |
| |
| </div> |
| |
| </div> |
| </body> |
| </html> |