visualculture
clone your own copy | download snapshot

Snapshots | iceberg

Inside this repository

views.py
text/x-python

Download raw (9.9 KB)

# -*- coding: utf-8 -*-
"""
git_info.views

Views that render the GitCollection accessible over HTTP a JSON API.

All the `render` functions should basically get out of here and become part
of the GitCollection class from git.py, in the form of `to_hash` methods.
That would clean up a bunch and save us the necessity to pass `repo_name`
around all the time.

"""


from datetime import datetime
import json

from pygit2 import GIT_SORT_TOPOLOGICAL

from django.http import HttpRequest, HttpResponse, HttpResponseRedirect, HttpResponseBadRequest, Http404, HttpResponseForbidden, HttpResponseNotAllowed
from django.core.urlresolvers import reverse
from django.views.decorators.cache import cache_page

from git_info.git import *
from utils import find_mime

from osp.models import get_api, get_url_contents
from osp.views import format_commits

import settings


if settings.PREFIX:
    git_collection = GitCollection(settings.PREFIX)
else:
    git_collection = GitCollection()

def render_commit(repo_name, commit):
    hash = {'type':'commit', 'repo_name': repo_name, 'hex' : commit.hex , 'author':commit.author.name, 'message':commit.message, 'files':commit.tree.hex, 'commit_time': commit.commit_time}
    if commit.parents:
        hash['parent'] = commit.parents[0].hex
    return hash


def find_last_commit(repo, name):
    last_commit = None
    last_oid = None
    i = 0

    try:
        for commit in repo.repo.walk(repo.repo.head.target, pygit2.GIT_SORT_TIME):
            if 'iceberg' in commit.tree:
                iceoid = commit.tree['iceberg'].hex
                icetree = repo[iceoid]

                if name in icetree:
                    i += 1
                    oid = icetree[name].oid

                    has_changed = (oid != last_oid and last_oid)

                    if has_changed:
                        break

                    last_oid = oid

                elif i > 1:
                    break

                last_commit = commit
    except:
        return last_commit or 'Corrupted repository'

    return last_commit or 'No commit'


def render_tree(repo_name, tree):
    repo = git_collection[repo_name]
    items = []
    dirs = []

    for item in tree:
        if repo[item.hex].type == pygit2.GIT_OBJ_TREE:
            dirs.append({'hex': item.hex, 'name': item.name, 'mime': find_mime(path=item.name)})
        else:
            res = find_last_commit(repo, item.name)
            if res != "No commit" and res != "Corrupted repository":
                dt = datetime.fromtimestamp(res.commit_time)
            else:
                dt = None
            items.append({'hex': item.hex, 'name': item.name, 'mime': find_mime(path=item.name), 'datetime': str(dt) })
    hash = {'type':'tree', 'repo_name':repo_name, 'dirs':dirs, 'files':items}
    return hash


def render_blob(repo_name, blob, path=None):
    """
    Ok so render is not the right name for this.
    Will re-rename them all to get.

    """

    mime = find_mime(blob, path)
    # Returns cache status as to let the caller decide if it goes for VC or cached files
    hash = {'type':'blob', 'repo_name':repo_name, 'hex' : blob.hex, 'mime': mime, 'size' : blob.size, 'is_binary': blob.is_binary }
    # embed the data directly if it is less then 100kb
    if not hash['is_binary'] and hash['size'] < 104857600:
        hash['data'] = blob.data
    return hash

def index(request):
    return HttpResponse(json.dumps({'repos': git_collection.get_names()}, indent=2), mimetype="application/json")

def render_repo(repo_slug, n_commits=5, tree=False, iceberg=False):
    repo = GitCollection(settings.PREFIX)[repo_slug]
    print(dir(repo))
    hash = {}
    hash['category'] = repo.repo_category
    hash['name'] = repo.repo_name
    hash['slug'] = repo_slug
    hash['commits'] = []
    i = 0
    try:
        for commit in repo.walk(repo.head.target, GIT_SORT_TOPOLOGICAL):
            hash['commits'].append(render_commit(repo_slug, commit))
            i += 1
            if i == n_commits:
                break
    except Exception as exn:
        pass
    if tree:
        head = repo.revparse_single('HEAD')
        hash['tree'] = render_tree(repo_slug, head.tree)
    if iceberg:
        if 'iceberg' in repo.head.get_object().tree:
            icetree = repo[ repo.head.get_object().tree['iceberg'].hex ]
            hash['iceberg'] = render_tree(repo_slug, icetree)
    #import ipdb; ipdb.set_trace()
    if 'fonts' in repo.head.get_object().tree:
        import random
        sentences = [
                "Never alone.",
                "Free software only since 2006.",
                "OSP asbl aims to stimulate the social movements of Free Culture and Free Software in the field of graphic design.",
                "Free Culture and Free Software challenge the excesses of copyright.",
                "Practices shape tools—tools shape practices.",
                "Print parties, workshops, performances, exhibitions and lectures",
                "The association is constituted for an undetermined period. It can be dissolved at any time.",
                "Échange et ré-approppriation participent de l’acte créatif",
                "le concept de culture libre s’étend (…) au dessin, à l’écriture, au design d’objets etc.",
                "Les pratiques façonnent les outils - les outils façonnent les pratiques",
                "Le logiciel libre, par sa nature ouverte, invite à comprendre les mécanismes des outils numériques",
                "Le nombre de membres effectif ne peut être inférieur à trois.",
                "Les membres effectifs et les membres source sont convoqués à l’assemblée générale ordinaire, qui aura lieu au moins une fois par an",
                "We are writing you because we just published Sans Guilt.",
                "Today she started with C.",
                "Did she feel the author of her alphabet?"
                ]
        woffs = []
        try: 
            fontes = get_api(repo_slug, 'path', 'fonts/webfonts')["files"]
            for fonte in fontes:
                woff = {}
                if fonte["mime"] == "font/woff":
                    woff["name"] = fonte["name"].split('.woff')[0]
                    woff["url"] = get_api(repo_slug, 'path', "fonts/webfonts/" + fonte["name"])['raw_url']
                    woff["sentence"] = random.choice(sentences)
                    woffs.append(woff)
            hash['woffs'] = woffs
        except:
            pass

    return hash

