From 16406fc9798c5d1563e33c7fb771af59880f7615 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 20 Oct 2011 21:24:09 -0700 Subject: [PATCH 01/58] Add some debugging hooks to the sample site. --- sample/hooks/__hooks__.py | 18 ++++++++++++++++++ sample/hooks/wok_sample_hooks.py | 2 ++ 2 files changed, 20 insertions(+) create mode 100644 sample/hooks/__hooks__.py create mode 100644 sample/hooks/wok_sample_hooks.py diff --git a/sample/hooks/__hooks__.py b/sample/hooks/__hooks__.py new file mode 100644 index 0000000..8f4c44b --- /dev/null +++ b/sample/hooks/__hooks__.py @@ -0,0 +1,18 @@ +import logging + +hooks = { + 'page.template.pre': [] +} + +try: + import wok_sample_hooks + hooks['page.render.pre'].append(wok_sample_hooks.import_hook) +except: + logging.warning("Failed to import hook.") + +def basic_hook(page, templ_vars): + logging.info('basic_hook got page 0[slug]}.'.format(page)) + +hooks['page.template.pre'].append(basic_hook) + +logging.info('Got hooks: {0}'.format(hooks)) diff --git a/sample/hooks/wok_sample_hooks.py b/sample/hooks/wok_sample_hooks.py new file mode 100644 index 0000000..76dc61d --- /dev/null +++ b/sample/hooks/wok_sample_hooks.py @@ -0,0 +1,2 @@ +def import_hook(page, templ_vars): + logging.info('import_hook got page {0[slug]}.', page.keys()) From ac9617a87a8582e29e3b37f726956eee639c5970 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 20 Oct 2011 22:51:27 -0700 Subject: [PATCH 02/58] Load the hooks --- wok/engine.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/wok/engine.py b/wok/engine.py index d16a259..9f519f0 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -29,6 +29,10 @@ class Engine(object): } def __init__(self, output_lvl = 1): + """ + Set up CLI options, logging levels, and start everything off. + Afterwards, run a dev server if asked to. + """ # CLI options # ----------- @@ -90,6 +94,7 @@ def __init__(self, output_lvl = 1): self.read_options() self.sanity_check() + self.load_hooks() self.prepare_output() self.load_pages() self.make_tree() @@ -126,6 +131,16 @@ def sanity_check(self): logging.critical("This doesn't look like a wok site. Aborting.") sys.exit(1) + def load_hooks(self): + sys.path.append('hooks') + try: + import __hooks__ + self.hooks = __hooks__.hook + logging.info('Loaded hooks: {0}'.format(self.hooks)) + except: + logging.debug('No hooks found') + + def prepare_output(self): """ Prepare the output directory. Remove any contents there already, and From 9d4ee087bfcf1cc3d6b529a7bdcf64f75cf99e4f Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 20 Oct 2011 22:58:22 -0700 Subject: [PATCH 03/58] Run the page.template.pre hook. Fix things. --- sample/hooks/__hooks__.py | 2 +- wok/engine.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/sample/hooks/__hooks__.py b/sample/hooks/__hooks__.py index 8f4c44b..4ac9556 100644 --- a/sample/hooks/__hooks__.py +++ b/sample/hooks/__hooks__.py @@ -11,7 +11,7 @@ logging.warning("Failed to import hook.") def basic_hook(page, templ_vars): - logging.info('basic_hook got page 0[slug]}.'.format(page)) + logging.info('basic_hook got page {0[slug]}.'.format(page)) hooks['page.template.pre'].append(basic_hook) diff --git a/wok/engine.py b/wok/engine.py index 9f519f0..c368d75 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -135,9 +135,10 @@ def load_hooks(self): sys.path.append('hooks') try: import __hooks__ - self.hooks = __hooks__.hook + self.hooks = __hooks__.hooks logging.info('Loaded hooks: {0}'.format(self.hooks)) except: + self.hooks = {} logging.debug('No hooks found') @@ -236,7 +237,6 @@ def render_site(self): for tag in tag_set: tag_dict[tag] = [p.meta for p in self.all_pages if tag in p.meta['tags']] - for p in self.all_pages: # Construct this every time, to avoid sharing one instance # between page objects. @@ -259,6 +259,10 @@ def render_site(self): if 'author' in self.options: templ_vars['site']['author'] = self.options['author'] + for hook in self.hooks.get('page.template.pre', []): + logging.debug('running hook {0}'.format(hook)) + hook(p.meta, templ_vars) + # Rendering the page might give us back more pages to render. new_pages = p.render(templ_vars) p.write() From a71b08d41d402a5257c5a86eae3c86a07f1f34df Mon Sep 17 00:00:00 2001 From: Jacques Uber Date: Sun, 27 Nov 2011 14:12:54 -0800 Subject: [PATCH 04/58] Applied changes until things were not broken. Feel free to fix this better. --- wok/page.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wok/page.py b/wok/page.py index cb1a08c..2f87193 100644 --- a/wok/page.py +++ b/wok/page.py @@ -298,6 +298,8 @@ def paginate(self): logging.debug('sort_key: {0}, sort_reverse: {1}'.format( sort_key, sort_reverse)) + if not source: + return extra_pages if isinstance(source[0], Page): source = [p.meta for p in source] @@ -310,6 +312,8 @@ def paginate(self): reverse=sort_reverse) chunks = list(util.chunk(source, self.meta['pagination']['limit'])) + if not chunks: + return extra_pages # Make a page for each chunk for idx, chunk in enumerate(chunks[1:]): From 0f285da2cb02c66ab5eb77524732c2c64b75b792 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 27 Nov 2011 12:48:48 -0800 Subject: [PATCH 05/58] Give the pagination-bits in the testing site titles. Shut up! --- sample/content/pagination-bits/a.mkd | 1 + sample/content/pagination-bits/b.mkd | 1 + sample/content/pagination-bits/c.mkd | 1 + sample/content/pagination-bits/d.mkd | 1 + sample/content/pagination-bits/e.mkd | 1 + sample/content/pagination-bits/f.mkd | 1 + sample/content/pagination-bits/g.mkd | 1 + sample/content/pagination-bits/h.mkd | 1 + sample/content/pagination-bits/i.mkd | 1 + sample/content/pagination-bits/j.mkd | 1 + sample/content/pagination-bits/k.mkd | 1 + 11 files changed, 11 insertions(+) diff --git a/sample/content/pagination-bits/a.mkd b/sample/content/pagination-bits/a.mkd index b60e591..6e00cec 100644 --- a/sample/content/pagination-bits/a.mkd +++ b/sample/content/pagination-bits/a.mkd @@ -1,3 +1,4 @@ +title: A category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/b.mkd b/sample/content/pagination-bits/b.mkd index c3f4552..75d055f 100644 --- a/sample/content/pagination-bits/b.mkd +++ b/sample/content/pagination-bits/b.mkd @@ -1,3 +1,4 @@ +title: B category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/c.mkd b/sample/content/pagination-bits/c.mkd index 3d2fd39..d90d99e 100644 --- a/sample/content/pagination-bits/c.mkd +++ b/sample/content/pagination-bits/c.mkd @@ -1,3 +1,4 @@ +title: C category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/d.mkd b/sample/content/pagination-bits/d.mkd index a0905ab..8ddb28a 100644 --- a/sample/content/pagination-bits/d.mkd +++ b/sample/content/pagination-bits/d.mkd @@ -1,3 +1,4 @@ +title: D category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/e.mkd b/sample/content/pagination-bits/e.mkd index 2f106f2..92ba7cc 100644 --- a/sample/content/pagination-bits/e.mkd +++ b/sample/content/pagination-bits/e.mkd @@ -1,3 +1,4 @@ +title: E category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/f.mkd b/sample/content/pagination-bits/f.mkd index a5469ba..371b691 100644 --- a/sample/content/pagination-bits/f.mkd +++ b/sample/content/pagination-bits/f.mkd @@ -1,3 +1,4 @@ +title: F category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/g.mkd b/sample/content/pagination-bits/g.mkd index f9f2bbf..d178cd9 100644 --- a/sample/content/pagination-bits/g.mkd +++ b/sample/content/pagination-bits/g.mkd @@ -1,3 +1,4 @@ +title: G category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/h.mkd b/sample/content/pagination-bits/h.mkd index be3776a..f20626f 100644 --- a/sample/content/pagination-bits/h.mkd +++ b/sample/content/pagination-bits/h.mkd @@ -1,3 +1,4 @@ +title: H category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/i.mkd b/sample/content/pagination-bits/i.mkd index 29b96c6..521c9f2 100644 --- a/sample/content/pagination-bits/i.mkd +++ b/sample/content/pagination-bits/i.mkd @@ -1,3 +1,4 @@ +title: I category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/j.mkd b/sample/content/pagination-bits/j.mkd index 169f1d1..03bf86b 100644 --- a/sample/content/pagination-bits/j.mkd +++ b/sample/content/pagination-bits/j.mkd @@ -1,3 +1,4 @@ +title: J category: pagination tags: tiny --- diff --git a/sample/content/pagination-bits/k.mkd b/sample/content/pagination-bits/k.mkd index ec9e4de..5a59b4c 100644 --- a/sample/content/pagination-bits/k.mkd +++ b/sample/content/pagination-bits/k.mkd @@ -1,3 +1,4 @@ +title: K category: pagination tags: tiny --- From ec613fd95cc898e4a1981455777d3b3c8e86c15c Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 27 Nov 2011 12:49:49 -0800 Subject: [PATCH 06/58] Pages can now be generated either from files, or from arbitrary metadata dictionaries. This enables hooks to make arbitrary new pages. Or, it will. Conflicts: wok/page.py --- wok/engine.py | 21 +++---- wok/page.py | 154 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 114 insertions(+), 61 deletions(-) diff --git a/wok/engine.py b/wok/engine.py index dd5f290..0d6d7a9 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -41,22 +41,22 @@ def __init__(self, output_lvl = 1): # Add option to to run the development server after generating pages devserver_grp = OptionGroup(parser, "Development server", - "Runs a small development server after site generation. \ - --address and --port will be ignored if --server is absent.") + "Runs a small development server after site generation. " + "--address and --port will be ignored if --server is absent.") devserver_grp.add_option('--server', action='store_true', dest='runserver', help="run a development server after generating the site") devserver_grp.add_option('--address', action='store', dest='address', help="specify ADDRESS on which to run development server") devserver_grp.add_option('--port', action='store', dest='port', - type='int', + type='int', help="specify PORT on which to run development server") parser.add_option_group(devserver_grp) # Options for noisiness level and logging logging_grp = OptionGroup(parser, "Logging", - "By default, log messages will be sent to standard out, \ - and report only errors and warnings.") + "By default, log messages will be sent to standard out, " + "and report only errors and warnings.") parser.set_defaults(loglevel=logging.WARNING) logging_grp.add_option('-q', '--quiet', action='store_const', const=logging.ERROR, dest='loglevel', @@ -148,7 +148,7 @@ def load_hooks(self): try: import __hooks__ self.hooks = __hooks__.hooks - logging.info('Loaded hooks: {0}'.format(self.hooks)) + logging.info('Loaded {0} hooks: {0}'.format(self.hooks)) except: self.hooks = {} logging.debug('No hooks found') @@ -208,16 +208,17 @@ def load_pages(self): 'for {0}. Using default renderer.'.format(f)) renderer = renderers.Renderer - p = page.Page(os.path.join(root, f), self.options, renderer) - if p.meta['published']: + p = page.Page.from_file(os.path.join(root, f), self.options, + renderer) + if p and p.meta['published']: self.all_pages.append(p) def make_tree(self): """ - Make the category pseduo-tree. + Make the category pseudo-tree. In this structure, each node is a page. Pages with sub pages are - interior nodes, and leaf nodes have no sub pages. It is not truely a + interior nodes, and leaf nodes have no sub pages. It is not truly a tree, because the root node doesn't exist. """ self.categories = {} diff --git a/wok/page.py b/wok/page.py index cb1a08c..eb001bd 100644 --- a/wok/page.py +++ b/wok/page.py @@ -23,61 +23,89 @@ class Page(object): tmpl_env = None - def __init__(self, path, options, renderer=None, extra_meta=None): + def __init__(self, options): + self.options = options + self.filename = None + self.meta = {} + + @classmethod + def from_meta(cls, meta, options, renderer=None): + """ + Build a page object from a meta dictionary. + + Note that you still need to call `render` and `write` to do anything + interesting. + """ + page = cls(options) + page.meta = meta + page.options = options + page.renderer = renderer if renderer else renderers.Plain + + # Make a template environment. Hopefully no one expects this to ever + # change. + if Page.tmpl_env is None: + Page.tmpl_env = jinja2.Environment(loader=GlobFileLoader( + page.options.get('template_dir', 'templates'))) + + try: + page.build_meta() + return page + except: + return None + + @classmethod + def from_file(cls, path, options, renderer=None): """ Load a file from disk, and parse the metadata from it. Note that you still need to call `render` and `write` to do anything interesting. """ - self.header = None - self.original = None - self.parsed = None - self.options = options - self.renderer = renderer if renderer else renderers.Plain + page = cls(options) + page.original = None + page.options = options + page.renderer = renderer if renderer else renderers.Plain logging.info('Loading {0}'.format(os.path.basename(path))) if Page.tmpl_env is None: Page.tmpl_env = jinja2.Environment(loader=GlobFileLoader( - self.options.get('template_dir', 'templates'))) + page.options.get('template_dir', 'templates'))) - self.path = path - _, self.filename = os.path.split(path) + page.path = path + page.filename = os.path.basename(path) with open(path) as f: - self.original = f.read() - splits = self.original.split('\n---\n') + page.original = f.read() + splits = page.original.split('\n---\n') if len(splits) > 3: logging.warning('Found more --- delimited sections in {0} ' 'than expected. Squashing the extra together.' - .format(self.path)) + .format(page.path)) # Handle the case where no meta data was provided if len(splits) == 1: - self.original = splits[0] - self.meta = {} + page.original = splits[0] + page.meta = {} elif len(splits) == 2: header = splits[0] - self.meta = yaml.load(header) - self.original = splits[1] + page.meta = yaml.load(header) + page.original = splits[1] - elif len(splits) == 3: + elif len(splits) >= 3: header = splits[0] - self.meta = {} - self.original = '\n'.join(splits[1:]) - self.meta['preview'] = splits[1] - self.meta.update(yaml.load(header)) + page.meta = {} + page.original = '\n'.join(splits[1:]) + page.meta['preview'] = splits[1] + page.meta.update(yaml.load(header)) logging.debug('Got preview') - if extra_meta: - logging.debug('Got extra_meta') - self.meta.update(extra_meta) + page.build_meta() + page.meta['content'] = page.renderer.render(page.original) - self.build_meta() - self.meta['content'] = self.renderer.render(self.original) + return page def build_meta(self): """ @@ -102,20 +130,42 @@ def build_meta(self): # title if not 'title' in self.meta: - self.meta['title'] = '.'.join(self.filename.split('.')[:-1]) - if (self.meta['title'] == ''): - self.meta['title'] = self.filename - - logging.info("You didn't specify a title in {0}. " - "Using the file name as a title.".format(self.filename)) + if self.filename: + # Take off the last file extension. + self.meta['title'] = '.'.join(self.filename.split('.')[:-1]) + if (self.meta['title'] == ''): + self.meta['title'] = self.filename + + logging.warning("You didn't specify a title in {0}. Using the " + "file name as a title.".format(self.path)) + elif 'slug' in self.meta: + self.meta['title'] = self.meta['slug'] + logging.warning("You didn't specify a title in {0}, which was " + "not generated from a file. Using the slug as a title." + .format(self.meta['slug'])) + else: + logging.error("A page was generated that is not from a file, " + "has no title, and no slug. I don't know what to do. " + "Not using this page.") + logging.info("Bad Meta's keys: {0}".format(self.meta.keys())) + logging.debug("Bad Meta: {0}".format(self.meta)) + raise BadMetaException() # slug if not 'slug' in self.meta: - self.meta['slug'] = util.slugify(self.meta['title']) - logging.debug("You didn't specify a slug, generating it from the title.") + if self.filename: + filename_no_ext = '.'.join(self.filename.split('.')[:-1]) + self.meta['slug'] = util.slugify(filename_no_ext) + logging.info("You didn't specify a slug, generating it from the " + "filename.") + else: + self.meta['slug'] = util.slugify(self.meta['title']) + logging.info("You didn't specify a slug, and no filename " + "exists. Generating the slug from the title.") + elif self.meta['slug'] != util.slugify(self.meta['slug']): logging.warning('Your slug should probably be all lower case, and ' - 'match "[a-z0-9-]*"') + 'match "[a-z0-9-]*"') # authors and author authors = self.meta.get('authors', self.meta.get('author', None)) @@ -130,15 +180,12 @@ def build_meta(self): '{0}.'.format(self.path)) elif authors is None: - if 'authors' in self.options: - self.meta['authors'] = self.options['authors'] - else: - self.meta['authors'] = [] + self.meta['authors'] = self.options.get('authors', []) else: - # wait, what? + # wait, what? Authors is of wrong type. self.meta['authors'] = [] logging.error(('Authors in {0} is an unknown type. Valid types ' - 'are string or list.').format(self.path)) + 'are string or list.').format(self.meta['slug'])) if self.meta['authors']: self.meta['author'] = self.meta['authors'] @@ -312,26 +359,28 @@ def paginate(self): chunks = list(util.chunk(source, self.meta['pagination']['limit'])) # Make a page for each chunk - for idx, chunk in enumerate(chunks[1:]): - extra_meta = { + for idx, chunk in enumerate(chunks[1:], 2): + new_meta = self.meta.copy() + new_meta.update({ 'pagination': { 'page_items': chunk, 'num_pages': len(chunks), - 'cur_page': idx + 2, + 'cur_page': idx+1, } - } - new_page = Page(self.path, self.options, - renderer=self.renderer, extra_meta=extra_meta) - extra_pages.append(new_page) + }) + new_page = Page.from_meta(new_meta, self.options, + renderer=self.renderer) + if new_page: + extra_pages.append(new_page) # Set up the next/previous page links - for idx, page in enumerate(extra_pages): - if idx == 0: + for idx, page in enumerate(extra_pages, 1): + if idx == 1: page.meta['pagination']['prev_page'] = self.meta else: page.meta['pagination']['prev_page'] = extra_pages[idx-1].meta - if idx < len(extra_pages) - 1: + if idx < len(extra_pages): page.meta['pagination']['next_page'] = extra_pages[idx+1].meta else: page.meta['pagination']['next_page'] = None @@ -407,3 +456,6 @@ def __repr__(self): def __unicode__(self): s = self.__str__() return s.replace('<', '<').replace('>', '>') + +class BadMetaException(Exception): + pass From df52b0249cdff5c3e8a8ba8d6464fb9d2897a4bd Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Mon, 28 Nov 2011 08:57:14 -0800 Subject: [PATCH 07/58] Fix the sample site's hooks. --- sample/config | 2 +- sample/content/tests.mkd | 2 +- sample/hooks/__hooks__.py | 11 ++++++----- sample/hooks/wok_sample_hooks.py | 4 +++- sample/templates/default.html | 1 + 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/sample/config b/sample/config index e03d1c1..1b2643f 100644 --- a/sample/config +++ b/sample/config @@ -1,4 +1,4 @@ site_title: Wok Scratch Site author: Default -url_pattern: "/{category}/{slug}{page}/index.{type}" +url_pattern: "/{category}/{slug}{page}/index.{ext}" url_include_index: no diff --git a/sample/content/tests.mkd b/sample/content/tests.mkd index a2b5530..d80bf8d 100644 --- a/sample/content/tests.mkd +++ b/sample/content/tests.mkd @@ -5,4 +5,4 @@ url: /index{page}.html --- These are the tests -The pagination test is [here](/pagination.html). +The pagination test is [here](/pagination/index.html). diff --git a/sample/hooks/__hooks__.py b/sample/hooks/__hooks__.py index 4ac9556..58e0cc5 100644 --- a/sample/hooks/__hooks__.py +++ b/sample/hooks/__hooks__.py @@ -4,14 +4,15 @@ 'page.template.pre': [] } -try: - import wok_sample_hooks - hooks['page.render.pre'].append(wok_sample_hooks.import_hook) -except: - logging.warning("Failed to import hook.") +import wok_sample_hooks +hooks['page.template.pre'].append(wok_sample_hooks.import_hook) +hook_count = 0 def basic_hook(page, templ_vars): + global hook_count logging.info('basic_hook got page {0[slug]}.'.format(page)) + templ_vars['hooked'] = hook_count + hook_count += 1 hooks['page.template.pre'].append(basic_hook) diff --git a/sample/hooks/wok_sample_hooks.py b/sample/hooks/wok_sample_hooks.py index 76dc61d..4d6183e 100644 --- a/sample/hooks/wok_sample_hooks.py +++ b/sample/hooks/wok_sample_hooks.py @@ -1,2 +1,4 @@ +import logging + def import_hook(page, templ_vars): - logging.info('import_hook got page {0[slug]}.', page.keys()) + logging.info('import_hook got page {0[slug]}.'.format(page)) diff --git a/sample/templates/default.html b/sample/templates/default.html index 8511bde..7224a32 100644 --- a/sample/templates/default.html +++ b/sample/templates/default.html @@ -11,5 +11,6 @@

