initial commit to seperate repo

This commit is contained in:
Don Harper 2015-06-09 22:50:31 -05:00
commit 1a020ca68b
1302 changed files with 201261 additions and 0 deletions

View file

@ -0,0 +1 @@
# Plugin modules go here.

1
plugins/__init__.py Normal file
View file

@ -0,0 +1 @@
# Plugin modules go here.

View file

@ -0,0 +1,9 @@
This plugin will do a quick and dirty import of any RSS or Atom feed into Nikola
To use it:
```
$ nikola plugin -i import_feed
$ nikola import_feed feed_url
```

View file

@ -0,0 +1,10 @@
[Core]
Name = import_feed
Module = import_feed
[Documentation]
Author = Grzegorz Śliwiński
Version = 0.1
Website = http://www.fizyk.net.pl/
Description = Import a blog posts from a RSS/Atom dump

View file

@ -0,0 +1,200 @@
# -*- coding: utf-8 -*-
# Copyright © 2012-2014 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import unicode_literals, print_function
import datetime
import os
import time
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse # NOQA
try:
import feedparser
except ImportError:
feedparser = None # NOQA
from nikola.plugin_categories import Command
from nikola import utils
from nikola.utils import req_missing
from nikola.plugins.basic_import import ImportMixin
from nikola.plugins.command.init import SAMPLE_CONF, prepare_config
LOGGER = utils.get_logger('import_feed', utils.STDERR_HANDLER)
class CommandImportFeed(Command, ImportMixin):
"""Import a feed dump."""
name = "import_feed"
needs_config = False
doc_usage = "[options] feed_file"
doc_purpose = "import a RSS/Atom dump"
cmd_options = ImportMixin.cmd_options
def _execute(self, options, args):
'''
Import Atom/RSS feed
'''
if feedparser is None:
req_missing(['feedparser'], 'import feeds')
return
if not args:
print(self.help())
return
options['filename'] = args[0]
self.feed_export_file = options['filename']
self.output_folder = options['output_folder']
self.import_into_existing_site = False
self.url_map = {}
channel = self.get_channel_from_file(self.feed_export_file)
self.context = self.populate_context(channel)
conf_template = self.generate_base_site()
self.context['REDIRECTIONS'] = self.configure_redirections(
self.url_map)
self.import_posts(channel)
self.write_configuration(self.get_configuration_output_path(
), conf_template.render(**prepare_config(self.context)))
@classmethod
def get_channel_from_file(cls, filename):
return feedparser.parse(filename)
@staticmethod
def populate_context(channel):
context = SAMPLE_CONF.copy()
context['DEFAULT_LANG'] = channel.feed.title_detail.language \
if channel.feed.title_detail.language else 'en'
context['BLOG_TITLE'] = channel.feed.title
context['BLOG_DESCRIPTION'] = channel.feed.get('subtitle', '')
context['SITE_URL'] = channel.feed.get('link', '').rstrip('/')
context['BLOG_EMAIL'] = channel.feed.author_detail.get('email', '') if 'author_detail' in channel.feed else ''
context['BLOG_AUTHOR'] = channel.feed.author_detail.get('name', '') if 'author_detail' in channel.feed else ''
context['POSTS'] = '''(
("posts/*.html", "posts", "post.tmpl"),
)'''
context['PAGES'] = '''(
("stories/*.html", "stories", "story.tmpl"),
)'''
context['COMPILERS'] = '''{
"rest": ('.txt', '.rst'),
"markdown": ('.md', '.mdown', '.markdown', '.wp'),
"html": ('.html', '.htm')
}
'''
return context
def import_posts(self, channel):
for item in channel.entries:
self.process_item(item)
def process_item(self, item):
self.import_item(item, 'posts')
def import_item(self, item, out_folder=None):
"""Takes an item from the feed and creates a post file."""
if out_folder is None:
out_folder = 'posts'
# link is something like http://foo.com/2012/09/01/hello-world/
# So, take the path, utils.slugify it, and that's our slug
link = item.link
link_path = urlparse(link).path
title = item.title
# blogger supports empty titles, which Nikola doesn't
if not title:
LOGGER.warn("Empty title in post with URL {0}. Using NO_TITLE "
"as placeholder, please fix.".format(link))
title = "NO_TITLE"
if link_path.lower().endswith('.html'):
link_path = link_path[:-5]
slug = utils.slugify(link_path)
if not slug: # should never happen
LOGGER.error("Error converting post:", title)
return
description = ''
post_date = datetime.datetime.fromtimestamp(time.mktime(
item.published_parsed))
if item.get('content'):
for candidate in item.get('content', []):
content = candidate.value
break
# FIXME: handle attachments
elif item.get('summary'):
content = item.get('summary')
tags = []
for tag in item.get('tags', []):
tags.append(tag.term)
if item.get('app_draft'):
tags.append('draft')
is_draft = True
else:
is_draft = False
self.url_map[link] = self.context['SITE_URL'] + '/' + \
out_folder + '/' + slug + '.html'
if is_draft and self.exclude_drafts:
LOGGER.notice('Draft "{0}" will not be imported.'.format(title))
elif content.strip():
# If no content is found, no files are written.
content = self.transform_content(content)
self.write_metadata(os.path.join(self.output_folder, out_folder,
slug + '.meta'),
title, slug, post_date, description, tags)
self.write_content(
os.path.join(self.output_folder, out_folder, slug + '.html'),
content)
else:
LOGGER.warn('Not going to import "{0}" because it seems to contain'
' no content.'.format(title))
@staticmethod
def write_metadata(filename, title, slug, post_date, description, tags):
ImportMixin.write_metadata(filename,
title,
slug,
post_date.strftime(r'%Y/%m/%d %H:%m:%S'),
description,
tags)

