Source

Pypaste / friendpaste / snippets / code.py

The default branch has multiple heads

# -*- coding: utf-8 -*-
"""
    :copyright: 2007 by Benoît Chesneau & KAeL <kael@crocobox.org> for parser. 
    :license: BSD, see license for more details
"""
import friendpaste

from pygments.lexers import get_all_lexers
from pygments import highlight, lexers, formatters
import re
import StringIO
from datetime import datetime
from time import mktime
import os
import web

_snippet_tpl = """@title %(title)s
@language %(language)s
@parent %(parent)s

@content 
%(snippet)s"""

METADATA_RE = re.compile('^@(?P<metadata>[a-z0-9\-_]+)\s+(?P<metacontent>.*)$', re.IGNORECASE)
METADATA_COMMENT_RE = re.compile('^\s*--')
CONTENT_START_RE = re.compile('^\s*@content\s*$')

MANDATORY_TAGS = ['title', 'language']


class MetadataException(Exception):
	pass

class Snippet(object):
    def __init__(self):
        self.id = None
        self.title = None
        self.language = None
        self.code = None
        self.raw_content = None

    def _parse(self):
        """ load snippet text """
        tags_seen = set()
        end_reached = False
        last_metadata = None
        io_obj = StringIO.StringIO(self.raw_content) 
        while not end_reached:
            line = io_obj.readline()
            if line.strip() == '': continue
            if CONTENT_START_RE.match(line):
                for t in MANDATORY_TAGS:
                    if t not in tags_seen:
                        raise MetadataException("Missing tag '%s' in snippet metadata" % (t))
                self.code = io_obj.read()
                self._highlight()
                end_reached = True
            elif METADATA_COMMENT_RE.match(line):
                pass # comment
            else:
                last_metadata = self._parse_metadata_line(line, last_metadata)
                tags_seen.add(last_metadata)
        


    def _parse_metadata_line(self, line, last_metadata):
        # parse a metadata line
        match = METADATA_RE.match(line)
        if match:
            if match.group('metadata'):
                metadata = match.group('metadata').lower()
            else:
                # metadata continuation
                metadata = last_metadata

            metacontent = match.group('metacontent').strip()
            try:
                setattr(self, metadata, metacontent)
            except AttributeError:
                raise MetadataException("Metadata '%s' not handled" % metadata)
            return metadata
        else:
            try:
                c = getattr(self, last_metaname)
            except:
                raise MetadataException("Syntax Error near '%s'" % line.rstrip())
            c += line.strip()
            setattr(self, last_metaname, c)

    def _highlight(self):
        lexer = lexers.get_lexer_by_name(self.language)
        highlighted = highlight(self.code, lexer,
                formatters.HtmlFormatter(linenos=True, 
                    cssclass="source", lineseparator="<br />"))
        setattr(self, 'highlighted', highlighted)

    def _genid(self):
        charset = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
        from random import choice
        return ''.join([choice(charset) for i in range(8)])
        
    def save(self, raw):
        self.raw_content = raw
        self._parse()
        found = False
        id = ""
        while not found:
            id = self._genid()
            dirs = '/'.join(c for c in id[0:4])
            path = "%s/%s" % (friendpaste.config.DATA_PATH,dirs)
            fn = "%s/%s" % (path, id[4:])
            if not os.path.exists(path):
                os.makedirs(path)
                os.chmod(path, 0771)
                self.id = id
                self.filename = fn
                found = True
            elif not os.path.exists(fn):
                self.id = id
                self.filename = fn
                found = True

        f = open(self.filename, 'w')
        f.write(self.raw_content)
        f.close()
        setattr(self, 'created', os.stat(self.filename).st_mtime)

    def get (self, id):
        if len(id) <= 4:
            raise ValueError, "id invalid"

        dirs = '/'.join(c for c in id[0:4])
        fn = "%s/%s/%s" % (friendpaste.config.DATA_PATH,dirs, id[4:])
        if not os.path.exists(fn):
            raise LookupError, "paste don't exist"
       
        self.id = id
        self.filename = fn
        f = open(self.filename, 'r')
        self.raw_content = f.read()
        f.close()
        self._parse()
        setattr(self, 'created', os.stat(self.filename).st_mtime)

    def __unicode__(self):
        return u"%s" % self.content

def save_snippet(args):
    now = datetime.now()
    snippet = _snippet_tpl % { 
            'title': args['title'].value,
            'language': args['language'].value,
            'snippet': args['snippet'].value,
            'parent': args['parent'].value and args['parent'].value or
            '',
    }

    s = Snippet()
    s.save(snippet)

    idx=web.ctx.index
    idx.put(s)
    return s


def get_snippet(id):
    s = Snippet()
    try:
        s.get(id)
    except:
        raise LookupError, "paste don't exist"
    return s