Commits

Leho Kraav committed 49197c3 Merge

merge upstream 0.13-dev changes

  • Participants
  • Parent commits d4fbdc5, 9df6af6

Comments (0)

Files changed (274)

 doc/.build
 *.mo
 trac/htdocs/js/messages/*.js
+.project
+.pydevproject
+.settings
+[patterns]
+contrib/trac-svn-hook = LF
+**.cmd = CRLF
+** = native
+Trac 0.12.2 (? ?, 2010)
+http://svn.edgewall.org/repos/trac/tags/trac-0.12.2
+
+Trac 0.12.1 (October 9, 2010)
+http://svn.edgewall.org/repos/trac/tags/trac-0.12.1
+
+This list contains only a few highlights:
+ - db: improve concurrency behavior (#9111)
+ - fcgi: add an environment variable `TRAC_USE_FLUP` to control the usage of flup vs. bundled _fcgi.py (defaults to 0, i.e. use bundled as before)
+ - svn authz: improve compatibility with svn 1.5 format (#8289)
+ - milestone: allow to set the time for the due date (#6369, #9582)
+ - ticket: fixes for the CC: property (#8597, #9522)
+ - notification: improved the formatting of ticket fields in notification e-mails (#9484, #9494) 
+ - i18n: added a configuration option to set the default language (#8117)
+ - several fixes for upgrade (#9400, #9416, #9483, #9556)
+
 Trac 0.12 'Babel' (June 13, 2010)
 http://svn.edgewall.org/repos/trac/tags/trac-0.12
 
 Trac Installation Guide
 =======================
+
 Trac is a lightweight project management tool that is implemented as a
-web-based application. Trac is written in the Python programming language and
-can use SQLite, PostgreSQL or MySQL as database. For HTML rendering, Trac uses 
-the Genshi templating system.
+web-based application. Trac is written in the Python programming
+language and can use SQLite, PostgreSQL or MySQL as database. For HTML
+rendering, Trac uses the Genshi templating system.
 
-
-Note that you should also read the trac/wiki/default-pages/TracInstall 
-documentation file present in the source distribution.
-If you're upgrading an already installed environment, please also read
-trac/wiki/default-pages/TracUpgrade.
-
+Note that you should also read the
+**trac/wiki/default-pages/TracInstall** documentation file present in
+the source distribution.  If you're upgrading an already installed
+environment, please also read trac/wiki/default-pages/TracUpgrade.
 
 
 Requirements
 ------------
+
 To install Trac, the following software packages must be installed:
 
- * Python, version >= 2.4.
+ * Python, version >= 2.5.
  * setuptools, version >= 0.6
  * Genshi, version >= 0.6
- * Optionally, Subversion, version >= 1.1.x and the Subversion SWIG Python 
-   bindings (not PySVN, that's something different).
+ * Optionally, Subversion, version >= 1.1.x and the Subversion SWIG
+   Python bindings (not PySVN, that's something different).
  * One of the following Python bindings, depending on the database used:
-    * pysqlite version 2.x for SQLite 3.x (is part of the standard library 
-      starting with Python 2.5)
+    * pysqlite version 2.x for SQLite 3.x
     * psycopg2 version 2.0.x for the PostgreSQL database
     * MySQLdb, version 1.2.2 for the MySQL database
- * A web server capable of executing CGI/FastCGI scripts, or Apache HTTPD with
-   mod_python or mod_wsgi. (Trac also comes with a standalone server, tracd)
+ * A web server capable of executing CGI/FastCGI scripts, or Apache
+   HTTPD with mod_python or mod_wsgi. (Trac also comes with a
+   standalone server, tracd)
 
-Any of the above python library can usually be installed using easy_install,
-which itself can be installed using the following bootstrap script:
+Any of the above python library can usually be installed using
+easy_install, which itself can be installed using the following
+bootstrap script::
 
   $ wget http://peak.telecommunity.com/dist/ez_setup.py
 
 
 After that, you can do for example: easy_install Genshi
 
-If you're using Python 2.4 and need pysqlite, you can download from
-http://code.google.com/p/pysqlite/downloads/list the Windows installers or the
-tar.gz archive for building from source:
+Your version of Python comes with its own version of pysqlite, however
+if want to use the latest pysqlite package, you can download from
+http://code.google.com/p/pysqlite/downloads/list the Windows
+installers or the tar.gz archive for building from source::
 
   $ tar xvfz <version>.tar.gz
 
 
 Installing Trac
 ---------------
-The command:
+
+The command::
 
   $ python ./setup.py install
 
 will byte-compile the python source code and install it in the
-site-packages directory of your python installation. The directories cgi-bin,
-templates, htdocs and wiki-default are all copied to ``$prefix/share/trac/``.
+site-packages directory of your python installation. The directories
+cgi-bin, templates, htdocs and wiki-default are all copied to
+``$prefix/share/trac/``.
 
-The script will also install the trac-admin command-line tool, used to create
-and maintain project environments. Trac-admin is the command center of Trac.
+The script will also install the trac-admin command-line tool, used to
+create and maintain project environments. Trac-admin is the command
+center of Trac.
 
 Note: you'll need root permissions or equivalent for this step.
 
-To install Trac in a different location, or use other advanced installation
-options, run:
+To install Trac in a different location, or use other advanced
+installation options, run::
 
   $ python ./setup.py --help
 
 
 Installing Trac on Windows
 --------------------------
-If you downloaded the Trac installer (the .exe file), installing is simply a
-matter of running the installer.  After running the installer, configuration
-and installation is the same as for other platforms.
+
+If you downloaded the Trac installer (the .exe file), installing is
+simply a matter of running the installer.  After running the
+installer, configuration and installation is the same as for other
+platforms.
 
 
 Creating a Project Environment
 ------------------------------
-A Trac environment is the backend storage format where Trac stores information
-like wiki pages, tickets, reports, settings, etc. A Trac environment consists
-of the environment configuration file (trac.ini), custom templates, log files,
-and more.
 
-A new Trac environment is created with trac-admin:
+A Trac environment is the backend storage format where Trac stores
+information like wiki pages, tickets, reports, settings, etc. A Trac
+environment consists of the environment configuration file (trac.ini),
+custom templates, log files, and more.
+
+A new Trac environment is created with trac-admin::
 
   $ trac-admin /path/to/projectenv initenv
 
-Note: The user account under which the web server is run needs write permission
-to the environment directory and all the files inside.
+Note: The user account under which the web server is run needs write
+permission to the environment directory and all the files inside.
 
-trac-admin will prompt you for the name of the project, where your subversion
-repository is located, what database you want to use, etc.
+trac-admin will prompt you for the name of the project, where your
+subversion repository is located, what database you want to use, etc.
 
 
 Running the Standalone Server
 -----------------------------
-After having created a Trac environment, you can easily try the web interface
-by running the standalone server tracd:
+
+After having created a Trac environment, you can easily try the web
+interface by running the standalone server ``tracd``::
 
   $ tracd --port 8000 /path/to/projectenv
 
-Then, fire up a browser and visit http://localhost:8000/. You should get a
-simple listing of all environments that tracd knows about. Follow the link
-to the environment you just created, and you should see Trac in action.
+Then, fire up a browser and visit http://localhost:8000/. You should
+get a simple listing of all environments that tracd knows
+about. Follow the link to the environment you just created, and you
+should see Trac in action.
 
 
 Running Trac on a Web Server
 ----------------------------
-Trac provides three options for connecting to a "real" web server: CGI, FastCGI
-and mod_python. For decent performance, it is recommended that you use either
-FastCGI or mod_python.
 
-Please refer to the TracInstall page for details on these setups. You can find
-it either in the wiki of the Trac project you just created, or on the main Trac
-site.
+Trac provides three options for connecting to a "real" web server:
+CGI, FastCGI and mod_python. For decent performance, it is recommended
+that you use either FastCGI or mod_python.
+
+Please refer to the TracInstall page for details on these setups. You
+can find it either in the wiki of the Trac project you just created,
+or on the main Trac site.
 
 
 Using Trac
 ----------
-Once you have your Trac site up and running, you should be able to browse your
-subversion repository, create tickets, view the timeline, etc.
 
-Keep in mind that anonymous (not logged in) users can by default access most
-but not all of the features. You will need to configure authentication and
-grant additional permissions to authenticated users to see the full set of
-features.
+Once you have your Trac site up and running, you should be able to
+browse your subversion repository, create tickets, view the timeline,
+etc.
+
+Keep in mind that anonymous (not logged in) users can by default
+access most but not all of the features. You will need to configure
+authentication and grant additional permissions to authenticated users
+to see the full set of features.
 
 For further documentation, see the TracGuide wiki page.
 
-#          Makefile for testing Trac (see doc/dev/testing.rst)
+# == Makefile for Trac related tasks (beyond those supported by setuptools) ==
 #
-#          Some i18n tasks are also supported, see HELP below.
+# Automating testing, i18n tasks, documentation generation, ... see HELP below
 # ----------------------------------------------------------------------------
 #
-# Note that this is a GNU Makefile.
-# nmake and other abominations are not supported.
+# Note about customization:
+#   No changes to the present Makefile should be necessary,
+#   rather copy Makefile.cfg.sample to Makefile.cfg and adapt it
+#   to match your local environment.
 #
-# ----------------------------------------------------------------------------
+# Note that this is a GNU Makefile, nmake and other abominations are
+# not supported.
+#
+# ============================================================================
 
 define HELP
 
 
   [locale=...]        variable for selecting a set of locales
 
+ ---------------- Documentation tasks
+
+  apidoc|sphinx       generate the Sphinx documentation (all specified formats)
+  apidoc-html         generate the Sphinx documentation in HTML format
+  apidoc-pdf          generate the Sphinx documentation in PDF format
+
+  apiref|epydoc       generate the full API reference using Epydoc
+
+  [sphinxformat=...]  list of formats for generated documentation
+  [sphinxopts=...]    variable containing extra options for Sphinx
+  [sphinxopts-html=...] variable containing extra options used for html format
+  [epydocopts=...]    variable containing extra options for Epydoc
+  [dotpath=/.../dot]  path to Graphviz' dot program (not used yet)
+                         
 endef
 export HELP
 
 # ` (keep emacs font-lock happy)
 
+define HELP_CFG
+ It looks like you don't have a Makefile.cfg file yet.
+ You can get started by doing `cp Makefile.cfg.sample Makefile.cfg'
+ and then adapt it to your environment.
+endef
+export HELP_CFG
+
+# ============================================================================
+
 # ----------------------------------------------------------------------------
 #
 # Main targets
+#
+# ----------------------------------------------------------------------------
 
 .PHONY: all help status clean clean-bytecode clean-mo
 
 all: help
 endif
 
-help:
+help: Makefile.cfg
 	@echo "$$HELP"
 
+
+Makefile.cfg:
+	@echo "$$HELP_CFG"
+
 status:
 	@echo -n "Python version: "
 	@python -V
 Trac.egg-info: status
 	python setup.py egg_info
 
-clean: clean-bytecode clean-figleaf clean-coverage
+clean: clean-bytecode clean-figleaf clean-coverage clean-doc
 
 clean-bytecode:
 	find -name \*.py[co] -exec rm {} \;
 
-Makefile Makefile.cfg: ;
+Makefile: ;
 
 # ----------------------------------------------------------------------------
 #
-# Copy Makefile.cfg.sample to Makefile.cfg and adapt to your local environment,
-# no customizations to the present Makefile should be necessary.
-#
-#
 -include Makefile.cfg
 #
 # ----------------------------------------------------------------------------
 # ----------------------------------------------------------------------------
 #
 # L10N related tasks
+#
+# ----------------------------------------------------------------------------
 
 ifdef locale
     locales = $(locale)
 	@echo -n "$(@): "
 	@msgfmt --check $(messages.po) && msgfmt --check $(messages-js.po) \
 	 && echo OK
+	@rm -f messages.mo
 
 stats: pre-stats $(addprefix stats-,$(locales))
 
 # ----------------------------------------------------------------------------
 #
 # Testing related tasks
+#
+# ----------------------------------------------------------------------------
 
 .PHONY: test unit-test functional-test test-wiki
 
 # Coverage related tasks
 #
 # (see http://nedbatchelder.com/code/coverage/)
+#
+# ----------------------------------------------------------------------------
 
 .PHONY: coverage clean-coverage show-coverage
 
 # ** NOTE: there are still several issues with this **
 #  - as soon as a DocTestSuite is run, figleaf gets confused
 #  - functional-test-figleaf is broken (no .figleaf generated)
+#
+# ----------------------------------------------------------------------------
 
 .PHONY: figleaf clean-figleaf show-figleaf
 
 # ----------------------------------------------------------------------------
 #
 # Tracd related tasks
+#
+# ----------------------------------------------------------------------------
 
 port ?= 8000
 tracdopts ?= -r
  $(if $(wildcard $(env)/VERSION),$(env),-e $(env))
 endef
 
+.PHONY: server
+
 server: Trac.egg-info
 ifdef env
 	python trac/web/standalone.py $(server-options)
 	@echo "\`env' variable was not specified. See \`make help'."
 endif
 
+
 # ----------------------------------------------------------------------------
 #
+# Documentation related tasks
+#
+# ----------------------------------------------------------------------------
+
+.PHONY: apidoc sphinx apiref epydoc clean-doc
+
+# We also try to honor the "conventional" environment variables used by Sphinx
+sphinxopts ?= $(SPHINXOPTS)
+SPHINXBUILD ?= sphinx-build
+BUILDDIR ?= build/doc
+PAPER ?= a4
+sphinxopts-latex ?= -D latex_paper_size=$(PAPER)
+sphinxformat = html
+
+sphinx: apidoc
+apidoc: $(addprefix apidoc-,$(sphinxformat))
+
+apidoc-%:
+	@$(SPHINXBUILD) -b $(*) \
+	    $(sphinxopts) $(sphinxopts-$(*)) \
+	    -d build/doc/doctree \
+	    doc $(BUILDDIR)/$(*)
+
+
+epydoc: apiref
+apiref: doc-images
+	@python doc/runepydoc.py --config=doc/epydoc.conf \
+	    $(epydocopts) $(if $(dotpath),--dotpath=$(dotpath))
+
+doc-images: $(addprefix build/,$(wildcard doc/images/*.png))
+build/doc/images/%: doc/images/% | build/doc/images
+	@cp $(<) $(@) 
+build/doc/images:
+	@mkdir -p $(@)
+
+clean-doc:
+	rm -fr build/doc
+
+
+
+# ============================================================================
+#
 # Setup environment variables
 
 python-home := $(python.$(if $(python),$(python),$($(db).python)))

File Makefile.cfg.sample

 # ----------------------------------------------------------------------------
 # Database Backends (select with `db=` on the `make` command line)
 
-# db URIs 
+# db URIs
+sqlite.uri = sqlite:test.db
 mysql.uri = mysql://tracuser:tracpassword@localhost/trac
 postgres.uri = postgres://tracuser:tracpassword@localhost:5432/trac?schema=tractest
 
 auth = *,~/tracenvs/htdigest.realm,realm
 
 # ----------------------------------------------------------------------------
+# Settings for the documentation
+
+dotpath = /usr/local/bin/dot
+
+# ----------------------------------------------------------------------------
 # Custom rules 
 
 .PHONY: bigtest
-Release Notes for Trac 0.12 Babel Release
-=========================================
-June 13, 2010
+Release Notes for Trac 0.13 Cell Release
+========================================
+Month xx, 201x
 
 Highlights
 ----------
- * Translation of Trac in your language using Babel (http://babel.edgewall.org)
- * Multiple Repository Support per environment
- * Improved Wiki, more powerful syntax and nicer user interface with 
-   automatic preview in side-by-side editing mode
- * Improved Ticket user interface, with editable comments and 
-   automatic preview
+ * ...
+
 
 Detailed User Visible Changes
 -----------------------------
 
-A detailed view of the API changes since 0.11.x can be found in 
-TracDev/ReleaseNotes/0.12.
+A detailed view of the API changes since 0.12.x can be found in
+http://trac.edgewall.org/wiki/TracDev/ReleaseNotes/0.13.
 
 Developer-visible changes
 -------------------------
 
-A detailed view of the API changes since 0.11.x can be found in 
-TracDev/ApiChanges/0.12.
+A detailed view of the API changes since 0.12.x can be found in 
+http://trac.edgewall.org/wiki/TracDev/ApiChanges/0.13.
 
 Acknowledgements
 ----------------
+
 Many thanks to the growing number of people who have, and continue to,
-support the project. Also our thanks to all people providing feedback and
-bug reports that helps us making Trac better, easier to use and more
-effective. Starting with the 0.12 release, special thanks go to our
-many translators.
-Without your invaluable help, Trac would not evolve. Thank you all.
+support the project. Also our thanks to all people providing feedback
+and bug reports that helps us making Trac better, easier to use and
+more effective. Starting with the 0.12 release, special thanks go to
+our many translators.  Without your invaluable help, Trac would not
+evolve. Thank you all.
 
-Finally, we offer hope that Trac will prove itself useful to like-minded
-programmers around the world, and that this release will prove an
-improvement over the last version.
+Finally, we offer hope that Trac will prove itself useful to
+like-minded programmers around the world, and that this release will
+prove an improvement over the last version.
 
 Please let us know. :-)
 

File TESTING-README

- = Testing Readme =
+= Testing Readme =
 
 So, you want to see what's broken?  Eeeexcellent.
 
 If you are running python < 2.4.4, please see the troubleshooting section.
 
- == Quick Start ==
-First thing to do is run the tests.
-If you have genshi and twill installed on your system, you should be able to run the tests like this:
-{{{
-PYTHONPATH=. ./trac/test.py
-}}}
+== Quick Start ==
 
- == Slow Start ==
-If you want to test against specific versions of genshi, twill, pygments, etc., you can set those up like this:
+First thing to do is run the tests.  If you have genshi and twill
+installed on your system, you should be able to run the tests like
+this: {{{ PYTHONPATH=. ./trac/test.py }}}
+
+== Slow Start ==
+
+If you want to test against specific versions of genshi, twill,
+pygments, etc., you can set those up like this:
 {{{
 myworktree/trac
           /pygments-0.8
           /genshi-0.4.4
 }}}
 
-Run `python setup egg_info` in those subdirectories as needed.
-Then you can run:
+Run `python setup egg_info` in those subdirectories as needed.  Then
+you can run:
 {{{
 PYTHONPATH=.:../twill-0.9:../genshi-0.4.4:../pygments-0.8 ./trac/test.py
 }}}
 
-If you want to run just the functional tests, you can do that by running
+If you want to run just the functional tests, you can do that by
+running
 {{{
 PYTHONPATH=.:../twill-0.9:../genshi-0.4.4:../pygments-0.8 ./trac/tests/functional/testcases.py
 }}}
 }}}
 
 
-NOTE: Unlike most unittests, the functional tests share a test fixture across tests.  This means that you can't(*) run just one of the tests by itself.
-But you can run a sub-set of the functional tests:
+NOTE: Unlike most unittests, the functional tests share a test fixture
+across tests.  This means that you can't(*) run just one of the tests
+by itself.  But you can run a sub-set of the functional tests:
 {{{
 PYTHONPATH=.:../twill-0.9:../genshi-0.4.4:../pygments-0.8 ./trac/tests/functional/__init__.py
 PYTHONPATH=.:../twill-0.9:../genshi-0.4.4:../pygments-0.8 ./trac/ticket/tests/functional.py
 PYTHONPATH=.:../twill-0.9:../genshi-0.4.4:../pygments-0.8 ./trac/versioncontrol/tests/functional.py
 }}}
-Note that that there is a set of functional tests that are run regardless of what subset you choose; these tests setup the shared fixture.
 
+Note that that there is a set of functional tests that are run
+regardless of what subset you choose; these tests setup the shared
+fixture.
 
-(*) Unless you modify the code to comment out the other functional tests.  The test fixture is setup and torn down by `FunctionalTestSuite`, and it runs the tests added to it with `_tester` and `_testenv` set in the testcase objects.
 
-The functional tests require subversion, and use a random local port 8000-8999 for the test web server.
+(*) Unless you modify the code to comment out the other functional
+tests.  The test fixture is setup and torn down by
+`FunctionalTestSuite`, and it runs the tests added to it with
+`_tester` and `_testenv` set in the testcase objects.
 
- == Testing output and byproducts ==
+The functional tests require subversion, and use a random local port
+8000-8999 for the test web server.
+
+== Testing output and byproducts ==
+
 There is some logging done:
- - testing.log
+ testing.log ::
     output from trac environment creation, tracd, and some svn commands
- - functional-testing.log
+ functional-testing.log ::
     output from twill
 
-The test fixture is left behind in 'testenv' so you can inspect it when debugging a problem.
+The test fixture is left behind in 'testenv' so you can inspect it
+when debugging a problem.
 {{{
 testenv/htpasswd   -- the password/authentication for the test fixture.  password = username
        /repo       -- the Subversion repository
        /trac       -- the Trac environment
 }}}
-(Note that running the tests again will automatically delete this test environment and create a new one.  If you want to save a test environment, you will need to rename this directory before running the tests again.)
+(Note that running the tests again will automatically delete this test
+environment and create a new one.  If you want to save a test
+environment, you will need to rename this directory before running the
+tests again.)
 
 The command to serve the test environment is:
 {{{
 ./trac/web/standalone.py --basic-auth=trac,testenv/htpasswd, -s \
     --port=8888 testenv/trac
 }}}
-This is particularly useful when a test fails and you want to explore the environment to debug the problem.
+This is particularly useful when a test fails and you want to explore
+the environment to debug the problem.
 
- == Test Coverage ==
-You can now determine statement coverage of unittests and functional tests.  But you'll have to run them separately for now.
+== Test Coverage ==
 
-`figleaf` will need to be on your `PATH`.  Set the `FIGLEAF` environment variable to the figleaf command.
+You can now determine statement coverage of unittests and functional
+tests.  But you'll have to run them separately for now.
 
-Create a figleaf-exclude file with filename patterns to exclude.  For example:
+`figleaf` will need to be on your `PATH`.  Set the `FIGLEAF`
+environment variable to the figleaf command.
+
+Create a figleaf-exclude file with filename patterns to exclude.  For
+example:
 {{{
 /usr/lib/python.*/.*.py
 .*.html
 
 To run without figleaf, be sure to unset `FIGLEAF`.
 
