Пример #1
0
def get_template(category, template):
	'''Returns a Template object for a template name or file path
	@param category: the template category (e.g. "html"). Use to resolve
	the template if a template name is given
	@param template: the template name or file path
	'''
	assert isinstance(template, basestring)

	if is_path_re.match(template):
		file = File(template)
	else:
		file = None
		for dir in data_dirs(('templates', category)):
			for basename in dir.list():
				name = basename.rsplit('.')[0] # robust if no '.' in basename
				if basename == template or name == template:
					file = dir.file(basename)
					if file.exists(): # is a file
						break
			if file and file.exists():
				break
		else:
			file = File(template)
			if not file.exists():
				raise PathLookupError, _('Could not find template "%s"') % template
					# T: Error message in template lookup

	if not file.exists():
		raise PathLookupError, _('No such file: %s') % file
			# T: Error message in template lookup

	logger.info('Loading template from: %s', file)
	#~ basename, ext = file.basename.rsplit('.', 1)
	#~ resources = file.dir.subdir(basename)
	return Template(file)
Пример #2
0
	def testAttachFileDialog(self):
		'''Test AttachFileDialog'''
		tmp_dir = self.create_tmp_dir('testAttachFileDialog')
		file = File((tmp_dir, 'file_to_be_attached'))
		file.write('Test 1 2 3\n')
		newfile = File((tmp_dir, 'attachments', 'Test', 'foo', 'file_to_be_attached'))
		self.assertTrue(file.exists())
		self.assertFalse(newfile.exists())

		dialog = zim.gui.AttachFileDialog(self.ui, path=Path('Test:foo'))
		dialog.set_file(file)
Пример #3
0
    def testAttachFileDialog(self):
        '''Test AttachFileDialog'''
        tmp_dir = self.create_tmp_dir('testAttachFileDialog')
        file = File((tmp_dir, 'file_to_be_attached'))
        file.write('Test 1 2 3\n')
        newfile = File(
            (tmp_dir, 'attachments', 'Test', 'foo', 'file_to_be_attached'))
        self.assertTrue(file.exists())
        self.assertFalse(newfile.exists())

        dialog = zim.gui.AttachFileDialog(self.ui, path=Path('Test:foo'))
        dialog.set_file(file)
Пример #4
0
class PlantumlGenerator(ImageGeneratorClass):
    def __init__(self, plugin, notebook, page):
        ImageGeneratorClass.__init__(self, plugin, notebook, page)
        self.dotfile = TmpFile('umldiagram.puml')
        self.dotfile.touch()
        self.pngfile = File(self.dotfile.path[:-5] +
                            '.png')  # len('.puml') == 5

    def generate_image(self, text):
        # Write to tmp file
        self.dotfile.writelines(text)

        # Call PlantUML
        try:
            dot = Application(dotcmd)
            dot.run((self.pngfile, self.dotfile))
        except ApplicationError:
            return None, None  # Sorry, no log
        else:
            if self.pngfile.exists():
                return self.pngfile, None
            else:
                # When supplying a dot file with a syntax error, the dot command
                # doesn't return an error code (so we don't raise
                # ApplicationError), but we still don't have a png file to
                # return, so return None.
                return None, None

    def cleanup(self):
        self.dotfile.remove()
        self.pngfile.remove()
Пример #5
0
def get_template(format, template):
	'''Returns a Template object for a template name, file path, or File object'''
	# NOTE: here the "category" needs to be a format at the same time !
	if isinstance(template, File):
		file = template
	else:
		if not is_path_re.match(template):
			file = None
			path = list(data_dirs(('templates', format)))
			path.reverse()
			for dir in path:
				for basename in dir.list():
					name = basename.rsplit('.')[0] # robust if no '.' in basename
					if name == template:
						file = dir.file(basename)
						if file.exists(): # is a file
							break

			if not file:
				file = File(template)
		else:
			file = File(template)

	logger.info('Loading template from: %s', file)
	if not file.exists():
		raise AssertionError, 'No such file: %s' % file

	basename, ext = file.basename.rsplit('.', 1)
	resources = file.dir.subdir(basename)

	return Template(file.readlines(), format, name=file.path, resources_dir=resources)
Пример #6
0
 def testSaveCopyDialog(self):
     '''Test SaveCopyDialog'''
     tmp_dir = self.create_tmp_dir('testSaveCopyDialog')
     file = File((tmp_dir, 'save_copy.txt'))
     self.assertFalse(file.exists())
     dialog = zim.gui.SaveCopyDialog(self.ui)
     dialog.set_file(file)
