| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 | 
							- #!/usr/bin/env python
 
- # Copyright (C) 2013 Oz Nahum <nahumoz@gmail.com>
 
- #
 
- # Everyone is permitted to copy and distribute verbatim or modified
 
- # copies of this license document, and changing it is allowed as long
 
- # as the name is changed.
 
- #
 
- # TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 
- #
 
- # 0. You just DO WHATEVER THE FUCK YOU WANT TO. (IT'S SLOPPY CODE ANYWAY)
 
- #
 
- # WARANTIES:
 
- # 0. Are you kidding me?
 
- # 1. Seriously, Are you fucking kidding me?
 
- # 2. If anything goes wrong, sue the "The Empire".
 
- # Note about Summary
 
- # has to be 1 line, no '\n' allowed!
 
- """
 
- Summary: |
 
-    some summary ...
 
- Your post
 
- """
 
- """
 
- Everything the Header can't have ":" or "..." in it, you can't have title
 
- with ":" it makes markdown break!
 
- """
 
- """
 
- The content directory can contain only mardown or txt files, no images
 
- allowed!
 
- """
 
- import os
 
- import re
 
- import datetime
 
- import yaml  # in debian python-yaml
 
- from StringIO import StringIO
 
- import codecs
 
- from jinja2 import Environment, FileSystemLoader  # in debian python-jinja2
 
- try:
 
-     import markdown2
 
- except ImportError:
 
-     import markdown as markdown2
 
- import argparse
 
- import sys
 
- from distutils import dir_util
 
- import shutil
 
- CONFIG = {
 
-     'content_root': 'content',  # where the markdown files are
 
-     'output_to': 'oz123.github.com',
 
-     'templates': 'templates',
 
-     'date_format': '%Y-%m-%d',
 
-     'base_url': 'http://oz123.github.com',
 
-     'http_port': 3030,
 
-     'content_encoding': 'utf-8',
 
-     'author': 'Oz Nahum Tiram'
 
- }
 
- # EDIT THIS PARAMETER TO CHANGE ARCHIVE SIZE
 
- # 0 Means that all the entries will be in the archive
 
- # 10 meas that all the entries except the last 10
 
- ARCHIVE_SIZE = 0
 
- GLOBAL_TEMPLATE_CONTEXT = {
 
-     'media_base': '/media/',
 
-     'media_url': '../media/',
 
-     'site_url': 'http://oz123.github.com',
 
-     'last_build': datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ"),
 
-     'twitter': 'https://twitter.com/#!/OzNTiram',
 
-     'stackoverflow': "http://stackoverflow.com/users/492620/oz123",
 
-     'github': "https://github.com/oz123",
 
- }
 
- KINDS = {
 
-     'writing': {
 
-         'name': 'writing', 'name_plural': 'writings',
 
-     },
 
-     'note': {
 
-         'name': 'note', 'name_plural': 'notes',
 
-     },
 
-     'link': {
 
-         'name': 'link', 'name_plural': 'links',
 
-     },
 
-     'photo': {
 
-         'name': 'photo', 'name_plural': 'photos',
 
-     },
 
-     'page': {
 
-         'name': 'page', 'name_plural': 'pages',
 
-     },
 
- }
 
- jinja_env = Environment(loader=FileSystemLoader(CONFIG['templates']))
 
- class Tag(object):
 
-     def __init__(self, name):
 
-         super(Tag, self).__init__()
 
-         self.name = name
 
-         self.prepare()
 
-         self.permalink = GLOBAL_TEMPLATE_CONTEXT["site_url"]
 
-     def prepare(self):
 
-         _slug = self.name.lower()
 
-         _slug = re.sub(r'[;;,. ]', '-', _slug)
 
-         self.slug = _slug
 
- class Entry(object):
 
-     def __init__(self, path):
 
-         super(Entry, self).__init__()
 
-         path = path.split('content/')[-1]
 
-         self.path = path
 
-         self.prepare()
 
-     def __str__(self):
 
-         return self.path
 
-     def __repr__(self):
 
-         return self.path
 
-     @property
 
-     def name(self):
 
