__all__ = [
# Globals
- "cfg", # configuration from webber.ini
- "directories", # global hash of directories, by rel_path
- "files", # global hash of files, by rel_path
- "functions", # all exported template functions
+ "cfg", # configuration from webber.ini
+ "directories", # global hash of directories, by rel_path
+ "files", # global hash of files, by rel_path
+ "functions", # all exported template functions
# Functions
- "set_hook", # decorator for hook-functions
- "set_macro", # define macro
+ "set_hook", # decorator for hook-functions
+ "set_macro", # define macro
"set_function", # define functions for the template
"get_file_for",
"get_link_from",
"get_current_file", # because mako-called functions cannot access the
- # current File object
+ # current File object
"get_program_directory",
- "log", # misc logging functions
+ "log", # misc logging functions
"info",
"warning",
"error",
def __init__(self, **kw):
Holder.__init__(self, **kw)
- directories[kw["rel_path"]] = self
+ kw["rel_path"] = self
+ if self.rel_path == "":
+ self.rel_path = "."
+ directories[self.rel_path] = self
+ try:
+ self.load(os.path.join(self.abs_path, "directory.conf"))
+ #print self
+ except IOError:
+ pass
+
+ def __repr__(self):
+ return "<Directory %s>" % self.rel_path
files = {}
Holder.__init__(self, **kw)
files[kw["rel_path"]] = self
self.render = None
+ self.contents = None
mtime = os.stat(self.path)[stat.ST_MTIME]
self.mtime = mtime
self.ctime = mtime
if read_keywords:
s = s.strip()
#print "kwd:", s
- if s==terminate_line:
+ if s == terminate_line:
read_keywords = False
continue
# Warn about long titles / long linktitles
if len(self.linktitle) > 20:
- log('%s: define a shorter "linktitle: xxx"')
+ log('%s: define a shorter linktitle' % self.rel_path)
self.contents = "".join(txt)
+ def __repr__(self):
+ return "<File %s>" % self.rel_path
+
_get_file_for_cache = {}
def get_file_for(name):
"""webber.files is an hash of File objects, but keyed on the real file name.
This function returns a File object for a specific linktitle."""
-
+
try:
return _get_file_for_cache[name]
except:
#print " via linktitle:", s
_get_file_for_cache[name] = f
return f
+ if f.title == name:
+ #print " via title:", s
+ _get_file_for_cache[name] = f
+ return f
except:
pass
# Allow exact match as well
def get_link_from(source, dest):
- #print "get_link_from", source, dest
- #print source
+ if dest is None:
+ raise KeyError
if not isinstance(source, File):
source = get_file_for(source)
if not source:
if not isinstance(dest, File):
dest = get_file_for(dest)
if not dest:
- print "NO DEST"
+ warning("unknown link from %s to %s" % (source.rel_path, dest))
return "."
rel_path = relpath(directories[source.direc].abs_path, directories[dest.direc].abs_path)
try:
if rel_path.startswith("./"):
rel_path = rel_path[2:]
#print " from path:", source.out_path
- #print " to path: ", out_path
+ #print " to path: ", out_path
#print " rel path: ", rel_path
return rel_path
#
# Logging
#
- # 1 Error
- # 2 Warning
- # 3 Info
- # 4 Log
+ # 1 Error
+ # 2 Warning
+ # 3 Info
+ # 4 Log
# 5... Debug
#
def log(s, level=4):
- if level>4:
+ if level > 4:
indent = " " * (level-4)
else:
indent = ""
# IkiWiki does something like this:
# At startup:
- # getopt modify ARGV
- # checkconfig check configuration
- # refresh allow plugins to build source files
+ # getopt modify ARGV
+ # checkconfig check configuration
+ # refresh allow plugins to build source files
# While scanning files:
- # needsbuild detect if page needs to be rebuild
- # filter arbitrary changes
- # scan collect metadata
+ # needsbuild detect if page needs to be rebuild
+ # filter arbitrary changes
+ # scan collect metadata
# While rendering files:
- # filter arbitrary changes
- # preprocess execute macros
- # linkify change wikilinks into links
- # htmlize turns text into html
- # sanitize sanitize html
- # templatefile allows changing of the template on a per-file basis
- # pagetemplate fill template with page
- # format similar to sanitize, but act on whole page body
+ # filter arbitrary changes
+ # preprocess execute macros
+ # linkify change wikilinks into links
+ # htmlize turns text into html
+ # sanitize sanitize html
+ # templatefile allows changing of the template on a per-file basis
+ # pagetemplate fill template with page
+ # format similar to sanitize, but act on whole page body
# At the end:
- # savestate plugins can save their state
+ # savestate plugins can save their state
#
#
# We do something like this:
#
# At startup:
- # addoptions allow plugins to add command-line options
- # checkconfig check configuration
- # start
+ # addoptions allow plugins to add command-line options
+ # checkconfig check configuration
+ # start
# While reading files:
- # read ask any reader (plugins!) to read the file
- # filter ask anybody to filter the contents
+ # read ask any reader (plugins!) to read the file
+ # filter ask anybody to filter the contents
# While scanning files:
- # scan called per file, let plugins act on file data
- # scan_done Allows post-processing of scanned data
+ # scan called per file, let plugins act on file data
+ # scan_done Allows post-processing of scanned data
# While rendering files:
- # htmlize turns text into html-part
- # linkify convert link macros to HTML
- # pagetemplate ask template engine (plugin!) to generate HTML out
- # of template and body part
+ # htmlize turns text into html-part
+ # linkify convert link macros to HTML
+ # pagetemplate ask template engine (plugin!) to generate HTML out
+ # of template and body part
# At the end:
# finish
#
def load_plugins():
"""Loads all plugins in the plugins directory."""
sys.path.append(os.path.join(get_program_directory(), "plugins"))
+ if cfg.has_key("plugin_dirs"):
+ for s in cfg.plugin_dirs:
+ sys.path.append(s)
for s in cfg.plugins:
- #print "import:", s
- #try:
exec "import %s" % s
- #except:
- # print "Could not import plugin '%s'" % s
- # sys.exit(1)
def set_hook(name, last=False):
try:
t = time.strptime(val, "%Y-%m-%d")
except ValueError:
- warning("%s: wrong ISO format in '%s'" % (self.rel_path, s))
+ warning("wrong ISO format in '%s'" % val)
return int(time.mktime(t))
@set_function("format_date")
- def format_date(timestamp):
- return time.strftime(cfg.date_format, time.localtime(timestamp))
+ def format_date(timestamp, format=None):
+ if not format:
+ format = cfg.date_format
+ return time.strftime(format, time.localtime(timestamp))
@set_function("get_time")
- def get_time():
- return format_date(time.time())
+ def get_time(format=None):
+ return format_date(time.time(), format)
@set_function("get_current_file")
def get_current_file():
return current_file
+@set_function("get_path_to_root")
+def get_path_to_root():
+ rel_path = relpath(directories[current_file.direc].abs_path, directories[''].abs_path)
+ rel_path = os.path.join(rel_path, os.path.split("")[1])
+ if rel_path[-1] == "/":
+ rel_path = rel_path[:-1]
+ return rel_path
return_holder=False)
if not contents:
return
+ file.contents = contents
log("filtering file %s" % file.rel_path, level=6)
- file.contents = contents
res = run_hooks("filter",
direc=direc,
file=file)
full_path = os.path.join(dirpath, s)
ok = True
if os.path.isdir(full_path):
- for e in cfg.exclude_dir:
+ for e in cfg.exclude_dirs:
if fnmatch.fnmatchcase(s, e):
log("ignoring directory %s" % s, level=7)
ok = False
)
file.inheritFrom(direc)
read_file(direc, file)
-
+
walk(dirpath)
#
reMacro = re.compile(r'''
- \[\[\! # Begin of macro
+ \[\[\! # Begin of macro
\s*
- ([^\s\]]+) # Macro name
+ ([^\s\]]+) # Macro name
(?:
- \s+ # optional space
- ([^\]]+) # optional argumens
+ \s+ # optional space
+ ([^\]]+) # optional argumens
)?
- \]\] # End of macro
+ \]\] # End of macro
''', re.VERBOSE)
reMacroArgs = re.compile(r'''
([-_\w]+) # parameter name
=
\s*
(?:
- "([^"]*)" # single-quoted
+ "([^"]*)" # single-quoted
|
- (\S+) # unquoted
+ (\S+) # unquoted
)
)?
''', re.VERBOSE)
s = reMacro.sub(do_macro, contents)
#print s
return s
-
+
def scan_files():
info("Scanning files ...")
for s in files:
file = files[s]
- try:
- # Just check if the file has contents
- contents = file.contents
- except:
+ if not file.has_key("contents"):
continue
+ # try:
+ # # Just check if the file has contents
+ # contents = file.contents
+ # except:
+ # continue
direc = directories[file.direc]
+ # "calculate" output file name
+ if file.render and file.render == "html":
+ file.out_path = os.path.splitext(s)[0] + ".html"
+
run_hooks("scan",
direc=direc,
file=file)
continue
file.contents = contents
- # Output-Filename "berechnen"
- file.out_path = os.path.splitext(fname_in)[0] + ".html"
-
for fname_in in files:
file = files[fname_in]
current_file = file
continue
direc = directories[file.direc]
- contents = run_hooks("linkify",
+ run_hooks("linkify",
direc=direc,
file=file,
- return_holder=False)
+ return_holder=True)
#print "contents after 'linkify':", contents
- if not contents:
+ if not file.contents:
continue
- file.contents = contents
- # TODO: einige Fragmente sollen u.U. in eine andere
- # Webseite eingebaut werden und sollten daher nicht in
- # ein HTML-File landen
+ # TODO: make it possible to render also "fragments", e.g.
+ # parts that don't end up immediately in a the HTML file.
contents = run_hooks("pagetemplate",
direc=direc,
file=file,
except OSError:
pass
- # TODO: evtl. überprüfen, ob contents == f.read(), dann nicht schreiben
+ # TODO: check if contents == f.read(). In this case we don't
+ # need to save. Probably overkill.
log("writing file %s" % fname_out, level=6)
f = open(fname_out, "w")
f.write(contents)
f.close()
- # TODO: Time-Stamps setzen?
+ os.utime(fname_out, (file.mtime, file.mtime))
#print file.mtime, file.get("ctime","?")
#print direc.keys()
return parser
-
+
@set_hook("checkconfig", last=True)
def checkconfig(params):
# Ensure absolute paths that end in '/'.
# link contents of webber.ini into cfg and set some defaults,
# then let plugins fixup things in cfg.*
cfg.inheritFrom(options)
- cfg.setDefault("exclude_dir", ["plugins"])
+ cfg.setDefault("exclude_dirs", [])
+ cfg.setDefault("exclude_files", ["webber.conf", "directory.conf", "*.tmpl"])
+ cfg.setDefault("copy_files", [])
+ cfg.setDefault("input_encoding", "iso-8859-1")
+ cfg.setDefault("output_encoding", "iso-8859-1")
+ cfg.setDefault("template", "default")
run_hooks("checkconfig")
run_hooks("start")