7"""This module provides the actual importing logic. See
8`:class:PluginImporter` for more info.
10For easy command line testing, call this module like this:
11 > python plugin_importer.py foo.zip /output/path
14from configparser
import ConfigParser, Error
as ConfigParserError
18from tempfile
import TemporaryDirectory
21from builtins
import i18n
24 """Base class for all exceptions of this module."""
29 """No valid plugins can be found in the zip file."""
34 """Zip file can't be read or its content can't be parsed."""
39 """Import a Krita Python Plugin from a zip file into the given
42 The Importer makes barely any assumptions about the file structure
43 in the zip file. It will find one or more plugins with the
46 1. Find files with the ending `.desktop` and read the Python
48 2. Find directories that correspond to the Python module names
49 and that contain an `__init__.py` file
50 3. Find files with ending `.action` that have matching
51 `<Action name=...>` tags (these files are optional)
52 4. Extract the desktop- and action-files and the Python module
53 directories into the corresponding pykrita and actions folders
57 >>> importer = PluginImporter(
58 '/path/to/plugin.zip',
59 '/path/to/krita/resources/',
60 confirm_overwrite_callback)
61 >>> imported = importer.import_all()
65 def __init__(self, zip_filename, resources_dir,
66 confirm_overwrite_callback):
68 """Initialise the importer.
70 :param zip_filename: Filename of the zip archive containing the
72 :param resources_dir: The Krita resources directory into which
73 to extract the plugin(s)
74 :param confirm_overwrite_callback: A function that gets called
75 if a plugin already exists in the resources directory. It gets
76 called with a dictionary of information about the plugin and
77 should return whether the user wants to overwrite the plugin
78 (True) or not (False).
84 self.
archive = zipfile.ZipFile(zip_filename)
85 except(zipfile.BadZipFile, zipfile.LargeZipFile, OSError)
as e:
90 for filename
in self.
archive.namelist():
91 if filename.endswith(
'.desktop'):
93 if filename.endswith(
'.action'):
99 if not os.path.exists(dest):
106 if not os.path.exists(dest):
122 namelist = self.
archive.namelist()
123 for filename
in namelist:
124 if (filename.endswith(
'/%s/' % name)
125 or filename ==
'%s/' % name):
127 if (
'%s__init__.py' % filename)
in namelist:
132 _, actionfilename = os.path.split(filename)
133 if actionfilename ==
'%s.action' % name:
137 config = ConfigParser()
140 self.
archive.read(desktop_filename).decode(
'utf-8'))
141 except ConfigParserError
as e:
143 '%s: %s' % (i18n(
'Desktop file'), str(e)))
151 name = config[
'Desktop Entry'][
'X-KDE-Library']
152 ui_name = config[
'Desktop Entry'][
'Name']
153 except KeyError
as e:
155 'Desktop file: Key %s not found' % str(e))
169 f.write(self.
archive.read(plugin[
'desktop']))
172 with TemporaryDirectory()
as tmp_dir:
173 for name
in self.
archive.namelist():
174 if name.startswith(plugin[
'module']):
175 self.
archive.extract(name, tmp_dir)
176 module_dirname = os.path.join(
177 tmp_dir, *plugin[
'module'].split(
'/'))
180 except FileNotFoundError:
182 shutil.copytree(module_dirname,
187 f.write(self.
archive.read(plugin[
'action']))
204 """Imports all plugins from the zip archive.
206 Returns a list of imported plugins.
214 for plugin
in plugins:
217 imported.append(plugin)
222if __name__ ==
'__main__':
224 print(
'Overwriting plugin:', plugin[
'ui_name'])
228 sys.argv[1], sys.argv[2], callback).import_all()
229 for plugin
in imported:
230 print(
'Imported plugin:', plugin[
'ui_name'])
confirm_overwrite_callback
destination_pykrita(self)
read_desktop_config(self, desktop_filename)
get_source_module(self, name)
extract_actionfile(self, plugin)
extract_module(self, plugin)
get_source_actionfile(self, name)
extract_desktop(self, plugin)
get_destination_actionfile(self, plugin)
extract_plugin(self, plugin)
get_destination_desktop(self, plugin)
__init__(self, zip_filename, resources_dir, confirm_overwrite_callback)
destination_actions(self)
get_destination_module(self, plugin)