def new_page(): from zim.notebook import Path, Page from zim.newfs.mock import MockFile, MockFolder file = MockFile('/mock/test/page.txt') folder = MockFile('/mock/test/page/') page = Page(Path('Test'), False, file, folder) page.set_parsetree(new_parsetree()) return page
def setUpNotebook(self, name='notebook', mock=MOCK_ALWAYS_MOCK, content={}, folder=None): ''' @param name: name postfix for the folder, see L{setUpFolder} @param mock: see L{setUpFolder}, default is C{MOCK_ALWAYS_MOCK} @param content: dictionary where the keys are page names and the values the page content. If a tuple or list is given, pages are created with default text. L{Path} objects are allowed instead of page names @param folder: determine the folder to be used, only needed in special cases where the folder must be outside of the project folder, like when testing version control logic ''' import datetime from zim.newfs.mock import MockFolder from zim.notebook.notebook import NotebookConfig, Notebook from zim.notebook.page import Path from zim.notebook.layout import FilesLayout from zim.notebook.index import Index from zim.formats.wiki import WIKI_FORMAT_VERSION if folder is None: folder = self.setUpFolder(name, mock) folder.touch() # Must exist for sane notebook cache_dir = folder.folder('.zim') layout = FilesLayout(folder, endofline='unix') if isinstance(folder, MockFolder): conffile = folder.file('notebook.zim') config = NotebookConfig(conffile) index = Index(':memory:', layout) else: conffile = folder.file('notebook.zim') config = NotebookConfig(conffile) cache_dir.touch() index = Index(cache_dir.file('index.db').path, layout) if isinstance(content, (list, tuple)): content = dict((p, 'test 123') for p in content) notebook = Notebook(cache_dir, config, folder, layout, index) for name, text in list(content.items()): path = Path(name) if isinstance(name, str) else name file, folder = layout.map_page(path) file.write( ('Content-Type: text/x-zim-wiki\n' 'Wiki-Format: %s\n' 'Creation-Date: %s\n\n') % (WIKI_FORMAT_VERSION, datetime.datetime.now().isoformat()) + text) notebook.index.check_and_update() assert notebook.index.is_uptodate return notebook
def resolve_pagename(self, parent, names): '''Resolve a pagename in the right case''' # We do not ignore placeholders here. This can lead to a dependencies # in how links are resolved based on order of indexing. However, this # is not really a problem. Ignoring them means you could see duplicates # if the tree for multiple links with slightly different spelling. # Also we would need another call to return the page_id if a resolved # page happens to exist. pagename = parent page_id = self.get_page_id(parent) for i, basename in enumerate(names): if page_id == ROOT_ID: row = self.db.execute( 'SELECT id, name FROM pages WHERE name=?', (basename,) ).fetchone() else: row = self.db.execute( 'SELECT id, name FROM pages WHERE parent=? and name LIKE ?', (page_id, "%:"+basename) ).fetchone() if row: # exact match pagename = Path(row['name']) page_id = row['id'] else: sortkey = natural_sort_key(basename) row = self.db.execute( 'SELECT id, name FROM pages ' 'WHERE parent=? and sortkey=? ORDER BY name', (page_id, sortkey) ).fetchone() if row: # case insensitive match pagename = Path(row['name']) page_id = row['id'] else: # no match return None, pagename.child(':'.join(names[i:])) else: return page_id, pagename
def setUpNotebook(cls, name=None, mock=MOCK_ALWAYS_MOCK, content={}): ''' @param name: basename for the folder, use class name if C{None} @param mock: see L{setUpFolder}, default is C{MOCK_ALWAYS_MOCK} @param content: dictionary where the keys are page names and the values the page content. ''' import datetime from zim.newfs.mock import MockFolder from zim.config import VirtualConfigBackend from zim.notebook.notebook import NotebookConfig, Notebook from zim.notebook.page import Path from zim.notebook.layout import FilesLayout from zim.notebook.index import Index from zim.formats.wiki import WIKI_FORMAT_VERSION folder = cls.setUpFolder(name, mock) cache_dir = folder.folder('.zim') layout = FilesLayout(folder, endofline='unix') if isinstance(folder, MockFolder): ### XXX - Big HACK here - Get better classes for this - XXX ### dir = VirtualConfigBackend() file = dir.file('notebook.zim') file.dir = dir file.dir.basename = folder.basename ### config = NotebookConfig(file) index = Index(':memory:', layout) else: from zim.fs import Dir conffile = Dir(folder.path).file('notebook.zim') config = NotebookConfig(conffile) cache_dir.touch() index = Index(cache_dir.file('index.db').path, layout) notebook = Notebook(None, cache_dir, config, folder, layout, index) for name, text in content.items(): file, folder = layout.map_page(Path(name)) file.write( ('Content-Type: text/x-zim-wiki\n' 'Wiki-Format: %s\n' 'Creation-Date: %s\n\n') % (WIKI_FORMAT_VERSION, datetime.datetime.now().isoformat()) + text + '\n') notebook.index.check_and_update() return notebook
def on_page_changed(self, o, row, doc): # Drop links for this page and add new ones (don't bother # determining delta and updating). self.db.execute( 'DELETE FROM links WHERE source=?', (row['id'],) ) pagename = Path(row['name']) for href in doc.iter_href(): target_id, targetname = self._pages.resolve_link(pagename, href) if target_id is None: target_id = self._pagesindexer.insert_link_placeholder(targetname) anchorkey = natural_sort_key(href.parts()[0]) self.db.execute( 'INSERT INTO links(source, target, rel, names, anchorkey) ' 'VALUES (?, ?, ?, ?, ?)', (row['id'], target_id, href.rel, href.names, anchorkey) )
def resolve_link(self, source, href, ignore_link_placeholders=True): if href.rel == HREF_REL_ABSOLUTE or source.isroot: return self.resolve_pagename(ROOT_PATH, href.parts()) start, relnames = source, [] while True: # Do not assume source exists, find start point that does try: start_id = self.get_page_id(start) except IndexNotFoundError: relnames.append(start.basename) start = start.parent else: break if href.rel == HREF_REL_RELATIVE: return self.resolve_pagename(start, relnames + href.parts()) else: # HREF_REL_FLOATING # Search upward namespaces for existing pages, # By default ignore link placeholders to avoid circular # dependencies between links and placeholders assert href.rel == HREF_REL_FLOATING anchor_key = natural_sort_key(href.parts()[0]) if relnames: # Check if we are anchored in non-existing part keys = map(natural_sort_key, relnames) if anchor_key in keys: i = [c for c,k in enumerate(keys) if k==anchorkey][-1] return self.resolve_pagename(db, root, relnames[:i] + href.parts()[1:]) if ignore_link_placeholders: c = self.db.execute( 'SELECT name FROM pages ' 'WHERE sortkey=? and is_link_placeholder=0 ' 'ORDER BY name DESC', (anchor_key,) ) # sort longest first else: c = self.db.execute( 'SELECT name FROM pages ' 'WHERE sortkey=? ' 'ORDER BY name DESC', (anchor_key,) ) # sort longest first maxdepth = source.name.count(':') depth = -1 # level where items were found found = [] # candidates that match the link - these can only differ in case of the basename for name, in c: mydepth = name.count(':') if mydepth > maxdepth: continue elif mydepth < depth: break if mydepth > 0: # check whether we have a common parent parentname = name.rsplit(':', 1)[0] if start.name.startswith(parentname): depth = mydepth found.append(name) else: # resolve from root namespace found.append(name) if found: # try to match case first, else just use first match parts = href.parts() anchor = parts.pop(0) for name in found: if name.endswith(anchor): return self.resolve_pagename(Path(name), parts) else: return self.resolve_pagename(Path(found[0]), parts) else: # Return "brother" of source if relnames: return self.resolve_pagename(start, relnames[:-1] + href.parts()) else: return self.resolve_pagename(start.parent, href.parts())
from datetime import datetime from zim.utils import natural_sort_key from zim.notebook.page import Path, HRef, \ HREF_REL_ABSOLUTE, HREF_REL_FLOATING, HREF_REL_RELATIVE from zim.tokenparser import TokenBuilder from .base import * from zim.notebook.layout import \ FILE_TYPE_PAGE_SOURCE, \ FILE_TYPE_ATTACHMENT ROOT_PATH = Path(':') ROOT_ID = 1 # Constant for the ID of the root namespace in "pages" # (Primary key starts count at 1 and first entry will be root) PAGE_EXISTS_UNCERTAIN = 0 # e.g. folder with unknown children - not shown to outside world PAGE_EXISTS_AS_LINK = 1 # placeholder for link target PAGE_EXISTS_HAS_CONTENT = 2 # either has content or children have content class PagesIndexer(IndexerBase): '''Indexer for the "pages" table. @signal: C{page-row-inserted (row)}: new row inserted @signal: C{page-row-changed (row)}: row changed @signal: C{page-row-deleted (row)}: row to be deleted
def new_notebook(fakedir=None): '''Returns a new Notebook object with all data in memory Uses data from L{WikiTestData} @param fakedir: optional parameter to set the 'dir' attribute for the notebook which allows you to resolve file paths etc. It will not automatically touch the dir (hence it being 'fake'). ''' import sqlite3 from zim.fs import Dir from zim.config import VirtualConfigBackend from zim.notebook import Notebook, Path from zim.notebook.notebook import NotebookConfig from zim.notebook.index import Index from zim.notebook.layout import FilesLayout from zim.newfs.mock import MockFolder, clone_mock_object, os_native_path global _notebook_data if not _notebook_data: # run this one time only templfolder = MockFolder('/mock/notebook') layout = FilesLayout(templfolder, endofline='unix') manifest = [] for name, text in WikiTestData: manifest.append(name) file, x = layout.map_page(Path(name)) file.write(text) manifest = frozenset(_expand_manifest(manifest)) index = Index(':memory:', layout) index.check_and_update() lines = list(index._db.iterdump()) sql = '\n'.join(lines) _notebook_data = (templfolder, sql, manifest) if fakedir: fakedir = fakedir if isinstance(fakedir, basestring) else fakedir.path fakedir = os_native_path(fakedir) templfolder, sql, manifest = _notebook_data folder = MockFolder(fakedir or templfolder.path) clone_mock_object(templfolder, folder) #~ print ">>>>>>>>>>>>>" #~ for path in folder._fs.tree(): #~ print path layout = FilesLayout(folder, endofline='unix') index = Index(':memory:', layout) tables = [ r[0] for r in index._db.execute( 'SELECT name FROM sqlite_master ' 'WHERE type="table" and name NOT LIKE "sqlite%"') ] for table in tables: index._db.execute('DROP TABLE %s' % table) index._db.executescript(sql) index._db.commit() ### XXX - Big HACK here - Get better classes for this - XXX ### dir = VirtualConfigBackend() file = dir.file('notebook.zim') file.dir = dir file.dir.basename = 'Unnamed Notebook' ### config = NotebookConfig(file) notebook = Notebook(None, None, config, folder, layout, index) if fakedir: notebook.dir = Dir(fakedir) notebook.testdata_manifest = manifest return notebook