---------------------------------------------------------------------------------
-== TROUBLESHOOTING: ==
+-----------------------------------------------------------------------------
+
+== Troubleshooting ==
 
  1. trac-admin is failing on initenv with this exception:
     {{{
     raise Exception('Failed with exitcode %s running trac-admin with %r' % (retval, args))
 Exception: Failed with exitcode 1 running trac-admin with ('initenv', 'testenv', 'sqlite:db/trac.db', 'svn', '..../testenv/repo')
     }}}
-    This can be caused by not having run `python setup.py egg_info` in the genshi tree.
+    This can be caused by not having run `python setup.py egg_info` in
+    the genshi tree.
 
- 2. Windows needs an implementation of crypt or fcrypt.  Carey Evans' pure
-    python version works, but prints warnings on Python 2.3 (they can be
-    ignored).  See http://carey.geek.nz/code/python-fcrypt/
+ 2. Windows needs an implementation of crypt or fcrypt.  Carey Evans'
+    pure python version works, but prints warnings on Python 2.3 (they
+    can be ignored).  See http://carey.geek.nz/code/python-fcrypt/
 
- 3. Python versions compatibility notes
-   * If using Python >=2.4.0, <2.4.4, you need to backport `unittest` from
-     2.4.4.  If you do not do this, you will get an `AttributeError` regarding
-     `_fixture` being unset on every test.
-   * If using Python >=2.3.0, <2.3.5, you need to backport a few modules for
-     `setuptools` to work properly (`httplib2`, `cookielib`, `_*CookieJar`) and
-     remove the tuple imports to replace with explicit line continuations.
-   * If using Python >=2.3.0, <2.4.0, you need `subprocess`, `unittest`, and
-     `traceback` from 2.4.4.  On Windows you also need to modify `subprocess.py`
-     to use `pywin32` instead of `_subprocess`.  Twill includes a `subprocess`
-     module that will not work in this situation because it is not modified.
-
  * Michele Cella
  * Sergey S. Chernov              sergeych@tancher.com
  * Felix Colins                   felix@keyghost.com