Binary file not shown.

View file

@ -0,0 +1 @@
feedparser

8
plugins/less/README.md Normal file
View file

@ -0,0 +1,8 @@
Compile [LESS](http://lesscss.org/) source files into CSS.
To use this plugin:
Create a ``less`` folder in your theme, put your ``.less`` files there, add a ``less/targets`` file listing the files you
want compiled.

Binary file not shown.

10
plugins/less/less.plugin Normal file
View file

@ -0,0 +1,10 @@
[Core]
Name = less
Module = less
[Documentation]
Author = Roberto Alsina
Version = 0.1
Website = http://plugins.getnikola.com/#less
Description = Build CSS out of LESS sources

121
plugins/less/less.py Normal file
View file

@ -0,0 +1,121 @@
# -*- coding: utf-8 -*-
# Copyright © 2012-2014 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import unicode_literals
import codecs
import glob
import os
import sys
import subprocess
from nikola.plugin_categories import Task
from nikola import utils
class BuildLess(Task):
"""Generate CSS out of LESS sources."""
name = "build_less"
sources_folder = "less"
sources_ext = ".less"
def gen_tasks(self):
"""Generate CSS out of LESS sources."""
self.compiler_name = self.site.config['LESS_COMPILER']
self.compiler_options = self.site.config['LESS_OPTIONS']
kw = {
'cache_folder': self.site.config['CACHE_FOLDER'],
'themes': self.site.THEMES,
}
tasks = {}
# Find where in the theme chain we define the LESS targets
# There can be many *.less in the folder, but we only will build
# the ones listed in less/targets
if os.path.isfile(os.path.join(self.sources_folder, "targets")):
targets_path = os.path.join(self.sources_folder, "targets")
else:
targets_path = utils.get_asset_path(os.path.join(self.sources_folder, "targets"), self.site.THEMES)
try:
with codecs.open(targets_path, "rb", "utf-8") as inf:
targets = [x.strip() for x in inf.readlines()]
except Exception:
targets = []
for task in utils.copy_tree(self.sources_folder, os.path.join(kw['cache_folder'], self.sources_folder)):
if task['name'] in tasks:
continue
task['basename'] = 'prepare_less_sources'
tasks[task['name']] = task
yield task
for theme_name in kw['themes']:
src = os.path.join(utils.get_theme_path(theme_name), self.sources_folder)
for task in utils.copy_tree(src, os.path.join(kw['cache_folder'], self.sources_folder)):
task['basename'] = 'prepare_less_sources'
yield task
# Build targets and write CSS files
base_path = utils.get_theme_path(self.site.THEMES[0])
dst_dir = os.path.join(self.site.config['OUTPUT_FOLDER'], 'assets', 'css')
# Make everything depend on all sources, rough but enough
deps = []
if os.path.isfile(os.path.join(self.sources_folder, "targets")):
deps += glob.glob(os.path.join(kw['cache_folder'], self.sources_folder,
'*{0}'.format(self.sources_ext)))
else:
deps += glob.glob(os.path.join(base_path, self.sources_folder,
'*{0}'.format(self.sources_ext)))
def compile_target(target, dst):
utils.makedirs(dst_dir)
src = os.path.join(kw['cache_folder'], self.sources_folder, target)
run_in_shell = sys.platform == 'win32'
try:
compiled = subprocess.check_output([self.compiler_name] + self.compiler_options + [src], shell=run_in_shell)
except OSError:
utils.req_missing([self.compiler_name],
'build LESS files (and use this theme)',
False, False)
with open(dst, "wb+") as outf:
outf.write(compiled)
yield self.group_task()
for target in targets:
dst = os.path.join(dst_dir, target.replace(self.sources_ext, ".css"))
yield {
'basename': self.name,
'name': dst,
'targets': [dst],
'file_dep': deps,
'task_dep': ['prepare_less_sources'],
'actions': ((compile_target, [target, dst]), ),
'uptodate': [utils.config_changed(kw)],
'clean': True
}

BIN
plugins/less/less.pyc Normal file

Binary file not shown.

View file

@ -0,0 +1 @@
LESS::http://lesscss.org

8
plugins/sass/README.md Normal file
View file

@ -0,0 +1,8 @@
Compile [SASS](http://sass-lang.com/) source files into CSS.
To use this plugin:
Create a ``sass`` folder in your theme, put your ``.scss`` files there, add a ``sass/targets`` file listing the files you
want compiled.

Binary file not shown.

View file

@ -0,0 +1 @@
SASS::http://sass-lang.com

9
plugins/sass/sass.plugin Normal file
View file

@ -0,0 +1,9 @@
[Core]
Name = sass
Module = sass
[Documentation]
Author = Roberto Alsina, Chris "Kwpolska" Warrick
Version = 0.1
Website = http://plugins.getnikola.com/#sass
Description = Build CSS out of Sass sources

143
plugins/sass/sass.py Normal file
View file

@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
# Copyright © 2012-2014 Roberto Alsina and others.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import unicode_literals
import codecs
import glob
import os
import sys
import subprocess
from nikola.plugin_categories import Task
from nikola import utils
class BuildSass(Task):
"""Generate CSS out of Sass sources."""
name = "build_sass"
sources_folder = "sass"
sources_ext = (".sass", ".scss")
def gen_tasks(self):
"""Generate CSS out of Sass sources."""
self.logger = utils.get_logger('build_sass', self.site.loghandlers)
self.compiler_name = self.site.config['SASS_COMPILER']
self.compiler_options = self.site.config['SASS_OPTIONS']
kw = {
'cache_folder': self.site.config['CACHE_FOLDER'],
'themes': self.site.THEMES,
}
tasks = {}
# Find where in the theme chain we define the Sass targets
# There can be many *.sass/*.scss in the folder, but we only
# will build the ones listed in sass/targets
if os.path.isfile(os.path.join(self.sources_folder, "targets")):
targets_path = os.path.join(self.sources_folder, "targets")
else:
targets_path = utils.get_asset_path(os.path.join(self.sources_folder, "targets"), self.site.THEMES)
try:
with codecs.open(targets_path, "rb", "utf-8") as inf:
targets = [x.strip() for x in inf.readlines()]
except Exception:
targets = []
for task in utils.copy_tree(self.sources_folder, os.path.join(kw['cache_folder'], self.sources_folder)):
if task['name'] in tasks:
continue
task['basename'] = 'prepare_sass_sources'
tasks[task['name']] = task
yield task
for theme_name in kw['themes']:
src = os.path.join(utils.get_theme_path(theme_name), self.sources_folder)
for task in utils.copy_tree(src, os.path.join(kw['cache_folder'], self.sources_folder)):
if task['name'] in tasks:
continue
task['basename'] = 'prepare_sass_sources'
tasks[task['name']] = task
yield task
# Build targets and write CSS files
base_path = utils.get_theme_path(self.site.THEMES[0])
dst_dir = os.path.join(self.site.config['OUTPUT_FOLDER'], 'assets', 'css')
# Make everything depend on all sources, rough but enough
deps = []
for ext in self.sources_ext:
if os.path.isfile(os.path.join(self.sources_folder, "targets")):
deps += glob.glob(os.path.join(kw['cache_folder'], self.sources_folder,
'*{0}'.format(ext)))
else:
deps += glob.glob(os.path.join(base_path, self.sources_folder,
'*{0}'.format(ext)))
def compile_target(target, dst):
utils.makedirs(dst_dir)
run_in_shell = sys.platform == 'win32'
src = os.path.join(kw['cache_folder'], self.sources_folder, target)
try:
compiled = subprocess.check_output([self.compiler_name] + self.compiler_options + [src], shell=run_in_shell)
except OSError:
utils.req_missing([self.compiler_name],
'build Sass files (and use this theme)',
False, False)
with open(dst, "wb+") as outf:
outf.write(compiled)
yield self.group_task()
# We can have file conflicts. This is a way to prevent them.
# I orignally wanted to use sets and their cannot-have-duplicates
# magic, but I decided not to do this so we can show the user
# what files were problematic.
# If we didnt do this, there would be a cryptic message from doit
# instead.
seennames = {}
for target in targets:
base = os.path.splitext(target)[0]
dst = os.path.join(dst_dir, base + ".css")
if base in seennames:
self.logger.error(
'Duplicate filenames for Sass compiled files: {0} and '
'{1} (both compile to {2})'.format(
seennames[base], target, base + ".css"))
else:
seennames.update({base: target})
yield {
'basename': self.name,
'name': dst,
'targets': [dst],
'file_dep': deps,
'task_dep': ['prepare_sass_sources'],
'actions': ((compile_target, [target, dst]), ),
'uptodate': [utils.config_changed(kw)],
'clean': True
}

BIN
plugins/sass/sass.pyc Normal file

Binary file not shown.

View file

@ -0,0 +1,12 @@
[Core]
Name = upgrade_metadata
Module = upgrade_metadata
[Nikola]
MinVersion = 7.4.0
[Documentation]
Author = Chris Warrick
Version = 0.1.2
Website = http://plugins.getnikola.com/#upgrade_metadata
Description = Upgrade old-style metadata

View file

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
# Copyright © 20142015, Chris Warrick.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import unicode_literals
import io
import os
import nikola.post
from nikola.plugin_categories import Command
from nikola import utils
class UpgradeMetadata(Command):
"""Upgrade metadata from the old no-descriptions format to the new reST-esque format."""
name = 'upgrade_metadata'
doc_purpose = 'upgrade old-style metadata'
cmd_options = [
{
'name': 'yes',
'short': 'y',
'long': 'yes',
'type': bool,
'default': False,
'help': 'Proceed without confirmation',
},
]
fields = ('title', 'slug', 'date', 'tags', 'link', 'description', 'type')
def _execute(self, options, args):
L = utils.get_logger('upgrade_metadata', self.site.loghandlers)
nikola.post._UPGRADE_METADATA_ADVERTISED = True
# scan posts
self.site.scan_posts()
flagged = []
for post in self.site.timeline:
if not post.newstylemeta:
flagged.append(post)
if flagged:
if len(flagged) == 1:
L.info('1 post (and/or its translations) contains old-style metadata:')
else:
L.info('{0} posts (and/or their translations) contain old-style metadata:'.format(len(flagged)))
for post in flagged:
L.info(' ' + post.metadata_path)
if not options['yes']:
yesno = utils.ask_yesno("Proceed with metadata upgrade?")
if options['yes'] or yesno:
for post in flagged:
for lang in post.translated_to:
if lang == post.default_lang:
fname = post.metadata_path
else:
meta_path = os.path.splitext(post.source_path)[0] + '.meta'
fname = utils.get_translation_candidate(post.config, meta_path, lang)
with io.open(fname, 'r', encoding='utf-8') as fh:
meta = fh.readlines()
if not meta[1].startswith('.. '):
# check if were dealing with old style metadata
with io.open(fname, 'w', encoding='utf-8') as fh:
for k, v in zip(self.fields, meta):
fh.write('.. {0}: {1}'.format(k, v))
L.debug(fname)
L.info('{0} posts upgraded.'.format(len(flagged)))
else:
L.info('Metadata not upgraded.')
else:
L.info('No old-style metadata posts found. No action is required.')

40
plugins/vcs/README.md Normal file
View file

@ -0,0 +1,40 @@
This **EXPERIMENTAL** plugin tries to make it easy to keep your site in a version control system.
**REMEMBER**, this is a first iteration, it's probably buggy, so be careful, and only use it
if you are experienced with your VCS, ok?
How to use it:
1. Choose your favourite VCS between git, bzr, subversion, mercurial.
2. Initialize the repo in your site (for example: ``git init .``)
3. Install this plugin: ``nikola plugin -i vcs``
4. Run ``nikola vcs``
5. Check what happened (for example: ``git status`` and ``git log``)
6. Use your site as usual, creating posts, adding stuff or removing it
7. GOTO 4.
8. You may want to add ``nikola vcs`` to your deploy commands.
What it should do:
1. Add a lot of stuff to the repo:
* All your posts
* All your pages
* All your galleries' images
* All your listings
* All your static files
* Your themes
* Your plugins
* Your conf.py
2. Remove stuff if you removed it
3. Commit stuff if you changed it
What it should **NOT** do:
1. Lose your data
2. Push it anywhere (yet)
3. Manage your output (consider ``github_deploy`` would not like it!)
Please report anything missing, or any ideas on how to improve this, where you want this to go
by [filing issues](https://github.com/getnikola/plugins/issues).

Binary file not shown.

View file

@ -0,0 +1,2 @@
anyvc
py

9
plugins/vcs/vcs.plugin Normal file
View file

@ -0,0 +1,9 @@
[Core]
Name = vcs
Module = vcs
[Documentation]
Author = Roberto Alsina
Version = 1.0
Website = https://getnikola.com
Description = Site vcs

114
plugins/vcs/vcs.py Normal file
View file

@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
# Copyright © 2015 Roberto Alsina.
# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
from __future__ import print_function
import os
from py.path import local
from anyvc import workdir
from nikola.plugin_categories import Command
from nikola.utils import get_logger
def get_path_list(path):
'''Walk path and return a list of everything in it.'''
paths = []
for root, dirs, files in os.walk(path, followlinks=True):
for fname in files:
fpath = os.path.join(root, fname)
paths.append(fpath)
return list(set(paths))
class CommandVCS(Command):
""" Site status. """
name = "vcs"
doc_purpose = "display site status"
doc_description = "Show information about the posts and site deployment."
logger = None
cmd_options = []
def _execute(self, options, args):
logger = get_logger('vcs', self.site.loghandlers)
self.site.scan_posts()
repo_path = local('.')
wd = workdir.open(repo_path)
# See if anything got deleted
del_paths = []
flag = False
for s in wd.status():
if s.state == 'removed':
if not flag:
logger.info('Found deleted files')
flag = True
logger.info('DEL => {}', s.relpath)
del_paths.append(s.relpath)
if flag:
logger.info('Marking as deleted')
wd.remove(paths=del_paths)
wd.commit(message='Deleted Files', paths=del_paths)
# Collect all paths that should be kept under control
# Post and page sources
paths = []
for lang in self.site.config['TRANSLATIONS']:
for p in self.site.timeline:
paths.extend(p.fragment_deps(lang))
# Files in general
for k, v in self.site.config['FILES_FOLDERS'].items():
paths.extend(get_path_list(k))
for k, v in self.site.config['LISTINGS_FOLDERS'].items():
paths.extend(get_path_list(k))
for k, v in self.site.config['GALLERY_FOLDERS'].items():
paths.extend(get_path_list(k))
# Themes and plugins
for p in ['plugins', 'themes']:
paths.extend(get_path_list(p))
# The configuration
paths.extend('conf.py')
# Add them to the VCS
paths = list(set(paths))
wd.add(paths=paths)
flag = False
for s in wd.status():
if s.state == 'added':
if not flag:
logger.info('Found new files')
flag = True
logger.info('NEW => {}', s.relpath)
logger.info('Committing changes')
wd.commit(message='Updated files')