Пример #7
0
def get_template(format, template):
    '''Returns a Template object for a template name, file path, or File object'''
    # NOTE: here the "category" needs to be a format at the same time !
    if isinstance(template, File):
        file = template
    else:
        if not is_path_re.match(template):
            file = None
            path = list(data_dirs(('templates', format)))
            path.reverse()
            for dir in path:
                for basename in dir.list():
                    name = basename.rsplit('.')[
                        0]  # robust if no '.' in basename
                    if name == template:
                        file = dir.file(basename)
                        if file.exists():  # is a file
                            break

            if not file:
                file = File(template)
        else:
            file = File(template)

    logger.info('Loading template from: %s', file)
    if not file.exists():
        raise AssertionError, 'No such file: %s' % file

    basename, ext = file.basename.rsplit('.', 1)
    resources = file.dir.subdir(basename)

    return Template(file.readlines(),
                    format,
                    name=file.path,
                    resources_dir=resources)
Пример #8
0
	def testSaveCopyDialog(self):
		'''Test SaveCopyDialog'''
		tmp_dir = self.create_tmp_dir('testSaveCopyDialog')
		file = File((tmp_dir, 'save_copy.txt'))
		self.assertFalse(file.exists())
		dialog = zim.gui.SaveCopyDialog(self.ui)
		dialog.set_file(file)
Пример #9
0
 def testImportPageDialog(self):
     '''Test ImportPageDialog'''
     tmp_dir = self.create_tmp_dir('testImportPageDialog')
     file = File((tmp_dir, 'import_page.txt'))
     file.write('test 123\n')
     self.assertTrue(file.exists())
     dialog = zim.gui.ImportPageDialog(self.ui)
     dialog.set_file(file)
Пример #10
0
	def testImportPageDialog(self):
		'''Test ImportPageDialog'''
		tmp_dir = self.create_tmp_dir('testImportPageDialog')
		file = File((tmp_dir, 'import_page.txt'))
		file.write('test 123\n')
		self.assertTrue(file.exists())
		dialog = zim.gui.ImportPageDialog(self.ui)
		dialog.set_file(file)
Пример #11
0
    def runTest(self):
        tmp_dir = self.create_tmp_dir()

        file = File((tmp_dir, 'test.txt'))
        file.write('test 123')
        self.assertTrue(file.exists())

        dialog = FileDialog(None, 'Test')
        dialog.set_file(file)
Пример #12
0
	def runTest(self):
		tmp_dir = self.create_tmp_dir()

		file = File((tmp_dir, 'test.txt'))
		file.write('test 123')
		self.assertTrue(file.exists())

		dialog = FileDialog(None, 'Test')
		dialog.set_file(file)
Пример #13
0
def set_basedirs(_ignore_test=False):
	'''This method sets the global configuration paths for according to the
	freedesktop basedir specification.
	Called automatically when module is first loaded, should be
	called explicitly only when environment has changed.
	'''
	global ZIM_DATA_DIR
	global XDG_DATA_HOME
	global XDG_DATA_DIRS
	global XDG_CONFIG_HOME
	global XDG_CONFIG_DIRS
	global XDG_CACHE_HOME

	# Cast string to folder
	import zim
	zim_data_dir = File(zim.ZIM_EXECUTABLE).dir.subdir('data')
	if zim_data_dir.exists():
		ZIM_DATA_DIR = zim_data_dir

	if os.name == 'nt':
		APPDATA = os.environ['APPDATA']

		XDG_DATA_HOME = Dir(
			os.environ.get('XDG_DATA_HOME', APPDATA + r'\zim\data'))

		XDG_DATA_DIRS = \
			_split_environ_dir_list(os.environ.get('XDG_DATA_DIRS'), ('~/.local/share/',)) # Backwards compatibility

		XDG_CONFIG_HOME = Dir(
			os.environ.get('XDG_CONFIG_HOME', APPDATA + r'\zim\config'))

		XDG_CONFIG_DIRS = \
			_split_environ_dir_list(os.environ.get('XDG_CONFIG_DIRS'), ('~/.config/',)) # Backwards compatibility

		XDG_CACHE_HOME = Dir(
			os.environ.get('XDG_CACHE_HOME', APPDATA + r'\zim\cache'))
	else:
		XDG_DATA_HOME = Dir(
			os.environ.get('XDG_DATA_HOME', '~/.local/share/'))

		XDG_DATA_DIRS = \
			_split_environ_dir_list(os.environ.get('XDG_DATA_DIRS'), ('/usr/share/', '/usr/local/share/'))

		XDG_CONFIG_HOME = Dir(
			os.environ.get('XDG_CONFIG_HOME', '~/.config/'))

		XDG_CONFIG_DIRS = \
			_split_environ_dir_list(os.environ.get('XDG_CONFIG_DIRS'), ('/etc/xdg/',))

		XDG_CACHE_HOME = Dir(
			os.environ.get('XDG_CACHE_HOME', '~/.cache'))

		if os.environ.get('ZIM_TEST_RUNNING') and not _ignore_test:
			# See tests/__init__.py, we load more folders then we really want
			# because the needs of Gtk, but want to restrict it here for all
			# zim internal use
			XDG_DATA_DIRS = [Dir(os.environ['TEST_XDG_DATA_DIRS'])]