+ * Simon Cross                    hodgestar@gmail.com
  * Wesley Crucius                 wcrucius@sandc.com
  * Wolfram Diestel                diestel@steloj.de
  * Mujdat Dinc 
 Upgrade Instructions
 ====================
 
-A Trac environment sometimes needs to be upgraded before it can be used with
-a new version of Trac. This document describes the steps necessary to upgrade
-an environment.
+A Trac environment sometimes needs to be upgraded before it can be
+used with a new version of Trac. This document describes the steps
+necessary to upgrade an environment.
 
-Note that you should also read the trac/wiki/default-pages/TracUpgrade 
+Note that you should also read the trac/wiki/default-pages/TracUpgrade
 documentation file present in the source distribution.
 
-
-Note that Environment upgrades are not necessary for minor version releases
-unless otherwise noted. For example, there's no need to upgrade a Trac
-environment created with (or upgraded) 0.8.0 when installing 0.8.4 (or any
-other 0.8.x release).
+Note that Environment upgrades are not necessary for minor version
+releases unless otherwise noted. For example, there's no need to
+upgrade a Trac environment created with (or upgraded) 0.8.0 when
+installing 0.8.4 (or any other 0.8.x release).
 
 General Instructions
 --------------------
-Typically, there are four steps involved in upgrading to a newer version of
-Trac:
+
+Typically, there are four steps involved in upgrading to a newer
+version of Trac:
 
 1. Update the Trac Code
 