-         return os.path.splitext(os.path.basename(self.path))[0]
 
-     @property
 
-     def abspath(self):
 
-         return os.path.abspath(os.path.join(CONFIG['content_root'], self.path))
 
-     @property
 
-     def destination(self):
 
-         dest = "%s/%s/index.html" % (KINDS[
 
-                                      self.kind]['name_plural'], self.name)
 
-         print dest
 
-         return os.path.join(CONFIG['output_to'], dest)
 
-     @property
 
-     def title(self):
 
-         return self.header['title']
 
-     @property
 
-     def summary_html(self):
 
-         return "%s" % markdown2.markdown(self.header['summary'].strip())
 
-     @property
 
-     def credits_html(self):
 
-         return "%s" % markdown2.markdown(self.header['credits'].strip())
 
-     @property
 
-     def summary_atom(self):
 
-         summarya = markdown2.markdown(self.header['summary'].strip())
 
-         summarya = re.sub("<p>|</p>", "", summarya)
 
-         more = '<a href="%s"> continue reading...</a>' % (self.permalink)
 
-         return summarya+more
 
-     @property
 
-     def published_html(self):
 
-         if self.kind in ['link', 'note', 'photo']:
 
-             return self.header['published'].strftime("%B %d, %Y %I:%M %p")
 
-         return self.header['published'].strftime("%B %d, %Y")
 
-     @property
 
-     def published_atom(self):
 
-         return self.published.strftime("%Y-%m-%dT%H:%M:%SZ")
 
-     @property
 
-     def atom_id(self):
 
-         return "tag:%s,%s:%s" % \
 
-             (
 
-                 self.published.strftime("%Y-%m-%d"),
 
-                 self.permalink,
 
-                 GLOBAL_TEMPLATE_CONTEXT["site_url"]
 
-             )
 
-     @property
 
-     def body_html(self):
 
-         return markdown2.markdown(self.body)  # , extras=['code-color'])
 
-     @property
 
-     def permalink(self):
 
-         return "/%s/%s" % (KINDS[self.kind]['name_plural'], self.name)
 
-     @property
 
-     def tags(self):
 
-         tags = list()
 
-         for t in self.header['tags']:
 
-             tags.append(Tag(t))
 
-         return tags
 
-     def prepare(self):
 
-         file = codecs.open(self.abspath, 'r')
 
-         header = ['---']
 
-         while True:
 
-             line = file.readline()
 
-             line = line.rstrip()
 
-             if not line:
 
-                 break
 
-             header.append(line)
 
-         self.header = yaml.load(StringIO('\n'.join(header)))
 
-         for h in self.header.items():
 
-             if h:
 
-                 try:
 
-                     setattr(self, h[0], h[1])
 
-                 except:
 
-                     pass
 
-         body = list()
 
-         for line in file.readlines():
 
-             body.append(line)
 
-         self.body = ''.join(body)
 
-         file.close()
 
-         if self.kind == 'link':
 
-             from urlparse import urlparse
 
-             self.domain_name = urlparse(self.url).netloc
 
-         elif self.kind == 'photo':
 
-             pass
 
-         elif self.kind == 'note':
 
-             pass
 
-         elif self.kind == 'writing':
 
-             pass
 
-     def render(self):
 
-         if not self.header['public']:
 
-             return False
 
-         try:
 
-             os.makedirs(os.path.dirname(self.destination))
 
-         except:
 
-             pass
 
-         context = GLOBAL_TEMPLATE_CONTEXT.copy()
 
-         context['entry'] = self
 
-         template = jinja_env.get_template("entry.html")
 
-         html = template.render(context)
 
-         destination = codecs.open(
 
-             self.destination, 'w', CONFIG['content_encoding'])
 
-         destination.write(html)
 
-         destination.close()
 
-         return True
 
- class Link(Entry):
 
-     def __init__(self, path):
 
-         super(Link, self).__init__(path)
 
-     @property
 
-     def permalink(self):
 
-         print "self.url", self.url
 
-         raw_input()
 
-         return self.url
 
- def entry_factory():
 
-     pass
 
- def _sort_entries(entries):
 
-     _entries = dict()
 