Пример #14
0
def _get_path_object(path):
	if isinstance(path, str):
		file = File(path)
		if file.exists(): # exists and is a file
			path = file
		else:
			path = Dir(path)
	else:
		assert isinstance(path, (File, Dir))
	return path
Пример #15
0
	def get_file(self):
		file = File(self.uistate['output_file'])
		if file.exists():
			ok = QuestionDialog(self, (
				_('File exists'), # T: message heading
				_('This file already exists.\n'
				  'Do you want to overwrite it?' ) # T: detailed message, answers are Yes and No
			) ).run()
			if not ok:
				return None
		return file
Пример #16
0
	def get_file(self):
		file = File(self.uistate['output_file'])
		if file.exists():
			ok = QuestionDialog(self, (
				_('File exists'), # T: message heading
				_('This file already exists.\n'
				  'Do you want to overwrite it?') # T: detailed message, answers are Yes and No
			)).run()
			if not ok:
				return None
		return file
Пример #17
0
	def delete_file(self, file=None, refresh=False):
		'''Deletes a file and refreshes the treeview if refresh == True'''
		if not file:
			file = self.selected_file
			refresh = True
		logger.debug('Deleting %s' % file)
		file = File(file)
		if file.exists():
			file.cleanup()
		if refresh:
			self.treeview.model.remove(self.iter)
Пример #18
0
def set_basedirs():
	'''This method sets the global configuration paths for according to the
	freedesktop basedir specification.
	Called automatically when module is first loaded, should be
	called explicitly only when environment has changed.
	'''
	global ZIM_DATA_DIR
	global XDG_DATA_HOME
	global XDG_DATA_DIRS
	global XDG_CONFIG_HOME
	global XDG_CONFIG_DIRS
	global XDG_CACHE_HOME

	# Cast string to folder
	import zim
	zim_data_dir = File(zim.ZIM_EXECUTABLE).dir.subdir('data')
	if zim_data_dir.exists():
		ZIM_DATA_DIR = zim_data_dir

	if os.name == 'nt':
		APPDATA = environ['APPDATA']

		XDG_DATA_HOME = Dir(
			environ.get('XDG_DATA_HOME', APPDATA + r'\zim\data'))

		XDG_DATA_DIRS = map(Dir,
			environ.get_list('XDG_DATA_DIRS', '~/.local/share/')) # Backwards compatibility

		XDG_CONFIG_HOME = Dir(
			environ.get('XDG_CONFIG_HOME', APPDATA + r'\zim\config'))

		XDG_CONFIG_DIRS = map(Dir,
			environ.get_list('XDG_CONFIG_DIRS', '~/.config/')) # Backwards compatibility

		XDG_CACHE_HOME = Dir(
			environ.get('XDG_CACHE_HOME', APPDATA + r'\zim\cache'))
	else:
		XDG_DATA_HOME = Dir(
			environ.get('XDG_DATA_HOME', '~/.local/share/'))

		XDG_DATA_DIRS = map(Dir,
			environ.get_list('XDG_DATA_DIRS', ('/usr/share/', '/usr/local/share/')))

		XDG_CONFIG_HOME = Dir(
			environ.get('XDG_CONFIG_HOME', '~/.config/'))

		XDG_CONFIG_DIRS = map(Dir,
			environ.get_list('XDG_CONFIG_DIRS', ('/etc/xdg/',)))

		XDG_CACHE_HOME = Dir(
			environ.get('XDG_CACHE_HOME', '~/.cache'))
Пример #19
0
    def testAttachFileDialog(self):
        '''Test AttachFileDialog'''
        tmp_dir = self.create_tmp_dir('testAttachFileDialog')
        file = File((tmp_dir, 'file_to_be_attached'))
        file.write('Test 1 2 3\n')
        newfile = File(
            (tmp_dir, 'attachments', 'Test', 'foo', 'file_to_be_attached'))
        self.assertTrue(file.exists())
        self.assertFalse(newfile.exists())

        mainwindow = tests.MockObject()
        mainwindow.pageview = tests.MockObject()
        mainwindow.ui = self.ui

        dialog = zim.gui.AttachFileDialog(mainwindow,
                                          self.ui.notebook,
                                          path=Path('Test:foo'))
        dialog.set_file(file)
        tests.gtk_process_events()
        dialog.assert_response_ok()

        self.assertTrue(file.exists())  # No move or delete happened
        self.assertTrue(newfile.exists())
        self.assertTrue(newfile.compare(file))
Пример #20
0
class DiagramGenerator(ImageGeneratorClass):

    uses_log_file = False

    object_type = 'diagram'
    scriptname = 'diagram.dot'
    imagename = 'diagram.png'

    def __init__(self, plugin):
        ImageGeneratorClass.__init__(self, plugin)
        self.dotfile = TmpFile(self.scriptname)
        self.dotfile.touch()
        self.pngfile = File(self.dotfile.path[:-4] +
                            '.png')  # len('.dot') == 4

    def generate_image(self, text):
        if isinstance(text, basestring):
            text = text.splitlines(True)

        # Write to tmp file
        self.dotfile.writelines(text)

        # Call GraphViz
        try:
            dot = Application(dotcmd)
            dot.run((self.pngfile, self.dotfile))
        except ApplicationError:
            return None, None  # Sorry, no log
        else:
            if self.pngfile.exists():
                return self.pngfile, None
            else:
                # When supplying a dot file with a syntax error, the dot command
                # doesn't return an error code (so we don't raise
                # ApplicationError), but we still don't have a png file to
                # return, so return None.
                return None, None

    def cleanup(self):
        self.dotfile.remove()
        self.pngfile.remove()
Пример #21
0
class DiagramGenerator(ImageGeneratorClass):

	uses_log_file = False

	object_type = 'diagram'
	scriptname = 'diagram.dot'
	imagename = 'diagram.png'

	def __init__(self, plugin):
		ImageGeneratorClass.__init__(self, plugin)
		self.dotfile = TmpFile(self.scriptname)
		self.dotfile.touch()
		self.pngfile = File(self.dotfile.path[:-4] + '.png') # len('.dot') == 4

	def generate_image(self, text):
		if isinstance(text, basestring):
			text = text.splitlines(True)

		# Write to tmp file
		self.dotfile.writelines(text)

		# Call GraphViz
		try:
			dot = Application(dotcmd)
			dot.run((self.pngfile, self.dotfile))
		except ApplicationError:
			return None, None # Sorry, no log
		else:
			if self.pngfile.exists():
				return self.pngfile, None
			else:
				# When supplying a dot file with a syntax error, the dot command
				# doesn't return an error code (so we don't raise
				# ApplicationError), but we still don't have a png file to
				# return, so return None.
				return None, None

	def cleanup(self):
		self.dotfile.remove()
		self.pngfile.remove()
Пример #22
0
	def testError(self):

		def creator_with_failure(*a):
			raise ThumbnailCreatorFailure

		def creator_with_error(*a):
			raise ValueError

		file = File('./data/zim.png')
		self.assertTrue(file.exists())
		self.assertTrue(file.isimage())

		for creator in creator_with_failure, creator_with_error:
			#~ print ">>", creator.__name__
			queue = ThumbnailQueue(creator)
			queue.queue_thumbnail_request(file, 64)

			with tests.LoggingFilter('zim.plugins.attachmentbrowser', 'Exception'):
				queue.start()
				while not queue.queue_empty():
					r = queue.get_ready_thumbnail()
					self.assertIsNone(r[0], None)