-Get the new version of Trac, either by downloading an offical release package
-or by checking it out from the Subversion repository.
+Get the new version of Trac, either by downloading an offical release
+package or by checking it out from the Subversion repository.
 
-If you have a source distribution, you need to run
+If you have a source distribution, you need to run::
 
    python setup.py install
 
-to install the new version. If you've downloaded the Windows installer, you
-execute it, and so on.
+to install the new version. If you've downloaded the Windows
+installer, you execute it, and so on.
 
-In any case, if you're doing a major version upgrade (such as from 0.8 to
-0.9), it is highly recommended that you first remove the existing Trac code.
-To do this, you need to delete the `trac` directory from the Python
-`lib/site-packages` directory. You may also want to remove the Trac `cgi-bin`,
-`htdocs` and `templates` directories that are commonly found in a directory
-called `share/trac` (the exact location depends on your platform).
+In any case, if you're doing a major version upgrade (such as from 0.8
+to 0.9), it is highly recommended that you first remove the existing
+Trac code.  To do this, you need to delete the `trac` directory from
+the Python `lib/site-packages` directory. You may also want to remove
+the Trac `cgi-bin`, `htdocs` and `templates` directories that are
+commonly found in a directory called `share/trac` (the exact location
+depends on your platform).
 
 2. Upgrade the Trac Environment
 
-Unless noted otherwise, upgrading between major versions (such as 0.8 and
-0.9) involves changes to the database schema, and possibly the layout of the
-environment. Fortunately, Trac provides automated upgrade scripts to ease the
-pain. These scripts are run via `trac-admin`:
+Unless noted otherwise, upgrading between major versions (such as 0.8
+and 0.9) involves changes to the database schema, and possibly the
+layout of the environment. Fortunately, Trac provides automated
+upgrade scripts to ease the pain. These scripts are run via
+`trac-admin`::
 
    trac-admin /path/to/projenv upgrade
 
 
 3. Update the Trac Documentation
 
-Every Trac environment includes a copy of the Trac documentation for the
-installed version. As you probably want to keep the included documentation in
-sync with the installed version of Trac, `trac-admin` provides a command to
-upgrade the documentation:
+Every Trac environment includes a copy of the Trac documentation for
+the installed version. As you probably want to keep the included
+documentation in sync with the installed version of Trac, `trac-admin`
+provides a command to upgrade the documentation::
 
    trac-admin /path/to/projenv wiki upgrade
 
-Note that this procedure will of course leave your `WikiStart` page intact.
+Note that this procedure will of course leave your `WikiStart` page
+intact.
 
 4. Restart the Web Server
 
 server (note this is not necessary for CGI).
 
 
-The following sections discuss any extra actions that may need to be taken
-to upgrade to specific versions of Trac.
+The following sections discuss any extra actions that may need to be
+taken to upgrade to specific versions of Trac.
+
+From 0.12.x to 0.13.x
+---------------------
+
+See below.
 
 From 0.11.x to 0.12.x
 ---------------------
 
-Really, go read trac/wiki/default-pages/TracUpgrade ...
+For this upgrade, the detailed information can be found either online
+at http://trac.edgewall.org/wiki/TracUpgrade or within the set of
+default wiki pages, part of this source distribution in
+trac/wiki/default-pages/TracUpgrade.
 
 From 0.10.x to 0.11.x
 ---------------------
 
  http://trac.edgewall.org/wiki/TracDev/ReleaseNotes/0.11#Caveats
 
-Also, you should be careful to check that the plugins you depend on have
-been ported to 0.11, as they most probably won't work without adaptation
-due to the numerous internal changes that occurred during 0.11 development.
-Note however that Clearsilver based plugin are still supported.
+Also, you should be careful to check that the plugins you depend on
+have been ported to 0.11, as they most probably won't work without
+adaptation due to the numerous internal changes that occurred during
+0.11 development.  Note however that Clearsilver based plugin are
+still supported.
 
 See: http://trac.edgewall.org/wiki/TracDev/ApiChanges/0.11
 
 
 From 0.9.x to 0.10.x
 --------------------
-Due to some changes in the Wiki syntax, you may notice that certain parts of 
-your pages no longer work as expected:
 
- * Previously, links to images would result in that image being embedded 
-   into the page. Since 0.10, links to images remain plain links. If you 
-   want to embed an image in the page, use the [[Image]] macro.
- * You can no longer use %20 in wiki links to encode spaces. Instead, you 
-   should quote the name containing spaces 
-   (for example, use wiki:"My page" instead of wiki:My%20page.) 
+Due to some changes in the Wiki syntax, you may notice that certain
+parts of your pages no longer work as expected:
 
-Several enhancements have been made to the version control subsystem, in
-particular for the support of scoped repositories has been improved. It is
-recommended that you perform a "trac-admin resync" operation to take
-advantage of these improvements.
+ * Previously, links to images would result in that image being
+   embedded into the page. Since 0.10, links to images remain plain
+   links. If you want to embed an image in the page, use the [[Image]]
+   macro.
+ * You can no longer use %20 in wiki links to encode spaces. Instead,
+   you should quote the name containing spaces (for example, use
+   wiki:"My page" instead of wiki:My%20page.)
 