Tags:

  • {{ tag }}
  • {% endfor %} + Hooked: {{ hooked }} {{ page.content }} {% endblock body %} From e9f0f9215420f2f4c5b99268456d5f2d92182b84 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Mon, 28 Nov 2011 08:57:25 -0800 Subject: [PATCH 08/58] Document the hooks. Most of these aren't actually implemented yet. --- docs/content/docs/hooks.mkd | 75 +++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 docs/content/docs/hooks.mkd diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd new file mode 100644 index 0000000..93da010 --- /dev/null +++ b/docs/content/docs/hooks.mkd @@ -0,0 +1,75 @@ +title: Hooks +category: docs +--- +Since version 0.9, wok provides a hook interface to add custom python code to +the site generation pipeline. + +To use hooks, make a new site directory (next to content, templates, etc.) +named `hooks`. In this folder make the file `__hooks__.py`. From this file, wok +will import the variable `hooks`. This should be a dictionary; the keys are the +hook names below, and the values are lists of functions (or other callables) to +run for the hooks. They will be run in the order they appear here. + +Functions +--------- +The available hooks, the arguments they will get, and when they run are + + +`site.start()` +:

    Called before anything else has started, except the loading of hooks. This would be a good time to modify the content, template, or media directories.

    + +`site.output.pre(output_path)` +: `output_path` + : The path to the output directory. +: This path will run before the output directory is populated by the media, + and after the old site has been deleted. You can add files that may be + overwritten by the media files, or the site content. + +`site.output.post(output_path)` +: `output_path` + : The path to the output directory. +: This hook will run after the output directory is populated by the media, + and before the content pages have started to be processed. You can use this + to modify, overwrite, or otherwise fiddle with the media directory after it + has been copied to the output dir. + +`site.content.gather.pre()` +: Return value + : List of `Page` objects to add to the list of pages. +: This hook will run before wok gathers content pages, and can be used to add + pages that don't exist on disk. + +`site.content.gather.post(pages)` +: `pages` + : The list of pages that wok has gathered from the content directory, and + any other hooks that have run. Also includes the duplicated versions of + paginated pages. +: Return value + : List of `Page` objects to add to the list of pages. +: This hook will run after wok gathers content pages, and can be used to add + pages that don't exist on disk, or to remove pages added by other means. If + you modify the list of pages received, those changes will take affect in + wok, and you can also return pages to add. + +`page.template.pre(page, templ_vars)` +: `page` + : The current page object that is being processed. +: `templ_vars` + : The variables that will be sent to the template engine. +: This hook will be called before the page is sent to the template engine. At + this point the content has been transformed from markup input to html + output (if applicable). If you modify the `templ_vars` parameter, those + changes will be visible to the template engine. + +`page.template.post(page)` +: `page` + : The current page being processed. +: This hook will be called after the page has been processed by the template + engine. The next step will be write the file to disk, if applicable, so any + last minute changes should happen here. + +`site.done()` +: Called after wok has finished everything. This would be a good time to make + any general modifications to the output, or to do something like upload the + site for distribution. If the `--server` option has been specified, this + will happen before the server is run. From c2026422afcb7452f098deddb58c0133c2de8a30 Mon Sep 17 00:00:00 2001 From: Jacques Uber Date: Sun, 27 Nov 2011 14:12:54 -0800 Subject: [PATCH 09/58] Applied changes until things were not broken. Feel free to fix this better. --- wok/page.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wok/page.py b/wok/page.py index cb1a08c..2f87193 100644 --- a/wok/page.py +++ b/wok/page.py @@ -298,6 +298,8 @@ def paginate(self): logging.debug('sort_key: {0}, sort_reverse: {1}'.format( sort_key, sort_reverse)) + if not source: + return extra_pages if isinstance(source[0], Page): source = [p.meta for p in source] @@ -310,6 +312,8 @@ def paginate(self): reverse=sort_reverse) chunks = list(util.chunk(source, self.meta['pagination']['limit'])) + if not chunks: + return extra_pages # Make a page for each chunk for idx, chunk in enumerate(chunks[1:]): From 4ff371fa1ac9a791c0ccbdd85b13c282511d23f7 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 29 Nov 2011 14:17:05 -0800 Subject: [PATCH 10/58] Implement the rest of the hooks. --- docs/content/docs/hooks.mkd | 9 +++++---- wok/engine.py | 32 ++++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index 93da010..c9e2d3b 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -15,6 +15,7 @@ Functions The available hooks, the arguments they will get, and when they run are + `site.start()` :

    Called before anything else has started, except the loading of hooks. This would be a good time to modify the content, template, or media directories.

    @@ -56,10 +57,10 @@ The available hooks, the arguments they will get, and when they run are : The current page object that is being processed. : `templ_vars` : The variables that will be sent to the template engine. -: This hook will be called before the page is sent to the template engine. At - this point the content has been transformed from markup input to html - output (if applicable). If you modify the `templ_vars` parameter, those - changes will be visible to the template engine. +: This hook will be called for each page before the page is sent to the + template engine. At this point the content has been transformed from markup + input to html output (if applicable). If you modify the `templ_vars` + parameter, those changes will be visible to the template engine. `page.template.post(page)` : `page` diff --git a/wok/engine.py b/wok/engine.py index 0d6d7a9..5b0488e 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -96,11 +96,16 @@ def __init__(self, output_lvl = 1): self.read_options() self.sanity_check() self.load_hooks() + + self.run_hook('site.start') + self.prepare_output() self.load_pages() self.make_tree() self.render_site() + self.run_hook('site.stop') + # Dev server # ---------- # Run the dev server after generating pages if the user said to @@ -108,6 +113,7 @@ def __init__(self, output_lvl = 1): devserver.run(cli_options.address, cli_options.port, serv_dir=os.path.join(self.options['output_dir'])) + def read_options(self): """Load options from the config file.""" self.options = Engine.default_options.copy() @@ -153,6 +159,9 @@ def load_hooks(self): self.hooks = {} logging.debug('No hooks found') + def run_hook(hook_name, *args): + for hook in self.hooks.get(hook_name, []): + yield hook(*args) def prepare_output(self): """ @@ -169,6 +178,8 @@ def prepare_output(self): else: os.mkdir(self.options['output_dir']) + self.run_hook('site.output.pre', self.options['output_dir']) + # Copy the media directory to the output folder try: for name in os.listdir(self.options['media_dir']): @@ -182,13 +193,21 @@ def prepare_output(self): else: shutil.copy(path, self.options['output_dir']) + self.run_hook('site.output.post', self.options['output_dir']) + # Do nothing if the media directory doesn't exist except OSError: # XXX: We should verify that the problem was the media dir - pass + logging.info('There was a problem copying the media files to the ' + 'output directory.') def load_pages(self): """Load all the content files.""" + # Load pages from hooks (pre) + for pages in self.run_hook('site.content.gather.pre'): + self.all_pages.extend(pages) + + # Load files for root, dirs, files in os.walk(self.options['content_dir']): # Grab all the parsable files for f in files: @@ -213,6 +232,10 @@ def load_pages(self): if p and p.meta['published']: self.all_pages.append(p) + # Load pages from hooks (post) + for page in self.run_hook('site.content.gather.post'): + self.all_pages.extend(pages) + def make_tree(self): """ Make the category pseudo-tree. @@ -279,12 +302,13 @@ def render_site(self): if 'author' in self.options: templ_vars['site']['author'] = self.options['author'] - for hook in self.hooks.get('page.template.pre', []): - logging.debug('running hook {0}'.format(hook)) - hook(p.meta, templ_vars) + self.run_hook('page.template.pre', p, templ_vars) # Rendering the page might give us back more pages to render. new_pages = p.render(templ_vars) + + self.run_hook('page.template.post', p) + if p.meta['make_file']: p.write() From e9a17868dcf36c70a385d4347a469b9a2c7daa83 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 29 Nov 2011 14:26:33 -0800 Subject: [PATCH 11/58] Add Corbin and Kevin's sites to the community page. --- docs/content/community.mkd | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/content/community.mkd b/docs/content/community.mkd index 850d5f7..f39d1d0 100644 --- a/docs/content/community.mkd +++ b/docs/content/community.mkd @@ -4,19 +4,24 @@ nav_sort: 3 --- In the wild ----------- -Wok powers an ever growing list of sites. +Wok powers an ever growing list of sites. If you want to see the power +of what wok can do, or how to do something, these website are a good +resource to look at. - This site ([source](https://github.com/mythmon/tree/master/docs)) - [Oregon State University LUG](http://lug.oregonstate.edu) ([source](https://github.com/OSULUG/OSULUG-Website)) -- [robmd.net](http://robmd.net) - ([source](https://github.com/robatron/robmd.net)) - Personal site of Rob - McGuire-Dale. - [Bravo Server](http://bravoserver.org) ([source](https://github.com/MostAwesomeDude/bravo/tree/master/website)) - A custom Minecraft server written in Python. +- [robmd.net](http://robmd.net) + ([source](https://github.com/robatron/robmd.net)) - Rob McGuire-Dale. - [uberj.com](http://uberj.com) ([source](https://github.com/uberj/wbsite)) - - Personal website of Jacques Uber. + Jacques Uber. +- [ngokevin.com](http://ngokevin.com) + ([source](https://github.com/ngokevin/ngokevin)) - Kevin Ngo. +- [corbinsimpson.com](http://corbinsimpson.com) + ([source](https://github.com/MostAwesomeDude/website)) - Corbin Simpson. Contributors ------------ From 0ce9c4b1e4dc83bd0d36c8b42743c4db4817c29d Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 29 Nov 2011 15:32:06 -0800 Subject: [PATCH 12/58] Fix the hooks. Why do we test before we commit? So we don't do stuff like this. --- sample/hooks/__hooks__.py | 31 +++++++++++++++------------- sample/hooks/wok_sample_hooks.py | 4 ---- wok/engine.py | 35 ++++++++++++++++---------------- 3 files changed, 35 insertions(+), 35 deletions(-) delete mode 100644 sample/hooks/wok_sample_hooks.py diff --git a/sample/hooks/__hooks__.py b/sample/hooks/__hooks__.py index 58e0cc5..a8a4252 100644 --- a/sample/hooks/__hooks__.py +++ b/sample/hooks/__hooks__.py @@ -1,19 +1,22 @@ import logging -hooks = { - 'page.template.pre': [] -} - -import wok_sample_hooks -hooks['page.template.pre'].append(wok_sample_hooks.import_hook) - hook_count = 0 -def basic_hook(page, templ_vars): - global hook_count - logging.info('basic_hook got page {0[slug]}.'.format(page)) - templ_vars['hooked'] = hook_count - hook_count += 1 +def make_hook(name): + def logging_hook(*args): + global hook_count + logging.info('logging_hook: {0}: {1}'.format(name, hook_count)) + hook_count += 1 + return [logging_hook] -hooks['page.template.pre'].append(basic_hook) +hooks = { + 'site.start': make_hook('site.start'), + 'site.output.pre': make_hook('site.output.pre'), + 'site.output.post': make_hook('site.output.post'), + 'site.content.gather.pre': make_hook('site.content.gather.pre'), + 'site.content.gather.post': make_hook('site.content.gather.post'), + 'page.template.pre': make_hook('page.template.pre'), + 'page.template.post': make_hook('page.template.post'), + 'site.stop': make_hook('site.stop'), +} -logging.info('Got hooks: {0}'.format(hooks)) +logging.info('loaded hooks.') diff --git a/sample/hooks/wok_sample_hooks.py b/sample/hooks/wok_sample_hooks.py deleted file mode 100644 index 4d6183e..0000000 --- a/sample/hooks/wok_sample_hooks.py +++ /dev/null @@ -1,4 +0,0 @@ -import logging - -def import_hook(page, templ_vars): - logging.info('import_hook got page {0[slug]}.'.format(page)) diff --git a/wok/engine.py b/wok/engine.py index 5b0488e..52f4c8b 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -9,7 +9,7 @@ import yaml import wok -from wok import page +from wok.page import Page, Author from wok import renderers from wok import util from wok import devserver @@ -128,9 +128,9 @@ def read_options(self): # Make authors a list, even only a single author was specified. authors = self.options.get('authors', self.options.get('author', None)) if isinstance(authors, list): - self.options['authors'] = [page.Author.parse(a) for a in authors] + self.options['authors'] = [Author.parse(a) for a in authors] elif isinstance(authors, str): - self.options['authors'] = [page.Author.parse(a) for a in authors.split(',')] + self.options['authors'] = [Author.parse(a) for a in authors.split(',')] if len(self.options['authors']) > 1: logging.warn('Deprecation Warning: Use YAML lists instead of ' 'CSV for multiple authors. i.e. ["John Doe", "Jane ' @@ -151,17 +151,16 @@ def sanity_check(self): def load_hooks(self): sys.path.append('hooks') - try: - import __hooks__ - self.hooks = __hooks__.hooks - logging.info('Loaded {0} hooks: {0}'.format(self.hooks)) - except: - self.hooks = {} - logging.debug('No hooks found') - - def run_hook(hook_name, *args): + import __hooks__ + self.hooks = __hooks__.hooks + logging.info('Loaded {0} hooks: {0}'.format(self.hooks)) + + def run_hook(self, hook_name, *args): + logging.debug('Running hook {0}'.format(hook_name)) + returns = [] for hook in self.hooks.get(hook_name, []): - yield hook(*args) + returns.append(hook(*args)) + return returns def prepare_output(self): """ @@ -205,7 +204,8 @@ def load_pages(self): """Load all the content files.""" # Load pages from hooks (pre) for pages in self.run_hook('site.content.gather.pre'): - self.all_pages.extend(pages) + if pages: + self.all_pages.extend(pages) # Load files for root, dirs, files in os.walk(self.options['content_dir']): @@ -227,14 +227,15 @@ def load_pages(self): 'for {0}. Using default renderer.'.format(f)) renderer = renderers.Renderer - p = page.Page.from_file(os.path.join(root, f), self.options, + p = Page.from_file(os.path.join(root, f), self.options, renderer) if p and p.meta['published']: self.all_pages.append(p) # Load pages from hooks (post) - for page in self.run_hook('site.content.gather.post'): - self.all_pages.extend(pages) + for pages in self.run_hook('site.content.gather.post'): + if pages: + self.all_pages.extend(pages) def make_tree(self): """ From 34442dab4a55df0c24f4358c136f9c64ce174551 Mon Sep 17 00:00:00 2001 From: Kevin Ngo Date: Wed, 30 Nov 2011 01:13:37 -0800 Subject: [PATCH 13/58] added kevin and corbin's site to readme --- README.mkd | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.mkd b/README.mkd index b819ffb..7679dd0 100644 --- a/README.mkd +++ b/README.mkd @@ -16,8 +16,8 @@ I wanted to do with my website. So I am writing my own. Funnily, the mythical website that inspired wok still hasn't been written. [jekyll]: https://github.com/mojombo/jekyll -[hyde]: https://github.com/lakshmivyas/hyde -[static]: http://static.newqdev.com/ +[hyde]: https://github.com/lakshmivyas/hyde +[static]: http://static.newqdev.com/ Sample Sites ------------ @@ -38,6 +38,12 @@ For some real world examples check out these sites. - [uberj.com](http://www.uberj.com) ([source](https://github.com/uberj/wbsite)) - Personal website of Jacques Uber +- [ngokevin.com](http://ngokevin.com) + ([source](https://github.com/ngokevin/ngokevin)) - Personal website of + Kevin Ngo +- [corbinsimpson.com](http://corbinsimpson.com) + ([source](https://github.com/mostawesomedude/website)) - Personal website + of Corbin Simpson - Your site here! If you are using wok to generate sites, and don't mind serving as an example, let me know and I will add a link to your site here. From 825227cdab0a4b708f966f8bceb1b0ec0d720103 Mon Sep 17 00:00:00 2001 From: Kevin Ngo Date: Wed, 30 Nov 2011 02:20:20 -0800 Subject: [PATCH 14/58] added some docs to the hooks that would have helped me --- docs/content/docs/hooks.mkd | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index c9e2d3b..fe264e3 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -8,7 +8,9 @@ To use hooks, make a new site directory (next to content, templates, etc.) named `hooks`. In this folder make the file `__hooks__.py`. From this file, wok will import the variable `hooks`. This should be a dictionary; the keys are the hook names below, and the values are lists of functions (or other callables) to -run for the hooks. They will be run in the order they appear here. +run for the hooks. Simply give the names of the functions and do not invoke +them. If the hooks below have parameters, the listed functions should accept +those parameters. They will be run in the order they appear here. Functions --------- @@ -60,7 +62,8 @@ The available hooks, the arguments they will get, and when they run are : This hook will be called for each page before the page is sent to the template engine. At this point the content has been transformed from markup input to html output (if applicable). If you modify the `templ_vars` - parameter, those changes will be visible to the template engine. + parameter, those changes will be visible to the template engine. The given + functions should take in these two variables. `page.template.post(page)` : `page` From f030d1416c0217fbe643921f130a2c2e55df6026 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 30 Nov 2011 08:23:18 -0800 Subject: [PATCH 15/58] Tweak the hook docs. --- docs/content/docs/hooks.mkd | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index c9e2d3b..43020d1 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -17,7 +17,9 @@ The available hooks, the arguments they will get, and when they run are `site.start()` -:

    Called before anything else has started, except the loading of hooks. This would be a good time to modify the content, template, or media directories.

    +: Called before anything else has started, except the loading of hooks. + This would be a good time to modify the content, templates, or the files in + the media directory. `site.output.pre(output_path)` : `output_path` @@ -56,12 +58,16 @@ The available hooks, the arguments they will get, and when they run are : `page` : The current page object that is being processed. : `templ_vars` - : The variables that will be sent to the template engine. + : A dictionart of the variables that will be sent to the template engine. + See the documentation on [templates][] for it's normal contents. : This hook will be called for each page before the page is sent to the template engine. At this point the content has been transformed from markup - input to html output (if applicable). If you modify the `templ_vars` + input (such as markdown) to html output if applicable. The transformed + version is in `templ_Vars['content']`. If you modify the `templ_vars` parameter, those changes will be visible to the template engine. +[templates]: /docs/templates/ + `page.template.post(page)` : `page` : The current page being processed. From 88286c61c95e4b59ae4bdaa11c7b6fa1b1b34a38 Mon Sep 17 00:00:00 2001 From: Kevin Ngo Date: Wed, 30 Nov 2011 01:13:37 -0800 Subject: [PATCH 16/58] added kevin and corbin's site to readme --- README.mkd | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.mkd b/README.mkd index b819ffb..7679dd0 100644 --- a/README.mkd +++ b/README.mkd @@ -16,8 +16,8 @@ I wanted to do with my website. So I am writing my own. Funnily, the mythical website that inspired wok still hasn't been written. [jekyll]: https://github.com/mojombo/jekyll -[hyde]: https://github.com/lakshmivyas/hyde -[static]: http://static.newqdev.com/ +[hyde]: https://github.com/lakshmivyas/hyde +[static]: http://static.newqdev.com/ Sample Sites ------------ @@ -38,6 +38,12 @@ For some real world examples check out these sites. - [uberj.com](http://www.uberj.com) ([source](https://github.com/uberj/wbsite)) - Personal website of Jacques Uber +- [ngokevin.com](http://ngokevin.com) + ([source](https://github.com/ngokevin/ngokevin)) - Personal website of + Kevin Ngo +- [corbinsimpson.com](http://corbinsimpson.com) + ([source](https://github.com/mostawesomedude/website)) - Personal website + of Corbin Simpson - Your site here! If you are using wok to generate sites, and don't mind serving as an example, let me know and I will add a link to your site here. From ce397b601b573a66bf0d48eb2b4ba7515ba25142 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Wed, 4 Jan 2012 20:06:04 -0800 Subject: [PATCH 17/58] Making hooks site module optional --- wok/engine.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/wok/engine.py b/wok/engine.py index 52f4c8b..fdff74e 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -150,16 +150,23 @@ def sanity_check(self): sys.exit(1) def load_hooks(self): - sys.path.append('hooks') - import __hooks__ - self.hooks = __hooks__.hooks - logging.info('Loaded {0} hooks: {0}'.format(self.hooks)) + try: + sys.path.append('hooks') + import __hooks__ + self.hooks = __hooks__.hooks + logging.info('Loaded {0} hooks: {0}'.format(self.hooks)) + except ImportError: + logging.info('No hooks module found.') def run_hook(self, hook_name, *args): + """ Run specified hooks if they exist """ logging.debug('Running hook {0}'.format(hook_name)) returns = [] - for hook in self.hooks.get(hook_name, []): - returns.append(hook(*args)) + try: + for hook in self.hooks.get(hook_name, []): + returns.append(hook(*args)) + except AttributeError: + logging.info('Hook {0} not defined'.format(hook_name)) return returns def prepare_output(self): From 06272a8a6cfb162b126e688ebae4cdcaca9d6109 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 8 Jan 2012 12:37:30 -0800 Subject: [PATCH 18/58] Call the page.template.* hooks from the Page object, instead of the engine. This fixes a problem where not all the template variables are available to hooks. In particular, only the variables from outside the Page were passed to the hooks. Closes #54 --- wok/engine.py | 4 ---- wok/page.py | 8 +++++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/wok/engine.py b/wok/engine.py index fdff74e..77cf84e 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -310,13 +310,9 @@ def render_site(self): if 'author' in self.options: templ_vars['site']['author'] = self.options['author'] - self.run_hook('page.template.pre', p, templ_vars) - # Rendering the page might give us back more pages to render. new_pages = p.render(templ_vars) - self.run_hook('page.template.post', p) - if p.meta['make_file']: p.write() diff --git a/wok/page.py b/wok/page.py index eb001bd..d2f2c95 100644 --- a/wok/page.py +++ b/wok/page.py @@ -294,26 +294,32 @@ def render(self, templ_vars=None): if not templ_vars: templ_vars = {} + # Handle pagination if we needed. if 'pagination' in self.meta and 'list' in self.meta['pagination']: extra_pages = self.paginate() else: extra_pages = [] + # Don't clobber possible values in the template variables. if 'page' in templ_vars: logging.debug('Found defaulted page data.') templ_vars['page'].update(self.meta) else: templ_vars['page'] = self.meta + # Don't clobber pagination either. if 'pagination' in templ_vars: templ_vars['pagination'].update(self.meta['pagination']) else: templ_vars['pagination'] = self.meta['pagination'] + # ... and actions! (and logging, and hooking) + self.run_hook('page.template.pre', p, templ_vars) logging.debug('templ_vars.keys(): ' + repr(templ_vars.keys())) self.rendered = self.template.render(templ_vars) - logging.debug('extra pages is: ' + repr(extra_pages)) + self.run_hook('page.template.post', p) + return extra_pages def paginate(self): From 5e86ac117ba639192b5707cebc02fa29ae1ad52d Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 11 Jan 2012 16:17:07 -0800 Subject: [PATCH 19/58] [docs] Hooks are no longer an upcoming feature. --- docs/content/home.mkd | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/content/home.mkd b/docs/content/home.mkd index 3fba8c0..026ee17 100644 --- a/docs/content/home.mkd +++ b/docs/content/home.mkd @@ -35,10 +35,7 @@ Features - Tagging and a hierarchical category system. - Simple development server, for testing. - Support for pagination. - -And more to come. Some features that are cooking in the devs' heads are -custom python plugins, once per page hooks, and support for more markup -languages. +- Custom Python hooks that run during site generation. [jinja2]: http://jinja.pocoo.org [mkd]: http://daringfireball.net/projects/markdown/ From c45e441f786ce14fb832ad7935c574e127c2bf3a Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sat, 14 Jan 2012 10:38:42 -0800 Subject: [PATCH 20/58] Give Pages a reference to engine, so they can call hooks. resolves the regression introduced in #06272a8a6cfb162b126e688ebae4cdcaca9d6109. Sorry @robatron! --- wok/engine.py | 3 +-- wok/page.py | 17 +++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/wok/engine.py b/wok/engine.py index 77cf84e..3ec7b4f 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -234,8 +234,7 @@ def load_pages(self): 'for {0}. Using default renderer.'.format(f)) renderer = renderers.Renderer - p = Page.from_file(os.path.join(root, f), self.options, - renderer) + p = Page.from_file(os.path.join(root, f), self.options, self, renderer) if p and p.meta['published']: self.all_pages.append(p) diff --git a/wok/page.py b/wok/page.py index cfb2c49..ee34cc4 100644 --- a/wok/page.py +++ b/wok/page.py @@ -23,20 +23,21 @@ class Page(object): tmpl_env = None - def __init__(self, options): + def __init__(self, options, engine): self.options = options self.filename = None self.meta = {} + self.engine = engine @classmethod - def from_meta(cls, meta, options, renderer=None): + def from_meta(cls, meta, options, engine, renderer=None): """ Build a page object from a meta dictionary. Note that you still need to call `render` and `write` to do anything interesting. """ - page = cls(options) + page = cls(options, engine) page.meta = meta page.options = options page.renderer = renderer if renderer else renderers.Plain @@ -54,14 +55,14 @@ def from_meta(cls, meta, options, renderer=None): return None @classmethod - def from_file(cls, path, options, renderer=None): + def from_file(cls, path, options, engine, renderer=None): """ Load a file from disk, and parse the metadata from it. Note that you still need to call `render` and `write` to do anything interesting. """ - page = cls(options) + page = cls(options, engine) page.original = None page.options = options page.renderer = renderer if renderer else renderers.Plain @@ -314,11 +315,11 @@ def render(self, templ_vars=None): templ_vars['pagination'] = self.meta['pagination'] # ... and actions! (and logging, and hooking) - self.run_hook('page.template.pre', p, templ_vars) + self.engine.run_hook('page.template.pre', self, templ_vars) logging.debug('templ_vars.keys(): ' + repr(templ_vars.keys())) self.rendered = self.template.render(templ_vars) logging.debug('extra pages is: ' + repr(extra_pages)) - self.run_hook('page.template.post', p) + self.engine.run_hook('page.template.post', self) return extra_pages @@ -378,7 +379,7 @@ def paginate(self): 'cur_page': idx+1, } }) - new_page = Page.from_meta(new_meta, self.options, + new_page = Page.from_meta(new_meta, self.options, self.engine, renderer=self.renderer) if new_page: extra_pages.append(new_page) From 06f3a9066926e9fd46ab8d9034b274801b5a9638 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Sun, 15 Jan 2012 19:42:23 -0800 Subject: [PATCH 21/58] Adding quotes around the 'output' directory name in docs README. --- docs/README | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README b/docs/README index 23f3d0c..68e684d 100644 --- a/docs/README +++ b/docs/README @@ -1,2 +1,2 @@ -This is a wok site. To see it as rendered HTML, run wok and look in the output -directory. +This is a wok site. To see it as rendered HTML, run wok and look in the +generated 'output' directory. From 110168b14bf43d1f15ea5339d27b9cf7a45ee0b9 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Sun, 15 Jan 2012 19:56:10 -0800 Subject: [PATCH 22/58] Fixing grammar, capitalization, and wording in Community section --- docs/content/community.mkd | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/content/community.mkd b/docs/content/community.mkd index f39d1d0..6a5b0d8 100644 --- a/docs/content/community.mkd +++ b/docs/content/community.mkd @@ -4,9 +4,9 @@ nav_sort: 3 --- In the wild ----------- -Wok powers an ever growing list of sites. If you want to see the power -of what wok can do, or how to do something, these website are a good -resource to look at. +Wok powers an ever-growing list of sites. If you want to see the power +of what wok can do, or how to do something, these websites are a good +resource: - This site ([source](https://github.com/mythmon/tree/master/docs)) - [Oregon State University LUG](http://lug.oregonstate.edu) @@ -15,13 +15,16 @@ resource to look at. ([source](https://github.com/MostAwesomeDude/bravo/tree/master/website)) - A custom Minecraft server written in Python. - [robmd.net](http://robmd.net) - ([source](https://github.com/robatron/robmd.net)) - Rob McGuire-Dale. + ([source](https://github.com/robatron/robmd.net)) - Personal web site of + Rob McGuire-Dale. - [uberj.com](http://uberj.com) ([source](https://github.com/uberj/wbsite)) - - Jacques Uber. + Personal web site of Jacques Uber. - [ngokevin.com](http://ngokevin.com) - ([source](https://github.com/ngokevin/ngokevin)) - Kevin Ngo. + ([source](https://github.com/ngokevin/ngokevin)) - Personal web site of + Kevin Ngo. - [corbinsimpson.com](http://corbinsimpson.com) - ([source](https://github.com/MostAwesomeDude/website)) - Corbin Simpson. + ([source](https://github.com/MostAwesomeDude/website)) - Personal web site + of Corbin Simpson. Contributors ------------ @@ -32,7 +35,7 @@ Without these early adopters, wok would have lacked direction, definition, and a purpose. Each of them helped me work through figuring out what wok could do, needed do to, where it was broken, and what it should become. -- Rob Mcguire-Dale (robatron) +- Rob McGuire-Dale (robatron) - Kevin Ngo (ngoke) - Corbin Simpson (MostAwesomeDude) - Jacque Uber (uberj) @@ -42,7 +45,7 @@ Support If there are bugs or feature requests for wok, please send them to [the issue tracker][gh-issues]. -For real time support, you can check out the irc channel `#wok` on +For real-time support, you can check out the irc channel `#wok` on irc.freenode.net. [gh-issues]: https://github.com/mythmon/wok/issues From bc116abf8af1a829b25316ab1c9c878da7fa7a38 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Sun, 15 Jan 2012 20:01:04 -0800 Subject: [PATCH 23/58] Fixing wok docs link in 'Community' --- docs/content/community.mkd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/community.mkd b/docs/content/community.mkd index 6a5b0d8..cdc5a5c 100644 --- a/docs/content/community.mkd +++ b/docs/content/community.mkd @@ -8,7 +8,7 @@ Wok powers an ever-growing list of sites. If you want to see the power of what wok can do, or how to do something, these websites are a good resource: -- This site ([source](https://github.com/mythmon/tree/master/docs)) +- This site ([source](https://github.com/mythmon/wok/tree/master/docs)) - [Oregon State University LUG](http://lug.oregonstate.edu) ([source](https://github.com/OSULUG/OSULUG-Website)) - [Bravo Server](http://bravoserver.org) From 8c42d7cdea2ce09983986a944a87f1266fee599b Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Sun, 15 Jan 2012 21:31:50 -0800 Subject: [PATCH 24/58] Cleaning up spacing, adding links to Markdown, reStructuredText and Pygments, and a small grammar change in 'Docs' index --- docs/content/docs.mkd | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/content/docs.mkd b/docs/content/docs.mkd index a81636c..ecee0bf 100644 --- a/docs/content/docs.mkd +++ b/docs/content/docs.mkd @@ -6,30 +6,34 @@ type: index-links-recurse Install ------- -If you just want to use wok, then you should install it from the [Python Package -Index][pypi]. A good way to do that is with `pip`: +If you just want to use wok, then you should install it from the +[Python Package Index][pypi]. A good way to do that is with `pip`: ::console sudo pip install wok -Which will install wok and the required dependencies. You should also install at least one of Markdown, or reStructuredText, for content markup. +This will install wok and the required dependencies. You should also install at +least one of [Markdown][mkd], or [reStructuredText][rst], for content markup: ::console sudo pip install Markdown sudo pip install docutils -If you want Pygments syntax highlighting, you also need Pygments. +If you want syntax highlighting, you will also need [Pygments][pgmnts]. ::console sudo pip install Pygments +[mkd]: http://daringfireball.net/projects/markdown/ +[rst]: http://docutils.sourceforge.net/rst.html +[pgmnts]: http://pygments.org/ [pypi]: http://pypi.python.org/pypi Contribute ---------- You can find wok's source code on [Github][gh]. If you find any issues, please post them to [the issue tracker][gh-issues]. If you want to help -code, feel free, patches and pull requests are welcome. +code, feel free. Patches and pull requests are welcome. [gh]: https://github.com/mythmon/wok [gh-issues]: https://github.com/mythmon/wok/issues From ec666c6e467466e2cbe4a3afc86ff54454338257 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Sun, 15 Jan 2012 21:44:39 -0800 Subject: [PATCH 25/58] Adding Drupal/Django links, changing wording for Git post-hook example, removing periods after each feature for consistency, rearranging wording in features for flow, and small grammar changes in 'Home' section. --- docs/content/home.mkd | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/content/home.mkd b/docs/content/home.mkd index 026ee17..ab499a1 100644 --- a/docs/content/home.mkd +++ b/docs/content/home.mkd @@ -8,12 +8,12 @@ content, and resources (like CSS and images) into a neat stack of plain HTML. You run it on your local computer, and it generates a directory of web files that you can upload to your web server, or serve directly. -The idea is that you don't need a big server-side engine like Drupal or -Django to generate every page, every visit, for every visitor. Caching -helps, but it can only do so much. Instead, you can generate the entire -site once ahead of time, and only regenerate things when something has -changed. A good way this could be done would be with a post-commit hook -on a git repository containing your content or layout. +The idea is that you don't need a big server-side engine like PHP, [Drupal][], +[Django][], etc. to generate every page, every visit, for every visitor. +Caching helps, but it can only do so much. Instead, you can generate the entire +site once ahead of time, and only regenerate things when something has changed, +e.g, with a post-commit hook on a Git repository containing your content or +layout. Wok is similar in concept to other static site generators, like [Jekyll][], [Hyde][], and [nanoc][], but different in a few ways, like @@ -21,6 +21,8 @@ a page/subpage category system, and a restricted focus of features. For example, instead of providing tools to generate RSS feeds directly, the tools that are needed to build a generic XML document are provided. +[drupal]: http://drupal.org +[django]: http://djangoproject.com [jekyll]: https://github.com/mojombo/jekyll [hyde]: https://github.com/lakshmivyas/hyde [nanoc]: http://nanoc.stoneship.org/ @@ -28,14 +30,14 @@ tools that are needed to build a generic XML document are provided. Features -------- -- Content and presentation are separated. -- [Markdown][mkd], [reStructuredText][rst], and plain text renders. -- [Jinja2][] based templating system. -- Optional: Syntax highlighting via [Pygments][] -- Tagging and a hierarchical category system. -- Simple development server, for testing. -- Support for pagination. -- Custom Python hooks that run during site generation. +- Content and presentation are separated +- [Markdown][mkd], [reStructuredText][rst], and plain text renders +- [Jinja2][]-based templating system +- Optional syntax highlighting via [Pygments][] +- Tagging and a hierarchical category system +- Simple development server +- Pagination support +- Custom Python hooks that run during site generation [jinja2]: http://jinja.pocoo.org [mkd]: http://daringfireball.net/projects/markdown/ From d88ca6ac35c2b43afb079d81214f46cb21231e38 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Mon, 16 Jan 2012 19:12:03 -0800 Subject: [PATCH 26/58] Adding examples to 'hooks' intro in 'docs', minor grammar. --- docs/content/docs/hooks.mkd | 46 +++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index d3ba298..29434d7 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -4,13 +4,45 @@ category: docs Since version 0.9, wok provides a hook interface to add custom python code to the site generation pipeline. -To use hooks, make a new site directory (next to content, templates, etc.) -named `hooks`. In this folder make the file `__hooks__.py`. From this file, wok -will import the variable `hooks`. This should be a dictionary; the keys are the -hook names below, and the values are lists of functions (or other callables) to -run for the hooks. Simply give the names of the functions and do not invoke -them. If the hooks below have parameters, the listed functions should accept -those parameters. They will be run in the order they appear here. +To use hooks, make a new directory in your site root named `hooks`. In this +directory, make the file `__hooks__.py`. For example: + + site-root/ + |-- config + |-- content/ + |-- hooks/ + | |-- __hooks__.py + | |-- hook_foo.py + | `-- hook_bar.py + | + |-- media/ + |-- output/ + `-- templates/ + + +From the `__hooks__.py` file, wok will import the variable `hooks`. +This should be a dictionary; The keys are the hook names below, and the values +are lists of functions (or other callables) to run for the hooks. Simply give +the names of the functions and (but do not invoke them.) For example: + + ::python + ''' __hooks__.py + + Attach Python functions to wok hooks. + ''' + + import hook_foo + import hook_bar + + # The `hooks` dictionary that wok will import + hooks = { + 'site.start': [hook_foo.download_images], + 'site.content.gather.post': [hook_bar.process_pages] + } + +If the hooks below have parameters, the listed functions should accept +those parameters. Similarly, if the hooks below have return values, the listed +functions should return them. Hooks will be run in the order they appear below. Functions --------- From b729d8e0698e699b8d14e39c70822f93320f3254 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Mon, 16 Jan 2012 19:29:39 -0800 Subject: [PATCH 27/58] Wording changes, grammar in 'docs/hooks' --- docs/content/docs/hooks.mkd | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index 29434d7..f21f200 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -41,17 +41,17 @@ the names of the functions and (but do not invoke them.) For example: } If the hooks below have parameters, the listed functions should accept -those parameters. Similarly, if the hooks below have return values, the listed -functions should return them. Hooks will be run in the order they appear below. +those parameters. Hooks will be run in the order they appear below. -Functions ---------- -The available hooks, the arguments they will get, and when they run are +Available hooks +--------------- +Below are the available hooks, when they will be run, and the arguments they +will pass to the hooked functions (if any.) `site.start()` -: Called before anything else has started, except the loading of hooks. +: Called before anything else has started, except for the loading of hooks. This would be a good time to modify the content, templates, or the files in the media directory. @@ -59,8 +59,8 @@ The available hooks, the arguments they will get, and when they run are : `output_path` : The path to the output directory. : This path will run before the output directory is populated by the media, - and after the old site has been deleted. You can add files that may be - overwritten by the media files, or the site content. + and after any existing output files have been deleted. You can add files + that may be overwritten by the media files or the site content. `site.output.post(output_path)` : `output_path` @@ -68,7 +68,7 @@ The available hooks, the arguments they will get, and when they run are : This hook will run after the output directory is populated by the media, and before the content pages have started to be processed. You can use this to modify, overwrite, or otherwise fiddle with the media directory after it - has been copied to the output dir. + has been copied to the output directory. `site.content.gather.pre()` : Return value @@ -86,16 +86,16 @@ The available hooks, the arguments they will get, and when they run are : This hook will run after wok gathers content pages, and can be used to add pages that don't exist on disk, or to remove pages added by other means. If you modify the list of pages received, those changes will take affect in - wok, and you can also return pages to add. + wok. You may also return pages to add. `page.template.pre(page, templ_vars)` : `page` : The current page object that is being processed. : `templ_vars` - : A dictionart of the variables that will be sent to the template engine. - See the documentation on [templates][] for it's normal contents. + : A dictionary of the variables that will be sent to the template engine. + See the documentation on [templates][] for its normal contents. : This hook will be called for each page before the page is sent to - the template engine. At this point the content has been transformed + the template engine. At this point, the content has been transformed from markup input (such as markdown) to html output, if applicable. The transformed version is in `templ_Vars['content']`. If you modify the `templ_vars` parameter, those changes will be visible to From bb903e5b5429ea06feb0de6fef89634c0ed01cbf Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Mon, 16 Jan 2012 22:22:12 -0800 Subject: [PATCH 28/58] Fixing capitalization, grammar. --- docs/content/docs/hooks.mkd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index f21f200..e7f5bb8 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -85,7 +85,7 @@ will pass to the hooked functions (if any.) : List of `Page` objects to add to the list of pages. : This hook will run after wok gathers content pages, and can be used to add pages that don't exist on disk, or to remove pages added by other means. If - you modify the list of pages received, those changes will take affect in + you modify the list of pages received, those changes will take effect in wok. You may also return pages to add. `page.template.pre(page, templ_vars)` @@ -97,7 +97,7 @@ will pass to the hooked functions (if any.) : This hook will be called for each page before the page is sent to the template engine. At this point, the content has been transformed from markup input (such as markdown) to html output, if applicable. - The transformed version is in `templ_Vars['content']`. If you + The transformed version is in `templ_vars['content']`. If you modify the `templ_vars` parameter, those changes will be visible to the template engine. The given functions should take in these two variables. From df7cd55dfc307c2d4ef6b73fc10f715ed9cba833 Mon Sep 17 00:00:00 2001 From: Rob McGuire-Dale Date: Mon, 16 Jan 2012 22:23:44 -0800 Subject: [PATCH 29/58] Making example tree of type plain text in hooks docs. --- docs/content/docs/hooks.mkd | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index e7f5bb8..1619a96 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -7,6 +7,7 @@ the site generation pipeline. To use hooks, make a new directory in your site root named `hooks`. In this directory, make the file `__hooks__.py`. For example: + ::text site-root/ |-- config |-- content/ From af1e175e7fbdc54ef2eed7cf98c422058be3605e Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 17 Jan 2012 09:11:32 -0800 Subject: [PATCH 30/58] Talk more about URL configs in the docs. --- docs/content/docs/urls.mkd | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/docs/content/docs/urls.mkd b/docs/content/docs/urls.mkd index 6b82805..ca1b940 100644 --- a/docs/content/docs/urls.mkd +++ b/docs/content/docs/urls.mkd @@ -24,12 +24,22 @@ arrange to your liking: If you don't include `{page}` in your `url_pattern`, then pagination won't work. Instead it will overwrite each page with it's sequel, resulting in only -the last page remaining. +the last page remaining. If you aren't using any pagination, then you don't +need the variable. Any time two or more forward slashes are generated, they will be replaced by a -single forward slash. If you set the option `url_include_index` to `false`, -then any time the url ends with `index.*`, that will also be removed from the -url patterns. The files will still be named `index.*`, however. +single forward slash. This lets you do things like +`/{category}/{page}/{slug}.html` without worrying about an empty page or empty +category causing bad paths. + +If you set the option `url_include_index` to `false` in the config file, then +any time the url ends with `index.*`, that will also be removed from the url +patterns. The files will still be named `index.*`, however. So for example if +your url pattern is `/{category}/{slug}/index.html`, the a blog post about +balloons would create a file named `/blog/balloons/index.html`, but anytime you +reference it in a template it's `url` field will be `/blog/balloons/`. This +makes URLs look a lot cleaner. This option off set to `true` by default (ie: +keep index in urls). ### Examples: From 93c9bd435aa7317800cf946f0ca88a3d8bf9eff0 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 17 Jan 2012 09:24:27 -0800 Subject: [PATCH 31/58] PEP8 --- wok/engine.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/wok/engine.py b/wok/engine.py index 3ec7b4f..b926377 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -14,6 +14,7 @@ from wok import util from wok import devserver + class Engine(object): """ The main engine of wok. Upon initialization, it generates a site from the @@ -29,7 +30,7 @@ class Engine(object): 'url_include_index': True, } - def __init__(self, output_lvl = 1): + def __init__(self, output_lvl=1): """ Set up CLI options, logging levels, and start everything off. Afterwards, run a dev server if asked to. @@ -113,7 +114,6 @@ def __init__(self, output_lvl = 1): devserver.run(cli_options.address, cli_options.port, serv_dir=os.path.join(self.options['output_dir'])) - def read_options(self): """Load options from the config file.""" self.options = Engine.default_options.copy() @@ -130,7 +130,8 @@ def read_options(self): if isinstance(authors, list): self.options['authors'] = [Author.parse(a) for a in authors] elif isinstance(authors, str): - self.options['authors'] = [Author.parse(a) for a in authors.split(',')] + csv = authors.split(',') + self.options['authors'] = [Author.parse(a) for a in csv] if len(self.options['authors']) > 1: logging.warn('Deprecation Warning: Use YAML lists instead of ' 'CSV for multiple authors. i.e. ["John Doe", "Jane ' @@ -193,7 +194,7 @@ def prepare_output(self): if os.path.isdir(path): shutil.copytree( path, - os.path.join(self.options['output_dir'], name), + os.path.join(self.options['output_dir'], name), symlinks=True ) else: @@ -269,7 +270,7 @@ def make_tree(self): for cat in p.meta['category']: # This line will fail if the page is an orphan parent = [subpage for subpage in siblings - if subpage['slug']== cat][0] + if subpage['slug'] == cat][0] siblings = parent['subpages'] siblings.append(p.meta) except IndexError: @@ -284,7 +285,12 @@ def render_site(self): tag_set = tag_set.union(p.meta['tags']) tag_dict = dict() for tag in tag_set: - tag_dict[tag] = [p.meta for p in self.all_pages if tag in p.meta['tags']] + # Add all pages with the current tag to the tag dict + tag_dict[tag] = [p.meta for p in self.all_pages + if tag in p.meta['tags']] + + # Gather slugs + slug_dict = dict((p.meta['slug'], p.meta) for p in self.all_pages) for p in self.all_pages: # Construct this every time, to avoid sharing one instance @@ -296,7 +302,7 @@ def render_site(self): 'tags': tag_dict, 'pages': self.all_pages[:], 'categories': self.categories, - 'slugs': dict((p.meta['slug'], p.meta) for p in self.all_pages), + 'slugs': slug_dict, }, } From ed73c15a98f2ef0e9611dcc0c8c40a74286281bd Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 17 Jan 2012 09:51:48 -0800 Subject: [PATCH 32/58] Make the hooks run like the docs say they should. - 'site.done' instead of 'site.stop'. - 'site.content.gather.post' provides the pages variable. Fixes #58. --- wok/engine.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wok/engine.py b/wok/engine.py index b926377..8b61036 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -105,7 +105,7 @@ def __init__(self, output_lvl=1): self.make_tree() self.render_site() - self.run_hook('site.stop') + self.run_hook('site.done') # Dev server # ---------- @@ -240,7 +240,7 @@ def load_pages(self): self.all_pages.append(p) # Load pages from hooks (post) - for pages in self.run_hook('site.content.gather.post'): + for pages in self.run_hook('site.content.gather.post', self.all_pages): if pages: self.all_pages.extend(pages) From 6c26ae119ef7d5f9fac0f66726a31266caa35f38 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 17 Jan 2012 18:56:49 -0800 Subject: [PATCH 33/58] Add anti-PIPA message. --- docs/templates/base.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/templates/base.html b/docs/templates/base.html index 5fa47fa..0e69563 100644 --- a/docs/templates/base.html +++ b/docs/templates/base.html @@ -42,7 +42,11 @@

    wok

    {{ site.slugs.footer.content|safe }}

    Last generated: {{ site.datetime.strftime('%c') }}.

    -
    + + + + + From 28d45b64ce7eac8da4bb03776cb1a6e790f17376 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 18 Jan 2012 14:41:56 -0800 Subject: [PATCH 34/58] Hook to do heading permalinks automatically. --- wok/contrib/__init__.py | 0 wok/contrib/hooks.py | 51 +++++++++++++++++++++++++++++++++++++++++ wok/exceptions.py | 2 ++ 3 files changed, 53 insertions(+) create mode 100644 wok/contrib/__init__.py create mode 100644 wok/contrib/hooks.py create mode 100644 wok/exceptions.py diff --git a/wok/contrib/__init__.py b/wok/contrib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wok/contrib/hooks.py b/wok/contrib/hooks.py new file mode 100644 index 0000000..326a494 --- /dev/null +++ b/wok/contrib/hooks.py @@ -0,0 +1,51 @@ +# vim: set fileencoding=utf8 : +"""Some hooks that might be useful.""" + +from StringIO import StringIO +import logging + +from wok.exceptions import DependencyException +from wok.util import slugify + +try: + from lxml import etree +except ImportError: + etree = None + + +class HeadingAnchors(object): + """ + Put some paragraph heading anchors. + + Serves as a 'page.template.post' wok hook. + """ + + def __init__(self, max_heading=3): + if not etree: + raise DependencyException('To use the HeadingAnchors hook, you must ' + 'install the library lxml.') + self.max_heading = max_heading + logging.debug('Loaded hook HeadingAnchors') + + def __call__(self, page): + logging.debug('Called hook HeadingAnchors on {0}'.format(page)) + parser = etree.HTMLParser() + sio_source = StringIO(page.rendered) + tree = etree.parse(sio_source, parser) + + for lvl in range(1, self.max_heading+1): + headings = tree.iterfind('//h{0}'.format(lvl)) + for heading in headings: + if not heading.text: + continue + logging.debug('[HeadingAnchors] {0} {1}'.format(heading, heading.text)) + anchor = etree.Element('a') + anchor.set('class', 'heading_anchor') + anchor.set('href', '#heading-{0}'.format(slugify(heading.text))) + anchor.set('name', 'heading-{0}'.format(slugify(heading.text))) + anchor.text = u'¶' + heading.append(anchor) + + sio_destination = StringIO() + tree.write(sio_destination) + page.rendered = sio_destination.getvalue() diff --git a/wok/exceptions.py b/wok/exceptions.py new file mode 100644 index 0000000..d13c136 --- /dev/null +++ b/wok/exceptions.py @@ -0,0 +1,2 @@ +class DependencyException(Exception): + pass From 31d42e08aa0e58be4fc9abf379f9a00b0a6de338 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 18 Jan 2012 14:42:18 -0800 Subject: [PATCH 35/58] Use the heading permalink hook. --- docs/hooks/__hooks__.py | 5 +++++ docs/hooks/__init__.py | 0 docs/media/css/base.css | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 docs/hooks/__hooks__.py create mode 100644 docs/hooks/__init__.py diff --git a/docs/hooks/__hooks__.py b/docs/hooks/__hooks__.py new file mode 100644 index 0000000..db104e9 --- /dev/null +++ b/docs/hooks/__hooks__.py @@ -0,0 +1,5 @@ +from wok.contrib.hooks import HeadingAnchors + +hooks = { + 'page.template.post': [ HeadingAnchors() ], +} diff --git a/docs/hooks/__init__.py b/docs/hooks/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/docs/media/css/base.css b/docs/media/css/base.css index 88f3610..1149155 100644 --- a/docs/media/css/base.css +++ b/docs/media/css/base.css @@ -75,6 +75,26 @@ a:hover { color: #322; margin: 5px 0 10px; } +h1 a.heading_anchor, h2 a.heading_anchor, h3 a.heading_anchor +h4 a.heading_anchor, h5 a.heading_anchor, h6 a.heading_anchor { + display: none; + color: #A60000; +} +h1:hover a.heading_anchor, h2:hover a.heading_anchor, +h3:hover a.heading_anchor, h4:hover a.heading_anchor, +h5:hover a.heading_anchor, h6:hover a.heading_anchor { + padding: 2px; + border: 3px; + display: inline; + font-weight: normal; +} +h1 a.heading_anchor:hover, h2 a.heading_anchor:hover, +h3 a.heading_anchor:hover, h4 a.heading_anchor:hover, +h5 a.heading_anchor:hover, h6 a.heading_anchor:hover { + color: #FFF; + background-color: #A60000; +} + p { margin: 0 0 20px 0; } From 86d6e5a8ba4adb305ebfa6f8c8f99df4e29625b1 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 19 Jan 2012 02:44:11 -0800 Subject: [PATCH 36/58] Add default values to date/times. --- sample/content/tests/dates.mkd | 1 + sample/content/tests/dates1.mkd | 1 + sample/content/tests/dates2.mkd | 1 + sample/content/tests/dates3.mkd | 1 + wok/page.py | 1 + wok/util.py | 7 +++++++ 6 files changed, 12 insertions(+) diff --git a/sample/content/tests/dates.mkd b/sample/content/tests/dates.mkd index b64dc20..f55458b 100644 --- a/sample/content/tests/dates.mkd +++ b/sample/content/tests/dates.mkd @@ -1,4 +1,5 @@ title: Dates type: index category: tests +url: "/{category}/{slug}{page}/{date.year}/{date.month}/{date.day}/index.{ext}" --- diff --git a/sample/content/tests/dates1.mkd b/sample/content/tests/dates1.mkd index f82a035..1946b6e 100644 --- a/sample/content/tests/dates1.mkd +++ b/sample/content/tests/dates1.mkd @@ -1,5 +1,6 @@ title: Datetime only datetime: 2011-10-12 12:20:00 category: tests/dates +url: "/{category}/{slug}{page}/{date.year}/{date.month}/{date.day}/index.{ext}" --- This only has a datetime diff --git a/sample/content/tests/dates2.mkd b/sample/content/tests/dates2.mkd index 526061b..61fdb91 100644 --- a/sample/content/tests/dates2.mkd +++ b/sample/content/tests/dates2.mkd @@ -2,5 +2,6 @@ title: Date and time date: 2011-10-12 time: 12:20:00 category: tests/dates +url: "/{category}/{slug}{page}/{date.year}/{date.month}/{date.day}/index.{ext}" --- This a date and time diff --git a/sample/content/tests/dates3.mkd b/sample/content/tests/dates3.mkd index 9d47710..2814292 100644 --- a/sample/content/tests/dates3.mkd +++ b/sample/content/tests/dates3.mkd @@ -2,5 +2,6 @@ title: Time overwriding datetime. datetime: 2011-10-12 12:20:00 time: 15:00:00 category: tests/dates +url: "/{category}/{slug}{page}/{date.year}/{date.month}/{date.day}/index.{ext}" --- In this a datetime is overwritten by at time. diff --git a/wok/page.py b/wok/page.py index ee34cc4..bcc7a5a 100644 --- a/wok/page.py +++ b/wok/page.py @@ -258,6 +258,7 @@ def build_meta(self): 'slug': self.meta['slug'], 'category': '/'.join(self.meta['category']), 'page': self.meta['pagination']['cur_page'], + 'date': self.meta['date'], } logging.debug('current page: ' + repr(parts['page'])) diff --git a/wok/util.py b/wok/util.py index 5367e40..39ead13 100644 --- a/wok/util.py +++ b/wok/util.py @@ -61,3 +61,10 @@ def date_and_times(meta): meta['datetime'] = datetime(date_part.year, date_part.month, date_part.day) else: meta['datetime'] = None + + if meta['date'] is None: + meta['date'] = date(1970, 1, 1) + if meta['time'] is None: + meta['time'] = time() + if meta['datetime'] is None: + meta['datetime'] = datetime(1970, 1, 1) From 860ba36bf590064eabb797a52d4c7f81a5dfa933 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 19 Jan 2012 02:52:23 -0800 Subject: [PATCH 37/58] Add datetime url parameters. --- wok/page.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wok/page.py b/wok/page.py index bcc7a5a..e2c51fd 100644 --- a/wok/page.py +++ b/wok/page.py @@ -259,6 +259,8 @@ def build_meta(self): 'category': '/'.join(self.meta['category']), 'page': self.meta['pagination']['cur_page'], 'date': self.meta['date'], + 'datetime': self.meta['datetime'], + 'time': self.meta['time'], } logging.debug('current page: ' + repr(parts['page'])) From 7d9f389e0093940b95c968d65a37cc791cf68f21 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 19 Jan 2012 02:55:56 -0800 Subject: [PATCH 38/58] Document and test date/times in urls. --- docs/content/docs/urls.mkd | 4 ++++ sample/content/tests/dates1.mkd | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/content/docs/urls.mkd b/docs/content/docs/urls.mkd index ca1b940..aacf558 100644 --- a/docs/content/docs/urls.mkd +++ b/docs/content/docs/urls.mkd @@ -21,6 +21,10 @@ arrange to your liking: page, this will always be an empty string. - `{ext}` - The file extension of the template that was used to generate this file. +- `{date}`, `{datetime}`, `{time}` - The date/time that were specified in the + metadata of a page. These are Python date, datetime, and time objects, so + they have year, month, day, hour, minute, etc fields. If you don't specify a + date in the file, the default is midnight on January 1st, 1970. If you don't include `{page}` in your `url_pattern`, then pagination won't work. Instead it will overwrite each page with it's sequel, resulting in only diff --git a/sample/content/tests/dates1.mkd b/sample/content/tests/dates1.mkd index 1946b6e..fc5743a 100644 --- a/sample/content/tests/dates1.mkd +++ b/sample/content/tests/dates1.mkd @@ -1,6 +1,6 @@ title: Datetime only datetime: 2011-10-12 12:20:00 category: tests/dates -url: "/{category}/{slug}{page}/{date.year}/{date.month}/{date.day}/index.{ext}" +url: "/{category}/{slug}{page}/{date.year}-{date.month}-{date.day}-{time.hour}-{datetime.minute}/index.{ext}" --- This only has a datetime From 2b7342a5846da64b03add66e9503cd5b27d3284d Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 19 Jan 2012 10:11:39 -0800 Subject: [PATCH 39/58] Add more hooks: page.render.pre/post and page.meta.pre/post. --- wok/page.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/wok/page.py b/wok/page.py index e2c51fd..efa4d0f 100644 --- a/wok/page.py +++ b/wok/page.py @@ -104,7 +104,10 @@ def from_file(cls, path, options, engine, renderer=None): logging.debug('Got preview') page.build_meta() + + page.engine.run_hook('page.render.pre', page) page.meta['content'] = page.renderer.render(page.original) + page.engine.run_hook('page.render.post', page) return page @@ -126,6 +129,8 @@ def build_meta(self): `page.subpages` - Will be a list containing every sub page of this page """ + self.engine.run_hook('page.meta.pre', self) + if not self.meta: self.meta = {} @@ -291,6 +296,8 @@ def build_meta(self): # subpages self.meta['subpages'] = [] + self.engine.run_hook('page.meta.post', self) + def render(self, templ_vars=None): """ Renders the page with the template engine. From ad32eb22818016d1967778c90820e57d5e8d71bd Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 19 Jan 2012 10:11:49 -0800 Subject: [PATCH 40/58] Document and test the new hooks. --- docs/content/docs/hooks.mkd | 73 +++++++++++++++++++++++++++++++------ sample/hooks/__hooks__.py | 4 ++ 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/docs/content/docs/hooks.mkd b/docs/content/docs/hooks.mkd index 1619a96..d7006b1 100644 --- a/docs/content/docs/hooks.mkd +++ b/docs/content/docs/hooks.mkd @@ -49,21 +49,38 @@ Available hooks Below are the available hooks, when they will be run, and the arguments they will pass to the hooked functions (if any.) - - -`site.start()` -: Called before anything else has started, except for the loading of hooks. +###List of hooks + +- [site.start](#site.start) +- [site.output.pre](#site.output.pre) +- [site.output.post](#site.output.post) +- [site.content.gather.pre](#site.content.gather.pre) +- [site.content.gather.post](#site.content.gather.post) +- [page.render.pre](#page.render.pre) +- [page.render.post](#page.render.post) +- [page.meta.pre](#page.meta.pre) +- [page.meta.post](#page.meta.post) +- [page.template.pre](#page.template.pre) +- [page.template.post](#page.template.post) +- [site.done](#site.done) + +### Details + + + +`site.start()` +:

    Called before anything else has started, except for the loading of hooks. This would be a good time to modify the content, templates, or the files in - the media directory. + the media directory.

    -`site.output.pre(output_path)` +`site.output.pre(output_path)` : `output_path` : The path to the output directory. : This path will run before the output directory is populated by the media, and after any existing output files have been deleted. You can add files that may be overwritten by the media files or the site content. -`site.output.post(output_path)` +`site.output.post(output_path)` : `output_path` : The path to the output directory. : This hook will run after the output directory is populated by the media, @@ -71,13 +88,13 @@ will pass to the hooked functions (if any.) to modify, overwrite, or otherwise fiddle with the media directory after it has been copied to the output directory. -`site.content.gather.pre()` +`site.content.gather.pre()` : Return value : List of `Page` objects to add to the list of pages. : This hook will run before wok gathers content pages, and can be used to add pages that don't exist on disk. -`site.content.gather.post(pages)` +`site.content.gather.post(pages)` : `pages` : The list of pages that wok has gathered from the content directory, and any other hooks that have run. Also includes the duplicated versions of @@ -89,7 +106,39 @@ will pass to the hooked functions (if any.) you modify the list of pages received, those changes will take effect in wok. You may also return pages to add. -`page.template.pre(page, templ_vars)` +`page.render.pre(page)` +: `page` + : The current page object that is being processed. +: This hook will be called for each page before the page is rendered by + Markdown, reStructuredText, etc. The unrendered text will be in the + variable `page.original`, if there is an original text. Keep in mind that + some pages won't be run through this hook because they come from other + sources, such as hooks, or pagination. + +`page.render.post(page)` +: `page` + : The current page object that is being processed. +: This hook will be called for each page right after the page is rendered by + Markdown, reStructuredText, etc. The unrendered text will be in the + variable `page.original`, and the rendered text will be in the meta + variable `page.meta['content']. Keep in mind that some pages won't be run + through this hook because they come from other sources, such as hooks, or + pagination. + +`page.meta.pre(page)` +: `page` + : The current page object that is being processed. +: This hook will be called for each page before the page has it's meta data + filled in. Some metadata will exist, but it will be in an unnormalized + state. + +`page.meta.post(page)` +: `page` + : The current page object that is being processed. +: This hook will be called for each page right after the page has it's meta + data filled in and normalized. + +`page.template.pre(page, templ_vars)` : `page` : The current page object that is being processed. : `templ_vars` @@ -105,14 +154,14 @@ will pass to the hooked functions (if any.) [templates]: /docs/templates/ -`page.template.post(page)` +`page.template.post(page)` : `page` : The current page being processed. : This hook will be called after the page has been processed by the template engine. The next step will be write the file to disk, if applicable, so any last minute changes should happen here. -`site.done()` +`site.done()` : Called after wok has finished everything. This would be a good time to make any general modifications to the output, or to do something like upload the site for distribution. If the `--server` option has been specified, this diff --git a/sample/hooks/__hooks__.py b/sample/hooks/__hooks__.py index a8a4252..7ee370b 100644 --- a/sample/hooks/__hooks__.py +++ b/sample/hooks/__hooks__.py @@ -14,6 +14,10 @@ def logging_hook(*args): 'site.output.post': make_hook('site.output.post'), 'site.content.gather.pre': make_hook('site.content.gather.pre'), 'site.content.gather.post': make_hook('site.content.gather.post'), + 'page.meta.pre': make_hook('page.template.pre'), + 'page.meta.post': make_hook('page.template.post'), + 'page.render.pre': make_hook('page.template.pre'), + 'page.render.post': make_hook('page.template.post'), 'page.template.pre': make_hook('page.template.pre'), 'page.template.post': make_hook('page.template.post'), 'site.stop': make_hook('site.stop'), From c695e0962829c3a757ff5c6d4edf2f912b23493a Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Fri, 20 Jan 2012 02:49:22 +0000 Subject: [PATCH 41/58] Add a version info to the doc site. --- docs/media/css/base.css | 10 +++++++++- docs/templates/base.html | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/media/css/base.css b/docs/media/css/base.css index 1149155..b9ec3e2 100644 --- a/docs/media/css/base.css +++ b/docs/media/css/base.css @@ -50,9 +50,9 @@ header nav a:hover { header nav a.active { border-top: 1px solid #A60000; } - /* Body */ #content { + position: relative; padding: 10px; color: #4E3434; line-height: 1.5; @@ -60,6 +60,14 @@ header nav a.active { font-family: serif; } +#content span.version_note { + position: absolute; + right: 0px; + top: 5px; + font-size: 10px; +} + + a { color: #BF3030; font-weight: bold; diff --git a/docs/templates/base.html b/docs/templates/base.html index 0e69563..03a8e70 100644 --- a/docs/templates/base.html +++ b/docs/templates/base.html @@ -35,6 +35,13 @@

    wok

    + + This is the 0.8 version of the docs. You could also see the + + dev version of this page. + + + {%- block content %} {%- endblock %}
    From bc9af73375c3376302f69c5c5eb7a14407980a01 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Fri, 20 Jan 2012 02:52:24 +0000 Subject: [PATCH 42/58] Update the version info to show that this is the dev page. --- docs/templates/base.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/templates/base.html b/docs/templates/base.html index 03a8e70..d826b62 100644 --- a/docs/templates/base.html +++ b/docs/templates/base.html @@ -36,9 +36,9 @@

    wok

    - This is the 0.8 version of the docs. You could also see the - - dev version of this page. + This is the dev version of the docs. You could also see the + + latest stable version of this page. From a7a13792dcdc9245cf29fdf6b5a6f2b0f68bf6b4 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Thu, 26 Jan 2012 08:02:06 -0800 Subject: [PATCH 43/58] Remove leading or trailing slashes in slugs. --- wok/util.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/wok/util.py b/wok/util.py index 39ead13..be1aa8c 100644 --- a/wok/util.py +++ b/wok/util.py @@ -14,7 +14,14 @@ def slugify(text, delim=u'-'): word = normalize('NFKD', unicode(word)).encode('ascii', 'ignore') if word: result.append(word) - return unicode(delim.join(result)) + + result = delim.join(result) + if result[0] == '-': + result = result[1:] + if result[-1] == '-': + result = result[:-1] + + return unicode(result) def chunk(li, n): From 559e67bea106dbfef1f767ba4a57003802cbed23 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 22 Jan 2012 10:21:48 -0800 Subject: [PATCH 44/58] Fix a bug introduced in ec613fd95c that causes pagination to not work. Apparentl ec613f broke a lot. Thats what I get for excepting all exceptions silently :\. --- docs/content/docs.mkd | 8 ++++---- wok/engine.py | 5 ++++- wok/page.py | 33 +++++++++++++++++++++++---------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/docs/content/docs.mkd b/docs/content/docs.mkd index ecee0bf..34bc2cb 100644 --- a/docs/content/docs.mkd +++ b/docs/content/docs.mkd @@ -10,19 +10,19 @@ If you just want to use wok, then you should install it from the [Python Package Index][pypi]. A good way to do that is with `pip`: ::console - sudo pip install wok + $ sudo pip install wok This will install wok and the required dependencies. You should also install at least one of [Markdown][mkd], or [reStructuredText][rst], for content markup: ::console - sudo pip install Markdown - sudo pip install docutils + $ sudo pip install Markdown + $ sudo pip install docutils If you want syntax highlighting, you will also need [Pygments][pgmnts]. ::console - sudo pip install Pygments + $ sudo pip install Pygments [mkd]: http://daringfireball.net/projects/markdown/ [rst]: http://docutils.sourceforge.net/rst.html diff --git a/wok/engine.py b/wok/engine.py index 8b61036..d8db08f 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -257,7 +257,9 @@ def make_tree(self): # We want to parse these in a approximately breadth first order self.all_pages.sort(key=lambda p: len(p.meta['category'])) - for p in [p for p in self.all_pages]: + # For every page + for p in self.all_pages: + # If it has a category (ie: is not at top level) if len(p.meta['category']) > 0: top_cat = p.meta['category'][0] if not top_cat in self.categories: @@ -266,6 +268,7 @@ def make_tree(self): self.categories[top_cat].append(p.meta) try: + # Put this page's meta in the right place in site_tree. siblings = site_tree for cat in p.meta['category']: # This line will fail if the page is an orphan diff --git a/wok/page.py b/wok/page.py index efa4d0f..9400ab2 100644 --- a/wok/page.py +++ b/wok/page.py @@ -48,11 +48,8 @@ def from_meta(cls, meta, options, engine, renderer=None): Page.tmpl_env = jinja2.Environment(loader=GlobFileLoader( page.options.get('template_dir', 'templates'))) - try: - page.build_meta() - return page - except: - return None + page.build_meta() + return page @classmethod def from_file(cls, path, options, engine, renderer=None): @@ -191,7 +188,8 @@ def build_meta(self): # wait, what? Authors is of wrong type. self.meta['authors'] = [] logging.error(('Authors in {0} is an unknown type. Valid types ' - 'are string or list.').format(self.meta['slug'])) + 'are string or list. Instead it is a {1}') + .format(self.meta['slug']), authors.type) if self.meta['authors']: self.meta['author'] = self.meta['authors'] @@ -200,7 +198,16 @@ def build_meta(self): # category if 'category' in self.meta: - self.meta['category'] = self.meta['category'].split('/') + if isinstance(self.meta['category'], str): + self.meta['category'] = self.meta['category'].split('/') + elif isinstance(self.meta['category'], list): + pass + else: + # category is of wrong type. + logging.error('Category in {0} is an unknown type. Valid ' + 'types are string or list. Instead it is a {1}' + .format(self.meta['slug'], type(self.meta['category']))) + self.meta['category'] = [] else: self.meta['category'] = [] if self.meta['category'] == None: @@ -302,6 +309,7 @@ def render(self, templ_vars=None): """ Renders the page with the template engine. """ + logging.debug('Rendering ' + self.meta['slug']) if not templ_vars: templ_vars = {} @@ -335,7 +343,9 @@ def render(self, templ_vars=None): def paginate(self): extra_pages = [] + logging.debug('called pagination for {0}'.format(self.meta['slug'])) if 'page_items' not in self.meta['pagination']: + logging.debug('doing pagination for {0}'.format(self.meta['slug'])) # This is the first page of a set of pages. Set up the rest. Other # wise don't do anything. @@ -353,7 +363,6 @@ def paginate(self): return for k in source_spec: - logging.debug(k) source = source[k] sort_key = self.meta['pagination'].get('sort_key', None) @@ -386,11 +395,12 @@ def paginate(self): 'pagination': { 'page_items': chunk, 'num_pages': len(chunks), - 'cur_page': idx+1, + 'cur_page': idx, } }) new_page = Page.from_meta(new_meta, self.options, self.engine, renderer=self.renderer) + logging.debug('page {0} is {1}'.format(idx, new_page)) if new_page: extra_pages.append(new_page) @@ -401,7 +411,7 @@ def paginate(self): else: page.meta['pagination']['prev_page'] = extra_pages[idx-1].meta - if idx < len(extra_pages): + if idx < len(extra_pages) - 1: page.meta['pagination']['next_page'] = extra_pages[idx+1].meta else: page.meta['pagination']['next_page'] = None @@ -455,6 +465,9 @@ def __init__(self, raw='', name=None, email=None): @classmethod def parse(cls, raw): + if isinstance(raw, cls): + return raw + a = cls(raw) a.name, _, a.email = cls.parse_author_regex.match(raw).groups() if a.name: From 7e4d62488e6e29db806d9003da3e4a89feefac6e Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Tue, 31 Jan 2012 08:56:25 -0800 Subject: [PATCH 45/58] Tweak pagination. --- wok/page.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/wok/page.py b/wok/page.py index 9400ab2..e51104c 100644 --- a/wok/page.py +++ b/wok/page.py @@ -4,6 +4,7 @@ from collections import namedtuple from datetime import datetime, date, time import logging +import copy # Libraries import jinja2 @@ -286,19 +287,19 @@ def build_meta(self): parts['type'] = parts['ext'] self.meta['ext'] = parts['ext'] - if parts['page'] == 1: - parts['page'] = '' + #if parts['page'] == 1: + # parts['page'] = '' if not 'url' in self.meta: - self.meta['url'] = self.options['url_pattern'].format(**parts); - else: - self.meta['url'] = self.meta['url'].format(**parts); + self.meta['url'] = self.options['url_pattern'] + + self.meta['url'] = self.meta['url'].format(**parts) # Get rid of extra slashes self.meta['url'] = re.sub(r'//+', '/', self.meta['url']) - logging.debug(self.meta['url']) # If we have been asked to, rip out any plain "index.html"s if not self.options['url_include_index']: self.meta['url'] = re.sub(r'/index\.html$', '/', self.meta['url']) + logging.debug('url is: ' + self.meta['url']) # subpages self.meta['subpages'] = [] @@ -390,7 +391,7 @@ def paginate(self): # Make a page for each chunk for idx, chunk in enumerate(chunks[1:], 2): - new_meta = self.meta.copy() + new_meta = copy.deepcopy(self.meta) new_meta.update({ 'pagination': { 'page_items': chunk, From c29d335c4799baac055c7b6594d0f8ff89c28efa Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 1 Feb 2012 09:03:36 -0800 Subject: [PATCH 46/58] Call the test site what it really is, not "sample". --- {sample => test_site}/config | 0 {sample => test_site}/content/pagination-bits/a.mkd | 0 {sample => test_site}/content/pagination-bits/b.mkd | 0 {sample => test_site}/content/pagination-bits/c.mkd | 0 {sample => test_site}/content/pagination-bits/d.mkd | 0 {sample => test_site}/content/pagination-bits/e.mkd | 0 {sample => test_site}/content/pagination-bits/f.mkd | 0 {sample => test_site}/content/pagination-bits/g.mkd | 0 {sample => test_site}/content/pagination-bits/h.mkd | 0 {sample => test_site}/content/pagination-bits/i.mkd | 0 {sample => test_site}/content/pagination-bits/j.mkd | 0 {sample => test_site}/content/pagination-bits/k.mkd | 0 {sample => test_site}/content/pagination-test.mkd | 0 {sample => test_site}/content/tests.mkd | 0 {sample => test_site}/content/tests/dates.mkd | 0 {sample => test_site}/content/tests/dates1.mkd | 0 {sample => test_site}/content/tests/dates2.mkd | 0 {sample => test_site}/content/tests/dates3.mkd | 0 {sample => test_site}/content/tests/markdown.mkd | 0 {sample => test_site}/content/tests/plain.txt | 0 {sample => test_site}/content/tests/rest_titles.rst | 0 {sample => test_site}/content/tests/restructuredtext.rst | 0 {sample => test_site}/content/tests/unpublished.txt | 0 {sample => test_site}/hooks/__hooks__.py | 0 {sample => test_site}/media/friendly.css | 0 {sample => test_site}/templates/base.html | 0 {sample => test_site}/templates/default.html | 0 {sample => test_site}/templates/index.html | 0 {sample => test_site}/templates/pagination.html | 0 29 files changed, 0 insertions(+), 0 deletions(-) rename {sample => test_site}/config (100%) rename {sample => test_site}/content/pagination-bits/a.mkd (100%) rename {sample => test_site}/content/pagination-bits/b.mkd (100%) rename {sample => test_site}/content/pagination-bits/c.mkd (100%) rename {sample => test_site}/content/pagination-bits/d.mkd (100%) rename {sample => test_site}/content/pagination-bits/e.mkd (100%) rename {sample => test_site}/content/pagination-bits/f.mkd (100%) rename {sample => test_site}/content/pagination-bits/g.mkd (100%) rename {sample => test_site}/content/pagination-bits/h.mkd (100%) rename {sample => test_site}/content/pagination-bits/i.mkd (100%) rename {sample => test_site}/content/pagination-bits/j.mkd (100%) rename {sample => test_site}/content/pagination-bits/k.mkd (100%) rename {sample => test_site}/content/pagination-test.mkd (100%) rename {sample => test_site}/content/tests.mkd (100%) rename {sample => test_site}/content/tests/dates.mkd (100%) rename {sample => test_site}/content/tests/dates1.mkd (100%) rename {sample => test_site}/content/tests/dates2.mkd (100%) rename {sample => test_site}/content/tests/dates3.mkd (100%) rename {sample => test_site}/content/tests/markdown.mkd (100%) rename {sample => test_site}/content/tests/plain.txt (100%) rename {sample => test_site}/content/tests/rest_titles.rst (100%) rename {sample => test_site}/content/tests/restructuredtext.rst (100%) rename {sample => test_site}/content/tests/unpublished.txt (100%) rename {sample => test_site}/hooks/__hooks__.py (100%) rename {sample => test_site}/media/friendly.css (100%) rename {sample => test_site}/templates/base.html (100%) rename {sample => test_site}/templates/default.html (100%) rename {sample => test_site}/templates/index.html (100%) rename {sample => test_site}/templates/pagination.html (100%) diff --git a/sample/config b/test_site/config similarity index 100% rename from sample/config rename to test_site/config diff --git a/sample/content/pagination-bits/a.mkd b/test_site/content/pagination-bits/a.mkd similarity index 100% rename from sample/content/pagination-bits/a.mkd rename to test_site/content/pagination-bits/a.mkd diff --git a/sample/content/pagination-bits/b.mkd b/test_site/content/pagination-bits/b.mkd similarity index 100% rename from sample/content/pagination-bits/b.mkd rename to test_site/content/pagination-bits/b.mkd diff --git a/sample/content/pagination-bits/c.mkd b/test_site/content/pagination-bits/c.mkd similarity index 100% rename from sample/content/pagination-bits/c.mkd rename to test_site/content/pagination-bits/c.mkd diff --git a/sample/content/pagination-bits/d.mkd b/test_site/content/pagination-bits/d.mkd similarity index 100% rename from sample/content/pagination-bits/d.mkd rename to test_site/content/pagination-bits/d.mkd diff --git a/sample/content/pagination-bits/e.mkd b/test_site/content/pagination-bits/e.mkd similarity index 100% rename from sample/content/pagination-bits/e.mkd rename to test_site/content/pagination-bits/e.mkd diff --git a/sample/content/pagination-bits/f.mkd b/test_site/content/pagination-bits/f.mkd similarity index 100% rename from sample/content/pagination-bits/f.mkd rename to test_site/content/pagination-bits/f.mkd diff --git a/sample/content/pagination-bits/g.mkd b/test_site/content/pagination-bits/g.mkd similarity index 100% rename from sample/content/pagination-bits/g.mkd rename to test_site/content/pagination-bits/g.mkd diff --git a/sample/content/pagination-bits/h.mkd b/test_site/content/pagination-bits/h.mkd similarity index 100% rename from sample/content/pagination-bits/h.mkd rename to test_site/content/pagination-bits/h.mkd diff --git a/sample/content/pagination-bits/i.mkd b/test_site/content/pagination-bits/i.mkd similarity index 100% rename from sample/content/pagination-bits/i.mkd rename to test_site/content/pagination-bits/i.mkd diff --git a/sample/content/pagination-bits/j.mkd b/test_site/content/pagination-bits/j.mkd similarity index 100% rename from sample/content/pagination-bits/j.mkd rename to test_site/content/pagination-bits/j.mkd diff --git a/sample/content/pagination-bits/k.mkd b/test_site/content/pagination-bits/k.mkd similarity index 100% rename from sample/content/pagination-bits/k.mkd rename to test_site/content/pagination-bits/k.mkd diff --git a/sample/content/pagination-test.mkd b/test_site/content/pagination-test.mkd similarity index 100% rename from sample/content/pagination-test.mkd rename to test_site/content/pagination-test.mkd diff --git a/sample/content/tests.mkd b/test_site/content/tests.mkd similarity index 100% rename from sample/content/tests.mkd rename to test_site/content/tests.mkd diff --git a/sample/content/tests/dates.mkd b/test_site/content/tests/dates.mkd similarity index 100% rename from sample/content/tests/dates.mkd rename to test_site/content/tests/dates.mkd diff --git a/sample/content/tests/dates1.mkd b/test_site/content/tests/dates1.mkd similarity index 100% rename from sample/content/tests/dates1.mkd rename to test_site/content/tests/dates1.mkd diff --git a/sample/content/tests/dates2.mkd b/test_site/content/tests/dates2.mkd similarity index 100% rename from sample/content/tests/dates2.mkd rename to test_site/content/tests/dates2.mkd diff --git a/sample/content/tests/dates3.mkd b/test_site/content/tests/dates3.mkd similarity index 100% rename from sample/content/tests/dates3.mkd rename to test_site/content/tests/dates3.mkd diff --git a/sample/content/tests/markdown.mkd b/test_site/content/tests/markdown.mkd similarity index 100% rename from sample/content/tests/markdown.mkd rename to test_site/content/tests/markdown.mkd diff --git a/sample/content/tests/plain.txt b/test_site/content/tests/plain.txt similarity index 100% rename from sample/content/tests/plain.txt rename to test_site/content/tests/plain.txt diff --git a/sample/content/tests/rest_titles.rst b/test_site/content/tests/rest_titles.rst similarity index 100% rename from sample/content/tests/rest_titles.rst rename to test_site/content/tests/rest_titles.rst diff --git a/sample/content/tests/restructuredtext.rst b/test_site/content/tests/restructuredtext.rst similarity index 100% rename from sample/content/tests/restructuredtext.rst rename to test_site/content/tests/restructuredtext.rst diff --git a/sample/content/tests/unpublished.txt b/test_site/content/tests/unpublished.txt similarity index 100% rename from sample/content/tests/unpublished.txt rename to test_site/content/tests/unpublished.txt diff --git a/sample/hooks/__hooks__.py b/test_site/hooks/__hooks__.py similarity index 100% rename from sample/hooks/__hooks__.py rename to test_site/hooks/__hooks__.py diff --git a/sample/media/friendly.css b/test_site/media/friendly.css similarity index 100% rename from sample/media/friendly.css rename to test_site/media/friendly.css diff --git a/sample/templates/base.html b/test_site/templates/base.html similarity index 100% rename from sample/templates/base.html rename to test_site/templates/base.html diff --git a/sample/templates/default.html b/test_site/templates/default.html similarity index 100% rename from sample/templates/default.html rename to test_site/templates/default.html diff --git a/sample/templates/index.html b/test_site/templates/index.html similarity index 100% rename from sample/templates/index.html rename to test_site/templates/index.html diff --git a/sample/templates/pagination.html b/test_site/templates/pagination.html similarity index 100% rename from sample/templates/pagination.html rename to test_site/templates/pagination.html From eb22d12802cbf2397a39c46efbc36f25cebc3551 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 1 Feb 2012 09:14:26 -0800 Subject: [PATCH 47/58] Update tests to not expect None date/times. --- wok/tests/test_util.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/wok/tests/test_util.py b/wok/tests/test_util.py index df349fe..8639996 100644 --- a/wok/tests/test_util.py +++ b/wok/tests/test_util.py @@ -43,7 +43,7 @@ def test_apostrophes(self): slug = u'dont-use-bobs-stuff' self.assertEqual(slug, util.slugify(orig)) - test_apostrophes.todo = "Apostrophes are treated like normal words right now" + test_apostrophes.todo = "Apostrophes are treated like normal words." class TestDatetimes(TestCase): @@ -53,7 +53,7 @@ def setUp(self): The datetime is the first commit of wok. The date is the day this test was first written. - The time is pi second, in GMT-8. + The time is pi second. """ self.datetime = datetime(2011, 2, 3, 0, 23, 0, 0) self.date = date(2011, 10, 12) @@ -61,7 +61,11 @@ def setUp(self): def test_blanks(self): inp = {} - out = {'datetime': None, 'date': None, 'time': None, } + out = { + 'datetime': datetime(1970, 1, 1), + 'date': date(1970, 1, 1), + 'time': time(), + } util.date_and_times(inp) self.assertEquals(inp, out) @@ -71,7 +75,7 @@ def test_just_date(self): out = { 'datetime': datetime(2011, 10, 12, 0, 0, 0, 0), 'date': self.date, - 'time': None, + 'time': time(), } util.date_and_times(inp) @@ -79,7 +83,11 @@ def test_just_date(self): def test_just_time(self): inp = {'time': self.time} - out = {'datetime': None, 'date': None, 'time': self.time, } + out = { + 'datetime': datetime(1970, 1, 1), + 'date': date(1970, 1, 1), + 'time': self.time, + } util.date_and_times(inp) self.assertEquals(inp, out) @@ -148,7 +156,7 @@ def test_types(self): out = { 'datetime': datetime(2011, 12, 25), 'date': date(2011, 12, 25), - 'time': None, + 'time': time(), } util.date_and_times(inp) From 5b6200d4a58da00c12ca04c89553d2728dc35502 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 1 Feb 2012 09:25:23 -0800 Subject: [PATCH 48/58] Provide site.date and site.time as well as site.datetime. Fixes #61. --- test_site/templates/base.html | 2 +- wok/engine.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test_site/templates/base.html b/test_site/templates/base.html index e27a57f..7c06dc4 100644 --- a/test_site/templates/base.html +++ b/test_site/templates/base.html @@ -11,7 +11,7 @@

    Footer Site by: {{site.author}} - Last generated: {{site.datetime}} + Last generated: Datetime: {{site.datetime}}, Date: {{site.date}}, Time: {{site.time}} diff --git a/wok/engine.py b/wok/engine.py index d8db08f..5869cda 100755 --- a/wok/engine.py +++ b/wok/engine.py @@ -302,6 +302,8 @@ def render_site(self): 'site': { 'title': self.options.get('site_title', 'Untitled'), 'datetime': datetime.now(), + 'date': datetime.now().date(), + 'time': datetime.now().time(), 'tags': tag_dict, 'pages': self.all_pages[:], 'categories': self.categories, From 9ab92fd8197e007234f8c811115b4945abed21a8 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Wed, 1 Feb 2012 09:26:11 -0800 Subject: [PATCH 49/58] Fix page 1's urls. --- wok/page.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wok/page.py b/wok/page.py index e51104c..f595cf5 100644 --- a/wok/page.py +++ b/wok/page.py @@ -287,8 +287,8 @@ def build_meta(self): parts['type'] = parts['ext'] self.meta['ext'] = parts['ext'] - #if parts['page'] == 1: - # parts['page'] = '' + if parts['page'] == 1: + parts['page'] = '' if not 'url' in self.meta: self.meta['url'] = self.options['url_pattern'] From 5e79628f73fca0fc3871ec4c547beb52a2921739 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sat, 11 Feb 2012 17:21:46 -0800 Subject: [PATCH 50/58] Save url patterns for use in possible sub pages. Closes #64. --- wok/page.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/wok/page.py b/wok/page.py index f595cf5..ecf0bf8 100644 --- a/wok/page.py +++ b/wok/page.py @@ -290,12 +290,23 @@ def build_meta(self): if parts['page'] == 1: parts['page'] = '' - if not 'url' in self.meta: - self.meta['url'] = self.options['url_pattern'] + if 'url' in self.meta: + logging.debug('Using page url pattern') + self.url_pattern = self.meta['url'] + else: + logging.debug('Using global url pattern') + self.url_pattern = self.options['url_pattern'] + + self.meta['url'] = self.url_pattern.format(**parts) + + logging.info('URL pattern is: {0}'.format(self.url_pattern)) + logging.info('URL parts are: {0}'.format(parts)) - self.meta['url'] = self.meta['url'].format(**parts) # Get rid of extra slashes self.meta['url'] = re.sub(r'//+', '/', self.meta['url']) + logging.debug('{0} will be written to {1}' + .format(self.meta['slug'], self.meta['url'])) + # If we have been asked to, rip out any plain "index.html"s if not self.options['url_include_index']: self.meta['url'] = re.sub(r'/index\.html$', '/', self.meta['url']) @@ -393,6 +404,7 @@ def paginate(self): for idx, chunk in enumerate(chunks[1:], 2): new_meta = copy.deepcopy(self.meta) new_meta.update({ + 'url': self.url_pattern, 'pagination': { 'page_items': chunk, 'num_pages': len(chunks), From 7b7e59befed89ecf4cc1166b0ca2cb21148041d9 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sat, 11 Feb 2012 17:23:37 -0800 Subject: [PATCH 51/58] Fix a bug in prev/next page links that was revealed after #64 was fixed. Also some minor tidying up. --- wok/page.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/wok/page.py b/wok/page.py index ecf0bf8..73deaf5 100644 --- a/wok/page.py +++ b/wok/page.py @@ -31,7 +31,7 @@ def __init__(self, options, engine): self.engine = engine @classmethod - def from_meta(cls, meta, options, engine, renderer=None): + def from_meta(cls, meta, options, engine, renderer=renderers.Plain): """ Build a page object from a meta dictionary. @@ -41,10 +41,14 @@ def from_meta(cls, meta, options, engine, renderer=None): page = cls(options, engine) page.meta = meta page.options = options - page.renderer = renderer if renderer else renderers.Plain + page.renderer = renderer + + if 'pagination' in meta: + logging.debug('from_meta: current page %d' % + meta['pagination']['cur_page']) # Make a template environment. Hopefully no one expects this to ever - # change. + # change after it is instantiated. if Page.tmpl_env is None: Page.tmpl_env = jinja2.Environment(loader=GlobFileLoader( page.options.get('template_dir', 'templates'))) @@ -53,7 +57,7 @@ def from_meta(cls, meta, options, engine, renderer=None): return page @classmethod - def from_file(cls, path, options, engine, renderer=None): + def from_file(cls, path, options, engine, renderer=renderers.Plain): """ Load a file from disk, and parse the metadata from it. @@ -63,7 +67,7 @@ def from_file(cls, path, options, engine, renderer=None): page = cls(options, engine) page.original = None page.options = options - page.renderer = renderer if renderer else renderers.Plain + page.renderer = renderer logging.info('Loading {0}'.format(os.path.basename(path))) @@ -418,8 +422,8 @@ def paginate(self): extra_pages.append(new_page) # Set up the next/previous page links - for idx, page in enumerate(extra_pages, 1): - if idx == 1: + for idx, page in enumerate(extra_pages): + if idx == 0: page.meta['pagination']['prev_page'] = self.meta else: page.meta['pagination']['prev_page'] = extra_pages[idx-1].meta From 828b83aea914ccb38158bc1530f3f72b6eb7d518 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 12 Feb 2012 23:53:09 -0800 Subject: [PATCH 52/58] Make wok.contrib.hooks.HeadingAnchors work right. --- wok/contrib/hooks.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/wok/contrib/hooks.py b/wok/contrib/hooks.py index 326a494..369e12d 100644 --- a/wok/contrib/hooks.py +++ b/wok/contrib/hooks.py @@ -39,13 +39,17 @@ def __call__(self, page): if not heading.text: continue logging.debug('[HeadingAnchors] {0} {1}'.format(heading, heading.text)) + + name = 'heading-{0}'.format(slugify(heading.text)) anchor = etree.Element('a') anchor.set('class', 'heading_anchor') - anchor.set('href', '#heading-{0}'.format(slugify(heading.text))) - anchor.set('name', 'heading-{0}'.format(slugify(heading.text))) + anchor.set('href', '#' + name) + anchor.set('title', 'Permalink to this section.') anchor.text = u'¶' heading.append(anchor) + heading.set('id', name) + sio_destination = StringIO() tree.write(sio_destination) page.rendered = sio_destination.getvalue() From 4abff0a3bf0abf1a0c8a61ea785db74bf30f9544 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 19 Feb 2012 09:18:47 -0800 Subject: [PATCH 53/58] Make page.author a Author, not a list of Authors. Fixes #59. --- wok/page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wok/page.py b/wok/page.py index 73deaf5..a2917e4 100644 --- a/wok/page.py +++ b/wok/page.py @@ -197,7 +197,7 @@ def build_meta(self): .format(self.meta['slug']), authors.type) if self.meta['authors']: - self.meta['author'] = self.meta['authors'] + self.meta['author'] = self.meta['authors'][0] else: self.meta['author'] = Author() From 9bc26f8a0d2c209fc3e73cd0f267164bfd49fef3 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 19 Feb 2012 14:07:06 -0800 Subject: [PATCH 54/58] Update setup.py --- setup.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 11eef1c..da73203 100755 --- a/setup.py +++ b/setup.py @@ -4,13 +4,27 @@ from wok import version -setup(name='wok', - version=version.encode("utf8"), - description='Static site generator', - install_requires=['pyyaml', 'jinja2'], - author='Mike Cooper', - author_email='mythmon@gmail.com', - url='https://www.github.com/mythmon/wok', - packages=['wok'], - scripts=['scripts/wok'], - ) +setup( + name='wok', + version=version.encode("utf8"), + author='Mike Cooper', + author_email='mythmon@gmail.com', + url='http://wok.mythmon.com', + description='Static site generator', + long_description= + "Wok is a static website generator. It turns a pile of templates, " + "content, and resources (like CSS and images) into a neat stack of " + "plain HTML. You run it on your local computer, and it generates a " + "directory of web files that you can upload to your web server, or " + "serve directly." + download_url="http://wok.mythmon.com/download", + classifiers=[ + "Development Status :: 4 - Beta", + "License :: OSI Approved :: MIT License", + 'Operating System :: POSIX', + 'Programming Language :: Python', + ] + requires=['pyyaml', 'jinja2', 'Markdown', 'docutils', 'Pygments'], + packages=['wok'], + scripts=['scripts/wok'], +) From b03ea6d2e90449358e1c5f7b025ffd443b1aeef2 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 19 Feb 2012 14:07:26 -0800 Subject: [PATCH 55/58] Update readme. --- README.mkd | 70 +++++++++++++++++++----------------------------------- 1 file changed, 25 insertions(+), 45 deletions(-) diff --git a/README.mkd b/README.mkd index 7679dd0..c1e86fc 100644 --- a/README.mkd +++ b/README.mkd @@ -21,7 +21,7 @@ mythical website that inspired wok still hasn't been written. Sample Sites ------------ -A bare bones site is included in the wok git repo, in the `sample` directory. +A bare bones site is included in the wok git repo, in the `test` directory. It is really just a playground for devs to test new features, and not a good learning tool. @@ -48,8 +48,10 @@ For some real world examples check out these sites. serving as an example, let me know and I will add a link to your site here. -For some tutorials, the [wok github wiki][wiki] has some good pointers. +For some more documentation, checkout [the doc site][docs]. To learn and share +with other users, you can check out [the wiki][wiki]. +[docs]: http://wok.mythmon.com [wiki]: https://github.com/mythmon/wok/wiki Installation @@ -72,7 +74,9 @@ dependencies by hand in this case. ###Dependencies All dependencies are available from pip. Although optional, you really should -install either markdown or docutils. +install either markdown or docutils, and if you install from pip, they will be +installed for you. Pygments is used for syntax highlighting, and will also be +installed from pip. ####Required @@ -81,17 +85,16 @@ install either markdown or docutils. ####Optional -- `markdown` - for rendering markdown documents. +- `Markdown` - for rendering markdown documents. - `docutils` - for rendering reStructuredText documents. -- `pygments` - for syntax highlighting. +- `Pygments` - for syntax highlighting. Usage ----- -To use wok, go to the directory where your site files are located, and -run the command `wok`. For now, no output will be given unless something -goes wrong. If it returns without error, you should have a shiny new -output folder containing some HTML, and your media that represents your -shiny new site. +To use wok, go to the directory where your site files are located, and run the +command `wok`. No output will be given unless something goes wrong. If it +returns without error, you should have a shiny new output folder containing +some HTML, and your media that represents your shiny new site. To aid in testing links on the site, wok includes a development server. You can run it with the command `wok --server`, which will generate the @@ -123,9 +126,7 @@ syntax highlighting and media copying make things even easier. [mkd]: http://daringfireball.net/projects/markdown/ [rst]: http://docutils.sourceforge.net/rst.html -[More info][more_content] - -[more_content]: https://github.com/mythmon/wok/wiki/Content +[More info](http://wok.mythmon.com/docs/content/) ### Templates ### Pulled from `templates` by default. Wok uses [Jinja2][jinja] templates, @@ -133,39 +134,9 @@ with various variables exposed to build pages. This is a very flexible templating environment with control flow, filters, and other ways to slice and dice the data that wok gives you. -[More info][more_templates] - -[more_templates]: https://github.com/mythmon/wok/wiki/Templates [jinja]: http://jinja.pocoo.org/ -### Pagination ### -Pagination requires teamwork from both the templates and the content of a page. -In the content, place a new item, `pagination`, with sub-items `limit` and -`list`. Optionally you can also include `sort_key` and `sort_reverse`. - -Example - - title: Pagination Test - pagination: - list: page.subpages - limit: 3 - sort_key: slug - sort_reverse: True - --- - Let's test pagination. - -Then the template for this page will get a new variable `pagination` with -useful things like `pagination.page_items` and `pagination.next_page`. - -[More info][more_pagination] - -[more_pagination]: https://github.com/mythmon/wok/wiki/Pagination - -### Media ### -Media is pretty simple. It is intended to be used for things like site wide -images, style sheets and JavaScript. Wok will copy everything from the media -directory straight to the output directory before generating anything. This -means that generated content can overwrite media. +[More info](http://wok.mythmon.com/docs/templates/) Configuration ------------- @@ -185,9 +156,18 @@ Possible configuration options (and their defaults) are place the output files. The default produces URLs like `/category/subcategory/foo.html`. To get "wordpress style" urls, you could use `/{category}/{slug}/index.html`. -- `url_use_index` (Yes) - If true, keep `index.*` in urls. Available variables: - `{category}` - The category of the site, slash seperated. - `{slug}` - The slug of the page. + - `{page}` - The current page. + - `{ext}` - The extension that the page should used. + - `{date}`, `{datetime}`, and `{time}` - The date/time from the metadata + of the page + +- `url_use_index` (Yes) - If true, keep `index.*` in urls. + +More info: +[config](http://wok.mythmon.com/docs/config/), +[urls](http://wok.mythmon.com/docs/urls/). From 13d473b993dc55302fb55149fa7951d5f92b45f4 Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 19 Feb 2012 14:07:36 -0800 Subject: [PATCH 56/58] Update some documentation. --- docs/content/docs/urls.mkd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/content/docs/urls.mkd b/docs/content/docs/urls.mkd index aacf558..97fd503 100644 --- a/docs/content/docs/urls.mkd +++ b/docs/content/docs/urls.mkd @@ -23,8 +23,8 @@ arrange to your liking: file. - `{date}`, `{datetime}`, `{time}` - The date/time that were specified in the metadata of a page. These are Python date, datetime, and time objects, so - they have year, month, day, hour, minute, etc fields. If you don't specify a - date in the file, the default is midnight on January 1st, 1970. + they have year, month, day, hour, minute, etc fields. If you don't specify + these, they will default to `None`. If you don't include `{page}` in your `url_pattern`, then pagination won't work. Instead it will overwrite each page with it's sequel, resulting in only From bf2e891d5ea7c20a144d4455f6c30c0a9b7902cd Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 19 Feb 2012 14:07:46 -0800 Subject: [PATCH 57/58] Add a download page to the site. --- docs/content/docs.mkd | 14 ++---------- docs/content/download.mkd | 48 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 docs/content/download.mkd diff --git a/docs/content/docs.mkd b/docs/content/docs.mkd index 34bc2cb..6cd5a40 100644 --- a/docs/content/docs.mkd +++ b/docs/content/docs.mkd @@ -12,22 +12,12 @@ If you just want to use wok, then you should install it from the ::console $ sudo pip install wok -This will install wok and the required dependencies. You should also install at -least one of [Markdown][mkd], or [reStructuredText][rst], for content markup: - - ::console - $ sudo pip install Markdown - $ sudo pip install docutils - -If you want syntax highlighting, you will also need [Pygments][pgmnts]. - - ::console - $ sudo pip install Pygments +This will install wok and the required dependencies. It will also install some optional dependencies: the two rendering libraries, [Markdown][mkd], and [reStructuredTest][rst]. It will also install a syntax highlighting library, [Pygments][pymnts]. +[pypi]: http://pypi.python.org/pypi [mkd]: http://daringfireball.net/projects/markdown/ [rst]: http://docutils.sourceforge.net/rst.html [pgmnts]: http://pygments.org/ -[pypi]: http://pypi.python.org/pypi Contribute ---------- diff --git a/docs/content/download.mkd b/docs/content/download.mkd new file mode 100644 index 0000000..23f0332 --- /dev/null +++ b/docs/content/download.mkd @@ -0,0 +1,48 @@ +title: Download +tags: [_nav] +nav_sort: 4 +--- + +The recommended way to get wok is from the [Python Package Index][pypi]. You +can do that with `pip`: + + ::console + $ sudo pip install wok + +This will install wok and the required dependencies. It will also install some optional dependencies: the two rendering libraries, [Markdown][mkd], and [reStructuredTest][rst]. It will also install a syntax highlighting library, [Pygments][]. + +[pypi]: http://pypi.python.org/pypi +[mkd]: http://daringfireball.net/projects/markdown/ +[rst]: http://docutils.sourceforge.net/rst.html +[pygments]: http://pygments.org/ + +Other Methods +============= + +You can also checkout out the code [from Github][gh], or download a tarball: + +Latest Stable +------------- + +- [Version 0.9](https://github.com/mythmon/wok/tarball/v0.9) + +Older Versions +-------------- + +- [Version 0.8.2](https://github.com/mythmon/wok/tarball/v0.8.2) +- [Version 0.8.1](https://github.com/mythmon/wok/tarball/v0.8.1) +- [Version 0.8](https://github.com/mythmon/wok/tarball/v0.8) +- [Version 0.7](https://github.com/mythmon/wok/tarball/v0.7) +- [Version 0.6.3](https://github.com/mythmon/wok/tarball/v0.6.3) +- [Version 0.6.2](https://github.com/mythmon/wok/tarball/v0.6.2) +- [Version 0.6.1](https://github.com/mythmon/wok/tarball/v0.6.1) +- [Version 0.6](https://github.com/mythmon/wok/tarball/v0.6) +- [Version 0.5.1](https://github.com/mythmon/wok/tarball/v0.5.1) +- [Version 0.5](https://github.com/mythmon/wok/tarball/v0.5) +- [Version 0.4](https://github.com/mythmon/wok/tarball/v0.4) +- [Version 0.3](https://github.com/mythmon/wok/tarball/v0.3) +- [Version 0.2.1](https://github.com/mythmon/wok/tarball/v0.2.1) +- [Version 0.2](https://github.com/mythmon/wok/tarball/v0.2) +- [Version 0.1](https://github.com/mythmon/wok/tarball/v0.1) + +[gh]: https://github.com/mythmon/wok From ff59819afb142b16b8ba5264876333cf5f674dcd Mon Sep 17 00:00:00 2001 From: Mike Cooper Date: Sun, 19 Feb 2012 14:09:06 -0800 Subject: [PATCH 58/58] Bump version. --- docs/templates/base.html | 6 +++--- wok/__init__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/templates/base.html b/docs/templates/base.html index d826b62..4d75181 100644 --- a/docs/templates/base.html +++ b/docs/templates/base.html @@ -36,9 +36,9 @@

    wok

    - This is the dev version of the docs. You could also see the - - latest stable version of this page. + This is the 0.9 version of the docs. You could also see the + + dev version of this page. diff --git a/wok/__init__.py b/wok/__init__.py index ca3970c..1dd823d 100644 --- a/wok/__init__.py +++ b/wok/__init__.py @@ -1 +1 @@ -version = u'0.8.0' +version = u'0.9.0'