Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: wmark/thot
base: b753258482
...
head fork: wmark/thot
compare: 2f0055be5f
  • 3 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
Commits on Aug 28, 2011
W. Mark Kubacki 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
W. Mark Kubacki Files can optionally be pre-compressed by GZIP. Will decrease load on…
… busy sites running state-of-the-art webserver software.
309b953
W. Mark Kubacki Version bump to 0.9.1 2f0055b
4 src/thot/__init__.py
View
@@ -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)
18 src/thot/app.py
View
@@ -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)
50 src/thot/core.py
View
@@ -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)
-
7 src/thot/utils.py
View
@@ -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.