diff --git a/ablog/__init__.py b/ablog/__init__.py
index c284a71..144d889 100755
--- a/ablog/__init__.py
+++ b/ablog/__init__.py
@@ -8,7 +8,7 @@ from .post import (PostDirective, PostListDirective, UpdateDirective,
UpdateNode, process_posts, process_postlist, purge_posts,
generate_archive_pages, generate_atom_feeds)
-__version__ = '0.5.1'
+__version__ = '0.6'
def anchor(post):
diff --git a/ablog/commands.py b/ablog/commands.py
index 7c5c1e2..09a543e 100644
--- a/ablog/commands.py
+++ b/ablog/commands.py
@@ -1,10 +1,14 @@
import os
import sys
+import glob
import ablog
+import shutil
import argparse
+
+
def find_confdir(subparser):
from os.path import isfile, join, abspath
@@ -107,7 +111,7 @@ def ablog_build(subparser, **kwargs):
subparser = ablog_commands.add_parser('build',
help='build your blog project',
- description="Build options can be set in conf.py. "
+ description="Path options can be set in conf.py. "
"Default values of paths are relative to conf.py.")
subparser.add_argument('-b', dest='builder', type=str,
@@ -116,14 +120,14 @@ subparser.add_argument('-b', dest='builder', type=str,
subparser.add_argument('-d', dest='doctrees', type=str,
default='.doctrees',
help="path for the cached environment and doctree files, "
- "default `ablog_doctrees` or .doctrees")
+ "default .doctrees when `ablog_doctrees` is not set in conf.py")
subparser.add_argument('-s', dest='sourcedir', type=str,
help="root path for source files, "
"default is path to the folder that contains conf.py")
subparser.add_argument('-w', dest='website', type=str,
- help="path for website, default `ablog_website` or _website")
+ help="path for website, default is _website when `ablog_website` is not set in conf.py")
subparser.add_argument('-T', dest='traceback',
action='store_true', default=False,
@@ -133,6 +137,50 @@ subparser.set_defaults(func=lambda ns: ablog_build(**ns.__dict__))
subparser.set_defaults(subparser=subparser)
+def ablog_clean(subparser, **kwargs):
+
+ confdir = find_confdir(subparser)
+ conf = read_conf(confdir)
+
+ website = (kwargs['website'] or
+ os.path.join(confdir, getattr(conf, 'ablog_builddir', '_website')))
+
+ doctrees = (kwargs['doctrees'] or
+ os.path.join(confdir, getattr(conf, 'ablog_doctrees', '.doctrees')))
+
+
+ if glob.glob(os.path.join(website, '*')):
+ shutil.rmtree(website)
+ print('Removed {}.'.format(os.path.relpath(website)))
+ else:
+ print('Nothing to clean.')
+
+ if kwargs['deep'] and glob.glob(os.path.join(doctrees, '*')):
+ shutil.rmtree(doctrees)
+ print('Removed {}.'.format(os.path.relpath(doctrees)))
+
+
+subparser = ablog_commands.add_parser('clean',
+ help='clean your blog build files',
+ description="Path options can be set in conf.py. "
+ "Default values of paths are relative to conf.py.")
+
+subparser.add_argument('-d', dest='doctrees', type=str,
+ default='.doctrees',
+ help="path for the cached environment and doctree files, "
+ "default .doctrees when `ablog_doctrees` is not set in conf.py")
+
+subparser.add_argument('-w', dest='website', type=str,
+ help="path for website, default is _website when `ablog_website` is not set in conf.py")
+
+subparser.add_argument('-D', dest='deep',
+ action='store_true', default=False,
+ help="deep clean, remove cached environment and doctree files")
+
+
+subparser.set_defaults(func=lambda ns: ablog_clean(**ns.__dict__))
+subparser.set_defaults(subparser=subparser)
+
def ablog_serve(subparser, **kwargs):
@@ -178,16 +226,18 @@ subparser.add_argument('-p', dest='port', type=int,
subparser.add_argument('-w', dest='website', type=str,
help="path for website, "
- "default `ablog_website` or _website")
+ "default is _website when `ablog_website` is not set in conf.py")
subparser.set_defaults(func=lambda ns: ablog_serve(**ns.__dict__))
subparser.set_defaults(subparser=subparser)
+
def ablog_post(subparser, **kwargs):
POST_TEMPLATE =u'''
%(title)s
====================
+
.. post:: %(date)s
:tags:
:category:
@@ -237,6 +287,78 @@ subparser.add_argument(dest='filename', type=str,
subparser.set_defaults(func=lambda ns: ablog_post(**ns.__dict__))
subparser.set_defaults(subparser=subparser)
+def ablog_deploy(subparser, **kwargs):
+
+ confdir = find_confdir(subparser)
+ conf = read_conf(confdir)
+
+ github_pages = (kwargs['github_pages'] or
+ getattr(conf, 'github_pages') or None)
+
+ #from subprocess import call
+
+ website = (kwargs['website'] or
+ os.path.join(confdir, getattr(conf, 'ablog_builddir', '_website')))
+
+ tomove = glob.glob(os.path.join(website, '*'))
+ if not tomove:
+ print('Nothing to deploy, build first.')
+ return
+
+ try:
+ from invoke import run
+ except ImportError:
+ raise ImportError("invoke is required by deploy command, "
+ "run `pip install invoke`")
+
+
+ if github_pages:
+
+ gitdir = os.path.join(confdir, "{0}.github.io".format(github_pages))
+ if os.path.isdir(gitdir):
+ os.chdir(gitdir)
+ run("git pull", echo=True)
+ else:
+ run("git clone https://github.com/{0}/{0}.github.io.git"
+ .format(github_pages), echo=True)
+
+ git_add = []
+ for tm in tomove:
+ for root, dirnames, filenames in os.walk(website):
+ for filename in filenames:
+ fn = os.path.join(root, filename)
+ fnnew = fn.replace(website, gitdir)
+ os.renames(fn, fnnew)
+ git_add.append(fnnew)
+ print('Moved {} files to {}.github.io'
+ .format(len(git_add), github_pages))
+ os.chdir(gitdir)
+
+ run("git add -f " +
+ " ".join([os.path.relpath(p) for p in git_add]), echo=True)
+ run('git commit -m "Updates."', echo=True)
+ run('git push', echo=True)
+
+ else:
+ print('No place to deploy.')
+
+
+subparser = ablog_commands.add_parser('deploy',
+ help='deploy your website build files',
+ description="Path options can be set in conf.py. "
+ "Default values of paths are relative to conf.py.")
+
+subparser.add_argument('-g', dest='github_pages', type=str,
+ help="GitHub user name for deploying to GitHub pages")
+
+subparser.add_argument('-w', dest='website', type=str,
+ help="path for website, default is _website when `ablog_website` is not set in conf.py")
+
+
+subparser.set_defaults(func=lambda ns: ablog_deploy(**ns.__dict__))
+subparser.set_defaults(subparser=subparser)
+
+
def ablog_main():
diff --git a/docs/index.rst b/docs/index.rst
index 0844c09..dedce9a 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -28,14 +28,14 @@ You can install ABlog using pip_::
pip install -U ablog
-This will also install `Sphinx `_, Alabaster_, and
-Werkzeug_, respectively required for building your website, making it look
-good, and generating feeds.
+This will also install `Sphinx `_, Alabaster_,
+Werkzeug_, and Invoke_ respectively required for building your website,
+making it look good, generating feeds, and running deploy commands.
.. _pip: https://pip.pypa.io
.. _Werkzeug: http://werkzeug.pocoo.org/
.. _Alabaster: https://github.com/bitprophet/alabaster
-
+.. _Invoke: http://www.pyinvoke.org/
Getting Started
---------------
diff --git a/docs/manual/ablog-commands.rst b/docs/manual/ablog-commands.rst
index f1da872..34f4325 100644
--- a/docs/manual/ablog-commands.rst
+++ b/docs/manual/ablog-commands.rst
@@ -16,7 +16,7 @@ and viewing blog pages, as well as starting a new blog.
::
$ ablog
- usage: ablog [-h] [-v] {start,build,serve,post} ...
+ usage: ablog [-h] [-v] {start,build,clean,serve,post,deploy} ...
ABlog for blogging with Sphinx
@@ -25,15 +25,23 @@ and viewing blog pages, as well as starting a new blog.
-v, --version print ABlog version and exit
subcommands:
- {start,build,serve,post}
+ {start,build,clean,serve,post,deploy}
start start a new blog project
build build your blog project
+ clean clean your blog build files
serve serve and view your project
post create a blank post
+ deploy deploy your website build files
See 'ablog -h' for more information on a specific command.
+
+
+.. contents:: Here are all the things you can do:
+ :local:
+ :backlinks: top
+
Start a Project
---------------
@@ -43,7 +51,7 @@ Start a Project
::
- $ ablog serve -h
+ $ ablog start -h
usage: ablog start [-h]
Start a new blog project with in less than 10 seconds. After answering a few
@@ -65,17 +73,18 @@ Running ``ablog build`` in your project folder builds your website HTML pages.
usage: ablog build [-h] [-b BUILDER] [-d DOCTREES] [-s SOURCEDIR] [-w WEBSITE]
[-T]
- Build options can be set in conf.py. Default values of paths are relative to
+ Path options can be set in conf.py. Default values of paths are relative to
conf.py.
optional arguments:
-h, --help show this help message and exit
-b BUILDER builder to use, default `ablog_builder` or dirhtml
-d DOCTREES path for the cached environment and doctree files, default
- `ablog_doctrees` or .doctrees
+ .doctrees when `ablog_doctrees` is not set in conf.py
-s SOURCEDIR root path for source files, default is path to the folder that
contains conf.py
- -w WEBSITE path for website, default `ablog_website` or _website
+ -w WEBSITE path for website, default is _website when `ablog_website` is
+ not set in conf.py
-T show full traceback on exception
Serve and View
@@ -96,7 +105,29 @@ server and open up browser tab to view your website.
-h, --help show this help message and exit
-n do not open website in a new browser tab
-p PORT port number for HTTP server; default is 8000
- -w WEBSITE path for website, default `ablog_website` or _website
+ -w WEBSITE path for website, default is _website when `ablog_website` is
+ not set in conf.py
+
+.. _deploy:
+
+Deploy Website
+--------------
+
+Running ``ablog deploy`` will push your website to GitHub.
+
+::
+
+ $ ablog deploy -h
+ usage: ablog deploy [-h] [-g GITHUB_PAGES] [-w WEBSITE]
+
+ Path options can be set in conf.py. Default values of paths are relative to
+ conf.py.
+
+ optional arguments:
+ -h, --help show this help message and exit
+ -g GITHUB_PAGES GitHub user name for deploying to GitHub pages
+ -w WEBSITE path for website, default is _website when `ablog_website`
+ is not set in conf.py
Create a Post
-------------
@@ -113,4 +144,31 @@ Finally, ``ablog post`` will make a new post template file.
optional arguments:
-h, --help show this help message and exit
- -t TITLE post title; default is `New Post
\ No newline at end of file
+ -t TITLE post title; default is `New Post
+
+Clean Files
+-----------
+
+In case you needed, running ``ablog clean`` will remove build files and
+do a deep clean with ``-D`` option.
+
+::
+
+ $ ablog clean -h
+ usage: ablog clean [-h] [-d DOCTREES] [-w WEBSITE] [-D]
+
+ Path options can be set in conf.py. Default values of paths are relative to
+ conf.py.
+
+ optional arguments:
+ -h, --help show this help message and exit
+ -d DOCTREES path for the cached environment and doctree files, default
+ .doctrees when `ablog_doctrees` is not set in conf.py
+ -w WEBSITE path for website, default is _website when `ablog_website` is
+ not set in conf.py
+ -D deep clean, remove cached environment and doctree files
+
+
+.. update:: Apr 7, 2015
+
+ Added ``ablog clean`` and ``ablog deploy`` commands.
\ No newline at end of file
diff --git a/docs/manual/ablog-configuration-options.rst b/docs/manual/ablog-configuration-options.rst
index 747bf55..f5ab1b0 100644
--- a/docs/manual/ablog-configuration-options.rst
+++ b/docs/manual/ablog-configuration-options.rst
@@ -91,7 +91,7 @@ Authors, languages, & locations
.. update:: Sep 15, 2014
Added :confval:`blog_languages` and :confval:`blog_default_language`
- confivuration variables.
+ configuration variables.
Post related
------------
@@ -245,3 +245,31 @@ you see on the left are listed below in the same order:
link to a archive pages generated for each tag, category, and year.
In addition, there are ``authors.html``, ``languages.html``, and
``locations.html`` sidebars that link to author and location archive pages.
+
+Command Options
+---------------
+
+.. update:: Apr 7, 2015
+
+ Added :ref:`commands` options.
+
+.. confval:: ablog_website
+
+ Directory name for build output files. Default is ``_website``.
+
+.. confval:: ablog_doctrees
+
+ Directory name for build cache files. Default is ``.doctrees``.
+
+.. confval:: ablog_builder
+
+ HTML builder, default is ``dirhtml``. Build HTML pages, but with
+ a single directory per document. Makes for prettier URLs (no .html)
+ if served from a webserver. Alternative is ``html`` to build
+ one HTML file per document.
+
+.. confval:: github_pages
+
+ GitHub user name used by ``ablog deploy`` command. See :ref:`deploy`
+ and :ref:`deploy-to-github-pages` for more information.
+
diff --git a/docs/manual/deploy-to-github-pages.rst b/docs/manual/deploy-to-github-pages.rst
new file mode 100644
index 0000000..e5d109b
--- /dev/null
+++ b/docs/manual/deploy-to-github-pages.rst
@@ -0,0 +1,37 @@
+
+Deploy to GitHub Pages
+======================
+
+
+.. post:: Apr 07, 2015
+ :tags:
+ :category:
+
+If you are looking for a place to publish your blog, `GitHub Pages`_ might
+be the place for you.
+
+.. _GitHub Pages: https://pages.github.com/
+
+Assuming that you have a GitHub account, here are what you need to do
+to get published:
+
+1. Head over to GitHub_ and create a new repository named ``username.github.io``, where
+ username is your username (or organization name) on GitHub.
+
+2. (optional) If you followed the link, you might as well give a star to ABlog ;)
+
+3. Set :confval:`github_pages` configuration variable in :file:`conf.py` file.
+
+4. Run ``ablog build`` in your project folder.
+
+5. Run ``ablog deploy``. This command will
+
+ i. clone your GitHub pages repository to project folder,
+
+ ii. copy all files from build folder (:file:`_website`) to :file:`username.github.io`,
+
+ iii. add copied files and commit,
+
+ iv. and finally push the changes to publish.
+
+Let us know how this works for you!
\ No newline at end of file
diff --git a/docs/release/ablog-v0.6-released.rst b/docs/release/ablog-v0.6-released.rst
new file mode 100644
index 0000000..66210cb
--- /dev/null
+++ b/docs/release/ablog-v0.6-released.rst
@@ -0,0 +1,12 @@
+ABlog v0.6 released
+===================
+
+.. post:: Apr 8, 2015
+ :author: Ahmet
+ :category: Release
+ :location: SF
+
+
+ABlog v0.6 is released with new :ref:`ablog-commands`. You can
+``ablog deploy`` use to :ref:`deploy-to-github-pages`, and also ``ablog clean``
+to do spring cleaning every once in a while.
diff --git a/setup.py b/setup.py
index 1d5ded7..2922634 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,7 @@ setup(
'Programming Language :: Python :: 3',
],
provides=['ablog ({0:s})'.format(__version__)],
- install_requires=['Werkzeug', 'Sphinx', 'alabaster'],
+ install_requires=['Werkzeug', 'Sphinx', 'alabaster', 'invoke'],
message_extractors={
'ablog': [
('**.html', 'jinja2', None),