-Also note that the argument list of the "trac-admin initenv" command has
-changed: there's a new argument for determining the type of version
-control system. The old usage was:
+Several enhancements have been made to the version control subsystem,
+in particular for the support of scoped repositories has been
+improved. It is recommended that you perform a "trac-admin resync"
+operation to take advantage of these improvements.
+
+Also note that the argument list of the "trac-admin initenv" command
+has changed: there's a new argument for determining the type of
+version control system. The old usage was::
 
    initenv <projectname> <db> <repospath> <templatepath>
 
-The new usage is:
+The new usage is::
 
    initenv <projectname> <db> <repostype> <repospath> <templatepath>
 
-If you're using any scripts that automate the creation of Trac environments,
-you will need to update them. If you're using Subversion, specify "svn" for
-the <repostype> argument.
+If you're using any scripts that automate the creation of Trac
+environments, you will need to update them. If you're using
+Subversion, specify "svn" for the <repostype> argument.
 
 
 From 0.9.3 to 0.9.4
 -------------------
-There is a bug in Pysqlite 1.x that causes reports using the "%" character 
-for LIKE clauses or date formatting to fail. You will need to use escape the 
-percent characters with another: "%%".
+
+There is a bug in Pysqlite 1.x that causes reports using the "%"
+character for LIKE clauses or date formatting to fail. You will need
+to use escape the percent characters with another: "%%".
 
 
 From 0.9.x to 0.9.3
 -------------------
-If you are using plugins you might need to upgrade them. See 
-http://trac.edgewall.org/milestone/0.9.3 for further details. 
+
+If you are using plugins you might need to upgrade them. See
+http://trac.edgewall.org/milestone/0.9.3 for further details.
 
 
 From 0.9-beta to 0.9
 --------------------
-If inclusion of the static resources (style sheets, javascript, images) is not
-working, check the value of the `htdocs_location` in trac.ini. For mod_python,
-Tracd and FastCGI, you can simply remove the option altogether. For CGI, you
-should fix it to point to the URL you mapped the Trac `htdocs` directory to.
 
-If you've been using plugins with a beta release of Trac 0.9, or have 
-disabled some of the built-in components, you might have to update the rules
-for disabling/enabling components in trac.ini. In particular, globally 
-installed plugins now need to be enabled explicitly. See the TracPlugins and 
-TracIni wiki pages for more information.
+If inclusion of the static resources (style sheets, javascript,
+images) is not working, check the value of the `htdocs_location` in
+trac.ini. For mod_python, Tracd and FastCGI, you can simply remove the
+option altogether. For CGI, you should fix it to point to the URL you
+mapped the Trac `htdocs` directory to.
 
-If you want to enable the display of all ticket changes in the timeline (the
-Ticket Details option), you now have to explicitly enable that in trac.ini,
-too:
+If you've been using plugins with a beta release of Trac 0.9, or have
+disabled some of the built-in components, you might have to update the
+rules for disabling/enabling components in trac.ini. In particular,
+globally installed plugins now need to be enabled explicitly. See the
+TracPlugins and TracIni wiki pages for more information.
+
+If you want to enable the display of all ticket changes in the
+timeline (the Ticket Details option), you now have to explicitly
+enable that in trac.ini, too::
 
    [timeline]
    ticket_show_details = true
 
 From 0.8.x to 0.9
 -----------------
-mod_python users will need to change the name of the mod_python handler in
-the Apache HTTPD configuration:
+
+mod_python users will need to change the name of the mod_python
+handler in the Apache HTTPD configuration::
 
    from: PythonHandler trac.ModPythonHandler
    to:   PythonHandler trac.web.modpython_frontend
 
-If you have PySQLite 2.x installed, Trac will now try to open your SQLite
-database using the SQLite 3.x file format. The database formats used by
-SQLite 2.8.x and SQLite 3.x are incompatible. If you get an error like "file
-is encrypted or is not a database" after upgrading, then you must convert
-your database file.
+If you have PySQLite 2.x installed, Trac will now try to open your
+SQLite database using the SQLite 3.x file format. The database formats
+used by SQLite 2.8.x and SQLite 3.x are incompatible. If you get an
+error like "file is encrypted or is not a database" after upgrading,
+then you must convert your database file.
 
-To do this, you need to have both SQLite 2.8.x and SQLite 3.x installed (they
-have different filenames so can coexist on the same system). Then use the
-following commands:
+To do this, you need to have both SQLite 2.8.x and SQLite 3.x
+installed (they have different filenames so can coexist on the same
+system). Then use the following commands::
 
    mv trac.db trac2.db
    sqlite trac2.db .dump | sqlite3 trac.db
 
-After testing that the conversion was successful, the `trac2.db` file can be
-deleted. For more information on the SQLite upgrade see
+After testing that the conversion was successful, the `trac2.db` file
+can be deleted. For more information on the SQLite upgrade see
 http://www.sqlite.org/version3.html.
 
-
 From 0.7.x to 0.8
 -----------------
-0.8 adds a new roadmap feature which requires additional permissions. While a
-fresh installation will by default grant `ROADMAP_VIEW` and `MILESTONE_VIEW`
-permissions to anonymous, these permissions have to be granted manually when
-upgrading:
+
+0.8 adds a new roadmap feature which requires additional
+permissions. While a fresh installation will by default grant
+`ROADMAP_VIEW` and `MILESTONE_VIEW` permissions to anonymous, these
+permissions have to be granted manually when upgrading::
 
    trac-admin /path/to/projectenv permission add anonymous MILESTONE_VIEW
    trac-admin /path/to/projectenv permission add anonymous ROADMAP_VIEW
 
 From 0.6.x to 0.7
 -----------------
+
 Trac 0.7 introduced a new database format, requiring manual upgrade.
 
-Previous versions of Trac stored wiki pages, ticket, reports, settings,
-etc. in a single SQLite database file. Trac 0.7 replaces this file
-with a new backend storage format; the 'Trac Environment', which is a
-directory containing an SQLite database, a human-readable configuration file,
-log-files and attachments.
+Previous versions of Trac stored wiki pages, ticket, reports,
+settings, etc. in a single SQLite database file. Trac 0.7 replaces
+this file with a new backend storage format; the 'Trac Environment',
+which is a directory containing an SQLite database, a human-readable
+configuration file, log-files and attachments.
 
 Fear not though, old-style Trac databases can easily be converted to
-Environments using the included `tracdb2env` program as follows:
+Environments using the included `tracdb2env` program as follows::
 
    tracdb2env /path/to/old/project.db /path/to/new/projectenv
 
-`tracdb2env` will create a new environment and copy the information from the
-old database to the new environment. The existing database will not be
-modified.
+`tracdb2env` will create a new environment and copy the information
+from the old database to the new environment. The existing database
+will not be modified.
 
 You also need to update your apache configuration:
 
-Change the line:
+Change the line::
 
    SetEnv TRAC_DB "/path/to/old/project.db"
 
-to:
+to::
 
    SetEnv TRAC_ENV "/path/to/new/projectenv"
 
 
 ----
 
-If you have trouble upgrading Trac, please ask questions on the mailing list:
+If you have trouble upgrading Trac, please ask questions on the
+mailing list:
 
   <http://trac.edgewall.org/wiki/MailingList>
 

