from django.db import models from django.conf import settings try: GITBROWSE_BASE = settings.GITBROWSE_BASE except AttributeError: GITBROWSE_BASE='/home' if GITBROWSE_BASE[-1] != '/': GITBROWSE_BASE += '/' try: GITCOMMAND = settings.GITCOMMAND except AttributeError: GITCOMMAND='git' try: ADMIN_URL = settings.ADMIN_URL except AttributeError: ADMIN_URL='/admin' if ADMIN_URL[-1] == '/': ADMIN_URL=ADMIN_URL[:-1] # Create your models here. class Repository(models.Model): path = models.FilePathField("relative path to repository", \ path=GITBROWSE_BASE,recursive=True,match="^.*\.git$",unique=True, \ blank=False) name = models.CharField(_("name"), maxlength=80) slug = models.SlugField(prepopulate_from=("path",),unique=True) git_version = models.CharField(_("git version"), maxlength=100, \ default="git version 1.4.4", blank=True, \ help_text="Output of \'git --version\'") description = models.TextField("description of repo",blank=True) class Admin: ordering = ['slug'] def __str__(self): return self.name def get_absolute_url(self): return "/code/%s/" % self.slug def get_admin_url(self): return "%s/code/repository/%s/" % (ADMIN_URL, self.slug) def getGITPREFIX(self): """returns the glued together combination of GITCOMMAND and GITBROWSE_BASE needed to call git commands on this repository""" return 'cd ' + str(GITBROWSE_BASE) + str(self.slug) + '; ' \ + str(GITCOMMAND) + ' --git-dir=' + str(GITBROWSE_BASE) \ + str(self.slug) + '/.git ' def scan(self): import os GITPREFIX = self.getGITPREFIX() heads = dict() for h in os.listdir(GITBROWSE_BASE + self.slug + '/.git/refs/heads/'): f = open(GITBROWSE_BASE + self.slug + '/.git/refs/heads/' + h,'r') heads[h.strip()] = f.readline().strip() f.close() tags = dict() for t in os.listdir(GITBROWSE_BASE + self.slug + '/.git/refs/tags/'): f = open(GITBROWSE_BASE + self.slug + '/.git/refs/tags/' + t,'r') tags[t.strip()] = f.readline().strip() f.close() return (GITPREFIX, heads, tags) def shortlog(self): import commands GITPREFIX = 'cd ' + GITBROWSE_BASE + self.slug + '; ' + GITCOMMAND \ + ' --git-dir=' + GITBROWSE_BASE + self.slug + '/.git ' logtxt = commands.getoutput(GITPREFIX \ + ' log --relative-date --max-count=6 | cat') log_items = logtxt.split('\ncommit ') if (log_items[0] == ''): log_items.pop(0) if (log_items[0].startswith('commit ')): log_items[0] = log_items[0][7:] shortlog = list() for li in log_items: logobj = dict() lines = li.splitlines() if len(lines) < 3: continue logobj['hash'] = lines[0].strip() logobj['shorthash'] = lines[0].strip()[:5] logobj['author'] = lines[1][8:] logobj['date'] = lines[2][8:] if len(lines) > 4: logobj['description'] = lines[4][4:] else: logobj['description'] = '(none)' # here we truncate commit comments for shortlogs logobj['shortdescription'] = logobj['description'][:128] shortlog.append(logobj) return shortlog class Tree(models.Model): repo = models.ForeignKey(Repository) mode = models.CharField("file mode/permissions", blank=False,maxlength=4) path = models.CharField("relative path from repo base", maxlength=512) id = models.CharField("hash", maxlength=40,blank=False,primary_key=True) name = models.CharField("name of dir", maxlength=128,blank=False) type = 'tree' class Admin: ordering = ['repo','path'] def __str__(self): return self.name def get_absolute_url(self): return "/code/%s/tree/%s/" % (self.repo.slug, self.hash) def get_admin_url(self): return "%s/code/tree/%s/" % (ADMIN_URL, self.id) def tree_from_str(s): s = s.split(); if len(s) != 4: return return Tree(mode=s[0],id=s[2],name=s[3]) class Blob(models.Model): repo = models.ForeignKey(Repository) mode = models.CharField("file mode/permissions", blank=False,maxlength=4) path = models.CharField("relative path from repo base", maxlength=512) id = models.CharField("hash", maxlength=40,blank=False,primary_key=True) name = models.CharField("name of dir", maxlength=128,blank=False) size = models.IntegerField("filesize in byte", maxlength=128,blank=False) contents = models.TextField("ASCII contents of the file") type='blob' class Admin: ordering = ['repo','path','name'] def __str__(self): return self.name def get_absolute_url(self): return "/code/%s/blob/%s/" % (self.repo.slug, self.hash) def get_admin_url(self): return "%s/code/blob/%s/" % (ADMIN_URL, self.id) def update(self): import commands if (not self.id) or (not self.repo): return GITPREFIX = self.repo.getGITPREFIX() self.id = self.id.strip() self.contents = commands.getoutput(GITPREFIX + ' cat-file -p ' \ + self.id) self.size = commands.getoutput(GITPREFIX + ' cat-file -s ' + self.id) return def blob_from_str(s): s = s.split(); if len(s) != 4: return return Blob(mode=s[0],id=s[2],name=s[3]) class Commit(models.Model): repo = models.ForeignKey(Repository) id = models.CharField("hash", maxlength=40,blank=False,primary_key=True) rawdiff = models.TextField("ASCII contents of full commit diff") commit_date = models.DateField("Date of commit to repository") author_date = models.DateField("Date commit was writen/created") author = models.CharField("Name of commit author") author_email = models.DateField("Email address of commit author") committer = models.CharField("Name of committer") committer_email = models.DateField("Email address of committer") comment = models.TextField("Notes on the commit") parenthash = models.CharField("parent's hash", maxlength=40) #TODO: parent = models.ForeignKey() treehash = models.CharField("tree object's hash", maxlength=40) tree = models.ForeignKey(Tree) type='commit' class Admin: ordering = ['repo','commit_date','author_date','author'] def __str__(self): return self.id def get_absolute_url(self): return "/code/%s/commit/%s/" % (self.repo.slug, self.hash) def get_admin_url(self): return "%s/code/commit/%s/" % (ADMIN_URL, self.id) def update(self): import commands,time if (not self.id) or (not self.repo): return GITPREFIX = self.repo.getGITPREFIX() self.id = self.id.strip() raw = commands.getoutput(GITPREFIX + ' cat-file -p ' + self.id) self.rawdiff = commands.getoutput(GITPREFIX + ' diff ' + self.id \ +' | cat') raw = raw.splitlines() if len(raw) < 3: return self.treehash = raw[0].split()[-1].strip() self.parenthash = raw[1][6:].strip() self.author = raw[2].split()[1] self.author_date = time.ctime(int(raw[2].split()[-2])) self.committer = raw[3].split()[1] self.committer_date = time.ctime(int(raw[3].split()[-2])) if len(raw) > 4: for l in raw[4:]: self.comment += str(l) + '\n' else: self.comment = '(none)' return