-     sorted_entries = list()
 
-     for entry in entries:
 
-         _published = entry.header['published'].isoformat()
 
-         _entries[_published] = entry
 
-     sorted_keys = sorted(_entries.keys())
 
-     sorted_keys.reverse()
 
-     for key in sorted_keys:
 
-         sorted_entries.append(_entries[key])
 
-     return sorted_entries
 
- def render_index(entries):
 
-     """
 
-     this function renders the main page located at index.html
 
-     under oz123.github.com
 
-     """
 
-     context = GLOBAL_TEMPLATE_CONTEXT.copy()
 
-     context['entries'] = entries[:10]
 
-     template = jinja_env.get_template('entry_index.html')
 
-     html = template.render(context)
 
-     destination = codecs.open("%s/index.html" % CONFIG[
 
-                               'output_to'], 'w', CONFIG['content_encoding'])
 
-     destination.write(html)
 
-     destination.close()
 
- def render_archive(entries, render_to=None):
 
-     """
 
-     this function creates the archive page
 
-     """
 
-     context = GLOBAL_TEMPLATE_CONTEXT.copy()
 
-     context['entries'] = entries[ARCHIVE_SIZE:]
 
-     template = jinja_env.get_template('archive_index.html')
 
-     html = template.render(context)
 
-     if not render_to:
 
-         render_to = "%s/archive/index.html" % CONFIG['output_to']
 
-         dir_util.mkpath("%s/archive" % CONFIG['output_to'])
 
-     destination = codecs.open("%s/archive/index.html" % CONFIG[
 
-                               'output_to'], 'w', CONFIG['content_encoding'])
 
-     destination.write(html)
 
-     destination.close()
 
- def render_atom_feed(entries, render_to=None):
 
-     context = GLOBAL_TEMPLATE_CONTEXT.copy()
 
-     context['entries'] = entries[:10]
 
-     template = jinja_env.get_template('atom.xml')
 
-     html = template.render(context)
 
-     if not render_to:
 
-         render_to = "%s/atom.xml" % CONFIG['output_to']
 
-     destination = codecs.open(render_to, 'w', CONFIG['content_encoding'])
 
-     destination.write(html)
 
-     destination.close()
 
- def render_tag_pages(tag_tree):
 
-     context = GLOBAL_TEMPLATE_CONTEXT.copy()
 
-     for t in tag_tree.items():
 
-         context['tag'] = t[1]['tag']
 
-         context['entries'] = _sort_entries(t[1]['entries'])
 
-         destination = "%s/tags/%s" % (CONFIG['output_to'], context['tag'].slug)
 
-         try:
 
-             os.makedirs(destination)
 
-         except:
 
-             pass
 
-         template = jinja_env.get_template('tag_index.html')
 
-         html = template.render(context)
 
-         file = codecs.open("%s/index.html" %
 
-                            destination, 'w', CONFIG['content_encoding'])
 
-         file.write(html)
 
-         file.close()
 
-         render_atom_feed(context[
 
-                          'entries'], render_to="%s/atom.xml" % destination)
 
- def build():
 
-     print
 
-     print "Rendering website now..."
 
-     print
 
-     print " entries:"
 
-     entries = list()
 
-     tags = dict()
 
-     for root, dirs, files in os.walk(CONFIG['content_root']):
 
-         for fileName in files:
 
-             try:
 
-                 if fileName.endswith('md') or fileName.endswith('markdown'):
 
-                     entry = Entry(os.path.join(root, fileName))
 
-             except Exception, e:
 
-                 print "Found some problem in: ", fileName
 
-                 print e
 
-                 raw_input("Please correct")
 
-                 sys.exit()
 
-             if entry.render():
 
-                 entries.append(entry)
 
-                 for tag in entry.tags:
 
-                     if tag.name not in tags:
 
-                         tags[tag.name] = {
 
-                             'tag': tag,
 
-                             'entries': list(),
 
-                         }
 
-                     tags[tag.name]['entries'].append(entry)
 
-             print "     %s" % entry.path
 
-     print " :done"
 
-     print
 
-     print " tag pages & their atom feeds:"
 
