# HG changeset patch # User Ludovic Chabant # Date 1393863316 28800 # Node ID fba20c625fb345659f787c355dd02e00e8b22395 # Parent 657edcb918043a60dbf7e693e85d3638af49aad0 Added `wk init` command to create a new wiki. diff -r 657edcb91804 -r fba20c625fb3 wikked/auth.py --- a/wikked/auth.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/auth.py Mon Mar 03 08:15:16 2014 -0800 @@ -36,6 +36,15 @@ self._updatePermissions(config) self._updateUserInfos(config) + def start(self, wiki): + pass + + def init(self, wiki): + pass + + def postInit(self): + pass + def getUsers(self): for user in self._users: yield self._createUser(user) diff -r 657edcb91804 -r fba20c625fb3 wikked/commands/manage.py --- a/wikked/commands/manage.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/commands/manage.py Mon Mar 03 08:15:16 2014 -0800 @@ -1,3 +1,6 @@ +import os +import os.path +import shutil import logging from wikked.commands.base import WikkedCommand, register_command @@ -6,6 +9,50 @@ @register_command +class InitCommand(WikkedCommand): + def __init__(self): + super(InitCommand, self).__init__() + self.name = 'init' + self.description = "Creates a new wiki" + self.requires_wiki = False + + def setupParser(self, parser): + parser.add_argument('destination', + help="The destination directory to create the wiki") + parser.add_argument('--hg', + help="Use Mercurial as a revision system (default)", + action='store_true') + parser.add_argument('--git', + help="Use Git as a revision system", + action='store_true') + parser.add_argument('--bare', + help="Don't create the default pages", + action='store_true') + + def run(self, ctx): + if ctx.args.git: + raise Exception("Git is not yet fully supported.") + + path = ctx.args.destination or os.getcwd() + path = os.path.abspath(path) + if not os.path.isdir(path): + os.makedirs(path) + + logger.info("Initializing new wiki at: %s" % path) + from wikked.wiki import WikiParameters, Wiki + parameters = WikiParameters(path) + wiki = Wiki(parameters, for_init=True) + wiki.init() + + if not ctx.args.bare: + src_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), + 'resources', 'init') + + shutil.copy(os.path.join(src_dir, 'Main page.md'), path) + shutil.copy(os.path.join(src_dir, 'Sandbox.md'), path) + + +@register_command class ResetCommand(WikkedCommand): def __init__(self): super(ResetCommand, self).__init__() diff -r 657edcb91804 -r fba20c625fb3 wikked/db/base.py --- a/wikked/db/base.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/db/base.py Mon Mar 03 08:15:16 2014 -0800 @@ -8,7 +8,13 @@ pass def start(self, wiki): - raise NotImplementedError() + pass + + def init(self, wiki): + pass + + def postInit(self): + pass def close(self): raise NotImplementedError() diff -r 657edcb91804 -r fba20c625fb3 wikked/db/sql.py --- a/wikked/db/sql.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/db/sql.py Mon Mar 03 08:15:16 2014 -0800 @@ -12,7 +12,7 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import ( scoped_session, sessionmaker, - relationship, backref, noload, load_only, subqueryload) + relationship, backref, load_only, subqueryload) from sqlalchemy.orm.exc import NoResultFound from wikked.db.base import Database from wikked.page import Page, PageData @@ -135,31 +135,10 @@ self._engine = None self._session = None - def start(self, wiki): - self.wiki = wiki - - def createDb(self): - create_schema = False - if self.engine_url != 'sqlite:///:memory:': - # The existing schema is outdated, re-create it. - schema_version = self._getSchemaVersion() - if schema_version < self.schema_version: - logger.debug( - "SQL database is outdated (got version %s), " - "will re-create.", - schema_version) - create_schema = True - else: - logger.debug( - "SQL database has up-to-date schema.") - else: - create_schema = True - if create_schema: - self._createSchema() - @property def engine(self): if self._engine is None: + logger.debug("Creating SQL engine from URL: %s" % self.engine_url) self._engine = create_engine(self.engine_url, convert_unicode=True) return self._engine @@ -173,6 +152,56 @@ bind=self.engine)) return self._session + def _needsSchemaUpdate(self): + if self.engine_url == 'sqlite:///:memory:': + # Always create the schema for a memory database. + return True + + # The existing schema is outdated, re-create it. + schema_version = self._getSchemaVersion() + if schema_version < self.schema_version: + logger.debug( + "SQL database is outdated (got version %s), " + "will re-create.", + schema_version) + return True + else: + logger.debug( + "SQL database has up-to-date schema.") + return False + + def _createSchema(self): + logger.debug("Creating new SQL schema.") + Base.metadata.drop_all(self.engine) + Base.metadata.create_all(self.engine) + + ver = SQLInfo() + ver.name = 'schema_version' + ver.int_value = self.schema_version + self.session.add(ver) + self.session.commit() + + def _getSchemaVersion(self): + try: + q = self.session.query(SQLInfo).\ + filter(SQLInfo.name == 'schema_version').\ + first() + if q is None: + return 0 + except: + return -1 + return q.int_value + + def init(self, wiki): + pass + + def postInit(self): + logger.info("Initializing SQL database.") + self._createSchema() + + def start(self, wiki): + self.wiki = wiki + def close(self, commit, exception): if self._session is not None: if commit and exception is None: @@ -187,6 +216,10 @@ self.session.commit() def update(self, pages, force=False): + if self._needsSchemaUpdate(): + raise Exception("This wiki needs a database upgrade. " + "Please run `wk reset`.") + to_update = set() already_added = set() to_remove = [] @@ -365,27 +398,6 @@ query = query.options(subqueryload(sqf)) return query - def _createSchema(self): - Base.metadata.drop_all(self.engine) - Base.metadata.create_all(self.engine) - - ver = SQLInfo() - ver.name = 'schema_version' - ver.int_value = self.schema_version - self.session.add(ver) - self.session.commit() - - def _getSchemaVersion(self): - try: - q = self.session.query(SQLInfo).\ - filter(SQLInfo.name == 'schema_version').\ - first() - if q is None: - return 0 - except: - return -1 - return q.int_value - def _addPage(self, page): logger.debug("Adding page '%s' to SQL database." % page.url) diff -r 657edcb91804 -r fba20c625fb3 wikked/fs.py --- a/wikked/fs.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/fs.py Mon Mar 03 08:15:16 2014 -0800 @@ -54,6 +54,12 @@ excluded += wiki.scm.getSpecialFilenames() self.excluded = [os.path.join(self.root, e) for e in excluded] + def init(self, wiki): + pass + + def postInit(self): + pass + def getPageInfos(self, subdir=None): basepath = self.root if subdir is not None: diff -r 657edcb91804 -r fba20c625fb3 wikked/indexer/base.py --- a/wikked/indexer/base.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/indexer/base.py Mon Mar 03 08:15:16 2014 -0800 @@ -14,6 +14,12 @@ def start(self, wiki): raise NotImplementedError() + def init(self, wiki): + pass + + def postInit(self): + pass + def reset(self, pages): raise NotImplementedError() diff -r 657edcb91804 -r fba20c625fb3 wikked/resources/init/Main page.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wikked/resources/init/Main page.md Mon Mar 03 08:15:16 2014 -0800 @@ -0,0 +1,6 @@ +Welcome to your new wiki! If you need help, check out the [user manual][1]. If you want to try things out, use the [[Sandbox]]. + +Now go and *have fun* with your new wiki! + +[1]: http://bolt80.com/wikked/ + diff -r 657edcb91804 -r fba20c625fb3 wikked/resources/init/Sandbox.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wikked/resources/init/Sandbox.md Mon Mar 03 08:15:16 2014 -0800 @@ -0,0 +1,2 @@ +You can play around here. _Go nuts_, or go back [[home|Main Page]]. + diff -r 657edcb91804 -r fba20c625fb3 wikked/scm/base.py --- a/wikked/scm/base.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/scm/base.py Mon Mar 03 08:15:16 2014 -0800 @@ -17,7 +17,13 @@ pass def start(self, wiki): - raise NotImplementedError() + pass + + def init(self, wiki): + pass + + def postInit(self): + pass def getSpecialFilenames(self): raise NotImplementedError() diff -r 657edcb91804 -r fba20c625fb3 wikked/scm/mercurial.py --- a/wikked/scm/mercurial.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/scm/mercurial.py Mon Mar 03 08:15:16 2014 -0800 @@ -27,14 +27,16 @@ } def start(self, wiki): - pass + self._doStart() - def createRepo(self): + def init(self, wiki): # Make a Mercurial repo if there's none. if not os.path.isdir(os.path.join(self.root, '.hg')): logger.info("Creating Mercurial repository at: " + self.root) self._initRepo(self.root) + self._doStart() + # Create a `.hgignore` file is there's none. ignore_path = os.path.join(self.root, '.hgignore') if not os.path.isfile(ignore_path): @@ -43,6 +45,9 @@ f.write('.wiki') self.commit([ignore_path], {'message': "Created `.hgignore`."}) + def _doStart(self): + pass + def getSpecialFilenames(self): return ['.hg*'] @@ -176,11 +181,17 @@ class MercurialCommandServerSourceControl(MercurialBaseSourceControl): def __init__(self, root, client=None): MercurialBaseSourceControl.__init__(self, root) + self.client = client - if client is None: + def _initRepo(self, root): + exe = ['hg', 'init', root] + logger.debug("Running Mercurial: " + str(exe)) + return subprocess.check_output(exe) + + def _doStart(self): + if self.client is None: import hglib - client = hglib.open(root) - self.client = client + self.client = hglib.open(self.root) def getHistory(self, path=None, limit=10): if path is not None: diff -r 657edcb91804 -r fba20c625fb3 wikked/wiki.py --- a/wikked/wiki.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/wiki.py Mon Mar 03 08:15:16 2014 -0800 @@ -68,7 +68,7 @@ from wikked.db.sql import SQLDatabase return SQLDatabase(self.config) - def scm_factory(self): + def scm_factory(self, for_init=False): if self._scm_factory is None: try: scm_type = self.config.get('wiki', 'sourcecontrol') @@ -83,9 +83,11 @@ scm_type = 'hg' if scm_type == 'hg': - # Only create the command server once. - import hglib - client = hglib.open(self.root) + client = None + if not for_init: + # Only create the command server once. + import hglib + client = hglib.open(self.root) def impl(): from wikked.scm.mercurial import ( @@ -171,7 +173,7 @@ class Wiki(object): """ The wiki class! This is where the magic happens. """ - def __init__(self, parameters): + def __init__(self, parameters, for_init=False): """ Creates a new wiki instance. It won't be fully functional until you call `start`, which does the actual initialization. This gives you a chance to customize a few more things before @@ -194,7 +196,7 @@ self.fs = parameters.fs_factory() self.index = parameters.index_factory() self.db = parameters.db_factory() - self.scm = parameters.scm_factory() + self.scm = parameters.scm_factory(for_init) self.auth = parameters.auth_factory() self._updateSetPage = parameters.getPageUpdater() @@ -210,10 +212,28 @@ self.scm.start(self) self.index.start(self) self.db.start(self) + self.auth.start(self) if update: self.update() + def init(self): + """ Creates a new wiki at the specified root directory. + """ + self.fs.init(self) + self.scm.init(self) + self.index.init(self) + self.db.init(self) + self.auth.init(self) + + self.start() + + self.fs.postInit() + self.scm.postInit() + self.index.postInit() + self.db.postInit() + self.auth.postInit() + def stop(self): self.db.close() @@ -233,17 +253,16 @@ fs_page = FileSystemPage(self, page_info) self.db.update([fs_page], force=True) updated_urls.append(url) + self._cachePages([url]) self.index.update([self.getPage(url)]) else: page_infos = self.fs.getPageInfos() fs_pages = FileSystemPage.fromPageInfos(self, page_infos) self.db.update(fs_pages) + self._cachePages() updated_urls += [p.url for p in fs_pages] self.index.update(self.getPages()) - if cache_ext_data: - self._cachePages([url] if url else None) - def getPageUrls(self, subdir=None): """ Returns all the page URLs in the wiki, or in the given sub-directory. diff -r 657edcb91804 -r fba20c625fb3 wikked/witch.py --- a/wikked/witch.py Mon Mar 03 08:15:03 2014 -0800 +++ b/wikked/witch.py Mon Mar 03 08:15:16 2014 -0800 @@ -111,9 +111,13 @@ # Create the wiki. root = find_wiki_root(result.root) - params = WikiParameters(root) - wiki = Wiki(params) - wiki.start() + if root: + params = WikiParameters(root) + wiki = Wiki(params) + wiki.start() + else: + params = None + wiki = None # Run the command! before = datetime.datetime.now()