def autocompile(ws, conf, env, **options): """Subcommand: autocompile -- automatically re-compiles when something in content-dir has changed and parallel serving files.""" CONF_PY = './conf.py' mtime = -1 cmtime = getmtime(CONF_PY) while True: ntime = max( max(getmtime(e) for e in readers.filelist(conf['content_dir']) if utils.istext(e)), max(getmtime(p) for p in readers.filelist(conf['layout_dir']))) if mtime != ntime: try: compile(conf, env, **options) except AcrylamidException as e: log.fatal(e.args[0]) pass event.reset() mtime = ntime if cmtime != getmtime(CONF_PY): log.info(' * Restarting due to change in %s' % (CONF_PY)) # Kill the webserver ws.shutdown() # Force compilation since no template was changed argv = sys.argv if options['force'] else sys.argv[:] + ["--force"] # Restart acrylamid os.execvp(sys.argv[0], argv) time.sleep(1)
def run(conf, env, options): """Subcommand: info -- a short overview of a blog.""" limit = options.max if options.max > 0 else 5 entrylist = sorted( [ Entry(e, conf) for e in utils.filelist(conf["content_dir"], conf.get("entries_ignore", [])) if utils.istext(e) ], key=lambda k: k.date, reverse=True, ) print print "acrylamid", blue(env["version"]) + ",", print "cache size:", blue("%0.2f" % (cache.size / 1024.0 ** 2)) + " mb" print for entry in entrylist[:limit]: print " ", green(ago(entry.date).ljust(13)), print white(entry.title) if entry.draft else entry.title print print "%s published," % blue(len([e for e in entrylist if not e.draft])), print "%s drafted articles" % blue(len([e for e in entrylist if e.draft])) time = localtime(getmtime(join(conf.get("cache_dir", ".cache/"), "info"))) print "last compilation at %s" % blue(strftime("%d. %B %Y, %H:%M", time))
def load(conf): """Load and parse textfiles from content directory and optionally filter by an ignore pattern. Filenames ending with a known binary extension such as audio, video or images are ignored. If not blacklisted open the file end check if it :func:`utils.istext`. This function is *not* exception-tolerant. If Acrylamid could not handle a file it will raise an exception. It returns a tuple containing the list of entries sorted by date reverse (newest comes first) and other pages (unsorted). :param conf: configuration with CONTENT_DIR and CONTENT_IGNORE set""" # list of Entry-objects reverse sorted by date. entrylist, pages = [], [] # collect and skip over malformed entries for path in filelist(conf['content_dir'], conf.get('content_ignore', [])): if path.endswith(('.txt', '.rst', '.md')) or istext(path): try: entry = Entry(path, conf) if entry.type == 'entry': entrylist.append(entry) else: pages.append(entry) except (ValueError, AcrylamidException) as e: raise AcrylamidException('%s: %s' % (path, e.args[0])) # sort by date, reverse return (sorted(entrylist, key=lambda k: k.date, reverse=True), pages)
def autocompile(ws, conf, env): """Subcommand: autocompile -- automatically re-compiles when something in content-dir has changed and parallel serving files.""" mtime = -1 cmtime = getmtime('conf.py') while True: ws.wait = True ntime = max( max(getmtime(e) for e in readers.filelist( conf['content_dir'], conf.get('content_ignore', [])) if istext(e)), max(getmtime(p) for p in readers.filelist( conf['theme'], conf.get('theme_ignore', [])))) if mtime != ntime: try: compile(conf, env) except (SystemExit, KeyboardInterrupt) as e: raise e except Exception as e: log.fatal(e.args[0]) event.reset() mtime = ntime ws.wait = False if cmtime != getmtime('conf.py'): log.info(' * Restarting due to change in conf.py') # Kill the webserver ws.shutdown() # Restart acrylamid os.execvp(sys.argv[0], sys.argv) time.sleep(1)
def autocompile(ws, conf, env, **options): """Subcommand: autocompile -- automatically re-compiles when something in content-dir has changed and parallel serving files.""" CONF_PY = './conf.py' mtime = -1 cmtime = getmtime(CONF_PY) while True: ntime = max( max( getmtime(e) for e in readers.filelist(conf['content_dir']) if utils.istext(e)), max(getmtime(p) for p in readers.filelist(conf['layout_dir']))) if mtime != ntime: try: compile(conf, env, **options) except AcrylamidException as e: log.fatal(e.args[0]) pass event.reset() mtime = ntime if cmtime != getmtime(CONF_PY): log.info(' * Restarting due to change in %s' % (CONF_PY)) # Kill the webserver ws.shutdown() # Force compilation since no template was changed argv = sys.argv if options['force'] else sys.argv[:] + ["--force"] # Restart acrylamid os.execvp(sys.argv[0], argv) time.sleep(1)
def autocompile(conf, env, **options): """Subcommand: autocompile -- automatically re-compiles when something in content-dir has changed and parallel serving files.""" mtime = -1 while True: ntime = max(getmtime(e) for e in utils.filelist(conf['content_dir']) if utils.istext(e)) if mtime != ntime: try: compile(conf, env, **options) except AcrylamidException as e: log.fatal(e.args[0]) pass mtime = ntime time.sleep(1)
def load(conf): """Load and parse textfiles from content directory and optionally filter by an ignore pattern. Filenames ending with a known binary extension such as audio, video or images are ignored. If not blacklisted open the file end check if it :func:`utils.istext`. This function is *not* exception-tolerant. If Acrylamid could not handle a file it will raise an exception. It returns a tuple containing the list of entries sorted by date reverse (newest comes first) and other pages (unsorted). :param conf: configuration with CONTENT_DIR and CONTENT_IGNORE set""" # list of Entry-objects reverse sorted by date. entries, pages, trans, drafts = [], [], [], [] # check for hash collisions seen = set([]) # collect and skip over malformed entries for path in filelist(conf['content_dir'], conf['content_ignore']): if path.endswith(('.txt', '.rst', '.md')) or istext(path): try: entry = Entry(path, conf) if entry in seen: raise RuntimeError( "REPORT THIS IMMEDIATELY: python's hash function is not safe!") seen.add(entry) if entry.draft: drafts.append(entry) elif entry.type == 'entry': entries.append(entry) else: pages.append(entry) except: log.fatal('uncaught exception for ' + path) raise # sort by date, reverse return sorted(entries, key=lambda k: k.date, reverse=True), pages, trans, drafts
def autocompile(ws, conf, env): """Subcommand: autocompile -- automatically re-compiles when something in content-dir has changed and parallel serving files.""" mtime = -1 cmtime = getmtime('conf.py') while True: ws.wait = True ntime = max( max(getmtime(e) for e in readers.filelist( conf['content_dir'], conf['content_ignore']) if istext(e)), max(getmtime(p) for p in chain( readers.filelist(conf['theme'], conf['theme_ignore']), chain(*map( lambda s: readers.filelist(s, conf['static_ignore']), conf['static']))))) if mtime != ntime: try: compile(conf, env) except (SystemExit, KeyboardInterrupt): raise except Exception: log.exception("uncaught exception during auto-compilation") else: conf = load(env.options.conf) event.reset() mtime = ntime ws.wait = False if cmtime != getmtime('conf.py'): log.info(' * Restarting due to change in conf.py') # Kill the webserver ws.shutdown() # Restart acrylamid os.execvp(sys.argv[0], sys.argv) time.sleep(1)
def compile(conf, env, force=False, **options): """The compilation process. Current API: #. when we require context #. when we called an event New API: #. before we start with view Initialization #. after we initialized views #. before we require context #. after we required context #. before we template #. before we write a file #. when we called an event #. when we finish """ # time measurement ctime = time.time() # populate env and corrects some conf things request = initialize(conf, env) if force: # acrylamid compile -f cache.clear() # list of Entry-objects reverse sorted by date. entrylist = sorted([Entry(e, conf) for e in utils.filelist(conf['content_dir'], conf.get('entries_ignore', [])) if utils.istext(e)], key=lambda k: k.date, reverse=True) # here we store all found filter and their aliases ns = defaultdict(set) # get available filter list, something like with obj.get-function # list = [<class head_offset.Headoffset at 0x1014882c0>, <class html.HTML at 0x101488328>,...] aflist = filters.get_filters() # ... and get all configured views _views = views.get_views() # filters found in all entries, views and conf.py found = sum((x.filters for x in entrylist+_views), []) + request['conf']['filters'] for val in found: # first we for `no` and get the function name and arguments f = val[2:] if val.startswith('no') else val fname, fargs = f.split('+')[:1][0], f.split('+')[1:] try: # initialize the filter with its function name and arguments fx = aflist[fname](conf, env, val, *fargs) if val.startswith('no'): fx = filters.disable(fx) except ValueError: try: fx = aflist[val.split('+')[:1][0]](conf, env, val, *fargs) except ValueError: raise AcrylamidException('no such filter: %s' % val) ns[fx].add(val) for entry in entrylist: for v in _views: # a list that sorts out conflicting and duplicated filters flst = filters.FilterList() # filters found in this specific entry plus views and conf.py found = entry.filters + v.filters + request['conf']['filters'] for fn in found: fx, _ = next((k for k in ns.iteritems() if fn in k[1])) if fx not in flst: flst.append(fx) # sort them ascending because we will pop within filters.add entry.filters.add(sorted(flst, key=lambda k: (-k.priority, k.name)), context=v.__class__.__name__) # lets offer a last break to populate tags or so # XXX this API component needs a review for v in _views: env = v.context(env, {'entrylist': filter(v.condition, entrylist)}) # now teh real thing! for v in _views: # XXX the entry should automatically determine its caller (using # some sys magic to recursively check wether the calling class is # derieved from `View`.) for entry in entrylist: entry.context = v.__class__.__name__ request['entrylist'] = filter(v.condition, entrylist) tt = time.time() for html, path in v.generate(request): helpers.mkfile(html, path, time.time()-tt, **options) tt = time.time() # remove abandoned cache files cache.shutdown() # print a short summary log.info('%i new, %i updated, %i skipped [%.2fs]', event.count('create'), event.count('update'), event.count('identical') + event.count('skip'), time.time() - ctime)