Skip to content

Commit

Permalink
Merge github.com:saimn/sigal
Browse files Browse the repository at this point in the history
Conflicts:
	sigal/gallery.py
  • Loading branch information
t.animal committed Sep 8, 2014
2 parents 67e453e + 4c3a35c commit af3ead7
Show file tree
Hide file tree
Showing 12 changed files with 121 additions and 40 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Expand Up @@ -3,4 +3,5 @@ alphabetical order):

- Christophe-Marie Duquesne
- Matthias Vogelgesang
- Vikram Shirgur
- Yuce Tekol
5 changes: 5 additions & 0 deletions docs/changelog.rst
Expand Up @@ -2,6 +2,11 @@
Changelog
===========

Version 0.9.dev
~~~~~~~~~~~~~~~

Released on 2014-xx-xx.

Version 0.8.0
~~~~~~~~~~~~~

Expand Down
21 changes: 20 additions & 1 deletion docs/getting_started.rst
Expand Up @@ -34,7 +34,7 @@ Serve
``index.html`` to the urls to allow browsing without a server.


Help of the ``sigal build`` command
Help on the ``sigal build`` command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::
Expand Down Expand Up @@ -73,3 +73,22 @@ Optional arguments:

``-n NCPU, --ncpu NCPU``
Number of cpu to use (default: all)

Help on the ``sigal serve`` command
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

::

$ sigal serve [-c CONFIG] [-p PORT] [destination]

Optional arguments:

``-c CONFIG, --config CONFIG``
Configuration file (default: ``sigal.conf.py`` in the current working
directory)

``-p PORT, --port PORT``
Port number to start the server on (default: 8000)

``destination``
Destination directory where the output of build is located (default: _build)
17 changes: 13 additions & 4 deletions docs/plugins.rst
Expand Up @@ -7,15 +7,24 @@ How to use plugins

Plugins must be specified with the ``plugins`` setting:

.. code-block:: python
plugins = ['sigal.plugins.adjust', 'sigal.plugins.copyright']
You can either specify the name of the module which contains the plugin, or
import the plugin before adding it to the list:

.. code-block:: python
from sigal.plugins import copyright
plugins = ['sigal.plugins.adjust', copyright]
You can either specify the name of the module which contains the plugin, or
import the plugin before adding it to the list. The ``plugin_paths`` setting
can be used to specify paths to search for plugins (if they are not in the
python path).
.. note:: Using an import like this will break the multiprocessing feature,
because the settings dict must be serializable. So in most cases you should
prefer the first option.

The ``plugin_paths`` setting can be used to specify paths to search for plugins
(if they are not in the python path).

Write a new plugin
------------------
Expand Down
52 changes: 34 additions & 18 deletions sigal/__init__.py
Expand Up @@ -169,24 +169,40 @@ def init_plugins(settings):


@main.command()
@argument('path', default='_build')
@argument('destination', default='_build')
@option('-p', '--port', help="Port to use", default=8000)
def serve(path, port):
@option('-c', '--config', default=_DEFAULT_CONFIG_FILE,
show_default=True, help='Configuration file')
def serve(destination, port, config):
"""Run a simple web server."""

if os.path.exists(path):
os.chdir(path)
Handler = server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", port), Handler, False)
print(" * Running on http://127.0.0.1:{}/".format(port))

try:
httpd.allow_reuse_address = True
httpd.server_bind()
httpd.server_activate()
httpd.serve_forever()
except KeyboardInterrupt:
print('\nAll done!')
if os.path.exists(destination):
pass
elif os.path.exists(config):
settings = read_settings(config)
destination = settings.get('destination')
if not os.path.exists(destination):
sys.stderr.write("The '{}' directory doesn't exist, "
"maybe try building first?"
"\n".format(destination))
sys.exit(1)
else:
sys.stderr.write("The '%s' directory doesn't exist.\n" % path)
sys.exit(1)
sys.stderr.write("The {destination} directory doesn't exist "
"and the config file ({config}) could not be "
"read."
"\n".format(destination=destination, config=config))
sys.exit(2)

print('DESTINATION : {}'.format(destination))
os.chdir(destination)
Handler = server.SimpleHTTPRequestHandler
httpd = socketserver.TCPServer(("", port), Handler, False)
print(" * Running on http://127.0.0.1:{}/".format(port))

try:
httpd.allow_reuse_address = True
httpd.server_bind()
httpd.server_activate()
httpd.serve_forever()
except KeyboardInterrupt:
print('\nAll done!')

23 changes: 15 additions & 8 deletions sigal/gallery.py
Expand Up @@ -27,6 +27,7 @@
import logging
import multiprocessing
import os
import pickle
import sys
import zipfile

Expand Down Expand Up @@ -97,10 +98,15 @@ def __unicode__(self):
@property
def big(self):
"""Path to the original image, if ``keep_orig`` is set (relative to the
album directory).
album directory). Copy the file if needed.
"""
if self.settings['keep_orig']:
return os.path.join(self.settings['orig_dir'], self.src_filename)
s = self.settings
orig_path = join(s['destination'], self.path, s['orig_dir'])
check_or_create_dir(orig_path)
copy(self.src_path, join(orig_path, self.src_filename),
symlink=s['orig_link'])
return url_from_path(join(s['orig_dir'], self.src_filename))
else:
return None

Expand Down Expand Up @@ -221,7 +227,6 @@ def __init__(self, path, settings, dirnames, filenames, gallery):
self.name = path.split(os.path.sep)[-1]
self.gallery = gallery
self.settings = settings
self.orig_path = None
self._thumbnail = None

if path == '.':
Expand Down Expand Up @@ -604,6 +609,13 @@ def log_func(x):
except KeyboardInterrupt:
self.pool.terminate()
sys.exit('Interrupted')
except pickle.PicklingError:
self.logger.critical(
"Failed to process files with the multiprocessing feature."
" This can be caused by some module import or object "
"defined in the settings file, which can't be serialized.",
exc_info=True)
sys.exit('Abort')

print('')
else:
Expand All @@ -621,16 +633,11 @@ def log_func(x):

def process_dir(self, album, force=False):
"""Process a list of images in a directory."""

for f in album:
if isfile(f.dst_path) and not force:
self.logger.info("%s exists - skipping", f.filename)
self.stats[f.type + '_skipped'] += 1
else:
if self.settings['keep_orig']:
copy(f.src_path, join(album.orig_path, f.filename),
symlink=self.settings['orig_link'])

self.stats[f.type] += 1
yield f.type, f.src_path, album.dst_path, self.settings

Expand Down
2 changes: 1 addition & 1 deletion sigal/pkgmeta.py
Expand Up @@ -22,7 +22,7 @@

__title__ = 'sigal'
__author__ = 'Simon Conseil'
__version__ = '0.8.0'
__version__ = '0.9.0-dev'
__license__ = 'MIT'
__url__ = 'https://github.com/saimn/sigal'
__all__ = ['__title__', '__author__', '__version__', '__license__', '__url__']
6 changes: 6 additions & 0 deletions sigal/templates/sigal.conf.py
Expand Up @@ -138,6 +138,12 @@
# Plugins
# --------

# List of plugins to use. The values must be a path than can be imported.
# Another option is to import the plugin and put the module in the list, but
# this will break with the multiprocessing feature (the settings dict obtained
# from this file must be serializable).
# plugins = ['sigal.plugins.adjust', 'sigal.plugins.copyright']

# Add a copyright text on the image (default: '')
# copyright = "© An example copyright message"

Expand Down
6 changes: 4 additions & 2 deletions sigal/video.py
Expand Up @@ -44,15 +44,17 @@ def check_subprocess(cmd, source, outname):
returncode, stdout, stderr = call_subprocess(cmd)
except KeyboardInterrupt:
logger.debug('Process terminated, removing file %s', outname)
os.remove(outname)
if os.path.isfile(outname):
os.remove(outname)
raise

if returncode:
logger.error('Failed to process ' + source)
logger.debug('STDOUT:\n %s', stdout)
logger.debug('STDERR:\n %s', stderr)
logger.debug('Process failed, removing file %s', outname)
os.remove(outname)
if os.path.isfile(outname):
os.remove(outname)


def video_size(source):
Expand Down
3 changes: 1 addition & 2 deletions tests/sample/sigal.conf.py
Expand Up @@ -8,8 +8,7 @@
links = [('Example link', 'http://example.org'),
('Another link', 'http://example.org')]

from sigal.plugins import copyright
plugins = ['sigal.plugins.adjust', copyright]
plugins = ['sigal.plugins.adjust', 'sigal.plugins.copyright']
copyright = u"© An example copyright message"
adjust_options = {'color': 0.0, 'brightness': 1.0,
'contrast': 1.0, 'sharpness': 0.0}
Expand Down
14 changes: 14 additions & 0 deletions tests/test_cli.py
Expand Up @@ -4,6 +4,7 @@
from click.testing import CliRunner

from sigal import init
from sigal import serve


def test_init(tmpdir):
Expand All @@ -18,3 +19,16 @@ def test_init(tmpdir):
assert result.exit_code == 1
assert result.output == ("Found an existing config file, will abort to "
"keep it safe.\n")

def test_serve(tmpdir):
config_file = str(tmpdir.join('sigal.conf.py'))
runner = CliRunner()
result = runner.invoke(init, [config_file])
assert result.exit_code == 0

result = runner.invoke(serve)
assert result.exit_code == 2

result = runner.invoke(serve, ['-c', config_file])
assert result.exit_code == 1

11 changes: 7 additions & 4 deletions tests/test_gallery.py
Expand Up @@ -79,18 +79,21 @@ def test_media(settings):
assert str(m) == file_path


def test_media_orig(settings):
def test_media_orig(settings, tmpdir):
settings['keep_orig'] = False
m = Media('11.jpg', 'dir1/test1', settings)
assert m.big is None

settings['keep_orig'] = True
settings['destination'] = str(tmpdir)

m = Image('11.jpg', 'dir1/test1', settings)
assert m.big == 'original/11.jpg'

m = Video('file.ogv', 'video', settings)
assert m.filename == 'file.webm'
assert m.big == 'original/file.ogv'
m = Video('stallman software-freedom-day-low.ogv', 'video', settings)
assert m.filename == 'stallman software-freedom-day-low.webm'
assert m.big == 'original/stallman software-freedom-day-low.ogv'
assert os.path.isfile(join(settings['destination'], m.path, m.big))


def test_image(settings, tmpdir):
Expand Down

0 comments on commit af3ead7

Please sign in to comment.