Пример #23
0
def set_basedirs():
	'''This method sets the global configuration paths for according to the
	freedesktop basedir specification.
	Called automatically when module is first loaded, should be
	called explicitly only when environment has changed.
	'''
	global ZIM_DATA_DIR
	global XDG_DATA_HOME
	global XDG_DATA_DIRS
	global XDG_CONFIG_HOME
	global XDG_CONFIG_DIRS
	global XDG_CACHE_HOME

	# Cast string to folder
	import zim
	zim_data_dir = File(zim.ZIM_EXECUTABLE).dir.subdir('data')
	if zim_data_dir.exists():
		ZIM_DATA_DIR = zim_data_dir

	if os.name == 'nt':
		APPDATA = environ['APPDATA']

		XDG_DATA_HOME = Dir(
			environ.get('XDG_DATA_HOME', APPDATA + r'\zim\data'))

		XDG_DATA_DIRS = map(Dir,
			environ.get_list('XDG_DATA_DIRS', '~/.local/share/')) # Backwards compatibility

		XDG_CONFIG_HOME = Dir(
			environ.get('XDG_CONFIG_HOME', APPDATA + r'\zim\config'))

		XDG_CONFIG_DIRS = map(Dir,
			environ.get_list('XDG_CONFIG_DIRS', '~/.config/')) # Backwards compatibility

		try:
			import _winreg as wreg
			wreg_key = wreg.OpenKey(
				wreg.HKEY_CURRENT_USER,
				r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders')
			cache_dir = str(wreg.QueryValueEx(wreg_key, "Cache")[0].replace(u'%USERPROFILE%', environ['USERPROFILE']))
			wreg.CloseKey(wreg_key)
		except:
			cache_dir = APPDATA + r'\zim\cache'
			# Not using TMP here because it is cleaned too often

		XDG_CACHE_HOME = Dir(
			environ.get('XDG_CACHE_HOME', cache_dir + r'\zim'))
	else:
		XDG_DATA_HOME = Dir(
			environ.get('XDG_DATA_HOME', '~/.local/share/'))

		XDG_DATA_DIRS = map(Dir,
			environ.get_list('XDG_DATA_DIRS', ('/usr/share/', '/usr/local/share/')))

		XDG_CONFIG_HOME = Dir(
			environ.get('XDG_CONFIG_HOME', '~/.config/'))

		XDG_CONFIG_DIRS = map(Dir,
			environ.get_list('XDG_CONFIG_DIRS', ('/etc/xdg/',)))

		XDG_CACHE_HOME = Dir(
			environ.get('XDG_CACHE_HOME', '~/.cache'))
Пример #24
0
def set_basedirs():
    '''This method sets the global configuration paths for according to the
	freedesktop basedir specification.
	Called automatically when module is first loaded, should be
	called explicitly only when environment has changed.
	'''
    global ZIM_DATA_DIR
    global XDG_DATA_HOME
    global XDG_DATA_DIRS
    global XDG_CONFIG_HOME
    global XDG_CONFIG_DIRS
    global XDG_CACHE_HOME

    # Cast string to folder
    import zim
    zim_data_dir = File(zim.ZIM_EXECUTABLE).dir.subdir('data')
    if zim_data_dir.exists():
        ZIM_DATA_DIR = zim_data_dir

    if os.name == 'nt':
        APPDATA = environ['APPDATA']

        XDG_DATA_HOME = Dir(
            environ.get('XDG_DATA_HOME', APPDATA + r'\zim\data'))

        XDG_DATA_DIRS = map(Dir,
                            environ.get_list(
                                'XDG_DATA_DIRS',
                                '~/.local/share/'))  # Backwards compatibility

        XDG_CONFIG_HOME = Dir(
            environ.get('XDG_CONFIG_HOME', APPDATA + r'\zim\config'))

        XDG_CONFIG_DIRS = map(
            Dir, environ.get_list('XDG_CONFIG_DIRS',
                                  '~/.config/'))  # Backwards compatibility

        try:
            import _winreg as wreg
            wreg_key = wreg.OpenKey(
                wreg.HKEY_CURRENT_USER,
                r'Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders'
            )
            cache_dir = str(
                wreg.QueryValueEx(wreg_key,
                                  "Cache")[0].replace(u'%USERPROFILE%',
                                                      environ['USERPROFILE']))
            wreg.CloseKey(wreg_key)
        except:
            cache_dir = APPDATA + r'\zim\cache'
            # Not using TMP here because it is cleaned too often

        XDG_CACHE_HOME = Dir(environ.get('XDG_CACHE_HOME',
                                         cache_dir + r'\zim'))
    else:
        XDG_DATA_HOME = Dir(environ.get('XDG_DATA_HOME', '~/.local/share/'))

        XDG_DATA_DIRS = map(
            Dir,
            environ.get_list('XDG_DATA_DIRS',
                             ('/usr/share/', '/usr/local/share/')))

        XDG_CONFIG_HOME = Dir(environ.get('XDG_CONFIG_HOME', '~/.config/'))

        XDG_CONFIG_DIRS = map(
            Dir, environ.get_list('XDG_CONFIG_DIRS', ('/etc/xdg/', )))

        XDG_CACHE_HOME = Dir(environ.get('XDG_CACHE_HOME', '~/.cache'))
Пример #25
0
	def runTest(self):
		plugins = PluginManager.list_installed_plugins()
		self.assertTrue(len(plugins) > 10)
		self.assertTrue('spell' in plugins)
		self.assertTrue('linkmap' in plugins)

		pluginindex = File('data/manual/Plugins.txt').read()

		seen = {
			'name': set(),
			'description': set(),
			'help': set(),
		}
		for name in plugins:
			#~ print '>>', name
			klass = PluginManager.get_plugin_class(name)

			# test plugin info
			for key in ('name', 'description', 'author'):
				self.assertTrue(
					klass.plugin_info.get(key),
					'Plugin %s misses info field \'%s\'' % (name, key)
				)

			for key in ('name', 'description', 'help'):
				self.assertIn(key, klass.plugin_info, 'Plugin %s missing "%s"' % (name, key))
				value = klass.plugin_info[key]
				self.assertFalse(
					value in seen[key],
					'Value for \'%s\' in %s seen before - copy-paste error ?' % (key, name)
				)
				seen[key].add(value)

			# test manual page present and at least documents preferences
			page = klass.plugin_info['help']
			self.assertTrue(page.startswith('Plugins:'), 'Help page for %s not valid' % name)

			rellink = "+%s" % page[8:]
			self.assertIn(rellink, pluginindex, 'Missing links "%s" in manual/Plugins.txt' % rellink)

			file = File('data/manual/' + page.replace(':', '/').replace(' ', '_') + '.txt')
			self.assertTrue(file.exists(), 'Missing file: %s' % file)

			manual = file.read()
			for pref in klass.plugin_preferences:
				label = pref[2]
				if '\n' in label:
					label, x = label.split('\n', 1)
					label = label.rstrip(',')
				self.assertIn(label, manual, 'Preference "%s" for %s plugin not documented in manual page' % (label, name))

			# test dependencies data
			dep = klass.check_dependencies()
			self.assertTrue(isinstance(dep,tuple))
			check, dep = dep
			self.assertTrue(isinstance(check,bool))
			self.assertTrue(isinstance(dep,list))
			for i in range(len(dep)):
				self.assertTrue(isinstance(dep[i],tuple))
				self.assertTrue(isinstance(dep[i][0],str))
				self.assertTrue(isinstance(dep[i][1],bool))
				self.assertTrue(isinstance(dep[i][2],bool))
Пример #26
0
class ConfigFile(object):
	'''Container object for a config file

	Maps to a "base" file in the home folder, used to write new values,
	and one or more default files, e.g. in C{/usr/share/zim}, which
	are the fallback to get default values

	@ivar file: the underlying file object for the base config file
	in the home folder

	@note: this class implement similar API to the L{File} class but
	is explicitly not a sub-class of L{File} because config files should
	typically not be moved, renamed, etc. It just implements the reading
	and writing methods.
	'''

	def __init__(self, path, file=None):
		'''Constructor
		@param path: either basename as string or tuple with relative path,
		is resolved relative to the default config dir for zim.
		@param file: optional argument for some special case to
		override the base file in the home folder.
		'''
		if isinstance(path, basestring):
			path = (path,)
		self._path = tuple(path)
		if file:
			self.file = file
		else:
			self.file = File((XDG_CONFIG_HOME, 'zim') + self._path)

	def __repr__(self):
		return '<%s: %s>' % (self.__class__.__name__, self.file.path)

	def __eq__(self, other):
		return isinstance(other, ConfigFile) \
		and other._path == self._path \
		and other.file == self.file

	@property
	def basename(self):
		return self.file.basename

	def default_files(self):
		'''Generator that yields default config files (read-only) to
		use instead of the standard file when it is still empty.
		Typically only the first one is used.
		'''
		for dir in config_dirs():
			default = dir.file(self._path)
			if default.exists():
				yield default

	def touch(self):
		'''Ensure the custom file in the home folder exists. Either by
		copying a default config file, or touching an empty file.
		Intended to be called before trying to edit the file with an
		external editor.
		'''
		if not self.file.exists():
			for file in self.default_files():
				file.copyto(self.file)
				break
			else:
				self.file.touch() # create empty file

	def read(self, fail=False):
		'''Read the base file or first default file
		@param fail: if C{True} a L{FileNotFoundError} error is raised
		when neither the base file or a default file are found. If
		C{False} it will return C{''} for a non-existing file.
		@returns: file content as a string
		'''
		try:
			return self.file.read()
		except FileNotFoundError:
			for file in self.default_files():
				return file.read()
			else:
				if fail:
					raise
				else:
					return ''

	def readlines(self, fail=False):
		'''Read the base file or first default file
		@param fail: if C{True} a L{FileNotFoundError} error is raised
		when neither the base file or a default file are found. If
		C{False} it will return C{[]} for a non-existing file.
		@returns: file content as a list of lines
		'''
		try:
			return self.file.readlines()
		except FileNotFoundError:
			for file in self.default_files():
				return file.readlines()
			else:
				if fail:
					raise
				else:
					return []

	# Not implemented: read_async and readlines_async

	def write(self, text):
		'''Write base file, see L{File.write()}'''
		self.file.write(text)

	def writelines(self, lines):
		'''Write base file, see L{File.writelines()}'''
		self.file.writelines(lines)

	def write_async(self, text, callback=None, data=None):
		'''Write base file async, see L{File.write_async()}'''
		return self.file.write_async(text, callback=callback, data=data)

	def writelines_async(self, lines, callback=None, data=None):
		'''Write base file async, see L{File.writelines_async()}'''
		return self.file.writelines_async(lines, callback=callback, data=data)

	def remove(self):
		'''Remove user file, leaves default files in place'''
		if self.file.exists():
			return self.file.remove()
Пример #27
0
def main(argv):
    """Run the main program

    Depending on the commandline given and whether or not there is
    an instance of zim running already, this method may return
    immediatly, or go into the mainloop untill the program is exitted.

    @param argv: commandline arguments, e.g. from C{sys.argv}

    @raises UsageError: when number of arguments is not correct
    @raises GetOptError: when invalid options are found
    """
    global ZIM_EXECUTABLE

    # FIXME - this returns python.exe on my windows test
    ZIM_EXECUTABLE = argv[0]
    zim_exec_file = File(ZIM_EXECUTABLE)
    if zim_exec_file.exists():
        # We were given an absolute path, e.g. "python ./zim.py"
        ZIM_EXECUTABLE = zim_exec_file.path

    # Check for special commandline args for ipc, does not return
    # if handled
    import zim.ipc

    zim.ipc.handle_argv()

    # Let getopt parse the option list
    short = "".join(shortopts.keys())
    for s, l in shortopts.items():
        if l.endswith("="):
            short = short.replace(s, s + ":")
    long = list(longopts) + list(commands)
    for opts in commandopts.values():
        long.extend(opts)

    opts, args = gnu_getopt(argv[1:], short, long)

    # First figure out which command to execute
    cmd = "gui"  # default
    if opts:
        o = opts[0][0].lstrip("-")
        if o in shortopts:
            o = shortopts[o].rstrip("=")
        if o in commands:
            opts.pop(0)
            cmd = o

    # If it is a simple command execute it and return
    if cmd == "version":
        print "zim %s\n" % __version__
        print __copyright__, "\n"
        print __license__
        return
    elif cmd == "help":
        print usagehelp.replace("zim", argv[0])
        print optionhelp
        return

    # Otherwise check the number of arguments
    if cmd in maxargs and len(args) > maxargs[cmd]:
        raise UsageError

    # --manual is an alias for --gui /usr/share/zim/manual
    if cmd == "manual":
        cmd = "gui"
        args.insert(0, data_dir("manual").path)

    # Now figure out which options are allowed for this command
    allowedopts = list(longopts)
    allowedopts.extend(commandopts[cmd])

    # Convert options into a proper dict
    optsdict = {}
    for o, a in opts:
        o = str(o.lstrip("-"))  # str() -> no unicode for keys
        if o in shortopts:
            o = shortopts[o].rstrip("=")

        if o + "=" in allowedopts:
            o = o.replace("-", "_")
            optsdict[o] = a
        elif o in allowedopts:
            o = o.replace("-", "_")
            optsdict[o] = True
        else:
            raise GetoptError, ("--%s is not allowed in combination with --%s" % (o, cmd), o)

    # --port is the only option that is not of type string
    if "port" in optsdict and not optsdict["port"] is None:
        try:
            optsdict["port"] = int(optsdict["port"])
        except ValueError:
            raise GetoptError, ("--port takes an integer argument", "port")

    # set logging output level for logging root (format has been set in zim.py)
    if not ZIM_EXECUTABLE[-4:].lower() == ".exe":
        # for most platforms
        level = logging.WARN
    else:
        # if running from Windows compiled .exe
        level = logging.ERROR
    if optsdict.pop("verbose", False):
        level = logging.INFO
    if optsdict.pop("debug", False):
        level = logging.DEBUG  # no "elif" !
    logging.getLogger().setLevel(level)

    logger.info("This is zim %s", __version__)
    if level == logging.DEBUG:
        logger.debug("Python version is %s", str(sys.version_info))
        logger.debug("Platform is %s", os.name)
        logger.debug(get_zim_revision())
        log_basedirs()

    # Now we determine the class to handle this command
    # and start the application ...
    logger.debug("Running command: %s", cmd)
    if cmd in ("export", "index", "search"):
        if not len(args) >= 1:
            default = _get_default_or_only_notebook()
            if not default:
                raise UsageError
            handler = NotebookInterface(notebook=default)
        else:
            handler = NotebookInterface(notebook=args[0])

        handler.load_plugins()  # should this go somewhere else ?

        if cmd == "search":
            if not len(args) == 2:
                raise UsageError
            optsdict["query"] = args[1]
        elif len(args) == 2:
            optsdict["page"] = args[1]

        method = getattr(handler, "cmd_" + cmd)
        method(**optsdict)
    elif cmd == "gui":
        notebook = None
        page = None
        if args:
            from zim.notebook import resolve_notebook

            notebook, page = resolve_notebook(args[0])
            if not notebook:
                notebook = File(args[0]).uri
                # make sure daemon approves of this uri and proper
                # error dialog is shown as a result by GtkInterface
            if len(args) == 2:
                page = args[1]

        if "list" in optsdict:
            del optsdict["list"]  # do not use default
        elif not notebook:
            import zim.notebook

            default = _get_default_or_only_notebook()
            if default:
                notebook = default
                logger.info("Opening default notebook")

        # DGT: HACK for debuger
        if "standalone" in optsdict or DEBUG:
            import zim.gui

            try:
                del optsdict["standalone"]
            except:
                pass

            if not notebook:
                import zim.gui.notebookdialog

                notebook = zim.gui.notebookdialog.prompt_notebook()
                if not notebook:
                    return  # User canceled notebook dialog
            handler = zim.gui.GtkInterface(notebook, page, **optsdict)
            handler.main()
        else:
            from zim.ipc import start_server_if_not_running, ServerProxy

            if not notebook:
                import zim.gui.notebookdialog

                notebook = zim.gui.notebookdialog.prompt_notebook()
                if not notebook:
                    return  # User canceled notebook dialog

            start_server_if_not_running()
            server = ServerProxy()
            gui = server.get_notebook(notebook)
            gui.present(page, **optsdict)

            logger.debug(
                """
NOTE FOR BUG REPORTS:
    At this point zim has send the command to open a notebook to a
    background process and the current process will now quit.
    If this is the end of your debug output it is probably not useful
    for bug reports. Please close all zim windows, quit the
    zim trayicon (if any), and try again.
"""
            )
    elif cmd == "server":
        standalone = optsdict.pop("standalone", False)
        # No daemon support for server, so no option doesn't
        # do anything for now
        gui = optsdict.pop("gui", False)
        if gui:
            import zim.gui.server

            zim.gui.server.main(*args, **optsdict)
        else:
            import zim.www

            zim.www.main(*args, **optsdict)
    elif cmd == "plugin":
        import zim.plugins

        try:
            pluginname = args.pop(0)
        except IndexError:
            raise UsageError
        module = zim.plugins.get_plugin_module(pluginname)
        module.main(*args)
Пример #28
0
	def runTest(self):
		plugins = PluginManager.list_installed_plugins()
		self.assertTrue(len(plugins) > 10)
		self.assertTrue('spell' in plugins)
		self.assertTrue('linkmap' in plugins)

		pluginindex = File('data/manual/Plugins.txt').read()

		seen = {
			'name': set(),
			'description': set(),
			'help': set(),
		}
		for name in plugins:
			#~ print('>>', name)
			klass = PluginManager.get_plugin_class(name)

			# test plugin info
			for key in ('name', 'description', 'author'):
				self.assertTrue(
					klass.plugin_info.get(key),
					'Plugin %s misses info field \'%s\'' % (name, key)
				)

			for key in ('name', 'description', 'help'):
				self.assertIn(key, klass.plugin_info, 'Plugin %s missing "%s"' % (name, key))
				value = klass.plugin_info[key]
				self.assertFalse(
					value in seen[key],
					'Value for \'%s\' in %s seen before - copy-paste error ?' % (key, name)
				)
				seen[key].add(value)

			# test manual page present and at least documents preferences
			page = klass.plugin_info['help']
			self.assertTrue(page.startswith('Plugins:'), 'Help page for %s not valid' % name)

			rellink = "+%s" % page[8:]
			self.assertIn(rellink, pluginindex, 'Missing links "%s" in manual/Plugins.txt' % rellink)

			file = File('data/manual/' + page.replace(':', '/').replace(' ', '_') + '.txt')
			self.assertTrue(file.exists(), 'Missing file: %s' % file)

			manual = file.read()
			ignore = getattr(klass, 'hide_preferences', [])
			for pref in klass.plugin_preferences:
				if pref[0] in ignore:
					continue
				label = pref[2]
				if '\n' in label:
					label, x = label.split('\n', 1)
					label = label.rstrip(',')
				self.assertIn(label, manual, 'Preference "%s" for %s plugin not documented in manual page' % (label, name))

			# test dependencies data
			dep = klass.check_dependencies()
			self.assertTrue(isinstance(dep, tuple))
			check, dep = dep
			self.assertTrue(isinstance(check, bool))
			self.assertTrue(isinstance(dep, list))
			for i in range(len(dep)):
				self.assertTrue(isinstance(dep[i], tuple))
				self.assertTrue(isinstance(dep[i][0], str))
				self.assertTrue(isinstance(dep[i][1], bool))
				self.assertTrue(isinstance(dep[i][2], bool))