File contrib/bugzilla2trac.py

 $Id$
 """
 
+from __future__ import with_statement
+
 import re
 
 ###
 class TracDatabase(object):
     def __init__(self, path):
         self.env = Environment(path)
-        self._db = self.env.get_db_cnx()
-        self._db.autocommit = False
         self.loginNameCache = {}
         self.fieldNameCache = {}
         from trac.db.api import DatabaseManager
-	self.using_postgres = DatabaseManager(self.env).connection_uri.startswith("postgres:")
-
-    def db(self):
-        return self._db
+	self.using_postgres = \
+                DatabaseManager(self.env).connection_uri.startswith("postgres:")
 
     def hasTickets(self):
-        c = self.db().cursor()
-        c.execute("SELECT count(*) FROM ticket")
-        return int(c.fetchall()[0][0]) > 0
+        return int(self.env.db_query("SELECT count(*) FROM ticket")[0][0] > 0)
 
     def assertNoTickets(self):
         if self.hasTickets():
         """Remove all severities, set them to `s`"""
         self.assertNoTickets()
 
-        c = self.db().cursor()
-        c.execute("DELETE FROM enum WHERE type='severity'")
-        for value, i in s:
-            print "  inserting severity '%s' - '%s'" % (value, i)
-            c.execute("""INSERT INTO enum (type, name, value)
-                                   VALUES (%s, %s, %s)""",
-                      ("severity", value.encode('utf-8'), i))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM enum WHERE type='severity'")
+            for value, i in s:
+                print "  inserting severity '%s' - '%s'" % (value, i)
+                db("""INSERT INTO enum (type, name, value)
+                      VALUES (%s, %s, %s)""",
+                   ("severity", value, i))
 
     def setPriorityList(self, s):
         """Remove all priorities, set them to `s`"""
         self.assertNoTickets()
 
-        c = self.db().cursor()
-        c.execute("DELETE FROM enum WHERE type='priority'")
-        for value, i in s:
-            print "  inserting priority '%s' - '%s'" % (value, i)
-            c.execute("""INSERT INTO enum (type, name, value)
-                                   VALUES (%s, %s, %s)""",
-                      ("priority", value.encode('utf-8'), i))
-        self.db().commit()
-
+        with self.env.db_transaction as db:
+            db("DELETE FROM enum WHERE type='priority'")
+            for value, i in s:
+                print "  inserting priority '%s' - '%s'" % (value, i)
+                db("INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)",
+                   ("priority", value, i))
 
     def setComponentList(self, l, key):
         """Remove all components, set them to `l`"""
         self.assertNoTickets()
 
-        c = self.db().cursor()
-        c.execute("DELETE FROM component")
-        for comp in l:
-            print "  inserting component '%s', owner '%s'" % \
-                            (comp[key], comp['owner'])
-            c.execute("INSERT INTO component (name, owner) VALUES (%s, %s)",
-                      (comp[key].encode('utf-8'),
-                       comp['owner'].encode('utf-8')))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM component")
+            for comp in l:
+                print "  inserting component '%s', owner '%s'" % \
+                                (comp[key], comp['owner'])
+                db("INSERT INTO component (name, owner) VALUES (%s, %s)",
+                   (comp[key], comp['owner']))
 
     def setVersionList(self, v, key):
         """Remove all versions, set them to `v`"""
         self.assertNoTickets()
 
-        c = self.db().cursor()
-        c.execute("DELETE FROM version")
-        for vers in v:
-            print "  inserting version '%s'" % (vers[key])
-            c.execute("INSERT INTO version (name) VALUES (%s)",
-                      (vers[key].encode('utf-8'),))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM version")
+            for vers in v:
+                print "  inserting version '%s'" % (vers[key])
+                db("INSERT INTO version (name) VALUES (%s)",
+                   (vers[key],))
 
     def setMilestoneList(self, m, key):
         """Remove all milestones, set them to `m`"""
         self.assertNoTickets()
 
-        c = self.db().cursor()
-        c.execute("DELETE FROM milestone")
-        for ms in m:
-            milestone = ms[key]
-            print "  inserting milestone '%s'" % (milestone)
-            c.execute("INSERT INTO milestone (name) VALUES (%s)",
-                      (milestone.encode('utf-8'),))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM milestone")
+            for ms in m:
+                milestone = ms[key]
+                print "  inserting milestone '%s'" % (milestone)
+                db("INSERT INTO milestone (name) VALUES (%s)",
+                   (milestone,))
 
     def addTicket(self, id, time, changetime, component, severity, priority,
                   owner, reporter, cc, version, milestone, status, resolution,
                   summary, description, keywords, customfields):
-        c = self.db().cursor()
 
-        desc = description.encode('utf-8')
+        desc = description
         type = "defect"
 
         if SEVERITIES:
 
         print "  inserting ticket %s -- %s" % (id, summary)
 
-        c.execute("""INSERT INTO ticket (id, type, time, changetime, component,
-                                         severity, priority, owner, reporter,
-                                         cc, version, milestone, status,
-                                         resolution, summary, description,
-                                         keywords)
-                                 VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s,
-                                         %s, %s, %s, %s, %s, %s, %s, %s)""",
-                  (id, type.encode('utf-8'), datetime2epoch(time),
-                   datetime2epoch(changetime), component.encode('utf-8'),
-                   severity.encode('utf-8'), priority.encode('utf-8'), owner,
-                   reporter, cc, version, milestone.encode('utf-8'),
-                   status.lower(), resolution, summary.encode('utf-8'), desc,
-                   keywords))
+        with self.env.db_transaction as db:
+            db("""INSERT INTO ticket (id, type, time, changetime, component,
+                                      severity, priority, owner, reporter, cc,
+                                      version, milestone, status, resolution,
+                                      summary, description, keywords)
+                  VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
+                          %s, %s, %s, %s)
+                  """, (id, type, datetime2epoch(time),
+                        datetime2epoch(changetime), component, severity,
+                        priority, owner, reporter, cc, version, milestone,
+                        status.lower(), resolution, summary, desc, keywords))
 
-        self.db().commit()
         if self.using_postgres:
-            c.execute("""SELECT SETVAL('ticket_id_seq', MAX(id)) FROM ticket;
-              SELECT SETVAL('report_id_seq', MAX(id)) FROM report""")
-        ticket_id = self.db().get_last_id(c, 'ticket')
+            with self.env.db_transaction as db:
+                c = db.cursor()
+                c.execute("""
+                    SELECT SETVAL('ticket_id_seq', MAX(id)) FROM ticket;
+                    SELECT SETVAL('report_id_seq', MAX(id)) FROM report""")
+                ticket_id = db.get_last_id(c, 'ticket')
 
         # add all custom fields to ticket
         for name, value in customfields.iteritems():
         return ticket_id
 
     def addTicketCustomField(self, ticket_id, field_name, field_value):
-        c = self.db().cursor()
-
         if field_value == None:
             return
-
-        c.execute("""INSERT INTO ticket_custom (ticket, name, value)
-                                 VALUES (%s, %s, %s)""",
-                  (ticket_id, field_name.encode('utf-8'), field_value.encode('utf-8')))
-
-        self.db().commit()
+        self.env.db_transaction("""
+            INSERT INTO ticket_custom (ticket, name, value) VALUES (%s, %s, %s)
+            """, (ticket_id, field_name, field_value))
 
     def addTicketComment(self, ticket, time, author, value):
-        comment = value.encode('utf-8')
+        comment = value
 
         if PREFORMAT_COMMENTS:
           comment = '{{{\n%s\n}}}' % comment
             if BUG_NO_RE.search(comment):
                 comment = re.sub(BUG_NO_RE, BUG_NO_REPL, comment)
 
-        c = self.db().cursor()
-        c.execute("""INSERT INTO ticket_change (ticket, time, author, field,
-                                                oldvalue, newvalue)
-                                        VALUES (%s, %s, %s, %s, %s, %s)""",
-                  (ticket, datetime2epoch(time), author, 'comment', '', comment))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("""INSERT INTO ticket_change (ticket, time, author, field,
+                                             oldvalue, newvalue)
+                  VALUES (%s, %s, %s, %s, %s, %s)
+                  """, (ticket, datetime2epoch(time), author, 'comment', '', 
+                        comment))
 
     def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue):
-        c = self.db().cursor()
 
         if field == "owner":
             if LOGIN_MAP.has_key(oldvalue):
         if oldvalue == newvalue:
             return
 
-        c.execute("""INSERT INTO ticket_change (ticket, time, author, field,
-                                                oldvalue, newvalue)
-                                        VALUES (%s, %s, %s, %s, %s, %s)""",
-                  (ticket, datetime2epoch(time), author, field,
-                   oldvalue.encode('utf-8'), newvalue.encode('utf-8')))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("""INSERT INTO ticket_change (ticket, time, author, field,
+                                             oldvalue, newvalue)
+                  VALUES (%s, %s, %s, %s, %s, %s)
+                  """, (ticket, datetime2epoch(time), author, field,
+                        oldvalue, newvalue))
 
     def addAttachment(self, author, a):
         if a['filename'] != '':
-            description = a['description'].encode('utf-8')
+            description = a['description']
             id = a['bug_id']
-            filename = a['filename'].encode('utf-8')
+            filename = a['filename']
             filedata = StringIO.StringIO(a['thedata'])
             filesize = len(filedata.getvalue())
             time = a['creation_ts']
             attachment = Attachment(self.env, 'ticket', id)
             attachment.author = author
             attachment.description = description
-            attachment.insert(filename, filedata, filesize, datetime2epoch(time))
+            attachment.insert(filename, filedata, filesize, 
+                              datetime2epoch(time))
             del attachment
 
     def getLoginName(self, cursor, userid):
             (_db, _host, _user, ("*" * len(_password)))
     mysql_con = MySQLdb.connect(host=_host,
                 user=_user, passwd=_password, db=_db, compress=1,
-                cursorclass=MySQLdb.cursors.DictCursor)
+                cursorclass=MySQLdb.cursors.DictCursor,
+                charset='utf8')
     mysql_cur = mysql_con.cursor()
 
     # init Trac environment
     # force mode...
     if _force == 1:
         print "\nCleaning all tickets..."
-        c = trac.db().cursor()
-        c.execute("DELETE FROM ticket_change")
-        trac.db().commit()
-
-        c.execute("DELETE FROM ticket")
-        trac.db().commit()
-
-        c.execute("DELETE FROM ticket_custom")
-        trac.db().commit()
-
-        c.execute("DELETE FROM attachment")
-	attachments_dir = os.path.join(os.path.normpath(trac.env.path),
-                                "attachments")
+        with trac.env.db_transaction as db:
+            db("DELETE FROM ticket_change")
+            db("DELETE FROM ticket")
+            db("DELETE FROM ticket_custom")
+            db("DELETE FROM attachment")
+        attachments_dir = os.path.join(os.path.normpath(trac.env.path),
+                                       "attachments")
         # Straight from the Python documentation.
         for root, dirs, files in os.walk(attachments_dir, topdown=False):
             for name in files:
                 os.rmdir(os.path.join(root, name))
         if not os.stat(attachments_dir):
             os.mkdir(attachments_dir)
-        trac.db().commit()
         print "All tickets cleaned..."
 
 
                 value = desc['thetext'])
 
         mysql_cur.execute("""SELECT * FROM bugs_activity WHERE bug_id = %s
