diff -Nru loggerhead-1.18.1+bzr457/debian/bzr-builddeb.conf loggerhead-1.19~bzr461/debian/bzr-builddeb.conf --- loggerhead-1.18.1+bzr457/debian/bzr-builddeb.conf 1970-01-01 00:00:00.000000000 +0000 +++ loggerhead-1.19~bzr461/debian/bzr-builddeb.conf 2011-10-24 15:07:44.000000000 +0000 @@ -0,0 +1,6 @@ +[BUILDDEB] +upstream-branch = lp:loggerhead +export-upstream-revision = tag:loggerhead-$UPSTREAM_VERSION + +[HOOKS] +merge-upstream = ./debian/update-deps.py diff -Nru loggerhead-1.18.1+bzr457/debian/changelog loggerhead-1.19~bzr461/debian/changelog --- loggerhead-1.18.1+bzr457/debian/changelog 2011-11-04 14:16:29.000000000 +0000 +++ loggerhead-1.19~bzr461/debian/changelog 2012-03-11 10:27:46.000000000 +0000 @@ -1,8 +1,15 @@ -loggerhead (1.18.1+bzr457-1~bazaar1~lucid1) lucid; urgency=low +loggerhead (1.19~bzr461-1~bazaar1~lucid1) lucid; urgency=low * Rebuild in PPA. - -- Max Bowsher <_@maxb.eu> Fri, 04 Nov 2011 14:16:29 +0000 + -- Max Bowsher <_@maxb.eu> Sun, 11 Mar 2012 10:27:46 +0000 + +loggerhead (1.19~bzr461-1) unstable; urgency=low + + * New upstream snapshot. + * Add build-dependency on python-fixtures, required for running testsuite. + + -- Jelmer Vernooij Sat, 26 Nov 2011 18:50:21 +0100 loggerhead (1.18.1+bzr457-1) unstable; urgency=low diff -Nru loggerhead-1.18.1+bzr457/debian/control loggerhead-1.19~bzr461/debian/control --- loggerhead-1.18.1+bzr457/debian/control 2011-09-30 08:19:12.000000000 +0000 +++ loggerhead-1.19~bzr461/debian/control 2011-12-08 04:37:21.000000000 +0000 @@ -4,7 +4,7 @@ Maintainer: Debian Bazaar Maintainers Uploaders: Jelmer Vernooij , Roland Mas Homepage: https://launchpad.net/loggerhead -Build-Depends-Indep: bzr (>= 1.17~), bzr (<< 2.5.0), python-testtools, python-subunit, python-bzrlib.tests | bzr (<< 2.4.0~beta1-2), python-sphinx +Build-Depends-Indep: bzr (>= 1.17~), bzr (<< 2.6.0), python-testtools, python-subunit, python-bzrlib.tests | bzr (<< 2.4.0~beta1-2), python-sphinx, python-fixtures Build-Depends: debhelper (>= 7.0.50~), python (>= 2.6.6-3), python-pkg-resources, python-paste (>= 1.6), python-simpletal, python-simplejson Standards-Version: 3.9.2 X-Python-Version: >= 2.4 @@ -13,14 +13,14 @@ Package: loggerhead Architecture: all -Depends: bzr (>= 1.17~), bzr (<< 2.5~), ${python:Depends}, python-simpletal, python-pkg-resources, python-paste (>= 1.6), ${misc:Depends}, adduser, python-simplejson, python-bzrlib (>= 1.17~), python-bzrlib (<< 2.5.0) -Suggests: python-pastedeploy (>= 1.3.0), loggerhead-doc +Depends: ${python:Depends}, python-simpletal, python-pkg-resources, python-paste (>= 1.6), ${misc:Depends}, adduser, python-simplejson, python-bzrlib (>= 1.17~), python-bzrlib (<< 2.6.0) +Suggests: python-pastedeploy (>= 1.3.0), loggerhead-doc, bzr Enhances: bzr Recommends: bzr-search, python-pygments Description: Web viewer for Bazaar This is a web viewer for projects in the Bazaar version control system. It can be used to navigate a branch history, annotate files, view patches and - perform searches. + perform searches. Package: loggerhead-doc Architecture: all diff -Nru loggerhead-1.18.1+bzr457/info.py loggerhead-1.19~bzr461/info.py --- loggerhead-1.18.1+bzr457/info.py 2011-03-19 08:35:57.000000000 +0000 +++ loggerhead-1.19~bzr461/info.py 2011-11-23 08:33:12.000000000 +0000 @@ -3,11 +3,12 @@ bzr_plugin_name = "loggerhead" -bzr_plugin_version = (1, 18, 0) +bzr_plugin_version = (1, 18, 1) # Keep in sync with loggerhead/__init__.py bzr_compatible_versions = [ (1, 17, 0), (1, 18, 0), (2, 0, 0), (2, 1, 0), (2, 2, 0), (2, 3, 0), - (2, 4, 0)] + (2, 4, 0), (2, 5, 0), + ] bzr_minimum_version = bzr_compatible_versions[0] diff -Nru loggerhead-1.18.1+bzr457/loggerhead/apps/branch.py loggerhead-1.19~bzr461/loggerhead/apps/branch.py --- loggerhead-1.18.1+bzr457/loggerhead/apps/branch.py 2011-08-17 11:04:00.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/apps/branch.py 2011-11-23 08:18:35.000000000 +0000 @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -# + """The WSGI application for serving a Bazaar branch.""" import logging @@ -22,6 +22,7 @@ import bzrlib.branch import bzrlib.errors +from bzrlib.hooks import Hooks import bzrlib.lru_cache from paste import request @@ -33,7 +34,7 @@ from loggerhead.controllers.atom_ui import AtomUI from loggerhead.controllers.changelog_ui import ChangeLogUI from loggerhead.controllers.diff_ui import DiffUI -from loggerhead.controllers.download_ui import DownloadUI +from loggerhead.controllers.download_ui import DownloadUI, DownloadTarballUI from loggerhead.controllers.filediff_ui import FileDiffUI from loggerhead.controllers.inventory_ui import InventoryUI from loggerhead.controllers.revision_ui import RevisionUI @@ -49,7 +50,13 @@ def __init__(self, branch, friendly_name=None, config={}, graph_cache=None, branch_link=None, is_root=False, - served_url=_DEFAULT, use_cdn=False): + served_url=_DEFAULT, use_cdn=False, private=False, + export_tarballs=True): + """Create branch-publishing WSGI app. + + :param export_tarballs: If true, allow downloading snapshots of revisions + as tarballs. + """ self.branch = branch self._config = config self.friendly_name = friendly_name @@ -61,6 +68,14 @@ self.is_root = is_root self.served_url = served_url self.use_cdn = use_cdn + self.private = private + self.export_tarballs = export_tarballs + + def public_private_css(self): + if self.private: + return "private" + else: + return "public" def get_history(self): revinfo_disk_cache = None @@ -123,6 +138,7 @@ 'revision': RevisionUI, 'search': SearchUI, 'view': ViewUI, + 'tarball': DownloadTarballUI, } def last_updated(self): @@ -155,6 +171,10 @@ self.served_url = self.url([]) except bzrlib.errors.InvalidURL: self.served_url = None + for hook in self.hooks['controller']: + controller = hook(self, environ) + if controller is not None: + return controller path = request.path_info_pop(environ) if not path: raise httpexceptions.HTTPMovedPermanently( @@ -165,9 +185,9 @@ environ['loggerhead.as_json'] = True path = request.path_info_pop(environ) cls = self.controllers_dict.get(path) - if cls is None: - raise httpexceptions.HTTPNotFound() - return cls(self, self.get_history) + if cls is not None: + return cls(self, self.get_history) + raise httpexceptions.HTTPNotFound() def app(self, environ, start_response): self.branch.lock_read() @@ -181,3 +201,23 @@ raise finally: self.branch.unlock() + + +class BranchWSGIAppHooks(Hooks): + """A dictionary mapping hook name to a list of callables for WSGI app branch hooks. + """ + + def __init__(self): + """Create the default hooks. + """ + Hooks.__init__(self, "bzrlib.plugins.loggerhead.apps.branch", + "BranchWSGIApp.hooks") + self.add_hook('controller', + "Invoked when looking for the controller to use for a " + "branch subpage. The api signature is (branch_app, environ)." + "If a hook can provide a controller, it should return one, " + "as a standard WSGI app. If it can't provide a controller, " + "it should return None", (1, 19)) + + +BranchWSGIApp.hooks = BranchWSGIAppHooks() diff -Nru loggerhead-1.18.1+bzr457/loggerhead/config.py loggerhead-1.19~bzr461/loggerhead/config.py --- loggerhead-1.18.1+bzr457/loggerhead/config.py 2010-05-12 14:38:05.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/config.py 2011-07-07 19:09:11.000000000 +0000 @@ -36,6 +36,7 @@ use_cdn=False, sql_dir=None, allow_writes=False, + export_tarballs=True, ) parser.add_option("--user-dirs", action="store_true", help="Serve user directories as ~user.") @@ -75,6 +76,8 @@ help="The directory to place the SQL cache in") parser.add_option("--allow-writes", action="store_true", help="Allow writing to the Bazaar server.") + parser.add_option("--export-tarballs", action="store_true", + help="Allow exporting revisions to tarballs.") return parser diff -Nru loggerhead-1.18.1+bzr457/loggerhead/controllers/download_ui.py loggerhead-1.19~bzr461/loggerhead/controllers/download_ui.py --- loggerhead-1.18.1+bzr457/loggerhead/controllers/download_ui.py 2010-05-05 19:03:40.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/controllers/download_ui.py 2011-11-25 01:41:07.000000000 +0000 @@ -19,46 +19,51 @@ import logging import mimetypes +import os import urllib from paste import httpexceptions from paste.request import path_info_pop from loggerhead.controllers import TemplatedBranchView +from loggerhead.exporter import export_archive log = logging.getLogger("loggerhead.controllers") class DownloadUI (TemplatedBranchView): - def __call__(self, environ, start_response): - # /download///[filename] + def encode_filename(self, filename): - h = self._history + return urllib.quote(filename.encode('utf-8')) + def get_args(self, environ): args = [] while True: arg = path_info_pop(environ) if arg is None: break args.append(arg) + return args + def __call__(self, environ, start_response): + # /download///[filename] + h = self._history + args = self.get_args(environ) if len(args) < 2: raise httpexceptions.HTTPMovedPermanently( self._branch.absolute_url('/changes')) - revid = h.fix_revid(args[0]) file_id = args[1] path, filename, content = h.get_file(file_id, revid) mime_type, encoding = mimetypes.guess_type(filename) if mime_type is None: mime_type = 'application/octet-stream' - self.log.info('/download %s @ %s (%d bytes)', path, h.get_revno(revid), len(content)) - encoded_filename = urllib.quote(filename.encode('utf-8')) + encoded_filename = self.encode_filename(filename) headers = [ ('Content-Type', mime_type), ('Content-Length', str(len(content))), @@ -67,3 +72,36 @@ ] start_response('200 OK', headers) return [content] + + +class DownloadTarballUI(DownloadUI): + + def __call__(self, environ, start_response): + """Stream a tarball from a bazaar branch.""" + # Tried to re-use code from downloadui, not very successful + if not self._branch.export_tarballs: + raise httpexceptions.HTTPForbidden( + "Tarball downloads are not allowed") + archive_format = "tgz" + history = self._history + self.args = self.get_args(environ) + if len(self.args): + revid = history.fix_revid(self.args[0]) + version_part = '-r' + self.args[0] + else: + revid = self.get_revid() + version_part = '' + # XXX: Perhaps some better suggestion based on the URL or path? + # + # TODO: Perhaps set the tarball suggested mtime to the revision + # mtime. + root = self._branch.friendly_name or 'branch' + encoded_filename = self.encode_filename( + root + version_part + '.' + archive_format) + headers = [ + ('Content-Type', 'application/octet-stream'), + ('Content-Disposition', + "attachment; filename*=utf-8''%s" % (encoded_filename,)), + ] + start_response('200 OK', headers) + return export_archive(history, root, revid, archive_format) diff -Nru loggerhead-1.18.1+bzr457/loggerhead/controllers/__init__.py loggerhead-1.19~bzr461/loggerhead/controllers/__init__.py --- loggerhead-1.18.1+bzr457/loggerhead/controllers/__init__.py 2011-06-28 16:09:37.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/controllers/__init__.py 2011-07-07 19:09:11.000000000 +0000 @@ -21,7 +21,7 @@ import simplejson import time -from paste.httpexceptions import HTTPNotFound +from paste.httpexceptions import HTTPNotFound, HTTPSeeOther from paste.request import path_info_pop, parse_querystring from loggerhead import util diff -Nru loggerhead-1.18.1+bzr457/loggerhead/controllers/revision_ui.py loggerhead-1.19~bzr461/loggerhead/controllers/revision_ui.py --- loggerhead-1.18.1+bzr457/loggerhead/controllers/revision_ui.py 2011-09-02 09:43:57.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/controllers/revision_ui.py 2011-11-23 08:18:35.000000000 +0000 @@ -140,6 +140,7 @@ self._branch.friendly_name, self._branch.is_root, 'changes')) + can_export = self._branch.export_tarballs values.update({ 'history': self._history, @@ -153,6 +154,7 @@ 'filter_file_id': filter_file_id, 'diff_chunks': diff_chunks, 'query': query, + 'can_export': can_export, 'specific_path': path, 'start_revid': start_revid, }) diff -Nru loggerhead-1.18.1+bzr457/loggerhead/exporter.py loggerhead-1.19~bzr461/loggerhead/exporter.py --- loggerhead-1.18.1+bzr457/loggerhead/exporter.py 1970-01-01 00:00:00.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/exporter.py 2011-11-24 07:46:41.000000000 +0000 @@ -0,0 +1,60 @@ +# Copyright (C) 2011 Canonical Ltd +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +"""Exports an archive from a bazaar branch""" + +from bzrlib.export import get_export_generator + + +class ExporterFileObject(object): + """Shim that accumulates temporarily written out data. + + There are python tarfile classes that want to write to a file like object. + We want to stream data. But wsgi assumes it can pull data from the + handler, rather than having bytes pushed. + + So this class holds the data temporarily, until it is pulled. It + should never buffer everything because as soon as a chunk is produced, + wsgi will be given the chance to take it. + """ + + def __init__(self): + self._buffer = [] + + def write(self, s): + self._buffer.append(s) + + def get_buffer(self): + try: + return ''.join(self._buffer) + finally: + self._buffer = [] + + def close(self): + pass + + +def export_archive(history, root, revid, archive_format): + """Export tree contents to an archive + + :param history: Instance of history to export + :param root: Root location inside the archive. + :param revid: Revision to export + :param archive_format: Format of the archive, eg 'tar.gz'. + """ + fileobj = ExporterFileObject() + tree = history._branch.repository.revision_tree(revid) + for _ in get_export_generator(tree=tree, root=root, fileobj=fileobj, + format=archive_format): + yield fileobj.get_buffer() + # Might have additonal contents written + yield fileobj.get_buffer() diff -Nru loggerhead-1.18.1+bzr457/loggerhead/history.py loggerhead-1.19~bzr461/loggerhead/history.py --- loggerhead-1.18.1+bzr457/loggerhead/history.py 2011-08-17 11:04:00.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/history.py 2011-11-23 08:29:50.000000000 +0000 @@ -33,6 +33,7 @@ import re import textwrap import threading +import tarfile from bzrlib import tag import bzrlib.branch @@ -803,4 +804,6 @@ renamed=sorted(reporter.renamed, key=lambda x: x.new_filename), removed=sorted(reporter.removed, key=lambda x: x.filename), modified=sorted(reporter.modified, key=lambda x: x.filename), - text_changes=sorted(reporter.text_changes, key=lambda x: x.filename)) + text_changes=sorted(reporter.text_changes, + key=lambda x: x.filename)) + diff -Nru loggerhead-1.18.1+bzr457/loggerhead/__init__.py loggerhead-1.19~bzr461/loggerhead/__init__.py --- loggerhead-1.18.1+bzr457/loggerhead/__init__.py 2011-03-24 03:40:33.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/__init__.py 2011-11-23 08:33:12.000000000 +0000 @@ -22,7 +22,7 @@ import pkg_resources -__version__ = '1.18.1' +__version__ = '1.18.1' # Keep in sync with ../info.py. required_bzrlib = (1, 17) pkg_resources.get_distribution('Paste>=1.6') diff -Nru loggerhead-1.18.1+bzr457/loggerhead/static/css/global.css loggerhead-1.19~bzr461/loggerhead/static/css/global.css --- loggerhead-1.18.1+bzr457/loggerhead/static/css/global.css 2011-04-22 17:22:49.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/static/css/global.css 2011-11-23 17:21:39.000000000 +0000 @@ -343,3 +343,68 @@ #footer { font-size: 77%; } + + +/* ==================== + Global notifications +*/ +/* Move the content down so the notification banner doesn't hide any content. */ +body.global-notification-visible { + padding-top: 40px; + } +body.global-notification-visible .login-logout { + top: 45px; + } +.notification-private { + background-image: url(/static/images/notification-private.png); /* sprite-ref: icon-sprites */ + background-repeat: no-repeat; + } +.global-notification { + position: fixed; + z-index: 10; + top: 0; + left: 0; + right: 0; + padding: 8px 20px; + /* Define colour for browsers that don't support transparency */ + background-color: #8d1f1f; + /* Set transparent background for browsers that support it */ + background-color: rgba(125,0,0,0.9); + color: #fff; + text-shadow: 0 -1px 0 #631616; + font-size: 14px; + line-height: 21px; + font-weight: bold; + -moz-box-shadow: 0 0 5px #333; + -webkit-box-shadow: 0 0 5px #333; + box-shadow: 0 0 5px #333; + } +.global-notification .sprite.notification-private { + float: left; + display: inline-block; + height: 21px; + width: 20px; + margin-right: 10px; + padding: 0; + } +.global-notification-close, .global-notification-close:active, +.global-notification-close:visited { + color: #e47a7a; + } +.global-notification-close { + display: block; + position: absolute; + top: 11px; + right: 20px; + font-size: 12px; + font-weight: normal; + line-height: 14px; + } +.global-notification-close .sprite.notification-close { + float: right; + display: block; + height: 9px; + width: 8px; + margin: 3px 0 0 7px; + padding: 0; + } Binary files /tmp/crYf1DFtuq/loggerhead-1.18.1+bzr457/loggerhead/static/images/notification-private.png and /tmp/bUDtGuHtgm/loggerhead-1.19~bzr461/loggerhead/static/images/notification-private.png differ diff -Nru loggerhead-1.18.1+bzr457/loggerhead/static/javascript/custom.js loggerhead-1.19~bzr461/loggerhead/static/javascript/custom.js --- loggerhead-1.18.1+bzr457/loggerhead/static/javascript/custom.js 2009-04-01 15:28:21.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/static/javascript/custom.js 2011-10-26 16:06:54.000000000 +0000 @@ -1,4 +1,4 @@ -Y = YUI().use("node", "io-base", "anim"); +Y = YUI().use("base", "node", "io-base", "anim"); var global_timeout_id = null; var global_search_request = null; @@ -280,3 +280,89 @@ } }; +var notification_node = null; +/* + * Display privacy notifications + * + * This should be called after the page has loaded e.g. on 'domready'. + */ +function setup_privacy_notification(config) { + if (notification_node !== null) { + return; + } + var notification_text = 'The information on this page is private'; + var hidden = true; + var target_id = "loggerheadCont"; + if (config !== undefined) { + if (config.notification_text !== undefined) { + notification_text = config.notification_text; + } + if (config.hidden !== undefined) { + hidden = config.hidden; + } + if (config.target_id !== undefined) { + target_id = config.target_id; + } + } + var id_selector = "#" + target_id; + var main = Y.get(id_selector); + notification_node = Y.Node.create('
') + .addClass('global-notification'); + if (hidden) { + notification_node.addClass('hidden'); + } + var notification_span = Y.Node.create('') + .addClass('sprite') + .addClass('notification-private'); + notification_node.set('innerHTML', notification_text); + main.appendChild(notification_node); + notification_node.appendChild(notification_span); +}; + +function display_privacy_notification() { + /* Set a temporary class on the body for the feature flag, + this is because we have no way to use feature flags in + css directly. This should be removed if the feature + is accepted. */ + var body = Y.get('body'); + body.addClass('feature-flag-bugs-private-notification-enabled'); + // Set the visible flag so that the content moves down. + body.addClass('global-notification-visible'); + + setup_privacy_notification(); + var global_notification = Y.get('.global-notification'); + if (global_notification.hasClass('hidden')) { + global_notification.addClass('transparent'); + global_notification.removeClass('hidden'); + + var fade_in = new Y.Anim({ + node: global_notification, + to: {opacity: 1}, + duration: 0.3 + }); + var body_space = new Y.Anim({ + node: 'body', + to: {'paddingTop': '40px'}, + duration: 0.2, + easing: Y.Easing.easeOut + }); + var black_link_space = new Y.Anim({ + node: '.black-link', + to: {'top': '45px'}, + duration: 0.2, + easing: Y.Easing.easeOut + }); + + fade_in.run(); + body_space.run(); + black_link_space.run(); + } +}; + +Y.on('domready', function() { + var body = Y.get('body'); + if (body.hasClass('private')) { + setup_privacy_notification(); + display_privacy_notification(); + } +}); diff -Nru loggerhead-1.18.1+bzr457/loggerhead/templates/branchinfo.pt loggerhead-1.19~bzr461/loggerhead/templates/branchinfo.pt --- loggerhead-1.18.1+bzr457/loggerhead/templates/branchinfo.pt 2009-01-23 20:53:40.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/templates/branchinfo.pt 2011-11-25 01:23:32.000000000 +0000 @@ -1,4 +1,5 @@ -
+
To get this branch, use:
bzr branch diff -Nru loggerhead-1.18.1+bzr457/loggerhead/templates/macros.pt loggerhead-1.19~bzr461/loggerhead/templates/macros.pt --- loggerhead-1.18.1+bzr457/loggerhead/templates/macros.pt 2011-03-03 10:58:57.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/templates/macros.pt 2011-11-04 18:16:32.000000000 +0000 @@ -43,7 +43,7 @@ - +
diff -Nru loggerhead-1.18.1+bzr457/loggerhead/templates/revision.pt loggerhead-1.19~bzr461/loggerhead/templates/revision.pt --- loggerhead-1.18.1+bzr457/loggerhead/templates/revision.pt 2011-06-28 16:51:55.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/templates/revision.pt 2011-11-23 08:33:55.000000000 +0000 @@ -73,7 +73,7 @@
  • + tal:content="string:compare with another revision">
  • compare with revision @@ -84,7 +84,10 @@ tal:attributes="href python:url(['/diff', change.revno], clear=1)">download diff download diff -
  • + +
  • + download tarball +
  • diff -Nru loggerhead-1.18.1+bzr457/loggerhead/tests/fixtures.py loggerhead-1.19~bzr461/loggerhead/tests/fixtures.py --- loggerhead-1.18.1+bzr457/loggerhead/tests/fixtures.py 1970-01-01 00:00:00.000000000 +0000 +++ loggerhead-1.19~bzr461/loggerhead/tests/fixtures.py 2011-11-25 02:28:56.000000000 +0000 @@ -0,0 +1,43 @@ +# Copyright (C) 2007, 2008, 2009, 2011 Canonical Ltd. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from __future__ import absolute_import + +from fixtures import Fixture + + +class SampleBranch(Fixture): + + def __init__(self, testcase): + # Must be a bzr TestCase to hook into branch creation, unfortunately. + self.testcase = testcase + + def setUp(self): + Fixture.setUp(self) + + self.tree = self.testcase.make_branch_and_tree('.') + + self.filecontents = ( + 'some\nmultiline\ndata\n' + 'with