Example #1
0
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
Example #2
0
    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
Example #3
0
	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
Example #4
0
    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
Example #5
0
	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)
			)
Example #6
0
	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())
Example #7
0
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
Example #8
0
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