-                           ORDER BY bug_when""" % bugid)
+                             ORDER BY bug_when""" % bugid)
         bugs_activity = mysql_cur.fetchall()
         resolution = ''
         ticketChanges = []
 
 def datetime2epoch(dt) :
     import time
-    return time.mktime(dt.timetuple())
+    return time.mktime(dt.timetuple()) * 1000000
 
 def usage():
     print """bugzilla2trac - Imports a bug database from Bugzilla into Trac.

File contrib/htdigest.py

 
 import errno
 import fileinput
+from getpass import getpass
+from hashlib import md5
+from optparse import OptionParser
 import sys
-from optparse import OptionParser
-from getpass import getpass
 
-# The md5 module is deprecated in Python 2.5
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
 
 def ask_pass():
     pass1 = getpass('New password: ')

File contrib/migrateticketmodel.py

 # 
 # Make sure to make a backup of the Trac environment before running this!
 
+from __future__ import with_statement
+
 import os
 import sys
 
         sys.exit(2)
 
     env = open_environment(sys.argv[1])
-    db = env.get_db_cnx()
+    with env.db_transaction:
+        for oldprio, newprio in priority_mapping.items():
+            priority = Priority(env, oldprio)
+            priority.name = newprio
+            priority.update()
 
-    for oldprio, newprio in priority_mapping.items():
-        priority = Priority(env, oldprio, db)
-        priority.name = newprio
-        priority.update(db)
-
-    for severity in list(Severity.select(env, db)):
-        severity.delete(db)
-
-    db.commit()
+        for severity in list(Severity.select(env)):
+            severity.delete()
 
 if __name__ == '__main__':
     main()

File contrib/sourceforge2trac.py

 Import a Sourceforge project's tracker items into a Trac database.
 
 Requires:
-   Trac 0.11 from http://trac.edgewall.org/
+   Trac 0.13 from http://trac.edgewall.org/
    Python 2.5 from http://www.python.org/
-           
+
+0.13 clean-up by cboos **untested**, use at your own risks and send patches
+
 The Sourceforge tracker items can be exported from the 'Backup' page
 of the project admin section. Substitute XXXXX with project id:
 https://sourceforge.net/export/xml_export2.php?group_id=XXXXX
 also want to rename ticket types and priorities to default.
 """
 
+from __future__ import with_statement
+
 from xml.etree.ElementTree import ElementTree
 import time
 import sys
         
         root = ElementTree().parse(f)   
         
-        self.users = dict([(FlatXML(u).userid, FlatXML(u).username) for u in root.find('referenced_users')])
+        self.users = dict([(FlatXML(u).userid, FlatXML(u).username) 
+                          for u in root.find('referenced_users')])
 
         for tracker in root.find('trackers'):
             tr = Tracker(tracker)
                 if res_id is not None and res_id not in self.used_resolutions:
                     for idx, name in self.resolutions:
                         if idx == res_id: break
-                    self.used_resolutions[res_id] = dict(self.resolutions)[res_id]
+                    self.used_resolutions[res_id] = \
+                            dict(self.resolutions)[res_id]
                 # used categories
                 categories = dict(self.get_categories(tr, noowner=True))
                 if tck.category_id not in self.used_categories:
-                    self.used_categories[tck.category_id] = categories[tck.category_id]
+                    self.used_categories[tck.category_id] = \
+                            categories[tck.category_id]
 
         # sorting everything
         self.trackers.sort(key=lambda x:x.name)
 class TracDatabase(object):
     def __init__(self, path):
         self.env = trac.env.Environment(path)
-        self._db = self.env.get_db_cnx()
-        self._db.autocommit = False
-        self._db.cnx.ping()
-    
-    def db(self):
-        return self._db
     
     def hasTickets(self):
-        c = self.db().cursor()
-        #c.execute("""DELETE FROM ticket""")
-        c.execute('''SELECT count(*) FROM ticket''')
-        return int(c.fetchall()[0][0]) > 0
+        return int(self.env.db_query("SELECT count(*) FROM ticket")[0][0]) > 0
 
     def dbCheck(self):
         if self.hasTickets():
     def setTypeList(self, s):
         """Remove all types, set them to `s`"""
         self.dbCheck()
-        c = self.db().cursor()
-        c.execute("""DELETE FROM enum WHERE type='ticket_type'""")
-        for i, value in enumerate(s):
-            c.execute("""INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""",
-                      ("ticket_type", value, i))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM enum WHERE type='ticket_type'")
+            for i, value in enumerate(s):
+                db("INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)",
+                   ("ticket_type", value, i))
     
     def setPriorityList(self, s):
         """Remove all priorities, set them to `s`"""
         self.dbCheck()
-        c = self.db().cursor()
-        c.execute("""DELETE FROM enum WHERE type='priority'""")
-        for i, value in enumerate(s):
-            c.execute("""INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""",
-                      ("priority", value, i))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM enum WHERE type='priority'")
+            for i, value in enumerate(s):
+                db("INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)",
+                   ("priority", value, i))
 
     def setResolutionList(self, t):
         """Remove all resolutions, set them to `t` (index, name)"""
         self.dbCheck()
