If you are contributing code to the RapidSVN project, please read this first. ========================== HACKER'S GUIDE TO RAPIDSVN ========================== TABLE OF CONTENTS * Coding style * Documenting * Writing log messages * Other conventions * Maintainer's Corner Coding style ============ To understand how things work, read doc/svn-design.{texi,info,ps,pdf}, and read the header files, which tend to have thoroughly-commented data structures. char * // func type on own line argblarg (char *arg1, int arg2) // func name on own line, single // space between function name // and opening paren { // first brace on own line if ((some_very_long_condition && arg2) // indent 2 cols (no tabs!) || remaining_condition) // new line before operator { // brace on own line arg1 = some_func (arg1, arg2); // space before opening paren } // close brace on own line else { do // format do-while like this { arg1 = another_func (arg1); } while (*arg1); } } 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. Naming conventions ================== Do not use variable prefixes like used with the Hungarian Notation naming style. Instead, try to give the variable a short but appropriate name. Dont use variable names like "foo3" since people always will have to lookup the meaning of the variable. Class variables and module local variable get the prefix "m_". Here is an example (with inline code). *** foo.h *** class Foo { int m_myMember; Foo (int intitialFoo) { int bar = initialFoo * 2; m_myMember = bar; } } Documenting =================== Every function and class, whether public or internal, must start out with a documentation comment that describes what the function does. The comments are placed in the headers. Comments in the source files are only used for implementation details. The documentation format that we choose is the Doxygen format: http://www.stack.nl/~dimitri/doxygen/ Example: /** * Multiplies 2 numbers together. * @param number1 first number * @param number2 second number * @return the multiplied number */ int MultiplyMe (int number1, int number2); Read over the RapidSVN code to get an overview of how this documentation looks in practice. Writing log messages ==================== Certain guidelines should be adhered to when writing log messages: Make a log message for every change. The value of the log becomes much less if developers cannot rely on its completeness. Even if you've only changed comments, write a log that says "Doc fix." or something. 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. 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. 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: * twirl.cpp (twirling_baton_*): Removed these obsolete structures. (handle_parser_warning): Pass data directly to callees, instead of storing in twirling_baton_*. * twirl.h: Fix indentation. 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: * twirl.cpp (twirling_baton_fast, twirling_baton_slow): Removed these obsolete structures. (handle_parser_warning): Pass data directly to callees, instead of storing in twirling_baton_*. * twirl.h: Fix indentation. 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. Note how each file gets its own entry, and the changes within a file are grouped by symbol, with the symbols are listed in parentheses followed by a colon, followed by text describing the change. Please adhere to this format -- not only does consistency aid readability, it also allows software to colorize log entries automatically. If your change is related to a specific issue in the issue tracker, then include a string like "issue #N" in the log message. For example, if a patch resolves issue 1729, then the log message might be: Fix issue #1729: * get_editor.cpp (frobnicate_file): Check that file exists first. 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. 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: (consume_count): If `count' is unreasonable, return 0 and don't advance input pointer. And then, in `consume_count' in `cplus-dem.cpp': 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; } This is why a new function, for example, needs only a log entry saying "New Function" --- all the details should be in the source. There are some common-sense exceptions to the need to name everything that was changed: * 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". * If you have rewritten a file completely, the reader understands that everything in it has changed, so your log entry may simply give the file name, and say "Rewritten". * If your change was only to one file, or was the same change to multiple files, then there's no need to list their paths in the log message (because "svn log" can show the changed paths for that revision anyway). Only when you need to describe how the change affected different areas in different ways is it necessary to organize the log message by paths and symbols, as in the examples above. 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 your best judgment --- and be considerate of your fellow developers. (Also, run "svn log" to see how others have been writing their log entries.) Other conventions ================= In addition to the standards above, RapidSVN uses these conventions: * 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. * Stay within 80 columns, the width of a minimal standard display window. * If you add any files to the project that might be opened on more than one operating system then give the file the native eol-style property. This ensures that all files downloaded via svn arrive with the line endings native to that OS. Here is how you add the property: % svn propset eol-style native new_file.cpp * If you add images to the project make sure you apply the correct mime-type property. Example for a XPM: % svn propset svn:mime-type image/x-xpm Maintainer's Corner =================== For the RapidSVN website we are producing two types of packages: * Source tarball rapidsvn-???.tar.gz * Windows Installer RapidSVN-???.exe These are the steps to follow when creating a new release of RapidSVN: 0. Before Release: * Check the translations (in src/locale). * Make sure all the strings for all the translations are up to date (contact translators) 1. Release preparations: * Edit the version numbers in the file "version.xml" and run the Python script check-version.py (from the directory "tools") * Create the the change description in the "CHANGES" file * Commit "version.xml" and "CHANGES" * Create the version tag by copying (either using svn or RapidSVN): "svn cp -m "Version XYZ tag" . http://rapidsvn.tigris.org/svn/rapidsvn/tags/XYZ 2. Create source tarball (on Linux): * Checkout a fresh working copy of RapidSVN (using http://rapidsvn.tigris.org/svn/rapidsvn/tags/XYZ) from the repository to make sure everything is built and no old stuff is lying around * Make sure all the tools required are there (autoconf, automake, doxygen, xsltproc, docbook) * Run "autogen.sh", "configure", "make" "make dist" (no errors allowed!) * Uninstall older rapidsvn/libsvncpp version (if there) * Extract the source tarball to a temporary directory, check if everything is there and call "configure", "make", "make install" * Run RapidSVN * Send the tarball to xelarellum@tigris.org, so he can upload it to http://www.rapidsvn.org/download and create the necessary links in the files/documents section of http://rapidsvn.tigris.org 3. Create Windows installer (on Windows using MSVC 6): * Checkout a fresh working copy of RapidSVN (using http://rapidsvn.tigris.org/svn/rapidsvn/tags/XYZ) from the repository to make sure everything is built and no old stuff is lying around * Make sure you are using the latest stable release of Innosetup, Subversion, wxWidgets, Openssl, BerkeyleyDB. Build all these tools and libraries. Some minor changes in apr_config.h or apu_config.h may be necessary so subversion compiles. Follow the build instructions for the subversion distribution * Because of incompatibilities of the shfolder dll between different Internet Explorer/Windows versions make sure the settings for Visual C (in the menu "Extras->Options->Directories") are: - Platform SDK library files first in list - Platform SDK header files last in files * Open the workspace rapidsvn.dsw in Visual C and build the projects "rapidsvn.dsp" and "svncpp.dsp" in release mode. * Uninstall older RapidSVN version (if there) * Copy the Openssl and BerkeleyDB dlls to "packages/win32" * Open "packages/win32/rapidsvn.iss" and build the installer executable * Run the installer * Run RapidSVN * Send the installer executable to xelarellum@tigris.org, so he can upload it to http://www.rapidsvn.org/download and create the necessary links in the files/documents section of http://rapidsvn.tigris.org 3. Create a news entry on http://rapidsvn.tigris.org and send announcement emails (with same text) to announce@rapidsvn.tigris.org, dev@rapidsvn.tigris.org, users@rapidsvn.tigris.org including the MD5 checksums for both the source tarball and the win32 installer executable. 4. Update and commit (with CVS) the webpage http://rapidsvn.tigris.org. This includes changes to the roadmap items, archival of older roadmap items, updating of the svncpp doxygen documentation (you can use the output generated when building on Linux). 5. Update the issue tracker. This includes creation of new versions and milestones. Voila. Another release of RapidSVN is done!