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(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 create(directory, path): """A shortcut for check if exists and shutil.copy to.""" dest = join(root, directory, basename(path)) if not isfile(dest) or options.overwrite == True: try: shutil.copy(path, dest) log.info('create %s', dest) except IOError as e: log.fatal(unicode(e)) else: log.info('skip %s already exists', dest)
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 whitelist of extensions are processed. 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, CONTENT_EXTENSION and CONTENT_IGNORE set""" # list of Entry-objects reverse sorted by date. entries, pages, trans, drafts = [], [], [], [] # config content_extension originally defined as string, not a list exts = conf.get('content_extension', ['.txt', '.rst', '.md']) if isinstance(exts, string_types): whitelist = (exts, ) else: whitelist = tuple(exts) # collect and skip over malformed entries for path in filelist(conf['content_dir'], conf['content_ignore']): if path.endswith(whitelist): try: entry = Entry(path, conf) if entry.draft: drafts.append(entry) elif entry.type == 'entry': entries.append(entry) else: pages.append(entry) except AcrylamidException as e: log.exception('failed to parse file %s (%s)' % (path, e)) 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 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 load(conf): """Load and parse textfiles from content directory and optionally filter by an ignore pattern. Filenames ending with a known whitelist of extensions are processed. 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, CONTENT_EXTENSION and CONTENT_IGNORE set""" # list of Entry-objects reverse sorted by date. entries, pages, trans, drafts = [], [], [], [] # config content_extension originally defined as string, not a list exts = conf.get('content_extension',['.txt', '.rst', '.md']) if isinstance(exts, string_types): whitelist = (exts,) else: whitelist = tuple(exts) # collect and skip over malformed entries for path in filelist(conf['content_dir'], conf['content_ignore']): if path.endswith(whitelist): try: entry = Entry(path, conf) if entry.draft: drafts.append(entry) elif entry.type == 'entry': entries.append(entry) else: pages.append(entry) except AcrylamidException as e: log.exception('failed to parse file %s (%s)' % (path, e)) 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 Acryl(): """The main function that dispatches the CLI. We use :class:`AcrylFormatter` as custom help formatter that ommits the useless list of available subcommands and their aliases. All flags from acrylamid --help are also available in subcommands altough not explicitely printed in their help.""" parser = argparse.ArgumentParser( parents=[], formatter_class=AcrylFormatter ) parser.add_argument("-v", "--verbose", action="store_const", dest="verbosity", help="more verbose", const=log.SKIP, default=log.INFO) parser.add_argument("-q", "--quiet", action="store_const", dest="verbosity", help="less verbose", const=log.WARN) parser.add_argument("-C", "--no-color", action="store_false", dest="colors", help="disable color", default=True) parser.add_argument("--conf", dest="conf", help="alternate conf.py", default="conf.py", metavar="/path/to/conf") parser.add_argument("--version", action="version", version=colors.blue('Acrylamid ') + __version__) subparsers = parser.add_subparsers(dest="parser") # a repeat yourself of default arguments but not visible on subcommand --help default = argparse.ArgumentParser(add_help=False) default.add_argument("-v", "--verbose", action="store_const", dest="verbosity", help=argparse.SUPPRESS, const=log.SKIP, default=log.INFO) default.add_argument("-q", "--quiet", action="store_const", dest="verbosity", help=argparse.SUPPRESS, const=log.WARN) default.add_argument("-C", "--no-color", action="store_false", dest="colors", help=argparse.SUPPRESS, default=True) # --- gen params --- # generate = subparsers.add_parser('compile', help='compile blog', parents=[default]) generate.add_argument("-f", "--force", action="store_true", dest="force", help="clear cache before compilation", default=False) generate.add_argument("-n", "--dry-run", dest="dryrun", action='store_true', help="show what would have been compiled", default=False) generate.add_argument("--ignore", dest="ignore", action="store_true", help="ignore critical errors", default=False) generate.add_argument("--search", dest="search", action="store_true", help="build search index", default=False) # --- webserver params --- # view = subparsers.add_parser('view', help="fire up built-in webserver", parents=[default]) view.add_argument("-p", "--port", dest="port", type=int, default=8000, help="webserver port") # --- aco params --- # autocompile = subparsers.add_parser('autocompile', help="automatic compilation and serving", parents=[default]) autocompile.add_argument("-f", "--force", action="store_true", dest="force", help="clear cache before compilation", default=False) autocompile.add_argument("-n", "--dry-run", dest="dryrun", action='store_true', help="show what would have been compiled", default=False) autocompile.add_argument("--ignore", dest="ignore", action="store_true", help="ignore critical errors", default=False) autocompile.add_argument("--search", dest="search", action="store_true", help="build search index", default=False) autocompile.add_argument("-p", "--port", dest="port", type=int, default=8000, help="webserver port") for alias in ('co', 'gen', 'generate'): subparsers._name_parser_map[alias] = generate for alias in ('serve', 'srv'): subparsers._name_parser_map[alias] = view subparsers._name_parser_map['aco'] = autocompile # initialize other tasks tasks.initialize(subparsers, default) # parse args options = parser.parse_args() # initialize colored logger log.init('acrylamid', level=options.verbosity, colors=options.colors) env = core.Environment({'author': __author__, 'url': __url__}) env['options'] = options env['globals'] = Struct() # -- init -- # try: if options.parser in ('init', ): tasks.collected[options.parser](env, options) sys.exit(0) except AcrylamidException as e: log.fatal(e.args[0]) sys.exit(1) # -- teh real thing -- # conf = core.Configuration(defaults.conf) try: ns = dict([(k.upper(), v) for k, v in defaults.conf.iteritems()]) os.chdir(dirname(find(basename(options.conf), dirname(options.conf) or os.getcwd()))) execfile(options.conf, ns) conf.update(dict([(k.lower(), ns[k]) for k in ns if k.upper() == k])) except IOError: log.critical('no conf.py found. Try "acrylamid init".') sys.exit(1) except Exception as e: log.critical("%s in `conf.py`" % e.__class__.__name__) traceback.print_exc(file=sys.stdout) sys.exit(1) # -- run -- # if options.parser in ('gen', 'generate', 'co', 'compile'): log.setLevel(options.verbosity) try: commands.compile(conf, env) except AcrylamidException as e: log.fatal(e.args[0]) sys.exit(1) elif options.parser in ('srv', 'serve', 'view'): from acrylamid.lib.httpd import Webserver ws = partial(Webserver, options.port, conf['output_dir']) ws = ws(log.info) if options.verbosity < 20 else ws(); ws.start() log.info(' * Running on http://127.0.0.1:%i/' % options.port) try: while True: time.sleep(1) except (SystemExit, KeyboardInterrupt) as e: ws.kill_received = True sys.exit(0) elif options.parser in ('aco', 'autocompile'): from acrylamid.lib.httpd import Webserver # XXX compile on request _or_ use inotify/fsevent ws = Webserver(options.port, conf['output_dir']); ws.start() log.info(' * Running on http://127.0.0.1:%i/' % options.port) try: commands.autocompile(ws, conf, env) except (SystemExit, KeyboardInterrupt) as e: ws.kill_received = True log.error(e.args[0]) traceback.print_exc(file=sys.stdout) sys.exit(0) elif options.parser in tasks.collected: try: tasks.collected[options.parser](conf, env, options) except AcrylamidException as e: log.critical(e.args[0]) sys.exit(1) else: log.critical('No such command!') sys.exit(2) sys.exit(0)
def Acryl(): """The main function that dispatches the CLI. We use :class:`AcrylFormatter` as custom help formatter that ommits the useless list of available subcommands and their aliases. All flags from acrylamid --help are also available in subcommands altough not explicitely printed in their help.""" parser = argparse.ArgumentParser( parents=[], formatter_class=AcrylFormatter ) parser.add_argument("-v", "--verbose", action="store_const", dest="verbosity", help="more verbose", const=log.SKIP, default=log.INFO) parser.add_argument("-q", "--quiet", action="store_const", dest="verbosity", help="less verbose", const=log.WARN) parser.add_argument("-C", "--no-color", action="store_false", dest="colors", help="disable color", default=True) parser.add_argument("--version", action="version", version=colors.blue('acrylamid ') + __version__) subparsers = parser.add_subparsers(dest="parser") # a repeat yourself of default arguments but not visible on subcommand --help default = argparse.ArgumentParser(add_help=False) default.add_argument("-v", "--verbose", action="store_const", dest="verbosity", help=argparse.SUPPRESS, const=log.SKIP, default=log.INFO) default.add_argument("-q", "--quiet", action="store_const", dest="verbosity", help=argparse.SUPPRESS, const=log.WARN) default.add_argument("-C", "--no-color", action="store_false", dest="colors", help=argparse.SUPPRESS, default=True) # --- gen params --- # generate = subparsers.add_parser('compile', help='compile blog', parents=[default]) generate.add_argument("-f", "--force", action="store_true", dest="force", help="clear cache before compilation", default=False) generate.add_argument("-n", "--dry-run", dest="dryrun", action='store_true', help="show what would have been compiled", default=False) generate.add_argument("-i", "--ignore", dest="ignore", action="store_true", help="ignore critical errors", default=False) # --- webserver params --- # view = subparsers.add_parser('view', help="fire up built-in webserver", parents=[default]) view.add_argument("-p", "--port", dest="port", type=int, default=8000, help="webserver port") # --- aco params --- # autocompile = subparsers.add_parser('autocompile', help="automatic compilation and serving", parents=[default]) autocompile.add_argument("-f", "--force", action="store_true", dest="force", help="clear cache before compilation", default=False) autocompile.add_argument("-n", "--dry-run", dest="dryrun", action='store_true', help="show what would have been compiled", default=False) autocompile.add_argument("-i", "--ignore", dest="ignore", action="store_true", help="ignore critical errors", default=False) autocompile.add_argument("-p", "--port", dest="port", type=int, default=8000, help="webserver port") for alias in ('co', 'gen', 'generate'): subparsers._name_parser_map[alias] = generate for alias in ('serve', 'srv'): subparsers._name_parser_map[alias] = view subparsers._name_parser_map['aco'] = autocompile new = subparsers.add_parser('new', help="create a new entry", parents=[default], epilog=("Takes all leading [args] as title or prompt if none given. creates " "a new entry based on your PERMALINK_FORMAT and opens it with your " "favourite $EDITOR.")) new.add_argument("title", nargs="*", default='') # initialize other tasks tasks.initialize(subparsers, default) # parse args options = parser.parse_args() # initialize colored logger log.init('acrylamid', level=options.verbosity, colors=options.colors) env = Struct({'version': __version__, 'author': __author__, 'url': __url__}) env['options'] = options env['globals'] = Struct() # -- init -- # # TODO: acrylamid init --layout_dir=somedir to overwrite defaults if options.parser in ('init', ): tasks.collected[options.parser](env, options) sys.exit(0) # -- teh real thing -- # conf = Struct(defaults.conf) try: ns = dict([(k.upper(), v) for k, v in defaults.conf.iteritems()]) os.chdir(os.path.dirname(find('conf.py', os.getcwd()))) execfile('conf.py', ns) conf.update(dict([(k.lower(), ns[k]) for k in ns if k.upper() == k])) except IOError: log.critical('no conf.py found. Try "acrylamid init".') sys.exit(1) except Exception as e: log.critical("%s in `conf.py`" % e.__class__.__name__) traceback.print_exc(file=sys.stdout) sys.exit(1) conf['output_dir'] = conf.get('output_dir', 'output/') conf['content_dir'] = conf.get('content_dir', 'content/') conf['layout_dir'] = conf.get('layout_dir', 'layouts/') # -- run -- # if options.parser in ('gen', 'generate', 'co', 'compile'): log.setLevel(options.verbosity) try: commands.compile(conf, env, **options.__dict__) except AcrylamidException as e: log.fatal(e.args[0]) sys.exit(1) elif options.parser in ('new', 'create'): try: commands.new(conf, env, title=' '.join(options.title), prompt=log.level()<log.WARN) except AcrylamidException as e: log.fatal(e.args[0]) sys.exit(1) elif options.parser in ('srv', 'serve', 'view'): from acrylamid.lib.httpd import Webserver ws = Webserver(options.port, conf['output_dir']); ws.start() log.info(' * Running on http://127.0.0.1:%i/' % options.port) try: while True: time.sleep(1) except (SystemExit, KeyboardInterrupt, Exception) as e: ws.kill_received = True sys.exit(0) elif options.parser in ('aco', 'autocompile'): from acrylamid.lib.httpd import Webserver # XXX compile on request _or_ use inotify/fsevent ws = Webserver(options.port, conf['output_dir']); ws.start() log.info(' * Running on http://127.0.0.1:%i/' % options.port) try: commands.autocompile(ws, conf, env, **options.__dict__) except (SystemExit, KeyboardInterrupt, Exception) as e: ws.kill_received = True log.error(e.args[0]) traceback.print_exc(file=sys.stdout) sys.exit(0) elif options.parser in tasks.collected: try: tasks.collected[options.parser](conf, env, options) except AcrylamidException as e: log.critical(e.args[0]) sys.exit(1) else: log.critical('No such command!') sys.exit(2) sys.exit(0)
sys.exit(1) conf['output_dir'] = conf.get('output_dir', 'output/') conf['content_dir'] = conf.get('content_dir', 'content/') conf['layout_dir'] = conf.get('layout_dir', 'layouts/') assert defaults.check_conf(conf) conf.update(dict((k, v) for k, v in options.__dict__.iteritems() if v != None)) # -- run -- # if options.parser in ('gen', 'generate', 'co', 'compile'): log.setLevel(options.verbosity) try: commands.compile(conf, env, **options.__dict__) except AcrylamidException as e: log.fatal(e.args[0]) sys.exit(1) elif options.parser in ('new', 'create'): try: commands.new(conf, env, title=' '.join(options.title), prompt=log.level()<log.WARN) except AcrylamidException as e: log.fatal(e.args[0]) sys.exit(1) elif options.parser in ('srv', 'serve', 'view'): from acrylamid.lib.httpd import Webserver ws = Webserver(options.port, conf['output_dir']); ws.start() log.info(' * Running on http://127.0.0.1:%i/' % options.port) try: