- @classmethod
- def create(cls, text='', *args, **kwargs):
- instance = cls(*args, **kwargs)
- instance.save()
- head = instance.head
- head.patch = Change.make_patch('', text)
- head.save()
- return instance
-
- def __unicode__(self):
- return u"{0}, HEAD: {1}".format(self.id, self.head_id)
-
- @models.permalink
- def get_absolute_url(self):
- return ('dvcs.views.document_data', (), {
- 'document_id': self.id,
- 'version': self.head_id,
- })
-
- def materialize(self, change=None):
- if self.head is None:
- return u''
- if change is None:
- change = self.head
- elif not isinstance(change, Change):
- change = self.change_set.get(pk=change)
- return change.materialize()
-
- def commit(self, **kwargs):
- if 'parent' not in kwargs:
- parent = self.head
- else:
- parent = kwargs['parent']
- if not isinstance(parent, Change):
- parent = Change.objects.get(pk=kwargs['parent'])
-
- if 'patch' not in kwargs:
- if 'text' not in kwargs:
- raise ValueError("You must provide either patch or target document.")
- patch = Change.make_patch(self.materialize(change=parent), kwargs['text'])
- else:
- if 'text' in kwargs:
- raise ValueError("You can provide only text or patch - not both")
- patch = kwargs['patch']
-
- old_head = self.head
- if parent != old_head:
- change = parent.make_merge_child(patch, kwargs['author'], kwargs.get('description', ''))
- # not Fast-Forward - perform a merge
- self.head = old_head.merge_with(change, author=kwargs['author'])
+ revision = models.ForeignKey(
+ Revision, null=True, blank=True, default=None, verbose_name=_('revision'),
+ help_text=_("The document's revision."), editable=False)
+
+ def __str__(self):
+ return "ref:{0}->rev:{1}".format(self.id, self.revision_id)
+
+ def merge_text(self, base, local, remote):
+ """Override in subclass to have different kinds of merges."""
+ files = []
+ for f in local, base, remote:
+ temp = NamedTemporaryFile(delete=False)
+ temp.write(f)
+ temp.close()
+ files.append(temp.name)
+ p = Popen(['/usr/bin/diff3', '-mE', '-L', 'old', '-L', '', '-L', 'new'] + files, stdout=PIPE)
+ result, errs = p.communicate()
+
+ for f in files:
+ os.unlink(f)
+ return result.decode('utf-8')
+
+ def merge_with(self, revision, author=None, author_name=None, author_email=None, description="Automatic merge."):
+ """Merges a given revision into the ref."""
+ if self.revision is None:
+ fast_forward = True
+ self.revision = revision
+ elif self.revision.pk == revision.pk or self.revision.is_descendant_of(revision):
+ # Already merged.
+ return
+ elif revision.is_descendant_of(self.revision):
+ # Fast forward.
+ fast_forward = True
+ self.revision = revision