Login

A basic darcs provider for jellyroll

Author:
insin
Posted:
April 10, 2008
Language:
Python
Version:
.96
Score:
0 (after 0 ratings)

Basic in that it only handles the main inventory file.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
### Models

from django.db import models

from docutils.core import publish_parts
from jellyroll.models import Item

def restructuredtext(source):
    """
    Use reStructuredText to format the given source text.
    """
    parts = publish_parts(source=source, writer_name='html4css1')
    return parts['html_body']

class DarcsRepository(models.Model):
    """
    A darcs repository that you may commit patches to.
    """
    name = models.CharField(maxlength=100)
    slug = models.SlugField(prepopulate_from=('name',))
    username = models.CharField(maxlength=100, blank=True, help_text='Your username - if provided, it will be used to filter patches.')
    url = models.URLField(help_text='Don\'t include the <code>_darcs</code> folder.')
    description = models.TextField(blank=True, help_text='Use <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">reStructuredText</a>')
    description_html = models.TextField(editable=False, blank=True)

    class Meta:
        verbose_name_plural = 'darcs repositories'

    class Admin:
        list_display = ('name', 'url', 'username')

    def __unicode__(self):
        return self.name

    def save(self):
        if self.description:
            self.description = self.description.strip()
            self.description_html = restructuredtext(self.description).strip()
        super(DarcsRepository, self).save()

class DarcsPatch(models.Model):
    """
    A darcs patch.
    """
    repository = models.ForeignKey(DarcsRepository, related_name='patches')
    name = models.TextField()
    author = models.CharField(maxlength=150)
    timestamp = models.DateTimeField()
    comment = models.TextField(blank=True)
    inverted = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural ='darcs patches'
        ordering = ['-timestamp']

    class Admin:
        list_display = ('name', 'author', 'timestamp', 'repository')
        list_filter = ('repository',)
        search_fields = ('name', 'comment')

    def __unicode__(self):
        return self.name

# Register item objects to be "followed"
Item.objects.follow_model(DarcsPatch)

### Provider

import datetime
import logging
import re
import time
import urlparse

from django.db import transaction
from django.encoding import smart_unicode

from jellyroll.models import Item
from jellyroll.providers import utils
from somewhere.models import DarcsPatch, DarcsRepository

PATCH_DATE_FORMAT = '%Y%m%d%H%M%S'

patch_pattern = r"""
   \[                                   # Patch start indicator
   (?P<name>[^\n]+)\n                   # Patch name (rest of same line)
   (?P<author>[^\*]+)                   # Patch author
   \*                                   # Author/date separator
   (?P<inverted>[-\*])                  # Inverted patch indicator
   (?P<date>\d{14})                     # Patch date
   (?:\n(?P<comment>(?:^\ [^\n]*\n)+))? # Optional long comment
   \]                                   # Patch end indicator
   """
patch_re = re.compile(patch_pattern, re.VERBOSE | re.MULTILINE)
tidy_comment_re = re.compile(r'^ ', re.MULTILINE)

class Patch:
    """
    Patch details, as defined in a darcs inventory file.

    Attribute names match those generated by the
    ``darcs changes --xml-output`` command.
    """
    def __init__(self, name, author, date, inverted, comment=None):
        self.name = smart_unicode(name)
        self.author = smart_unicode(author)
        self.date = datetime(*time.strptime(date, PATCH_DATE_FORMAT)[:6])
        self.inverted = inverted
        self.comment = smart_unicode(comment)

    def __str__(self):
        return self.name

log = logging.getLogger('newsite.providers.darcs')

#
# Public API
#

def enabled():
    return True # No dependencies

def update():
    for repository in DarcsRepository.objects.all():
        _update_repository(repository)

#
# Private API
#

def _update_repository(repository):
    source_identifier = '%s:%s' % (__name__, repository.url)
    last_update_date = Item.objects.get_last_update_of_model(DarcsPatch, source=source_identifier)
    log.info(u'Updating changes from %s since %s', repository.url, last_update_date)
    inventory = utils.fetch_resource(urlparse.urljoin(repository.url, '_darcs/inventory'))
    for patch in reversed(list(_parse_inventory(inventory))):
        if patch.date < last_update_date:
            log.debug(u'Hit an old patch (commited %s; last update was %s); stopping.', patch.date, last_update_date)
            break
        if repository.username is None or repository.username in patch.author:
            _handle_patch(repository, patch)

def _parse_inventory(inventory):
    """
    Given the contents of a darcs inventory file, generates ``Patch``
    objects representing contained patch details.
    """
    for match in patch_re.finditer(inventory):
        attrs = match.groupdict(None)
        attrs['inverted'] = (attrs['inverted'] == '-')
        if attrs['comment'] is not None:
            attrs['comment'] = tidy_comment_re.sub('', attrs['comment']).strip()
        yield Patch(**attrs)

@transaction.commit_on_success
def _handle_patch(repository, patch):
    log.debug(u'Handling "%s" from %s' % (patch.name, repository.url))
    ci, created = DarcsPatch.objects.get_or_create(
        repository = repository,
        author     = patch.author,
        name       = patch.name,
        timestamp  = patch.date,
        inverted   = patch.inverted,
        defaults   = {'comment': patch.comment}
    )
    return Item.objects.create_or_update(
        instance  = ci,
        timestamp = patch.date,
        source    = u'%s:%s' % (__name__, repository.url),
    )

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

Please login first before commenting.