diff --git a/rcsfield/backends/base.py b/rcsfield/backends/base.py index 3d4864c..e916af4 100644 --- a/rcsfield/backends/base.py +++ b/rcsfield/backends/base.py @@ -54,8 +54,17 @@ def fetch(self, key, rev): raise NotImplementedError - + def get_revisions(self, key): + """ + return a list of all revisions in which ``key`` changed + + """ + raise NotImplementedError + + + + \ No newline at end of file diff --git a/rcsfield/backends/bzr.py b/rcsfield/backends/bzr.py index d67da22..d2ac311 100644 --- a/rcsfield/backends/bzr.py +++ b/rcsfield/backends/bzr.py @@ -83,6 +83,39 @@ def commit(self, key, data): except: raise wt.commit(message='auto commit from django') + + + def get_revisions(self, key): + """ + returns a list with all revisions at which ``key`` was changed. + Revision Numbers are integers starting at 1. + + """ + wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) + file_id = wt.path2id(key) + revisions = wt.branch.repository.all_revision_ids() # bzr ids + + wt.lock_read() + try: + changes = wt.branch.repository.fileids_altered_by_revision_ids(revisions) + except: + changes = {} + finally: + wt.unlock() + + if changes.has_key(file_id): + changed_in = changes[file_id] + else: + changed_in = () + + crevs = [] #`key` changed in these revisions + for rev_id in changed_in: + try: + crevs.append(wt.branch.revision_id_to_revno(rev_id)) + except: + pass + crevs.sort(reverse=True) + return crevs[1:] #cut of the HEAD revision-number @@ -92,7 +125,8 @@ def commit(self, key, data): fetch = rcs.fetch commit = rcs.commit initial = rcs.initial +get_revisions = rcs.get_revisions -__all__ = ('fetch', 'commit', 'initial') +__all__ = ('fetch', 'commit', 'initial', 'get_revisions') diff --git a/rcsfield/backends/dummy.py b/rcsfield/backends/dummy.py index f422afd..bbb6e92 100644 --- a/rcsfield/backends/dummy.py +++ b/rcsfield/backends/dummy.py @@ -21,6 +21,7 @@ def ignore(*args, **kwargs): fetch = complain commit = complain initial = complain +get_revisions = complain -__all__ = ('fetch', 'commit', 'initial') +__all__ = ('fetch', 'commit', 'initial', 'get_revisions') diff --git a/rcsfield/fields.py b/rcsfield/fields.py index 8b2c2c6..5018aaf 100644 --- a/rcsfield/fields.py +++ b/rcsfield/fields.py @@ -38,11 +38,28 @@ class RcsTextField(models.TextField): ''' #we need this, to know if we can fetch old revisions. - IS_VERSIONED = True + #IS_VERSIONED = True + + def __init__(self, *args, **kwargs): + """ + Allow specifying a different format for the key used to identify + versionized content in the model-definition. + + """ + if kwargs.get('rcskey_format', False): + self.rcskey_format = kwargs['rcskey_format'] + del kwargs['rcskey_format'] + #TODO: check if the string has the correct format + else: + self.rcskey_format = "%s/%s/%s/%s.txt" + self.IS_VERSIONED = True # so we can figure out that this field is versionized quickly + TextField.__init__(self, *args, **kwargs) + def get_internal_type(self): return "TextField" + def post_save(self, instance=None): """ create a file and add to the repository, if not already existing @@ -50,61 +67,63 @@ def post_save(self, instance=None): """ data = getattr(instance, self.attname) - key = "%s/%s/%s/%s.txt" % (instance._meta.app_label,instance.__class__.__name__,self.attname,instance.id) + key = self.rcskey_format % (instance._meta.app_label,instance.__class__.__name__,self.attname,instance.id) try: backend.commit(key, data) except: raise - def get_revisions(self, instance, raw=False): - wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) - revisions = wt.branch.repository.all_revision_ids() - revs = [] - for rev in revisions: - revs.append(wt.branch.revision_id_to_revno(rev)) - if raw: - return revisions - return revs + #def get_revisions(self, instance, raw=False): + # wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) + # revisions = wt.branch.repository.all_revision_ids() + # revs = [] + # for rev in revisions: + # revs.append(wt.branch.revision_id_to_revno(rev)) + # if raw: + # return revisions + #return revs - def get_changes(self, instance, field): - wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) - wt.lock_read() - changes = wt.branch.repository.fileids_altered_by_revision_ids(self.get_revisions(instance, True)) - wt.unlock() - myself = self.get_my_fileid(instance, field) - for fileid in changes: - if fileid == myself: - return changes[fileid] - return changes + #def get_changes(self, instance, field): + # wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) + # wt.lock_read() + # changes = wt.branch.repository.fileids_altered_by_revision_ids(self.get_revisions(instance, True)) + #wt.unlock() + #myself = self.get_my_fileid(instance, field) + #for fileid in changes: + # if fileid == myself: + # return changes[fileid] + #return changes def get_changed_revisions(self, instance, field): - wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) - changed_in = self.get_changes(instance, field) - crevs = [] - for rev_id in changed_in: - try: - crevs.append(wt.branch.revision_id_to_revno(rev_id)) - except: - pass - crevs.sort(reverse=True) - return crevs[1:15] #FIXME:better handle this limit on app-level, not here + return backend.get_revisions(self.rcskey_format % (instance._meta.app_label, instance.__class__.__name__,field.attname, instance.id)) + #wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) + #changed_in = self.get_changes(instance, field) + #crevs = [] + #for rev_id in changed_in: + # try: + # crevs.append(wt.branch.revision_id_to_revno(rev_id)) + # except: + # pass + #crevs.sort(reverse=True) + #return crevs[1:15] #FIXME:better handle this limit on app-level, not here - def get_my_fileid(self, instance, field): - wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) - path = '%s/%s_%s-%s.txt' % (instance._meta.app_label, instance.__class__.__name__,field.attname, instance.id) - return wt.path2id(path) + #def get_my_fileid(self, instance, field): + # wt = workingtree.WorkingTree.open(settings.BZR_WC_PATH) + # path = '%s/%s/%s/%s.txt' % (instance._meta.app_label, instance.__class__.__name__,field.attname, instance.id) + # return wt.path2id(path) def get_FIELD_revisions(self, instance, field): - return self.get_revisions(instance) + return backend.get_revisions(self.rcskey_format % (instance._meta.app_label, instance.__class__.__name__,field.attname, instance.id)) + #return self.get_changed_revisions(instance, field) def contribute_to_class(self, cls, name): super(RcsTextField, self).contribute_to_class(cls, name) - setattr(cls, 'get_my_fileid', curry(self.get_my_fileid, field=self)) - setattr(cls, 'get_revisions', curry(self.get_revisions)) + #setattr(cls, 'get_my_fileid', curry(self.get_my_fileid, field=self)) + #setattr(cls, 'get_revisions', curry(self.get_revisions)) setattr(cls, 'get_%s_revisions' % self.name, curry(self.get_FIELD_revisions, field=self)) - setattr(cls, 'get_changes', curry(self.get_changes, field=self)) + #setattr(cls, 'get_changes', curry(self.get_changes, field=self)) setattr(cls, 'get_changed_revisions', curry(self.get_changed_revisions, field=self)) #cls.add_to_class('objects', RevisionManager()) dispatcher.connect(self.post_save, signal=signals.post_save, sender=cls) diff --git a/rcsfield/manager.py b/rcsfield/manager.py index 50a08e2..cd01ddd 100644 --- a/rcsfield/manager.py +++ b/rcsfield/manager.py @@ -4,10 +4,8 @@ from django.db.models.query import QuerySet try: - #django pre-qsrf from django.db.models.query import GET_ITERATOR_CHUNK_SIZE except ImportError: - #django post-qsrf from django.db.models.query import CHUNK_SIZE as GET_ITERATOR_CHUNK_SIZE from rcsfield.backends import backend diff --git a/rcsfield/templatetags/historytrail.py b/rcsfield/templatetags/historytrail.py index dad78c7..83bf17f 100644 --- a/rcsfield/templatetags/historytrail.py +++ b/rcsfield/templatetags/historytrail.py @@ -1,7 +1,6 @@ from django import template from django.db import models from django.db.models import get_model -from django.template import TemplateSyntaxError, resolve_variable register = template.Library() @@ -14,8 +13,8 @@ class HistoryTrailNode(template.Node): Usage: {% historytrail object %} - or to only show the last 2 revisions: - {% historytrail object 2 %} + or to only show links to the last 5 revisions: + {% historytrail object 5 %} """ def __init__(self, model, count=0): @@ -23,7 +22,7 @@ def __init__(self, model, count=0): self.count = int(count) def render(self, context): - self.instance = resolve_variable(self.model, context) + self.instance = template.resolve_variable(self.model, context) revs = self.instance.get_changed_revisions() out = "" if self.count > 0: @@ -38,9 +37,9 @@ def render(self, context): def historytrail(parser, token): bits = token.contents.split() if len(bits) < 2: - raise TemplateSyntaxError, "historytrail tag takes at least one argument" + raise template.TemplateSyntaxError, "historytrail tag takes at least one argument" if len(bits) > 3: - raise TemplateSyntaxError, "historytrail tag takes at most two arguments" + raise template.TemplateSyntaxError, "historytrail tag takes at most two arguments" if len(bits) == 2: return HistoryTrailNode(bits[1]) if len(bits) == 3: