Browse Source

Added optipng plugin

main
Lakshmi Vyasarajan 14 years ago
parent
commit
690aa4f4d7
7 changed files with 158 additions and 21 deletions
  1. +70
    -0
      hyde/ext/plugins/optipng.py
  2. +33
    -19
      hyde/fs.py
  3. +5
    -1
      hyde/plugin.py
  4. +1
    -0
      hyde/tests/ext/optipng/hyde-lt-b.png
  5. +1
    -1
      hyde/tests/ext/test_less.py
  6. +45
    -0
      hyde/tests/ext/test_optipng.py
  7. +3
    -0
      hyde/tests/test_fs.py

+ 70
- 0
hyde/ext/plugins/optipng.py View File

@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
"""
OPTIPNG plugin
"""

from hyde.plugin import CLTransformer
from hyde.fs import File

class OptiPNGPlugin(CLTransformer):
"""
The plugin class for OptiPNG
"""

def __init__(self, site):
super(OptiPNGPlugin, self).__init__(site)

@property
def plugin_name(self):
"""
The name of the plugin.
"""
return "optipng"

def option_prefix(self, option):
return "-"

def binary_resource_complete(self, resource):
"""
If the site is in development mode, just return.
Otherwise, run optipng to compress the png file.
"""

try:
mode = self.site.config.mode
except AttributeError:
mode = "production"

if not resource.source_file.kind == 'png':
return

if mode.startswith('dev'):
self.logger.debug("Skipping optipng in development mode.")
return

supported = [
"o",
"fix",
"force",
"preserve",
"quiet",
"log",
"f",
"i",
"zc",
"zm",
"zs",
"zw",
"full",
"nb",
"nc",
"np",
"nz"
]
target = File(self.site.config.deploy_root_path.child(
resource.relative_deploy_path))
optipng = self.app
args = [str(optipng)]
args.extend(self.process_args(supported))
args.extend([str(target)])
self.call_app(args)

+ 33
- 19
hyde/fs.py View File

@@ -13,6 +13,7 @@ import os
import shutil
from distutils import dir_util
import functools
import fnmatch

from hyde.util import getLoggerWithNullHandler

@@ -94,12 +95,12 @@ class FS(object):
Generates the parents until stop or the absolute
root directory is reached.
"""
f = self
while f.parent != stop:
if f.parent == f:
folder = self
while folder.parent != stop:
if folder.parent == folder:
return
yield f.parent
f = f.parent
yield folder.parent
folder = folder.parent

def is_descendant_of(self, ancestor):
"""
@@ -185,9 +186,22 @@ class File(FS):
"""
return self.extension.lstrip(".")

@property
def size(self):
"""
Size of this file.
"""

if not self.exists:
return -1
return os.path.getsize(self.path)

@property
def mimetype(self):
(mime, encoding) = mimetypes.guess_type(self.path)
"""
Gets the mimetype of this file.
"""
(mime, _) = mimetypes.guess_type(self.path)
return mime

@property
@@ -246,9 +260,9 @@ class File(FS):
import tempfile
(handle, path) = tempfile.mkstemp(text=True)
os.close(handle)
f = File(path)
f.write(text)
return f
afile = File(path)
afile.write(text)
return afile

def read_all(self, encoding='utf-8'):
"""
@@ -296,26 +310,26 @@ class FSVisitor(object):
self.folder = folder
self.pattern = pattern

def folder_visitor(self, f):
def folder_visitor(self, function):
"""
Decorator for `visit_folder` protocol
"""
self.visit_folder = f
return f
self.visit_folder = function
return function

def file_visitor(self, f):
def file_visitor(self, function):
"""
Decorator for `visit_file` protocol
"""
self.visit_file = f
return f
self.visit_file = function
return function

def finalizer(self, f):
def finalizer(self, function):
"""
Decorator for `visit_complete` protocol
"""
self.visit_complete = f
return f
self.visit_complete = function
return function

def __enter__(self):
return self
@@ -341,7 +355,7 @@ class FolderWalker(FSVisitor):
if not walk_files and not walk_folders:
return

for root, dirs, a_files in os.walk(self.folder.path, followlinks=True):
for root, _, a_files in os.walk(self.folder.path, followlinks=True):
folder = Folder(root)
if walk_folders:
yield folder


+ 5
- 1
hyde/plugin.py View File

@@ -262,6 +262,9 @@ class CLTransformer(Plugin):

return app

def option_prefix(self, option):
return "--"

def process_args(self, supported):
"""
Given a list of supported arguments, consutructs an argument
@@ -282,7 +285,8 @@ class CLTransformer(Plugin):
descriptive = short = arg

if descriptive in args or short in args:
result.append("--%s" % descriptive)
result.append("%s%s" % (self.option_prefix(descriptive),
descriptive))
val = args[descriptive if descriptive in args else short]
if val:
result.append(val)


+ 1
- 0
hyde/tests/ext/optipng/hyde-lt-b.png View File

@@ -0,0 +1 @@
../../../../resources/hyde-lt-b.png

+ 1
- 1
hyde/tests/ext/test_less.py View File

@@ -32,7 +32,7 @@ class TestLess(object):
paths = ['/usr/local/share/npm/bin/lessc', '~/local/bin/lessc']
less = [path for path in paths if File(path).exists]
if not less:
assert False, "Cannot find the uglify executable"
assert False, "Cannot find the lessc executable"
less = less[0]
s.config.less = Expando(dict(app=less))
source = TEST_SITE.child('content/media/css/site.less')


+ 45
- 0
hyde/tests/ext/test_optipng.py View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
"""
Use nose
`$ pip install nose`
`$ nosetests`
"""
from hyde.fs import File, Folder
from hyde.model import Expando
from hyde.generator import Generator
from hyde.site import Site

OPTIPNG_SOURCE = File(__file__).parent.child_folder('optipng')
TEST_SITE = File(__file__).parent.parent.child_folder('_test')


class TestOptipng(object):

def setUp(self):
TEST_SITE.make()
TEST_SITE.parent.child_folder(
'sites/test_jinja').copy_contents_to(TEST_SITE)
IMAGES = TEST_SITE.child_folder('content/media/images')
IMAGES.make()
OPTIPNG_SOURCE.copy_contents_to(IMAGES)


def tearDown(self):
TEST_SITE.delete()

def test_can_execute_optipng(self):
s = Site(TEST_SITE)
s.config.mode = "production"
s.config.plugins = ['hyde.ext.plugins.optipng.OptiPNGPlugin']
paths = ['/usr/local/bin/optipng']
optipng = [path for path in paths if File(path).exists]
if not optipng:
assert False, "Cannot find the optipng executable"
optipng = optipng[0]
s.config.optipng = Expando(dict(app=optipng, args=dict(quiet="")))
source =File(TEST_SITE.child('content/media/images/hyde-lt-b.png'))
target = File(Folder(s.config.deploy_root_path).child('media/images/hyde-lt-b.png'))
gen = Generator(s)
gen.generate_resource_at_path(source)
assert target.exists
assert target.size < source.size

+ 3
- 0
hyde/tests/test_fs.py View File

@@ -204,6 +204,9 @@ def test_is_image():
assert not HELPERS.is_image
assert LOGO.is_image

def test_file_size():
assert LOGO.size == 1942

@nottest
def setup_data():
DATA_ROOT.make()


Loading…
Cancel
Save