-     render_tag_pages(tags)
 
-     print " :done"
 
-     print
 
-     print " site wide index"
 
-     entries = _sort_entries(entries)
 
-     render_index(entries)
 
-     print "................done"
 
-     print " archive index"
 
-     render_archive(entries)
 
-     print "................done"
 
-     print " site wide atom feeds"
 
-     render_atom_feed(entries)
 
-     print "...........done"
 
-     print
 
-     print "All done "
 
- def preview(PREVIEW_ADDR='127.0.1.1', PREVIEW_PORT=11000):
 
-     """
 
-     launch an HTTP to preview the website
 
-     """
 
-     import SimpleHTTPServer
 
-     import SocketServer
 
-     Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
 
-     httpd = SocketServer.TCPServer(("", CONFIG['http_port']), Handler)
 
-     os.chdir(CONFIG['output_to'])
 
-     print "and ready to test at http://127.0.0.1:%d" % CONFIG['http_port']
 
-     print "Hit Ctrl+C to exit"
 
-     try:
 
-         httpd.serve_forever()
 
-     except KeyboardInterrupt:
 
-         print
 
-         print "Shutting Down... Bye!."
 
-         print
 
-         httpd.server_close()
 
- def publish(GITDIRECTORY=CONFIG['output_to']):
 
-     pass
 
- def new_post(GITDIRECTORY=CONFIG['output_to']):
 
-     """
 
-     This function should create a template for a new post with a title
 
-     read from the user input.
 
-     Most other fields should be defaults.
 
-     """
 
-     title = raw_input("Give the title of the post:")
 
-     # TODO check there is not : in the title
 
-     author = CONFIG['author']
 
-     date = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d')
 
-     tags = '['+raw_input("Give the tags, separated by ', ':")+']'
 
-     published = 'yes'
 
-     chronological = 'yes'
 
-     kind = 'writing'
 
-     summary = ("summary: |\n   Type your summary here\nDo not change the "
 
-                "indentation"
 
-                "to the left\n...\nStart writing your post here!")
 
-     # make file name
 
-     fname = os.path.join(os.getcwd(), 'content', kind,
 
-                          datetime.datetime.strftime(datetime.datetime.now(),
 
-                                                     '%Y'),
 
-                          date+'-'+title.replace(' ', '-')+'.markdown')
 
-     print fname
 
- def clean(GITDIRECTORY="oz123.github.com"):
 
-     directoriestoclean = ["writings", "notes", "links", "tags", "archive"]
 
-     os.chdir(GITDIRECTORY)
 
-     for directory in directoriestoclean:
 
-         shutil.rmtree(directory)
 
- def dist(SOURCEDIR=os.getcwd()+"/content/",
 
-          DESTDIR="oz123.github.com/writings_raw/content/"):
 
-     """
 
-     sync raw files from SOURCE to DEST
 
-     """
 
-     import subprocess as sp
 
-     sp.call(["rsync", "-avP", SOURCEDIR, DESTDIR], shell=False,
 
-             cwd=os.getcwd())
 
- if __name__ == '__main__':
 
-     parser = argparse.ArgumentParser(
 
-         description='blogit - a tool to blog on github.')
 
-     parser.add_argument('-b', '--build', action="store_true",
 
-                         help='convert the markdown files to HTML')
 
-     parser.add_argument('-p', '--preview', action="store_true",
 
-                         help='Launch HTTP server to preview the website')
 
-     parser.add_argument('-c', '--clean', action="store_true",
 
-                         help='clean output files')
 
-     parser.add_argument('-n', '--new', action="store_true",
 
-                         help='create new post')
 
-     parser.add_argument('-d', '--dist', action="store_true",
 
-                         help='sync raw files from SOURCE to DEST')
 
-     args = parser.parse_args()
 
-     if len(sys.argv) < 2:
 
-         parser.print_help()
 
-         sys.exit()
 
-     if args.clean:
 
-         clean()
 
-     if args.build:
 
-         build()
 
-     if args.dist:
 
-         dist()
 
-     if args.preview:
 
-         preview()
 
-     if args.new:
 
-         new_post()
 
 
  |