Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: wmark/thot
base: b753258482
...
head fork: wmark/thot
compare: 2f0055be5f
Checking mergeability… Don't worry, you can still create the pull request.
  • 3 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
Commits on Aug 28, 2011
@wmark Output files have the same modification date as their corresponding i…
…nput files.

"ctime" is not used anymore because changing file permissions does not affect the content,
which in turn shouldn't be reflected on any date or time webservers provide browsers with.
9d7518f
@wmark Files can optionally be pre-compressed by GZIP. Will decrease load on…
… busy sites running state-of-the-art webserver software.
309b953
@wmark Version bump to 0.9.1 2f0055b
View
4 src/thot/__init__.py
@@ -14,6 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-__version__ = "0.9"
+__version__ = "0.9.1"
version = __version__
-version_info = (0, 9)
+version_info = (0, 9, 1)
View
18 src/thot/app.py
@@ -8,6 +8,7 @@
exists, normpath
from shutil import copytree
import sys
+import time
import pytz
import pkg_resources
@@ -16,6 +17,12 @@
from thot.template import get_templating_cls
LOGGING_LEVELS = {'info': logging.INFO, 'debug': logging.DEBUG}
+GZIP_ENDINGS = [
+ '.css', '.js', '.xml', '.txt', '.sh', '.svg',
+ '.xls', '.doc', '.xjs', '.psd', '.ppt',
+ '.java', '.py', '.pyc', '.pyo', '.bat', '.dll', '.lib',
+ '.cfg', '.ini',
+ ]
def quickstart(settings):
login = getlogin()
@@ -46,7 +53,7 @@ def quickstart(settings):
# before writing the settings file, make sure the _lib dir exists
if not exists(settings['lib_dir']):
makedirs(settings['lib_dir'])
-
+
with open(settings['settings_path'], 'wb', encoding='utf-8') as configfile:
configfile.write(yaml.dump(config, default_flow_style=False))
@@ -63,6 +70,8 @@ def main():
parser.add_option('--hardlinks', action="store_true",
help="instead of copying static files, creates hardlinks" \
+ " - which is faster and saves space")
+ parser.add_option('-z', '--gzip', action="store_true",
+ help="make a gzip-compressed copy of rendered files")
parser.add_option('-t', '--templating', default='mako',
dest='templating_engine',
help="templating engine (e.g. jinja2, mako) for output")
@@ -74,7 +83,7 @@ def main():
project_dir = abspath(args[0])
except IndexError:
project_dir = abspath(getcwd())
-
+
settings = {'project_dir': project_dir,
'output_dir': join(project_dir, '_output'),
'template_dir': join(project_dir, '_templates'),
@@ -82,8 +91,11 @@ def main():
'url_path': join(project_dir, '_lib', 'urls.py'),
'settings_path': join(project_dir, '_lib', 'settings.cfg'),
'hardlinks': options.hardlinks,
+ 'make_compressed_copy': options.gzip,
+ 'compress_if_ending': GZIP_ENDINGS,
'templating_engine': options.templating_engine,
'source': options.source,
+ 'build_tz': pytz.timezone(time.strftime("%Z", time.gmtime())),
'build_time': pytz.utc.localize(datetime.utcnow())}
# configure logging
@@ -91,7 +103,7 @@ def main():
logging.basicConfig(level=logging_level,
format='%(asctime)s %(levelname)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
-
+
# quickstart
if options.quickstart:
quickstart(settings)
View
50 src/thot/core.py
@@ -1,17 +1,18 @@
-from codecs import open
+import codecs
from datetime import datetime
import imp
import logging
import types
-from os import makedirs
-from os.path import splitext, join, dirname, split, getctime, \
+from os import makedirs, utime
+from os.path import splitext, join, dirname, split, getmtime, \
basename, exists, relpath, isabs
-from shutil import rmtree, copytree
+from shutil import rmtree, copytree, copystat
import sys
import time
import pytz
import pkg_resources
import weakref
+import gzip
from thot import parser
from thot.url import get_url
@@ -216,8 +217,29 @@ def _write(self):
# write to filesystem
logging.debug("writing %s to %s", page['path'], output_path)
- with open(output_path, 'w', 'utf-8') as f:
+ with codecs.open(output_path, 'w', 'utf-8') as f:
f.write(rendered)
+ page_dt_for_fs = page['date'].astimezone(self.settings['build_tz'])
+ atime = mtime = int(time.mktime(page_dt_for_fs.timetuple()))
+ utime(output_path, (atime, mtime))
+
+ # GZIP output for webservers which support pre-compressed files
+ if self.settings['make_compressed_copy']:
+ gz_output_path = output_path+'.gz'
+ with gzip.GzipFile(gz_output_path, 'w', mtime=mtime) as f:
+ f.write(rendered.encode('utf-8'))
+ utime(gz_output_path, (atime, mtime))
+
+ def _copy_static_file(self, static_file, dst):
+ logging.debug('copying %s to %s', static_file, dst)
+ if copy_file(static_file, dst, self.settings['hardlinks']) \
+ and self.settings['make_compressed_copy']:
+ for ending in self.settings['compress_if_ending']:
+ if static_file.endswith(ending):
+ with open(static_file, 'rb') as fin, gzip.open(dst+'.gz', 'wb') as fout:
+ fout.writelines(fin)
+ copystat(static_file, dst+'.gz')
+ break
def _copy_static_files(self):
"Copies static files to output directory"
@@ -225,8 +247,7 @@ def _copy_static_files(self):
for static_file in self.static_files:
dst = join(self.settings['output_dir'],
relpath(static_file, self.settings['project_dir']))
- logging.debug('copying %s to %s', static_file, dst)
- copy_file(static_file, dst, self.settings['hardlinks'])
+ self._copy_static_file(static_file, dst)
# static files that are associated with pages
for page in self.pages:
@@ -234,8 +255,7 @@ def _copy_static_files(self):
dst = join(self.settings['output_dir'],
dirname(self._get_output_path(page['url'])),
relpath(static_file, dirname(page['path'])))
- logging.debug('copying %s to %s', static_file, dst)
- copy_file(static_file, dst, self.settings['hardlinks'])
+ self._copy_static_file(static_file, dst)
def run(self):
start_time = time.time()
@@ -322,7 +342,7 @@ def _create_page(self, path, static_files):
return page
def read(self, path):
- with open(join(self.project_dir, path), 'r', encoding='utf-8') as f:
+ with codecs.open(join(self.project_dir, path), 'r', encoding='utf-8') as f:
return f.read()
def _get_default_headers(self, path):
@@ -331,10 +351,9 @@ def _get_default_headers(self, path):
`path` - the relative path from the project dir to the file
`title` - titleized version of the filename
- `date` - set to ctime. On unix this is the time of the most recent
- metadata change; on windows the creation time. If ctime
- cannot be accessed (due to permissions), the current
- time is used.
+ `date` - set to mtime. This is the time of the most recent
+ content change. If mtime cannot be accessed (due
+ to permissions), the current time is used.
`status` - set to 'live'
`template` - set to 'default.html'
`url` - set to "default" rule
@@ -350,7 +369,7 @@ def _get_default_headers(self, path):
slug = filename
title = filename.title()
try:
- date = pytz.utc.localize(datetime.utcfromtimestamp(getctime(path)))
+ date = pytz.utc.localize(datetime.utcfromtimestamp(getmtime(path)))
except OSError:
# use the current date if the ctime cannot be accessed
date = self.build_time
@@ -359,4 +378,3 @@ def _get_default_headers(self, path):
title=title, date=date, status='live',
slug=slug, template=template, url='default',
output_ext=output_ext)
-
View
7 src/thot/utils.py
@@ -92,16 +92,17 @@ def copy_file(src, dst, hardlinks=False):
if os.path.isfile(dst):
if equivalent_files(src, dst):
- return
+ return False
try:
if hardlinks:
try:
os.link(src, dst)
- return
+ return True
except OSError:
logging.debug("Could not create hardlink for '%s'->'%s'.",
src, dst)
- shutil.copy(src, dst)
+ shutil.copy2(src, dst)
+ return True
except IOError:
logging.debug("Caught IOError when copying '%s'->'%s'.", src, dst)
pass

No commit comments for this range

Something went wrong with that request. Please try again.