def repo(request, repo_name):
    print('Requested repo: %s'%repo_name)
    hash = render_repo(repo_name, n_commits=-1, tree=True, iceberg=True)
    return HttpResponse(json.dumps(hash, indent=2), mimetype="application/json")

def repos(repo_names):
    hash = []
    for repo_name in repo_names:
        hash.append(render_repo(repo_name, iceberg=True))
    return hash

@cache_page(60 * 60)
def home(request, n=8, category=None):
    if category:
        slugs = [slug for slug in GitCollection(settings.PREFIX).get_names() if len(slug.split('.')) > 1 and slug.split('.')[1] == category]
    else:
        slugs = GitCollection(settings.PREFIX).get_names()[:n]
    hash = repos(slugs)
    return HttpResponse(json.dumps(hash, indent=2), mimetype="application/json")

def item(request, repo_name, oid):
    print('Requested item: %s %s' % (repo_name, oid))
    repo = git_collection[repo_name]
    obj = None
    if(oid == 'head'):
        obj = repo.head
    else:
        try:
            obj = repo[oid]
        except KeyError:
            raise Http404

    if obj.type == pygit2.GIT_OBJ_COMMIT:
        hash = render_commit(repo_name, obj)

    elif obj.type == pygit2.GIT_OBJ_TREE:
        hash = render_tree(repo_name, obj)

    elif obj.type == pygit2.GIT_OBJ_BLOB:
        hash = render_blob(repo_name, obj)

    else:
        return HttpResponseBadRequest('Unhandled object type %s'%obj.type)

    return HttpResponse(json.dumps(hash, indent=2), mimetype="application/json")


def item_from_path(request, repo_name, path):
    """
    Git doesn’t have a specific way to search for a tree or blob by path,
    you just recurse down the tree
    """
    repo = git_collection[repo_name]

    paths = path.split('/')

    #print "looking for %s from %s in %s" % (paths, path, repo_name)
    obj = repo.head.get_object().tree
    for p in paths:
        if p == '':
            break
        try:
            obj = repo[ obj[p].hex ]
        except KeyError:
            raise Http404

    if paths[-1] == '':
        if len(paths) == 1:
            # root path named after repo
            name = repo_name
        else:
            # tree named after tree
            name = paths[-2]
    else:
        # blob named after blob
        name = paths[-1]

    if obj.type == pygit2.GIT_OBJ_TREE:
        hash = render_tree(repo_name, obj)

    elif obj.type == pygit2.GIT_OBJ_BLOB:
        hash = render_blob(repo_name, obj, path)
        hash['raw_url'] = reverse('git_info.views.blob_data', args=[repo_name, hash['hex']]) + name
        # Note: to pass the absolute url:
        hash['raw_url'] = request.build_absolute_uri(hash['raw_url'])

    hash['name'] = name
    hash['paths'] = paths

    return HttpResponse(json.dumps(hash, indent=2), mimetype="application/json")

def blob_data(request, repo_name, oid):
    obj = git_collection[repo_name][oid]

    if obj.type == pygit2.GIT_OBJ_BLOB:
        mime = find_mime(obj)
        return HttpResponse(obj.data, mimetype=mime)

    return HttpResponseBadRequest('Requested object is not a BLOB')

def blob_data_from_path(request, repo_name, path):
    repo = git_collection[repo_name]
    paths = path.split('/')

    obj = repo.head.get_object().tree
    for p in paths:
        if p == '':
            break
        try:
            obj = repo[ obj[p].hex ]
        except KeyError:
            raise Http404

    if obj.type == pygit2.GIT_OBJ_BLOB:
        mime = find_mime(obj, path)
        return HttpResponse(obj.data, mimetype=mime)

    return HttpResponseBadRequest('Requested object is not a BLOB')