-        c = self.db().cursor()
-        c.execute("""DELETE FROM enum WHERE type='resolution'""")
-        for value, name in t:
-            c.execute("""INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)""",
-                      ("resolution", name, value))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM enum WHERE type='resolution'")
+            for value, name in t:
+                db("INSERT INTO enum (type, name, value) VALUES (%s, %s, %s)",
+                   ("resolution", name, value))
     
     def setComponentList(self, t):
         """Remove all components, set them to `t` (name, owner)"""
         self.dbCheck()
-        c = self.db().cursor()
-        c.execute("""DELETE FROM component""")
-        for name, owner in t:
-            c.execute("""INSERT INTO component (name, owner) VALUES (%s, %s)""",
-                      (name, owner))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM component")
+            for name, owner in t:
+                db("INSERT INTO component (name, owner) VALUES (%s, %s)",
+                   (name, owner))
     
     def setVersionList(self, v):
         """Remove all versions, set them to `v`"""
         self.dbCheck()
-        c = self.db().cursor()
-        c.execute("""DELETE FROM version""")
-        for value in v:
-            # time and description are also available
-            c.execute("""INSERT INTO version (name) VALUES (%s)""",
-                      value)
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM version")
+            for value in v:
+                # time and description are also available
+                db("INSERT INTO version (name) VALUES (%s)", value)
         
     def setMilestoneList(self, m):
         """Remove all milestones, set them to `m` ("""
         self.dbCheck()
-        c = self.db().cursor()
-        c.execute("""DELETE FROM milestone""")
-        for value in m:
-            # due, completed, description are also available
-            c.execute("""INSERT INTO milestone (name) VALUES (%s)""",
-                      value)
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("DELETE FROM milestone")
+            for value in m:
+                # due, completed, description are also available
+                db("INSERT INTO milestone (name) VALUES (%s)", value)
     
     def addTicket(self, type, time, changetime, component,
                   priority, owner, reporter, cc,
         description     text,           -- problem description (long)
         keywords        text
         """
-        db = self.db()
-        c = db.cursor()
         if status.lower() == 'open':
             if owner != '':
                 status = 'assigned'
             else:
                 status = 'new'
 
-        c.execute("""INSERT INTO ticket (type, time, changetime, component,
-                                         priority, owner, reporter, cc,
-                                         version, milestone, status, resolution,
-                                         summary, description, keywords)
-                                 VALUES (%s, %s, %s,
-                                         %s, %s, %s, %s, %s,
-                                         %s, %s, %s, %s,
-                                         %s, %s, %s)""",
-                  (type, time, changetime, component,
-                  priority, owner, reporter, cc,
-                  version, milestone, status.lower(), resolution,
-                  summary, '%s' % description, keywords))
-        db.commit()
-        return db.get_last_id(c, 'ticket')
+        with self.env.db_transaction as db:
+            c = db.cursor()
+            c.execute("""
+                INSERT INTO ticket (type, time, changetime, component,
+                                    priority, owner, reporter, cc, version, 
+                                    milestone, status, resolution, summary,
+                                    description, keywords)
+                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
+                        %s, %s)
+                """, (type, time, changetime, component, priority, owner,
+                      reporter, cc, version, milestone, status.lower(),
+                      resolution, summary, '%s' % description, keywords))
+            return db.get_last_id(c, 'ticket')
     
     def addTicketComment(self, ticket, time, author, value):
-        c = self.db().cursor()
-        c.execute("""INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue)
-                                 VALUES        (%s, %s, %s, %s, %s, %s)""",
-                  (ticket, time, author, 'comment', '', '%s' % value))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("""
+                INSERT INTO ticket_change (ticket, time, author, field,
+                                           oldvalue, newvalue)
+                VALUES (%s, %s, %s, %s, %s, %s)
+                """, (ticket, time, author, 'comment', '', '%s' % value))
 
     def addTicketChange(self, ticket, time, author, field, oldvalue, newvalue):
-        c = self.db().cursor()
-        c.execute("""INSERT INTO ticket_change (ticket, time, author, field, oldvalue, newvalue)
-                                 VALUES        (%s, %s, %s, %s, %s, %s)""",
-                  (ticket, time, author, field, oldvalue, newvalue))
-        self.db().commit()
+        with self.env.db_transaction as db:
+            db("""INSERT INTO ticket_change (ticket, time, author, field,
+                                             oldvalue, newvalue)
+                  VALUES (%s, %s, %s, %s, %s, %s)
+                  """, (ticket, time, author, field, oldvalue, newvalue))
 
 
 def importData(f, env, opt):
     project = ExportedProjectData(f)
     trackers = project.trackers
     
-    db = TracDatabase(env)
+    trac = TracDatabase(env)
 
     # Data conversion
     typeList = [x.name for x in trackers]
         % (len(project.groups), project.groups)
     print "%d resolutions found :\n  %s" \
         % (len(project.resolutions), project.resolutions)
-    resolutions = [(k,project.used_resolutions[k]) for k in project.used_resolutions]
+    resolutions = [(k,project.used_resolutions[k]) 
+                   for k in project.used_resolutions]
     resolutions.sort(key=lambda x:int(x[0]))
     print ".. only %d used will be imported:\n  %s" \
         % (len(resolutions), resolutions)
         sys.exit()
 
     # Data save
-    db.setTypeList(typeList)
-    db.setComponentList(components)
-    db.setPriorityList(range(min(project.priorities), max(project.priorities)))
-    db.setVersionList(set([x[1] for x in project.groups]))
-    db.setResolutionList(resolutions)
-    db.setMilestoneList([])
+    trac.setTypeList(typeList)
+    trac.setComponentList(components)
+    trac.setPriorityList(range(min(project.priorities), 
+                               max(project.priorities)))
+    trac.setVersionList(set([x[1] for x in project.groups]))
+    trac.setResolutionList(resolutions)
+    trac.setMilestoneList([])
     
     for tracker in project.trackers:
       # id 100 means no component selected
-      component_lookup = dict(project.get_categories(noowner=True)+[("100", None)])
+      component_lookup = dict(project.get_categories(noowner=True) +
+                              [("100", None)])
       for t in tracker.tracker_items:
-        i = db.addTicket(type=tracker.name,
-                         time=int(t.submit_date),
-                         changetime=int(t.submit_date),
-                         component=component_lookup[t.category_id],
-                         priority=t.priority,
-                         owner=t.assignee if t.assignee not in user_map else user_map[t.assignee],
-                         reporter=t.submitter if t.submitter not in user_map else user_map[t.submitter],
-                         cc=None,
-                         # 100 means no group selected
-                         version=dict(project.groups+[("100", None)])[t.group_id],
-                         milestone=None,
-                         status=dict(project.statuses)[t.status_id],
-                         resolution=dict(resolutions)[t.resolution_id] if hasattr(t, "resolution_id") else None,
-                         summary=t.summary,
-                         description=t.details,
-                         keywords='sf'+t.id)
+        i = trac.addTicket(type=tracker.name,
+                           time=int(t.submit_date),
+                           changetime=int(t.submit_date),
+                           component=component_lookup[t.category_id],
+                           priority=t.priority,
+                           owner=t.assignee \
+                                   if t.assignee not in user_map \
+                                   else user_map[t.assignee],
+                           reporter=t.submitter \
+                                   if t.submitter not in user_map \
+                                   else user_map[t.submitter],
+                           cc=None,
+                           # 100 means no group selected
+                           version=dict(project.groups + 
+                                        [("100", None)])[t.group_id],
+                           milestone=None,
+                           status=dict(project.statuses)[t.status_id],
+                           resolution=dict(resolutions)[t.resolution_id] \
+                                   if hasattr(t, "resolution_id") else None,
+                           summary=t.summary,
+                           description=t.details,
+                           keywords='sf' + t.id)
 
         print 'Imported %s as #%d' % (t.id, i)